BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / cfe / cfe / ui / ui_command.c
blob85542e2c38ad5d930e2f2d6309e2722a8d8b4838
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * UI Command Dispatch File: ui_command.c
5 *
6 * This module contains routines to maintain the command table,
7 * parse and execute commands
8 *
9 * Author: Mitch Lichtenberg (mpl@broadcom.com)
11 *********************************************************************
13 * Copyright 2000,2001,2002,2003
14 * Broadcom Corporation. All rights reserved.
16 * This software is furnished under license and may be used and
17 * copied only in accordance with the following terms and
18 * conditions. Subject to these conditions, you may download,
19 * copy, install, use, modify and distribute modified or unmodified
20 * copies of this software in source and/or binary form. No title
21 * or ownership is transferred hereby.
23 * 1) Any source code used, modified or distributed must reproduce
24 * and retain this copyright notice and list of conditions
25 * as they appear in the source file.
27 * 2) No right is granted to use any trade name, trademark, or
28 * logo of Broadcom Corporation. The "Broadcom Corporation"
29 * name may not be used to endorse or promote products derived
30 * from this software without the prior written permission of
31 * Broadcom Corporation.
33 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
34 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
35 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
37 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
38 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
40 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
41 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
43 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
45 * THE POSSIBILITY OF SUCH DAMAGE.
46 ********************************************************************* */
49 #include <stdarg.h>
51 #include "lib_queue.h"
53 #include "lib_types.h"
54 #include "lib_string.h"
55 #include "lib_malloc.h"
56 #include "lib_printf.h"
58 #include "cfe_iocb.h"
59 #include "cfe_device.h"
60 #include "cfe_console.h"
61 #include "cfe_error.h"
62 #include "env_subr.h"
63 #include "cfe.h"
65 #include "ui_command.h"
67 #define MAX_EXPAND 16
69 typedef struct cmdtab_s {
70 struct cmdtab_s *sibling;
71 struct cmdtab_s *child;
72 char *cmdword;
73 int (*func)(ui_cmdline_t *,int argc,char *argv[]);
74 void *ref;
75 char *help;
76 char *usage;
77 char *switches;
78 } cmdtab_t;
80 cmdtab_t *cmd_root;
83 #define myisalpha(x) (((x)>='A')&&((x)<='Z')&&((x)>='a')&&((x)<='z'))
84 #define myisdigit(x) (((x)>='0')&&((x)<='9'))
85 #define myisquote(x) (((x)=='\'')||((x)=='"'))
87 char *varchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
88 "abcdefghijklmnopqrstuvwxyz"
89 "0123456789_?";
91 static char *tokenbreaks = " =\t\n\'\"&|;";
92 static char *spacechars = " \t";
94 static char *cmd_eat_quoted_arg(queue_t *head,ui_token_t *t);
97 static inline int is_white_space(ui_token_t *t)
99 return (strchr(spacechars,t->token) != NULL);
102 int cmd_sw_value(ui_cmdline_t *cmd,char *swname,char **swvalue)
104 int idx;
106 for (idx = 0; idx < cmd->swc; idx++) {
107 if (strcmp(swname,cmd->swv[idx].swname) == 0) {
108 *swvalue = cmd->swv[idx].swvalue;
109 return 1;
113 return 0;
116 int cmd_sw_posn(ui_cmdline_t *cmd,char *swname)
118 int idx;
120 for (idx = 0; idx < cmd->swc; idx++) {
121 if (strcmp(swname,cmd->swv[idx].swname) == 0) {
122 return cmd->swv[idx].swidx;
126 return -1;
129 char *cmd_sw_name(ui_cmdline_t *cmd,int swidx)
131 if ((swidx < 0) || (swidx >= cmd->swc)) return NULL;
133 return cmd->swv[swidx].swname;
137 int cmd_sw_isset(ui_cmdline_t *cmd,char *swname)
139 int idx;
141 for (idx = 0; idx < cmd->swc; idx++) {
142 if (strcmp(swname,cmd->swv[idx].swname) == 0) {
143 return 1;
147 return 0;
150 char *cmd_getarg(ui_cmdline_t *cmd,int argnum)
152 argnum += cmd->argidx;
153 if ((argnum < 0) || (argnum >= cmd->argc)) return NULL;
154 return cmd->argv[argnum];
157 void cmd_free(ui_cmdline_t *cmd)
159 int idx;
161 for (idx = 0; idx < cmd->argc; idx++) {
162 KFREE(cmd->argv[idx]);
165 for (idx = 0; idx < cmd->swc; idx++) {
166 KFREE(cmd->swv[idx].swname);
169 cmd->argc = 0;
170 cmd->swc = 0;
173 int cmd_sw_validate(ui_cmdline_t *cmd,char *validstr)
175 char *vdup;
176 char *vptr;
177 char *vnext;
178 char atype;
179 char *x;
180 int idx;
181 int valid;
183 if (cmd->swc == 0) return -1;
185 vdup = strdup(validstr);
187 for (idx = 0; idx < cmd->swc; idx++) {
188 vptr = vdup;
190 vnext = vptr;
191 valid = 0;
193 while (vnext) {
196 * Eat the next switch description from the valid string
198 x = strchr(vptr,'|');
199 if (x) {
200 *x = '\0';
201 vnext = x+1;
203 else {
204 vnext = NULL;
208 * Get the expected arg type, if any
210 x = strchr(vptr,'=');
211 if (x) {
212 atype = *(x+1);
213 *x = 0;
215 else {
216 if ((x = strchr(vptr,';'))) *x = 0;
217 atype = 0;
221 if (strcmp(vptr,cmd->swv[idx].swname) == 0) {
222 /* Value not needed and not supplied */
223 if ((atype == 0) && (cmd->swv[idx].swvalue == NULL)) {
224 valid = 1;
226 /* value needed and supplied */
227 if ((atype != 0) && (cmd->swv[idx].swvalue != NULL)) {
228 valid = 1;
230 strcpy(vdup,validstr);
231 break;
235 * Otherwise, next!
238 strcpy(vdup,validstr);
239 vptr = vnext;
243 * If not valid, return index of bad switch
246 if (valid == 0) {
247 KFREE(vdup);
248 return idx;
254 * Return -1 if everything went well. A little strange,
255 * but it's easier this way.
258 KFREE(vdup);
259 return -1;
262 static cmdtab_t *cmd_findword(cmdtab_t *list,char *cmdword)
264 while (list) {
265 if (strcmp(cmdword,list->cmdword) == 0) return list;
266 list = list->sibling;
269 return NULL;
273 void cmd_build_cmdline(queue_t *head, ui_cmdline_t *cmd)
275 ui_token_t *t;
276 ui_token_t *next;
278 memset(cmd, 0, sizeof(ui_cmdline_t));
280 t = (ui_token_t *) q_deqnext(head);
282 while (t != NULL) {
283 if (is_white_space(t)) {
284 /* do nothing */
286 else if (t->token != '-') {
287 if(cmd->argc < MAX_TOKENS){
288 cmd->argv[cmd->argc] = cmd_eat_quoted_arg(head,t);
289 cmd->argc++;
291 /* Token is a switch */
293 else {
294 if (cmd->swc < MAX_SWITCHES) {
295 cmd->swv[cmd->swc].swname = lib_strdup(&(t->token));
297 if (t->qb.q_next != head) { /* more tokens */
298 next = (ui_token_t *) t->qb.q_next;
299 if (next->token == '=') { /* switch has value */
300 KFREE(t); /* Free switch name */
301 t = (ui_token_t *) q_deqnext(head); /* eat equal sign */
302 KFREE(t); /* and free it */
303 t = (ui_token_t *) q_deqnext(head); /* now have value */
304 if (t != NULL) {
305 cmd->swv[cmd->swc].swvalue = cmd_eat_quoted_arg(head,t);
308 else { /* no value */
309 cmd->swv[cmd->swc].swvalue = NULL;
313 * swidx is the index of the argument that this
314 * switch precedes. So, if you have "foo -d bar",
315 * swidx for "-d" would be 1.
317 cmd->swv[cmd->swc].swidx = cmd->argc;
318 cmd->swc++;
321 KFREE(t);
322 t = (ui_token_t *) q_deqnext(head);
328 int cmd_addcmd(char *command,
329 int (*func)(ui_cmdline_t *,int argc,char *argv[]),
330 void *ref,
331 char *help,
332 char *usage,
333 char *switches)
335 cmdtab_t **list = &cmd_root;
336 cmdtab_t *cmd = NULL;
337 queue_t tokens;
338 queue_t *cur;
339 ui_token_t *t;
341 cmd_build_list(&tokens,command);
342 cur = tokens.q_next;
344 while (cur != &tokens) {
345 t = (ui_token_t *) cur;
346 if (!is_white_space(t)) {
347 cmd = cmd_findword(*list,&(t->token));
348 if (!cmd) {
349 cmd = KMALLOC(sizeof(cmdtab_t)+strlen(&(t->token))+1,0);
350 memset(cmd,0,sizeof(cmdtab_t));
351 cmd->cmdword = (char *) (cmd+1);
352 strcpy(cmd->cmdword,&(t->token));
353 cmd->sibling = *list;
354 *list = cmd;
356 list = &(cmd->child);
358 cur = cur->q_next;
361 cmd_free_tokens(&tokens);
363 if (!cmd) return -1;
365 cmd->func = func;
366 cmd->usage = usage;
367 cmd->ref = ref;
368 cmd->help = help;
369 cmd->switches = switches;
371 return 0;
376 static void _dumpindented(char *str,int amt)
378 int idx;
379 char *dupstr;
380 char *end;
381 char *ptr;
383 dupstr = strdup(str);
385 ptr = dupstr;
387 while (*ptr) {
388 for (idx = 0; idx < amt; idx++) printf(" ");
390 end = strchr(ptr,'\n');
392 if (end) *end++ = '\0';
393 else end = ptr + strlen(ptr);
395 printf("%s\n",ptr);
396 ptr = end;
399 KFREE(dupstr);
402 static void _dumpswitches(char *str)
404 char *switches;
405 char *end;
406 char *ptr;
407 char *semi;
408 char *newline;
410 switches = strdup(str);
412 ptr = switches;
414 while (*ptr) {
415 end = strchr(ptr,'|');
416 if (end) *end++ = '\0';
417 else end = ptr + strlen(ptr);
419 printf(" ");
420 if ((semi = strchr(ptr,';'))) {
421 *semi++ = '\0';
422 newline = strchr(semi,'\n');
423 if (newline) *newline++ = '\0';
424 printf("%-12s %s\n",ptr,semi);
425 if (newline) _dumpindented(newline,5+12+1);
427 else {
428 printf("%-12s (no information)\n",ptr);
430 ptr = end;
433 KFREE(switches);
436 static void _dumpcmds(cmdtab_t *cmd,int level,char **words,int verbose)
438 int idx;
439 int len;
441 while (cmd) {
442 len = 0;
443 words[level] = cmd->cmdword;
444 if (cmd->func) {
445 for (idx = 0; idx < level; idx++) {
446 printf("%s ",words[idx]);
447 len += strlen(words[idx])+1;
449 printf("%s",cmd->cmdword);
450 len += strlen(cmd->cmdword);
451 for (idx = len; idx < 20; idx++) printf(" ");
452 printf("%s\n",cmd->help);
453 if (verbose) {
454 printf("\n");
455 _dumpindented(cmd->usage,5);
456 printf("\n");
457 _dumpswitches(cmd->switches);
458 printf("\n");
461 _dumpcmds(cmd->child,level+1,words,verbose);
462 cmd = cmd->sibling;
466 static void dumpcmds(int verbose)
468 char *words[20];
470 _dumpcmds(cmd_root,0,words,verbose);
474 static void _showpossible(ui_cmdline_t *cline,cmdtab_t *cmd)
476 int i;
478 if (cline->argidx == 0) {
479 printf("Available commands: ");
481 else {
482 printf("Available \"");
483 for (i = 0; i < cline->argidx; i++) {
484 printf("%s%s",(i == 0) ? "" : " ",cline->argv[i]);
486 printf("\" commands: ");
489 while (cmd) {
490 printf("%s",cmd->cmdword);
491 if (cmd->sibling) printf(", ");
492 cmd = cmd->sibling;
495 printf("\n");
498 static int cmd_help(ui_cmdline_t *cmd,int argc,char *argv[])
500 cmdtab_t **tab;
501 cmdtab_t *cword;
502 int idx;
504 if (argc == 0) {
505 printf("Available commands:\n\n");
506 dumpcmds(0);
507 printf("\n");
508 printf("For more information about a command, enter 'help command-name'\n");
510 else {
511 idx = 0;
512 tab = &cmd_root;
513 cword = NULL;
515 for (;;) {
516 cword = cmd_findword(*tab,argv[idx]);
517 if (!cword) break;
518 if (cword->func != NULL) break;
519 idx++;
520 tab = &(cword->child);
521 if (idx >= argc) break;
524 if (cword == NULL) {
525 printf("No help available for '%s'.\n\n",argv[idx]);
526 printf("Type 'help' for a list of commands.\n");
527 return -1;
530 if (!cword->func && (idx >= argc)) {
531 printf("No help available for '%s'.\n\n",cword->cmdword);
532 printf("Type 'help' for a list of commands.\n");
533 return -1;
536 printf("\n SUMMARY\n\n");
537 _dumpindented(cword->help,5);
538 printf("\n USAGE\n\n");
539 _dumpindented(cword->usage,5);
540 if (cword->switches && cword->switches[0]) {
541 printf("\n OPTIONS\n\n");
542 _dumpswitches(cword->switches);
544 printf("\n");
547 return 0;
550 void cmd_init(void)
552 cmd_root = NULL;
554 cmd_addcmd("help",
555 cmd_help,
556 NULL,
557 "Obtain help for CFE commands",
558 "help [command]\n\n"
559 "Without any parameters, the 'help' command will display a summary\n"
560 "of available commands. For more details on a command, type 'help'\n"
561 "and the command name.",
562 "");
566 int cmd_lookup(queue_t *head,ui_cmdline_t *cmd)
568 cmdtab_t **tab;
569 cmdtab_t *cword;
570 int idx;
573 * Reset the command line
576 memset(cmd,0,sizeof(ui_cmdline_t));
579 * Break it up into tokens
582 cmd_build_cmdline(head, cmd);
584 if (cmd->argc == 0) return CMD_ERR_BLANK;
587 * Start walking the tree looking for a function
588 * to execute.
591 idx = 0;
592 tab = &cmd_root;
593 cword = NULL;
595 for (;;) {
596 cword = cmd_findword(*tab,cmd->argv[idx]);
597 if (!cword) break;
598 if (cword->func != NULL) break;
599 idx++;
600 tab = &(cword->child);
601 if (idx >= cmd->argc) break;
604 cmd->argidx = idx;
607 if (cword == NULL) {
608 printf("Invalid command: \"%s\"\n", cmd->argv[idx]);
609 _showpossible(cmd,*tab);
610 printf("\n");
611 return CMD_ERR_INVALID;
614 if (!cword->func && (idx >= cmd->argc)) {
615 printf("Incomplete command: \"%s\"\n",cmd->argv[idx-1]);
616 _showpossible(cmd,*tab);
617 printf("\n");
618 return CMD_ERR_AMBIGUOUS;
621 cmd->argidx++;
622 cmd->ref = cword->ref;
623 cmd->usage = cword->usage;
624 cmd->switches = cword->switches;
625 cmd->func = cword->func;
627 return 0;
631 void cmd_showusage(ui_cmdline_t *cmd)
633 printf("\n");
634 _dumpindented(cmd->usage,5);
635 printf("\n");
636 if (cmd->switches[0]) {
637 _dumpswitches(cmd->switches);
638 printf("\n");
643 static void cmd_eat_leading_white(queue_t *head)
645 ui_token_t *t;
647 while (!q_isempty(head)) {
648 t = (ui_token_t *) q_getfirst(head);
649 if (is_white_space(t)) {
650 q_dequeue(&(t->qb));
651 KFREE(t);
653 else break;
657 ui_command_t *cmd_readcommand(queue_t *head)
659 char *ptr;
660 int insquote = FALSE;
661 int indquote = FALSE;
662 ui_command_t *cmd;
663 int term = CMD_TERM_EOL;
664 ui_token_t *t;
666 cmd_eat_leading_white(head);
668 if (q_isempty(head)) return NULL;
670 cmd = (ui_command_t *) KMALLOC(sizeof(ui_command_t),0);
671 q_init(&(cmd->head));
673 while ((t = (ui_token_t *) q_deqnext(head))) {
675 ptr = &(t->token);
677 if (!insquote && !indquote) {
678 if ((*ptr == ';') || (*ptr == '\n')) {
679 term = CMD_TERM_SEMI;
680 break;
682 if ((*ptr == '&') && (*(ptr+1) == '&')) {
683 term = CMD_TERM_AND;
684 break;
686 if ((*ptr == '|') && (*(ptr+1) == '|')) {
687 term = CMD_TERM_OR;
688 break;
692 if (*ptr == '\'') {
693 insquote = !insquote;
696 if (!insquote) {
697 if (*ptr == '"') {
698 indquote = !indquote;
702 q_enqueue(&(cmd->head),&(t->qb));
706 cmd->term = term;
708 /* If we got out by finding a command separator, eat the separator */
709 if (term != CMD_TERM_EOL) {
710 KFREE(t);
713 return cmd;
718 static ui_token_t *make_token(char *str,int len)
720 ui_token_t *t = (ui_token_t *) KMALLOC(sizeof(ui_token_t) + len,0);
722 memcpy(&(t->token),str,len);
723 (&(t->token))[len] = 0;
725 return t;
728 void cmd_build_list(queue_t *qb,char *buf)
730 char *cur = buf, *start = NULL, *fin = NULL;
731 ui_token_t *t;
733 q_init(qb);
735 start = cur;
736 while(*cur != '\0'){
737 if (*cur == '&' && *(cur + 1) != '&') {
738 /* Do nothing if we have only one & */
740 else if (*cur == '|' && *(cur + 1) != '|') {
741 /* Do nothing if we have only one | */
743 else if (((*cur == ' ')||(*cur == '\t')) &&
744 ((*(cur - 1) == ' ')||(*(cur - 1) == '\t'))) {
745 /* Make one big token for white space */
747 else {
749 if (strchr(tokenbreaks,*cur)) {
750 if (cur != buf) {
751 fin = cur;
752 t = make_token(start,fin-start);
753 q_enqueue(qb,&(t->qb));
754 start = cur; /* Start new token */
757 else {
758 /* If we are on a normal character but the last character was */
759 /* a special char we need to start a new token */
761 if ((cur > buf) && strchr(tokenbreaks,*(cur-1))) {
762 fin = cur;
763 t = make_token(start,fin-start);
764 q_enqueue(qb,&(t->qb));
765 start = cur; /* Start new token */
767 else {
768 /* If the last charecter wasn't special keep going with */
769 /* current token */
776 cur++;
779 fin = cur;
781 if (fin-start > 0) {
782 t = make_token(start,fin-start);
783 q_enqueue(qb,&(t->qb));
786 return;
789 static int is_command_separator(ui_token_t *t)
791 char *string = &(t->token);
792 int sep = 0;
794 switch(*string){
795 case ';':
796 sep = 1;
797 break;
798 case '&':
799 if(*(string + 1) == '&')
800 sep = 1;
801 break;
802 case '|':
803 if(*(string + 1) == '|')
804 sep = 1;
805 default:
806 break;
809 return(sep);
812 static char *cmd_eat_quoted_arg(queue_t *head,ui_token_t *t)
814 int dquote = 0;
815 int squote = 0;
816 queue_t qlist;
817 queue_t *q;
818 char *dest;
819 int maxlen = 0;
822 * If it's not a quoted string, just return this token.
825 if (!myisquote(t->token)) {
826 dest = lib_strdup(&(t->token));
827 /* Note: caller deletes original token */
828 return dest;
832 * Otherwise, eat tokens in the quotes.
835 q_init(&qlist);
837 if (t->token == '"') dquote = 1;
838 else squote = 1; /* must be one or the other */
840 t = (ui_token_t *) q_deqnext(head);
841 while (t != NULL) {
842 /* A single quote can only be terminated by another single quote */
843 if (squote && (t->token == '\'')) {
844 KFREE(t);
845 break;
847 /* A double quote is only honored if not in a single quote */
848 if (dquote && !squote && (t->token == '\"')) {
849 KFREE(t);
850 break;
852 /* Otherwise, keep this token. */
853 q_enqueue(&qlist,(queue_t *) t);
854 t = (ui_token_t *) q_deqnext(head);
858 * Go back through what we collected and figure out the string length.
861 for (q = qlist.q_next; q != &qlist; q = q->q_next) {
862 maxlen += strlen(&(((ui_token_t *) q)->token));
865 dest = KMALLOC(maxlen+1,0);
866 if (!dest) return NULL;
868 *dest = '\0';
870 while ((t = (ui_token_t *) q_deqnext(&qlist))) {
871 strcat(dest,&(t->token));
872 KFREE(t);
875 return dest;
878 static void cmd_append_tokens(queue_t *qb,char *str)
880 queue_t *qq;
881 queue_t explist;
883 cmd_build_list(&explist,str);
885 while ((qq = q_deqnext(&explist))) {
886 q_enqueue(qb,qq);
892 void cmd_walk_and_expand (queue_t *qb)
894 queue_t *q;
895 queue_t newq;
896 ui_token_t *t;
897 int alias_check = TRUE;
898 int insquote = FALSE;
899 char *envstr;
901 q_init(&newq);
903 while ((t = (ui_token_t *) q_deqnext(qb))) {
904 if (t->token == '\'') {
905 alias_check = FALSE;
906 insquote = !insquote;
907 /* Check to see if we should try to expand this token */
909 else if (!insquote) {
910 if (alias_check && !strchr(tokenbreaks,t->token) &&
911 (envstr = env_getenv(&(t->token)))) {
912 /* Aliases: stick into token stream if no environment found */
913 cmd_append_tokens(&newq,envstr);
914 KFREE(t);
915 t = NULL;
917 else if (t->token == '$') {
918 /* non-aliases: remove from token stream if no env found */
919 envstr = env_getenv(&(t->token)+1);
920 if (envstr) cmd_append_tokens(&newq,envstr);
921 KFREE(t);
922 t = NULL;
924 else {
925 /* Drop down below, keep this token as-is and append */
930 * If token was not removed, add it to the new queue
933 if (t) {
934 q_enqueue(&newq,&(t->qb));
935 alias_check = is_command_separator(t);
941 * Put everything back on the original list.
944 while ((q = q_deqnext(&newq))) {
945 q_enqueue(qb,q);
950 void cmd_free_tokens(queue_t *list)
952 queue_t *q;
954 while ((q = q_deqnext(list))) {
955 KFREE(q);