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