source: rtems/cpukit/libmisc/monitor/mon-command.c @ 5ceb9d24

4.104.114.84.95
Last change on this file since 5ceb9d24 was 5ceb9d24, checked in by Ralf Corsepius <ralf.corsepius@…>, on Oct 26, 2002 at 6:29:59 AM

2002-10-26 Ralf Corsepius <corsepiu@…>

  • monitor/mon-command.c: Don't build rtems_monitor_line_editor for RTEMS_UNIX to avoid gcc warning.
  • 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#ifndef RTEMS_UNIX
207/*
208 * The line editor with history.
209 */
210
211static int
212rtems_monitor_line_editor (
213    char *command
214)
215{
216  int repeating = 0;
217
218  memset (buffer, 0, RTEMS_COMMAND_BUFFER_SIZE);
219  history = history_next;
220  pos     = 0;
221         
222  if (!logged_in)
223    printf ("\nMonitor ready, press enter to login.\n\n");
224  else
225    printf ("%s $ ", monitor_prompt);
226
227  while (1)
228  {
229    unsigned int extended_key = rtems_monitor_getchar ();
230    char         c = extended_key & KEYS_NORMAL_MASK;
231
232    /*
233     * Make the extended_key usable as a boolean.
234     */
235    extended_key &= ~KEYS_NORMAL_MASK;
236   
237    if (!extended_key && !logged_in)
238    {
239      if (c == '\n')
240      {
241        logged_in = 1;
242        /*
243         * The prompt has changed from `>' to `$' to help know
244         * which version of the monitor code people are using.
245         */
246        printf("%s $ ", monitor_prompt);
247      }
248    }
249    else
250    {
251      if (extended_key)
252      {
253        switch (c)
254        {
255          case KEYS_END:
256            printf (buffer + pos);
257            pos = (int) strlen (buffer);
258            break;
259
260          case KEYS_HOME:
261            printf ("\r%s $ ", monitor_prompt);
262            pos = 0;
263            break;
264       
265          case KEYS_LARROW:
266            if (pos > 0)
267            {
268              pos--;
269              putchar ('\b');
270            }
271            break;
272
273          case KEYS_RARROW:
274            if ((pos < RTEMS_COMMAND_BUFFER_SIZE) && (buffer[pos] != '\0'))
275            {
276              putchar (buffer[pos]);
277              pos++;
278            }
279            break;
280
281          case KEYS_UARROW:
282            /*
283             * If we are moving up the histories then we need to save the working
284             * buffer.
285             */
286            if (history)
287            {
288              int end;
289              int bs;
290              if (history == history_next)
291              {
292                memcpy (history_buffer[history_next], buffer,
293                        RTEMS_COMMAND_BUFFER_SIZE);
294                history_pos[history_next] = pos;
295              }
296              history--;
297              memcpy (buffer, history_buffer[history],
298                      RTEMS_COMMAND_BUFFER_SIZE);
299              pos = history_pos[history];
300              printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
301              printf ("\r%s $ %s", monitor_prompt, buffer);
302              end = (int) strlen (buffer);
303              for (bs = 0; bs < (end - pos); bs++)
304                putchar ('\b');
305            }
306            break;
307                 
308          case KEYS_DARROW:
309            if (history < history_next)
310            {
311              int end;
312              int bs;
313              history++;
314              memcpy (buffer, history_buffer[history],
315                      RTEMS_COMMAND_BUFFER_SIZE);
316              pos = history_pos[history];
317              printf ("\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
318              printf ("\r%s $ %s", monitor_prompt, buffer);
319              end = (int) strlen (buffer);
320              for (bs = 0; bs < (end - pos); bs++)
321                putchar ('\b');
322            }
323            break;
324
325          case KEYS_DEL:
326            if (buffer[pos] != '\0')
327            {
328              int end;
329              int bs;
330              strcpy (&buffer[pos], &buffer[pos + 1]);
331              printf ("\r%s $ %s", monitor_prompt, buffer);
332              end = (int) strlen (buffer);
333              for (bs = 0; bs < (end - pos); bs++)
334                putchar ('\b');
335            }
336            break;
337        }
338      }
339      else
340      {
341        switch (c)
342        {
343          case '\b':
344          case '\x7e':
345          case '\x7f':
346            if (pos > 0)
347            {
348              int bs;
349              pos--;
350              strcpy (buffer + pos, buffer + pos + 1);
351              printf ("\b%s \b", buffer + pos);
352              for (bs = 0; bs < ((int) strlen (buffer) - pos); bs++)
353                putchar ('\b');
354            }
355            break;
356
357          case '\n':
358            /*
359             * Process the command.
360             */
361            printf ("\n");
362            repeating = 1;
363            /*
364             * Only process the history if we have a command and
365             *a history.
366             */
367            if (strlen (buffer))
368            {
369              if (history_next && (history == history_next))
370              {
371                /*
372                 * Do not place the last command into the history
373                 *if the same.
374                 */
375                if (strcmp (history_buffer[history_next - 1], buffer))
376                  repeating = 0;
377              }
378              else
379                repeating = 0;
380            }
381            if (!repeating)
382            {
383              memcpy (history_buffer[history_next], buffer,
384                      RTEMS_COMMAND_BUFFER_SIZE);
385              history_pos[history_next] = pos;
386              if (history_next < (RTEMS_COMMAND_HISTORIES - 1))
387                history_next++;
388              else
389              {
390                memmove (history_buffer[0], history_buffer[1],
391                         RTEMS_COMMAND_BUFFER_SIZE * (RTEMS_COMMAND_HISTORIES - 1));
392                memmove (&history_pos[0], &history_pos[1],
393                         sizeof (history_pos[0]) * (RTEMS_COMMAND_HISTORIES - 1));
394              }
395            }
396            else
397            {
398#ifdef ENABLE_ENTER_REPEATS
399              if (history_next)
400                memcpy (buffer, history_buffer[history_next - 1],
401                        RTEMS_COMMAND_BUFFER_SIZE);
402#endif
403            }
404            memmove (command, buffer, RTEMS_COMMAND_BUFFER_SIZE);
405            return repeating;
406            break;
407
408          default:
409            if ((pos < (RTEMS_COMMAND_BUFFER_SIZE - 1)) &&
410                (c >= ' ') && (c <= 'z'))
411            {
412              int end;
413              end = strlen (buffer);
414              if ((pos < end) && (end < RTEMS_COMMAND_BUFFER_SIZE))
415              {
416                int ch, bs;
417                for (ch = end + 1; ch > pos; ch--)
418                  buffer[ch] = buffer[ch - 1];
419                printf (buffer + pos);
420                for (bs = 0; bs < (end - pos + 1); bs++)
421                  putchar ('\b');
422              }
423              buffer[pos++] = c;
424              if (pos > end)
425                buffer[pos] = '\0';
426              putchar (c);
427            }
428            break;
429        }
430      }
431    }
432  }
433}
434#endif
435
436/*
437 * make_argv(cp): token-count
438 *  Break up the command line in 'cp' into global argv[] and argc (return
439 *  value).
440 */
441
442int
443rtems_monitor_make_argv(
444    char *cp,
445    int  *argc_p,
446    char **argv)
447{
448  int argc = 0;
449
450  while ((cp = strtok(cp, " \t\n\r")))
451  {
452    argv[argc++] = cp;
453    cp = (char *) NULL;
454  }
455  argv[argc] = (char *) NULL;      /* end of argv */
456
457  return *argc_p = argc;
458}
459
460
461/*
462 * Read and break up a monitor command
463 *
464 * We have to loop on the gets call, since it will return NULL under UNIX
465 *  RTEMS when we get a signal (eg: SIGALRM).
466 */
467
468int
469rtems_monitor_command_read(char *command,
470                           int  *argc,
471                           char **argv)
472{
473        char *env_prompt;
474
475        env_prompt = getenv("RTEMS_MONITOR_PROMPT");
476
477  /*
478   * put node number in the prompt if we are multiprocessing
479   */
480  if (!rtems_configuration_get_user_multiprocessing_table ())
481    sprintf (monitor_prompt, "%s", 
482             (env_prompt == NULL) ? MONITOR_PROMPT: env_prompt);
483  else if (rtems_monitor_default_node != rtems_monitor_node)
484    sprintf (monitor_prompt, "%d-%s-%d", rtems_monitor_node,
485             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt,
486             rtems_monitor_default_node);
487  else
488    sprintf (monitor_prompt, "%d-%s", rtems_monitor_node, 
489             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt);
490
491#if defined(RTEMS_UNIX)
492  /* RTEMS on unix gets so many interrupt system calls this is hosed */
493  printf ("%s> ", monitor_prompt);
494  fflush (stdout);
495  while (gets(command) == (char *) 0)
496    ;
497#else
498  rtems_monitor_line_editor (command);
499#endif
500
501  return rtems_monitor_make_argv (command, argc, argv);
502}
503
504/*
505 * Look up a command in a command table
506 *
507 */
508
509rtems_monitor_command_entry_t *
510rtems_monitor_command_lookup(
511    rtems_monitor_command_entry_t *table,
512    int                            argc,
513    char                          **argv
514)
515{
516  int command_length;
517  rtems_monitor_command_entry_t *found_it = NULL;
518
519  command_length = strlen (argv[0]);
520
521  if ((table == 0) || (argv[0] == 0))
522    return 0;
523   
524  while (table)
525  {
526    if (table->command)
527    {
528
529      /*
530       * Check for ambiguity
531       */
532      if (!strncmp (table->command, argv[0], command_length))
533      {
534        if (found_it)
535        {
536          return 0;
537        }
538       
539        else
540          found_it = table;
541      }
542    }
543    table = table->next;
544  }
545
546  /*
547   * No ambiguity (the possible partial command was unique after all)
548   */
549  if (found_it)
550  {
551    if (table->command_function == 0)
552      return 0;
553
554    return found_it;
555  }
556
557  return 0;
558}
559
560void
561rtems_monitor_show_help (
562  rtems_monitor_command_entry_t *help_cmd,
563  int                           max_cmd_len
564)
565{
566#define MAX_HELP_LINE_LENGTH (75 - max_cmd_len - 2)
567
568  if (help_cmd && help_cmd->command)
569  {
570    const char *help = help_cmd->usage;
571    int         help_len = strlen (help);
572    int         spaces = max_cmd_len - strlen (help_cmd->command);
573    int         show_this_line = 0;
574    int         line_one = 1;
575    int         c;
576
577    printf ("%s", help_cmd->command);
578
579    if (help_len == 0)
580    {
581      printf (" - No help associated.\n");
582      return;
583    }
584 
585    while (help_len)
586    {
587      printf ("%*c", spaces, ' ');
588     
589      if (line_one)
590        printf (" - ");
591
592      spaces   = max_cmd_len + 2;
593      line_one = 0;
594
595      /*
596       * See if greater then the line length if so, work back
597       * from the end for a space, tab or lf or cr.
598       */
599     
600      if (help_len > MAX_HELP_LINE_LENGTH)
601      {
602        for (show_this_line = MAX_HELP_LINE_LENGTH - 1; 
603             show_this_line; 
604             show_this_line--)
605          if ((help[show_this_line] == ' ') ||
606              (help[show_this_line] == '\n') ||
607              (help[show_this_line] == '\r'))
608            break;
609
610        /*
611         * If show_this_line is 0, it is a very long word !!
612         */
613     
614        if (show_this_line == 0)
615          show_this_line = MAX_HELP_LINE_LENGTH - 1;
616      }
617      else
618        show_this_line = help_len;
619
620      for (c = 0; c < show_this_line; c++)
621        if ((help[c] == '\r') || (help[c] == '\n'))
622          show_this_line = c;
623        else
624          putchar (help[c]);
625
626      printf ("\n");
627                 
628      help     += show_this_line;
629      help_len -= show_this_line;
630
631      /*
632       * Move past the line feeds or what ever else is being skipped.
633       */
634   
635      while (help_len)
636      {
637        if ((*help != '\r') && (*help != '\n'))
638          break;
639
640        if (*help != ' ')
641        {
642          help++;
643          help_len--;
644          break;
645        }
646        help++;
647        help_len--;
648      }
649    }
650  }
651}
652
653void
654rtems_monitor_command_usage(
655  rtems_monitor_command_entry_t *table,
656  char                          *command_string
657)
658{
659  rtems_monitor_command_entry_t *command = table;
660  int                           max_cmd_len = 0;
661   
662  /* if first entry in table is a usage, then print it out */
663
664  if (command_string && (*command_string != '\0'))
665  {
666    char *argv[2];
667   
668    argv[0] = command_string;
669    argv[1] = 0;
670   
671    command = rtems_monitor_command_lookup (table, 1, argv);
672
673    if (command)
674      rtems_monitor_show_help (command, strlen (command_string));
675    else
676      printf ("Unrecognised command; try just 'help'\n");
677    return;
678  }
679 
680  /*
681   * Find the largest command size.
682   */
683 
684  while (command)
685  {
686    int len = strlen (command->command);
687
688    if (len > max_cmd_len)
689      max_cmd_len = len;
690
691    command = command->next;
692  }
693
694  max_cmd_len++;
695
696  command = table;
697
698  /*
699   * Now some nice formatting for the help.
700   */
701
702  while (command)
703  {
704    rtems_monitor_show_help (command, max_cmd_len);
705    command = command->next;
706  }
707}
708
709
710void
711rtems_monitor_help_cmd(
712    int          argc,
713    char       **argv,
714    unsigned32   command_arg,
715    boolean verbose
716)
717{
718  int arg;
719  rtems_monitor_command_entry_t *command;
720
721  command = (rtems_monitor_command_entry_t *) command_arg;
722   
723  if (argc == 1)
724    rtems_monitor_command_usage(command, 0);
725  else
726  {
727    for (arg = 1; argv[arg]; arg++)
728      rtems_monitor_command_usage(command, argv[arg]);
729  }
730}
Note: See TracBrowser for help on using the repository browser.