VIS

src/cmd/cmdCmd.c

Go to the documentation of this file.
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 }