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