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

4.104.114.84.95
Last change on this file since f26145b was 714f06c, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/17/04 at 08:12:02

2004-04-17 Ralf Corsepius <ralf_corsepius@…>

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