home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / dirs / line_457.lzh / Line / line.c < prev    next >
C/C++ Source or Header  |  1991-02-14  |  27KB  |  1,115 lines

  1. /*  :ts=8  */
  2. /*  $Header: yyy:work/sh/RCS/line.c,v 1.15 90/08/28 01:16:08 john Beta $  */
  3.  
  4. /*
  5.  *    known bugs: 
  6.  *    o  env var args limited to 20
  7.  *    o  any number of them at end of long line
  8.  *    o  recognises scripts, but doesn't know what to do with them
  9.  */
  10.  
  11. #include <ctype.h>
  12. #include <string.h>
  13. #include <arpbase.h>
  14. #include <exec/exec.h>
  15. #include <libraries/dos.h>
  16. #include <libraries/dosextens.h>
  17. #include <functions.h>
  18.  
  19. #pragma amicall(ArpBase,0x276,BaseName(a0))
  20. #pragma amicall(ArpBase,0xea,FPrintf(d0,a0,a1))
  21. #pragma amicall(ArpBase,0xfc,GADS(a0,d0,a1,a2,a3))
  22. #pragma amicall(ArpBase,0x11a,Getenv(a0,a1,d0))
  23. #pragma amicall(ArpBase,0x14a,PathName(d0,a0,d1))
  24. #pragma amicall(ArpBase,0xe4,Printf(a0,a1))
  25. #pragma amicall(ArpBase,0x210,Strncmp(a0,a1,d0))
  26. #pragma amicall(ArpBase,0x21c,SyncRun(a0,a1,d0,d1))
  27. struct ArpBase *ArpBase;
  28.  
  29. char *tmpnam (char *_s);
  30.  
  31. #define CSI        0x9b
  32. #define KEY_UNKNOWN    -1
  33.  
  34. #define CTRL(c)        ('c'&037)
  35.  
  36. #define WERASE        CTRL(w)
  37. #define KILL        CTRL(u)
  38. #define ESC        '\033'
  39. #define TAB        CTRL(i)
  40. #define BS        CTRL(h)
  41. #define RET        CTRL(j)
  42. #define NL        CTRL(m)
  43. #define QUIT        CTRL(q)
  44. #define AMIKILL        CTRL(x)
  45.  
  46. #define BIGNUMBER    256
  47. #define MAXLINE        255
  48. #define ALIASLOOP    20
  49. #define BUILTIN        9
  50. #define IGNORE        ""
  51. #define PROMPT        "%N> "
  52. #define TMPDIR        "tmp:"
  53. #define STARTUP        "s:.linerc"
  54. #define MAXHIST        20
  55. #define MAXALIAS    20
  56. #define MAXPP        5
  57.  
  58. #define DOS_TRUE    -1
  59. #define DOS_FALSE    0
  60. #define raw()        ttymode(DOS_TRUE)
  61. #define cooked()    ttymode(DOS_FALSE)
  62.  
  63. typedef unsigned char byte;
  64. typedef char bool;
  65.  
  66. char *progname;
  67. bool is_dflt=TRUE;
  68. char *prompt=PROMPT, *ignorelist=IGNORE, *tmpdir=TMPDIR;
  69. char *startup=STARTUP;
  70.  
  71. struct FileInfoBlock *fib;
  72. struct MsgPort *rp;
  73. struct StandardPacket *packet;
  74.  
  75. #define A_EMPTY(x)    (!A[x].name)
  76.  
  77. int a_max=MAXALIAS;
  78.  
  79. struct alias {
  80.     char *name, *sub;
  81. } *A;
  82.  
  83. #define hINC(i)        (((i)+1) % h_max)
  84. #define hDEC(i)        (!(i) ? h_max-1 : (i)-1)
  85.  
  86. int h_num, h_max=MAXHIST, cmd_number;
  87.  
  88. struct history {
  89.     int num;
  90.     char line[MAXLINE+1];
  91. } *H;
  92.  
  93. int pp_max=MAXPP, pp_sp=-1;
  94. long *pp_stk;
  95.  
  96. int errcode=-1;
  97.  
  98. int fprintf (long _fh, const char *_format, ...)
  99. {
  100.     return (FPrintf (_fh, _format, (char *) &_format + sizeof (char *)));
  101. }
  102.  
  103. int printf (const char *_format, ...)
  104. {
  105.     return (Printf (_format, (char *) &_format + sizeof (char *)));
  106. }
  107.  
  108. int do_csi ()
  109. {
  110.     char ch;
  111.  
  112.     Read (Input(), &ch, 1);
  113.     switch (ch) {
  114.         case 'A':
  115.         case 'B':
  116.         case 'C':
  117.         case 'D':
  118.         case 'T':
  119.         case 'S':
  120.         break;
  121.         case '1':
  122.         Read (Input(), &ch, 1);
  123.             if (ch == '~') break;
  124.         /* else falls through */
  125.         case '?':
  126.     case ' ':
  127.         default:
  128.         Read (Input(), &ch, 1);
  129.     }
  130.     return (KEY_UNKNOWN);
  131. }
  132.  
  133. /*
  134.  *    The code for ttymode() was garnered directly from code
  135.  *    by Chuck McManis, CBM (Phil Lindsay, Carolyn Scheppner,
  136.  *    && Andy Finkel), and a tutorial from Michael van Elst.
  137.  */
  138.  
  139. void ttymode (mode)
  140. long mode;
  141. {
  142.     long fh;
  143.     struct MsgPort *mp;
  144.  
  145.     fh = Input();
  146.     mp = ((struct FileHandle *)(fh<<2))->fh_Type;
  147.     packet->sp_Msg.mn_Node.ln_Name = (char *) &packet->sp_Pkt;
  148.     packet->sp_Pkt.dp_Link = &packet->sp_Msg;
  149.     packet->sp_Pkt.dp_Port = rp;
  150.     packet->sp_Pkt.dp_Type = ACTION_SCREEN_MODE;
  151.     packet->sp_Pkt.dp_Arg1 = mode;
  152.     PutMsg (mp, (struct Message *) packet);
  153.     WaitPort (rp);
  154.     GetMsg (rp);
  155. }
  156.  
  157. void cleanup ()
  158. {
  159.     int i;
  160.  
  161.     if (pp_stk)
  162.         for (i = 0; i < pp_max; i++) if (pp_stk[i]) UnLock (pp_stk[i]);
  163.     CloseLibrary (ArpBase);
  164.     if (fib) FreeMem (fib, sizeof (struct FileInfoBlock));
  165.     if (packet) FreeMem (packet, sizeof (struct StandardPacket));
  166.     if (rp) DeletePort (rp);
  167. }
  168.  
  169. void _abort    () { /* stub */ }
  170. void _wb_parse () { /* stub */ }
  171.  
  172. char *toint (p, i)
  173. char *p;
  174. int *i;
  175. {
  176.     *i = 0;
  177.     while (isdigit (*p))
  178.         *i = *i * 10 + (*p++ - '0');
  179.     return (p);
  180. }
  181.  
  182. void makeargs (s, n, args)
  183. char *s, ***args;
  184. int *n;
  185. {
  186.     int i, j;
  187.  
  188.     i = *n = 0;
  189.     while (s[i]) {
  190.         while (s[i] && isspace(s[i])) i++;
  191.         if (s[i]) (*n)++;
  192.         while (s[i] && !isspace(s[i])) {
  193.         if (s[i] == '\"') {
  194.             i++;
  195.             while (s[i] && s[i] != '\"') i++;
  196.         }
  197.         i++;
  198.     }
  199.     }
  200.     if ( !(*args = (char **) malloc (*n * sizeof (char *))) ) {
  201.         printf ("%s: out of memory\n", progname);
  202.         exit (RETURN_FAIL);
  203.     }
  204.     i = j = 0;
  205.     while (s[i]) {
  206.         while (s[i] && isspace(s[i])) i++;
  207.         if (s[i]) {
  208.             (*args)[j] = &s[i];
  209.             j++;
  210.         }
  211.         while (s[i] && !isspace(s[i])) {
  212.         if (s[i] == '\"') {
  213.             i++;
  214.             while (s[i] && s[i] != '\"') i++;
  215.         }
  216.         i++;
  217.     }
  218.     if (s[i]) s[i++] = '\0';
  219.     }
  220. }
  221.  
  222. /*
  223.  *    return -1 if error (-2 if it be fatal), 0 if not builtin,
  224.  *    1 otherwise
  225.  */
  226.  
  227. int builtin (name, args, fh)
  228. char *name, *args;
  229. long fh;
  230. {
  231.     int i, j, k, orig_len;
  232.     char **argv, *p, t[MAXLINE];
  233.  
  234.     static char rcsid[] = 
  235.     "$Revision: 1.15 $\n"
  236.     "$Date: 90/08/28 01:16:08 $\n";
  237.     /* if adding commands, don't forget to update BUILTIN */
  238.     static char *C[] = {
  239.         "cls",
  240.         "history",
  241.     "alias",
  242.     "unalias",
  243.     "dirs",
  244.     "push",
  245.     "pop",
  246.     "ver",
  247.     "exit"
  248.     };
  249.  
  250.     for (i = 0; i < BUILTIN && strcmp (C[i], name); i++) ;
  251.     switch (i) {
  252.         case 0:    /* cls */
  253.             if (args && *args) goto bi_err;
  254.         fprintf (fh, "\f");
  255.         break;
  256.         case 1:    /* history */
  257.             if (args && *args) goto bi_err;
  258.             for (i = h_num, j = 0; j < h_max; i = hDEC(i), j++) 
  259.                 if (H[i].line[0])
  260.                     fprintf (fh, "%6ld  %s\n", H[i].num, H[i].line);
  261.             break;
  262.     case 2:    /* alias */
  263.         if (!args) {
  264.         for (i = 0; i < a_max; i++)
  265.             if (!A_EMPTY(i)) 
  266.             fprintf (fh, "%s\t%s\n", A[i].name, A[i].sub);
  267.         } else {
  268.         orig_len = strlen (args);
  269.         makeargs (args, &i, &argv);
  270.         if (i == 1) {
  271.             for (j = 0; j < a_max; j++)
  272.             if (!A_EMPTY(j) && !strcmp (A[j].name, argv[0])) 
  273.                 break;
  274.             if (j != a_max) fprintf (fh, "%s\n", A[j].sub);
  275.         } else {
  276.             for (j = 0; j < a_max && !A_EMPTY(j) &&
  277.             strcmp (A[j].name, argv[0]); j++) ;
  278.             if (j == a_max) {
  279.             fprintf (fh, "Too many aliases\n");
  280.             return (-1);
  281.             } else if (A_EMPTY(j)) {
  282.             if ( !(A[j].name = (char *) malloc 
  283.                 (strlen (argv[0]) + 1)) ) {
  284.                 printf ("%s: out of memory\n", progname);
  285.                 return (-2);
  286.             }
  287.             strcpy (A[j].name, argv[0]);
  288.             } else free (A[j].sub);
  289.             p = argv[1];
  290.             for (k = 0; k < orig_len; k++)
  291.             if (!args[k]) args[k] = ' ';
  292.             if ( !(A[j].sub = (char *) malloc (strlen (p) + 1)) ) {
  293.             printf ("%s: out of memory\n", progname);
  294.             return (-2);
  295.             }
  296.             strcpy (A[j].sub, p);
  297.         }
  298.         free (argv);
  299.         }
  300.         break;
  301.     case 3:    /* unalias */
  302.         if (!args) break;
  303.         makeargs (args, &i, &argv);
  304.         for ( ; i; --i) {
  305.         for (j = 0; j < a_max; j++)
  306.             if (!A_EMPTY(j) && !strcmp (A[j].name, argv[i-1])) {
  307.             free (A[j].name);
  308.             free (A[j].sub);
  309.             A[j].name = A[j].sub = NULL;
  310.             break;
  311.             }
  312.         }
  313.         free (argv);
  314.         break;
  315.     case 4:    /* dirs */
  316.         if (args && *args) goto bi_err;
  317.         for (i = pp_sp; i >= 0; --i) {
  318.             PathName (pp_stk[i], t, BIGNUMBER);
  319.         fprintf (fh, "%s\n", t);
  320.         }
  321.         break;
  322.     case 5:    /* push */
  323.         if (args && *args) goto bi_err;
  324.         if (pp_sp < pp_max-1) {
  325.         if ( !(pp_stk[++pp_sp] = Lock ("", ACCESS_READ)) ||
  326.             !PathName (pp_stk[pp_sp], t, BIGNUMBER) ) {
  327.             --pp_sp;
  328.             break;
  329.         }
  330.         fprintf (fh, "(%s)\n", t);
  331.         } else {
  332.             fprintf (fh, "Directory stack full\n");
  333.         return (-1);
  334.         }
  335.         break;
  336.     case 6:    /* pop */
  337.         if (args && *args) goto bi_err;
  338.         if (pp_sp >= 0) {
  339.             CurrentDir ((struct FileLock *) pp_stk[pp_sp]);
  340.         PathName (pp_stk[pp_sp], t, BIGNUMBER);
  341.         pp_stk[pp_sp--] = 0L;
  342.         fprintf (fh, "(%s)\n", t);
  343.         } else {
  344.             fprintf (fh, "Directory stack empty\n");
  345.         return (-1);
  346.         }
  347.         break;
  348.     case 7:    /* ver */
  349.         if (args && *args) goto bi_err;
  350.         fprintf (fh, "%s... by John D Aycock\n%s", progname, rcsid);
  351.         break;
  352.     case 8:    /* exit */
  353.         if (args && *args) goto bi_err;
  354.         errcode = RETURN_OK;
  355.         return (-2);
  356.         case BUILTIN:
  357.             return (0);
  358.     }
  359.     return (1);
  360.  
  361. bi_err:
  362.     printf ("Syntax error\n");
  363.     return (-1);
  364. }
  365.  
  366. /*
  367.  *    returns NULL if no alias sub done, else char * to
  368.  *    malloc'ed substitution... amount malloc'ed is MAXLINE+1
  369.  */
  370.  
  371. char *alias (arg)
  372. char *arg;
  373. {
  374.     int i;
  375.     char *ret, *p, *q;
  376.  
  377.     for (i = 0; i < a_max; i++) {
  378.     if (!A_EMPTY(i) && !strcmp (A[i].name, arg)) {
  379.         if ( !(ret = (char *) malloc (MAXLINE+1)) ) {
  380.         printf ("%s: out of memory\n", progname);
  381.         exit (RETURN_FAIL);
  382.         }
  383.         for (p = A[i].sub, q = ret; *p; )
  384.         if (*p == '\"') p++;
  385.         else if (*p == '!' && *(p+1) == '\'') {
  386.             p += 2;
  387.             *q++ = '\"';
  388.         } else *q++ = *p++;
  389.         *q = '\0';
  390.         return (ret);
  391.     }
  392.     }
  393.     return (NULL);
  394. }
  395.  
  396. /*
  397.  *    returns 0 if no history substitution done,
  398.  *    -1 if error, or char * to new (malloc'ed) arg
  399.  */
  400.  
  401. char *history (arg)
  402. char *arg;
  403. {
  404.     int num, len, s_len, r_len, repl;
  405.     char *new, *s=NULL, *r;
  406.     register int i, j;
  407.  
  408.     if (!h_max) return (NULL);
  409.     if (*arg == '!') {
  410.         if (*++arg == '!') arg++, num = -1;
  411.     else if (isdigit (*arg)) arg = toint (arg, &num);
  412.     else if (*arg == '-') {
  413.         arg = toint (++arg, &num);
  414.         num = -num;
  415.     } else if (*arg) {
  416.         len = strlen (arg);
  417.         for (i = hINC(h_num); i != h_num; i = hINC(i))
  418.             if (!strncmp (H[i].line, arg, len)) break;
  419.         if (strncmp (H[i].line, arg, len)) goto h_fail;
  420.         num = H[i].num;
  421.         arg += len;
  422.     } else goto h_err;
  423.     } else if (*arg == '^') {
  424.     for (r = s = ++arg; *r && *r != '^'; r++) ;
  425.     if (!*r || !(s_len = r - s) ) goto h_err;
  426.     for (arg = ++r; *arg && *arg != '^'; arg++) ;
  427.     r_len = arg - r;
  428.     if (*arg) arg++;    /* skip optional final '^' */
  429.     num = -1;
  430.     } else return (NULL);
  431.     if (!num) {
  432. h_err:
  433.     printf ("Syntax error\n");
  434.     return ((char *) -1);
  435.     }
  436.     if (num < 0) {
  437.     if ((num = -num) > h_max) goto h_fail;
  438.     for (i = h_num; num; i = hINC(i), --num) ;
  439.     } else {
  440.         for (i = 0; i < h_max; i++) if (H[i].num == num) break;
  441.     if (i == h_max) goto h_fail;
  442.     }
  443.     if (!H[i].line[0]) {
  444. h_fail:
  445.     printf ("Invalid history substitution\n");
  446.     return ((char *) -1);
  447.     }
  448.     if ( !(new = (char *) malloc (MAXLINE+1)) ) {
  449.     printf ("%s: out of memory\n", progname);
  450.     exit (RETURN_FAIL);
  451.     }
  452.     strcpy (new, H[i].line);
  453.     if (s) {
  454.     for (i = repl = 0; new[i]; i++) { 
  455.         if (!strncmp (&new[i], s, s_len)) {
  456.         len = strlen (new);
  457.         for (j = s_len + i; j <= len; j++) new[j-s_len] = new[j];
  458.         len -= s_len;
  459.         for (j = len + r_len; j >= i; --j)
  460.             if (j < MAXLINE+1) new[j] = new[j-r_len];
  461.         new[MAXLINE] = '\0';
  462.         strncpy (&new[i], r, r_len);
  463.         i += r_len;
  464.             repl++;
  465.         }
  466.     }
  467.     if (!repl) goto h_fail;
  468.     }
  469.     strcat (new, arg);
  470.     return (new);
  471. }
  472.  
  473. #define STDIN        0
  474. #define STDOUT        0
  475. #define PIPE        1
  476. #define REDIRECT    2
  477.  
  478. #define issep(x)    ((*(x)=='|'||*(x)==';')&&*((x)+1)=='\0')
  479.  
  480. struct command {
  481.     byte I, O;
  482.     char *name, *args, *in_fname, *out_fname;
  483. };
  484.  
  485. void doit (s, tmpdir)
  486. char *s, *tmpdir;
  487. {
  488.     int argc, n_cmds, cur_cmd, cmd_st, len, arg_st;
  489.     int orig_len, h_len, rv, aliascnt=0, a_len, copy_args;
  490.     long in_fh, out_fh;
  491.     bool h_sub=FALSE, re_eval, aliasing=FALSE, fatal=FALSE;
  492.     char **argv=NULL, *p, ch, *hist, *aka, *q;
  493.     struct command *cmd=NULL;
  494.     register int i, j, cmd_end;
  495.  
  496. X:
  497.     re_eval = FALSE;
  498.     orig_len = strlen (s);
  499.     makeargs (s, &argc, &argv);
  500.     for (i = 0, n_cmds = 1; i < argc; i++)
  501.         if (issep (argv[i])) n_cmds++;
  502.     if ( !(cmd = (struct command *) calloc 
  503.         (n_cmds, sizeof (struct command))) ) {
  504.         printf ("%s: out of memory\n", progname);
  505.         exit (RETURN_FAIL);
  506.     }
  507.     for (cur_cmd = cmd_end = 0; cur_cmd < n_cmds; cur_cmd++, cmd_end++) {
  508.         for (cmd_st = cmd_end, len = 0; cmd_end < argc && 
  509.         !issep (argv[cmd_end]); ++cmd_end) {
  510.         if (cmd_st == cmd_end)
  511.             cmd[cur_cmd].name = argv[cmd_st];
  512.         else {
  513.             if (*argv[cmd_end] == '<') {
  514.             i = cmd_end;
  515.                 cmd[cur_cmd].in_fname = (*(argv[cmd_end]+1) ? 
  516.                 argv[cmd_end]+1 : argv[++cmd_end]);
  517.             if (cmd_end >= argc || issep (cmd[cur_cmd].in_fname)
  518.                 || cmd[cur_cmd].I) {
  519.                     printf ("Syntax error\n");
  520.                 goto error;
  521.             }
  522.             cmd[cur_cmd].I = REDIRECT;
  523.             argv[i] = argv[cmd_end] = NULL;
  524.             } else if (*argv[cmd_end] == '>') {
  525.             i = cmd_end;
  526.                 cmd[cur_cmd].out_fname = (*(argv[cmd_end]+1) ? 
  527.                 argv[cmd_end]+1 : argv[++cmd_end]);
  528.             if (cmd_end >= argc || issep (cmd[cur_cmd].out_fname)
  529.                 || cmd[cur_cmd].O) {
  530.                     printf ("Syntax error\n");
  531.                 goto error;
  532.             }
  533.             cmd[cur_cmd].O = REDIRECT;
  534.             argv[i] = argv[cmd_end] = NULL;
  535.             } else {
  536.                 len += strlen (argv[cmd_end]) + 1;
  537.             if (cmd_end - cmd_st == 1) arg_st = cmd_end;
  538.             }
  539.         }
  540.     }
  541.     if (len) {
  542.         if ( !(cmd[cur_cmd].args = (char *) malloc (len)) ) {
  543.             printf ("%s: out of memory\n", progname);
  544.             exit (RETURN_FAIL);
  545.            }
  546.         for (i = arg_st, *(cmd[cur_cmd].args) = '\0'; i < cmd_end; i++) {
  547.         if (!argv[i]) continue;
  548.             strcat (cmd[cur_cmd].args, argv[i]);
  549.         for (j = i+1; j <= cmd_end && !argv[j]; j++) ;
  550.             if (j < cmd_end) strcat (cmd[cur_cmd].args, " ");
  551.         }
  552.     }
  553.     if (cmd_end < argc && !strcmp (argv[cmd_end], "|")) {
  554.         if (cmd[cur_cmd].O || cur_cmd+1 >= n_cmds) {
  555.             printf ("Syntax error\n");
  556.             goto error;
  557.         }
  558.         cmd[cur_cmd].O = cmd[cur_cmd+1].I = PIPE;
  559.     }
  560.         if (!cmd[cur_cmd].name) {
  561.         printf ("Syntax error\n");
  562.         goto error;
  563.     }
  564.     }
  565.     for (i = 0; !aliasing && i < n_cmds; i++) {
  566.         if ( !(hist = history (cmd[i].name)) ) continue;
  567.     else if ((int) hist == -1) goto error;
  568.     h_len = strlen (cmd[i].name);
  569.     for (j = 0; j < orig_len; j++) if (!s[j]) s[j] = ' ';
  570.     for (j = (cmd[i].name - s) + h_len; j <= orig_len; j++)
  571.         s[j-h_len] = s[j];
  572.     orig_len -= h_len;
  573.     h_len = strlen (hist);
  574.     for (j = orig_len + h_len; j >= cmd[i].name - s; --j)
  575.         if (j < MAXLINE+1) s[j] = s[j-h_len];
  576.     s[MAXLINE] = '\0';
  577.     strncpy (&s[j]+1, hist, h_len);
  578.     free (hist);
  579.     h_sub = re_eval = TRUE;
  580.     goto error;    /* loops back up && re-evaluates */
  581.     }
  582.     if (!aliasing && h_max) {
  583.     H[h_num].num = cmd_number;
  584.     for (i = 0; i < orig_len; i++) 
  585.         H[h_num].line[i] = (!s[i] ? ' ' : s[i]);
  586.     H[h_num].line[i] = '\0';
  587.     if (h_sub) printf ("%s\n", H[h_num].line);
  588.     h_num = hDEC(h_num);
  589.     }
  590.     if (a_max) for (i = 0; i < n_cmds; i++) {
  591.     if ( !(aka = alias (cmd[i].name)) ) continue;
  592.     for (j = copy_args = 0; aka[j]; j++)
  593.         if (aka[j] == '!' && aka[j+1] == '*') copy_args++;
  594.     for (arg_st = 0; argv[arg_st] != cmd[i].name; arg_st++) ;
  595.     for ( ; arg_st < argc && !issep (argv[arg_st]); arg_st++) ;
  596.     if (arg_st == argc)
  597.         len = orig_len - (cmd[i].name - s + strlen (cmd[i].name) + 1);
  598.     else
  599.         len = argv[arg_st] - cmd[i].name - strlen (cmd[i].name) - 2;
  600.     if (len < 0) len = 0;
  601.     if (!len) p = &ch;
  602.     else if ( !(p = (char *) malloc (len + 1)) ) {
  603.         printf ("%s: out of memory\n", progname);
  604.         exit (RETURN_FAIL);
  605.     }
  606.     q = cmd[i].name + strlen (cmd[i].name) + 1;
  607.     for (j = 0; j < len; j++) p[j] = (!q[j] ? ' ' : q[j]);
  608.     p[j] = '\0';
  609.     a_len = strlen (cmd[i].name);
  610.     if (copy_args) a_len += len + (len ? 1 : 0);
  611.     for (j = 0; j < orig_len; j++) if (!s[j]) s[j] = ' ';
  612.     for (j = (cmd[i].name - s) + a_len; j <= orig_len; j++)
  613.         s[j-a_len] = s[j];
  614.     orig_len -= a_len;
  615.     a_len = strlen (aka) - 2*copy_args + copy_args*len;
  616.     for (j = orig_len + a_len; j >= cmd[i].name - s; --j)
  617.         if (j < MAXLINE+1) s[j] = s[j-a_len];
  618.     s[MAXLINE] = '\0';
  619.     for (j = 0, q = cmd[i].name; aka[j]; j++)
  620.         if (aka[j] == '!' && aka[j+1] == '*') {
  621.             strncpy (q, p, len);
  622.         q += len;
  623.         j++;
  624.         } else *q++ = aka[j];
  625.     if (len) free (p);
  626.     free (aka);
  627.     aliasing = TRUE;
  628.     if (++aliascnt > ALIASLOOP) {
  629.         printf ("Alias loop\n");
  630.         goto error;
  631.     }
  632.     re_eval = TRUE;
  633.     goto error;
  634.     }
  635.     cmd_number++;
  636.     for (i = 0; i < n_cmds; i++) {
  637.     switch (cmd[i].I) {
  638.         case STDIN:
  639.             in_fh = Input ();
  640.         break;
  641.         case PIPE:
  642.             in_fh = out_fh;
  643.         if (Seek (in_fh, 0L, OFFSET_BEGINNING) == -1) {
  644.             printf ("Error in pipe\n");
  645.             Close (in_fh);
  646.             DeleteFile (cmd[i-1].out_fname);
  647.             free (cmd[i-1].out_fname);
  648.             goto error;
  649.         }
  650.         break;
  651.         case REDIRECT:
  652.             if ( !(in_fh = Open (cmd[i].in_fname, MODE_OLDFILE)) ) {
  653.             printf ("Error on input redirection\n");
  654.             goto error;
  655.         }
  656.         break;
  657.     }
  658.     switch (cmd[i].O) {
  659.         case STDOUT:
  660.             out_fh = Output ();
  661.         break;
  662.         case PIPE:
  663.             p = tmpnam (NULL);
  664.         if ( !(cmd[i].out_fname = (char *) malloc (strlen (tmpdir) +
  665.             strlen (p) + 1)) ) {
  666.             printf ("%s: out of memory\n", progname);
  667.             if (cmd[i].I) Close (in_fh);
  668.             if (cmd[i].I == PIPE)
  669.                 DeleteFile (cmd[i-1].out_fname);
  670.             exit (RETURN_FAIL);
  671.         }
  672.         strcpy (cmd[i].out_fname, tmpdir);
  673.         ch = tmpdir[strlen(tmpdir)-1];
  674.         if (*tmpdir && ch != ':' && ch != '/')
  675.             strcat (cmd[i].out_fname, "/");
  676.         strcat (cmd[i].out_fname, p);
  677.         if ( !(out_fh = Open (cmd[i].out_fname, MODE_NEWFILE)) ) {
  678.             printf ("Error in pipe\n");
  679.             if (cmd[i].I) Close (in_fh);
  680.             if (cmd[i].I == PIPE) {
  681.                 DeleteFile (cmd[i-1].out_fname);
  682.                 free (cmd[i-1].out_fname);
  683.             }
  684.             goto error;
  685.         }
  686.         break;
  687.         case REDIRECT:
  688.             if ( !(out_fh = Open (cmd[i].out_fname, MODE_NEWFILE)) ) {
  689.             printf ("Error on output redirection\n");
  690.             if (cmd[i].I) Close (in_fh);
  691.             if (cmd[i].I == PIPE) {
  692.                 DeleteFile (cmd[i-1].out_fname);
  693.             free (cmd[i-1].out_fname);
  694.             }
  695.             goto error;
  696.         }
  697.         break;
  698.     }
  699.     rv = 0;
  700.     if ( (rv = builtin (cmd[i].name, cmd[i].args, out_fh)) == -2)
  701.         fatal = TRUE;
  702.     if (rv < 0) goto do_err;
  703.     if (!rv && (rv=SyncRun (cmd[i].name, cmd[i].args, in_fh, out_fh))) {
  704.         switch (rv) {
  705.             case PR_NOFILE:
  706.             printf ("Unknown command %s\n", cmd[i].name);
  707.             break;
  708.         case PR_NOEXEC:
  709.             printf ("Execute bit not set for %s\n", cmd[i].name);
  710.             break;
  711.         case PR_SCRIPT:
  712.             printf ("Script bit set for %s\n", cmd[i].name);
  713.             break;
  714.         case PR_WANTSMESSAGE:
  715.             printf ("Program returned error #%ld\n", IoErr());
  716.             break;
  717.         default:
  718.             if (rv < 0) printf ("Error %ld from SyncRun()\n", rv);
  719.         }
  720. do_err:
  721.         if (cmd[i].I) Close (in_fh);
  722.         if (cmd[i].I == PIPE) {
  723.             DeleteFile (cmd[i-1].out_fname);
  724.         free (cmd[i-1].out_fname);
  725.         }
  726.         if (cmd[i].O) Close (out_fh);
  727.         if (cmd[i].O == PIPE) {
  728.             DeleteFile (cmd[i].out_fname);
  729.         free (cmd[i].out_fname);
  730.         }
  731.         if (fatal) exit (errcode);
  732.         break;
  733.     }
  734.     if (cmd[i].I) Close (in_fh);
  735.     if (cmd[i].I == PIPE) {
  736.         DeleteFile (cmd[i-1].out_fname);
  737.         free (cmd[i-1].out_fname);
  738.     }
  739.     if (cmd[i].O == REDIRECT) Close (out_fh);
  740.     }
  741.  
  742. error:
  743.     free (argv);
  744.     if (cmd) {
  745.         for (i = 0; i < n_cmds; i++) if (cmd[i].args) free (cmd[i].args);
  746.     free (cmd);
  747.     cmd = NULL;
  748.     }
  749.     if (re_eval) goto X;
  750. }
  751.  
  752. bool fignore (s, list)
  753. char *s, *list;
  754. {
  755.     int s_len, e_len;
  756.     char *l_ptr;
  757.  
  758.     s_len = strlen (s);
  759.     while (*list) {
  760.         if (l_ptr = strchr (list, '|')) e_len = l_ptr - list;
  761.     else {
  762.         e_len = strlen (list);
  763.         l_ptr = " ";  /* makes it look like end of list */
  764.     }
  765.     if ( !Strncmp (list, &s[s_len-e_len], e_len) )
  766.         return (TRUE);
  767.     list = l_ptr + 1;
  768.     }
  769.     return (FALSE);
  770. }
  771.  
  772. char *fcomp (s, n, ignorelist)
  773. char *s, *ignorelist;
  774. int *n;    /* RETURN */
  775. {
  776.     int bn_len;
  777.     long lock;
  778.     bool first=TRUE;
  779.     char *p, *q, basename[FCHARS], pathname[FCHARS];
  780.  
  781.     static char common[FCHARS];
  782.  
  783.     p = BaseName (s);
  784.     bn_len = strlen (p);
  785.     *n = 0;
  786.     strcpy (basename, p);
  787.     strcpy (pathname, s);
  788.     if (p == s) *pathname = '\0';
  789.     else *(pathname+strlen(s)-bn_len) = '\0';
  790.     if ( !(lock = Lock (pathname, ACCESS_READ)) || 
  791.         !Examine (lock, (BPTR) fib) ) {
  792.         if (lock) UnLock (lock);
  793.             return ("");
  794.     }
  795.     strcpy (common, basename);
  796.     while (ExNext (lock, (BPTR) fib)) {
  797.         if (!bn_len || !Strncmp (basename, fib->fib_FileName, bn_len)) {
  798.         if (fignore (fib->fib_FileName, ignorelist)) continue;
  799.         if (first) {
  800.         strcpy (common, fib->fib_FileName);
  801.             first = FALSE;
  802.         } else {
  803.             for (p = common+bn_len, q = fib->fib_FileName+bn_len;
  804.             *p && *q && tolower(*p) == tolower(*q); p++, q++) ;
  805.         *p = '\0';
  806.         }
  807.     }
  808.     }
  809.     UnLock (lock);
  810.     *n = bn_len;
  811.     return (common);
  812. }
  813.  
  814. char *int2s (p, i)
  815. char *p;
  816. int i;
  817. {
  818.     int off=0;
  819.     char buffer[20];    /* arbitrary */
  820.  
  821.     do {
  822.         buffer[off++] = i % 10 + '0';
  823.     i /= 10;
  824.     } while (i);
  825.     while (off > 0) *p++ = buffer[--off];
  826.     return (p);
  827. }
  828.  
  829. char *makeprompt (format)
  830. char *format;
  831. {
  832.     int len;
  833.     long lock;
  834.     struct Process *proc;
  835.     register char *pf, *pb;
  836.     static char prompt[MAXLINE];
  837.  
  838.     for (pf = format, pb = prompt; *pf; pf++) {
  839.         if (*pf != '%') *pb++ = *pf;
  840.     else if (*(pf+1)) {
  841.         switch (*++pf) {
  842.             case 'b':
  843.             if ( !(lock = Lock ("", ACCESS_READ)) || 
  844.                 !Examine (lock, (BPTR) fib) ) {
  845.                 if (lock) UnLock (lock);
  846.                 break;
  847.             }
  848.             strcpy (pb, fib->fib_FileName);
  849.             pb += strlen (fib->fib_FileName);
  850.             UnLock (lock);
  851.             break;
  852.         case 'c':
  853.             pb = int2s (pb, cmd_number);
  854.             break;
  855.         case 'e':
  856.             *pb++ = ESC;
  857.             break;
  858.         case 'h':
  859.             *pb++ = BS;
  860.             break;
  861.         case 'i':
  862.             *pb++ = TAB;
  863.             break;
  864.         case 'n':
  865.             *pb++ = NL;
  866.             break;
  867.         case 'p':
  868.             if ( !(lock = Lock ("", ACCESS_READ)) ||
  869.                 !(len = PathName (lock, pb, BIGNUMBER)) ) {
  870.                     if (lock) UnLock (lock);
  871.                 break;
  872.             }
  873.             pb += len;
  874.             UnLock (lock);
  875.             break;
  876.         case 'N':
  877.             proc = (struct Process *) FindTask (NULL);
  878.             pb = int2s (pb, proc->pr_TaskNum);
  879.             break;
  880.         default:
  881.             *pb++ = *pf;
  882.             break;
  883.         }
  884.     }
  885.     }
  886.     *pb = '\0';
  887.     return (prompt);
  888. }
  889.  
  890. void edit (prompt, ignorelist, tmpdir)
  891. char *prompt, *ignorelist, *tmpdir;
  892. {
  893.     int b_i, n;
  894.     char buf[MAXLINE+1], *rest;
  895.     unsigned char ch;
  896.     register int i;
  897.  
  898.     raw ();
  899.     b_i = 0;
  900.     printf (makeprompt (prompt));
  901.  
  902.     while (1) {
  903.     if (Read (Input(), (char *) &ch, 1) != 1) ch = QUIT;
  904.     switch (ch) {
  905.         case CSI:
  906.         (void) do_csi ();
  907.         break;
  908.         case WERASE:
  909.         for (i = b_i; i && isspace (buf[i-1]); --i) ;
  910.         for ( ; i && !isspace (buf[i-1]); --i) ;
  911.         for ( ; b_i > i; --b_i) printf ("\b \b");
  912.         break;
  913.         case TAB:
  914.         buf[b_i] = '\0';
  915.         for (i = b_i; i && !isspace (buf[i-1]); --i) ;
  916.         rest = fcomp (&buf[i], &n, ignorelist);
  917.         if (n) printf ("\033[%ldD", n);
  918.         b_i -= n;
  919.         for ( ; b_i < MAXLINE && *rest; rest++) {
  920.             buf[b_i++] = *rest;
  921.             Write (Output(), rest, 1);
  922.         }
  923.         break;
  924.         case AMIKILL:
  925.         case KILL:
  926.         for (i = 0; i < b_i; i++) printf ("\b \b");
  927.         b_i = 0;
  928.         break;
  929.         case BS:
  930.         if (b_i) {
  931.             printf ("\b \b");
  932.             --b_i;
  933.         }
  934.         break;
  935.         case RET:
  936.         case NL:
  937.         for (i = 0; i < b_i && isspace(buf[i]); i++) ;
  938.         printf ("\n");
  939.         if (b_i && i != b_i) {
  940.             cooked ();
  941.             buf[b_i] = '\0';
  942.             doit (buf, tmpdir);
  943.             b_i = 0;
  944.             raw ();
  945.         }
  946.         printf (makeprompt (prompt));
  947.         break;
  948.         case QUIT:
  949.         for (i = 0; i < b_i; i++) printf ("\b \b");
  950.         printf ("\n");
  951.         cooked ();
  952.         return;
  953.         default:
  954.         if (!iscntrl (ch) && b_i < MAXLINE) {
  955.             buf[b_i++] = ch;
  956.             Write (Output(), (char *) &ch, 1);
  957.         }
  958.         break;
  959.     }
  960.     }
  961. }
  962.  
  963. void parseargs (start_arg, argc, argv)
  964. int start_arg, argc;
  965. char **argv;
  966. {
  967.     int i;
  968.     char *cp;
  969.  
  970.     for (i = start_arg; i < argc; i++) {
  971.         if (*(cp = argv[i]) == '-') {
  972.         switch (*++cp) {
  973.         case 'a':
  974.             if (*(cp+1)) cp++;
  975.             else if (i < argc-1) cp = argv[++i];
  976.             else cp = "0";
  977.             toint (cp, &a_max);
  978.             break;
  979.         case 'c':
  980.             if (*(cp+1)) cp++;
  981.             else if (i < argc-1) cp = argv[++i];
  982.             else cp = "0";
  983.             toint (cp, &h_max);
  984.             break;
  985.         case 'd':
  986.             if (*(cp+1)) cp++;
  987.             else if (i < argc-1) cp = argv[++i];
  988.             else cp = "0";
  989.             toint (cp, &pp_max);
  990.             break;
  991.         case 'f':
  992.             if (*(cp+1)) ignorelist = cp+1;
  993.             else if (i < argc-1) ignorelist = argv[++i];
  994.             else ignorelist = "";
  995.             break;
  996.         case 'p':
  997.             if (*(cp+1)) prompt = cp+1;
  998.             else if (i < argc-1) prompt = argv[++i];
  999.             else prompt = "";
  1000.             break;
  1001.         case 'h':
  1002.             printf ("Usage: %s [-a<maxaliases>] [-c<histsize>] "
  1003.                 "[-d<dirstack>] [-f<ignorelist>] [-p<prompt>] "
  1004.             "[-s<startup>] [-t<tmpdir>]\n", progname);
  1005.             printf ("       %s -h[elp]\n", progname);
  1006.             exit (RETURN_OK);
  1007.         case 's':
  1008.             if (*(cp+1)) startup = cp+1;
  1009.             else if (i < argc-1) startup = argv[++i];
  1010.             else startup = NULL;
  1011.             is_dflt = FALSE;
  1012.             break;
  1013.         case 't':
  1014.             if (*(cp+1)) tmpdir = cp+1;
  1015.             else if (i < argc-1) tmpdir = argv[++i];
  1016.             else tmpdir = "";
  1017.             break;
  1018.             default:
  1019.             printf ("%s: bad option\n", progname);
  1020.             exit (RETURN_ERROR);
  1021.         }
  1022.     } else {
  1023.         printf ("%s: bad arguments\n", progname);
  1024.         exit (RETURN_ERROR);
  1025.     }
  1026.     }
  1027. }
  1028.  
  1029. void main (argc, argv)
  1030. int argc;
  1031. char *argv[];
  1032. {
  1033.     int i, h_tmp, j, want, actual, lines;
  1034.     long fh;
  1035.     char ch, t[MAXLINE+1], cmd_buf[MAXLINE+1];
  1036.  
  1037.     int E_argc;
  1038.     long E_argv[20];
  1039.     char E[MAXLINE+1];
  1040.  
  1041.     Enable_Abort = FALSE;
  1042.     if ( !(ArpBase = (struct ArpBase *) OpenLibrary ("arp.library", 0L)) ) {
  1043.     Write (Output(), "Can\'t open arp.library\n", 23);
  1044.     exit (RETURN_FAIL);
  1045.     }
  1046.     atexit (cleanup);
  1047.     if ( !(rp = (struct MsgPort *) CreatePort (NULL, 0)) ) {
  1048.     printf ("Can\'t create port\n");
  1049.     exit (RETURN_FAIL);
  1050.     }
  1051.     if ( !(packet = (struct StandardPacket *) AllocMem 
  1052.         (sizeof (struct StandardPacket), MEMF_PUBLIC|MEMF_CLEAR)) ||
  1053.     !(fib = (struct FileInfoBlock *) AllocMem
  1054.     (sizeof (struct FileInfoBlock), 0L)) ) {
  1055.             printf ("Can\'t allocate memory\n");
  1056.         exit (RETURN_FAIL);
  1057.     }
  1058.     progname = BaseName (argv[0]);
  1059.     if (Getenv ("LINEOPTS", E, MAXLINE+1)) {
  1060.     E_argc = GADS (E, strlen(E), NULL, E_argv, ",,,,,,,,,,,,,,,,,,,");
  1061.     parseargs (0, E_argc, (char **) E_argv);
  1062.     }
  1063.     parseargs (1, argc, argv);
  1064.     if ( h_max && !(H = (struct history *) calloc (h_max, 
  1065.     sizeof (struct history))) ) {
  1066.         printf ("%s: out of memory\n", progname);
  1067.         exit (RETURN_FAIL);
  1068.     }
  1069.     if ( a_max && !(A = (struct alias *) calloc (a_max,
  1070.     sizeof (struct alias))) ) {
  1071.         printf ("%s: out of memory\n", progname);
  1072.         exit (RETURN_FAIL);
  1073.     }
  1074.     if ( pp_max && !(pp_stk = (long *) calloc (pp_max, sizeof (long))) ) {
  1075.         printf ("%s: out of memory\n", progname);
  1076.     exit (RETURN_FAIL);
  1077.     }
  1078.     if (startup) {
  1079.         if ( !(fh = Open (startup, MODE_OLDFILE)) ) {
  1080.         if (!is_dflt) printf ("Can\'t open %s\n", startup);
  1081.     } else {
  1082.         /* temporarily disable history */
  1083.         h_tmp = h_max;  h_max = 0;
  1084.         j = 0;  want = MAXLINE;
  1085.         while ((actual = Read (fh, &t[j], want)) > 0) {
  1086.         actual += j;
  1087.         for (i = lines = 0; i < actual; ) 
  1088.             if (t[i++]=='\n') lines++;
  1089.         if (!lines) {
  1090.             printf ("Error reading %s\n", startup);
  1091.             break;
  1092.         }
  1093.         for ( ; lines-- ; ) {
  1094.             for (i = 0; t[i] != '\n'; i++) ;
  1095.             t[i] = '\0';
  1096.             for (j = 0; t[j] && isspace(t[j]); j++) ;
  1097.             if (t[j] && t[j] != '#') {
  1098.             strcpy (cmd_buf, &t[j]);
  1099.                 doit (cmd_buf, tmpdir);
  1100.             }
  1101.             for (j = 0, i++; i < actual; ) t[j++] = t[i++];
  1102.             actual = j;
  1103.         }
  1104.         want = MAXLINE - j;
  1105.         }
  1106.         h_max = h_tmp;
  1107.         Close (fh);
  1108.     }
  1109.     }
  1110.     cmd_number = 1;
  1111.     edit (prompt, ignorelist, tmpdir);
  1112.     exit (RETURN_OK);
  1113. }
  1114.  
  1115.