source: rtems/cpukit/libmisc/monitor/mon-editor.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 16.0 KB
Line 
1/**
2 * @file
3 *
4 * @brief Command line editor for RTEMS monitor.
5 */
6
7/*
8 * 2001-01-30 KJO (vac4050@cae597.rsc.raytheon.com):
9 *  Fixed rtems_monitor_command_lookup() to accept partial
10 *  commands to uniqeness.  Added support for setting
11 *  the monitor prompt via an environment variable:
12 *  RTEMS_MONITOR_PROMPT
13 *
14 * CCJ: 26-3-2000, adding command history and command line
15 * editing. This code is donated from My Right Boot and not
16 * covered by GPL, only the RTEMS license.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include <rtems.h>
24
25#include <rtems/monitor.h>
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30#include <inttypes.h>
31#include <termios.h>
32#include <unistd.h>
33
34#ifndef MONITOR_PROMPT
35#define MONITOR_PROMPT "rtems"          /* will have '> ' appended */
36#endif
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];
66static char buffer[RTEMS_COMMAND_BUFFER_SIZE];
67static int  pos;
68static int  logged_in;
69
70/*
71 * History data.
72 */
73
74#define RTEMS_COMMAND_HISTORIES (20)
75
76static char history_buffer[RTEMS_COMMAND_HISTORIES][RTEMS_COMMAND_BUFFER_SIZE];
77static int  history_pos[RTEMS_COMMAND_HISTORIES];
78static int  history;
79static int  history_next;
80
81/*
82 * Translation tables. Not sure if this is the best way to
83 * handle this, how-ever I wish to avoid the overhead of
84 * including a more complete and standard environment such
85 * as ncurses.
86 */
87
88struct translation_table
89{
90  char                     expecting;
91  const struct translation_table *branch;
92  unsigned int             key;
93};
94
95static const struct translation_table trans_two[] =
96{
97  { '~', 0, KEYS_INS },
98  { 0,   0, 0 }
99};
100
101static const struct translation_table trans_three[] =
102{
103  { '~', 0, KEYS_DEL },
104  { 0,   0, 0 }
105};
106
107static const struct translation_table trans_tab_csi[] =
108{
109  { '2', trans_two,   0 },
110  { '3', trans_three, 0 },
111  { 'A', 0,           KEYS_UARROW },
112  { 'B', 0,           KEYS_DARROW },
113  { 'D', 0,           KEYS_LARROW },
114  { 'C', 0,           KEYS_RARROW },
115  { 'F', 0,           KEYS_END },
116  { 'H', 0,           KEYS_HOME },
117  { 0,   0,           0 }
118};
119
120static const struct translation_table trans_tab_O[] =
121{
122  { '1', 0, KEYS_F1 },
123  { '2', 0, KEYS_F2 },
124  { '3', 0, KEYS_F3 },
125  { '4', 0, KEYS_F4 },
126  { '5', 0, KEYS_F5 },
127  { '6', 0, KEYS_F6 },
128  { '7', 0, KEYS_F7 },
129  { '8', 0, KEYS_F8 },
130  { '9', 0, KEYS_F9 },
131  { ':', 0, KEYS_F10 },
132  { 'P', 0, KEYS_F1 },
133  { 'Q', 0, KEYS_F2 },
134  { 'R', 0, KEYS_F3 },
135  { 'S', 0, KEYS_F4 },
136  { 'T', 0, KEYS_F5 },
137  { 'U', 0, KEYS_F6 },
138  { 'V', 0, KEYS_F7 },
139  { 'W', 0, KEYS_F8 },
140  { 'X', 0, KEYS_F9 },
141  { 'Y', 0, KEYS_F10 },
142  { 0,   0, 0 }
143};
144
145static const struct translation_table trans_tab[] =
146{
147  { '[', trans_tab_csi, 0 },    /* CSI command sequences */
148  { 'O', trans_tab_O,   0 },    /* O are the fuction keys */
149  { 0,   0,             0 }
150};
151
152/*
153 * Perform a basic translation for some ANSI/VT100 key codes.
154 * This code could do with a timeout on the ESC as it is
155 * now lost from the input stream. It is not* used by the
156 * line editor below so considiered not worth the effort.
157 */
158
159static unsigned int
160rtems_monitor_getchar (void)
161{
162  const struct translation_table *translation = 0;
163  for (;;)
164  {
165    char c = getchar ();
166    if (c == 27)
167      translation = trans_tab;
168    else
169    {
170      /*
171       * If no translation happing just pass through
172       * and return the key.
173       */
174      if (translation)
175      {
176        /*
177         * Scan the current table for the key, and if found
178         * see if this key is a fork. If so follow it and
179         * wait else return the extended key.
180         */
181        int index    = 0;
182        int branched = 0;
183        while ((translation[index].expecting != '\0') ||
184               (translation[index].key != '\0'))
185        {
186          if (translation[index].expecting == c)
187          {
188            /*
189             * A branch is take if more keys are to come.
190             */
191            if (translation[index].branch == 0)
192              return KEYS_EXTENDED | translation[index].key;
193            else
194            {
195              translation = translation[index].branch;
196              branched    = 1;
197              break;
198            }
199          }
200          index++;
201        }
202        /*
203         * Who knows what these keys are, just drop them.
204         */
205        if (!branched)
206          translation = 0;
207      }
208      else
209        return c;
210    }
211  }
212}
213
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    fprintf(stdout,"\nMonitor ready, press enter to login.\n\n");
231  else
232    fprintf(stdout,"%s $ ", monitor_prompt);
233
234  while (1)
235  {
236    unsigned int extended_key;
237    char         c;
238
239    fflush (stdout);
240
241    extended_key = rtems_monitor_getchar ();
242    c = extended_key & KEYS_NORMAL_MASK;
243
244    /*
245     * Make the extended_key usable as a boolean.
246     */
247    extended_key &= ~KEYS_NORMAL_MASK;
248
249    if (!extended_key && !logged_in)
250    {
251      if (c == '\n')
252      {
253        logged_in = 1;
254        /*
255         * The prompt has changed from `>' to `$' to help know
256         * which version of the monitor code people are using.
257         */
258        fprintf(stdout,"%s $ ", monitor_prompt);
259      }
260    }
261    else
262    {
263      if (extended_key)
264      {
265        switch (c)
266        {
267          case KEYS_END:
268            fprintf(stdout,buffer + pos);
269            pos = (int) strlen (buffer);
270            break;
271
272          case KEYS_HOME:
273            fprintf(stdout,"\r%s $ ", monitor_prompt);
274            pos = 0;
275            break;
276
277          case KEYS_LARROW:
278            if (pos > 0)
279            {
280              pos--;
281              putchar ('\b');
282            }
283            break;
284
285          case KEYS_RARROW:
286            if ((pos < RTEMS_COMMAND_BUFFER_SIZE) && (buffer[pos] != '\0'))
287            {
288              putchar (buffer[pos]);
289              pos++;
290            }
291            break;
292
293          case KEYS_UARROW:
294            /*
295             * If we are moving up the histories then we need to save the working
296             * buffer.
297             */
298            if (history)
299            {
300              int end;
301              int bs;
302              if (history == history_next)
303              {
304                memcpy (history_buffer[history_next], buffer,
305                        RTEMS_COMMAND_BUFFER_SIZE);
306                history_pos[history_next] = pos;
307              }
308              history--;
309              memcpy (buffer, history_buffer[history],
310                      RTEMS_COMMAND_BUFFER_SIZE);
311              pos = history_pos[history];
312              fprintf(stdout,"\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
313              fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer);
314              end = (int) strlen (buffer);
315              for (bs = 0; bs < (end - pos); bs++)
316                putchar ('\b');
317            }
318            break;
319
320          case KEYS_DARROW:
321            if (history < history_next)
322            {
323              int end;
324              int bs;
325              history++;
326              memcpy (buffer, history_buffer[history],
327                      RTEMS_COMMAND_BUFFER_SIZE);
328              pos = history_pos[history];
329              fprintf(stdout,"\r%*c", RTEMS_COMMAND_BUFFER_SIZE, ' ');
330              fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer);
331              end = (int) strlen (buffer);
332              for (bs = 0; bs < (end - pos); bs++)
333                putchar ('\b');
334            }
335            break;
336
337          case KEYS_DEL:
338            if (buffer[pos] != '\0')
339            {
340              int end;
341              int bs;
342              strcpy (&buffer[pos], &buffer[pos + 1]);
343              fprintf(stdout,"\r%s $ %s", monitor_prompt, buffer);
344              end = (int) strlen (buffer);
345              for (bs = 0; bs < (end - pos); bs++)
346                putchar ('\b');
347            }
348            break;
349        }
350      }
351      else
352      {
353        switch (c)
354        {
355          case '\b':
356          case '\x7e':
357          case '\x7f':
358            if (pos > 0)
359            {
360              int bs;
361              pos--;
362              strcpy (buffer + pos, buffer + pos + 1);
363              fprintf(stdout,"\b%s \b", buffer + pos);
364              for (bs = 0; bs < ((int) strlen (buffer) - pos); bs++)
365                putchar ('\b');
366            }
367            break;
368
369          case '\n':
370            /*
371             * Process the command.
372             */
373            fprintf(stdout,"\n");
374            repeating = 1;
375            /*
376             * Only process the history if we have a command and
377             *a history.
378             */
379            if (strlen (buffer))
380            {
381              if (history_next && (history == history_next))
382              {
383                /*
384                 * Do not place the last command into the history
385                 *if the same.
386                 */
387                if (strcmp (history_buffer[history_next - 1], buffer))
388                  repeating = 0;
389              }
390              else
391                repeating = 0;
392            }
393            if (!repeating)
394            {
395              memcpy (history_buffer[history_next], buffer,
396                      RTEMS_COMMAND_BUFFER_SIZE);
397              history_pos[history_next] = pos;
398              if (history_next < (RTEMS_COMMAND_HISTORIES - 1))
399                history_next++;
400              else
401              {
402                memmove (history_buffer[0], history_buffer[1],
403                         RTEMS_COMMAND_BUFFER_SIZE * (RTEMS_COMMAND_HISTORIES - 1));
404                memmove (&history_pos[0], &history_pos[1],
405                         sizeof (history_pos[0]) * (RTEMS_COMMAND_HISTORIES - 1));
406              }
407            }
408            else
409            {
410#ifdef ENABLE_ENTER_REPEATS
411              if (history_next)
412                memcpy (buffer, history_buffer[history_next - 1],
413                        RTEMS_COMMAND_BUFFER_SIZE);
414#endif
415            }
416            memmove (command, buffer, RTEMS_COMMAND_BUFFER_SIZE);
417            return repeating;
418            break;
419
420          default:
421            if ((pos < (RTEMS_COMMAND_BUFFER_SIZE - 1)) &&
422                (c >= ' ') && (c <= 'z'))
423            {
424              int end;
425              end = strlen (buffer);
426              if ((pos < end) && (end < RTEMS_COMMAND_BUFFER_SIZE))
427              {
428                int ch, bs;
429                for (ch = end; ch > pos; ch--)
430                  buffer[ch] = buffer[ch - 1];
431                fprintf(stdout,buffer + pos);
432                for (bs = 0; bs < (end - pos + 1); bs++)
433                  putchar ('\b');
434              }
435              buffer[pos++] = c;
436              if (pos > end)
437                buffer[pos] = '\0';
438              putchar (c);
439            }
440            break;
441        }
442      }
443    }
444  }
445}
446
447/*
448 * make_argv(cp): token-count
449 *  Break up the command line in 'cp' into global argv[] and argc (return
450 *  value).
451 */
452
453int
454rtems_monitor_make_argv(
455    char *cp,
456    int  *argc_p,
457    char **argv)
458{
459  int argc = 0;
460
461  while ((cp = strtok(cp, " \t\n\r")))
462  {
463    argv[argc++] = cp;
464    cp = (char *) NULL;
465  }
466  argv[argc] = (char *) NULL;      /* end of argv */
467
468  return *argc_p = argc;
469}
470
471
472/*
473 * Read and break up a monitor command
474 *
475 * We have to loop on the gets call, since it will return NULL under UNIX
476 *  RTEMS when we get a signal (eg: SIGALRM).
477 */
478
479int
480rtems_monitor_command_read(char *command,
481                           int  *argc,
482                           char **argv)
483{
484        char *env_prompt;
485
486        env_prompt = getenv("RTEMS_MONITOR_PROMPT");
487
488  /*
489   * put node number in the prompt if we are multiprocessing
490   */
491#if defined(RTEMS_MULTIPROCESSING)
492  if (!rtems_configuration_get_user_multiprocessing_table ())
493    sprintf (monitor_prompt, "%s",
494             (env_prompt == NULL) ? MONITOR_PROMPT: env_prompt);
495  else /* .... */
496#endif
497  if (rtems_monitor_default_node != rtems_monitor_node)
498    sprintf (monitor_prompt, "%" PRId32 "-%s-%" PRId32 "", rtems_monitor_node,
499             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt,
500             rtems_monitor_default_node);
501  else
502    sprintf (monitor_prompt, "%" PRId32 "-%s", rtems_monitor_node,
503             (env_prompt == NULL) ? MONITOR_PROMPT : env_prompt);
504
505  rtems_monitor_line_editor (command);
506
507  return rtems_monitor_make_argv (command, argc, argv);
508}
509
510/*
511 * Main monitor command loop
512 */
513
514void
515rtems_monitor_task(
516    rtems_task_argument monitor_flags
517)
518{
519#if UNUSED
520    rtems_tcb *debugee = 0;
521    rtems_context *rp;
522#if (CPU_HARDWARE_FP == TRUE) || (CPU_SOFTWARE_FP == TRUE)
523    rtems_context_fp *fp;
524#endif
525#endif
526    char command_buffer[513];
527    int argc;
528    char *argv[64];
529    bool  verbose = false;
530    struct termios term;
531
532    /*
533     * Make the stdin stream characte not line based.
534     */
535
536    if (tcgetattr (STDIN_FILENO, &term) < 0)
537    {
538      fprintf(stdout,"rtems-monitor: cannot get terminal attributes.\n");
539    }
540    else
541    {
542      /*
543       * No echo, no canonical processing.
544       */
545
546      term.c_lflag &= ~(ECHO | ICANON | IEXTEN);
547
548      /*
549       * No sigint on BREAK, CR-to-NL off, input parity off,
550       * don't strip 8th bit on input, output flow control off
551       */
552
553      term.c_lflag    &= ~(INPCK | ISTRIP | IXON);
554      term.c_cc[VMIN]  = 1;
555      term.c_cc[VTIME] = 0;
556
557      if (tcsetattr (STDIN_FILENO, TCSANOW, &term) < 0)
558      {
559        fprintf(stdout,"cannot set terminal attributes\n");
560      }
561    }
562
563    if (!(monitor_flags & RTEMS_MONITOR_NOSYMLOAD)) {
564      rtems_monitor_symbols_loadup();
565    }
566
567    if (monitor_flags & RTEMS_MONITOR_SUSPEND)
568        (void) rtems_monitor_suspend(RTEMS_NO_TIMEOUT);
569
570    for (;;)
571    {
572        const rtems_monitor_command_entry_t *command;
573
574#if UNUSED
575        debugee = _Thread_Executing;
576        rp = &debugee->Registers;
577#if (CPU_HARDWARE_FP == TRUE) || (CPU_SOFTWARE_FP == TRUE)
578        fp = debugee->fp_context;  /* possibly 0 */
579#endif
580#endif
581        if (0 == rtems_monitor_command_read(command_buffer, &argc, argv))
582            continue;
583        if (argc < 1
584          || (command = rtems_monitor_command_lookup(argv [0])) == 0) {
585          /* no command */
586          fprintf(stdout,"Unrecognised command; try 'help'\n");
587          continue;
588        }
589
590        command->command_function(argc, argv, &command->command_arg, verbose);
591
592        fflush(stdout);
593    }
594}
595
596
597void
598rtems_monitor_kill(void)
599{
600    if (rtems_monitor_task_id)
601        rtems_task_delete(rtems_monitor_task_id);
602    rtems_monitor_task_id = 0;
603
604    rtems_monitor_server_kill();
605}
606
607void
608rtems_monitor_init(
609    uint32_t   monitor_flags
610)
611{
612    rtems_status_code status;
613
614    rtems_monitor_kill();
615
616    status = rtems_task_create(RTEMS_MONITOR_NAME,
617                               1,
618                               RTEMS_MINIMUM_STACK_SIZE * 2,
619                               RTEMS_INTERRUPT_LEVEL(0),
620                               RTEMS_DEFAULT_ATTRIBUTES,
621                               &rtems_monitor_task_id);
622    if (status != RTEMS_SUCCESSFUL)
623    {
624        rtems_error(status, "could not create monitor task");
625        return;
626    }
627
628    rtems_monitor_node = rtems_object_id_get_node(rtems_monitor_task_id);
629    rtems_monitor_default_node = rtems_monitor_node;
630
631    rtems_monitor_server_init(monitor_flags);
632
633    if (!(monitor_flags & RTEMS_MONITOR_NOTASK)) {
634      /*
635       * Start the monitor task itself
636       */
637      status = rtems_task_start(
638        rtems_monitor_task_id, rtems_monitor_task, monitor_flags);
639      if (status != RTEMS_SUCCESSFUL) {
640        rtems_error(status, "could not start monitor");
641        return;
642      }
643   }
644}
Note: See TracBrowser for help on using the repository browser.