home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 074.lha / CShell / Sources / execom.c < prev    next >
C/C++ Source or Header  |  1986-11-20  |  16KB  |  727 lines

  1. /*
  2.  * EXECOM.C
  3.  *
  4.  * Matthew Dillon, 10 August 1986
  5.  *    Finally re-written.
  6.  *
  7.  * Version 2.07M by Steve Drew 10-Sep-87
  8.  *
  9.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. #define F_EXACT 0
  15. #define F_ABBR    1
  16.  
  17. #define ST_COND      0x01
  18. #define ST_NORED  0x02
  19. #define ST_NOEXP  0x04
  20. #define ST_AV     0x08 /* delimit args within a variable */
  21.  
  22. int has_wild = 0;          /* set if any arg has wild card */
  23.  
  24.  
  25. struct COMMAND {
  26.    int (*func)();
  27.    short minargs;
  28.    short stat;
  29.    int     val;
  30.    char *name;
  31. };
  32.  
  33. extern char *format_insert_string();
  34. extern char *mpush(), *exarg();
  35.  
  36. extern int do_run(), do_number();
  37. extern int do_quit(), do_set_var(), do_unset_var();
  38. extern int do_echo(), do_source(), do_mv();
  39. extern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
  40. extern int do_mem(), do_cat(), do_dir(), do_devinfo(), do_inc();
  41. extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
  42. extern int do_input(), do_ver(), do_sleep(), do_help();
  43. extern int do_strhead(), do_strtail();
  44. extern int do_copy(), date(),  do_ps();
  45. extern int do_forever(), do_abortline();
  46. char *push_cpy();
  47.  
  48. static struct COMMAND Command[] = {
  49.    do_run      , 0,  ST_AV,      0,   "\001",   /* may call do_source */
  50.    do_number   , 0,  0,         0 ,   "\001",
  51.    do_set_var  , 0,  0, LEVEL_ALIAS,   "alias",  /* uses avline */
  52.    do_abortline, 0,  0,         0,    "abortline",
  53.    do_cat      , 0,  0,         0 ,   "cat",
  54.    do_cd       , 0,  0,         0 ,   "cd",
  55.    do_copy     , 1,  0,         0 ,   "copy",
  56.    date           , 0,  0,         0 ,   "date",
  57.    do_dir      , 0,  ST_NOEXP,     0 ,   "dir",
  58.    do_inc      , 1,  0,        -1 ,   "dec",
  59.    do_devinfo  , 0,  0,         0 ,   "devinfo",
  60.    do_echo     , 0,  0,         0 ,   "echo",  /* uses avline */
  61.    do_if       , 0,  ST_COND,     1 ,   "else",
  62.    do_if       , 0,  ST_COND,     2 ,   "endif",
  63.    do_foreach  , 3,  ST_NORED,     0 ,   "foreach",
  64.    do_forever  , 1,  ST_NORED,     0 ,   "forever",
  65.    do_goto     , 1,  0,         0 ,   "goto",
  66.    do_help     , 0,  0,         0 ,   "help",
  67.    do_history  , 0,  0,         0 ,   "history",
  68.    do_if       , 1,  ST_COND,     0 ,   "if",
  69.    do_inc      , 1,  0,         1 ,   "inc",
  70.    do_input    , 1,  0,         0 ,   "input",
  71.    do_label    , 1,  ST_COND,     0,    "label",
  72.    do_mem      , 0,  0,         0 ,   "mem",
  73.    do_mkdir    , 0,  0,         0 ,   "mkdir",
  74.    do_mv       , 2,  0,         0 ,   "mv",
  75.    do_ps       , 0,  0,         0,    "ps",
  76.    do_pwd      , 0,  0,         0 ,   "pwd",
  77.    do_quit     , 0,  ST_NORED,     0 ,   "quit",
  78.    do_return   , 0,  0,         0 ,   "return",
  79.    do_run      , 1,  ST_NORED,   0,    "run",    
  80.    do_rm       , 0,  0,         0 ,   "rm",
  81.    do_set_var  , 0,  ST_AV, LEVEL_SET, "set",
  82.    do_sleep    , 0,  0,         0,    "sleep",
  83.    do_source   , 0,  ST_NORED|ST_AV, 0,"source", /* uses avline */
  84.    do_strhead  , 3,  0,         0 ,   "strhead",
  85.    do_strtail  , 3,  0,         0 ,   "strtail",
  86.    do_unset_var, 0,  0, LEVEL_ALIAS,   "unalias",
  87.    do_unset_var, 0,  0, LEVEL_SET  ,   "unset",
  88.    do_ver      , 0,  0,         0 ,   "version",
  89.    '\0'           , 0,  0,         0 ,   NULL
  90. };
  91.  
  92.  
  93. static unsigned char elast;         /* last end delimeter */
  94. static char Cin_ispipe, Cout_ispipe;
  95.  
  96. exec_command(base)
  97. char *base;
  98. {
  99.    register char *scr;
  100.    register int i;
  101.    char buf[32];
  102.  
  103.    if (!H_stack) {
  104.       add_history(base);
  105.       sprintf(buf, "%d", H_tail_base + H_len);
  106.       set_var(LEVEL_SET, V_HISTNUM, buf);
  107.    }
  108.    scr = malloc((strlen(base) << 2) + 2);    /* 4X */
  109.    preformat(base, scr);
  110.    i = fcomm(scr, 1);
  111.    return ((i) ? -1 : 1);
  112. }
  113.  
  114. isalphanum(c)
  115. char c;
  116. {
  117.    if (c >= '0' && c <= '9')
  118.       return (1);
  119.    if (c >= 'a' && c <= 'z')
  120.       return (1);
  121.    if (c >= 'A' && c <= 'Z')
  122.       return (1);
  123.    if (c == '_')
  124.       return (1);
  125.    return (0);
  126. }
  127.  
  128. preformat(s, d)
  129. register char *s, *d;
  130. {
  131.    register int si, di, qm;
  132.  
  133.    si = di = qm = 0;
  134.    while (s[si] == ' ' || s[si] == 9)
  135.       ++si;
  136.    while (s[si]) {
  137.       if (qm && s[si] != '\"' && s[si] != '\\') {
  138.      d[di++] = s[si++] | 0x80;
  139.      continue;
  140.       }
  141.       switch (s[si]) {
  142.       case ' ':
  143.       case 9:
  144.      d[di++] = ' ';
  145.      while (s[si] == ' ' || s[si] == 9)
  146.         ++si;
  147.      if (s[si] == 0 || s[si] == '|' || s[si] == ';')
  148.         --di;
  149.      break;
  150.       case '*':
  151.       case '?':
  152.      d[di++] = 0x80;
  153.       case '!':
  154.      d[di++] = s[si++];
  155.      break;
  156.       case '#':
  157.      d[di++] = '\0';
  158.      while (s[si])
  159.         ++si;
  160.      break;
  161.       case ';':
  162.       case '|':
  163.      d[di++] = s[si++];
  164.      while (s[si] == ' ' || s[si] == 9)
  165.         ++si;
  166.      break;
  167.       case '\\':
  168.      d[di++] = s[++si] | 0x80;
  169.      if (s[si]) ++si;
  170.      break;
  171.       case '\"':
  172.      qm = 1 - qm;
  173.      ++si;
  174.      break;
  175.       case '^':
  176.      d[di++] = s[++si] & 0x1F;
  177.      if (s[si]) ++si;
  178.      break;
  179.       case '$':        /* search end of var name and place false space */
  180.      d[di++] = 0x80;
  181.      d[di++] = s[si++];
  182.      while (isalphanum(s[si]))
  183.         d[di++] = s[si++];
  184.      d[di++] = 0x80;
  185.      break;
  186.       default:
  187.      d[di++] = s[si++];
  188.      break;
  189.       }
  190.    }
  191.    d[di++] = 0;
  192.    d[di]   = 0;
  193.    if (debug) {
  194.       fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
  195.    }
  196. }
  197.  
  198. /*
  199.  * process formatted string.  ' ' is the delimeter.
  200.  *
  201.  *    0: check '\0': no more, stop, done.
  202.  *    1: check $.     if so, extract, format, insert
  203.  *    2: check alias. if so, extract, format, insert. goto 1
  204.  *    3: check history or substitution, extract, format, insert. goto 1
  205.  *
  206.  *    4: assume first element now internal or disk based command.
  207.  *
  208.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  209.  *     in av[] list (except 0x80 args appended).  check in order:
  210.  *
  211.  *           '$'       insert string straight
  212.  *           '>'       setup stdout
  213.  *           '>>'       setup stdout flag for append
  214.  *           '<'       setup stdin
  215.  *           '*' or '?'  do directory search and insert as separate args.
  216.  *
  217.  *           ';' 0 '|'   end of command.  if '|' setup stdout
  218.  *                -execute command, fix stdin and out (|) sets
  219.  *                 up stdin for next guy.
  220.  */
  221.  
  222.  
  223. fcomm(str, freeok)
  224. register char *str;
  225. {
  226.    static int alias_count;
  227.    int p_alias_count = 0;
  228.    char *istr;
  229.    char *nextstr;
  230.    char *command;
  231.    char *pend_alias = NULL;
  232.    char err = 0;
  233.    has_wild = 0;
  234.  
  235.    ++alias_count;
  236.  
  237.    mpush_base();
  238.    if (*str == 0)
  239.       goto done1;
  240. step1:
  241.    if (alias_count == MAXALIAS || ++p_alias_count == MAXALIAS) {
  242.       fprintf(stderr,"Alias Loop\n");
  243.       err = 20;
  244.       goto done1;
  245.    }
  246. /*
  247.    if (str[1] == '$') {
  248.       if (istr = get_var (LEVEL_SET, str + 2)) 
  249.          str = format_insert_string(str, istr, &freeok);
  250.    }
  251. */
  252.    istr = NULL;
  253.    if (*(unsigned char *)str < 0x80)
  254.       istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
  255.    *str &= 0x7F;              /* remove \ teltail      */
  256.    if (istr) {
  257.       if (*istr == '%') {
  258.      pend_alias = istr;
  259.       } else {
  260.      str = format_insert_string(str, istr, &freeok);
  261.      goto step1;
  262.       }
  263.    }
  264.    if (*str == '!') {
  265.       char *p, c;              /* fix to allow !cmd1;!cmd2 */
  266.       for(p = str; *p && *p != ';' ; ++p);
  267.       c = *p;
  268.       *p = '\0';
  269.       istr = get_history(str);
  270.       *p = c;
  271.       replace_head(istr);
  272.       str = format_insert_string(str, istr, &freeok);
  273.       goto step1;
  274.    }
  275.    nextstr = str;
  276.    command = exarg(&nextstr);
  277.    if (*command == 0)
  278.       goto done0;
  279.    if (pend_alias == 0) {
  280.       if (cmd_stat(command) & ST_COND)
  281.      goto skipgood;
  282.    }
  283.    if (disable || forward_goto) {
  284.       while (elast && elast != ';' && elast != '|')
  285.      exarg(&nextstr);
  286.       goto done0;
  287.    }
  288. skipgood:
  289.    {
  290.       register char *arg, *ptr, *scr;
  291.       short redir;
  292.       short doexpand;
  293.       short cont;
  294.       short inc;
  295.  
  296.       ac = 1;
  297.       av[0] = command;
  298. step5:                        /* ac = nextac */
  299.       if (!elast || elast == ';' || elast == '|')
  300.      goto stepdone;
  301.  
  302.       av[ac] = '\0';
  303.       cont = 1;
  304.       doexpand = redir = inc = 0;
  305.  
  306.       while (cont && elast) {
  307.      int cstat = cmd_stat(command);
  308.  
  309.      ptr = exarg(&nextstr);
  310.      inc = 1;
  311.      arg = "";
  312.      cont = (elast == 0x80);
  313.      switch (*ptr) {
  314.      case '<':
  315.         redir = -2;
  316.      case '>':
  317.         if (cstat & (ST_NORED | ST_COND)) {
  318.                             /* don't extract   */
  319.         redir = 0;                /* <> stuff if its */
  320.         arg = ptr;                /* external cmd.   */
  321.         break;
  322.         }
  323.         ++redir;
  324.         arg = ptr + 1;
  325.         if (*arg == '>') {
  326.            redir = 2;     /* append >> */
  327.            ++arg;
  328.         }
  329.         cont = 1;
  330.         break;
  331.      case '$':
  332.         /* restore args if from set command or pend_alias */
  333.         if ((arg = get_var(LEVEL_SET, ptr + 1)) != NULL) {
  334.            if (cstat & ST_COND) {
  335.               char *tp;
  336.                   tp = push_cpy(arg); 
  337.                   arg = tp;
  338.                }
  339.                else {
  340.                   char *pe, sv, *index();
  341.               while (pe = index(arg,0xA0)) {
  342.                      sv = *pe;
  343.                  *pe = '\0';
  344.              av[ac++] = push_cpy(arg); 
  345.                      *pe = sv;
  346.              av[ac] = '\0';
  347.              arg = pe+1;
  348.           }
  349.            }
  350.         }
  351.         else
  352.            arg = ptr;
  353.         break;
  354.      case '*':
  355.      case '?':
  356.         if ((cstat & ST_NOEXP) == 0)
  357.            doexpand = 1;
  358.         arg = ptr;
  359.         break;
  360.      default:
  361.         arg = ptr;
  362.         break;
  363.      }
  364.  
  365.      /* Append arg to av[ac] */
  366.  
  367.      for (scr = arg; *scr; ++scr)
  368.         *scr &= 0x7F;
  369.      if (av[ac]) {
  370.         register char *old = av[ac];
  371.         av[ac] = mpush(strlen(arg)+strlen(av[ac]));
  372.         strcpy(av[ac], old);
  373.         strcat(av[ac], arg);
  374.      } else {
  375.         av[ac] = push_cpy(arg);
  376.      }
  377.      if (elast != 0x80)
  378.         break;
  379.       }
  380.  
  381.       /* process expansion */
  382.  
  383.       if (doexpand) {
  384.      char **eav, **ebase;
  385.      int eac;
  386.      has_wild = 1;
  387.      eav = ebase = expand(av[ac], &eac);
  388.      inc = 0;
  389.      if (eav) {
  390.         if (ac + eac + 2 > MAXAV) {
  391.            ierror (NULL, 506);
  392.            err = 1;
  393.         } else {
  394.            QuickSort(eav, eac);
  395.            for (; eac; --eac, ++eav)
  396.           av[ac++] = push_cpy(*eav);
  397.         }
  398.         free_expand (ebase);
  399.      }
  400.       }
  401.  
  402.       /* process redirection  */
  403.  
  404.       if (redir && !err) {
  405.      register char *file = (doexpand) ? av[--ac] : av[ac];
  406.  
  407.      if (redir < 0)
  408.         Cin_name = file;
  409.      else {
  410.         Cout_name = file;
  411.         Cout_append = (redir == 2);
  412.      }
  413.      inc = 0;
  414.       }
  415.  
  416.       /* check elast for space */
  417.  
  418.       if (inc) {
  419.      ++ac;
  420.      if (ac + 2 > MAXAV) {
  421.         ierror (NULL, 506);
  422.         err = 1;            /* error condition */
  423.         elast = 0;            /* don't process any more arguemnts */
  424.      }
  425.       }
  426.       if (elast == ' ')
  427.      goto step5;
  428.    }
  429. stepdone:
  430.    av[ac] = '\0';
  431.  
  432.    /* process pipes via files */
  433.  
  434.    if (elast == '|' && !err) {
  435.       static int which;            /* 0 or 1 in case of multiple pipes */
  436.       which = 1 - which;
  437.       Cout_name = (which) ? Pipe1 : Pipe2;
  438.       Cout_ispipe = 1;
  439.    }
  440.  
  441.  
  442.    if (err)
  443.       goto done0;
  444.  
  445.    {
  446.       register int i, len;
  447.       char save_elast;
  448.       char *compile_av();
  449.       register char *avline;
  450.       unsigned char delim = ' ';
  451.  
  452.       save_elast = elast;
  453.       if (pend_alias || (cmd_stat(command) & ST_AV)) 
  454.       delim = 0xA0;
  455.       avline = compile_av(av,((pend_alias) ? 1 : 0), ac , delim);
  456.  
  457.  
  458.       if (pend_alias) {                      /* special % alias */
  459.      register char *ptr, *scr;
  460.      for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
  461.      set_var (LEVEL_SET, pend_alias + 1, avline);
  462.      free (avline);
  463.  
  464.      scr = malloc((strlen(ptr) << 2) + 2);
  465.      preformat (ptr, scr);
  466.      fcomm (scr, 1);
  467.      unset_var (LEVEL_SET, pend_alias + 1);
  468.       } else {                          /* normal command     */
  469.      register int ccno;
  470.      long  oldcin  = Myprocess->pr_CIS;
  471.      long  oldcout = Myprocess->pr_COS;
  472.      char *Cin_buf;
  473.            struct FileHandle *ci;
  474.      long oldbuf;
  475.      struct _dev *stdfp;
  476.  
  477.      fflush(stdout);
  478.      ccno = find_command (command);
  479.      if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
  480.         if (Cin_name) {
  481.            if ((Cin = (long)Open(Cin_name,1005L)) == 0L) {
  482.           ierror (NULL, 504);
  483.           err = 1;
  484.           Cin_name = '\0';
  485.            } else {
  486.           Myprocess->pr_CIS = _devtab[stdin->_unit].fd = Cin;
  487.               ci = (struct FileHandle *)(((long)Cin)<<2);
  488.           Cin_buf = (char *)AllocMem(202L, MEMF_PUBLIC);
  489.           oldbuf = ci->fh_Buf;
  490.           if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
  491.              ci->fh_Buf = (long)Cin_buf>>2;
  492.            }
  493.         }
  494.         if (Cout_name) {
  495.            if (Cout_append && (Cout =(long)Open(Cout_name, 1005L)) ) {
  496.              Seek(Cout, 0L, 1L);
  497.            } else {
  498.           Cout = (long)Open(Cout_name,1006L);
  499.            }
  500.            if (Cout == NULL) {
  501.           err = 1;
  502.           ierror (NULL, 504);
  503.           Cout_name = '\0';
  504.           Cout_append = 0;
  505.            } else {
  506.           Myprocess->pr_COS = _devtab[stdout->_unit].fd = Cout;
  507.            }
  508.         }
  509.      }
  510.      if (ac < Command[ccno].minargs + 1) {
  511.         ierror (NULL, 500);
  512.         err = -1;
  513.      } else if (!err) {
  514.         i = (*Command[ccno].func)(avline, Command[ccno].val);
  515.         if (i < 0)
  516.            i = 20;
  517.         err = i;
  518.      }
  519.      free (avline);
  520.      if (E_stack == 0 && Lastresult != err) {
  521.         Lastresult = err;
  522.         seterr();
  523.      }
  524.      if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
  525.         if (Cin_name) {
  526.            fflush(stdin);
  527.            clearerr(stdin);
  528.            ci->fh_Buf = oldbuf;
  529.            Close(Cin);
  530.            FreeMem(Cin_buf, 202L);
  531.         }
  532.         if (Cout_name) {
  533.            fflush(stdout);
  534.            clearerr(stdout);
  535.            stdout->_flags &= ~_DIRTY;    /* because of nil: device */
  536.            Close(Cout);
  537.            Cout_append = 0;
  538.         }
  539.      }
  540.          Myprocess->pr_CIS =  _devtab[stdin->_unit].fd  = oldcin;
  541.          Myprocess->pr_COS =  _devtab[stdout->_unit].fd = oldcout;
  542.       }
  543.  
  544.       if (Cin_ispipe && Cin_name)
  545.      DeleteFile(Cin_name);
  546.       if (Cout_ispipe) {
  547.      Cin_name = Cout_name;           /* ok to assign.. static name */
  548.      Cin_ispipe = 1;
  549.       } else {
  550.      Cin_name = '\0';
  551.       }
  552.       Cout_name = '\0';
  553.       Cout_ispipe = 0;
  554.       elast = save_elast;
  555.    }
  556.    mpop_tobase();               /* free arguments   */
  557.    mpush_base();               /* push dummy base  */
  558.  
  559. done0:
  560.    {
  561.       char *str;
  562.       if (err && E_stack == 0) {
  563.      str = get_var(LEVEL_SET, V_EXCEPT);
  564.      if (err >= ((str)?atoi(str):1)) {
  565.         if (str) {
  566.            ++H_stack;
  567.            ++E_stack;
  568.            exec_command(str);
  569.            --E_stack;
  570.            --H_stack;
  571.         } else {
  572.            Exec_abortline = 1;
  573.         }
  574.      }
  575.       }
  576.       if (elast != 0 && Exec_abortline == 0)
  577.      err = fcomm(nextstr, 0);
  578.       Exec_abortline = 0;
  579.       if (Cin_name)
  580.      DeleteFile(Cin_name);
  581.       Cin_name = NULL;
  582.       Cin_ispipe = 0;
  583.    }
  584. done1:
  585.    mpop_tobase();
  586.    if (freeok)
  587.       free(str);
  588.    --alias_count;
  589.    return ((int)err);               /* TRUE = error occured      */
  590. }
  591.  
  592.  
  593. char *
  594. exarg(ptr)
  595. unsigned char **ptr;
  596. {
  597.    register unsigned char *end;
  598.    register unsigned char *start;
  599.  
  600.    start = end = *ptr;
  601.    while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
  602.       ++end;
  603.    elast = *end;
  604.    *end = '\0';
  605.    *ptr = end + 1;
  606.    return ((char *)start);
  607. }
  608.  
  609. static char **Mlist;
  610.  
  611. mpush_base()
  612. {
  613.    char *str;
  614.  
  615.    str = malloc(5);
  616.    *(char ***)str = Mlist;
  617.    str[4] = 0;
  618.    Mlist = (char **)str;
  619. }
  620.  
  621. char *
  622. mpush(bytes)
  623. {
  624.    char *str;
  625.  
  626.    str = malloc(6 + bytes + 2);   /* may need extra 2 bytes in do_run() */
  627.    *(char ***)str = Mlist;
  628.    str[4] = 1;
  629.    Mlist = (char **)str;
  630.    return (str + 5);
  631. }
  632.  
  633. mpop_tobase()
  634. {
  635.    register char *next;
  636.    while (Mlist) {
  637.       next = *Mlist;
  638.       if (((char *)Mlist)[4] == 0) {
  639.      free (Mlist);
  640.      Mlist = (char **)next;
  641.      break;
  642.       }
  643.       free (Mlist);      
  644.       Mlist = (char **)next;
  645.    }
  646. }
  647.  
  648.  
  649. /*
  650.  * Insert 'from' string in front of 'str' while deleting the
  651.  * first entry in 'str'.  if freeok is set, then 'str' will be
  652.  * free'd
  653.  */
  654.  
  655.  
  656.  
  657. char *
  658. format_insert_string(str, from, freeok)
  659. char *str;
  660. char *from;
  661. int *freeok;
  662. {
  663.    register char *new1, *new2;
  664.    register unsigned char *strskip;
  665.    int len;
  666.  
  667.    for (strskip = (unsigned char *)str; *strskip && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
  668.    len = strlen(from);
  669.    new1 = malloc((len << 2) + 2);
  670.    preformat(from, new1);
  671.    len = strlen(new1) + strlen(strskip);
  672.    new2 = malloc(len+2);
  673.    strcpy(new2, new1);
  674.    strcat(new2, strskip);
  675.    new2[len+1] = 0;
  676.    free (new1);
  677.    if (*freeok)
  678.       free (str);
  679.    *freeok = 1;
  680.    return (new2);
  681. }
  682.  
  683. cmd_stat(str)
  684. char *str;
  685. {
  686.    return(Command[find_command(str)].stat);
  687. }
  688.  
  689. find_command(str)
  690. char *str;
  691. {
  692.    int i;
  693.    int len = strlen(str);
  694.  
  695.    if (*str >= '0'  &&    *str <= '9')
  696.       return (1);
  697.    for (i = 0; Command[i].func; ++i) {
  698.       if (strncmp (str, Command[i].name, len) == 0)
  699.      return (i);
  700.    }
  701.    return (0);
  702. }
  703.  
  704. do_help()
  705. {
  706.    register struct COMMAND *com;
  707.    int i= 0;
  708.  
  709.  
  710.    for (com = &Command[2]; com->func; ++com) {
  711.       printf ("%-12s", com->name);
  712.       if (++i  % 6 == 0) printf("\n");
  713.    }
  714.    printf("\n");
  715.    return(0);
  716. }
  717.  
  718.  
  719. char *
  720. push_cpy(s)
  721. char *s;
  722. {
  723.    return(strcpy(mpush(strlen(s)), s));
  724. }
  725.  
  726.  
  727.