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) 10 * 11 ********************************************************************* 12 * 13 * Copyright 2000,2001,2002,2003 14 * Broadcom Corporation. All rights reserved. 15 * 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. 22 * 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. 26 * 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. 32 * 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 ********************************************************************* */ 47 48 49#include <stdarg.h> 50 51#include "lib_queue.h" 52 53#include "lib_types.h" 54#include "lib_string.h" 55#include "lib_malloc.h" 56#include "lib_printf.h" 57 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" 64 65#include "ui_command.h" 66 67#define MAX_EXPAND 16 68 69typedef 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; 79 80cmdtab_t *cmd_root; 81 82 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)=='"')) 86 87char *varchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 88 "abcdefghijklmnopqrstuvwxyz" 89 "0123456789_?"; 90 91static char *tokenbreaks = " =\t\n\'\"&|;"; 92static char *spacechars = " \t"; 93 94static char *cmd_eat_quoted_arg(queue_t *head,ui_token_t *t); 95 96 97static inline int is_white_space(ui_token_t *t) 98{ 99 return (strchr(spacechars,t->token) != NULL); 100} 101 102int cmd_sw_value(ui_cmdline_t *cmd,char *swname,char **swvalue) 103{ 104 int idx; 105 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; 110 } 111 } 112 113 return 0; 114} 115 116int cmd_sw_posn(ui_cmdline_t *cmd,char *swname) 117{ 118 int idx; 119 120 for (idx = 0; idx < cmd->swc; idx++) { 121 if (strcmp(swname,cmd->swv[idx].swname) == 0) { 122 return cmd->swv[idx].swidx; 123 } 124 } 125 126 return -1; 127} 128 129char *cmd_sw_name(ui_cmdline_t *cmd,int swidx) 130{ 131 if ((swidx < 0) || (swidx >= cmd->swc)) return NULL; 132 133 return cmd->swv[swidx].swname; 134} 135 136 137int cmd_sw_isset(ui_cmdline_t *cmd,char *swname) 138{ 139 int idx; 140 141 for (idx = 0; idx < cmd->swc; idx++) { 142 if (strcmp(swname,cmd->swv[idx].swname) == 0) { 143 return 1; 144 } 145 } 146 147 return 0; 148} 149 150char *cmd_getarg(ui_cmdline_t *cmd,int argnum) 151{ 152 argnum += cmd->argidx; 153 if ((argnum < 0) || (argnum >= cmd->argc)) return NULL; 154 return cmd->argv[argnum]; 155} 156 157void cmd_free(ui_cmdline_t *cmd) 158{ 159 int idx; 160 161 for (idx = 0; idx < cmd->argc; idx++) { 162 KFREE(cmd->argv[idx]); 163 } 164 165 for (idx = 0; idx < cmd->swc; idx++) { 166 KFREE(cmd->swv[idx].swname); 167 } 168 169 cmd->argc = 0; 170 cmd->swc = 0; 171} 172 173int cmd_sw_validate(ui_cmdline_t *cmd,char *validstr) 174{ 175 char *vdup; 176 char *vptr; 177 char *vnext; 178 char atype; 179 char *x; 180 int idx; 181 int valid; 182 183 if (cmd->swc == 0) return -1; 184 185 vdup = strdup(validstr); 186 187 for (idx = 0; idx < cmd->swc; idx++) { 188 vptr = vdup; 189 190 vnext = vptr; 191 valid = 0; 192 193 while (vnext) { 194 195 /* 196 * Eat the next switch description from the valid string 197 */ 198 x = strchr(vptr,'|'); 199 if (x) { 200 *x = '\0'; 201 vnext = x+1; 202 } 203 else { 204 vnext = NULL; 205 } 206 207 /* 208 * Get the expected arg type, if any 209 */ 210 x = strchr(vptr,'='); 211 if (x) { 212 atype = *(x+1); 213 *x = 0; 214 } 215 else { 216 if ((x = strchr(vptr,';'))) *x = 0; 217 atype = 0; 218 } 219 220 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; 225 } 226 /* value needed and supplied */ 227 if ((atype != 0) && (cmd->swv[idx].swvalue != NULL)) { 228 valid = 1; 229 } 230 strcpy(vdup,validstr); 231 break; 232 } 233 234 /* 235 * Otherwise, next! 236 */ 237 238 strcpy(vdup,validstr); 239 vptr = vnext; 240 } 241 242 /* 243 * If not valid, return index of bad switch 244 */ 245 246 if (valid == 0) { 247 KFREE(vdup); 248 return idx; 249 } 250 251 } 252 253 /* 254 * Return -1 if everything went well. A little strange, 255 * but it's easier this way. 256 */ 257 258 KFREE(vdup); 259 return -1; 260} 261 262static cmdtab_t *cmd_findword(cmdtab_t *list,char *cmdword) 263{ 264 while (list) { 265 if (strcmp(cmdword,list->cmdword) == 0) return list; 266 list = list->sibling; 267 } 268 269 return NULL; 270} 271 272 273void cmd_build_cmdline(queue_t *head, ui_cmdline_t *cmd) 274{ 275 ui_token_t *t; 276 ui_token_t *next; 277 278 memset(cmd, 0, sizeof(ui_cmdline_t)); 279 280 t = (ui_token_t *) q_deqnext(head); 281 282 while (t != NULL) { 283 if (is_white_space(t)) { 284 /* do nothing */ 285 } 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++; 290 } 291 /* Token is a switch */ 292 } 293 else { 294 if (cmd->swc < MAX_SWITCHES) { 295 cmd->swv[cmd->swc].swname = lib_strdup(&(t->token)); 296 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); 306 } 307 } 308 else { /* no value */ 309 cmd->swv[cmd->swc].swvalue = NULL; 310 } 311 } 312 /* 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. 316 */ 317 cmd->swv[cmd->swc].swidx = cmd->argc; 318 cmd->swc++; 319 } 320 } 321 KFREE(t); 322 t = (ui_token_t *) q_deqnext(head); 323 } 324 325 326} 327 328int 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) 334{ 335 cmdtab_t **list = &cmd_root; 336 cmdtab_t *cmd = NULL; 337 queue_t tokens; 338 queue_t *cur; 339 ui_token_t *t; 340 341 cmd_build_list(&tokens,command); 342 cur = tokens.q_next; 343 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; 355 } 356 list = &(cmd->child); 357 } 358 cur = cur->q_next; 359 } 360 361 cmd_free_tokens(&tokens); 362 363 if (!cmd) return -1; 364 365 cmd->func = func; 366 cmd->usage = usage; 367 cmd->ref = ref; 368 cmd->help = help; 369 cmd->switches = switches; 370 371 return 0; 372} 373 374 375 376static void _dumpindented(char *str,int amt) 377{ 378 int idx; 379 char *dupstr; 380 char *end; 381 char *ptr; 382 383 dupstr = strdup(str); 384 385 ptr = dupstr; 386 387 while (*ptr) { 388 for (idx = 0; idx < amt; idx++) printf(" "); 389 390 end = strchr(ptr,'\n'); 391 392 if (end) *end++ = '\0'; 393 else end = ptr + strlen(ptr); 394 395 printf("%s\n",ptr); 396 ptr = end; 397 } 398 399 KFREE(dupstr); 400} 401 402static void _dumpswitches(char *str) 403{ 404 char *switches; 405 char *end; 406 char *ptr; 407 char *semi; 408 char *newline; 409 410 switches = strdup(str); 411 412 ptr = switches; 413 414 while (*ptr) { 415 end = strchr(ptr,'|'); 416 if (end) *end++ = '\0'; 417 else end = ptr + strlen(ptr); 418 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); 426 } 427 else { 428 printf("%-12s (no information)\n",ptr); 429 } 430 ptr = end; 431 } 432 433 KFREE(switches); 434} 435 436static void _dumpcmds(cmdtab_t *cmd,int level,char **words,int verbose) 437{ 438 int idx; 439 int len; 440 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; 448 } 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"); 459 } 460 } 461 _dumpcmds(cmd->child,level+1,words,verbose); 462 cmd = cmd->sibling; 463 } 464} 465 466static void dumpcmds(int verbose) 467{ 468 char *words[20]; 469 470 _dumpcmds(cmd_root,0,words,verbose); 471} 472 473 474static void _showpossible(ui_cmdline_t *cline,cmdtab_t *cmd) 475{ 476 int i; 477 478 if (cline->argidx == 0) { 479 printf("Available commands: "); 480 } 481 else { 482 printf("Available \""); 483 for (i = 0; i < cline->argidx; i++) { 484 printf("%s%s",(i == 0) ? "" : " ",cline->argv[i]); 485 } 486 printf("\" commands: "); 487 } 488 489 while (cmd) { 490 printf("%s",cmd->cmdword); 491 if (cmd->sibling) printf(", "); 492 cmd = cmd->sibling; 493 } 494 495 printf("\n"); 496} 497 498static int cmd_help(ui_cmdline_t *cmd,int argc,char *argv[]) 499{ 500 cmdtab_t **tab; 501 cmdtab_t *cword; 502 int idx; 503 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"); 509 } 510 else { 511 idx = 0; 512 tab = &cmd_root; 513 cword = NULL; 514 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; 522 } 523 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; 528 } 529 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; 534 } 535 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); 543 } 544 printf("\n"); 545 } 546 547 return 0; 548} 549 550void cmd_init(void) 551{ 552 cmd_root = NULL; 553 554 cmd_addcmd("help", 555 cmd_help, 556 NULL, 557 "Obtain help for CFE commands", 558#ifndef CFG_MINIMAL_SIZE 559 "help [command]\n\n" 560 "Without any parameters, the 'help' command will display a summary\n" 561 "of available commands. For more details on a command, type 'help'\n" 562 "and the command name.", 563#else /* CFG_MINIMAL_SIZE */ 564 "help [command]\n", 565#endif /* CFG_MINIMAL_SIZE */ 566 ""); 567} 568 569 570int cmd_lookup(queue_t *head,ui_cmdline_t *cmd) 571{ 572 cmdtab_t **tab; 573 cmdtab_t *cword; 574 int idx; 575 576 /* 577 * Reset the command line 578 */ 579 580 memset(cmd,0,sizeof(ui_cmdline_t)); 581 582 /* 583 * Break it up into tokens 584 */ 585 586 cmd_build_cmdline(head, cmd); 587 588 if (cmd->argc == 0) return CMD_ERR_BLANK; 589 590 /* 591 * Start walking the tree looking for a function 592 * to execute. 593 */ 594 595 idx = 0; 596 tab = &cmd_root; 597 cword = NULL; 598 599 for (;;) { 600 cword = cmd_findword(*tab,cmd->argv[idx]); 601 if (!cword) break; 602 if (cword->func != NULL) break; 603 idx++; 604 tab = &(cword->child); 605 if (idx >= cmd->argc) break; 606 } 607 608 cmd->argidx = idx; 609 610 611 if (cword == NULL) { 612 printf("Invalid command: \"%s\"\n", cmd->argv[idx]); 613 _showpossible(cmd,*tab); 614 printf("\n"); 615 return CMD_ERR_INVALID; 616 } 617 618 if (!cword->func && (idx >= cmd->argc)) { 619 printf("Incomplete command: \"%s\"\n",cmd->argv[idx-1]); 620 _showpossible(cmd,*tab); 621 printf("\n"); 622 return CMD_ERR_AMBIGUOUS; 623 } 624 625 cmd->argidx++; 626 cmd->ref = cword->ref; 627 cmd->usage = cword->usage; 628 cmd->switches = cword->switches; 629 cmd->func = cword->func; 630 631 return 0; 632} 633 634 635void cmd_showusage(ui_cmdline_t *cmd) 636{ 637 printf("\n"); 638 _dumpindented(cmd->usage,5); 639 printf("\n"); 640 if (cmd->switches[0]) { 641 _dumpswitches(cmd->switches); 642 printf("\n"); 643 } 644} 645 646 647static void cmd_eat_leading_white(queue_t *head) 648{ 649 ui_token_t *t; 650 651 while (!q_isempty(head)) { 652 t = (ui_token_t *) q_getfirst(head); 653 if (is_white_space(t)) { 654 q_dequeue(&(t->qb)); 655 KFREE(t); 656 } 657 else break; 658 } 659} 660 661ui_command_t *cmd_readcommand(queue_t *head) 662{ 663 char *ptr; 664 int insquote = FALSE; 665 int indquote = FALSE; 666 ui_command_t *cmd; 667 int term = CMD_TERM_EOL; 668 ui_token_t *t; 669 670 cmd_eat_leading_white(head); 671 672 if (q_isempty(head)) return NULL; 673 674 cmd = (ui_command_t *) KMALLOC(sizeof(ui_command_t),0); 675 q_init(&(cmd->head)); 676 677 while ((t = (ui_token_t *) q_deqnext(head))) { 678 679 ptr = &(t->token); 680 681 if (!insquote && !indquote) { 682 if ((*ptr == ';') || (*ptr == '\n')) { 683 term = CMD_TERM_SEMI; 684 break; 685 } 686 if ((*ptr == '&') && (*(ptr+1) == '&')) { 687 term = CMD_TERM_AND; 688 break; 689 } 690 if ((*ptr == '|') && (*(ptr+1) == '|')) { 691 term = CMD_TERM_OR; 692 break; 693 } 694 } 695 696 if (*ptr == '\'') { 697 insquote = !insquote; 698 } 699 700 if (!insquote) { 701 if (*ptr == '"') { 702 indquote = !indquote; 703 } 704 } 705 706 q_enqueue(&(cmd->head),&(t->qb)); 707 708 } 709 710 cmd->term = term; 711 712 /* If we got out by finding a command separator, eat the separator */ 713 if (term != CMD_TERM_EOL) { 714 KFREE(t); 715 } 716 717 return cmd; 718} 719 720 721 722static ui_token_t *make_token(char *str,int len) 723{ 724 ui_token_t *t = (ui_token_t *) KMALLOC(sizeof(ui_token_t) + len,0); 725 726 memcpy(&(t->token),str,len); 727 (&(t->token))[len] = 0; 728 729 return t; 730} 731 732void cmd_build_list(queue_t *qb,char *buf) 733{ 734 char *cur = buf, *start = NULL, *fin = NULL; 735 ui_token_t *t; 736 737 q_init(qb); 738 739 start = cur; 740 while(*cur != '\0'){ 741 if (*cur == '&' && *(cur + 1) != '&') { 742 /* Do nothing if we have only one & */ 743 } 744 else if (*cur == '|' && *(cur + 1) != '|') { 745 /* Do nothing if we have only one | */ 746 } 747 else if (((*cur == ' ')||(*cur == '\t')) && 748 ((*(cur - 1) == ' ')||(*(cur - 1) == '\t'))) { 749 /* Make one big token for white space */ 750 } 751 else { 752 753 if (strchr(tokenbreaks,*cur)) { 754 if (cur != buf) { 755 fin = cur; 756 t = make_token(start,fin-start); 757 q_enqueue(qb,&(t->qb)); 758 start = cur; /* Start new token */ 759 } 760 } 761 else { 762 /* If we are on a normal character but the last character was */ 763 /* a special char we need to start a new token */ 764 765 if ((cur > buf) && strchr(tokenbreaks,*(cur-1))) { 766 fin = cur; 767 t = make_token(start,fin-start); 768 q_enqueue(qb,&(t->qb)); 769 start = cur; /* Start new token */ 770 } 771 else { 772 /* If the last charecter wasn't special keep going with */ 773 /* current token */ 774 } 775 776 777 } 778 779 } 780 cur++; 781 } 782 783 fin = cur; 784 785 if (fin-start > 0) { 786 t = make_token(start,fin-start); 787 q_enqueue(qb,&(t->qb)); 788 } 789 790 return; 791} 792 793static int is_command_separator(ui_token_t *t) 794{ 795 char *string = &(t->token); 796 int sep = 0; 797 798 switch(*string){ 799 case ';': 800 sep = 1; 801 break; 802 case '&': 803 if(*(string + 1) == '&') 804 sep = 1; 805 break; 806 case '|': 807 if(*(string + 1) == '|') 808 sep = 1; 809 default: 810 break; 811 } 812 813 return(sep); 814} 815 816static char *cmd_eat_quoted_arg(queue_t *head,ui_token_t *t) 817{ 818 int dquote = 0; 819 int squote = 0; 820 queue_t qlist; 821 queue_t *q; 822 char *dest; 823 int maxlen = 0; 824 825 /* 826 * If it's not a quoted string, just return this token. 827 */ 828 829 if (!myisquote(t->token)) { 830 dest = lib_strdup(&(t->token)); 831 /* Note: caller deletes original token */ 832 return dest; 833 } 834 835 /* 836 * Otherwise, eat tokens in the quotes. 837 */ 838 839 q_init(&qlist); 840 841 if (t->token == '"') dquote = 1; 842 else squote = 1; /* must be one or the other */ 843 844 t = (ui_token_t *) q_deqnext(head); 845 while (t != NULL) { 846 /* A single quote can only be terminated by another single quote */ 847 if (squote && (t->token == '\'')) { 848 KFREE(t); 849 break; 850 } 851 /* A double quote is only honored if not in a single quote */ 852 if (dquote && !squote && (t->token == '\"')) { 853 KFREE(t); 854 break; 855 } 856 /* Otherwise, keep this token. */ 857 q_enqueue(&qlist,(queue_t *) t); 858 t = (ui_token_t *) q_deqnext(head); 859 } 860 861 /* 862 * Go back through what we collected and figure out the string length. 863 */ 864 865 for (q = qlist.q_next; q != &qlist; q = q->q_next) { 866 maxlen += strlen(&(((ui_token_t *) q)->token)); 867 } 868 869 dest = KMALLOC(maxlen+1,0); 870 if (!dest) return NULL; 871 872 *dest = '\0'; 873 874 while ((t = (ui_token_t *) q_deqnext(&qlist))) { 875 strcat(dest,&(t->token)); 876 KFREE(t); 877 } 878 879 return dest; 880} 881 882static void cmd_append_tokens(queue_t *qb,char *str) 883{ 884 queue_t *qq; 885 queue_t explist; 886 887 cmd_build_list(&explist,str); 888 889 while ((qq = q_deqnext(&explist))) { 890 q_enqueue(qb,qq); 891 } 892} 893 894 895 896void cmd_walk_and_expand (queue_t *qb) 897{ 898 queue_t *q; 899 queue_t newq; 900 ui_token_t *t; 901 int alias_check = TRUE; 902 int insquote = FALSE; 903 char *envstr; 904 905 q_init(&newq); 906 907 while ((t = (ui_token_t *) q_deqnext(qb))) { 908 if (t->token == '\'') { 909 alias_check = FALSE; 910 insquote = !insquote; 911 /* Check to see if we should try to expand this token */ 912 } 913 else if (!insquote) { 914 if (alias_check && !strchr(tokenbreaks,t->token) && 915 (envstr = env_getenv(&(t->token)))) { 916 /* Aliases: stick into token stream if no environment found */ 917 cmd_append_tokens(&newq,envstr); 918 KFREE(t); 919 t = NULL; 920 } 921 else if (t->token == '$') { 922 /* non-aliases: remove from token stream if no env found */ 923 envstr = env_getenv(&(t->token)+1); 924 if (envstr) cmd_append_tokens(&newq,envstr); 925 KFREE(t); 926 t = NULL; 927 } 928 else { 929 /* Drop down below, keep this token as-is and append */ 930 } 931 } 932 933 /* 934 * If token was not removed, add it to the new queue 935 */ 936 937 if (t) { 938 q_enqueue(&newq,&(t->qb)); 939 alias_check = is_command_separator(t); 940 } 941 942 } 943 944 /* 945 * Put everything back on the original list. 946 */ 947 948 while ((q = q_deqnext(&newq))) { 949 q_enqueue(qb,q); 950 } 951 952} 953 954void cmd_free_tokens(queue_t *list) 955{ 956 queue_t *q; 957 958 while ((q = q_deqnext(list))) { 959 KFREE(q); 960 } 961} 962 963