home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 488.lha / csh_v5.0 / src / csh500src.lzh / execom.c < prev    next >
C/C++ Source or Header  |  1991-02-17  |  31KB  |  1,222 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.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  9.  * Version 5.00L by Urban Mueller 17-Feb-91
  10.  *
  11.  */
  12.  
  13. #include "shell.h"
  14.  
  15. /* execom.c */
  16. static void preformat(char *s, char *d);
  17. static void backtrans(char *str);
  18. static int fcomm(char *str);
  19. static char *exarg(char **ptr);
  20. static void mpush_base(void);
  21. static char *mpush(int bytes);
  22. static void mpop_tobase(void);
  23. static char *format_insert_string(char *str, char *from);
  24. static int cmd_stat(char *str);
  25. static int find_command(char *str);
  26. static char *push_cpy(char *s);
  27. static void exec_every(void);
  28. static void show_usage(char *str);
  29. static void get_opt(char **av, int *ac, int ccno);
  30. static int checkav( int n );
  31.  
  32.  
  33. int has_wild = 0;                 /* set if any arg has wild card */
  34. char *LastCommand;
  35.  
  36. struct COMMAND {
  37.     int (*func)();
  38.     short minargs;
  39.     short stat;
  40.     int val;
  41.     char *name;
  42.     char *options;
  43.     char *usage;
  44. };
  45.  
  46. extern int do_basename(), do_tackon();
  47. extern int do_fltupper(), do_fltlower(), do_linecnt();
  48. extern int do_strleft(), do_strright(), do_strmid(), do_strlen();
  49. extern int do_fornum(), do_forline(), do_exec();
  50. extern int do_diskchange(), do_stack(), do_fault(), do_path(), do_pri();
  51. extern int do_rpn(), do_resident(), do_truerun(), do_aset(), do_howmany();
  52. extern int do_open(), do_close(), do_fileslist(), do_htype(), do_aget();
  53. extern int do_run(), do_number(), do_assign(), do_join();
  54. extern int do_quit(), do_set_var(), do_unset_var();
  55. extern int do_echo(), do_source(), do_mv(), do_addbuffers();
  56. extern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
  57. extern int do_mem(), do_cat(), do_dir(), do_info(), do_inc();
  58. extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
  59. extern int do_input(), do_ver(), do_sleep(), do_help();
  60. extern int do_strhead(), do_strtail(), do_relabel();
  61. extern int do_copy(), do_date(), do_protect(), do_ps();
  62. extern int do_forever(), do_abortline(), do_strings(), do_touch();
  63. extern int do_window(), do_search(), do_filenote(), do_rxrec(), do_rxsend();
  64. extern int do_ascii(), do_whereis(), do_sort(), do_qcd(), do_usage();
  65. extern int do_uniq(), do_man(), do_head(), do_tee(), do_menu(), do_readfile();
  66. extern int do_rxreturn(), do_split(), do_which(), do_class();
  67. extern int do_action(), do_keymap();
  68.  
  69. #define ST_COND   0x01
  70. #define ST_NORED  0x02
  71. #define ST_NOEXP  0x04
  72. #define ST_AV     0x08 /* delimit args within a variable */
  73. #define ST_FUNC   0x10
  74.  
  75. #define COND  ST_COND
  76. #define NORED ST_NORED
  77. #define NOEXP ST_NOEXP
  78. #define AV    ST_AV
  79. #define FUNC  ST_FUNC
  80.  
  81. #define ALIAS LEVEL_ALIAS
  82. #define SET   LEVEL_SET
  83.  
  84. BPTR   OldCin;
  85.  
  86. struct COMMAND Command[] = {
  87.  do_run,       0,   AV,     0, "\001",       NULL, NULL, /* may call do_source, do_cd */
  88.  do_abortline, 0,    0,     0, "abortline",  NULL, "",
  89.  do_action,    2,    0,     9, "action",     "av", "action file [args]",
  90.  do_addbuffers,2,    0,     0, "addbuffers", NULL, "{drive bufs}",
  91.  do_set_var,   0,    0, ALIAS, "alias",      NULL, "[name [string] ]",/* uses avline */
  92.  do_ascii,     0,    0,     0, "ascii",      "oh", "-oh [string]",
  93.  do_aset,      1,    0,     0, "aset",       NULL, "name value",
  94.  do_assign,    0,    0,     0, "assign",     "ln", ",logical,-ln {logical physical}",
  95.  do_basename,  2, FUNC,     0, "basename",   NULL, "var path",
  96.  do_cat,       0,    0,     0, "cat",        "n",  "-n [file file...]",
  97.  do_cd,        0,    0,     0, "cd",         "g",  "[path],-g path...path",
  98.  do_class,     0,   AV,     0, "class",      "n",  "-n name {type=param} \"actions\" {action=command}",
  99.  do_close,     0,    0,     0, "close",      NULL, "filenumber",
  100.  do_copy,      1,    0,     0, "copy",       "rudpf","-rudpf file file,-ud file...file dir,-ud dir...dir dir",
  101.  do_copy,      1,    0,     0, "cp",         "rudpf","-rudpf file file,-ud file...file dir,-ud dir...dir dir",
  102.  do_date,      0,    0,     0, "date",       "sr", "-sr [date/time]",
  103.  do_inc,       1,    0,    -1, "dec",        NULL, "varname [step]",
  104.  do_rm,        0,    0,     0, "delete",     "rp", "-pr file...file",
  105.  do_dir,       0,NOEXP,     0, "dir",        "sfdcnhltbuikqavo","-abcdfhiklnoqstuv [path...path]",
  106.  do_diskchange,1,    0,     0, "diskchange", NULL, "drive",
  107.  do_echo,      0,   AV,     0, "echo",       "ne", "-ne string",
  108.  do_if,        0, COND,     1, "else",       NULL, "",
  109.  do_if,        0, COND,     2, "endif",      NULL, "",
  110.  do_exec,      1,    0,     0, "exec",       NULL, "command",
  111.  do_fault,     1,    0,     0, "fault",      NULL, "error",
  112.  do_filenote,  1,    0,     0, "filenote",   "s",  "file...file note,-s file...file",
  113.  do_fileslist, 0,    0,     0, "flist",      NULL, "",
  114.  do_fltlower,  0,    0,     0, "fltlower",   NULL, "<in >out",
  115.  do_fltupper,  0,    0,     0, "fltupper",   NULL, "<in >out",
  116.  do_foreach,   3,NORED,     0, "foreach",    "v",  "-v varname ( string ) command",
  117.  do_forever,   1,NORED,     0, "forever",    NULL, "command",
  118.  do_forline,   3,NORED,     0, "forline",    NULL, "var filename command",
  119.  do_fornum,    4,NORED,     0, "fornum",     "vs", "-vs var n1 n2 command",
  120.  do_getenv,    1, FUNC,     0, "getenv",     NULL, "shellvar envvar",
  121.  do_goto,      1,    0,     0, "goto",       NULL, "label",
  122.  do_head,      1,    0,     0, "head",       NULL, "filename [num]",
  123.  do_help,      0,    0,     0, "help",       NULL, "",
  124.  do_history,   0,    0,     0, "history",    NULL, "[partial_string]",
  125.  do_howmany,   0,    0,     0, "howmany",    NULL, "",
  126.  do_htype,     1,    0,     0, "htype",      "r",  "-r file...file",
  127.  do_if,        1,COND|NORED,0, "if",         "rftmdvn","-n arg cond arg,-n arg,-nf file,-nd dir -nm,-nt file...file,-nr rpn_expr,-v varname",
  128.  do_inc,       1,    0,     1, "inc",        NULL, "varname [step]",
  129.  do_info,      0,    0,     0, "info",       NULL, "[drive...drive]",
  130.  do_input,     1,    0,     0, "input",      "sr", "-rs var...var",
  131.  do_join,      2,    0,     1, "join",       "r",  "-r file...file",
  132.  do_keymap,    1,    0,     0, "keymap",     "n",  "-n number {key=function}",
  133.  do_label,     1, COND,     0, "label",      NULL, "name",
  134.  do_linecnt,   0,    0,     0, "linecnt",    NULL, "<in >out",
  135.  do_dir,       0,NOEXP,     0, "ls",         "sfdcnhltbuikqav","-abcdfhiklnqstuv [path...path]",
  136.  do_man,       0,    0,     0, "man",        NULL, "command...command",
  137.  do_mkdir,     0,    0,     0, "md",         NULL, "name...name",
  138.  do_mem,       0,    0,     0, "mem",        "cfqsr","-cfqsr",
  139.  do_menu,      0,    0,     0, "menu",       "n",  "-n [title item...item]",
  140.  do_mkdir,     0,    0,     0, "mkdir",      NULL, "name...name",
  141.  do_mv,        2,    0,     0, "mv",         NULL, "from to,from...from todir",
  142.  do_open,      3,    0,     0, "open",       NULL, "file mode number",
  143.  do_path,      0,    0,     0, "path",       "r",  "-r [dir...dir]",
  144.  do_pri,       2,    0,     0, "pri",        NULL, "clinumber pri,0 pri",
  145.  do_protect,   2,    0,     0, "protect",    NULL, "file...file flags",
  146.  do_ps,        0,    0,     0, "ps",         "le", "-el [commandname...commandname]",
  147.  do_pwd,       0,    0,     0, "pwd",        NULL, "",
  148.  do_qsort,     0,    0,     0, "qsort",      NULL, "<in >out",
  149.  do_quit,      0,NORED,     0, "quit",       NULL, "",
  150.  do_truerun,   1,NORED,     1, "rback",      NULL, "command",
  151.  do_mv,        2,    0,     0, "rename",     NULL, "from to,from...from todir",
  152.  do_readfile,  1,    0,     0, "readfile",   NULL, "varname [filename]",
  153.  do_relabel,   2,    0,     0, "relabel",    NULL, "drive name",
  154.  do_resident,  0,    0,     0, "resident",   "ard",",-ard file...file",
  155.  do_return,    0,    0,     0, "return",     NULL, "[n]",
  156.  do_rm,        0,    0,     0, "rm",         "rp", "-rp file...file",
  157.  do_rpn,       0,NOEXP,     0, "rpn",        NULL, "expression",
  158.  do_rxrec,     0,    0,     0, "rxrec",      NULL, "[portname]",
  159.  do_rxsend,    2,    0,     0, "rxsend",     "rl", "-lc portname string",
  160.  do_truerun,   1,NORED,     0, "run",        NULL, "command",
  161.  do_search,    2,    0,     0, "search",     "rcwneqvbfalo","-abceflnoqrvw file...file string",
  162.  do_set_var,   0,   AV,   SET, "set",        NULL, "[name [string] ]",
  163.  do_setenv,    2,    0,     0, "setenv",     NULL, "var value",
  164.  do_sleep,     0,    0,     0, "sleep",      NULL, "timeout",
  165.  do_split,     1,    0,     0, "split",      NULL, "srcvar dstvar...dstvar",
  166.  do_source,    1,NORED|AV,  0, "source",     NULL, "file", /* uses avline */
  167.  do_stack,     0,    0,     0, "stack",      NULL, "[bytes]",
  168.  do_strhead,   3, FUNC,     0, "strhead",    NULL, "varname breakchar string",
  169.  do_strings,   1,    0,     0, "strings",    "r",  "-r file...file minlength",
  170.  do_strleft,   3, FUNC,     0, "strleft",    NULL, "varname string n",
  171.  do_strlen,    2, FUNC,     0, "strlen",     NULL, "varname string",
  172.  do_strmid,    3, FUNC,     0, "strmid",     NULL, "varname string n1 [n2]",
  173.  do_strright,  3, FUNC,     0, "strright",   NULL, "varname string n",
  174.  do_strtail,   3, FUNC,     0, "strtail",    NULL, "varname breakchar string",
  175.  do_tackon,    3, FUNC,     0, "tackon",     NULL, "var pathname filename",
  176.  do_head,      1,    0,     1, "tail",       NULL, "filename [num]",
  177.  do_tee,       0,    0,     0, "tee",        NULL, "<in >out",
  178.  do_touch,     0,    0,     0, "touch",      NULL, "file...file",
  179.  do_truncate,  0,    0,     0, "truncate",   NULL, "<in >out",
  180.  do_cat,       0,    0,     0, "type",       NULL, "-n [file...file]",
  181.  do_unset_var, 0,    0, ALIAS, "unalias",    NULL, "name...name",
  182.  do_uniq,      0,    0,     0, "uniq",       NULL, "<in >out",
  183.  do_unset_var, 0,    0,   SET, "unset",      NULL, "name...name",
  184.  do_usage,     0,    0,     0, "usage",      NULL, "[command...command]",
  185.  do_ver,       0,    0,     0, "version",    NULL, "",
  186.  do_waitport,  1,    0,     0, "waitforport",NULL, "portname [seconds]",
  187.  do_whereis,   1,NOEXP,     0, "whereis",    "r",  "-r file [path...path]",
  188.  do_window,    0,NOEXP,     0, "window",     "slfbaq","-slfbaq",
  189.  NULL,         0,    0,     0, NULL,         NULL, NULL,
  190. };
  191.  
  192.  
  193. /* do_which,     1,    0,     0, "which",      NULL, "command", */
  194.  
  195. static char elast;        /* last end delimeter */
  196. char Cin_ispipe, Cout_ispipe;
  197.  
  198. #ifdef isalphanum
  199. char isalph[256];
  200. #endif
  201.  
  202. int
  203. exec_command( char *base )
  204. {
  205.     char *scr;
  206.     char buf[32];
  207.  
  208.     if (!H_stack && S_histlen>1) {
  209.         add_history(base);
  210.         sprintf(buf, "%d", H_tail_base + H_len);
  211.         set_var(LEVEL_SET, v_histnum, buf);
  212.     }
  213.     scr = malloc((strlen(base) << 2) + 2);
  214.     preformat(base, scr);
  215.     return (fcomm(scr) ? -1 : 1);
  216. }
  217.  
  218. #ifndef isalphanum
  219. isalphanum( char c )
  220. {
  221.     return (
  222.         (c >= 'a' && c <= 'z') ||
  223.         (c >= 'A' && c <= 'Z') ||
  224.         (c >= '0' && c <= '9') ||
  225.         (c == '_')
  226.     );
  227. }
  228. #endif
  229.  
  230. #define HOT_GAP    0x80
  231. #define HOT_BLANK  0x81
  232. #define HOT_STAR   0x82
  233. #define HOT_QUES   0x83
  234. #define HOT_EXCL   0x84
  235. #define HOT_SEMI   0x85
  236. #define HOT_PIPE   0x86
  237. #define HOT_DOLLAR 0x87
  238. #define HOT_IN     0x88
  239. #define HOT_OUT    0x89
  240. #define HOT_BSLASH 0x8a
  241. #define HOT_APOSTR 0x8b
  242. #define HOT_USAGE  0x8c
  243. #define HOT_SBLANK 0xA0
  244.  
  245.  
  246. static void
  247. preformat( char *s, char *d )
  248. {
  249.     int qm, i;
  250.  
  251.     qm = 0;
  252.     while (*s == ' ' || *s == 9) ++s;
  253.     if      (*s == '\\' ) { *d++=HOT_BSLASH; if( *d++=*++s ) ++s; }
  254.     else if (*s == '~'  ) { *d++=HOT_APOSTR; s++; }
  255.  
  256.     while (*s) {
  257.         if (qm ) {
  258.             while( *s && *s != '\"' && *s != '\\')
  259.                 *d++ = *s++;
  260.             if( !*s ) break;
  261.         }
  262.         switch (*s) {
  263.         case ' ':
  264.         case 9:
  265.             *d++ = HOT_BLANK;
  266.             while (*s == ' ' || *s == 9) ++s;
  267.             if      (*s == '~'  ) { *d++=HOT_APOSTR; s++; }
  268.             else if (*s == 0 || *s == '|' || *s == ';') --d;
  269.             break;
  270.         case '*':
  271.             *d++ = HOT_GAP;
  272.             *d++ = HOT_STAR;
  273.             ++s;
  274.             break;
  275.         case '?':
  276.             *d++ = HOT_GAP;
  277.             *d++ = HOT_QUES;
  278.             ++s;
  279.             break;
  280.         case '!':
  281.             *d++ = HOT_EXCL;
  282.             ++s;
  283.             break;
  284.         case '#':
  285.             *d++ = '\0';
  286.             while (*s) ++s;
  287.             break;
  288.         case ';':
  289.         case '|':
  290.             *d++= (*s++==';') ? HOT_SEMI : HOT_PIPE;
  291.             while (*s == ' ' || *s == 9) ++s;
  292.             if    (*s == '\\' ) { *d++=HOT_BSLASH; if( *d++=*++s ) ++s; }
  293.             break;
  294.         case '\\':
  295.             if( (i=*++s-'0')>=0 && i<=7 ) {
  296.                 if( *++s>='0' && *s<='7' ) {
  297.                     i= 8*i + *s++-'0';
  298.                     if( *s>='0' && *s<='7' )
  299.                         i= 8*i + *s++-'0';
  300.                 }
  301.                 *d++ = i;
  302.             } else {
  303.                 *d++ = *s;
  304.                 if (*s) ++s;
  305.             }
  306.             break;
  307.         case '\"':
  308.             qm = 1 - qm;
  309.             ++s;
  310.             break;
  311.         case '^':
  312.             *d++ = *++s & 0x1F;
  313.             if (*s) ++s;
  314.             break;
  315.         case '<':
  316.             *d++ = HOT_IN;
  317.             ++s;
  318.             break;
  319.         case '>':
  320.             *d++ = HOT_OUT;
  321.             ++s;
  322.             break;
  323.         case '$': /* search end of var name and place false space */
  324.             *d++ = HOT_GAP;
  325.             *d++ = HOT_DOLLAR;
  326.             ++s;
  327.             while (isalphanum(*s)) *d++ = *s++;
  328.             *d++ = HOT_GAP;
  329.             break;
  330.         default:
  331.             *d++ = *s++;
  332.             break;
  333.         }
  334.     }
  335.     *d++=0;
  336.     *d=0;
  337.     if (debug) fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
  338. }
  339.  
  340. static void
  341. backtrans( char *str )
  342. {
  343.     while( *str ) {
  344.         while( *(signed char *)str>0 ) str++;
  345.         if( !*str ) break;
  346.         switch( *str) {
  347.             case HOT_GAP   : *str++=0;    break;
  348.             case HOT_BLANK : *str++=' ';  break;
  349.             case HOT_STAR  : *str++='*';  break;
  350.             case HOT_QUES  : *str++='?';  break;
  351.             case HOT_EXCL  : *str++='!';  break;
  352.             case HOT_SEMI  : *str++=';';  break;
  353.             case HOT_PIPE  : *str++='|';  break;
  354.             case HOT_DOLLAR: *str++='$';  break;
  355.             case HOT_IN    : *str++='<';  break;
  356.             case HOT_OUT   : *str++='>';  break;
  357.             case HOT_BSLASH: *str++='\\'; break;
  358.             case HOT_APOSTR: *str++='~';  break;
  359.             default        : str++;       break;
  360.         }
  361.     }
  362. }
  363.  
  364.  
  365. void *
  366. mymalloc( int len )
  367. {
  368.     return malloc(len);
  369. }
  370.  
  371. extern BPTR extOpen();
  372.  
  373. /*
  374.  * process formatted string.  ' ' is the delimeter.
  375.  *
  376.  *    0: check '\0': no more, stop, done.
  377.  *    1: check $.     if so, extract, format, insert
  378.  *    2: check alias. if so, extract, format, insert. goto 1
  379.  *    3: check history or substitution, extract, format, insert. goto 1
  380.  *
  381.  *    4: assume first element now internal or disk based command.
  382.  *
  383.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  384.  *       in av[] list (except 0x80 args appended).  check in order:
  385.  *
  386.  *             '$'         insert string straight
  387.  *             '>'         setup stdout
  388.  *             '>>'        setup stdout flag for append
  389.  *             '<'         setup stdin
  390.  *             '*' or '?'  do directory search and insert as separate args.
  391.  *
  392.  *             ';' 0 '|'   end of command.  if '|' setup stdout
  393.  *                          -execute command, fix stdin and out (|) sets
  394.  *                           up stdin for next guy.
  395.  */
  396.  
  397.  
  398. int
  399. fcomm( char *str )
  400. {
  401.     static int alias_count;
  402.     int p_alias_count;
  403.     char *istr, *nextstr, *command;
  404.     char *pend_alias;
  405.     int err;
  406.  
  407.     ++alias_count;
  408.  
  409. entry:
  410.     p_alias_count = 0;
  411.     pend_alias = NULL;
  412.     err=0;
  413.     has_wild = 0;
  414.  
  415.     mpush_base();
  416.     if (*str == 0)
  417.         goto done1;
  418. step1:
  419.     if (alias_count >= MAXALIAS || p_alias_count >= MAXALIAS) {
  420.         fprintf(stderr,"Alias Loop\n");
  421.         err = 20;
  422.         goto done1;
  423.     }
  424.  
  425.     istr = NULL;
  426.     if ( *str == HOT_BSLASH )
  427.         memmove( str, str+1, strlen(str));
  428.     else 
  429.         istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
  430.  
  431.     if (istr) {
  432.         p_alias_count++;
  433.         if (*istr == '%' || *istr=='*') {
  434.             pend_alias = istr;
  435.         } else {
  436.             str = format_insert_string(str, istr );
  437.             goto step1;
  438.         }
  439.     }
  440.  
  441.     if (*str == HOT_EXCL) {
  442.         char *p, c;                     /* fix to allow !cmd1;!cmd2 */
  443.         for(p = str; *p && *p != HOT_SEMI ; ++p);
  444.         c = *p;
  445.         *p = '\0';
  446.         istr = get_history(str,1);
  447.         *p = c;
  448.         replace_head(istr);
  449.         str = format_insert_string(str, istr );
  450.         goto step1;
  451.     }
  452.  
  453.     nextstr = str;
  454.     command = exarg(&nextstr);
  455.     if (*command == 0)
  456.         goto done0;
  457.     if (pend_alias == 0) {
  458.         if (cmd_stat(command) & ST_COND)
  459.             goto skipgood;
  460.     }
  461.  
  462.     if (disable || forward_goto) {
  463.         while (elast && elast != HOT_SEMI && elast != HOT_PIPE)
  464.             exarg(&nextstr);
  465.         goto done0;
  466.     }
  467. skipgood:
  468.     {
  469.         char *arg, *ptr;
  470.         short redir;
  471.         short doexpand;
  472.         short cont;
  473.         short inc;
  474.  
  475.         ac = 1;
  476.         av[0] = command;
  477.         backtrans( av[0] );
  478. step5:                                          /* ac = nextac */
  479.         if (!elast || elast == HOT_SEMI || elast == HOT_PIPE)
  480.             goto stepdone;
  481.  
  482.         av[ac] = NULL;
  483.         cont = 1;
  484.         doexpand = redir = inc = 0;
  485.  
  486.         while (cont && elast) {
  487.             int cstat = cmd_stat(command);
  488.  
  489.             ptr = exarg(&nextstr);
  490.             inc = 1;
  491.             arg = "";
  492.             cont = (elast == 0x80);
  493.             switch (*ptr) {
  494.             case HOT_IN:
  495.                 redir = -2;
  496.             case HOT_OUT:
  497.                 if (cstat & (ST_NORED | ST_COND)) {     /* don't extract   */
  498.                     redir = 0;                          /* <> stuff if its */
  499.                     arg = ptr;                          /* external cmd.   */
  500.                     break;
  501.                 }
  502.                 ++redir;
  503.                 arg = ptr + 1;
  504.                 if (*arg == HOT_OUT) {
  505.                     redir = 2;        /* append >> */
  506.                     ++arg;
  507.                 }
  508.                 cont = 1;
  509.                 break;
  510.             case HOT_DOLLAR:
  511.                 /* restore args if from set command or pend_alias */
  512.                 if ((arg = get_var(LEVEL_SET, ptr + 1)) != NULL) {
  513.                     char *pe, sv;
  514.                     while (pe = index(arg,0xA0)) {
  515.                         sv = *pe;
  516.                         *pe = '\0';
  517.                         checkav(1);
  518.                         av[ac++] = push_cpy(arg);
  519.                         *pe = sv;
  520.                         av[ac] = NULL;
  521.                         arg = pe+1;
  522.                     }
  523.                 } else
  524.                     arg = ptr;
  525.                 break;
  526.             case HOT_APOSTR:
  527.                 if ((arg = get_var(LEVEL_SET, v_lcd)) != NULL) {
  528.                     if( ptr[1] ) {
  529.                         strcpy(Buf,arg);
  530.                         appendslash(Buf);
  531.                         strcat(Buf,ptr+1);
  532.                         arg=Buf;
  533.                     }
  534.                 } else
  535.                     arg = ptr;
  536.                 break;
  537.  
  538.             case HOT_STAR:
  539.             case HOT_QUES:
  540.                 if((cstat & ST_NOEXP) == 0 && !(pend_alias && *istr=='*'))
  541.                     if(ac==1&&(av[1]==NULL||!*av[1])&& *ptr==HOT_QUES&& !ptr[1])
  542.                         ;
  543.                     else 
  544.                         doexpand = 1;
  545.                 arg = ptr;
  546.                 break;
  547.             default:
  548.                 arg = ptr;
  549.                 break;
  550.             }
  551.  
  552.             /* Append arg to av[ac] */
  553.  
  554.             if (av[ac]) {
  555.                 char *old = av[ac];
  556.                 av[ac] = mpush(strlen(arg)+strlen(av[ac]));
  557.                 strcpy(av[ac], old);
  558.                 strcat(av[ac], arg);
  559.             } else
  560.                 av[ac] = push_cpy(arg);
  561.  
  562.             if (elast != 0x80)
  563.                 break;
  564.         }
  565.  
  566.         /* process expansion */
  567.  
  568.         backtrans( av[ac] );
  569.         if (doexpand) {
  570.             char **eav, **ebase;
  571.             int eac;
  572.             has_wild = 1;
  573.             eav = ebase = expand(av[ac], &eac);
  574.             inc = 0;
  575.             if (eav) {
  576.                 if( checkav( eac ) ) {
  577.                     ierror (NULL, 506);
  578.                     err = 1;
  579.                 } else {
  580.                     QuickSort(eav, eac);
  581.                     for (; eac; --eac, ++eav)
  582.                     av[ac++] = push_cpy(*eav);
  583.                 }
  584.                 free_expand (ebase);
  585.             }
  586.         } else if( av[ac][0]==')' ) {
  587.             int i;
  588.             char *pe, sv;
  589.             for( i=ac-1; i>0; i-- )
  590.                 if( *av[i]=='@' )
  591.                     break;
  592.             if( i>0 && av[i][strlen(av[i])-1]=='(' ) {
  593.                 extern int exec_fn_err;
  594.                 char *exec_function();
  595.                 char *avi=av[i], *last=av[ac];
  596.                 av[i]=v_value; av[ac]=NULL;
  597.                 arg=exec_function( avi+1, av+i, ac-i );
  598.                 av[i]=avi;     av[ac]=last;
  599.                 inc=0;
  600.                 if( exec_fn_err<0 )
  601.                     ac++;
  602.                 else if( exec_fn_err>0 || !arg )
  603.                     ac=i, av[ac++]="";
  604.                 else {
  605.                     ac=i;
  606.                     while (pe = index(arg,0xA0)) {
  607.                         sv = *pe;
  608.                         *pe = '\0';
  609.                         checkav( 2 );
  610.                         av[ac++] = push_cpy(arg);
  611.                         *pe = sv;
  612.                         arg= pe+1;
  613.                     }
  614.                     av[ac] = mpush(strlen(arg)+strlen(last+1)+4);
  615.                     strcpy(av[ac],arg);
  616.                     strcat(av[ac++], last+1 );
  617.                 }
  618.             }
  619.         }
  620.  
  621.  
  622.         /* process redirection  */
  623.  
  624.         if (redir && !err) {
  625.             char *file = (doexpand) ? av[--ac] : av[ac];
  626.  
  627.             if (redir < 0)
  628.                 Cin_name = file;
  629.             else {
  630.                 Cout_name = file;
  631.                 Cout_append = (redir == 2);
  632.             }
  633.             inc = 0;
  634.         }
  635.  
  636.         /* check elast for space */
  637.  
  638.         if (inc) {
  639.             ++ac;
  640.             if (ac + 2 > MAXAV) {
  641.                 ierror (NULL, 506);
  642.                 err = 1;                /* error condition */
  643.                 elast = 0;              /* don't process any more arguemnts */
  644.             }
  645.         }
  646.         if (elast == HOT_BLANK)
  647.             goto step5;
  648.     }
  649. stepdone:
  650.     av[ac] = NULL;
  651.  
  652.     /* process pipes via files */
  653.  
  654.     if (elast == HOT_PIPE && !err) {
  655.         static int which;             /* 0 or 1 in case of multiple pipes */
  656.         which = 1 - which;
  657.         Cout_name = (which) ? Pipe1 : Pipe2;
  658.         Cout_ispipe = 1;
  659.     }
  660.  
  661.  
  662.     if (err)
  663.         goto done0;
  664.  
  665.     {
  666.         int i;
  667.         char save_elast;
  668.         char *avline;
  669.         char delim = ' ';
  670.         char *larg=av[ac-1];
  671.  
  672.         if( *larg && larg[strlen(larg)-1]=='&' ) {
  673.             memmove( av+1, av, (ac-1)*sizeof(*av));
  674.             command=av[0]="rback";
  675.             if( strlen(larg)>1 )
  676.                 larg[strlen(larg)-1]=0, ac++;
  677.         }
  678.         save_elast = elast;
  679.         if (pend_alias || (cmd_stat(command) & ST_AV))
  680.             delim = 0xA0;
  681.         avline = compile_av(av,((pend_alias) ? 1 : 0), ac, delim, 0);
  682.  
  683.         if (pend_alias) {                               /* special % alias */
  684.             char *ptr, *scr, *varname, *val=avline, *gap;
  685.             ptr=pend_alias;
  686.             do {                                        /* set all args    */
  687.                 for ( varname= ++ptr; *ptr && *ptr!=' ' && *ptr!='%'; ++ptr);
  688.                 if( *ptr=='%' && (gap=index(val,0xA0 )) ) *gap=0;
  689.                 set_var( LEVEL_SET, varname, val );
  690.                 val= gap ? gap+1 : "";
  691.             } while( *ptr=='%' );
  692.             free (avline);
  693.  
  694.             scr = malloc((strlen(ptr) << 2) + 2);
  695.             preformat (ptr, scr);
  696.             fcomm (scr);
  697.             ptr=pend_alias;
  698.             do {                                        /* unset all args  */
  699.                 for ( varname=++ptr; *ptr && *ptr!=' ' && *ptr!='%'; ++ptr);
  700.                 unset_var( LEVEL_SET, varname );
  701.             } while( *ptr=='%' );
  702.             unset_var (LEVEL_SET, pend_alias + 1);
  703.         } else {                                        /* normal command  */
  704.             int ccno;
  705.             BPTR  oldcin  = Myprocess->pr_CIS;
  706.             BPTR  oldcout = Myprocess->pr_COS;
  707.             char *Cin_buf;
  708.             struct FileHandle *ci;
  709.             long oldbuf;
  710.  
  711.             OldCin=oldcin;
  712.             fflush(stdout);
  713.             LastCommand=command;
  714.             ccno = find_command ( command);
  715.             if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
  716.                 if (Cin_name) {
  717.                     if ((Cin = (long)extOpen(Cin_name,1005L)) == 0) {
  718.                         ierror (NULL, 504);
  719.                         err = 1;
  720.                         Cin_name = NULL;
  721.                     } else {
  722.                         Myprocess->pr_CIS = DEVTAB(stdin) = Cin;
  723.                         ci = (struct FileHandle *)(((long)Cin)<<2);
  724.                         Cin_buf = AllocMem(202L, MEMF_PUBLIC);
  725.                         oldbuf = ci->fh_Buf;
  726.                         if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
  727.                             ci->fh_Buf = (long)Cin_buf>>2;
  728.                     }
  729.                 }
  730.                 if (Cout_name) {
  731.                     if (Cout_append && (Cout =(long)extOpen(Cout_name,1005L))) {
  732.                         Seek(Cout, 0L, 1L);
  733.                     } else {
  734.                         Cout = (long)extOpen(Cout_name,1006L);
  735.                     }
  736.                     if (Cout == NULL) {
  737.                         err = 1;
  738.                         ierror (NULL, 504);
  739.                         Cout_name = NULL;
  740.                         Cout_append = 0;
  741.                     } else {
  742.                         Myprocess->pr_COS = DEVTAB(stdout) = Cout;
  743.                     }
  744.                 }
  745.             }
  746.             if (ac < Command[ccno].minargs + 1) {
  747.                 show_usage( NULL );
  748.                 err = -1;
  749.             } else if (!err) {
  750.                 int (*func)(char*,int)=Command[ccno].func;
  751.                 get_opt( av, &ac, ccno );
  752.                 i=0;
  753.                 if( ccno>0 && ac>1 && !strcmp(av[1],"?") )
  754.                     show_usage(avline);
  755.                 else 
  756.                     i = (*func)(avline, Command[ccno].val);
  757.                 fflush(stderr);
  758.                 if (i < 0)
  759.                     i = 20;
  760.                 err = i;
  761.             }
  762.             free (avline);
  763.             if (E_stack == 0 && Lastresult != err) {
  764.                 Lastresult = err;
  765.                 seterr();
  766.             }
  767.             if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
  768.                 if (Cin_name) {
  769.                     ci->fh_Buf = oldbuf;
  770.                     fflush(stdin);
  771.                     clearerr(stdin);
  772. #ifdef AZTEC_C
  773.                     stdin->_bp=stdin->_bend;
  774. #else
  775.                     stdin->_rcnt=stdin->_wcnt;
  776. #endif
  777.                     extClose(Cin);
  778.                     FreeMem(Cin_buf, 202L);
  779.                 }
  780.                 if (Cout_name) {
  781.                     fflush(stdout);
  782.                     clearerr(stdout);
  783. #ifdef AZTEC_C
  784.                     stdout->_flags &= ~_IODIRTY;    /* because of nil: device */
  785. #endif
  786.                     extClose(Cout);
  787.                     Cout_append = 0;
  788.                 }
  789.             }
  790.             Myprocess->pr_CIS = DEVTAB(stdin)  = oldcin;
  791.             Myprocess->pr_COS = DEVTAB(stdout) = oldcout;
  792.         }
  793.  
  794.         if (Cin_ispipe && Cin_name)
  795.             DeleteFile(Cin_name);
  796.         if (Cout_ispipe) {
  797.             Cin_name = Cout_name;         /* ok to assign.. static name */
  798.             Cin_ispipe = 1;
  799.         } else {
  800.             Cin_name = NULL;
  801.         }
  802.         Cout_name = NULL;
  803.         Cout_ispipe = 0;
  804.         elast = save_elast;
  805.     }
  806.     mpop_tobase();                      /* free arguments   */
  807.     mpush_base();                       /* push dummy base  */
  808.  
  809. done0:
  810.     {
  811.         char *exc;
  812.         if (err && E_stack == 0) {
  813.             exc = get_var(LEVEL_SET, v_except);
  814.             if (err >= ((exc)?atoi(exc):1)) {
  815.                 if (exc) {
  816.                     ++H_stack, ++E_stack;
  817.                     a0tospace(exc);
  818.                     exec_command(exc);
  819.                     --E_stack, --H_stack;
  820.                 } else {
  821.                     Exec_abortline = 1;
  822.                 }
  823.             }
  824.         }
  825.         if (elast != 0 && Exec_abortline == 0) {
  826.             memmove( str, nextstr, strlen(nextstr)+1 );
  827.             goto entry;
  828.         }
  829.         Exec_abortline = 0;
  830.         if (Cin_name)
  831.             DeleteFile(Cin_name);
  832.         Cin_name = NULL;
  833.         Cin_ispipe = 0;
  834.     }
  835. done1:
  836.     mpop_tobase();
  837.     free(str);
  838.     --alias_count;
  839.     return err;                      /* TRUE = error occured    */
  840. }
  841.  
  842.  
  843. static char *
  844. exarg(ptr)
  845. char **ptr;
  846. {
  847.     char *end, *start;
  848.  
  849.     start = end = *ptr;
  850.     while ( *(signed char *)end>0 || *end && *end != 0x80 &&
  851.              *end != HOT_SEMI &&  *end != HOT_PIPE && *end != HOT_BLANK)
  852.         ++end;
  853.     elast = *end;
  854.     *end = '\0';
  855.     *ptr = end + 1;
  856.     return start;
  857. }
  858.  
  859. static char **Mlist;
  860.  
  861. static void
  862. mpush_base()
  863. {
  864.     char *str;
  865.  
  866.     str = malloc(5);
  867.     *(char ***)str = Mlist;
  868.     str[4] = 0;
  869.     Mlist = (char **)str;
  870. }
  871.  
  872. static char *
  873. mpush(bytes)
  874. {
  875.     char *str;
  876.  
  877.     str = malloc(6 + bytes + 2);   /* may need extra 2 bytes in do_run() */
  878.     *(char ***)str = Mlist;
  879.     str[4] = 1;
  880.     Mlist = (char **)str;
  881.     return (str + 5);
  882. }
  883.  
  884. static void
  885. mpop_tobase()
  886. {
  887.     char *next;
  888.     while (Mlist) {
  889.         next = *Mlist;
  890.         if (((char *)Mlist)[4] == 0) {
  891.             free (Mlist);
  892.             Mlist = (char **)next;
  893.             break;
  894.         }
  895.         free (Mlist);
  896.         Mlist = (char **)next;
  897.     }
  898. }
  899.  
  900.  
  901. /*
  902.  * Insert 'from' string in front of 'str' while deleting the
  903.  * first entry in 'str'.  if freeok is set, then 'str' will be
  904.  * free'd
  905.  */
  906.  
  907. static char *
  908. format_insert_string(char *str, char *from)
  909. {
  910.     char *new1, *new2;
  911.     char *strskip;
  912.     int len;
  913.  
  914.     for (strskip = str; *(signed char *)strskip>0 ||
  915.         *strskip && *strskip != HOT_BLANK 
  916.         && *strskip != HOT_SEMI && *strskip != HOT_PIPE
  917.         && *strskip != 0x80; ++strskip);
  918.     len = strlen(from);
  919.     new1 = malloc((len << 2) + 2);
  920.     preformat(from, new1);
  921.     len = strlen(new1) + strlen(strskip);
  922.     new2 = malloc(len+2);
  923.     strcpy(new2, new1);
  924.     strcat(new2, strskip);
  925.     new2[len+1] = 0;
  926.     free (new1);
  927.     free (str);
  928.     return new2;
  929. }
  930.  
  931. static int
  932. cmd_stat( char *str )
  933. {
  934.     return (int)Command[find_command(str)].stat;
  935. }
  936.  
  937. char *
  938. find_internal( char *str )
  939. {
  940.     return(Command[find_command(str)].name);
  941. }
  942.  
  943. static int
  944. find_command( char *str )
  945. {
  946.     int i, len = strlen(str);
  947.     struct COMMAND *com;
  948.     char c=*str;
  949.  
  950.     for( com=Command, i=0; com->func; com++, i++ )
  951.         if ( c==*com->name && !strncmp(str, com->name, len))
  952.             return i;
  953.     return 0;
  954. }
  955.  
  956. int exec_fn_err;
  957.  
  958. extern struct FUNCTION {
  959.     short id, minargs, maxargs;
  960.     char *name;
  961. } Function[];
  962.  
  963.  
  964. char *gotfunc( int i, char **fav, int fac );
  965.  
  966. char *
  967. exec_function( char *str, char **fav, int fac)
  968. {
  969.     int len=strlen(str)-1, i;
  970.  
  971.     exec_fn_err=0;
  972.     for (i = 0; Command[i].func; ++i)
  973.         if ( Command[i].stat&ST_FUNC && !strncmp(str,Command[i].name,len)) {
  974.             if( fac<Command[i].minargs ) {
  975.                 exec_fn_err=20;
  976.                 return NULL;
  977.             } else {
  978.                 int (*func)( void )=Command[i].func;
  979.                 char **oldav=av;
  980.                 int  oldac=ac;
  981.                 av=fav-1, ac=fac+1;
  982.                 exec_fn_err=(*func)();
  983.                 av=oldav, ac=oldac;
  984.                 return get_var( LEVEL_SET, fav[0] );
  985.             }
  986.         }
  987.     for (i = 0; Function[i].id; ++i)
  988.         if ( len==strlen(Function[i].name)&&!strncmp(str,Function[i].name,len))
  989.             return gotfunc( i,fav,fac );
  990.  
  991.     exec_fn_err=-1;
  992.     return NULL;
  993. }
  994.  
  995. int
  996. echofunc(void)
  997. {
  998.     int  i;
  999.     char *str;
  1000.  
  1001.     if( !strlen(av[0]) ) return -1;
  1002.     exec_fn_err=0;
  1003.     for (i = 0; Function[i].id; ++i)
  1004.         if ( !strcmp(av[0],Function[i].name)) {
  1005.             if(str=gotfunc( i,av,ac ))
  1006.                 printf("%s\n",str);
  1007.             return exec_fn_err;
  1008.         }
  1009.     return -1;
  1010. }
  1011.  
  1012.  
  1013. char *
  1014. gotfunc( int i, char **fav, int fac )
  1015. {
  1016.     fac--; fav++;
  1017.     if( fac<Function[i].minargs ) {
  1018.         fprintf( stderr, "Not enough arguments for @%s\n",
  1019.                           Function[i].name );
  1020.         exec_fn_err=20;
  1021.         return NULL;
  1022.     } else if( fac>Function[i].maxargs ) {
  1023.         if( ac > Function[i].maxargs )
  1024.             fprintf( stderr, "Too many arguments for @%s\n",
  1025.                               Function[i].name );
  1026.         exec_fn_err=20;
  1027.         return NULL;
  1028.     } else {
  1029.         exec_fn_err=dofunc( Function[i].id, fav, fac);
  1030.         return get_var( LEVEL_SET, v_value );
  1031.     }
  1032.     return NULL;
  1033. }
  1034.  
  1035.  
  1036.  
  1037. do_help()
  1038. {
  1039.     struct COMMAND *com;
  1040.     int i=0;
  1041.  
  1042.     for (com = &Command[1]; com->func; ++com) {
  1043.         printf ("%-12s", com->name);
  1044.         if (++i % 6 == 0) printf("\n");
  1045.     }
  1046.     printf("\n\nUse   man <command>   for more information\n");
  1047.     return 0;
  1048. }
  1049.  
  1050. static char *
  1051. push_cpy(s)
  1052. char *s;
  1053. {
  1054.     return strcpy(mpush(strlen(s)), s);
  1055. }
  1056.  
  1057. void
  1058. exec_every(void)
  1059. {
  1060.     char *str = get_var(LEVEL_SET, v_every);
  1061.  
  1062.     if (str) {
  1063.         ++H_stack, ++E_stack;
  1064.         a0tospace( str );
  1065.         exec_command(str);
  1066.         --E_stack, --H_stack;
  1067.     }
  1068. }
  1069.  
  1070. char *
  1071. a0tospace( str )
  1072.     char *str;
  1073. {
  1074.     char *get=str, *put=str;
  1075.  
  1076.     while( *get )
  1077.         if( *get==0xA0 )
  1078.             *put++=' ', get++;
  1079.         else 
  1080.             *put++=*get++;
  1081.     return str;
  1082. }
  1083.  
  1084. void
  1085. show_usage( str )
  1086.     char *str;
  1087. {
  1088.     int ccno, first=0, err=0;
  1089.     char *get, *put, buf[300];
  1090.  
  1091.     if( !str )
  1092.         str=LastCommand, err=1;
  1093.     for( put=str; *put && (*put&127)!=32; put++ ) ;
  1094.     *put=0;
  1095.  
  1096.     put=buf;
  1097.     ccno = find_command (str);
  1098.     if( get= Command[ccno].usage ) {
  1099.         do {
  1100.             put+=sprintf(put, first++?"       %s ":"Usage: %s ",
  1101.                          Command[ccno].name );
  1102.             if( *get=='-' ) {
  1103.                 *put++='['; *put++='-';
  1104.                 get++;
  1105.                 while( *get && *get!=' ' && *get!=',' )
  1106.                     *put++=*get++;
  1107.                 *put++=']';
  1108.             }
  1109.             while( *get && *get!=','  )
  1110.                 *put++=*get++;
  1111.             *put++='\n';
  1112.         } while( *get++ );
  1113.         *put=0;
  1114.         fprintf( err ? stderr : stdout, "%s", buf );
  1115.     }
  1116. }
  1117.  
  1118. int
  1119. execute( char *str )
  1120. {
  1121.     char  **tav=av, telast=elast;
  1122.     int   tac=ac;
  1123.     ULONG toptions=options;
  1124.     int   thas_wild=has_wild;
  1125.  
  1126.     if( !str ) return -1;
  1127.  
  1128.     ++H_stack;
  1129.     exec_command(str);
  1130.     --H_stack;
  1131.  
  1132.     av=tav; ac=tac; elast=telast; options=toptions; has_wild=thas_wild;
  1133.  
  1134.     return 0;
  1135. }
  1136.  
  1137. do_exec( char *str )
  1138. {
  1139.     return execute( next_word( str ) );
  1140. }
  1141.  
  1142. int
  1143. interactive( void )
  1144. {
  1145.     return IsInteractive(Output());
  1146. }
  1147.  
  1148. static int
  1149. checkav( int n )
  1150. {
  1151.     char **tmp;
  1152.     int newac;
  1153.  
  1154.     if( ac+n+10>=max_ac ) {
  1155.         newac=max_ac+n+40;
  1156.         if( tmp=(char **)malloc(newac*sizeof(char *))) {
  1157.             memcpy(tmp,av,max_ac*sizeof(char *));
  1158.             free(av);
  1159.             av=tmp; max_ac=newac;
  1160.         } else 
  1161.             return 1;
  1162.     }
  1163.     return 0;
  1164. }
  1165.  
  1166. /*    Parse the options specified in sw[]
  1167.     Setting a bit in global variable options
  1168.     for each one found
  1169. */
  1170.  
  1171. static void
  1172. get_opt( char **av, int *ac, int ccno )
  1173. {
  1174.     char **get=av+1,**put=av+1, *c, *s;
  1175.     int i=1, l, usage=0, nac;
  1176.     long oldopts;
  1177.  
  1178.     options=0;
  1179.     if( !ccno )
  1180.         return;
  1181.  
  1182.     for( ; i<*ac && *av[i]=='-'; i++, get++ ) {
  1183.         if( !*(c=*get+1) )
  1184.             goto stop;
  1185.         oldopts=options;
  1186.         for ( ; *c ; c++) {
  1187.             if( *c<'a' || *c>'z' ) 
  1188.                 { options=oldopts; goto stop; }
  1189.             for( l=0, s=Command[ccno].options; *s && *s != *c; ++s )
  1190.                 ++l;
  1191.             if ( *s )
  1192.                 options |= (1 << l);
  1193.             else if( !usage ) {
  1194.                 usage=1;
  1195.                 show_usage(NULL);
  1196.             }
  1197.         }
  1198.     }
  1199. stop:
  1200.     for( nac=1; i<*ac; i++ )
  1201.         *put++=*get++, nac++;
  1202.     *put=NULL;
  1203.     *ac=nac;
  1204. }
  1205.  
  1206. #if 0
  1207. USHORT Options[160];
  1208.  
  1209. int
  1210. do_options()
  1211. {
  1212.     for( i=1; i<ac; i+=2 ) {
  1213.         if( ac-i<=1 )
  1214.             { ierror( av[i], 500 ); return 20; }
  1215.         if( *av[i+1]!='-' )
  1216.             { ierror( av[i+1], 500 ); return 20; }
  1217.         options=0;
  1218.         parseopts( av[i+1]+1 );
  1219.     }
  1220. }
  1221. #endif
  1222.