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

4.104.114.9
Last change on this file since 976162a6 was 976162a6, checked in by Joel Sherrill <joel.sherrill@…>, on Dec 3, 2007 at 10:23:13 PM

2007-12-03 Joel Sherrill <joel.sherrill@…>

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