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

4.104.114.84.95
Last change on this file since 3523321 was 3523321, checked in by Joel Sherrill <joel.sherrill@…>, on 08/30/06 at 13:53:02

2006-08-30 Joel Sherrill <joel@…>

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