| 1 | /**CFile*********************************************************************** | 
|---|
| 2 |  | 
|---|
| 3 |   FileName    [cmdCmd.c] | 
|---|
| 4 |  | 
|---|
| 5 |   PackageName [cmd] | 
|---|
| 6 |  | 
|---|
| 7 |   Synopsis    [Command table and command execution.] | 
|---|
| 8 |  | 
|---|
| 9 |   Author      [Originated from SIS] | 
|---|
| 10 |  | 
|---|
| 11 |   Copyright   [Copyright (c) 1994-1996 The Regents of the Univ. of California. | 
|---|
| 12 |   All rights reserved. | 
|---|
| 13 |  | 
|---|
| 14 |   Permission is hereby granted, without written agreement and without license | 
|---|
| 15 |   or royalty fees, to use, copy, modify, and distribute this software and its | 
|---|
| 16 |   documentation for any purpose, provided that the above copyright notice and | 
|---|
| 17 |   the following two paragraphs appear in all copies of this software. | 
|---|
| 18 |  | 
|---|
| 19 |   IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR | 
|---|
| 20 |   DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT | 
|---|
| 21 |   OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF | 
|---|
| 22 |   CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|---|
| 23 |  | 
|---|
| 24 |   THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, | 
|---|
| 25 |   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND | 
|---|
| 26 |   FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN | 
|---|
| 27 |   "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE | 
|---|
| 28 |   MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.] | 
|---|
| 29 |  | 
|---|
| 30 | ******************************************************************************/ | 
|---|
| 31 |  | 
|---|
| 32 | #include "cmdInt.h" | 
|---|
| 33 |  | 
|---|
| 34 | static char rcsid[] UNUSED = "$Id: cmdCmd.c,v 1.16 2005/04/16 04:23:02 fabio Exp $"; | 
|---|
| 35 |  | 
|---|
| 36 | /*---------------------------------------------------------------------------*/ | 
|---|
| 37 | /* Stucture declarations                                                     */ | 
|---|
| 38 | /*---------------------------------------------------------------------------*/ | 
|---|
| 39 |  | 
|---|
| 40 | /**Struct********************************************************************** | 
|---|
| 41 |  | 
|---|
| 42 |   Synopsis    [required] | 
|---|
| 43 |  | 
|---|
| 44 |   Description [optional] | 
|---|
| 45 |  | 
|---|
| 46 |   SeeAlso     [optional] | 
|---|
| 47 |  | 
|---|
| 48 | ******************************************************************************/ | 
|---|
| 49 | typedef struct CommandDescrStruct { | 
|---|
| 50 |   char *name; | 
|---|
| 51 |   PFI command_fp; | 
|---|
| 52 |   int changes_hmgr; | 
|---|
| 53 | } CommandDescr_t; | 
|---|
| 54 |  | 
|---|
| 55 |  | 
|---|
| 56 | /*---------------------------------------------------------------------------*/ | 
|---|
| 57 | /* Variable declarations                                                     */ | 
|---|
| 58 | /*---------------------------------------------------------------------------*/ | 
|---|
| 59 | Hrc_Manager_t *cmdBackupHmgr; | 
|---|
| 60 | avl_tree *cmdCommandTable; | 
|---|
| 61 |  | 
|---|
| 62 | static char visShellChar = '!';      /* can be reset using the "set shell_char" */ | 
|---|
| 63 |  | 
|---|
| 64 | static int autoexec;            /* indicates currently in autoexec */ | 
|---|
| 65 | static jmp_buf env; | 
|---|
| 66 |  | 
|---|
| 67 |  | 
|---|
| 68 | /**AutomaticStart*************************************************************/ | 
|---|
| 69 |  | 
|---|
| 70 | /*---------------------------------------------------------------------------*/ | 
|---|
| 71 | /* Static function prototypes                                                */ | 
|---|
| 72 | /*---------------------------------------------------------------------------*/ | 
|---|
| 73 |  | 
|---|
| 74 | static int com_dispatch(Hrc_Manager_t ** hmgr, int argc, char ** argv); | 
|---|
| 75 | static int apply_alias(Hrc_Manager_t ** hmgr, int * argcp, char *** argvp, int * loop); | 
|---|
| 76 | static void variableInterpolation(int *argc, char ***argv); | 
|---|
| 77 | static char * variableInterpolationRecur(char *str); | 
|---|
| 78 | static char * split_line(char * command, int * argc, char *** argv); | 
|---|
| 79 | static int check_shell_escape(char * p, int * status); | 
|---|
| 80 | static void sigterm(int sig); | 
|---|
| 81 |  | 
|---|
| 82 | /**AutomaticEnd***************************************************************/ | 
|---|
| 83 |  | 
|---|
| 84 |  | 
|---|
| 85 | /*---------------------------------------------------------------------------*/ | 
|---|
| 86 | /* Definition of exported functions                                          */ | 
|---|
| 87 | /*---------------------------------------------------------------------------*/ | 
|---|
| 88 |  | 
|---|
| 89 | /**Function******************************************************************** | 
|---|
| 90 |  | 
|---|
| 91 |   Synopsis    [Adds a command to the command table.] | 
|---|
| 92 |  | 
|---|
| 93 |   Description [Adds a command to the command table.  If name already defines | 
|---|
| 94 |   an existing command, its definition is replaced.  FuncFp is a function | 
|---|
| 95 |   pointer to code of the form: <p> | 
|---|
| 96 |  | 
|---|
| 97 |                 int <br> | 
|---|
| 98 |                 CommandTest(hmgr, argc, argv)<br> | 
|---|
| 99 |                   Hrc_Manager_t **hmgr;<br> | 
|---|
| 100 |                   int argc;<br> | 
|---|
| 101 |                   char **argv;<br> | 
|---|
| 102 |                 {<br> | 
|---|
| 103 |                     return 0;<br> | 
|---|
| 104 |                 }<p> | 
|---|
| 105 |  | 
|---|
| 106 |   Note the double de-reference on the hmgr which is passed to the command; | 
|---|
| 107 |   this allows the command to replace the current hmgr.  argv\[0\] will generally | 
|---|
| 108 |   be the command name, and argv\[1\] ... argv\[argc-1\] are the arguments for the | 
|---|
| 109 |   command.  util_getopt() can be used to parse the arguments, but | 
|---|
| 110 |   util_getopt_reset() must be used before calling util_getopt().  The command | 
|---|
| 111 |   function should return 0 for normal operation, 1 for any error.  The changes | 
|---|
| 112 |   flag is used to automatically save the hmgr before executing the command (in | 
|---|
| 113 |   order to support undo).] | 
|---|
| 114 |  | 
|---|
| 115 |   SideEffects [] | 
|---|
| 116 |  | 
|---|
| 117 | ******************************************************************************/ | 
|---|
| 118 | void | 
|---|
| 119 | Cmd_CommandAdd( | 
|---|
| 120 |   char * name, | 
|---|
| 121 |   PFI  funcFp, | 
|---|
| 122 |   int  changes) | 
|---|
| 123 | { | 
|---|
| 124 |   char *key, *value; | 
|---|
| 125 |   CommandDescr_t *descr; | 
|---|
| 126 |   int status; | 
|---|
| 127 |  | 
|---|
| 128 |   key = name; | 
|---|
| 129 |   if (avl_delete(cmdCommandTable, &key, &value)) { | 
|---|
| 130 |     /* delete existing definition for this command */ | 
|---|
| 131 |     (void) fprintf | 
|---|
| 132 |       (vis_stderr, "** cmd warning: redefining '%s'\n", name); | 
|---|
| 133 |     CmdCommandFree(value); | 
|---|
| 134 |   } | 
|---|
| 135 |  | 
|---|
| 136 |   descr = ALLOC(CommandDescr_t, 1); | 
|---|
| 137 |   descr->name = util_strsav(name); | 
|---|
| 138 |   descr->command_fp = funcFp; | 
|---|
| 139 |   descr->changes_hmgr = changes; | 
|---|
| 140 |   status = avl_insert(cmdCommandTable, descr->name, (char *) descr); | 
|---|
| 141 |   assert(!status);  /* error here in SIS version, TRS, 8/4/95 */ | 
|---|
| 142 | } | 
|---|
| 143 |  | 
|---|
| 144 |  | 
|---|
| 145 | /**Function******************************************************************** | 
|---|
| 146 |  | 
|---|
| 147 |   Synopsis    [Executes a command line.] | 
|---|
| 148 |  | 
|---|
| 149 |   Description [Executes a command line.  This is the top-level of the command | 
|---|
| 150 |   interpreter, and supports multiple commands (separated by ;), alias | 
|---|
| 151 |   substitution, etc.  For many simple operations, Cmd_CommandExecute() is the | 
|---|
| 152 |   easiest way to accomplish a given task. For example, to set a variable, use | 
|---|
| 153 |   the code: Cmd_CommandExecute(&hmgr, "set color blue").] | 
|---|
| 154 |  | 
|---|
| 155 |   SideEffects [] | 
|---|
| 156 |  | 
|---|
| 157 | ******************************************************************************/ | 
|---|
| 158 | int | 
|---|
| 159 | Cmd_CommandExecute( | 
|---|
| 160 |   Hrc_Manager_t ** hmgr, | 
|---|
| 161 |   char * command) | 
|---|
| 162 | { | 
|---|
| 163 |   int status, argc; | 
|---|
| 164 |   int loop; | 
|---|
| 165 |   char *commandp, **argv; | 
|---|
| 166 |  | 
|---|
| 167 |   (void) signal(SIGINT, SIG_IGN); | 
|---|
| 168 |   commandp = command; | 
|---|
| 169 |   do { | 
|---|
| 170 |     if (check_shell_escape(commandp, &status)) { | 
|---|
| 171 |       break; | 
|---|
| 172 |     } | 
|---|
| 173 |      | 
|---|
| 174 |     commandp = split_line(commandp, &argc, &argv); | 
|---|
| 175 |     loop = 0; | 
|---|
| 176 |     status = apply_alias(hmgr, &argc, &argv, &loop); | 
|---|
| 177 |     if (status == 0) { | 
|---|
| 178 |  | 
|---|
| 179 |       variableInterpolation(&argc, &argv); | 
|---|
| 180 |  | 
|---|
| 181 |       status = com_dispatch(hmgr, argc, argv); | 
|---|
| 182 |     } | 
|---|
| 183 |     CmdFreeArgv(argc, argv); | 
|---|
| 184 |   } while (status == 0 && *commandp != '\0'); | 
|---|
| 185 |   return status; | 
|---|
| 186 | } | 
|---|
| 187 |  | 
|---|
| 188 |  | 
|---|
| 189 |  | 
|---|
| 190 | /*---------------------------------------------------------------------------*/ | 
|---|
| 191 | /* Definition of internal functions                                          */ | 
|---|
| 192 | /*---------------------------------------------------------------------------*/ | 
|---|
| 193 |  | 
|---|
| 194 |  | 
|---|
| 195 | /**Function******************************************************************** | 
|---|
| 196 |  | 
|---|
| 197 |   Synopsis    [required] | 
|---|
| 198 |  | 
|---|
| 199 |   Description [optional] | 
|---|
| 200 |  | 
|---|
| 201 |   SideEffects [required] | 
|---|
| 202 |  | 
|---|
| 203 |   SeeAlso     [optional] | 
|---|
| 204 |  | 
|---|
| 205 | ******************************************************************************/ | 
|---|
| 206 | void | 
|---|
| 207 | CmdCommandFree( | 
|---|
| 208 |   char * value) | 
|---|
| 209 | { | 
|---|
| 210 |   CommandDescr_t *command = (CommandDescr_t *) value; | 
|---|
| 211 |  | 
|---|
| 212 |   FREE(command->name);          /* same as key */ | 
|---|
| 213 |   FREE(command); | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 |  | 
|---|
| 217 | /*---------------------------------------------------------------------------*/ | 
|---|
| 218 | /* Definition of static functions                                            */ | 
|---|
| 219 | /*---------------------------------------------------------------------------*/ | 
|---|
| 220 |  | 
|---|
| 221 | /**Function******************************************************************** | 
|---|
| 222 |  | 
|---|
| 223 |   Synopsis    [required] | 
|---|
| 224 |  | 
|---|
| 225 |   Description [optional] | 
|---|
| 226 |  | 
|---|
| 227 |   SideEffects [required] | 
|---|
| 228 |  | 
|---|
| 229 |   SeeAlso     [optional] | 
|---|
| 230 |  | 
|---|
| 231 | ******************************************************************************/ | 
|---|
| 232 | static int | 
|---|
| 233 | com_dispatch( | 
|---|
| 234 |   Hrc_Manager_t ** hmgr, | 
|---|
| 235 |   int  argc, | 
|---|
| 236 |   char ** argv) | 
|---|
| 237 | { | 
|---|
| 238 |   int status; | 
|---|
| 239 |   char *value; | 
|---|
| 240 |   CommandDescr_t *descr; | 
|---|
| 241 |  | 
|---|
| 242 |   if (argc == 0) {              /* empty command */ | 
|---|
| 243 |     return 0; | 
|---|
| 244 |   } | 
|---|
| 245 |  | 
|---|
| 246 |   if (! avl_lookup(cmdCommandTable, argv[0], &value)) { | 
|---|
| 247 |     (void) fprintf(vis_stderr, "** cmd error: unknown command '%s'\n", argv[0]); | 
|---|
| 248 |     return 1; | 
|---|
| 249 |   } | 
|---|
| 250 |  | 
|---|
| 251 |   descr = (CommandDescr_t *) value; | 
|---|
| 252 |   if (setjmp(env)) { | 
|---|
| 253 | #if 0 | 
|---|
| 254 |     /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */ | 
|---|
| 255 |     /* return from control-c -- restore the hmgr */ | 
|---|
| 256 |     if (descr->changes_hmgr) { | 
|---|
| 257 |       *hmgr = cmdBackupHmgr; | 
|---|
| 258 |       cmdBackupHmgr = NIL(Hrc_Manager_t); | 
|---|
| 259 |     } | 
|---|
| 260 | #endif | 
|---|
| 261 |     return 1; | 
|---|
| 262 |   } | 
|---|
| 263 |  | 
|---|
| 264 |    | 
|---|
| 265 | #if 0 | 
|---|
| 266 |   /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */ | 
|---|
| 267 |   if (descr->changes_hmgr) { | 
|---|
| 268 |     if (cmdBackupHmgr != NIL(Hrc_Manager_t)) { | 
|---|
| 269 |       Hrc_ManagerFree(cmdBackupHmgr); | 
|---|
| 270 |     } | 
|---|
| 271 |     cmdBackupHmgr = hmgr_dup(*hmgr); | 
|---|
| 272 |   } | 
|---|
| 273 | #endif | 
|---|
| 274 |    | 
|---|
| 275 |   (void) signal(SIGINT, sigterm); | 
|---|
| 276 |   status = (*descr->command_fp)(hmgr, argc, argv); | 
|---|
| 277 |  | 
|---|
| 278 |   /* automatic execution of arbitrary command after each command */ | 
|---|
| 279 |   /* usually this is a passive command ... */ | 
|---|
| 280 |   if (status == 0 && ! autoexec) { | 
|---|
| 281 |     if (avl_lookup(cmdFlagTable, "autoexec", &value)) { | 
|---|
| 282 |       autoexec = 1; | 
|---|
| 283 |       status = Cmd_CommandExecute(hmgr, value); | 
|---|
| 284 |       autoexec = 0; | 
|---|
| 285 |     } | 
|---|
| 286 |   } | 
|---|
| 287 |  | 
|---|
| 288 |   (void) signal(SIGINT, SIG_IGN); | 
|---|
| 289 |   return status; | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 |  | 
|---|
| 293 | /**Function******************************************************************** | 
|---|
| 294 |  | 
|---|
| 295 |   Synopsis    [required] | 
|---|
| 296 |  | 
|---|
| 297 |   Description [Applies alias.  If perform a history substitution in expanding | 
|---|
| 298 |   an alias, remove all the orginal trailing arguments.  For example:<p> | 
|---|
| 299 |  | 
|---|
| 300 |     > alias t rl \!:1<br> | 
|---|
| 301 |     > t lion.blif  would otherwise expand to   rl lion.blif lion.blif <br>] | 
|---|
| 302 |  | 
|---|
| 303 |   SideEffects [required] | 
|---|
| 304 |  | 
|---|
| 305 |   SeeAlso     [optional] | 
|---|
| 306 |  | 
|---|
| 307 | ******************************************************************************/ | 
|---|
| 308 | static int | 
|---|
| 309 | apply_alias( | 
|---|
| 310 |   Hrc_Manager_t ** hmgr, | 
|---|
| 311 |   int * argcp, | 
|---|
| 312 |   char *** argvp, | 
|---|
| 313 |   int * loop) | 
|---|
| 314 | { | 
|---|
| 315 |   int i, argc, stopit, added, offset, did_subst, subst, status, newc, j; | 
|---|
| 316 |   char *arg, **argv, **newv; | 
|---|
| 317 |   CmdAliasDescr_t *alias; | 
|---|
| 318 |  | 
|---|
| 319 |   argc = *argcp; | 
|---|
| 320 |   argv = *argvp; | 
|---|
| 321 |   stopit = 0; | 
|---|
| 322 |   for(; *loop < 20; (*loop)++) { | 
|---|
| 323 |     if (argc == 0) { | 
|---|
| 324 |       return 0; | 
|---|
| 325 |     } | 
|---|
| 326 |     if (stopit != 0 || avl_lookup(cmdAliasTable, argv[0], &alias) == 0) { | 
|---|
| 327 |       return 0; | 
|---|
| 328 |     } | 
|---|
| 329 |     if (strcmp(argv[0], alias->argv[0]) == 0) { | 
|---|
| 330 |       stopit = 1; | 
|---|
| 331 |     } | 
|---|
| 332 |     FREE(argv[0]); | 
|---|
| 333 |     added = alias->argc - 1; | 
|---|
| 334 |  | 
|---|
| 335 |     /* shift all the arguments to the right */ | 
|---|
| 336 |     if (added != 0) { | 
|---|
| 337 |       argv = REALLOC(char *, argv, argc + added); | 
|---|
| 338 |       for (i = argc - 1; i >= 1; i--) { | 
|---|
| 339 |         argv[i + added] = argv[i]; | 
|---|
| 340 |       } | 
|---|
| 341 |       for (i = 1; i <= added; i++) { | 
|---|
| 342 |         argv[i] = NIL(char); | 
|---|
| 343 |       } | 
|---|
| 344 |       argc += added; | 
|---|
| 345 |     } | 
|---|
| 346 |     subst = 0; | 
|---|
| 347 |     for (i = 0, offset = 0; i < alias->argc; i++, offset++) { | 
|---|
| 348 |       arg = CmdHistorySubstitution(alias->argv[i], &did_subst); | 
|---|
| 349 |       if (arg == NIL(char)) { | 
|---|
| 350 |         *argcp = argc; | 
|---|
| 351 |         *argvp = argv; | 
|---|
| 352 |         return(1); | 
|---|
| 353 |       } | 
|---|
| 354 |       if (did_subst != 0) { | 
|---|
| 355 |         subst = 1; | 
|---|
| 356 |       } | 
|---|
| 357 |       status = 0; | 
|---|
| 358 |       do { | 
|---|
| 359 |         arg = split_line(arg, &newc, &newv); | 
|---|
| 360 |         /* | 
|---|
| 361 |          * If there's a complete `;' terminated command in `arg', | 
|---|
| 362 |          * when split_line() returns arg[0] != '\0'. | 
|---|
| 363 |          */ | 
|---|
| 364 |         if (arg[0] == '\0') {   /* just a bunch of words */ | 
|---|
| 365 |           break; | 
|---|
| 366 |         } | 
|---|
| 367 |         status = apply_alias(hmgr, &newc, &newv, loop); | 
|---|
| 368 |         if (status == 0) { | 
|---|
| 369 |           status = com_dispatch(hmgr, newc, newv); | 
|---|
| 370 |         } | 
|---|
| 371 |         CmdFreeArgv(newc, newv); | 
|---|
| 372 |       } while (status == 0); | 
|---|
| 373 |       if (status != 0) { | 
|---|
| 374 |         *argcp = argc; | 
|---|
| 375 |         *argvp = argv; | 
|---|
| 376 |         return(1); | 
|---|
| 377 |       } | 
|---|
| 378 |       added = newc - 1; | 
|---|
| 379 |       if (added != 0) { | 
|---|
| 380 |         argv = REALLOC(char *, argv, argc + added); | 
|---|
| 381 |         for (j = argc - 1; j > offset; j--) { | 
|---|
| 382 |           argv[j + added] = argv[j]; | 
|---|
| 383 |         } | 
|---|
| 384 |         argc += added; | 
|---|
| 385 |       } | 
|---|
| 386 |       for (j = 0; j <= added; j++) { | 
|---|
| 387 |         argv[j + offset] = newv[j]; | 
|---|
| 388 |       } | 
|---|
| 389 |       FREE(newv); | 
|---|
| 390 |       offset += added; | 
|---|
| 391 |     } | 
|---|
| 392 |     if (subst == 1) { | 
|---|
| 393 |       for (i = offset; i < argc; i++) { | 
|---|
| 394 |         FREE(argv[i]); | 
|---|
| 395 |       } | 
|---|
| 396 |       argc = offset; | 
|---|
| 397 |     } | 
|---|
| 398 |     *argcp = argc; | 
|---|
| 399 |     *argvp = argv; | 
|---|
| 400 |   } | 
|---|
| 401 |  | 
|---|
| 402 |   (void) fprintf(vis_stderr, "** cmd error: alias loop\n"); | 
|---|
| 403 |   return 1; | 
|---|
| 404 | } | 
|---|
| 405 |  | 
|---|
| 406 |  | 
|---|
| 407 | /**Function******************************************************************** | 
|---|
| 408 |  | 
|---|
| 409 |   Synopsis    [Allows interpolation of variables] | 
|---|
| 410 |  | 
|---|
| 411 |   Description [Allows interpolation of variables. Here it is implemented by | 
|---|
| 412 |   allowing variables to be referred to with the prefix of '$'. The variables | 
|---|
| 413 |   are set using the "set" command. So for example, the following can be done <p> | 
|---|
| 414 |  | 
|---|
| 415 |   <code> | 
|---|
| 416 |   vis> set foo bar <br> | 
|---|
| 417 |   vis> echo $foo <br> | 
|---|
| 418 |   bar <br> | 
|---|
| 419 |   </code> | 
|---|
| 420 |    | 
|---|
| 421 |   The last line "bar" will the output produced by vis. | 
|---|
| 422 |  | 
|---|
| 423 |   The following can also be done: <p> | 
|---|
| 424 |    | 
|---|
| 425 |   <code> | 
|---|
| 426 |   vis> set foo $foo:foobar <br> | 
|---|
| 427 |   vis> echo $foobar <br> | 
|---|
| 428 |   bar:foobar <br> | 
|---|
| 429 |   </code> | 
|---|
| 430 |   The last line will be the output produced by vis. <p> | 
|---|
| 431 |  | 
|---|
| 432 |   These variables can | 
|---|
| 433 |   be used in recursive definitions. The following termination characters are | 
|---|
| 434 |   recognized for the variables \\n, \\0, ' ', \\t,  :,  ;,  #,  /. | 
|---|
| 435 |  | 
|---|
| 436 |   Although the set command allows the usage of the some of the | 
|---|
| 437 |   above termination characters between quotes,  | 
|---|
| 438 |   the variable interpolation procedure has the restriction | 
|---|
| 439 |   that the two characters ':' and '/' may not be used with quotes. | 
|---|
| 440 |   A variable with spaces in it may be used only if it is enclosed | 
|---|
| 441 |   within quotes. ] | 
|---|
| 442 |  | 
|---|
| 443 |   SideEffects [required] | 
|---|
| 444 |  | 
|---|
| 445 |   SeeAlso     [optional] | 
|---|
| 446 |  | 
|---|
| 447 | ******************************************************************************/ | 
|---|
| 448 |  | 
|---|
| 449 | static void | 
|---|
| 450 | variableInterpolation(int *ori_argc, char ***ori_argv) | 
|---|
| 451 | { | 
|---|
| 452 |   int i;          /* to iterate through the arguments */ | 
|---|
| 453 |   char *newStr;   /* string returned by the expanded value */ | 
|---|
| 454 |   char dollar;    /* character to store reference to the variable, now '$' */ | 
|---|
| 455 |   int argc; | 
|---|
| 456 |   char **argv; | 
|---|
| 457 |   int index; | 
|---|
| 458 |   int null_string_flag; | 
|---|
| 459 |  | 
|---|
| 460 |   argc = *ori_argc; | 
|---|
| 461 |   argv = *ori_argv; | 
|---|
| 462 |  | 
|---|
| 463 |   dollar = '$'; | 
|---|
| 464 |   null_string_flag = 0; | 
|---|
| 465 |  | 
|---|
| 466 |   /* step through all argvs */ | 
|---|
| 467 |   for (i = 0; i < argc; i++) { | 
|---|
| 468 |     if (strchr((char *)argv[i], (int)dollar) != NULL) { | 
|---|
| 469 |       /* expanded string returned by the procedure */ | 
|---|
| 470 |       newStr = variableInterpolationRecur(argv[i]); | 
|---|
| 471 |       if(!strcmp(newStr, " ")) { | 
|---|
| 472 |         FREE(argv[i]); | 
|---|
| 473 |         /* replace old value with new */ | 
|---|
| 474 |         argv[i] = 0; | 
|---|
| 475 |         null_string_flag = 1; | 
|---|
| 476 |       } | 
|---|
| 477 |       else { | 
|---|
| 478 |         FREE(argv[i]); | 
|---|
| 479 |         /* replace old value with new */ | 
|---|
| 480 |         argv[i] = newStr; | 
|---|
| 481 |       } | 
|---|
| 482 |     } | 
|---|
| 483 |   } /* end of iterating through all arguments */ | 
|---|
| 484 |  | 
|---|
| 485 |   if(null_string_flag) { | 
|---|
| 486 |     *ori_argv = ALLOC(char *, argc); | 
|---|
| 487 |     index = 0; | 
|---|
| 488 |     for (i = 0; i < argc; i++) { | 
|---|
| 489 |       if(argv[i] == 0) { | 
|---|
| 490 |         (*ori_argc)--; | 
|---|
| 491 |         continue; | 
|---|
| 492 |       } | 
|---|
| 493 |       (*ori_argv)[index++] = argv[i]; | 
|---|
| 494 |     } | 
|---|
| 495 |     FREE(argv); | 
|---|
| 496 |   } | 
|---|
| 497 |  | 
|---|
| 498 |   return; | 
|---|
| 499 | }/* end of variable interpolation */ | 
|---|
| 500 |  | 
|---|
| 501 |  | 
|---|
| 502 | /**Function******************************************************************** | 
|---|
| 503 |  | 
|---|
| 504 |   Synopsis    [Recursive procedure that expands the interpolation variables] | 
|---|
| 505 |  | 
|---|
| 506 |   Description [Recursive procedure that expands the interpolation variables. | 
|---|
| 507 |   This procedure is designed to handle multiple occurrences of variables | 
|---|
| 508 |   in a string and recursive definitions. If the expanded variable has another | 
|---|
| 509 |   variable, then the procedure is called recursively. The existence of a | 
|---|
| 510 |   variable is identified by the $ sign in the string. But since this may be | 
|---|
| 511 |   an environment variable too, the variable is untouched if not found in | 
|---|
| 512 |   this table. A sophisticated check can be made to see if this variable | 
|---|
| 513 |   exists in the environment, but it is NOT done here. Therefore, detection | 
|---|
| 514 |   of bogus values cannot be done. The procedure steps through the string | 
|---|
| 515 |   to see if any variables are present. If a termination character (one of | 
|---|
| 516 |   :, /) is found after the '$', then the variable | 
|---|
| 517 |   is identified and looked up in the flag table. If the returned string again | 
|---|
| 518 |   has a dollar, then the procedure is called recursively. If not, the returned | 
|---|
| 519 |   value replaces the variable and the stepping through continues. If the | 
|---|
| 520 |   variable is not found, then it might be an environment variable.So the | 
|---|
| 521 |   procedure leaves the variable there. ] | 
|---|
| 522 |  | 
|---|
| 523 |   SideEffects [required] | 
|---|
| 524 |  | 
|---|
| 525 |   SeeAlso     [optional] | 
|---|
| 526 |  | 
|---|
| 527 | ******************************************************************************/ | 
|---|
| 528 |  | 
|---|
| 529 | static char * | 
|---|
| 530 | variableInterpolationRecur(char *str) | 
|---|
| 531 | { | 
|---|
| 532 |   int i;               /* iterators */ | 
|---|
| 533 |   int findEndDollar;   /* flag to denote that a $ has been found. So | 
|---|
| 534 |                         * search till end of variable | 
|---|
| 535 |                         */ | 
|---|
| 536 |   int endDollarIndex;  /* index in the current string of the end of the | 
|---|
| 537 |                         * variable | 
|---|
| 538 |                         */ | 
|---|
| 539 |   int dollarIndex;     /* index in the current string of the dollar sign */   | 
|---|
| 540 |   int singleQuote;     /* flag that symbolizes that a quote is started */  | 
|---|
| 541 |   int doubleQuote;     /* flag that symbolizes that a quote is started */ | 
|---|
| 542 |   char *value;         /* value of the variable that is returned by the table */ | 
|---|
| 543 |   char *subStr;        /* string to store the variable */ | 
|---|
| 544 |   int curStrIndex;     /* index to step through the current string */ | 
|---|
| 545 |   int subLen;          /* length of the variable */ | 
|---|
| 546 |   int index;           /* variable use to step through the various strings */ | 
|---|
| 547 |   char *curStr;        /* current string which may change as substitutions | 
|---|
| 548 |                         * take place | 
|---|
| 549 |                         */ | 
|---|
| 550 |   char *newCurStr;     /* new string pieced together with the expanded value */ | 
|---|
| 551 |   char c;              /* current character in the string */ | 
|---|
| 552 |  | 
|---|
| 553 |   int freeNewValue;    /* new value of string returned by recursion needs | 
|---|
| 554 |                         * to be freed. | 
|---|
| 555 |                         */ | 
|---|
| 556 |   char dollar;         /* character that stores the dollar sign */ | 
|---|
| 557 |   int lastPos;         /* position of the last character of the variable | 
|---|
| 558 |                         * in the string. | 
|---|
| 559 |                         */ | 
|---|
| 560 |   int envVar;           /* flag to say that the variable is not found in | 
|---|
| 561 |                          * the table, hence may be an environment variable | 
|---|
| 562 |                          */ | 
|---|
| 563 |  | 
|---|
| 564 |   dollar = '$'; | 
|---|
| 565 |   curStrIndex = 0; | 
|---|
| 566 |   subLen = 0; | 
|---|
| 567 |   findEndDollar = 0; | 
|---|
| 568 |   singleQuote = 0; | 
|---|
| 569 |   doubleQuote = 0; | 
|---|
| 570 |   dollarIndex = -1; | 
|---|
| 571 |   endDollarIndex = -1; | 
|---|
| 572 |   /* make a local copy since the string may change */ | 
|---|
| 573 |   curStr = ALLOC(char, strlen(str)+1); | 
|---|
| 574 |   curStr = strncpy(curStr, str, strlen(str)+1); | 
|---|
| 575 |   /* search through the end of string including te \0 character to detect | 
|---|
| 576 |    * end of variable, if required. | 
|---|
| 577 |    */ | 
|---|
| 578 |   while (curStrIndex <= (int) strlen(curStr)) { | 
|---|
| 579 |     /* current character */ | 
|---|
| 580 |     c = curStr[curStrIndex]; | 
|---|
| 581 |     /* redundant here since split_line already strips out the quotes */ | 
|---|
| 582 |     if ((c == '\"') || (c == '\'')) { | 
|---|
| 583 |       /* also termination charactrers for $ */ | 
|---|
| 584 |       /* set flags for quote found */ | 
|---|
| 585 |       singleQuote = !singleQuote; | 
|---|
| 586 |       doubleQuote = !doubleQuote; | 
|---|
| 587 |       /* also a variable termination */ | 
|---|
| 588 |       if (findEndDollar) { | 
|---|
| 589 |         findEndDollar = 0; | 
|---|
| 590 |         endDollarIndex = curStrIndex; | 
|---|
| 591 |       } | 
|---|
| 592 |     } | 
|---|
| 593 |     /* detect a $ if not within quotes */ | 
|---|
| 594 |     if ((c == '$') && (!singleQuote) && (!doubleQuote)) { | 
|---|
| 595 |       if (findEndDollar == 1) { | 
|---|
| 596 |         error_append("Cannot have nested $ signs, not found termination\n"); | 
|---|
| 597 |         break; | 
|---|
| 598 |       } | 
|---|
| 599 |       /* note the beginning of the dollar position */ | 
|---|
| 600 |       dollarIndex = curStrIndex; | 
|---|
| 601 |       /* start quest for end of dollar */ | 
|---|
| 602 |       findEndDollar = 1; | 
|---|
| 603 |       endDollarIndex = -1; | 
|---|
| 604 |     } | 
|---|
| 605 |     /* termination characters are \0, :, / when not within quotes. | 
|---|
| 606 |      * Although, some of these may never be encountered | 
|---|
| 607 |      * since this is called after split_line and apply_alias | 
|---|
| 608 |      * Termination characters except '\0' are ignored within quotes | 
|---|
| 609 |      */ | 
|---|
| 610 |     if ((findEndDollar) && | 
|---|
| 611 |         ((c == '\0') || | 
|---|
| 612 |          ((!singleQuote) && (!doubleQuote) && | 
|---|
| 613 |           ((c == ':') || (c == '/'))))) { | 
|---|
| 614 |       /*     if (((c == '\n') || (c == '\t') || (isspace(c)) || | 
|---|
| 615 |         (c == ':') || (c == ';') || (c == '\0') || | 
|---|
| 616 |         (c == '#') || (c == '/')) && (findEndDollar)) { */ | 
|---|
| 617 |         findEndDollar = 0; | 
|---|
| 618 |         endDollarIndex = curStrIndex; | 
|---|
| 619 |     } /* end of find termination characters */ | 
|---|
| 620 |  | 
|---|
| 621 |     /* found the interpolation variable and its end*/ | 
|---|
| 622 |     if (!findEndDollar && (endDollarIndex != -1)) { | 
|---|
| 623 |       /* found an interpolation variable */ | 
|---|
| 624 |       subLen = 0; | 
|---|
| 625 |       freeNewValue = 0; | 
|---|
| 626 |       envVar = 0; | 
|---|
| 627 |       subStr = NULL; | 
|---|
| 628 |       if (endDollarIndex > (dollarIndex +1)) { | 
|---|
| 629 |         /* if not empty string */ | 
|---|
| 630 |         subStr = ALLOC(char, endDollarIndex - dollarIndex); | 
|---|
| 631 |         /* copy the variable into another string */ | 
|---|
| 632 |         for ( i = 0; i <  endDollarIndex - dollarIndex - 1; i++) { | 
|---|
| 633 |           subStr[i] = curStr[dollarIndex+1+i]; | 
|---|
| 634 |         } | 
|---|
| 635 |         subStr[i] = '\0'; | 
|---|
| 636 |         /* quiet if of the form var$:iable or var$foo:iable and | 
|---|
| 637 |          * $foo not in flag table | 
|---|
| 638 |          */ | 
|---|
| 639 |         if (avl_lookup(cmdFlagTable, subStr, (char **)&value) != 0) { | 
|---|
| 640 |           /* found the variable in the alias table */ | 
|---|
| 641 |           if (strchr((char *)value, (int)dollar) != NULL) { | 
|---|
| 642 |             /* if more $s in the value */ | 
|---|
| 643 |             value = variableInterpolationRecur(value); | 
|---|
| 644 |             subLen = strlen(value); | 
|---|
| 645 |             /* to be freed later since variableInterpolationRecur | 
|---|
| 646 |              * returns a new string to be freed later. | 
|---|
| 647 |              */ | 
|---|
| 648 |             freeNewValue = 1; | 
|---|
| 649 |  | 
|---|
| 650 |           }  else { | 
|---|
| 651 |           /* if no dollars in the value, substitute the return value | 
|---|
| 652 |            * in the string | 
|---|
| 653 |            */ | 
|---|
| 654 |             subLen = strlen(value); | 
|---|
| 655 |           } | 
|---|
| 656 |         } else {  | 
|---|
| 657 |           /* if the variable is not found, it might be an | 
|---|
| 658 |            * environment variable and so keep it. This might be | 
|---|
| 659 |            * a hazard for bogus variables but that is upto the user. | 
|---|
| 660 |            */ | 
|---|
| 661 |           value = subStr; | 
|---|
| 662 |           /* for environment variable keep the $ sign */ | 
|---|
| 663 |           subLen = strlen(value) +1; | 
|---|
| 664 |           envVar = 1; | 
|---|
| 665 |         } | 
|---|
| 666 |  | 
|---|
| 667 |       } /* end of interpolation variable not trivial */ | 
|---|
| 668 |       /* prefix + strlen(substituted value) + suffix */ | 
|---|
| 669 |       newCurStr = ALLOC(char, dollarIndex +  | 
|---|
| 670 |                               subLen + | 
|---|
| 671 |                               strlen(curStr) - endDollarIndex + 1); | 
|---|
| 672 |                          | 
|---|
| 673 |        | 
|---|
| 674 |        | 
|---|
| 675 |       /* copy prefix */ | 
|---|
| 676 |       newCurStr = strncpy(newCurStr, curStr, dollarIndex); | 
|---|
| 677 |       i = dollarIndex; | 
|---|
| 678 |       if (subLen) { | 
|---|
| 679 |         /* copy substituted value */ | 
|---|
| 680 |         if (envVar) { | 
|---|
| 681 |           /* if it is an environment variable, keep the $ sign */ | 
|---|
| 682 |           newCurStr[i++] = '$'; | 
|---|
| 683 |         } | 
|---|
| 684 |         index = 0; | 
|---|
| 685 |         while (value[index] != '\0') { | 
|---|
| 686 |           newCurStr[i++] = value[index++]; | 
|---|
| 687 |         } | 
|---|
| 688 |         if (freeNewValue) { | 
|---|
| 689 |           FREE(value); | 
|---|
| 690 |         } | 
|---|
| 691 |       } | 
|---|
| 692 |       /* freed here cos value might be subStr in one case */ | 
|---|
| 693 |       if (subStr != NULL) { | 
|---|
| 694 |         FREE(subStr); | 
|---|
| 695 |       } | 
|---|
| 696 |       /* copy suffix */ | 
|---|
| 697 |       index = endDollarIndex; | 
|---|
| 698 |       /* figure out where to start the next search */ | 
|---|
| 699 |       lastPos = i; | 
|---|
| 700 |       while (curStr[index] != '\0') { | 
|---|
| 701 |         newCurStr[i++] = curStr[index++]; | 
|---|
| 702 |       } | 
|---|
| 703 |       newCurStr[i] = '\0'; | 
|---|
| 704 |       FREE(curStr); | 
|---|
| 705 |       curStr = newCurStr; | 
|---|
| 706 |       /* reset counter for further search. Due to recursive calling of this | 
|---|
| 707 |        * function eventually, the value that is substituted will not have a $ | 
|---|
| 708 |        */ | 
|---|
| 709 |       curStrIndex = lastPos; | 
|---|
| 710 |       dollarIndex = -1; | 
|---|
| 711 |       endDollarIndex = -1; | 
|---|
| 712 |       /* end of found a variable */    | 
|---|
| 713 |     } else { /* if a variable is not found, keep going */ | 
|---|
| 714 |       curStrIndex++; | 
|---|
| 715 |     } | 
|---|
| 716 |   } /* end of stepping through the string */ | 
|---|
| 717 |   return(curStr); | 
|---|
| 718 | } /* end of variableInterpolationRecur */ | 
|---|
| 719 |  | 
|---|
| 720 |  | 
|---|
| 721 |  | 
|---|
| 722 | /**Function******************************************************************** | 
|---|
| 723 |  | 
|---|
| 724 |   Synopsis    [required] | 
|---|
| 725 |  | 
|---|
| 726 |   Description [optional] | 
|---|
| 727 |  | 
|---|
| 728 |   SideEffects [required] | 
|---|
| 729 |  | 
|---|
| 730 |   SeeAlso     [optional] | 
|---|
| 731 |  | 
|---|
| 732 | ******************************************************************************/ | 
|---|
| 733 | static char * | 
|---|
| 734 | split_line( | 
|---|
| 735 |   char * command, | 
|---|
| 736 |   int * argc, | 
|---|
| 737 |   char *** argv) | 
|---|
| 738 | { | 
|---|
| 739 |   register char *p, *start, c; | 
|---|
| 740 |   register int i, j; | 
|---|
| 741 |   register char *new_arg; | 
|---|
| 742 |   array_t *argv_array; | 
|---|
| 743 |   int single_quote, double_quote; | 
|---|
| 744 |  | 
|---|
| 745 |   argv_array = array_alloc(char *, 5); | 
|---|
| 746 |  | 
|---|
| 747 |   p = command; | 
|---|
| 748 |   for(;;) { | 
|---|
| 749 |     /* skip leading white space */ | 
|---|
| 750 |     while (isspace((int)(*p))) { | 
|---|
| 751 |       p++; | 
|---|
| 752 |     } | 
|---|
| 753 |  | 
|---|
| 754 |     /* skip until end of this token */ | 
|---|
| 755 |     single_quote = double_quote = 0; | 
|---|
| 756 |     for(start = p; (c = *p) != '\0'; p++) { | 
|---|
| 757 |       if (c == ';' || c == '#' || isspace((int)c)) { | 
|---|
| 758 |         if (! single_quote && ! double_quote) { | 
|---|
| 759 |           break; | 
|---|
| 760 |         } | 
|---|
| 761 |       } | 
|---|
| 762 |       if (c == '\'') { | 
|---|
| 763 |         single_quote = ! single_quote; | 
|---|
| 764 |       } | 
|---|
| 765 |       if (c == '"') { | 
|---|
| 766 |         double_quote = ! double_quote; | 
|---|
| 767 |       } | 
|---|
| 768 |     } | 
|---|
| 769 |     if (single_quote || double_quote) { | 
|---|
| 770 |       (void) fprintf(vis_stderr, "** cmd warning: ignoring unbalanced quote ...\n"); | 
|---|
| 771 |     } | 
|---|
| 772 |     if (start == p) break; | 
|---|
| 773 |  | 
|---|
| 774 |     new_arg = ALLOC(char, p - start + 1); | 
|---|
| 775 |     j = 0; | 
|---|
| 776 |     for(i = 0; i < p - start; i++) { | 
|---|
| 777 |       c = start[i]; | 
|---|
| 778 |       if ((c != '\'') && (c != '\"')) { | 
|---|
| 779 |         new_arg[j++] = isspace((int)c) ? ' ' : start[i]; | 
|---|
| 780 |       } | 
|---|
| 781 |     } | 
|---|
| 782 |     new_arg[j] = '\0'; | 
|---|
| 783 |     array_insert_last(char *, argv_array, new_arg); | 
|---|
| 784 |   } | 
|---|
| 785 |  | 
|---|
| 786 |   *argc = array_n(argv_array); | 
|---|
| 787 |   *argv = array_data(char *, argv_array); | 
|---|
| 788 |   array_free(argv_array); | 
|---|
| 789 |   if (*p == ';') { | 
|---|
| 790 |     p++; | 
|---|
| 791 |   } | 
|---|
| 792 |   else if (*p == '#') { | 
|---|
| 793 |     for(; *p != 0; p++) ;               /* skip to end of line */ | 
|---|
| 794 |   } | 
|---|
| 795 |   return p; | 
|---|
| 796 | }     | 
|---|
| 797 |  | 
|---|
| 798 |  | 
|---|
| 799 | /**Function******************************************************************** | 
|---|
| 800 |  | 
|---|
| 801 |   Synopsis    [required] | 
|---|
| 802 |  | 
|---|
| 803 |   Description [optional] | 
|---|
| 804 |  | 
|---|
| 805 |   SideEffects [required] | 
|---|
| 806 |  | 
|---|
| 807 |   SeeAlso     [optional] | 
|---|
| 808 |  | 
|---|
| 809 | ******************************************************************************/ | 
|---|
| 810 | static int | 
|---|
| 811 | check_shell_escape( | 
|---|
| 812 |   char * p, | 
|---|
| 813 |   int * status) | 
|---|
| 814 | { | 
|---|
| 815 |     char *value; | 
|---|
| 816 |     while (isspace((int)(*p))) { | 
|---|
| 817 |         p++; | 
|---|
| 818 |     } | 
|---|
| 819 |     if ((value = Cmd_FlagReadByName("shell_char")) != NIL(char)){ | 
|---|
| 820 |         visShellChar = *value; | 
|---|
| 821 |     } | 
|---|
| 822 |     if (*p == visShellChar) { | 
|---|
| 823 |         *status = system(p+1); | 
|---|
| 824 |         return 1; | 
|---|
| 825 |     } | 
|---|
| 826 |     return 0; | 
|---|
| 827 | } | 
|---|
| 828 |  | 
|---|
| 829 | /**Function******************************************************************** | 
|---|
| 830 |  | 
|---|
| 831 |   Synopsis    [Signal handler.] | 
|---|
| 832 |  | 
|---|
| 833 |   SideEffects [] | 
|---|
| 834 |  | 
|---|
| 835 |   SeeAlso     [com_dispatch] | 
|---|
| 836 |  | 
|---|
| 837 | ******************************************************************************/ | 
|---|
| 838 | static void | 
|---|
| 839 | sigterm(int sig) | 
|---|
| 840 | { | 
|---|
| 841 |     (void) signal(SIGINT, SIG_IGN);     /* ignore further ctl-c */ | 
|---|
| 842 |     (void)fprintf(vis_stderr, "\n"); | 
|---|
| 843 |     (void)fprintf(vis_stderr, | 
|---|
| 844 |                   "** cmd warning : data may be corrupted due to CTRL-c.\n"); | 
|---|
| 845 |     (void)fprintf(vis_stderr, | 
|---|
| 846 |                   "                 It may cause abnormal termination.\n"); | 
|---|
| 847 |     longjmp(env, 1); | 
|---|
| 848 | } | 
|---|