VIS
|
00001 00032 #include "cmdInt.h" 00033 00034 static char rcsid[] UNUSED = "$Id: cmdCmd.c,v 1.16 2005/04/16 04:23:02 fabio Exp $"; 00035 00036 /*---------------------------------------------------------------------------*/ 00037 /* Stucture declarations */ 00038 /*---------------------------------------------------------------------------*/ 00039 00049 typedef struct CommandDescrStruct { 00050 char *name; 00051 PFI command_fp; 00052 int changes_hmgr; 00053 } CommandDescr_t; 00054 00055 00056 /*---------------------------------------------------------------------------*/ 00057 /* Variable declarations */ 00058 /*---------------------------------------------------------------------------*/ 00059 Hrc_Manager_t *cmdBackupHmgr; 00060 avl_tree *cmdCommandTable; 00061 00062 static char visShellChar = '!'; /* can be reset using the "set shell_char" */ 00063 00064 static int autoexec; /* indicates currently in autoexec */ 00065 static jmp_buf env; 00066 00067 00070 /*---------------------------------------------------------------------------*/ 00071 /* Static function prototypes */ 00072 /*---------------------------------------------------------------------------*/ 00073 00074 static int com_dispatch(Hrc_Manager_t ** hmgr, int argc, char ** argv); 00075 static int apply_alias(Hrc_Manager_t ** hmgr, int * argcp, char *** argvp, int * loop); 00076 static void variableInterpolation(int *argc, char ***argv); 00077 static char * variableInterpolationRecur(char *str); 00078 static char * split_line(char * command, int * argc, char *** argv); 00079 static int check_shell_escape(char * p, int * status); 00080 static void sigterm(int sig); 00081 00085 /*---------------------------------------------------------------------------*/ 00086 /* Definition of exported functions */ 00087 /*---------------------------------------------------------------------------*/ 00088 00118 void 00119 Cmd_CommandAdd( 00120 char * name, 00121 PFI funcFp, 00122 int changes) 00123 { 00124 char *key, *value; 00125 CommandDescr_t *descr; 00126 int status; 00127 00128 key = name; 00129 if (avl_delete(cmdCommandTable, &key, &value)) { 00130 /* delete existing definition for this command */ 00131 (void) fprintf 00132 (vis_stderr, "** cmd warning: redefining '%s'\n", name); 00133 CmdCommandFree(value); 00134 } 00135 00136 descr = ALLOC(CommandDescr_t, 1); 00137 descr->name = util_strsav(name); 00138 descr->command_fp = funcFp; 00139 descr->changes_hmgr = changes; 00140 status = avl_insert(cmdCommandTable, descr->name, (char *) descr); 00141 assert(!status); /* error here in SIS version, TRS, 8/4/95 */ 00142 } 00143 00144 00158 int 00159 Cmd_CommandExecute( 00160 Hrc_Manager_t ** hmgr, 00161 char * command) 00162 { 00163 int status, argc; 00164 int loop; 00165 char *commandp, **argv; 00166 00167 (void) signal(SIGINT, SIG_IGN); 00168 commandp = command; 00169 do { 00170 if (check_shell_escape(commandp, &status)) { 00171 break; 00172 } 00173 00174 commandp = split_line(commandp, &argc, &argv); 00175 loop = 0; 00176 status = apply_alias(hmgr, &argc, &argv, &loop); 00177 if (status == 0) { 00178 00179 variableInterpolation(&argc, &argv); 00180 00181 status = com_dispatch(hmgr, argc, argv); 00182 } 00183 CmdFreeArgv(argc, argv); 00184 } while (status == 0 && *commandp != '\0'); 00185 return status; 00186 } 00187 00188 00189 00190 /*---------------------------------------------------------------------------*/ 00191 /* Definition of internal functions */ 00192 /*---------------------------------------------------------------------------*/ 00193 00194 00206 void 00207 CmdCommandFree( 00208 char * value) 00209 { 00210 CommandDescr_t *command = (CommandDescr_t *) value; 00211 00212 FREE(command->name); /* same as key */ 00213 FREE(command); 00214 } 00215 00216 00217 /*---------------------------------------------------------------------------*/ 00218 /* Definition of static functions */ 00219 /*---------------------------------------------------------------------------*/ 00220 00232 static int 00233 com_dispatch( 00234 Hrc_Manager_t ** hmgr, 00235 int argc, 00236 char ** argv) 00237 { 00238 int status; 00239 char *value; 00240 CommandDescr_t *descr; 00241 00242 if (argc == 0) { /* empty command */ 00243 return 0; 00244 } 00245 00246 if (! avl_lookup(cmdCommandTable, argv[0], &value)) { 00247 (void) fprintf(vis_stderr, "** cmd error: unknown command '%s'\n", argv[0]); 00248 return 1; 00249 } 00250 00251 descr = (CommandDescr_t *) value; 00252 if (setjmp(env)) { 00253 #if 0 00254 /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */ 00255 /* return from control-c -- restore the hmgr */ 00256 if (descr->changes_hmgr) { 00257 *hmgr = cmdBackupHmgr; 00258 cmdBackupHmgr = NIL(Hrc_Manager_t); 00259 } 00260 #endif 00261 return 1; 00262 } 00263 00264 00265 #if 0 00266 /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */ 00267 if (descr->changes_hmgr) { 00268 if (cmdBackupHmgr != NIL(Hrc_Manager_t)) { 00269 Hrc_ManagerFree(cmdBackupHmgr); 00270 } 00271 cmdBackupHmgr = hmgr_dup(*hmgr); 00272 } 00273 #endif 00274 00275 (void) signal(SIGINT, sigterm); 00276 status = (*descr->command_fp)(hmgr, argc, argv); 00277 00278 /* automatic execution of arbitrary command after each command */ 00279 /* usually this is a passive command ... */ 00280 if (status == 0 && ! autoexec) { 00281 if (avl_lookup(cmdFlagTable, "autoexec", &value)) { 00282 autoexec = 1; 00283 status = Cmd_CommandExecute(hmgr, value); 00284 autoexec = 0; 00285 } 00286 } 00287 00288 (void) signal(SIGINT, SIG_IGN); 00289 return status; 00290 } 00291 00292 00308 static int 00309 apply_alias( 00310 Hrc_Manager_t ** hmgr, 00311 int * argcp, 00312 char *** argvp, 00313 int * loop) 00314 { 00315 int i, argc, stopit, added, offset, did_subst, subst, status, newc, j; 00316 char *arg, **argv, **newv; 00317 CmdAliasDescr_t *alias; 00318 00319 argc = *argcp; 00320 argv = *argvp; 00321 stopit = 0; 00322 for(; *loop < 20; (*loop)++) { 00323 if (argc == 0) { 00324 return 0; 00325 } 00326 if (stopit != 0 || avl_lookup(cmdAliasTable, argv[0], &alias) == 0) { 00327 return 0; 00328 } 00329 if (strcmp(argv[0], alias->argv[0]) == 0) { 00330 stopit = 1; 00331 } 00332 FREE(argv[0]); 00333 added = alias->argc - 1; 00334 00335 /* shift all the arguments to the right */ 00336 if (added != 0) { 00337 argv = REALLOC(char *, argv, argc + added); 00338 for (i = argc - 1; i >= 1; i--) { 00339 argv[i + added] = argv[i]; 00340 } 00341 for (i = 1; i <= added; i++) { 00342 argv[i] = NIL(char); 00343 } 00344 argc += added; 00345 } 00346 subst = 0; 00347 for (i = 0, offset = 0; i < alias->argc; i++, offset++) { 00348 arg = CmdHistorySubstitution(alias->argv[i], &did_subst); 00349 if (arg == NIL(char)) { 00350 *argcp = argc; 00351 *argvp = argv; 00352 return(1); 00353 } 00354 if (did_subst != 0) { 00355 subst = 1; 00356 } 00357 status = 0; 00358 do { 00359 arg = split_line(arg, &newc, &newv); 00360 /* 00361 * If there's a complete `;' terminated command in `arg', 00362 * when split_line() returns arg[0] != '\0'. 00363 */ 00364 if (arg[0] == '\0') { /* just a bunch of words */ 00365 break; 00366 } 00367 status = apply_alias(hmgr, &newc, &newv, loop); 00368 if (status == 0) { 00369 status = com_dispatch(hmgr, newc, newv); 00370 } 00371 CmdFreeArgv(newc, newv); 00372 } while (status == 0); 00373 if (status != 0) { 00374 *argcp = argc; 00375 *argvp = argv; 00376 return(1); 00377 } 00378 added = newc - 1; 00379 if (added != 0) { 00380 argv = REALLOC(char *, argv, argc + added); 00381 for (j = argc - 1; j > offset; j--) { 00382 argv[j + added] = argv[j]; 00383 } 00384 argc += added; 00385 } 00386 for (j = 0; j <= added; j++) { 00387 argv[j + offset] = newv[j]; 00388 } 00389 FREE(newv); 00390 offset += added; 00391 } 00392 if (subst == 1) { 00393 for (i = offset; i < argc; i++) { 00394 FREE(argv[i]); 00395 } 00396 argc = offset; 00397 } 00398 *argcp = argc; 00399 *argvp = argv; 00400 } 00401 00402 (void) fprintf(vis_stderr, "** cmd error: alias loop\n"); 00403 return 1; 00404 } 00405 00406 00449 static void 00450 variableInterpolation(int *ori_argc, char ***ori_argv) 00451 { 00452 int i; /* to iterate through the arguments */ 00453 char *newStr; /* string returned by the expanded value */ 00454 char dollar; /* character to store reference to the variable, now '$' */ 00455 int argc; 00456 char **argv; 00457 int index; 00458 int null_string_flag; 00459 00460 argc = *ori_argc; 00461 argv = *ori_argv; 00462 00463 dollar = '$'; 00464 null_string_flag = 0; 00465 00466 /* step through all argvs */ 00467 for (i = 0; i < argc; i++) { 00468 if (strchr((char *)argv[i], (int)dollar) != NULL) { 00469 /* expanded string returned by the procedure */ 00470 newStr = variableInterpolationRecur(argv[i]); 00471 if(!strcmp(newStr, " ")) { 00472 FREE(argv[i]); 00473 /* replace old value with new */ 00474 argv[i] = 0; 00475 null_string_flag = 1; 00476 } 00477 else { 00478 FREE(argv[i]); 00479 /* replace old value with new */ 00480 argv[i] = newStr; 00481 } 00482 } 00483 } /* end of iterating through all arguments */ 00484 00485 if(null_string_flag) { 00486 *ori_argv = ALLOC(char *, argc); 00487 index = 0; 00488 for (i = 0; i < argc; i++) { 00489 if(argv[i] == 0) { 00490 (*ori_argc)--; 00491 continue; 00492 } 00493 (*ori_argv)[index++] = argv[i]; 00494 } 00495 FREE(argv); 00496 } 00497 00498 return; 00499 }/* end of variable interpolation */ 00500 00501 00529 static char * 00530 variableInterpolationRecur(char *str) 00531 { 00532 int i; /* iterators */ 00533 int findEndDollar; /* flag to denote that a $ has been found. So 00534 * search till end of variable 00535 */ 00536 int endDollarIndex; /* index in the current string of the end of the 00537 * variable 00538 */ 00539 int dollarIndex; /* index in the current string of the dollar sign */ 00540 int singleQuote; /* flag that symbolizes that a quote is started */ 00541 int doubleQuote; /* flag that symbolizes that a quote is started */ 00542 char *value; /* value of the variable that is returned by the table */ 00543 char *subStr; /* string to store the variable */ 00544 int curStrIndex; /* index to step through the current string */ 00545 int subLen; /* length of the variable */ 00546 int index; /* variable use to step through the various strings */ 00547 char *curStr; /* current string which may change as substitutions 00548 * take place 00549 */ 00550 char *newCurStr; /* new string pieced together with the expanded value */ 00551 char c; /* current character in the string */ 00552 00553 int freeNewValue; /* new value of string returned by recursion needs 00554 * to be freed. 00555 */ 00556 char dollar; /* character that stores the dollar sign */ 00557 int lastPos; /* position of the last character of the variable 00558 * in the string. 00559 */ 00560 int envVar; /* flag to say that the variable is not found in 00561 * the table, hence may be an environment variable 00562 */ 00563 00564 dollar = '$'; 00565 curStrIndex = 0; 00566 subLen = 0; 00567 findEndDollar = 0; 00568 singleQuote = 0; 00569 doubleQuote = 0; 00570 dollarIndex = -1; 00571 endDollarIndex = -1; 00572 /* make a local copy since the string may change */ 00573 curStr = ALLOC(char, strlen(str)+1); 00574 curStr = strncpy(curStr, str, strlen(str)+1); 00575 /* search through the end of string including te \0 character to detect 00576 * end of variable, if required. 00577 */ 00578 while (curStrIndex <= (int) strlen(curStr)) { 00579 /* current character */ 00580 c = curStr[curStrIndex]; 00581 /* redundant here since split_line already strips out the quotes */ 00582 if ((c == '\"') || (c == '\'')) { 00583 /* also termination charactrers for $ */ 00584 /* set flags for quote found */ 00585 singleQuote = !singleQuote; 00586 doubleQuote = !doubleQuote; 00587 /* also a variable termination */ 00588 if (findEndDollar) { 00589 findEndDollar = 0; 00590 endDollarIndex = curStrIndex; 00591 } 00592 } 00593 /* detect a $ if not within quotes */ 00594 if ((c == '$') && (!singleQuote) && (!doubleQuote)) { 00595 if (findEndDollar == 1) { 00596 error_append("Cannot have nested $ signs, not found termination\n"); 00597 break; 00598 } 00599 /* note the beginning of the dollar position */ 00600 dollarIndex = curStrIndex; 00601 /* start quest for end of dollar */ 00602 findEndDollar = 1; 00603 endDollarIndex = -1; 00604 } 00605 /* termination characters are \0, :, / when not within quotes. 00606 * Although, some of these may never be encountered 00607 * since this is called after split_line and apply_alias 00608 * Termination characters except '\0' are ignored within quotes 00609 */ 00610 if ((findEndDollar) && 00611 ((c == '\0') || 00612 ((!singleQuote) && (!doubleQuote) && 00613 ((c == ':') || (c == '/'))))) { 00614 /* if (((c == '\n') || (c == '\t') || (isspace(c)) || 00615 (c == ':') || (c == ';') || (c == '\0') || 00616 (c == '#') || (c == '/')) && (findEndDollar)) { */ 00617 findEndDollar = 0; 00618 endDollarIndex = curStrIndex; 00619 } /* end of find termination characters */ 00620 00621 /* found the interpolation variable and its end*/ 00622 if (!findEndDollar && (endDollarIndex != -1)) { 00623 /* found an interpolation variable */ 00624 subLen = 0; 00625 freeNewValue = 0; 00626 envVar = 0; 00627 subStr = NULL; 00628 if (endDollarIndex > (dollarIndex +1)) { 00629 /* if not empty string */ 00630 subStr = ALLOC(char, endDollarIndex - dollarIndex); 00631 /* copy the variable into another string */ 00632 for ( i = 0; i < endDollarIndex - dollarIndex - 1; i++) { 00633 subStr[i] = curStr[dollarIndex+1+i]; 00634 } 00635 subStr[i] = '\0'; 00636 /* quiet if of the form var$:iable or var$foo:iable and 00637 * $foo not in flag table 00638 */ 00639 if (avl_lookup(cmdFlagTable, subStr, (char **)&value) != 0) { 00640 /* found the variable in the alias table */ 00641 if (strchr((char *)value, (int)dollar) != NULL) { 00642 /* if more $s in the value */ 00643 value = variableInterpolationRecur(value); 00644 subLen = strlen(value); 00645 /* to be freed later since variableInterpolationRecur 00646 * returns a new string to be freed later. 00647 */ 00648 freeNewValue = 1; 00649 00650 } else { 00651 /* if no dollars in the value, substitute the return value 00652 * in the string 00653 */ 00654 subLen = strlen(value); 00655 } 00656 } else { 00657 /* if the variable is not found, it might be an 00658 * environment variable and so keep it. This might be 00659 * a hazard for bogus variables but that is upto the user. 00660 */ 00661 value = subStr; 00662 /* for environment variable keep the $ sign */ 00663 subLen = strlen(value) +1; 00664 envVar = 1; 00665 } 00666 00667 } /* end of interpolation variable not trivial */ 00668 /* prefix + strlen(substituted value) + suffix */ 00669 newCurStr = ALLOC(char, dollarIndex + 00670 subLen + 00671 strlen(curStr) - endDollarIndex + 1); 00672 00673 00674 00675 /* copy prefix */ 00676 newCurStr = strncpy(newCurStr, curStr, dollarIndex); 00677 i = dollarIndex; 00678 if (subLen) { 00679 /* copy substituted value */ 00680 if (envVar) { 00681 /* if it is an environment variable, keep the $ sign */ 00682 newCurStr[i++] = '$'; 00683 } 00684 index = 0; 00685 while (value[index] != '\0') { 00686 newCurStr[i++] = value[index++]; 00687 } 00688 if (freeNewValue) { 00689 FREE(value); 00690 } 00691 } 00692 /* freed here cos value might be subStr in one case */ 00693 if (subStr != NULL) { 00694 FREE(subStr); 00695 } 00696 /* copy suffix */ 00697 index = endDollarIndex; 00698 /* figure out where to start the next search */ 00699 lastPos = i; 00700 while (curStr[index] != '\0') { 00701 newCurStr[i++] = curStr[index++]; 00702 } 00703 newCurStr[i] = '\0'; 00704 FREE(curStr); 00705 curStr = newCurStr; 00706 /* reset counter for further search. Due to recursive calling of this 00707 * function eventually, the value that is substituted will not have a $ 00708 */ 00709 curStrIndex = lastPos; 00710 dollarIndex = -1; 00711 endDollarIndex = -1; 00712 /* end of found a variable */ 00713 } else { /* if a variable is not found, keep going */ 00714 curStrIndex++; 00715 } 00716 } /* end of stepping through the string */ 00717 return(curStr); 00718 } /* end of variableInterpolationRecur */ 00719 00720 00721 00733 static char * 00734 split_line( 00735 char * command, 00736 int * argc, 00737 char *** argv) 00738 { 00739 register char *p, *start, c; 00740 register int i, j; 00741 register char *new_arg; 00742 array_t *argv_array; 00743 int single_quote, double_quote; 00744 00745 argv_array = array_alloc(char *, 5); 00746 00747 p = command; 00748 for(;;) { 00749 /* skip leading white space */ 00750 while (isspace((int)(*p))) { 00751 p++; 00752 } 00753 00754 /* skip until end of this token */ 00755 single_quote = double_quote = 0; 00756 for(start = p; (c = *p) != '\0'; p++) { 00757 if (c == ';' || c == '#' || isspace((int)c)) { 00758 if (! single_quote && ! double_quote) { 00759 break; 00760 } 00761 } 00762 if (c == '\'') { 00763 single_quote = ! single_quote; 00764 } 00765 if (c == '"') { 00766 double_quote = ! double_quote; 00767 } 00768 } 00769 if (single_quote || double_quote) { 00770 (void) fprintf(vis_stderr, "** cmd warning: ignoring unbalanced quote ...\n"); 00771 } 00772 if (start == p) break; 00773 00774 new_arg = ALLOC(char, p - start + 1); 00775 j = 0; 00776 for(i = 0; i < p - start; i++) { 00777 c = start[i]; 00778 if ((c != '\'') && (c != '\"')) { 00779 new_arg[j++] = isspace((int)c) ? ' ' : start[i]; 00780 } 00781 } 00782 new_arg[j] = '\0'; 00783 array_insert_last(char *, argv_array, new_arg); 00784 } 00785 00786 *argc = array_n(argv_array); 00787 *argv = array_data(char *, argv_array); 00788 array_free(argv_array); 00789 if (*p == ';') { 00790 p++; 00791 } 00792 else if (*p == '#') { 00793 for(; *p != 0; p++) ; /* skip to end of line */ 00794 } 00795 return p; 00796 } 00797 00798 00810 static int 00811 check_shell_escape( 00812 char * p, 00813 int * status) 00814 { 00815 char *value; 00816 while (isspace((int)(*p))) { 00817 p++; 00818 } 00819 if ((value = Cmd_FlagReadByName("shell_char")) != NIL(char)){ 00820 visShellChar = *value; 00821 } 00822 if (*p == visShellChar) { 00823 *status = system(p+1); 00824 return 1; 00825 } 00826 return 0; 00827 } 00828 00838 static void 00839 sigterm(int sig) 00840 { 00841 (void) signal(SIGINT, SIG_IGN); /* ignore further ctl-c */ 00842 (void)fprintf(vis_stderr, "\n"); 00843 (void)fprintf(vis_stderr, 00844 "** cmd warning : data may be corrupted due to CTRL-c.\n"); 00845 (void)fprintf(vis_stderr, 00846 " It may cause abnormal termination.\n"); 00847 longjmp(env, 1); 00848 }