VIS

src/cmd/cmdCmd.c File Reference

#include "cmdInt.h"
Include dependency graph for cmdCmd.c:

Go to the source code of this file.

Data Structures

struct  CommandDescrStruct

Typedefs

typedef struct CommandDescrStruct CommandDescr_t

Functions

static int com_dispatch (Hrc_Manager_t **hmgr, int argc, char **argv)
static int apply_alias (Hrc_Manager_t **hmgr, int *argcp, char ***argvp, int *loop)
static void variableInterpolation (int *argc, char ***argv)
static char * variableInterpolationRecur (char *str)
static char * split_line (char *command, int *argc, char ***argv)
static int check_shell_escape (char *p, int *status)
static void sigterm (int sig)
void Cmd_CommandAdd (char *name, PFI funcFp, int changes)
int Cmd_CommandExecute (Hrc_Manager_t **hmgr, char *command)
void CmdCommandFree (char *value)

Variables

static char rcsid[] UNUSED = "$Id: cmdCmd.c,v 1.16 2005/04/16 04:23:02 fabio Exp $"
Hrc_Manager_t * cmdBackupHmgr
avl_tree * cmdCommandTable
static char visShellChar = '!'
static int autoexec
static jmp_buf env

Typedef Documentation

Struct**********************************************************************

Synopsis [required]

Description [optional]

SeeAlso [optional]


Function Documentation

static int apply_alias ( Hrc_Manager_t **  hmgr,
int *  argcp,
char ***  argvp,
int *  loop 
) [static]

Function********************************************************************

Synopsis [required]

Description [Applies alias. If perform a history substitution in expanding an alias, remove all the orginal trailing arguments. For example:

> alias t rl \!:1
> t lion.blif would otherwise expand to rl lion.blif lion.blif
]

SideEffects [required]

SeeAlso [optional]

Definition at line 309 of file cmdCmd.c.

{
  int i, argc, stopit, added, offset, did_subst, subst, status, newc, j;
  char *arg, **argv, **newv;
  CmdAliasDescr_t *alias;

  argc = *argcp;
  argv = *argvp;
  stopit = 0;
  for(; *loop < 20; (*loop)++) {
    if (argc == 0) {
      return 0;
    }
    if (stopit != 0 || avl_lookup(cmdAliasTable, argv[0], &alias) == 0) {
      return 0;
    }
    if (strcmp(argv[0], alias->argv[0]) == 0) {
      stopit = 1;
    }
    FREE(argv[0]);
    added = alias->argc - 1;

    /* shift all the arguments to the right */
    if (added != 0) {
      argv = REALLOC(char *, argv, argc + added);
      for (i = argc - 1; i >= 1; i--) {
        argv[i + added] = argv[i];
      }
      for (i = 1; i <= added; i++) {
        argv[i] = NIL(char);
      }
      argc += added;
    }
    subst = 0;
    for (i = 0, offset = 0; i < alias->argc; i++, offset++) {
      arg = CmdHistorySubstitution(alias->argv[i], &did_subst);
      if (arg == NIL(char)) {
        *argcp = argc;
        *argvp = argv;
        return(1);
      }
      if (did_subst != 0) {
        subst = 1;
      }
      status = 0;
      do {
        arg = split_line(arg, &newc, &newv);
        /*
         * If there's a complete `;' terminated command in `arg',
         * when split_line() returns arg[0] != '\0'.
         */
        if (arg[0] == '\0') {   /* just a bunch of words */
          break;
        }
        status = apply_alias(hmgr, &newc, &newv, loop);
        if (status == 0) {
          status = com_dispatch(hmgr, newc, newv);
        }
        CmdFreeArgv(newc, newv);
      } while (status == 0);
      if (status != 0) {
        *argcp = argc;
        *argvp = argv;
        return(1);
      }
      added = newc - 1;
      if (added != 0) {
        argv = REALLOC(char *, argv, argc + added);
        for (j = argc - 1; j > offset; j--) {
          argv[j + added] = argv[j];
        }
        argc += added;
      }
      for (j = 0; j <= added; j++) {
        argv[j + offset] = newv[j];
      }
      FREE(newv);
      offset += added;
    }
    if (subst == 1) {
      for (i = offset; i < argc; i++) {
        FREE(argv[i]);
      }
      argc = offset;
    }
    *argcp = argc;
    *argvp = argv;
  }

  (void) fprintf(vis_stderr, "** cmd error: alias loop\n");
  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int check_shell_escape ( char *  p,
int *  status 
) [static]

Function********************************************************************

Synopsis [required]

Description [optional]

SideEffects [required]

SeeAlso [optional]

Definition at line 811 of file cmdCmd.c.

{
    char *value;
    while (isspace((int)(*p))) {
        p++;
    }
    if ((value = Cmd_FlagReadByName("shell_char")) != NIL(char)){
        visShellChar = *value;
    }
    if (*p == visShellChar) {
        *status = system(p+1);
        return 1;
    }
    return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void Cmd_CommandAdd ( char *  name,
PFI  funcFp,
int  changes 
)

AutomaticEnd Function********************************************************************

Synopsis [Adds a command to the command table.]

Description [Adds a command to the command table. If name already defines an existing command, its definition is replaced. FuncFp is a function pointer to code of the form:

int
CommandTest(hmgr, argc, argv)
Hrc_Manager_t **hmgr;
int argc;
char **argv;
{
return 0;
}

Note the double de-reference on the hmgr which is passed to the command; this allows the command to replace the current hmgr. argv\[0\] will generally be the command name, and argv\[1\] ... argv\[argc-1\] are the arguments for the command. util_getopt() can be used to parse the arguments, but util_getopt_reset() must be used before calling util_getopt(). The command function should return 0 for normal operation, 1 for any error. The changes flag is used to automatically save the hmgr before executing the command (in order to support undo).]

SideEffects []

Definition at line 119 of file cmdCmd.c.

{
  char *key, *value;
  CommandDescr_t *descr;
  int status;

  key = name;
  if (avl_delete(cmdCommandTable, &key, &value)) {
    /* delete existing definition for this command */
    (void) fprintf
      (vis_stderr, "** cmd warning: redefining '%s'\n", name);
    CmdCommandFree(value);
  }

  descr = ALLOC(CommandDescr_t, 1);
  descr->name = util_strsav(name);
  descr->command_fp = funcFp;
  descr->changes_hmgr = changes;
  status = avl_insert(cmdCommandTable, descr->name, (char *) descr);
  assert(!status);  /* error here in SIS version, TRS, 8/4/95 */
}

Here is the call graph for this function:

Here is the caller graph for this function:

int Cmd_CommandExecute ( Hrc_Manager_t **  hmgr,
char *  command 
)

Function********************************************************************

Synopsis [Executes a command line.]

Description [Executes a command line. This is the top-level of the command interpreter, and supports multiple commands (separated by ;), alias substitution, etc. For many simple operations, Cmd_CommandExecute() is the easiest way to accomplish a given task. For example, to set a variable, use the code: Cmd_CommandExecute(&hmgr, "set color blue").]

SideEffects []

Definition at line 159 of file cmdCmd.c.

{
  int status, argc;
  int loop;
  char *commandp, **argv;

  (void) signal(SIGINT, SIG_IGN);
  commandp = command;
  do {
    if (check_shell_escape(commandp, &status)) {
      break;
    }
    
    commandp = split_line(commandp, &argc, &argv);
    loop = 0;
    status = apply_alias(hmgr, &argc, &argv, &loop);
    if (status == 0) {

      variableInterpolation(&argc, &argv);

      status = com_dispatch(hmgr, argc, argv);
    }
    CmdFreeArgv(argc, argv);
  } while (status == 0 && *commandp != '\0');
  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void CmdCommandFree ( char *  value)

Function********************************************************************

Synopsis [required]

Description [optional]

SideEffects [required]

SeeAlso [optional]

Definition at line 207 of file cmdCmd.c.

{
  CommandDescr_t *command = (CommandDescr_t *) value;

  FREE(command->name);          /* same as key */
  FREE(command);
}

Here is the caller graph for this function:

static int com_dispatch ( Hrc_Manager_t **  hmgr,
int  argc,
char **  argv 
) [static]

AutomaticStart

Function********************************************************************

Synopsis [required]

Description [optional]

SideEffects [required]

SeeAlso [optional]

Definition at line 233 of file cmdCmd.c.

{
  int status;
  char *value;
  CommandDescr_t *descr;

  if (argc == 0) {              /* empty command */
    return 0;
  }

  if (! avl_lookup(cmdCommandTable, argv[0], &value)) {
    (void) fprintf(vis_stderr, "** cmd error: unknown command '%s'\n", argv[0]);
    return 1;
  }

  descr = (CommandDescr_t *) value;
  if (setjmp(env)) {
#if 0
    /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */
    /* return from control-c -- restore the hmgr */
    if (descr->changes_hmgr) {
      *hmgr = cmdBackupHmgr;
      cmdBackupHmgr = NIL(Hrc_Manager_t);
    }
#endif
    return 1;
  }

  
#if 0
  /* FIX (Tom) need hmgr_dup and network_dup to use this functionality */
  if (descr->changes_hmgr) {
    if (cmdBackupHmgr != NIL(Hrc_Manager_t)) {
      Hrc_ManagerFree(cmdBackupHmgr);
    }
    cmdBackupHmgr = hmgr_dup(*hmgr);
  }
#endif
  
  (void) signal(SIGINT, sigterm);
  status = (*descr->command_fp)(hmgr, argc, argv);

  /* automatic execution of arbitrary command after each command */
  /* usually this is a passive command ... */
  if (status == 0 && ! autoexec) {
    if (avl_lookup(cmdFlagTable, "autoexec", &value)) {
      autoexec = 1;
      status = Cmd_CommandExecute(hmgr, value);
      autoexec = 0;
    }
  }

  (void) signal(SIGINT, SIG_IGN);
  return status;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void sigterm ( int  sig) [static]

Function********************************************************************

Synopsis [Signal handler.]

SideEffects []

SeeAlso [com_dispatch]

Definition at line 839 of file cmdCmd.c.

{
    (void) signal(SIGINT, SIG_IGN);     /* ignore further ctl-c */
    (void)fprintf(vis_stderr, "\n");
    (void)fprintf(vis_stderr,
                  "** cmd warning : data may be corrupted due to CTRL-c.\n");
    (void)fprintf(vis_stderr,
                  "                 It may cause abnormal termination.\n");
    longjmp(env, 1);
}

Here is the caller graph for this function:

static char * split_line ( char *  command,
int *  argc,
char ***  argv 
) [static]

Function********************************************************************

Synopsis [required]

Description [optional]

SideEffects [required]

SeeAlso [optional]

Definition at line 734 of file cmdCmd.c.

{
  register char *p, *start, c;
  register int i, j;
  register char *new_arg;
  array_t *argv_array;
  int single_quote, double_quote;

  argv_array = array_alloc(char *, 5);

  p = command;
  for(;;) {
    /* skip leading white space */
    while (isspace((int)(*p))) {
      p++;
    }

    /* skip until end of this token */
    single_quote = double_quote = 0;
    for(start = p; (c = *p) != '\0'; p++) {
      if (c == ';' || c == '#' || isspace((int)c)) {
        if (! single_quote && ! double_quote) {
          break;
        }
      }
      if (c == '\'') {
        single_quote = ! single_quote;
      }
      if (c == '"') {
        double_quote = ! double_quote;
      }
    }
    if (single_quote || double_quote) {
      (void) fprintf(vis_stderr, "** cmd warning: ignoring unbalanced quote ...\n");
    }
    if (start == p) break;

    new_arg = ALLOC(char, p - start + 1);
    j = 0;
    for(i = 0; i < p - start; i++) {
      c = start[i];
      if ((c != '\'') && (c != '\"')) {
        new_arg[j++] = isspace((int)c) ? ' ' : start[i];
      }
    }
    new_arg[j] = '\0';
    array_insert_last(char *, argv_array, new_arg);
  }

  *argc = array_n(argv_array);
  *argv = array_data(char *, argv_array);
  array_free(argv_array);
  if (*p == ';') {
    p++;
  }
  else if (*p == '#') {
    for(; *p != 0; p++) ;               /* skip to end of line */
  }
  return p;
}    

Here is the caller graph for this function:

static void variableInterpolation ( int *  ori_argc,
char ***  ori_argv 
) [static]

Function********************************************************************

Synopsis [Allows interpolation of variables]

Description [Allows interpolation of variables. Here it is implemented by allowing variables to be referred to with the prefix of '$'. The variables are set using the "set" command. So for example, the following can be done

vis> set foo bar
vis> echo $foo
bar

The last line "bar" will the output produced by vis.

The following can also be done:

vis> set foo $foo:foobar
vis> echo $foobar
bar:foobar
The last line will be the output produced by vis.

These variables can be used in recursive definitions. The following termination characters are recognized for the variables \n, \0, ' ', \t, :, ;, #, /.

Although the set command allows the usage of the some of the above termination characters between quotes, the variable interpolation procedure has the restriction that the two characters ':' and '/' may not be used with quotes. A variable with spaces in it may be used only if it is enclosed within quotes. ]

SideEffects [required]

SeeAlso [optional]

Definition at line 450 of file cmdCmd.c.

{
  int i;          /* to iterate through the arguments */
  char *newStr;   /* string returned by the expanded value */
  char dollar;    /* character to store reference to the variable, now '$' */
  int argc;
  char **argv;
  int index;
  int null_string_flag;

  argc = *ori_argc;
  argv = *ori_argv;

  dollar = '$';
  null_string_flag = 0;

  /* step through all argvs */
  for (i = 0; i < argc; i++) {
    if (strchr((char *)argv[i], (int)dollar) != NULL) {
      /* expanded string returned by the procedure */
      newStr = variableInterpolationRecur(argv[i]);
      if(!strcmp(newStr, " ")) {
        FREE(argv[i]);
        /* replace old value with new */
        argv[i] = 0;
        null_string_flag = 1;
      }
      else {
        FREE(argv[i]);
        /* replace old value with new */
        argv[i] = newStr;
      }
    }
  } /* end of iterating through all arguments */

  if(null_string_flag) {
    *ori_argv = ALLOC(char *, argc);
    index = 0;
    for (i = 0; i < argc; i++) {
      if(argv[i] == 0) {
        (*ori_argc)--;
        continue;
      }
      (*ori_argv)[index++] = argv[i];
    }
    FREE(argv);
  }

  return;
}/* end of variable interpolation */

Here is the call graph for this function:

Here is the caller graph for this function:

static char * variableInterpolationRecur ( char *  str) [static]

Function********************************************************************

Synopsis [Recursive procedure that expands the interpolation variables]

Description [Recursive procedure that expands the interpolation variables. This procedure is designed to handle multiple occurrences of variables in a string and recursive definitions. If the expanded variable has another variable, then the procedure is called recursively. The existence of a variable is identified by the $ sign in the string. But since this may be an environment variable too, the variable is untouched if not found in this table. A sophisticated check can be made to see if this variable exists in the environment, but it is NOT done here. Therefore, detection of bogus values cannot be done. The procedure steps through the string to see if any variables are present. If a termination character (one of :, /) is found after the '$', then the variable is identified and looked up in the flag table. If the returned string again has a dollar, then the procedure is called recursively. If not, the returned value replaces the variable and the stepping through continues. If the variable is not found, then it might be an environment variable.So the procedure leaves the variable there. ]

SideEffects [required]

SeeAlso [optional]

Definition at line 530 of file cmdCmd.c.

{
  int i;               /* iterators */
  int findEndDollar;   /* flag to denote that a $ has been found. So
                        * search till end of variable
                        */
  int endDollarIndex;  /* index in the current string of the end of the
                        * variable
                        */
  int dollarIndex;     /* index in the current string of the dollar sign */  
  int singleQuote;     /* flag that symbolizes that a quote is started */ 
  int doubleQuote;     /* flag that symbolizes that a quote is started */
  char *value;         /* value of the variable that is returned by the table */
  char *subStr;        /* string to store the variable */
  int curStrIndex;     /* index to step through the current string */
  int subLen;          /* length of the variable */
  int index;           /* variable use to step through the various strings */
  char *curStr;        /* current string which may change as substitutions
                        * take place
                        */
  char *newCurStr;     /* new string pieced together with the expanded value */
  char c;              /* current character in the string */

  int freeNewValue;    /* new value of string returned by recursion needs
                        * to be freed.
                        */
  char dollar;         /* character that stores the dollar sign */
  int lastPos;         /* position of the last character of the variable
                        * in the string.
                        */
  int envVar;           /* flag to say that the variable is not found in
                         * the table, hence may be an environment variable
                         */

  dollar = '$';
  curStrIndex = 0;
  subLen = 0;
  findEndDollar = 0;
  singleQuote = 0;
  doubleQuote = 0;
  dollarIndex = -1;
  endDollarIndex = -1;
  /* make a local copy since the string may change */
  curStr = ALLOC(char, strlen(str)+1);
  curStr = strncpy(curStr, str, strlen(str)+1);
  /* search through the end of string including te \0 character to detect
   * end of variable, if required.
   */
  while (curStrIndex <= (int) strlen(curStr)) {
    /* current character */
    c = curStr[curStrIndex];
    /* redundant here since split_line already strips out the quotes */
    if ((c == '\"') || (c == '\'')) {
      /* also termination charactrers for $ */
      /* set flags for quote found */
      singleQuote = !singleQuote;
      doubleQuote = !doubleQuote;
      /* also a variable termination */
      if (findEndDollar) {
        findEndDollar = 0;
        endDollarIndex = curStrIndex;
      }
    }
    /* detect a $ if not within quotes */
    if ((c == '$') && (!singleQuote) && (!doubleQuote)) {
      if (findEndDollar == 1) {
        error_append("Cannot have nested $ signs, not found termination\n");
        break;
      }
      /* note the beginning of the dollar position */
      dollarIndex = curStrIndex;
      /* start quest for end of dollar */
      findEndDollar = 1;
      endDollarIndex = -1;
    }
    /* termination characters are \0, :, / when not within quotes.
     * Although, some of these may never be encountered
     * since this is called after split_line and apply_alias
     * Termination characters except '\0' are ignored within quotes
     */
    if ((findEndDollar) &&
        ((c == '\0') ||
         ((!singleQuote) && (!doubleQuote) &&
          ((c == ':') || (c == '/'))))) {
      /*     if (((c == '\n') || (c == '\t') || (isspace(c)) ||
        (c == ':') || (c == ';') || (c == '\0') ||
        (c == '#') || (c == '/')) && (findEndDollar)) { */
        findEndDollar = 0;
        endDollarIndex = curStrIndex;
    } /* end of find termination characters */

    /* found the interpolation variable and its end*/
    if (!findEndDollar && (endDollarIndex != -1)) {
      /* found an interpolation variable */
      subLen = 0;
      freeNewValue = 0;
      envVar = 0;
      subStr = NULL;
      if (endDollarIndex > (dollarIndex +1)) {
        /* if not empty string */
        subStr = ALLOC(char, endDollarIndex - dollarIndex);
        /* copy the variable into another string */
        for ( i = 0; i <  endDollarIndex - dollarIndex - 1; i++) {
          subStr[i] = curStr[dollarIndex+1+i];
        }
        subStr[i] = '\0';
        /* quiet if of the form var$:iable or var$foo:iable and
         * $foo not in flag table
         */
        if (avl_lookup(cmdFlagTable, subStr, (char **)&value) != 0) {
          /* found the variable in the alias table */
          if (strchr((char *)value, (int)dollar) != NULL) {
            /* if more $s in the value */
            value = variableInterpolationRecur(value);
            subLen = strlen(value);
            /* to be freed later since variableInterpolationRecur
             * returns a new string to be freed later.
             */
            freeNewValue = 1;

          }  else {
          /* if no dollars in the value, substitute the return value
           * in the string
           */
            subLen = strlen(value);
          }
        } else { 
          /* if the variable is not found, it might be an
           * environment variable and so keep it. This might be
           * a hazard for bogus variables but that is upto the user.
           */
          value = subStr;
          /* for environment variable keep the $ sign */
          subLen = strlen(value) +1;
          envVar = 1;
        }

      } /* end of interpolation variable not trivial */
      /* prefix + strlen(substituted value) + suffix */
      newCurStr = ALLOC(char, dollarIndex + 
                              subLen +
                              strlen(curStr) - endDollarIndex + 1);
                        
      
      
      /* copy prefix */
      newCurStr = strncpy(newCurStr, curStr, dollarIndex);
      i = dollarIndex;
      if (subLen) {
        /* copy substituted value */
        if (envVar) {
          /* if it is an environment variable, keep the $ sign */
          newCurStr[i++] = '$';
        }
        index = 0;
        while (value[index] != '\0') {
          newCurStr[i++] = value[index++];
        }
        if (freeNewValue) {
          FREE(value);
        }
      }
      /* freed here cos value might be subStr in one case */
      if (subStr != NULL) {
        FREE(subStr);
      }
      /* copy suffix */
      index = endDollarIndex;
      /* figure out where to start the next search */
      lastPos = i;
      while (curStr[index] != '\0') {
        newCurStr[i++] = curStr[index++];
      }
      newCurStr[i] = '\0';
      FREE(curStr);
      curStr = newCurStr;
      /* reset counter for further search. Due to recursive calling of this
       * function eventually, the value that is substituted will not have a $
       */
      curStrIndex = lastPos;
      dollarIndex = -1;
      endDollarIndex = -1;
      /* end of found a variable */   
    } else { /* if a variable is not found, keep going */
      curStrIndex++;
    }
  } /* end of stepping through the string */
  return(curStr);
} /* end of variableInterpolationRecur */

Here is the caller graph for this function:


Variable Documentation

int autoexec [static]

Definition at line 64 of file cmdCmd.c.

Hrc_Manager_t* cmdBackupHmgr

Definition at line 59 of file cmdCmd.c.

avl_tree* cmdCommandTable

Definition at line 60 of file cmdCmd.c.

jmp_buf env [static]

Definition at line 65 of file cmdCmd.c.

char rcsid [] UNUSED = "$Id: cmdCmd.c,v 1.16 2005/04/16 04:23:02 fabio Exp $" [static]

CFile***********************************************************************

FileName [cmdCmd.c]

PackageName [cmd]

Synopsis [Command table and command execution.]

Author [Originated from SIS]

Copyright [Copyright (c) 1994-1996 The Regents of the Univ. of California. All rights reserved.

Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software.

IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.]

Definition at line 34 of file cmdCmd.c.

char visShellChar = '!' [static]

Definition at line 62 of file cmdCmd.c.