home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / GNU / SH164AS.ZIP / SHELL / SH2.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-28  |  16.6 KB  |  973 lines

  1. /* MS-DOS SHELL - Parser
  2.  *
  3.  * MS-DOS SHELL - Copyright (c) 1990 Data Logic Limited and Charles Forsyth
  4.  *
  5.  * This code is based on (in part) the shell program written by Charles
  6.  * Forsyth and is subject to the following copyright restrictions:
  7.  *
  8.  * 1.  Redistribution and use in source and binary forms are permitted
  9.  *     provided that the above copyright notice is duplicated in the
  10.  *     source form and the copyright notice in file sh6.c is displayed
  11.  *     on entry to the program.
  12.  *
  13.  * 2.  The sources (or parts thereof) or objects generated from the sources
  14.  *     (or parts of sources) cannot be sold under any circumstances.
  15.  *
  16.  *    $Header: C:/SRC/SHELL/RCS/sh2.c 1.7 90/09/11 20:00:01 Ian_Stewartson Exp $
  17.  *
  18.  *    $Log:    sh2.c $
  19.  * Revision 1.7  90/09/11  20:00:01  Ian_Stewartson
  20.  * Add support for $() POSIX functionality
  21.  * 
  22.  * Revision 1.6  90/08/14  23:30:26  Ian_Stewartson
  23.  * Add support for read/write IO
  24.  * 
  25.  * Revision 1.5  90/04/25  09:18:38  MS_user
  26.  * Fix for ... do to not require terminating colon
  27.  * 
  28.  * Revision 1.4  90/03/14  19:30:06  MS_user
  29.  * Make collect a global for here document processing.
  30.  * Add IOTHERE support to detect <<- redirection
  31.  * 
  32.  * Revision 1.3  90/03/06  16:49:42  MS_user
  33.  * Add disable history option
  34.  * 
  35.  * Revision 1.2  90/03/05  13:49:41  MS_user
  36.  * Change talking checks
  37.  * 
  38.  * Revision 1.1  90/01/25  13:41:12  MS_user
  39.  * Initial revision
  40.  * 
  41.  */
  42.  
  43. #include <sys/types.h>
  44. #include <stddef.h>
  45. #include <signal.h>
  46. #include <errno.h>
  47. #include <setjmp.h>
  48. #include <string.h>
  49. #include <ctype.h>
  50. #include <unistd.h>
  51. #include <limits.h>
  52. #include <dirent.h>
  53. #include "sh.h"
  54.  
  55. /*
  56.  * shell: syntax (C version)
  57.  */
  58.  
  59. typedef union {
  60.     char    *cp;
  61.     char    **wp;
  62.     int        i;
  63.     C_Op    *o;
  64. } YYSTYPE;
  65.  
  66. #define    WORD    256
  67. #define    LOGAND    257
  68. #define    LOGOR    258
  69. #define    BREAK    259
  70. #define    IF    260
  71. #define    THEN    261
  72. #define    ELSE    262
  73. #define    ELIF    263
  74. #define    FI    264
  75. #define    CASE    265
  76. #define    ESAC    266
  77. #define    FOR    267
  78. #define    WHILE    268
  79. #define    UNTIL    269
  80. #define    DO    270
  81. #define    DONE    271
  82. #define    IN    272
  83. #define    YYERRCODE 300
  84.  
  85. /* flags to yylex */
  86.  
  87. #define    CONTIN    01    /* skip new lines to complete command */
  88.  
  89. static bool        startl;
  90. static int        peeksym;
  91. static bool        Allow_funcs;
  92. static int        iounit = IODEFAULT;
  93. static C_Op        *tp;
  94. static YYSTYPE        yylval;
  95. static char        *syntax_err = "sh: syntax error\n";
  96.  
  97. static C_Op        *pipeline (int);
  98. static C_Op        *andor (void);
  99. static C_Op        *c_list (bool);
  100. static bool        synio (int);
  101. static void        musthave (int, int);
  102. static C_Op        *simple (void);
  103. static C_Op        *nested (int, int);
  104. static C_Op        *command (int);
  105. static C_Op        *dogroup (int);
  106. static C_Op        *thenpart (void);
  107. static C_Op        *elsepart (void);
  108. static C_Op        *caselist (void);
  109. static C_Op        *casepart (void);
  110. static char        **pattern (void);
  111. static char        **wordlist (void);
  112. static C_Op        *list (C_Op *, C_Op *);
  113. static C_Op        *block (int, C_Op *, C_Op *, char **);
  114. static int        rlookup (char *);
  115. static C_Op        *namelist (C_Op *);
  116. static char        **copyw (void);
  117. static void        word (char *);
  118. static IO_Actions    **copyio (void);
  119. static IO_Actions    *io (int, int, char *);
  120. static void        yyerror (char *);
  121. static int        yylex (int);
  122. static int        dual (int);
  123. static void        diag (int);
  124. static char        *tree (unsigned int);
  125.  
  126. C_Op    *yyparse ()
  127. {
  128.     C_Op    *outtree;
  129.  
  130.     startl  = TRUE;
  131.     peeksym = 0;
  132.     yynerrs = 0;
  133.     outtree = c_list (TRUE);
  134.     musthave (NL, 0);
  135.  
  136.     return (yynerrs != 0) ? (C_Op *)NULL : outtree;
  137. }
  138.  
  139. static C_Op    *pipeline (cf)
  140. int        cf;
  141. {
  142.     register C_Op    *t, *p;
  143.     register int    c;
  144.  
  145.     if ((t = command (cf)) != (C_Op *)NULL)
  146.     {
  147.     Allow_funcs = FALSE;
  148.     while ((c = yylex (0)) == '|') 
  149.     {
  150.         if ((p = command (CONTIN)) == (C_Op *)NULL)
  151.         yyerror (syntax_err);
  152.  
  153. /* shell statement */
  154.  
  155.         if ((t->type != TPAREN) && (t->type != TCOM))
  156.         t = block (TPAREN, t, NOBLOCK, NOWORDS);
  157.  
  158.         t = block (TPIPE, t, p, NOWORDS);
  159.     }
  160.  
  161.     peeksym = c;
  162.     }
  163.  
  164.     return t;
  165. }
  166.  
  167. static C_Op    *andor ()
  168. {
  169.     register C_Op    *t, *p;
  170.     register int    c;
  171.  
  172.     if ((t = pipeline (0)) != (C_Op *)NULL)
  173.     {
  174.     Allow_funcs = FALSE;
  175.     while (((c = yylex (0)) == LOGAND) || (c == LOGOR))
  176.     {
  177.         if ((p = pipeline (CONTIN)) == (C_Op *)NULL)
  178.         yyerror (syntax_err);
  179.  
  180.         t = block ((c == LOGAND) ? TAND : TOR, t, p, NOWORDS);
  181.     }
  182.  
  183.     peeksym = c;
  184.     }
  185.  
  186.     return t;
  187. }
  188.  
  189. static C_Op    *c_list (allow)
  190. bool        allow;
  191. {
  192.     register C_Op    *t, *p;
  193.     register int    c;
  194.  
  195. /* Functions are only allowed at the start of a line */
  196.  
  197.     Allow_funcs = allow;
  198.  
  199.     if ((t = andor ()) != (C_Op *)NULL)
  200.     {
  201.     Allow_funcs = FALSE;
  202.  
  203.     if ((peeksym = yylex (0)) == '&')
  204.         t = block (TASYNC, t, NOBLOCK, NOWORDS);
  205.  
  206.     while ((c = yylex(0)) == ';' || c == '&' || multiline && c == NL)
  207.     {
  208.         if ((p = andor ()) == (C_Op *)NULL)
  209.         return t;
  210.  
  211.         if ((peeksym = yylex (0)) == '&')
  212.         p = block (TASYNC, p, NOBLOCK, NOWORDS);
  213.  
  214.         t = list (t, p);
  215.     }
  216.     peeksym = c;
  217.     }
  218.  
  219.     return t;
  220. }
  221.  
  222.  
  223. static bool    synio (cf)
  224. int        cf;
  225. {
  226.     register IO_Actions    *iop;
  227.     register int    i;
  228.     register int    c;
  229.  
  230.     if (((c = yylex (cf)) != '<') && (c != '>'))
  231.     {
  232.     peeksym = c;
  233.     return FALSE;
  234.     }
  235.  
  236.     i = yylval.i;
  237.     musthave (WORD, 0);
  238.     iop = io (iounit, i, yylval.cp);
  239.     iounit = IODEFAULT;
  240.  
  241.     if (i & IOHERE)
  242.     markhere (yylval.cp, iop);
  243.     
  244.     return TRUE;
  245. }
  246.  
  247. static void    musthave (c, cf)
  248. int        c, cf;
  249. {
  250.     if ((peeksym = yylex (cf)) != c)
  251.     yyerror (syntax_err);
  252.  
  253.     peeksym = 0;
  254. }
  255.  
  256. static C_Op    *simple ()
  257. {
  258.     register C_Op    *t = (C_Op *)NULL;
  259.  
  260.     while (1)
  261.     {
  262.     switch (peeksym = yylex (0)) 
  263.     {
  264.         case '<':
  265.         case '>':
  266.         synio (0);
  267.         break;
  268.  
  269.         case WORD:
  270.         if (t == (C_Op *)NULL) 
  271.             (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM;
  272.  
  273.         peeksym = 0;
  274.         word (yylval.cp);
  275.         break;
  276.  
  277. /* Check for function - name () { word; } */
  278.  
  279.         case '(':
  280.         if ((t != (C_Op *)NULL) && (Allow_funcs == TRUE) &&
  281.             (wdlist != (Word_B *)NULL) && (wdlist->w_nword == 1))
  282.         {
  283.             Word_B    *save;
  284.  
  285.             peeksym = 0;
  286.             musthave (')', 0);
  287.             musthave ('{', 0);
  288.             save = wdlist;
  289.             wdlist = (Word_B *)NULL;
  290.             t->type = TFUNC;
  291.             t->left = nested (TBRACE, '}');
  292.             wdlist = save;
  293.             Allow_funcs = FALSE;
  294.             musthave (NL, 0);
  295.             peeksym = NL;
  296.         }
  297.  
  298.         default:
  299.         return t;
  300.     }
  301.     }
  302. }
  303.  
  304. static C_Op    *nested (type, mark)
  305. int        type, mark;
  306. {
  307.     register C_Op    *t;
  308.  
  309.     multiline++;
  310.     t = c_list (FALSE);
  311.     musthave (mark, 0);
  312.     multiline--;
  313.     return block (type, t, NOBLOCK, NOWORDS);
  314. }
  315.  
  316. static C_Op    *command (cf)
  317. int        cf;
  318. {
  319.     register C_Op    *t;
  320.     Word_B        *iosave = iolist;
  321.     register int    c;
  322.  
  323.     iolist = (Word_B *)NULL;
  324.  
  325.     if (multiline)
  326.     cf |= CONTIN;
  327.  
  328.     while (synio (cf))
  329.     cf = 0;
  330.  
  331.     switch (c = yylex (cf)) 
  332.     {
  333.     default:
  334.         peeksym = c;
  335.  
  336.         if ((t = simple ()) == (C_Op *)NULL)
  337.         {
  338.         if (iolist == (Word_B *)NULL)
  339.             return (C_Op *)NULL;
  340.  
  341.         (t = (C_Op *)tree (sizeof (C_Op)))->type = TCOM;
  342.         }
  343.  
  344.         break;
  345.  
  346.     case '(':
  347.         t = nested (TPAREN, ')');
  348.         break;
  349.  
  350.     case '{':
  351.         t = nested (TBRACE, '}');
  352.         break;
  353.  
  354.     case FOR:
  355.         (t = (C_Op *)tree (sizeof (C_Op)))->type = TFOR;
  356.         musthave (WORD, 0);
  357.         startl = TRUE;
  358.         t->str = yylval.cp;
  359.         multiline++;
  360.         t->words = wordlist ();
  361.  
  362. /* CHeck for "for word in word...; do" versus "for word do" */
  363.  
  364.         c = yylex (0);
  365.  
  366.         if ((t->words == (char **)NULL) && (c != NL))
  367.         peeksym = c;
  368.         
  369.         else if ((t->words != (char **)NULL) && (c != NL) && (c != ';'))
  370.         yyerror (syntax_err);
  371.  
  372.         t->left = dogroup (0);
  373.         multiline--;
  374.         break;
  375.  
  376.     case WHILE:
  377.     case UNTIL:
  378.         multiline++;
  379.         t = (C_Op *)tree (sizeof (C_Op));
  380.         t->type = (c == WHILE) ? TWHILE : TUNTIL;
  381.         t->left = c_list (FALSE);
  382.         t->right = dogroup (1);
  383.         t->words = (char **)NULL;
  384.         multiline--;
  385.         break;
  386.  
  387.     case CASE:
  388.         (t = (C_Op *)tree (sizeof (C_Op)))->type = TCASE;
  389.         musthave (WORD, 0);
  390.         t->str = yylval.cp;
  391.         startl = TRUE;
  392.         multiline++;
  393.         musthave (IN, CONTIN);
  394.         startl = TRUE;
  395.         t->left = caselist();
  396.         musthave (ESAC, 0);
  397.         multiline--;
  398.         break;
  399.  
  400.     case IF:
  401.         multiline++;
  402.         (t = (C_Op *)tree (sizeof (C_Op)))->type = TIF;
  403.         t->left = c_list (FALSE);
  404.         t->right = thenpart ();
  405.         musthave (FI, 0);
  406.         multiline--;
  407.         break;
  408.     }
  409.  
  410.     while (synio (0))
  411.     ;
  412.  
  413.     t = namelist (t);
  414.     iolist = iosave;
  415.     return t;
  416. }
  417.  
  418. static C_Op    *dogroup (onlydone)
  419. int        onlydone;
  420. {
  421.     register int    c;
  422.     register C_Op    *list;
  423.  
  424.     if (((c = yylex (CONTIN)) == DONE) && onlydone)
  425.     return (C_Op *)NULL;
  426.  
  427.     if (c != DO)
  428.     yyerror (syntax_err);
  429.  
  430.     list = c_list (FALSE);
  431.     musthave (DONE, 0);
  432.     return list;
  433. }
  434.  
  435. static C_Op    *thenpart ()
  436. {
  437.     register int    c;
  438.     register C_Op    *t;
  439.  
  440.     if ((c = yylex (0)) != THEN) 
  441.     {
  442.     peeksym = c;
  443.     return (C_Op *)NULL;
  444.     }
  445.  
  446.     (t = (C_Op *)tree (sizeof (C_Op)))->type = 0;
  447.  
  448.     if ((t->left = c_list (FALSE)) == (C_Op *)NULL)
  449.     yyerror (syntax_err);
  450.  
  451.     t->right = elsepart ();
  452.     return t;
  453. }
  454.  
  455. static C_Op    *elsepart ()
  456. {
  457.     register int    c;
  458.     register C_Op    *t;
  459.  
  460.     switch (c = yylex (0)) 
  461.     {
  462.     case ELSE:
  463.         if ((t = c_list (FALSE)) == (C_Op *)NULL)
  464.         yyerror (syntax_err);
  465.  
  466.         return t;
  467.  
  468.     case ELIF:
  469.         (t = (C_Op *)tree (sizeof (C_Op)))->type = TELIF;
  470.         t->left = c_list (FALSE);
  471.         t->right = thenpart ();
  472.         return t;
  473.  
  474.     default:
  475.         peeksym = c;
  476.         return (C_Op *)NULL;
  477.     }
  478. }
  479.  
  480. static C_Op    *caselist()
  481. {
  482.     register C_Op    *t = (C_Op *)NULL;
  483.  
  484.     while ((peeksym = yylex (CONTIN)) != ESAC)
  485.     t = list (t, casepart ());
  486.  
  487.     return t;
  488. }
  489.  
  490. static C_Op    *casepart ()
  491. {
  492.     register C_Op    *t = (C_Op *)tree (sizeof (C_Op));
  493.  
  494.     t->type = TPAT;
  495.     t->words = pattern ();
  496.     musthave (')', 0);
  497.     t->left = c_list (FALSE);
  498.  
  499.     if ((peeksym = yylex (CONTIN)) != ESAC)
  500.     musthave (BREAK, CONTIN);
  501.  
  502.     return t;
  503. }
  504.  
  505. static char    **pattern()
  506. {
  507.     register int    c, cf;
  508.  
  509.     cf = CONTIN;
  510.  
  511.     do
  512.     {
  513.     musthave (WORD, cf);
  514.     word (yylval.cp);
  515.     cf = 0;
  516.     } while ((c = yylex(0)) == '|');
  517.  
  518.     peeksym = c;
  519.     word (NOWORD);
  520.     return copyw();
  521. }
  522.  
  523. static char    **wordlist()
  524. {
  525.     register int    c;
  526.  
  527.     if ((c = yylex(0)) != IN) 
  528.     {
  529.     peeksym = c;
  530.     return (char **)NULL;
  531.     }
  532.  
  533.     startl = FALSE;
  534.     while ((c = yylex (0)) == WORD)
  535.     word (yylval.cp);
  536.  
  537.     word (NOWORD);
  538.     peeksym = c;
  539.  
  540.     return copyw();
  541. }
  542.  
  543. /*
  544.  * supporting functions
  545.  */
  546.  
  547. static C_Op    *list (t1, t2)
  548. register C_Op    *t1, *t2;
  549. {
  550.     if (t1 == (C_Op *)NULL)
  551.     return t2;
  552.  
  553.     if (t2 == (C_Op *)NULL)
  554.     return t1;
  555.  
  556.     return block (TLIST, t1, t2, NOWORDS);
  557. }
  558.  
  559. static C_Op    *block (type, t1, t2, wp)
  560. C_Op        *t1, *t2;
  561. char        **wp;
  562. {
  563.     register C_Op *t = (C_Op *)tree (sizeof (C_Op));
  564.  
  565.     t->type = type;
  566.     t->left = t1;
  567.     t->right = t2;
  568.     t->words = wp;
  569.     return t;
  570. }
  571.  
  572. static struct res {
  573.     char    *r_name;
  574.     int        r_val;
  575. } restab[] = {
  576.     {    "for",        FOR},        {"case",    CASE},
  577.     {"esac",    ESAC},        {"while",    WHILE},
  578.     {"do",        DO},        {"done",    DONE},
  579.     {"if",        IF},        {"in",        IN},
  580.     {"then",    THEN},        {"else",    ELSE},
  581.     {"elif",    ELIF},        {"until",    UNTIL},
  582.     {"fi",        FI},
  583.  
  584.     {";;",        BREAK},        {"||",        LOGOR},
  585.     {"&&",        LOGAND},    {"{",        '{'},
  586.     {"}",        '}'},
  587.  
  588.     {(char *)NULL,    0}
  589. };
  590.  
  591. static int    rlookup (n)
  592. register char    *n;
  593. {
  594.     register struct res        *rp = restab;
  595.  
  596.     while ((rp->r_name != (char *)NULL) && strcmp (rp->r_name, n))
  597.     rp++;
  598.  
  599.     return rp->r_val;
  600. }
  601.  
  602. static C_Op    *namelist(t)
  603. register C_Op    *t;
  604. {
  605.     if (iolist) 
  606.     {
  607.     iolist = addword ((char *)NULL, iolist);
  608.     t->ioact = copyio ();
  609.     }
  610.     
  611.     else
  612.     t->ioact = (IO_Actions **)NULL;
  613.  
  614.     if ((t->type != TCOM) && (t->type != TFUNC))
  615.     {
  616.     if ((t->type != TPAREN) && (t->ioact != (IO_Actions **)NULL))
  617.     {
  618.         t = block (TPAREN, t, NOBLOCK, NOWORDS);
  619.         t->ioact = t->left->ioact;
  620.         t->left->ioact = (IO_Actions **)NULL;
  621.     }
  622.     }
  623.  
  624.     else
  625.     {
  626.     word (NOWORD);
  627.     t->words = copyw();
  628.     }
  629.  
  630.     return t;
  631. }
  632.  
  633. static char    **copyw ()
  634. {
  635.     register char **wd = getwords (wdlist);
  636.  
  637.     wdlist = (Word_B *)NULL;
  638.     return wd;
  639. }
  640.  
  641. static void    word (cp)
  642. char        *cp;
  643. {
  644.     wdlist = addword (cp, wdlist);
  645. }
  646.  
  647. static IO_Actions    **copyio ()
  648. {
  649.     IO_Actions    **iop = (IO_Actions **)getwords (iolist);
  650.  
  651.     iolist = (Word_B *)NULL;
  652.     return iop;
  653. }
  654.  
  655. static IO_Actions    *io (u, f, cp)
  656. int            f, u;
  657. char            *cp;
  658. {
  659.     register IO_Actions *iop = (IO_Actions *)tree (sizeof (IO_Actions));
  660.  
  661.     iop->io_unit = u;
  662.     iop->io_flag = f;
  663.     iop->io_name = cp;
  664.     iolist = addword ((char *)iop, iolist);
  665.     return iop;
  666. }
  667.  
  668. static void    yyerror (s)
  669. char        *s;
  670. {
  671.     yynerrs++;
  672.  
  673.     if (Interactive ())
  674.     {
  675.     multiline = 0;
  676.  
  677.     while ((eofc () == 0) && (yylex (0) != NL))
  678.         ;
  679.     }
  680.  
  681.     print_error (s);
  682.     fail ();
  683. }
  684.  
  685. static int    yylex (cf)
  686. int        cf;
  687. {
  688.     register int    c, c1;
  689.     bool        atstart;
  690.  
  691.     if ((c = peeksym) > 0) 
  692.     {
  693.     peeksym = 0;
  694.  
  695.     if (c == NL)
  696.         startl = TRUE;
  697.  
  698.     return c;
  699.     }
  700.  
  701.     e.linep = e.cline;
  702.     atstart = startl;
  703.     startl = FALSE;
  704.     yylval.i = 0;
  705.  
  706. loop:
  707.     while ((c = Getc (0)) == SP || c == '\t')
  708.     ;
  709.  
  710.     switch (c) 
  711.     {
  712.     default:
  713.         if (isdigit (c)) 
  714.         {
  715.         unget (c1 = Getc(0));
  716.  
  717.         if ((c1 == '<') || (c1 == '>'))
  718.         {
  719.             iounit = c - '0';
  720.             goto loop;
  721.         }
  722.  
  723.         *e.linep++ = (char)c;
  724.         c = c1;
  725.         }
  726.  
  727.         break;
  728.  
  729.     case '#':
  730.         while ((c = Getc(0)) != 0 && (c != NL))
  731.         ;
  732.  
  733.         unget(c);
  734.         goto loop;
  735.  
  736.     case 0:
  737.         return c;
  738.  
  739. /* Allow $name, ${name}, $(command) and support $[arthmetic functions] */
  740.  
  741.     case '$':
  742.         *e.linep++ = (char)c;
  743.  
  744.         if (((c = Getc(0)) == '{') || (c == '('))
  745.         {
  746.         if ((c = collect (c, (c == '{') ? '}' : ')')) != '\0')
  747.             return (c);
  748.  
  749.         goto pack;
  750.         }
  751.  
  752.         break;
  753.  
  754.     case '`':
  755.     case '\'':
  756.     case '"':
  757.         if ((c = collect (c, c)) != '\0')
  758.         return c;
  759.  
  760.         goto pack;
  761.  
  762.     case '|':
  763.     case '&':
  764.     case ';':
  765.         if ((c1 = dual (c)) != '\0') 
  766.         {
  767.         startl = TRUE;
  768.         return c1;
  769.         }
  770.  
  771.     case '(':
  772.     case ')':
  773.         startl = TRUE;
  774.         return c;
  775.  
  776.     case '^':
  777.         startl = TRUE;
  778.         return '|';
  779.  
  780.     case '>':
  781.     case '<':
  782.         diag (c);
  783.         return c;
  784.  
  785.     case NL:
  786.         gethere ();
  787.         startl = TRUE;
  788.  
  789.         if (multiline || (cf & CONTIN))
  790.         {
  791.         if (Interactive ())
  792.         {
  793. #ifndef NO_HISTORY
  794.             Add_History (FALSE);
  795. #endif
  796.             put_prompt (ps2->value);
  797.         }
  798.  
  799.         if (cf & CONTIN)
  800.             goto loop;
  801.         }
  802.  
  803.         return(c);
  804.     }
  805.  
  806.     unget (c);
  807.  
  808. pack:
  809.     while (((c = Getc (0)) != 0) && (!any ((char)c, "`$ '\"\t;&<>()|^\n")))
  810.     {
  811.     if (e.linep >= e.eline)
  812.         print_error ("sh: word too long\n");
  813.  
  814.     else
  815.         *e.linep++ = (char)c;
  816.     }
  817.  
  818.     unget (c);
  819.  
  820.     if (any ((char)c, spcl2))
  821.     goto loop;
  822.  
  823.     *e.linep++ = '\0';
  824.  
  825.     if (atstart && (c = rlookup (e.cline)) != 0) 
  826.     {
  827.     startl = TRUE;
  828.     return c;
  829.     }
  830.  
  831. /* Special processing for $(command) to convert it to `command` */
  832.  
  833.     if (strncmp (e.cline, "$(", 2) == 0)
  834.     {
  835.     yylval.cp = strsave (e.cline + 1, areanum);
  836.     *yylval.cp = '`';
  837.     yylval.cp[strlen (yylval.cp) - 1] = '`';
  838.     }
  839.  
  840. /* Otherwise, handle words beginning with a ~ */
  841.  
  842.     else if (*e.cline == '~')
  843.     {
  844.     char    *dir = lookup (home, FALSE)->value;
  845.  
  846.     yylval.cp = tree (strlen (e.cline) + strlen (dir));
  847.     strcat (strcpy (yylval.cp, dir), e.cline + 1);
  848.     }
  849.  
  850. /* Otherwise, just save it */
  851.  
  852.     else
  853.     yylval.cp = strsave (e.cline, areanum);
  854.  
  855.     return WORD;
  856. }
  857.  
  858. /* Read input until we read the specified end character */
  859.  
  860. int        collect (c, c1)
  861. register int    c, c1;
  862. {
  863.     char *s = "x\n";
  864.  
  865.     *e.linep++ = (char)c;        /* Save the current character    */
  866.  
  867.     while ((c = Getc (c1)) != c1) 
  868.     {
  869.     if (c == 0)             /* End of file - abort        */
  870.     {
  871.         unget (c);
  872.         *s = (char)c1;
  873.         S_puts ("sh: no closing ");
  874.         yyerror (s);
  875.         return YYERRCODE;
  876.     }
  877.  
  878.     if (Interactive () && (c == NL))
  879.     {
  880. #ifndef NO_HISTORY
  881.         Add_History (FALSE);
  882. #endif
  883.         put_prompt (ps2->value);
  884.     }
  885.  
  886.     *e.linep++ = (char)c;
  887.     }
  888.  
  889.     *e.linep++ = (char)c;
  890.     return 0;
  891. }
  892.  
  893. /* Check for &&, || and ;; */
  894.  
  895. static int    dual (c)
  896. register int    c;
  897. {
  898.     char        s[3];
  899.     register char    *cp = s;
  900.  
  901. /* Get the next character and set up double string.  Look up in valid
  902.  * operators.  If invalid, unget character
  903.  */
  904.  
  905.     *cp++ = (char)c;
  906.     *cp++ = (char)Getc (0);
  907.     *cp = 0;
  908.  
  909.     if ((c = rlookup (s)) == 0)
  910.     unget (*--cp);
  911.  
  912.     return c;
  913. }
  914.  
  915. /* Process I/O re-direction */
  916.  
  917. static void    diag (ec)
  918. register int    ec;
  919. {
  920.     register int    c;
  921.  
  922. /* Get the next character to see if it is a re-direction character as well */
  923.  
  924.     if (((c = Getc (0)) == '>') || (c == '<'))
  925.     {
  926.  
  927. /* Check for open in read/write mode */
  928.  
  929.     if ((ec == '<') && (c == '>'))
  930.         yylval.i = IOWRITE | IOREAD;
  931.  
  932. /* Otherwise, we must have a double character */
  933.  
  934.     else if (c != ec)
  935.         yyerror (syntax_err);
  936.  
  937.     else
  938.         yylval.i = (ec == '>') ? IOWRITE | IOCAT : IOHERE;
  939.  
  940.     c = Getc (0);
  941.     }
  942.     
  943.     else
  944.     yylval.i = (ec == '>') ? IOWRITE : IOREAD;
  945.  
  946. /* Check for >&, <& and <<- */
  947.  
  948.     if ((c == '-') && (yylval.i == IOHERE))
  949.     yylval.i |= IOTHERE;
  950.  
  951.     else if ((c != '&') || (yylval.i == IOHERE))
  952.     unget (c);
  953.  
  954.     else
  955.     yylval.i |= IODUP;
  956. }
  957.  
  958. /* Get a new tree leaf structure */
  959.  
  960. static char    *tree (size)
  961. unsigned int    size;
  962. {
  963.     register char *t;
  964.  
  965.     if ((t = getcell (size)) == (char *)NULL)
  966.     {
  967.     S_puts ("sh: command line too complicated\n");
  968.     fail ();
  969.     }
  970.  
  971.     return t;
  972. }
  973.