source: rtems/cpukit/libmisc/monitor/mon-command.c @ 80fe968c

4.104.114.84.95
Last change on this file since 80fe968c was 80fe968c, checked in by Joel Sherrill <joel.sherrill@…>, on May 1, 2002 at 10:33:52 PM

2002-03-20 Chris Johns <ccj@…>

  • monitor/mon-command.c: Per PR192 the RTEMS monitor makes everything lowercase. The capture engine need to set triggers or watches on task with uppercase names. Also stop the monitor repeating command when enter is pressed.
  • Property mode set to 100644
File size: 17.0 KB
Line 
1/*
2 * Command parsing routines for RTEMS monitor
3 *
4 * TODO:
5 *
6 *  $Id$
7 */
8
9#include <rtems.h>
10
11#include <rtems/monitor.h>
12
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16
17/*
18 * 2001-01-30 KJO (vac4050@cae597.rsc.raytheon.com):
19 *  Fixed rtems_monitor_command_lookup() to accept partial
20 *  commands to uniqeness.  Added support for setting
21 *  the monitor prompt via an environment variable:
22 *  RTEMS_MONITOR_PROMPT
23 *
24 * CCJ: 26-3-2000, adding command history and command line
25 * editing. This code is donated from My Right Boot and not
26 * covered by GPL, only the RTEMS license.
27 */
28
29/*
30 * Some key labels to define special keys.
31 */
32
33#define KEYS_EXTENDED    (0x8000)
34#define KEYS_NORMAL_MASK (0x00ff)
35#define KEYS_INS         (0)
36#define KEYS_DEL         (1)
37#define KEYS_UARROW      (2)
38#define KEYS_DARROW      (3)
39#define KEYS_LARROW      (4)
40#define KEYS_RARROW      (5)
41#define KEYS_HOME        (6)
42#define KEYS_END         (7)
43#define KEYS_F1          (8)
44#define KEYS_F2          (9)
45#define KEYS_F3          (10)
46#define KEYS_F4          (11)
47#define KEYS_F5          (12)
48#define KEYS_F6          (13)
49#define KEYS_F7          (14)
50#define KEYS_F8          (15)
51#define KEYS_F9          (16)
52#define KEYS_F10         (17)
53
54#define RTEMS_COMMAND_BUFFER_SIZE (75)
55
56static char monitor_prompt[32];
57static char buffer[RTEMS_COMMAND_BUFFER_SIZE];
58static int  pos;
59static int  logged_in;
60
61/*
62 * History data.
63 */
64
65#define RTEMS_COMMAND_HISTORIES (20)
66
67static char history_buffer[RTEMS_COMMAND_HISTORIES][RTEMS_COMMAND_BUFFER_SIZE];
68static int  history_pos[RTEMS_COMMAND_HISTORIES];
69static int  history;
70static int  history_next;
71
72/*
73 * Translation tables. Not sure if this is the best way to
74 * handle this, how-ever I wish to avoid the overhead of
75 * including a more complete and standard environment such
76 * as ncurses.
77 */
78
79struct translation_table
80{
81  char                     expecting;
82  struct translation_table *branch;
83  unsigned int             key;
84};
85
86static struct translation_table trans_two[] =
87{
88  { '~', 0, KEYS_INS },
89  { 0,   0, 0 }
90};
91
92static struct translation_table trans_three[] =
93{
94  { '~', 0, KEYS_DEL },
95  { 0,   0, 0 }
96};
97
98static struct translation_table trans_tab_csi[] =
99{
100  { '2', trans_two,   0 },
101  { '3', trans_three, 0 },
102  { 'A', 0,           KEYS_UARROW },
103  { 'B', 0,           KEYS_DARROW },
104  { 'D', 0,           KEYS_LARROW },
105  { 'C', 0,           KEYS_RARROW },
106  { 'F', 0,           KEYS_END },
107  { 'H', 0,           KEYS_HOME },
108  { 0,   0,           0 }
109};
110
111static struct translation_table trans_tab_O[] =
112{
113  { '1', 0, KEYS_F1 },
114  { '2', 0, KEYS_F2 },
115  { '3', 0, KEYS_F3 },
116  { '4', 0, KEYS_F4 },
117  { '5', 0, KEYS_F5 },
118  { '6', 0, KEYS_F6 },
119  { '7', 0, KEYS_F7 },
120  { '8', 0, KEYS_F8 },
121  { '9', 0, KEYS_F9 },
122  { ':', 0, KEYS_F10 },
123  { 'P', 0, KEYS_F1 },
124  { 'Q', 0, KEYS_F2 },
125  { 'R', 0, KEYS_F3 },
126  { 'S', 0, KEYS_F4 },
127  { 'T', 0, KEYS_F5 },
128  { 'U', 0, KEYS_F6 },
129  { 'V', 0, KEYS_F7 },
130  { 'W', 0, KEYS_F8 },
131  { 'X', 0, KEYS_F9 },
132  { 'Y', 0, KEYS_F10 },
133  { 0,   0, 0 }
134};
135
136static struct translation_table trans_tab[] =
137{
138  { '[', trans_tab_csi, 0 },    /* CSI command sequences */
139  { 'O', trans_tab_O,   0 },    /* O are the fuction keys */
140  { 0,   0,             0 }
141};
142
143/*
144 * Perform a basic tranlation for some ANSI/VT100 key codes.
145 * This code could do with a timeout on the ESC as it is
146 * now lost from the input stream. It is not* used by the
147 * line editor below so considiered not worth the effort.
148 */
149
150static unsigned int
151rtems_monitor_getchar (
152)
153{
154  struct translation_table *translation = 0;
155  for (;;)
156  {
157    char c = getchar ();
158    if (c == 27)
159      translation = trans_tab;
160    else
161    {
162      /*
163       * If no translation happing just pass through
164       * and return the key.
165       */
166      if (translation)
167      {
168        /*
169         * Scan the current table for the key, and if found
170         * see if this key is a fork. If so follow it and
171         * wait else return the extended key.
172         */
173        int index    = 0;
174        int branched = 0;
175        while ((translation[index].expecting != '\0') ||
176               (translation[index].key != '\0'))
177        {
178          if (translation[index].expecting == c)
179          {
180            /*
181             * A branch is take if more keys are to come.
182             */
183            if (translation[index].branch == 0)
184              return KEYS_EXTENDED | translation[index].key;
185            else
186            {
187              translation = translation[index].branch;
188              branched    = 1;
189              break;
190            }
191          }
192          index++;
193        }
194        /*
195         * Who knows what these keys are, just drop them.
196         */
197        if (!branched)
198          translation = 0;
199      }
200      else
201        return c;
202    }
203  }
204}
205
206/*
207 * The line editor with history.
208 */
209
210static int
211rtems_monitor_line_editor (
212    char *command
213)
214{
215  int repeating = 0;
216
217  memset (buffer, 0, RTEMS_COMMAND_BUFFER_SIZE);
218  history = history_next;
219  pos     = 0;
220         
221  if (!logged_in)
222    printf ("\nMonitor ready, press enter to login.\n\n");
223  else
224    printf ("%s $ ", monitor_prompt);
225
226  while (1)
227  {
228    unsigned int extended_key = rtems_monitor_getchar ();
229    char         c = extended_key & KEYS_NORMAL_MASK;
230
231    /*
232     * Make the extended_key usable as a boolean.
233     */
234    extended_key &= ~KEYS_NORMAL_MASK;
235   
236    if (!extended_key && !logged_in)
237    {
238      if (c == '\n')
239      {
240        logged_in = 1;
241        /*
242         * The prompt has changed from `>' to `$' to help know
243         * which version of the monitor code people are using.
244         */
245        printf("%s $ ", monitor_prompt);
246      }
247    }
248    else
249    {
250      if (extended_key)
251      {
252        switch (c)
253        {
254          case KEYS_END:
255            printf (buffer + pos);
256            pos = (int) strlen (buffer);
257            break;
258
259          case KEYS_HOME:
260            printf ("\r%s $ ", monitor_prompt);
261            pos = 0;
262            break;
263       
264          case KEYS_LARROW:
265            if (pos > 0)
266            {
267              pos--;
268              putchar ('\b');
269            }
270            break;
271
272          case KEYS_RARROW:
273            if ((pos < RTEMS_COMMAND_BUFFER_SIZE) && (buffer[pos] != '\0'))
274            {
275              putchar (buffer[pos]);
276              pos++;
277            }
278            break;
279
280          case KEYS_UARROW:
281            /*
282             * If we are moving up the histories then we need to save the working
283             * buffer.
284             */
285            if (history)
286            {
287              int end;
288              int bs;
289              if (history == history_next)
290              {
291                memcpy (history_buffer[history_next], buffer,
292                        RTEMS_COMMAND_BUFFER_SIZE);
293                history_pos[history_next] = pos;
294              }
295              history--;
296              memcpy (buffer, history_buffer[history],
297                      RTEMS_COMMAND_BUFFER_SIZE);
298              pos = history_pos[history];
299              printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
300              printf ("\r%s $ %s", monitor_prompt, buffer);
301              end = (int) strlen (buffer);
302              for (bs = 0; bs < (end - pos); bs++)
303                putchar ('\b');
304            }
305            break;
306                 
307          case KEYS_DARROW:
308            if (history < history_next)
309            {
310              int end;
311              int bs;
312              history++;
313              memcpy (buffer, history_buffer[history],
314                      RTEMS_COMMAND_BUFFER_SIZE);
315              pos = history_pos[history];
316              printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
317              printf ("\r%s $ %s", monitor_prompt, buffer);
318              end = (int) strlen (buffer);
319              for (bs = 0; bs < (end - pos); bs++)
320                putchar ('\b');
321            }
322            break;
323
324          case KEYS_DEL:
325            if (buffer[pos] != '\0')
326            {
327              int end;
328              int bs;
329              strcpy (&buffer[pos], &buffer[pos + 1]);
330              printf ("\r%s $ %s", monitor_prompt, buffer);
331              end = (int) strlen (buffer);
332              for (bs = 0; bs < (end - pos); bs++)
333                putchar ('\b');
334            }
335            break;
336        }
337      }
338      else
339      {
340        switch (c)
341        {
342          case '\b':
343          case '\x7e':
344          case '\x7f':
345            if (pos > 0)
346            {
347              int bs;
348              pos--;
349              strcpy (buffer + pos, buffer + pos + 1);
350              printf ("\b%s \b", buffer + pos);
351              for (bs = 0; bs < ((int) strlen (buffer) - pos); bs++)
352                putchar ('\b');
353            }
354            break;
355
356          case '\n':
357            /*
358             * Process the command.
359             */
360            printf ("\n");
361            repeating = 1;
362            /*
363             * Only process the history if we have a command and
364             *a history.
365             */
366            if (strlen (buffer))
367            {
368              if (history_next && (history == history_next))
369              {
370                /*
371                 * Do not place the last command into the history
372                 *if the same.
373                 */
374                if (strcmp (history_buffer[history_next - 1], buffer))
375                  repeating = 0;
376              }
377              else
378                repeating = 0;
379            }
380            if (!repeating)
381            {
382              memcpy (history_buffer[history_next], buffer,
383                      RTEMS_COMMAND_BUFFER_SIZE);
384              history_pos[history_next] = pos;
385              if (history_next < (RTEMS_COMMAND_HISTORIES - 1))
386                history_next++;
387              else
388              {
389                memmove (history_buffer[0], history_buffer[1],
390                         RTEMS_COMMAND_BUFFER_SIZE * (RTEMS_COMMAND_HISTORIES - 1));
391                memmove (&history_pos[0], &history_pos[1],
392                         sizeof (history_pos[0]) * (RTEMS_COMMAND_HISTORIES - 1));
393              }
394            }
395            else
396            {
397#ifdef ENABLE_ENTER_REPEATS
398              if (history_next)
399                memcpy (buffer, history_buffer[history_next - 1],
400                        RTEMS_COMMAND_BUFFER_SIZE);
401#endif
402            }
403            memmove (command, buffer, RTEMS_COMMAND_BUFFER_SIZE);
404            return repeating;
405            break;
406
407          default:
408            if ((pos < (RTEMS_COMMAND_BUFFER_SIZE - 1)) &&
409                (c >= ' ') && (c <= 'z'))
410            {
411              int end;
412              end = strlen (buffer);
413              if ((pos < end) && (end < RTEMS_COMMAND_BUFFER_SIZE))
414              {
415                int ch, bs;
416                for (ch = end + 1; ch > pos; ch--)
417                  buffer[ch] = buffer[ch - 1];
418                printf (buffer + pos);
419                for (bs = 0; bs < (end - pos + 1); bs++)
420                  putchar ('\b');
421              }
422              buffer[pos++] = c;
423              if (pos > end)
424                buffer[pos] = '\0';
425              putchar (c);
426            }
427            break;
428        }
429      }
430    }
431  }
432}
433
434/*
435 * make_argv(cp): token-count
436 *  Break up the command line in 'cp' into global argv[] and argc (return
437 *  value).
438 */
439
440int
441rtems_monitor_make_argv(
442    char *cp,
443    int  *argc_p,
444    char **argv)
445{
446  int argc = 0;
447
448  while ((cp = strtok(cp, " \t\n\r")))
449  {
450    argv[argc++] = cp;
451    cp = (char *) NULL;
452  }
453  argv[argc] = (char *) NULL;      /* end of argv */
454
455  return *argc_p = argc;
456}
457
458
459/*
460 * Read and break up a monitor command
461 *
462 * We have to loop on the gets call, since it will return NULL under UNIX
463 *  RTEMS when we get a signal (eg: SIGALRM).
464 */
465
466int
467rtems_monitor_command_read(char *command,
468                           int  *argc,
469                           char **argv)
470{
471        char *env_prompt;
472
473        env_prompt = getenv("RTEMS_MONITOR_PROMPT");
474
475  /*
476   * put node number in the prompt if we are multiprocessing
477   */
478  if (!rtems_configuration_get_user_multiprocessing_table ())
479    sprintf (monitor_prompt, "%s", 
480             (env_prompt == NULL) ? MONITOR_PROMPT: env_prompt);
481  else if (rtems_monitor_default_node != rtems_monitor_node)
482    sprintf (monitor_prompt, "%d-%s-%d", rtems_monitor_node,
483             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt,
484             rtems_monitor_default_node);
485  else
486    sprintf (monitor_prompt, "%d-%s", rtems_monitor_node, 
487             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt);
488
489#if defined(RTEMS_UNIX)
490  /* RTEMS on unix gets so many interrupt system calls this is hosed */
491  printf ("%s> ", monitor_prompt);
492  fflush (stdout);
493  while (gets(command) == (char *) 0)
494    ;
495#else
496  rtems_monitor_line_editor (command);
497#endif
498
499  return rtems_monitor_make_argv (command, argc, argv);
500}
501
502/*
503 * Look up a command in a command table
504 *
505 */
506
507rtems_monitor_command_entry_t *
508rtems_monitor_command_lookup(
509    rtems_monitor_command_entry_t *table,
510    int                            argc,
511    char                          **argv
512)
513{
514  int command_length;
515  rtems_monitor_command_entry_t *found_it = NULL;
516
517  command_length = strlen (argv[0]);
518
519  if ((table == 0) || (argv[0] == 0))
520    return 0;
521   
522  while (table)
523  {
524    if (table->command)
525    {
526
527      /*
528       * Check for ambiguity
529       */
530      if (!strncmp (table->command, argv[0], command_length))
531      {
532        if (found_it)
533        {
534          return 0;
535        }
536       
537        else
538          found_it = table;
539      }
540    }
541    table = table->next;
542  }
543
544  /*
545   * No ambiguity (the possible partial command was unique after all)
546   */
547  if (found_it)
548  {
549    if (table->command_function == 0)
550      return 0;
551
552    return found_it;
553  }
554
555  return 0;
556}
557
558void
559rtems_monitor_show_help (
560  rtems_monitor_command_entry_t *help_cmd,
561  int                           max_cmd_len
562)
563{
564#define MAX_HELP_LINE_LENGTH (75 - max_cmd_len - 2)
565
566  if (help_cmd && help_cmd->command)
567  {
568    const char *help = help_cmd->usage;
569    int         help_len = strlen (help);
570    int         spaces = max_cmd_len - strlen (help_cmd->command);
571    int         show_this_line = 0;
572    int         line_one = 1;
573    int         c;
574
575    printf ("%s", help_cmd->command);
576
577    if (help_len == 0)
578    {
579      printf (" - No help associated.\n");
580      return;
581    }
582 
583    while (help_len)
584    {
585      printf ("%*c", spaces, ' ');
586     
587      if (line_one)
588        printf (" - ");
589
590      spaces   = max_cmd_len + 2;
591      line_one = 0;
592
593      /*
594       * See if greater then the line length if so, work back
595       * from the end for a space, tab or lf or cr.
596       */
597     
598      if (help_len > MAX_HELP_LINE_LENGTH)
599      {
600        for (show_this_line = MAX_HELP_LINE_LENGTH - 1; 
601             show_this_line; 
602             show_this_line--)
603          if ((help[show_this_line] == ' ') ||
604              (help[show_this_line] == '\n') ||
605              (help[show_this_line] == '\r'))
606            break;
607
608        /*
609         * If show_this_line is 0, it is a very long word !!
610         */
611     
612        if (show_this_line == 0)
613          show_this_line = MAX_HELP_LINE_LENGTH - 1;
614      }
615      else
616        show_this_line = help_len;
617
618      for (c = 0; c < show_this_line; c++)
619        if ((help[c] == '\r') || (help[c] == '\n'))
620          show_this_line = c;
621        else
622          putchar (help[c]);
623
624      printf ("\n");
625                 
626      help     += show_this_line;
627      help_len -= show_this_line;
628
629      /*
630       * Move past the line feeds or what ever else is being skipped.
631       */
632   
633      while (help_len)
634      {
635        if ((*help != '\r') && (*help != '\n'))
636          break;
637
638        if (*help != ' ')
639        {
640          help++;
641          help_len--;
642          break;
643        }
644        help++;
645        help_len--;
646      }
647    }
648  }
649}
650
651void
652rtems_monitor_command_usage(
653  rtems_monitor_command_entry_t *table,
654  char                          *command_string
655)
656{
657  rtems_monitor_command_entry_t *command = table;
658  int                           max_cmd_len = 0;
659   
660  /* if first entry in table is a usage, then print it out */
661
662  if (command_string && (*command_string != '\0'))
663  {
664    char *argv[2];
665   
666    argv[0] = command_string;
667    argv[1] = 0;
668   
669    command = rtems_monitor_command_lookup (table, 1, argv);
670
671    if (command)
672      rtems_monitor_show_help (command, strlen (command_string));
673    else
674      printf ("Unrecognised command; try just 'help'\n");
675    return;
676  }
677 
678  /*
679   * Find the largest command size.
680   */
681 
682  while (command)
683  {
684    int len = strlen (command->command);
685
686    if (len > max_cmd_len)
687      max_cmd_len = len;
688
689    command = command->next;
690  }
691
692  max_cmd_len++;
693
694  command = table;
695
696  /*
697   * Now some nice formatting for the help.
698   */
699
700  while (command)
701  {
702    rtems_monitor_show_help (command, max_cmd_len);
703    command = command->next;
704  }
705}
706
707
708void
709rtems_monitor_help_cmd(
710    int          argc,
711    char       **argv,
712    unsigned32   command_arg,
713    boolean verbose
714)
715{
716  int arg;
717  rtems_monitor_command_entry_t *command;
718
719  command = (rtems_monitor_command_entry_t *) command_arg;
720   
721  if (argc == 1)
722    rtems_monitor_command_usage(command, 0);
723  else
724  {
725    for (arg = 1; argv[arg]; arg++)
726      rtems_monitor_command_usage(command, argv[arg]);
727  }
728}
Note: See TracBrowser for help on using the repository browser.