home *** CD-ROM | disk | FTP | other *** search
/ Big Green CD 8 / BGCD_8_Dev.iso / NEXTSTEP / UNIX / Shells / zsh-3.0.5-MIHS / src / Src / lex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-06-03  |  25.5 KB  |  1,349 lines

  1. /*
  2.  * $Id: lex.c,v 2.47 1996/10/15 20:16:35 hzoli Exp $
  3.  *
  4.  * lex.c - lexical analysis
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and to distribute modified versions of this software for any
  14.  * purpose, provided that the above copyright notice and the following
  15.  * two paragraphs appear in all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. /* lexical state */
  35.  
  36. int len = 0, bsiz = 256;
  37. char *bptr;
  38. extern int hwgetword;
  39.  
  40. struct lexstack {
  41.     struct lexstack *next;
  42.  
  43.     int incmdpos;
  44.     int incond;
  45.     int incasepat;
  46.     int isfirstln;
  47.     int isfirstch;
  48.     int histactive;
  49.     int histdone;
  50.     int spaceflag;
  51.     int stophist;
  52.     int hlinesz;
  53.     char *hline;
  54.     char *hptr;
  55.     int tok;
  56.     int isnewlin;
  57.     char *tokstr;
  58.     char *yytext;
  59.     char *bptr;
  60.     int bsiz;
  61.     short *chwords;
  62.     int chwordlen;
  63.     int chwordpos;
  64.     int hwgetword;
  65.     int lexstop;
  66.     struct heredocs *hdocs;
  67.  
  68.     unsigned char *cstack;
  69.     int csp;
  70. };
  71.  
  72. static struct lexstack *lstack = NULL;
  73.  
  74. /* History word status variables from hist.c */
  75. extern short *chwords;
  76. extern int chwordlen, chwordpos;
  77.  
  78. /* save the lexical state */
  79.  
  80. /* is this a hack or what? */
  81.  
  82. /**/
  83. void
  84. lexsave(void)
  85. {
  86.     struct lexstack *ls;
  87.  
  88.     ls = (struct lexstack *)malloc(sizeof(struct lexstack));
  89.  
  90.     ls->incmdpos = incmdpos;
  91.     ls->incond = incond;
  92.     ls->incasepat = incasepat;
  93.     ls->isfirstln = isfirstln;
  94.     ls->isfirstch = isfirstch;
  95.     ls->histactive = histactive;
  96.     ls->histdone = histdone;
  97.     ls->spaceflag = spaceflag;
  98.     ls->stophist = stophist;
  99.     ls->hline = chline;
  100.     ls->hptr = hptr;
  101.     ls->hlinesz = hlinesz;
  102.     ls->cstack = cmdstack;
  103.     ls->csp = cmdsp;
  104.     cmdstack = (unsigned char *)zalloc(256);
  105.     ls->tok = tok;
  106.     ls->isnewlin = isnewlin;
  107.     ls->tokstr = tokstr;
  108.     ls->yytext = yytext;
  109.     ls->bptr = bptr;
  110.     ls->bsiz = bsiz;
  111.     ls->chwords = chwords;
  112.     ls->chwordlen = chwordlen;
  113.     ls->chwordpos = chwordpos;
  114.     ls->hwgetword = hwgetword;
  115.     ls->lexstop = lexstop;
  116.     ls->hdocs = hdocs;
  117.     cmdsp = 0;
  118.     inredir = 0;
  119.     hdocs = NULL;
  120.  
  121.     ls->next = lstack;
  122.     lstack = ls;
  123. }
  124.  
  125. /* restore lexical state */
  126.  
  127. /**/
  128. void
  129. lexrestore(void)
  130. {
  131.     struct lexstack *ln;
  132.  
  133.     DPUTS(!lstack, "lexrestore without lexsave");
  134.     incmdpos = lstack->incmdpos;
  135.     incond = lstack->incond;
  136.     incasepat = lstack->incasepat;
  137.     isfirstln = lstack->isfirstln;
  138.     isfirstch = lstack->isfirstch;
  139.     histactive = lstack->histactive;
  140.     histdone = lstack->histdone;
  141.     spaceflag = lstack->spaceflag;
  142.     stophist = lstack->stophist;
  143.     chline = lstack->hline;
  144.     hptr = lstack->hptr;
  145.     if (cmdstack)
  146.     free(cmdstack);
  147.     cmdstack = lstack->cstack;
  148.     cmdsp = lstack->csp;
  149.     tok = lstack->tok;
  150.     isnewlin = lstack->isnewlin;
  151.     tokstr = lstack->tokstr;
  152.     yytext = lstack->yytext;
  153.     bptr = lstack->bptr;
  154.     bsiz = lstack->bsiz;
  155.     chwords = lstack->chwords;
  156.     chwordlen = lstack->chwordlen;
  157.     chwordpos = lstack->chwordpos;
  158.     hwgetword = lstack->hwgetword;
  159.     lexstop = lstack->lexstop;
  160.     hdocs = lstack->hdocs;
  161.     hlinesz = lstack->hlinesz;
  162.     errflag = 0;
  163.  
  164.     ln = lstack->next;
  165.     free(lstack);
  166.     lstack = ln;
  167. }
  168.  
  169. /**/
  170. void
  171. yylex(void)
  172. {
  173.     if (tok == LEXERR)
  174.     return;
  175.     do
  176.     tok = gettok();
  177.     while (tok != ENDINPUT && exalias());
  178.     if (tok == NEWLIN || tok == ENDINPUT) {
  179.     while (hdocs) {
  180.         struct heredocs *next = hdocs->next;
  181.  
  182.         hwbegin(0);
  183.         cmdpush(hdocs->rd->type == HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
  184.         STOPHIST
  185.         hdocs->rd->name = gethere(hdocs->rd->name, hdocs->rd->type);
  186.         ALLOWHIST
  187.         cmdpop();
  188.         hwend();
  189.         hdocs->rd->type = HERESTR;
  190.         zfree(hdocs, sizeof(struct heredocs));
  191.         hdocs = next;
  192.     }
  193.     }
  194.     if (tok != NEWLIN)
  195.     isnewlin = 0;
  196.     else
  197.     isnewlin = (inbufct) ? -1 : 1;
  198.     if (tok == SEMI || tok == NEWLIN)
  199.     tok = SEPER;
  200. }
  201.  
  202. /**/
  203. void
  204. ctxtlex(void)
  205. {
  206.     static int oldpos;
  207.  
  208.     yylex();
  209.     switch (tok) {
  210.     case SEPER:
  211.     case NEWLIN:
  212.     case SEMI:
  213.     case DSEMI:
  214.     case AMPER:
  215.     case AMPERBANG:
  216.     case INPAR:
  217.     case INBRACE:
  218.     case DBAR:
  219.     case DAMPER:
  220.     case BAR:
  221.     case BARAMP:
  222.     case INOUTPAR:
  223.     case DO:
  224.     case THEN:
  225.     case ELIF:
  226.     case ELSE:
  227.     case DOUTBRACK:
  228.     incmdpos = 1;
  229.     break;
  230.     case STRING:
  231.  /* case ENVSTRING: */
  232.     case ENVARRAY:
  233.     case OUTPAR:
  234.     case CASE:
  235.     case DINBRACK:
  236.     incmdpos = 0;
  237.     break;
  238.     }
  239.     if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
  240.     inredir = 1;
  241.     oldpos = incmdpos;
  242.     incmdpos = 0;
  243.     } else if (inredir) {
  244.     incmdpos = oldpos;
  245.     inredir = 0;
  246.     }
  247. }
  248.  
  249. #define LX1_BKSLASH 0
  250. #define LX1_COMMENT 1
  251. #define LX1_NEWLIN 2
  252. #define LX1_SEMI 3
  253. #define LX1_AMPER 5
  254. #define LX1_BAR 6
  255. #define LX1_INPAR 7
  256. #define LX1_OUTPAR 8
  257. #define LX1_INANG 13
  258. #define LX1_OUTANG 14
  259. #define LX1_OTHER 15
  260.  
  261. #define LX2_BREAK 0
  262. #define LX2_OUTPAR 1
  263. #define LX2_BAR 2
  264. #define LX2_STRING 3
  265. #define LX2_INBRACK 4
  266. #define LX2_OUTBRACK 5
  267. #define LX2_TILDE 6
  268. #define LX2_INPAR 7
  269. #define LX2_INBRACE 8
  270. #define LX2_OUTBRACE 9
  271. #define LX2_OUTANG 10
  272. #define LX2_INANG 11
  273. #define LX2_EQUALS 12
  274. #define LX2_BKSLASH 13
  275. #define LX2_QUOTE 14
  276. #define LX2_DQUOTE 15
  277. #define LX2_BQUOTE 16
  278. #define LX2_COMMA 17
  279. #define LX2_OTHER 18
  280. #define LX2_META 19
  281.  
  282. unsigned char lexact1[256], lexact2[256], lextok2[256];
  283.  
  284. /**/
  285. void
  286. initlextabs(void)
  287. {
  288.     int t0;
  289.     static char *lx1 = "\\q\n;!&|(){}[]<>";
  290.     static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
  291.  
  292.     for (t0 = 0; t0 != 256; t0++) {
  293.     lexact1[t0] = LX1_OTHER;
  294.     lexact2[t0] = LX2_OTHER;
  295.     lextok2[t0] = t0;
  296.     }
  297.     for (t0 = 0; lx1[t0]; t0++)
  298.     lexact1[(int)lx1[t0]] = t0;
  299.     for (t0 = 0; lx2[t0]; t0++)
  300.     lexact2[(int)lx2[t0]] = t0;
  301.     lexact2['&'] = LX2_BREAK;
  302.     lexact2[STOUC(Meta)] = LX2_META;
  303.     lextok2['*'] = Star;
  304.     lextok2['?'] = Quest;
  305.     lextok2['{'] = Inbrace;
  306.     lextok2['['] = Inbrack;
  307.     lextok2['$'] = String;
  308.     lextok2['~'] = Tilde;
  309.     lextok2['#'] = Pound;
  310.     lextok2['^'] = Hat;
  311. }
  312.  
  313. /* initialize lexical state */
  314.  
  315. /**/
  316. void
  317. lexinit(void)
  318. {
  319.     incond = incasepat = nocorrect =
  320.     lexstop = 0;
  321.     incmdpos = 1;
  322.     tok = ENDINPUT;
  323. }
  324.  
  325. /* add a char to the string buffer */
  326.  
  327. /**/
  328. void
  329. add(int c)
  330. {
  331.     *bptr++ = c;
  332.     if (bsiz == ++len) {
  333.     int newbsiz;
  334.  
  335.     newbsiz = bsiz * 8;
  336.     while (newbsiz < inbufct)
  337.         newbsiz *= 2;
  338.     bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
  339.     bsiz = newbsiz;
  340.     }
  341. }
  342.  
  343. #define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && cs >= ll+1-inbufct) parbegin = inbufct;}
  344. #define SETPAREND {\
  345.         if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1)\
  346.         if (cs >= ll + 1 - inbufct)\
  347.             parbegin = -1;\
  348.         else\
  349.             parend = inbufct;}
  350.  
  351. static int
  352. cmd_or_math(int cs_type)
  353. {
  354.     int oldlen = len;
  355.     int c;
  356.  
  357.     cmdpush(cs_type);
  358.     c = dquote_parse(')', 0);
  359.     cmdpop();
  360.     *bptr = '\0';
  361.     if (!c) {
  362.     c = hgetc();
  363.     if (c == ')')
  364.         return 1;
  365.     hungetc(c);
  366.     lexstop = 0;
  367.     c = ')';
  368.     }
  369.     hungetc(c);
  370.     lexstop = 0;
  371.     while (len > oldlen) {
  372.     len--;
  373.     hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr);
  374.     }
  375.     hungetc('(');
  376.     return 0;
  377. }
  378.  
  379. static int
  380. cmd_or_math_sub(void)
  381. {
  382.     int c = hgetc();
  383.  
  384.     if (c == '(') {
  385.     add(Inpar);
  386.     add('(');
  387.     if (cmd_or_math(CS_MATHSUBST)) {
  388.         add(')');
  389.         return 0;
  390.     }
  391.     bptr -= 2;
  392.     len -= 2;
  393.     } else {
  394.     hungetc(c);
  395.     lexstop = 0;
  396.     }
  397.     return skipcomm();
  398. }
  399.  
  400. /**/
  401. int
  402. gettok(void)
  403. {
  404.     int c, d;
  405.     int peekfd = -1, peek;
  406.  
  407.     MUSTUSEHEAP("gettok");
  408.   beginning:
  409.     tokstr = NULL;
  410.     while (iblank(c = hgetc()) && !lexstop);
  411.     if (lexstop)
  412.     return (errflag) ? LEXERR : ENDINPUT;
  413.     isfirstln = 0;
  414.     wordbeg = inbufct - (qbang && c == bangchar);
  415.     hwbegin(-1-(qbang && c == bangchar));
  416.     /* word includes the last character read and possibly \ before ! */
  417.     if (idigit(c)) {    /* handle 1< foo */
  418.     d = hgetc();
  419.     if (d == '>' || d == '<') {
  420.         peekfd = c - '0';
  421.         c = d;
  422.     } else {
  423.         hungetc(d);
  424.         lexstop = 0;
  425.     }
  426.     }
  427.  
  428.     /* chars in initial position in word */
  429.  
  430.     if (c == hashchar &&
  431.     (isset(INTERACTIVECOMMENTS) ||
  432.      (!zleparse && !expanding &&
  433.       (!interact || unset(SHINSTDIN) || strin)))) {
  434.     /* History is handled here to prevent extra  *
  435.      * newlines being inserted into the history. */
  436.  
  437.     while ((c = ingetc()) != '\n' && !lexstop) {
  438.         hwaddc(c);
  439.         addtoline(c);
  440.     }
  441.  
  442.     if (errflag)
  443.         peek = LEXERR;
  444.     else {
  445.         hwend();
  446.         hwbegin(0);
  447.         hwaddc('\n');
  448.         addtoline('\n');
  449.         peek = NEWLIN;
  450.     }
  451.     return peek;
  452.     }
  453.     switch (lexact1[STOUC(c)]) {
  454.     case LX1_BKSLASH:
  455.     d = hgetc();
  456.     if (d == '\n')
  457.         goto beginning;
  458.     hungetc(d);
  459.     lexstop = 0;
  460.     break;
  461.     case LX1_NEWLIN:
  462.     return NEWLIN;
  463.     case LX1_SEMI:
  464.     d = hgetc();
  465.     if (d != ';') {
  466.         hungetc(d);
  467.         lexstop = 0;
  468.         return SEMI;
  469.     }
  470.     return DSEMI;
  471.     case LX1_AMPER:
  472.     d = hgetc();
  473.     if (d == '&')
  474.         return DAMPER;
  475.     else if (d == '!' || d == '|')
  476.         return AMPERBANG;
  477.     else if (d == '>') {
  478.         d = hgetc();
  479.         if (d == '!' || d == '|')
  480.         return OUTANGAMPBANG;
  481.         else if (d == '>') {
  482.         d = hgetc();
  483.         if (d == '!' || d == '|')
  484.             return DOUTANGAMPBANG;
  485.         hungetc(d);
  486.         lexstop = 0;
  487.         return DOUTANGAMP;
  488.         }
  489.         hungetc(d);
  490.         lexstop = 0;
  491.         return AMPOUTANG;
  492.     }
  493.     hungetc(d);
  494.     lexstop = 0;
  495.     return AMPER;
  496.     case LX1_BAR:
  497.     d = hgetc();
  498.     if (d == '|')
  499.         return DBAR;
  500.     else if (d == '&')
  501.         return BARAMP;
  502.     hungetc(d);
  503.     lexstop = 0;
  504.     return BAR;
  505.     case LX1_INPAR:
  506.     d = hgetc();
  507.     if (d == '(' && incmdpos) {
  508.         len = 0;
  509.         bptr = tokstr = (char *)ncalloc(bsiz = 256);
  510.         return cmd_or_math(CS_MATH) ? DINPAR : INPAR;
  511.     } else if (d == ')')
  512.         return INOUTPAR;
  513.     hungetc(d);
  514.     lexstop = 0;
  515.     if (!(incond == 1 || incmdpos))
  516.         break;
  517.     return INPAR;
  518.     case LX1_OUTPAR:
  519.     return OUTPAR;
  520.     case LX1_INANG:
  521.     d = hgetc();
  522.     if (!incmdpos && d == '(') {
  523.         hungetc(d);
  524.         lexstop = 0;
  525.         break;
  526.     }
  527.     if (d == '>')
  528.         peek = INOUTANG;
  529.     else if (idigit(d) || d == '-') {
  530.         int tbs = 256, n = 0, nc;
  531.         char *tbuf, *tbp, *ntb;
  532.  
  533.         tbuf = tbp = (char *)zalloc(tbs);
  534.         hungetc(d);
  535.  
  536.         while ((nc = hgetc()) && !lexstop) {
  537.         if (!idigit(nc) && nc != '-')
  538.             break;
  539.         *tbp++ = (char)nc;
  540.         if (++n == tbs) {
  541.             ntb = (char *)realloc(tbuf, tbs *= 2);
  542.             tbp += ntb - tbuf;
  543.             tbuf = ntb;
  544.         }
  545.         }
  546.         if (nc == '>' && !lexstop) {
  547.         hungetc(nc);
  548.         while (n--)
  549.             hungetc(*--tbp);
  550.         zfree(tbuf, tbs);
  551.         break;
  552.         }
  553.         if (nc && !lexstop)
  554.         hungetc(nc);
  555.         lexstop = 0;
  556.         while (n--)
  557.         hungetc(*--tbp);
  558.         zfree(tbuf, tbs);
  559.         peek = INANG;
  560.     } else if (d == '<') {
  561.         int e = hgetc();
  562.  
  563.         if (e == '(') {
  564.         hungetc(e);
  565.         hungetc(d);
  566.         peek = INANG;
  567.         } else if (e == '<')
  568.         peek = TRINANG;
  569.         else if (e == '-')
  570.         peek = DINANGDASH;
  571.         else {
  572.         hungetc(e);
  573.         lexstop = 0;
  574.         peek = DINANG;
  575.         }
  576.     } else if (d == '&')
  577.         peek = INANGAMP;
  578.     else {
  579.         peek = INANG;
  580.         hungetc(d);
  581.         lexstop = 0;
  582.     }
  583.     tokfd = peekfd;
  584.     return peek;
  585.     case LX1_OUTANG:
  586.     d = hgetc();
  587.     if (d == '(') {
  588.         hungetc(d);
  589.         break;
  590.     } else if (d == '&') {
  591.         d = hgetc();
  592.         if (d == '!' || d == '|')
  593.         peek = OUTANGAMPBANG;
  594.         else {
  595.         hungetc(d);
  596.         lexstop = 0;
  597.         peek = OUTANGAMP;
  598.         }
  599.     } else if (d == '!' || d == '|')
  600.         peek = OUTANGBANG;
  601.     else if (d == '>') {
  602.         d = hgetc();
  603.         if (d == '&') {
  604.         d = hgetc();
  605.         if (d == '!' || d == '|')
  606.             peek = DOUTANGAMPBANG;
  607.         else {
  608.             hungetc(d);
  609.             lexstop = 0;
  610.             peek = DOUTANGAMP;
  611.         }
  612.         } else if (d == '!' || d == '|')
  613.         peek = DOUTANGBANG;
  614.         else if (d == '(') {
  615.         hungetc(d);
  616.         hungetc('>');
  617.         peek = OUTANG;
  618.         } else {
  619.         hungetc(d);
  620.         lexstop = 0;
  621.         peek = DOUTANG;
  622.         if (isset(HISTALLOWCLOBBER))
  623.             hwaddc('|');
  624.         }
  625.     } else {
  626.         hungetc(d);
  627.         lexstop = 0;
  628.         peek = OUTANG;
  629.         if (!incond && isset(HISTALLOWCLOBBER))
  630.         hwaddc('|');
  631.     }
  632.     tokfd = peekfd;
  633.     return peek;
  634.     }
  635.  
  636.     /* we've started a string, now get the *
  637.      * rest of it, performing tokenization */
  638.     return gettokstr(c, 0);
  639. }
  640.  
  641. /**/
  642. int
  643. gettokstr(int c, int sub)
  644. {
  645.     int bct = 0, pct = 0, brct = 0;
  646.     int intpos = 1, in_brace_param = 0;
  647.     int peek, inquote;
  648. #ifdef DEBUG
  649.     int ocmdsp = cmdsp;
  650. #endif
  651.  
  652.     peek = STRING;
  653.     if (!sub) {
  654.     len = 0;
  655.     bptr = tokstr = (char *)ncalloc(bsiz = 256);
  656.     }
  657.     for (;;) {
  658.     int act;
  659.     int e;
  660.  
  661.     if (inblank(c) && !in_brace_param && !pct)
  662.         act = LX2_BREAK;
  663.     else {
  664.         act = lexact2[STOUC(c)];
  665.         c = lextok2[STOUC(c)];
  666.     }
  667.     switch (act) {
  668.     case LX2_BREAK:
  669.         if (!in_brace_param && !sub)
  670.         goto brk;
  671.         break;
  672.     case LX2_META:
  673.         c = hgetc();
  674. #ifdef DEBUG
  675.         if (lexstop) {
  676.         fputs("BUG: input terminated by Meta\n", stderr);
  677.         fflush(stderr);
  678.         goto brk;
  679.         }
  680. #endif
  681.         add(Meta);
  682.         break;
  683.     case LX2_OUTPAR:
  684.         if ((sub || in_brace_param) && isset(SHGLOB))
  685.         break;
  686.         if (!in_brace_param && !pct--)
  687.         if (sub) {
  688.             pct = 0;
  689.             break;
  690.         } else
  691.             goto brk;
  692.         c = Outpar;
  693.         break;
  694.     case LX2_BAR:
  695.         if (!pct && !in_brace_param)
  696.         if (sub)
  697.             break;
  698.         else
  699.             goto brk;
  700.         if (unset(SHGLOB) || (!sub && !in_brace_param))
  701.         c = Bar;
  702.         break;
  703.     case LX2_STRING:
  704.         e = hgetc();
  705.         if (e == '[') {
  706.         cmdpush(CS_MATHSUBST);
  707.         add(String);
  708.         add(Inbrack);
  709.         c = dquote_parse(']', sub);
  710.         cmdpop();
  711.         if (c) {
  712.             peek = LEXERR;
  713.             goto brk;
  714.         }
  715.         c = Outbrack;
  716.         } else if (e == '(') {
  717.         add(String);
  718.         c = cmd_or_math_sub();
  719.         if (c) {
  720.             peek = LEXERR;
  721.             goto brk;
  722.         }
  723.         c = Outpar;
  724.         } else {
  725.         if (e == '{') {
  726.             add(c);
  727.             c = Inbrace;
  728.             ++bct;
  729.             cmdpush(CS_BRACEPAR);
  730.             if (!in_brace_param)
  731.             in_brace_param = bct;
  732.         } else {
  733.             hungetc(e);
  734.             lexstop = 0;
  735.         }
  736.         }
  737.         break;
  738.     case LX2_INBRACK:
  739.         add(c);
  740.         if (!in_brace_param)
  741.         brct++;
  742.         c = hgetc();
  743.         if (c == '!' || c == '^') {
  744.         add(c);
  745.         c = hgetc();
  746.         }
  747.         if (c == ']')
  748.         break;
  749.         if (lexstop)
  750.         goto brk;
  751.         intpos = 0;
  752.         continue;
  753.     case LX2_OUTBRACK:
  754.         if (!in_brace_param)
  755.         brct--;
  756.         if (brct < 0) {
  757.         brct = 0;
  758.         break;
  759.         }
  760.         c = Outbrack;
  761.         break;
  762.     case LX2_INPAR:
  763.         if ((sub || in_brace_param) && isset(SHGLOB))
  764.         break;
  765.         if (!in_brace_param) {
  766.         if (!sub) {
  767.             e = hgetc();
  768.             hungetc(e);
  769.             lexstop = 0;
  770.             if (e == ')' ||
  771.             (incmdpos && !brct && peek != ENVSTRING))
  772.             goto brk;
  773.         }
  774.         pct++;
  775.         }
  776.         c = Inpar;
  777.         break;
  778.     case LX2_INBRACE:
  779.         if (isset(IGNOREBRACES) || sub)
  780.         c = '{';
  781.         else {
  782.         if (!len && incmdpos) {
  783.             add('{');
  784.             *bptr = '\0';
  785.             return STRING;
  786.         }
  787.         if (in_brace_param)
  788.             cmdpush(CS_BRACE);
  789.         bct++;
  790.         }
  791.         break;
  792.     case LX2_OUTBRACE:
  793.         if ((isset(IGNOREBRACES) || sub) && !in_brace_param)
  794.         break;
  795.         if (!bct)
  796.         break;
  797.         if (in_brace_param)
  798.         cmdpop();
  799.         if (bct-- == in_brace_param)
  800.         in_brace_param = 0;
  801.         c = Outbrace;
  802.         break;
  803.     case LX2_COMMA:
  804.         if (unset(IGNOREBRACES) && !sub && bct > in_brace_param)
  805.         c = Comma;
  806.         break;
  807.     case LX2_OUTANG:
  808.         if (!intpos)
  809.         if (in_brace_param || sub)
  810.             break;
  811.         else
  812.             goto brk;
  813.         e = hgetc();
  814.         if (e != '(') {
  815.         hungetc(e);
  816.         lexstop = 0;
  817.         goto brk;
  818.         }
  819.         add(Outang);
  820.         if (skipcomm()) {
  821.         peek = LEXERR;
  822.         goto brk;
  823.         }
  824.         c = Outpar;
  825.         break;
  826.     case LX2_INANG:
  827.         if (isset(SHGLOB) && sub)
  828.         break;
  829.         e = hgetc();
  830.         if (!(idigit(e) || e == '-' || (e == '(' && intpos))) {
  831.         hungetc(e);
  832.         lexstop = 0;
  833.         if (in_brace_param || sub)
  834.             break;
  835.         goto brk;
  836.         }
  837.         c = Inang;
  838.         if (e == '(') {
  839.         add(c);
  840.         if (skipcomm()) {
  841.             peek = LEXERR;
  842.             goto brk;
  843.         }
  844.         c = Outpar;
  845.         } else {
  846.         add(c);
  847.         c = e;
  848.         while (c != '>' && !lexstop)
  849.             add(c), c = hgetc();
  850.         c = Outang;
  851.         }
  852.         break;
  853.     case LX2_EQUALS:
  854.         if (intpos) {
  855.         e = hgetc();
  856.         if (e != '(') {
  857.             hungetc(e);
  858.             lexstop = 0;
  859.             c = Equals;
  860.         } else {
  861.             add(Equals);
  862.             if (skipcomm()) {
  863.             peek = LEXERR;
  864.             goto brk;
  865.             }
  866.             c = Outpar;
  867.         }
  868.         } else if (!sub && peek != ENVSTRING &&
  869.                incmdpos && !bct && !brct) {
  870.         char *t = tokstr;
  871.         if (idigit(*t))
  872.             while (++t < bptr && idigit(*t));
  873.         else {
  874.             while (iident(*t) && ++t < bptr);
  875.             if (t < bptr) {
  876.             *bptr = '\0';
  877.             skipparens(Inbrack, Outbrack, &t);
  878.             }
  879.         }
  880.         if (t == bptr) {
  881.             e = hgetc();
  882.             if (e == '(' && incmdpos) {
  883.             *bptr = '\0';
  884.             return ENVARRAY;
  885.             }
  886.             hungetc(e);
  887.             lexstop = 0;
  888.             peek = ENVSTRING;
  889.             intpos = 2;
  890.         } else
  891.             c = Equals;
  892.         } else
  893.         c = Equals;
  894.         break;
  895.     case LX2_BKSLASH:
  896.         c = hgetc();
  897.         if (c == '\n') {
  898.         c = hgetc();
  899.         if (!lexstop)
  900.             continue;
  901.         } else
  902.         add(Bnull);
  903.         if (lexstop)
  904.         goto brk;
  905.         break;
  906.     case LX2_QUOTE:
  907.         add(Snull);
  908.         cmdpush(CS_QUOTE);
  909.         for (;;) {
  910.         STOPHIST
  911.         while ((c = hgetc()) != '\'' && !lexstop) {
  912.             if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
  913.             if (bptr[-1] == '\\')
  914.                 bptr--, len--;
  915.             else
  916.                 break;
  917.             }
  918.             add(c);
  919.         }
  920.         ALLOWHIST
  921.         if (c != '\'') {
  922.             zerr("unmatched \'", NULL, 0);
  923.             peek = LEXERR;
  924.             cmdpop();
  925.             goto brk;
  926.         }
  927.         e = hgetc();
  928.         if (e != '\'' || unset(RCQUOTES))
  929.             break;
  930.         add(c);
  931.         }
  932.         cmdpop();
  933.         hungetc(e);
  934.         lexstop = 0;
  935.         c = Snull;
  936.         break;
  937.     case LX2_DQUOTE:
  938.         add(Dnull);
  939.         cmdpush(CS_DQUOTE);
  940.         c = dquote_parse('"', sub);
  941.         cmdpop();
  942.         if (c) {
  943.         zerr("unmatched \"", NULL, 0);
  944.         peek = LEXERR;
  945.         goto brk;
  946.         }
  947.         c = Dnull;
  948.         break;
  949.     case LX2_BQUOTE:
  950.         add(Tick);
  951.         cmdpush(CS_BQUOTE);
  952.         SETPARBEGIN
  953.         inquote = 0;
  954.         while ((c = hgetc()) != '`' && !lexstop)
  955.         if (c == '\\') {
  956.             c = hgetc();
  957.             if (c != '\n') {
  958.             add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\');
  959.             add(c);
  960.             }
  961.             else if (!sub && isset(CSHJUNKIEQUOTES))
  962.             add(c);
  963.         } else {
  964.             if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
  965.             break;
  966.             }
  967.             add(c);
  968.             if (c == '\'')
  969.             if ((inquote = !inquote))
  970.                 STOPHIST
  971.             else
  972.                 ALLOWHIST
  973.         }
  974.         if (inquote)
  975.         ALLOWHIST
  976.         cmdpop();
  977.         if (c != '`') {
  978.         zerr("unmatched `", NULL, 0);
  979.         peek = LEXERR;
  980.         goto brk;
  981.         }
  982.         c = Tick;
  983.         SETPAREND
  984.         break;
  985.     }
  986.     add(c);
  987.     c = hgetc();
  988.     if (intpos)
  989.         intpos--;
  990.     if (lexstop)
  991.         break;
  992.     }
  993.   brk:
  994.     hungetc(c);
  995.     if (in_brace_param) {
  996.     while(bct-- >= in_brace_param)
  997.         cmdpop();
  998.     zerr("closing brace expected", NULL, 0);
  999.     } else if (unset(IGNOREBRACES) && !sub && len > 1 &&
  1000.            peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) {
  1001.     /* hack to get {foo} command syntax work */
  1002.     bptr--;
  1003.     len--;
  1004.     lexstop = 0;
  1005.     hungetc('}');
  1006.     }
  1007.     *bptr = '\0';
  1008.     DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed.");
  1009.     return peek;
  1010. }
  1011.  
  1012. extern int addedx;
  1013.  
  1014. /**/
  1015. int
  1016. dquote_parse(char endchar, int sub)
  1017. {
  1018.     int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
  1019.     int c;
  1020.     int math = endchar == ')' || endchar == ']';
  1021.     int zlemath = math && cs > ll + addedx - inbufct;
  1022.  
  1023.     while (((c = hgetc()) != endchar || bct ||
  1024.         (math && ((pct > 0) || (brct > 0))) ||
  1025.         intick) && !lexstop) {
  1026.       cont:
  1027.     switch (c) {
  1028.     case '\\':
  1029.         c = hgetc();
  1030.         if (c != '\n') {
  1031.         if (c == '$' || c == '\\' || (c == '}' && !intick && bct) ||
  1032.             c == endchar || c == '`')
  1033.             add(Bnull);
  1034.         else {
  1035.             /* lexstop is implicitely handled here */
  1036.             add('\\');
  1037.             goto cont;
  1038.         }
  1039.         } else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"')
  1040.         continue;
  1041.         break;
  1042.     case '\n':
  1043.         err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"';
  1044.         break;
  1045.     case '$':
  1046.         if (intick)
  1047.         break;
  1048.         c = hgetc();
  1049.         if (c == '(') {
  1050.         add(Qstring);
  1051.         err = cmd_or_math_sub();
  1052.         c = Outpar;
  1053.         } else if (c == '[') {
  1054.         add(String);
  1055.         add(Inbrack);
  1056.         cmdpush(CS_MATHSUBST);
  1057.         err = dquote_parse(']', sub);
  1058.         cmdpop();
  1059.         c = Outbrack;
  1060.         } else if (c == '{') {
  1061.         add(Qstring);
  1062.         c = Inbrace;
  1063.         cmdpush(CS_BRACEPAR);
  1064.         bct++;
  1065.         } else if (c == '$')
  1066.         add(Qstring);
  1067.         else {
  1068.         hungetc(c);
  1069.         lexstop = 0;
  1070.         c = Qstring;
  1071.         }
  1072.         break;
  1073.     case '}':
  1074.         if (intick || !bct)
  1075.         break;
  1076.         c = Outbrace;
  1077.         bct--;
  1078.         cmdpop();
  1079.         break;
  1080.     case '`':
  1081.         c = Qtick;
  1082.         if (intick == 2)
  1083.         ALLOWHIST
  1084.         if ((intick = !intick)) {
  1085.         SETPARBEGIN
  1086.         cmdpush(CS_BQUOTE);
  1087.         } else {
  1088.         SETPAREND
  1089.             cmdpop();
  1090.         }
  1091.         break;
  1092.     case '\'':
  1093.         if (!intick)
  1094.         break;
  1095.         if (intick == 1)
  1096.         intick = 2, STOPHIST
  1097.         else
  1098.         intick = 1, ALLOWHIST
  1099.         break;
  1100.     case '(':
  1101.         pct++;
  1102.         break;
  1103.     case ')':
  1104.         err = (!pct-- && math);
  1105.         break;
  1106.     case '[':
  1107.         brct++;
  1108.         break;
  1109.     case ']':
  1110.         err = (!brct-- && math);
  1111.         break;
  1112.     case '"':
  1113.         if (intick || (!endchar && !bct))
  1114.         break;
  1115.         if (bct) {
  1116.         add(Dnull);
  1117.         err = dquote_parse('"', sub);
  1118.         c = Dnull;
  1119.         } else
  1120.         err = 1;
  1121.         break;
  1122.     }
  1123.     if (err || lexstop)
  1124.         break;
  1125.     add(c);
  1126.     }
  1127.     if (intick == 2)
  1128.     ALLOWHIST
  1129.     if (intick)
  1130.     cmdpop();
  1131.     while (bct--)
  1132.     cmdpop();
  1133.     if (lexstop)
  1134.     err = intick || endchar || err;
  1135.     else if (err == 1)
  1136.     err = c;
  1137.     if (zlemath && cs <= ll + 1 - inbufct)
  1138.     inwhat = IN_MATH;
  1139.     return err;
  1140. }
  1141.  
  1142. /* Tokenize a string given in s. Parsing is done as in double *
  1143.  * quotes.  This is usually called before singsub().          */
  1144.  
  1145. /**/
  1146. int
  1147. parsestr(char *s)
  1148. {
  1149.     int l = strlen(s), err;
  1150.  
  1151.     HEAPALLOC {
  1152.     lexsave();
  1153.     untokenize(s);
  1154.     inpush(dupstring(s), 0, NULL);
  1155.     strinbeg();
  1156.     stophist = 2;
  1157.     len = 0;
  1158.     bptr = tokstr = s;
  1159.     bsiz = l + 1;
  1160.     err = dquote_parse('\0', 1);
  1161.     *bptr = '\0';
  1162.     strinend();
  1163.     inpop();
  1164.     DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
  1165.     lexrestore();
  1166.     if (err) {
  1167.         untokenize(s);
  1168.         if (err > 32 && err < 127)
  1169.         zerr("parse error near `%c'", NULL, err);
  1170.         else
  1171.         zerr("parse error", NULL, 0);
  1172.     }
  1173.     } LASTALLOC;
  1174.     return err;
  1175. }
  1176.  
  1177. /* Tokenize a string given in s. Parsing is done as if s were a normal *
  1178.  * command-line argument but it may contain separators.  This is used  *
  1179.  * to parse the right-hand side of ${...%...} substitutions.           */
  1180.  
  1181. /**/
  1182. int
  1183. parse_subst_string(char *s)
  1184. {
  1185.     int c, l = strlen(s), err;
  1186.  
  1187.     if (! *s)
  1188.     return 0;
  1189.     lexsave();
  1190.     untokenize(s);
  1191.     inpush(dupstring(s), 0, NULL);
  1192.     strinbeg();
  1193.     stophist = 2;
  1194.     len = 0;
  1195.     bptr = tokstr = s;
  1196.     bsiz = l + 1;
  1197.     c = hgetc();
  1198.     c = gettokstr(c, 1);
  1199.     err = errflag;
  1200.     strinend();
  1201.     inpop();
  1202.     DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
  1203.     lexrestore();
  1204.     errflag = err;
  1205.     if (c == LEXERR) {
  1206.     untokenize(s);
  1207.     return 1;
  1208.     }
  1209. #ifdef DEBUG
  1210.     if (c != STRING || len != l || errflag) {
  1211.     fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
  1212.         len < l ? "len < l" : errflag ? "errflag" : "c != STRING");
  1213.     fflush(stderr);
  1214.     untokenize(s);
  1215.     return 1;
  1216.     }
  1217. #endif
  1218.     return 0;
  1219. }
  1220.  
  1221. /* expand aliases and reserved words */
  1222.  
  1223. /**/
  1224. int
  1225. exalias(void)
  1226. {
  1227.     Alias an;
  1228.     Reswd rw;
  1229.  
  1230.     hwend();
  1231.     if (interact && isset(SHINSTDIN) && !strin && !incasepat &&
  1232.     tok == STRING && !nocorrect && !(inbufflags & INP_ALIAS) &&
  1233.     (isset(CORRECTALL) || (isset(CORRECT) && incmdpos)))
  1234.     spckword(&tokstr, 1, incmdpos, 1);
  1235.  
  1236.     if (!tokstr) {
  1237.     yytext = tokstrings[tok];
  1238.     if (yytext)
  1239.         yytext = dupstring(yytext);
  1240.     return 0;
  1241.     }
  1242.  
  1243.     if (has_token(tokstr)) {
  1244.     char *p, *t;
  1245.  
  1246.     yytext = p = ncalloc(strlen(tokstr) + 1);
  1247.     for (t = tokstr; (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
  1248.     } else
  1249.     yytext = tokstr;
  1250.  
  1251.     if (zleparse && !(inbufflags & INP_ALIAS)) {
  1252.     int zp = zleparse;
  1253.  
  1254.     gotword();
  1255.     if (zp == 1 && !zleparse) {
  1256.         return 0;
  1257.     }
  1258.     }
  1259.  
  1260.     if (tok == STRING) {
  1261.     /* Check for an alias */
  1262.     an = noaliases ? NULL : (Alias) aliastab->getnode(aliastab, yytext);
  1263.     if (an && !an->inuse && ((an->flags & ALIAS_GLOBAL) || incmdpos ||
  1264.          inalmore)) {
  1265.         inpush(an->text, INP_ALIAS, an);
  1266.         /* remove from history if it begins with space */
  1267.         if (isset(HISTIGNORESPACE) && an->text[0] == ' ')
  1268.         remhist();
  1269.         lexstop = 0;
  1270.         return 1;
  1271.     }
  1272.  
  1273.     /* Then check for a reserved word */
  1274.     if ((incmdpos ||
  1275.          (unset(IGNOREBRACES) && yytext[0] == '}' && !yytext[1])) &&
  1276.         (rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) {
  1277.         tok = rw->token;
  1278.         if (tok == DINBRACK)
  1279.         incond = 1;
  1280.     } else if (incond && !strcmp(yytext, "]]")) {
  1281.         tok = DOUTBRACK;
  1282.         incond = 0;
  1283.     } else if (incond && yytext[0] == '!' && !yytext[1])
  1284.         tok = BANG;
  1285.     }
  1286.     inalmore = 0;
  1287.     return 0;
  1288. }
  1289.  
  1290. /* skip (...) */
  1291.  
  1292. /**/
  1293. int
  1294. skipcomm(void)
  1295. {
  1296.     int pct = 1, c;
  1297.  
  1298.     cmdpush(CS_CMDSUBST);
  1299.     SETPARBEGIN
  1300.     c = Inpar;
  1301.     do {
  1302.     add(c);
  1303.     c = hgetc();
  1304.     if (itok(c) || lexstop)
  1305.         break;
  1306.     switch (c) {
  1307.     case '(':
  1308.         pct++;
  1309.         break;
  1310.     case ')':
  1311.         pct--;
  1312.         break;
  1313.     case '\\':
  1314.         add(c);
  1315.         c = hgetc();
  1316.         break;
  1317.     case '\'':
  1318.         add(c);
  1319.         STOPHIST
  1320.         while ((c = hgetc()) != '\'' && !lexstop)
  1321.         add(c);
  1322.         ALLOWHIST
  1323.         break;
  1324.     case '\"':
  1325.         add(c);
  1326.         while ((c = hgetc()) != '\"' && !lexstop)
  1327.         if (c == '\\') {
  1328.             add(c);
  1329.             add(hgetc());
  1330.         } else
  1331.             add(c);
  1332.         break;
  1333.     case '`':
  1334.         add(c);
  1335.         while ((c = hgetc()) != '`' && !lexstop)
  1336.         if (c == '\\')
  1337.             add(c), add(hgetc());
  1338.         else
  1339.             add(c);
  1340.         break;
  1341.     }
  1342.     }
  1343.     while (pct);
  1344.     if (!lexstop)
  1345.     SETPAREND
  1346.     cmdpop();
  1347.     return lexstop;
  1348. }
  1349.