OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libmisc/] [monitor/] [mon-command.c] - Blame information for rev 1026

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.