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

Last change on this file since b9e230a2 was b9e230a2, checked in by Ralf Corsepius <ralf.corsepius@…>, on 07/08/03 at 08:38:15

2003-07-08 Ralf Corsepius <corsepiu@…>

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