source: rtems/c/src/libmisc/monitor/mon-command.c @ f585287

4.104.114.84.95
Last change on this file since f585287 was 32e2554, checked in by Joel Sherrill <joel.sherrill@…>, on 06/14/00 at 17:22:59

Patch rtems-4.5-beta3-mon.diff from Chris Johns <cjohns@…>
to:

I have also added the ability to register and unregister commands. This
allows me to create a set of monitor commands for the network stack plus
basic memory dump/patch commands (needs a working probe interface). I
will also look at a basic ls/cd/rm/mv/cp command set at some stage.

I have been thinking about changing the monitor in the future to more
like a light weight RTEMS shell, `eshell' for embedded shell. This is a
story for another day but is a process or getting the commands to map to
the filesystem (eg, major=commands, minor=command) and supporting an
environment. The filesystem provide a structure for the commands.

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