openenvutils/commandshell/shell/src/lex.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // lex.c - lexical analysis
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007-2008. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 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.mdh"
       
    33 #include "lex.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #ifdef __WINSCW__
       
    37 #pragma warn_unusedarg off
       
    38 #pragma warn_possunwant off
       
    39 #endif//__WINSCW__
       
    40 #endif//__SYMBIAN32__
       
    41 
       
    42 /* tokens */
       
    43 
       
    44 /**/
       
    45 mod_export char ztokens[] = "#$^*()$=|{}[]`<>?~`,'\"\\";
       
    46 
       
    47 /* parts of the current token */
       
    48 
       
    49 /**/
       
    50 char *yytext;
       
    51 /**/
       
    52 mod_export char *tokstr;
       
    53 /**/
       
    54 mod_export int tok;
       
    55 /**/
       
    56 mod_export int tokfd;
       
    57 
       
    58 /* lexical analyzer error flag */
       
    59  
       
    60 /**/
       
    61 mod_export int lexstop;
       
    62 
       
    63 /* if != 0, this is the first line of the command */
       
    64  
       
    65 /**/
       
    66 mod_export int isfirstln;
       
    67  
       
    68 /* if != 0, this is the first char of the command (not including white space) */
       
    69  
       
    70 /**/
       
    71 int isfirstch;
       
    72 
       
    73 /* flag that an alias should be expanded after expansion ending in space */
       
    74 
       
    75 /**/
       
    76 int inalmore;
       
    77 
       
    78 /* don't do spelling correction */
       
    79  
       
    80 /**/
       
    81 int nocorrect;
       
    82 
       
    83 /* the line buffer */
       
    84 
       
    85 /**/
       
    86 mod_export unsigned char *line;
       
    87 
       
    88 /* cursor position and line length */
       
    89 /* N.B.: must use the real names here, for the .export file */
       
    90 
       
    91 /**/
       
    92 mod_export int zshcs, zshll;
       
    93 
       
    94 /* inwhat says what exactly we are in     *
       
    95  * (its value is one of the IN_* things). */
       
    96 
       
    97 /**/
       
    98 mod_export int inwhat;
       
    99 
       
   100 /* 1 if x added to complete in a blank between words */
       
   101 
       
   102 /**/
       
   103 mod_export int addedx;
       
   104 
       
   105 /* wb and we hold the beginning/end position of the word we are completing. */
       
   106 
       
   107 /**/
       
   108 mod_export int wb, we;
       
   109 
       
   110 /* 1 if aliases should not be expanded */
       
   111  
       
   112 /**/
       
   113 mod_export int noaliases;
       
   114 
       
   115 /* we are parsing a line sent to use by the editor */
       
   116  
       
   117 /**/
       
   118 mod_export int zleparse;
       
   119  
       
   120 /**/
       
   121 mod_export int wordbeg;
       
   122  
       
   123 /**/
       
   124 mod_export int parbegin;
       
   125 
       
   126 /**/
       
   127 mod_export int parend;
       
   128 
       
   129 /* don't recognize comments */
       
   130  
       
   131 /**/
       
   132 mod_export int nocomments;
       
   133 
       
   134 /* text of punctuation tokens */
       
   135 
       
   136 /**/
       
   137 mod_export char *tokstrings[WHILE + 1] = {
       
   138     NULL,	/* NULLTOK	  0  */
       
   139     ";",	/* SEPER	     */
       
   140     "\\n",	/* NEWLIN	     */
       
   141     ";",	/* SEMI		     */
       
   142     ";;",	/* DSEMI	     */
       
   143     "&",	/* AMPER	  5  */
       
   144     "(",	/* INPAR	     */
       
   145     ")",	/* OUTPAR	     */
       
   146     "||",	/* DBAR		     */
       
   147     "&&",	/* DAMPER	     */
       
   148     ">",	/* OUTANG	  10 */
       
   149     ">|",	/* OUTANGBANG	     */
       
   150     ">>",	/* DOUTANG	     */
       
   151     ">>|",	/* DOUTANGBANG	     */
       
   152     "<",	/* INANG	     */
       
   153     "<>",	/* INOUTANG	  15 */
       
   154     "<<",	/* DINANG	     */
       
   155     "<<-",	/* DINANGDASH	     */
       
   156     "<&",	/* INANGAMP	     */
       
   157     ">&",	/* OUTANGAMP	     */
       
   158     "&>",	/* AMPOUTANG	  20 */
       
   159     "&>|",	/* OUTANGAMPBANG     */
       
   160     ">>&",	/* DOUTANGAMP	     */
       
   161     ">>&|",	/* DOUTANGAMPBANG    */
       
   162     "<<<",	/* TRINANG	     */
       
   163     "|",	/* BAR		  25 */
       
   164     "|&",	/* BARAMP	     */
       
   165     "()",	/* INOUTPAR	     */
       
   166     "((",	/* DINPAR	     */
       
   167     "))",	/* DOUTPAR	     */
       
   168     "&|",	/* AMPERBANG	  30 */
       
   169     ";&",	/* SEMIAMP	     */
       
   170 };
       
   171 
       
   172 /* lexical state */
       
   173 
       
   174 static int dbparens;
       
   175 static int len = 0, bsiz = 256;
       
   176 static char *bptr;
       
   177 
       
   178 struct lexstack {
       
   179     struct lexstack *next;
       
   180 
       
   181     int incmdpos;
       
   182     int incond;
       
   183     int incasepat;
       
   184     int dbparens;
       
   185     int isfirstln;
       
   186     int isfirstch;
       
   187     int histactive;
       
   188     int histdone;
       
   189     int stophist;
       
   190     int hlinesz;
       
   191     char *hline;
       
   192     char *hptr;
       
   193     int tok;
       
   194     int isnewlin;
       
   195     char *tokstr;
       
   196     char *yytext;
       
   197     char *bptr;
       
   198     int bsiz;
       
   199     int len;
       
   200     short *chwords;
       
   201     int chwordlen;
       
   202     int chwordpos;
       
   203     int hwgetword;
       
   204     int lexstop;
       
   205     struct heredocs *hdocs;
       
   206     int (*hgetc) _((void));
       
   207     void (*hungetc) _((int));
       
   208     void (*hwaddc) _((int));
       
   209     void (*hwbegin) _((int));
       
   210     void (*hwend) _((void));
       
   211     void (*addtoline) _((int));
       
   212 
       
   213     int eclen, ecused, ecnpats;
       
   214     Wordcode ecbuf;
       
   215     Eccstr ecstrs;
       
   216     int ecsoffs, ecssub, ecnfunc;
       
   217 
       
   218     unsigned char *cstack;
       
   219     int csp;
       
   220 };
       
   221 
       
   222 static struct lexstack *lstack = NULL;
       
   223 
       
   224 /* save the lexical state */
       
   225 
       
   226 /* is this a hack or what? */
       
   227 
       
   228 /**/
       
   229 mod_export void
       
   230 lexsave(void)
       
   231 {
       
   232     struct lexstack *ls;
       
   233 
       
   234     ls = (struct lexstack *)malloc(sizeof(struct lexstack));
       
   235 
       
   236     ls->incmdpos = incmdpos;
       
   237     ls->incond = incond;
       
   238     ls->incasepat = incasepat;
       
   239     ls->dbparens = dbparens;
       
   240     ls->isfirstln = isfirstln;
       
   241     ls->isfirstch = isfirstch;
       
   242     ls->histactive = histactive;
       
   243     ls->histdone = histdone;
       
   244     ls->stophist = stophist;
       
   245     ls->hline = chline;
       
   246     ls->hptr = hptr;
       
   247     ls->hlinesz = hlinesz;
       
   248     ls->cstack = cmdstack;
       
   249     ls->csp = cmdsp;
       
   250     cmdstack = (unsigned char *)zalloc(CMDSTACKSZ);
       
   251     ls->tok = tok;
       
   252     ls->isnewlin = isnewlin;
       
   253     ls->tokstr = tokstr;
       
   254     ls->yytext = yytext;
       
   255     ls->bptr = bptr;
       
   256     ls->bsiz = bsiz;
       
   257     ls->len = len;
       
   258     ls->chwords = chwords;
       
   259     ls->chwordlen = chwordlen;
       
   260     ls->chwordpos = chwordpos;
       
   261     ls->hwgetword = hwgetword;
       
   262     ls->lexstop = lexstop;
       
   263     ls->hdocs = hdocs;
       
   264     ls->hgetc = hgetc;
       
   265     ls->hungetc = hungetc;
       
   266     ls->hwaddc = hwaddc;
       
   267     ls->hwbegin = hwbegin;
       
   268     ls->hwend = hwend;
       
   269     ls->addtoline = addtoline;
       
   270     ls->eclen = eclen;
       
   271     ls->ecused = ecused;
       
   272     ls->ecnpats = ecnpats;
       
   273     ls->ecbuf = ecbuf;
       
   274     ls->ecstrs = ecstrs;
       
   275     ls->ecsoffs = ecsoffs;
       
   276     ls->ecssub = ecssub;
       
   277     ls->ecnfunc = ecnfunc;
       
   278     cmdsp = 0;
       
   279     inredir = 0;
       
   280     hdocs = NULL;
       
   281     histactive = 0;
       
   282     ecbuf = NULL;
       
   283 
       
   284     ls->next = lstack;
       
   285     lstack = ls;
       
   286 }
       
   287 
       
   288 /* restore lexical state */
       
   289 
       
   290 /**/
       
   291 mod_export void
       
   292 lexrestore(void)
       
   293 {
       
   294     struct lexstack *ln;
       
   295 
       
   296     DPUTS(!lstack, "BUG: lexrestore() without lexsave()");
       
   297     incmdpos = lstack->incmdpos;
       
   298     incond = lstack->incond;
       
   299     incasepat = lstack->incasepat;
       
   300     dbparens = lstack->dbparens;
       
   301     isfirstln = lstack->isfirstln;
       
   302     isfirstch = lstack->isfirstch;
       
   303     histactive = lstack->histactive;
       
   304     histdone = lstack->histdone;
       
   305     stophist = lstack->stophist;
       
   306     chline = lstack->hline;
       
   307     hptr = lstack->hptr;
       
   308     if (cmdstack)
       
   309 	free(cmdstack);
       
   310     cmdstack = lstack->cstack;
       
   311     cmdsp = lstack->csp;
       
   312     tok = lstack->tok;
       
   313     isnewlin = lstack->isnewlin;
       
   314     tokstr = lstack->tokstr;
       
   315     yytext = lstack->yytext;
       
   316     bptr = lstack->bptr;
       
   317     bsiz = lstack->bsiz;
       
   318     len = lstack->len;
       
   319     chwords = lstack->chwords;
       
   320     chwordlen = lstack->chwordlen;
       
   321     chwordpos = lstack->chwordpos;
       
   322     hwgetword = lstack->hwgetword;
       
   323     lexstop = lstack->lexstop;
       
   324     hdocs = lstack->hdocs;
       
   325     hgetc = lstack->hgetc;
       
   326     hungetc = lstack->hungetc;
       
   327     hwaddc = lstack->hwaddc;
       
   328     hwbegin = lstack->hwbegin;
       
   329     hwend = lstack->hwend;
       
   330     addtoline = lstack->addtoline;
       
   331     if (ecbuf)
       
   332 	zfree(ecbuf, eclen);
       
   333     eclen = lstack->eclen;
       
   334     ecused = lstack->ecused;
       
   335     ecnpats = lstack->ecnpats;
       
   336     ecbuf = lstack->ecbuf;
       
   337     ecstrs = lstack->ecstrs;
       
   338     ecsoffs = lstack->ecsoffs;
       
   339     ecssub = lstack->ecssub;
       
   340     ecnfunc = lstack->ecnfunc;
       
   341     hlinesz = lstack->hlinesz;
       
   342     errflag = 0;
       
   343 
       
   344     ln = lstack->next;
       
   345     free(lstack);
       
   346     lstack = ln;
       
   347 }
       
   348 
       
   349 /**/
       
   350 void
       
   351 yylex(void)
       
   352 {
       
   353     if (tok == LEXERR)
       
   354 	return;
       
   355     do
       
   356 	tok = gettok();
       
   357     while (tok != ENDINPUT && exalias());
       
   358     if (tok == NEWLIN || tok == ENDINPUT) {
       
   359 	while (hdocs) {
       
   360 	    struct heredocs *next = hdocs->next;
       
   361 	    char *name;
       
   362 
       
   363 	    hwbegin(0);
       
   364 	    cmdpush(hdocs->type == REDIR_HEREDOC ? CS_HEREDOC : CS_HEREDOCD);
       
   365 	    STOPHIST
       
   366 	    name = gethere(hdocs->str, hdocs->type);
       
   367 	    ALLOWHIST
       
   368 	    cmdpop();
       
   369 	    hwend();
       
   370 	    setheredoc(hdocs->pc, REDIR_HERESTR, name);
       
   371 	    zfree(hdocs, sizeof(struct heredocs));
       
   372 	    hdocs = next;
       
   373 	}
       
   374     }
       
   375     if (tok != NEWLIN)
       
   376 	isnewlin = 0;
       
   377     else
       
   378 	isnewlin = (inbufct) ? -1 : 1;
       
   379     if (tok == SEMI || tok == NEWLIN)
       
   380 	tok = SEPER;
       
   381 }
       
   382 
       
   383 /**/
       
   384 mod_export void
       
   385 ctxtlex(void)
       
   386 {
       
   387     static int oldpos;
       
   388 
       
   389     yylex();
       
   390     switch (tok) {
       
   391     case SEPER:
       
   392     case NEWLIN:
       
   393     case SEMI:
       
   394     case DSEMI:
       
   395     case SEMIAMP:
       
   396     case AMPER:
       
   397     case AMPERBANG:
       
   398     case INPAR:
       
   399     case INBRACE:
       
   400     case DBAR:
       
   401     case DAMPER:
       
   402     case BAR:
       
   403     case BARAMP:
       
   404     case INOUTPAR:
       
   405     case DOLOOP:
       
   406     case THEN:
       
   407     case ELIF:
       
   408     case ELSE:
       
   409     case DOUTBRACK:
       
   410 	incmdpos = 1;
       
   411 	break;
       
   412     case STRING:
       
   413  /* case ENVSTRING: */
       
   414     case ENVARRAY:
       
   415     case OUTPAR:
       
   416     case CASE:
       
   417     case DINBRACK:
       
   418 	incmdpos = 0;
       
   419 	break;
       
   420     }
       
   421     if (tok != DINPAR)
       
   422 	infor = tok == FOR ? 2 : 0;
       
   423     if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) {
       
   424 	inredir = 1;
       
   425 	oldpos = incmdpos;
       
   426 	incmdpos = 0;
       
   427     } else if (inredir) {
       
   428 	incmdpos = oldpos;
       
   429 	inredir = 0;
       
   430     }
       
   431 }
       
   432 
       
   433 #define LX1_BKSLASH 0
       
   434 #define LX1_COMMENT 1
       
   435 #define LX1_NEWLIN 2
       
   436 #define LX1_SEMI 3
       
   437 #define LX1_AMPER 5
       
   438 #define LX1_BAR 6
       
   439 #define LX1_INPAR 7
       
   440 #define LX1_OUTPAR 8
       
   441 #define LX1_INANG 13
       
   442 #define LX1_OUTANG 14
       
   443 #define LX1_OTHER 15
       
   444 
       
   445 #define LX2_BREAK 0
       
   446 #define LX2_OUTPAR 1
       
   447 #define LX2_BAR 2
       
   448 #define LX2_STRING 3
       
   449 #define LX2_INBRACK 4
       
   450 #define LX2_OUTBRACK 5
       
   451 #define LX2_TILDE 6
       
   452 #define LX2_INPAR 7
       
   453 #define LX2_INBRACE 8
       
   454 #define LX2_OUTBRACE 9
       
   455 #define LX2_OUTANG 10
       
   456 #define LX2_INANG 11
       
   457 #define LX2_EQUALS 12
       
   458 #define LX2_BKSLASH 13
       
   459 #define LX2_QUOTE 14
       
   460 #define LX2_DQUOTE 15
       
   461 #define LX2_BQUOTE 16
       
   462 #define LX2_COMMA 17
       
   463 #define LX2_OTHER 18
       
   464 #define LX2_META 19
       
   465 
       
   466 static unsigned char lexact1[256], lexact2[256], lextok2[256];
       
   467 
       
   468 /**/
       
   469 void
       
   470 initlextabs(void)
       
   471 {
       
   472     int t0;
       
   473     static char *lx1 = "\\q\n;!&|(){}[]<>";
       
   474     static char *lx2 = ";)|$[]~({}><=\\\'\"`,";
       
   475 
       
   476     for (t0 = 0; t0 != 256; t0++) {
       
   477 	lexact1[t0] = LX1_OTHER;
       
   478 	lexact2[t0] = LX2_OTHER;
       
   479 	lextok2[t0] = t0;
       
   480     }
       
   481     for (t0 = 0; lx1[t0]; t0++)
       
   482 	lexact1[(int)lx1[t0]] = t0;
       
   483     for (t0 = 0; lx2[t0]; t0++)
       
   484 	lexact2[(int)lx2[t0]] = t0;
       
   485     lexact2['&'] = LX2_BREAK;
       
   486     lexact2[STOUC(Meta)] = LX2_META;
       
   487     lextok2['*'] = Star;
       
   488     lextok2['?'] = Quest;
       
   489     lextok2['{'] = Inbrace;
       
   490     lextok2['['] = Inbrack;
       
   491     lextok2['$'] = String;
       
   492     lextok2['~'] = Tilde;
       
   493     lextok2['#'] = Pound;
       
   494     lextok2['^'] = Hat;
       
   495 }
       
   496 
       
   497 /* initialize lexical state */
       
   498 
       
   499 /**/
       
   500 void
       
   501 lexinit(void)
       
   502 {
       
   503     incond = incasepat = nocorrect =
       
   504     infor = dbparens = lexstop = 0;
       
   505     incmdpos = 1;
       
   506     tok = ENDINPUT;
       
   507 }
       
   508 
       
   509 /* add a char to the string buffer */
       
   510 
       
   511 /**/
       
   512 void
       
   513 add(int c)
       
   514 {
       
   515     *bptr++ = c;
       
   516     if (bsiz == ++len) {
       
   517 #if 0
       
   518 	int newbsiz;
       
   519 
       
   520 	newbsiz = bsiz * 8;
       
   521 	while (newbsiz < inbufct)
       
   522 	    newbsiz *= 2;
       
   523 	bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
       
   524 	bsiz = newbsiz;
       
   525 #endif
       
   526 
       
   527 	int newbsiz = bsiz * 2;
       
   528 
       
   529 	if (newbsiz > inbufct && inbufct > bsiz)
       
   530 	    newbsiz = inbufct;
       
   531 
       
   532 	bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz));
       
   533 	bsiz = newbsiz;
       
   534     }
       
   535 }
       
   536 
       
   537 #define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && cs >= ll+1-inbufct) parbegin = inbufct;}
       
   538 #define SETPAREND {\
       
   539 	    if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1) {\
       
   540 		if (cs >= ll + 1 - inbufct)\
       
   541 		    parbegin = -1;\
       
   542 		else\
       
   543 		    parend = inbufct;} }
       
   544 
       
   545 static int
       
   546 cmd_or_math(int cs_type)
       
   547 {
       
   548     int oldlen = len;
       
   549     int c;
       
   550 
       
   551     cmdpush(cs_type);
       
   552     c = dquote_parse(')', 0);
       
   553     cmdpop();
       
   554     *bptr = '\0';
       
   555     if (!c) {
       
   556 	c = hgetc();
       
   557 	if (c == ')')
       
   558 	    return 1;
       
   559 	hungetc(c);
       
   560 	lexstop = 0;
       
   561 	c = ')';
       
   562     }
       
   563     hungetc(c);
       
   564     lexstop = 0;
       
   565     while (len > oldlen) {
       
   566 	len--;
       
   567 	hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr);
       
   568     }
       
   569     hungetc('(');
       
   570     return 0;
       
   571 }
       
   572 
       
   573 static int
       
   574 cmd_or_math_sub(void)
       
   575 {
       
   576     int c = hgetc();
       
   577 
       
   578     if (c == '(') {
       
   579 	add(Inpar);
       
   580 	add('(');
       
   581 	if (cmd_or_math(CS_MATHSUBST)) {
       
   582 	    add(')');
       
   583 	    return 0;
       
   584 	}
       
   585 	bptr -= 2;
       
   586 	len -= 2;
       
   587     } else {
       
   588 	hungetc(c);
       
   589 	lexstop = 0;
       
   590     }
       
   591     return skipcomm();
       
   592 }
       
   593 
       
   594 /* Check whether we're looking at valid numeric globbing syntax      *
       
   595  * (/\<[0-9]*-[0-9]*\>/).  Call pointing just after the opening "<". *
       
   596  * Leaves the input in the same place, returning 0 or 1.             */
       
   597 
       
   598 /**/
       
   599 static int
       
   600 isnumglob(void)
       
   601 {
       
   602     int c, ec = '-', ret = 0;
       
   603     int tbs = 256, n = 0;
       
   604     char *tbuf = (char *)zalloc(tbs);
       
   605 
       
   606     while(1) {
       
   607 	c = hgetc();
       
   608 	if(lexstop) {
       
   609 	    lexstop = 0;
       
   610 	    break;
       
   611 	}
       
   612 	tbuf[n++] = c;
       
   613 	if(!idigit(c)) {
       
   614 	    if(c != ec)
       
   615 		break;
       
   616 	    if(ec == '>') {
       
   617 		ret = 1;
       
   618 		break;
       
   619 	    }
       
   620 	    ec = '>';
       
   621 	}
       
   622 	if(n == tbs)
       
   623 	    tbuf = (char *)realloc(tbuf, tbs *= 2);
       
   624     }
       
   625     while(n--)
       
   626 	hungetc(tbuf[n]);
       
   627     zfree(tbuf, tbs);
       
   628     return ret;
       
   629 }
       
   630 
       
   631 /**/
       
   632 int
       
   633 gettok(void)
       
   634 {
       
   635     int c, d;
       
   636     int peekfd = -1, peek;
       
   637 
       
   638   beginning:
       
   639     tokstr = NULL;
       
   640     while (iblank(c = hgetc()) && !lexstop);
       
   641     if (lexstop)
       
   642 	return (errflag) ? LEXERR : ENDINPUT;
       
   643     isfirstln = 0;
       
   644     wordbeg = inbufct - (qbang && c == bangchar);
       
   645     hwbegin(-1-(qbang && c == bangchar));
       
   646     /* word includes the last character read and possibly \ before ! */
       
   647     if (dbparens) {
       
   648 	len = 0;
       
   649 	bptr = tokstr = (char *) hcalloc(bsiz = 32);
       
   650 	hungetc(c);
       
   651 	cmdpush(CS_MATH);
       
   652 	c = dquote_parse(infor ? ';' : ')', 0);
       
   653 	cmdpop();
       
   654 	*bptr = '\0';
       
   655 	if (!c && infor) {
       
   656 	    infor--;
       
   657 	    return DINPAR;
       
   658 	}
       
   659 	if (c || (c = hgetc()) != ')') {
       
   660 	    hungetc(c);
       
   661 	    return LEXERR;
       
   662 	}
       
   663 	dbparens = 0;
       
   664 	return DOUTPAR;
       
   665     } else if (idigit(c)) {	/* handle 1< foo */
       
   666 	d = hgetc();
       
   667 	if(d == '&') {
       
   668 	    d = hgetc();
       
   669 	    if(d == '>') {
       
   670 		peekfd = c - '0';
       
   671 		hungetc('>');
       
   672 		c = '&';
       
   673 	    } else {
       
   674 		hungetc(d);
       
   675 		lexstop = 0;
       
   676 		hungetc('&');
       
   677 	    }
       
   678 	} else if (d == '>' || d == '<') {
       
   679 	    peekfd = c - '0';
       
   680 	    c = d;
       
   681 	} else {
       
   682 	    hungetc(d);
       
   683 	    lexstop = 0;
       
   684 	}
       
   685     }
       
   686 
       
   687     /* chars in initial position in word */
       
   688 
       
   689     if (c == hashchar && !nocomments &&
       
   690 	(isset(INTERACTIVECOMMENTS) ||
       
   691 	 (!zleparse && !expanding &&
       
   692 	  (!interact || unset(SHINSTDIN) || strin)))) {
       
   693 	/* History is handled here to prevent extra  *
       
   694 	 * newlines being inserted into the history. */
       
   695 
       
   696 	while ((c = ingetc()) != '\n' && !lexstop) {
       
   697 	    hwaddc(c);
       
   698 	    addtoline(c);
       
   699 	}
       
   700 
       
   701 	if (errflag)
       
   702 	    peek = LEXERR;
       
   703 	else {
       
   704 	    hwend();
       
   705 	    hwbegin(0);
       
   706 	    hwaddc('\n');
       
   707 	    addtoline('\n');
       
   708 	    peek = NEWLIN;
       
   709 	}
       
   710 	return peek;
       
   711     }
       
   712     switch (lexact1[STOUC(c)]) {
       
   713     case LX1_BKSLASH:
       
   714 	d = hgetc();
       
   715 	if (d == '\n')
       
   716 	    goto beginning;
       
   717 	hungetc(d);
       
   718 	lexstop = 0;
       
   719 	break;
       
   720     case LX1_NEWLIN:
       
   721 	return NEWLIN;
       
   722     case LX1_SEMI:
       
   723 	d = hgetc();
       
   724 	if(d == ';')
       
   725 	    return DSEMI;
       
   726 	else if(d == '&')
       
   727 	    return SEMIAMP;
       
   728 	hungetc(d);
       
   729 	lexstop = 0;
       
   730 	return SEMI;
       
   731     case LX1_AMPER:
       
   732 	d = hgetc();
       
   733 	if (d == '&')
       
   734 	    return DAMPER;
       
   735 	else if (d == '!' || d == '|')
       
   736 	    return AMPERBANG;
       
   737 	else if (d == '>') {
       
   738 	    tokfd = peekfd;
       
   739 	    d = hgetc();
       
   740 	    if (d == '!' || d == '|')
       
   741 		return OUTANGAMPBANG;
       
   742 	    else if (d == '>') {
       
   743 		d = hgetc();
       
   744 		if (d == '!' || d == '|')
       
   745 		    return DOUTANGAMPBANG;
       
   746 		hungetc(d);
       
   747 		lexstop = 0;
       
   748 		return DOUTANGAMP;
       
   749 	    }
       
   750 	    hungetc(d);
       
   751 	    lexstop = 0;
       
   752 	    return AMPOUTANG;
       
   753 	}
       
   754 	hungetc(d);
       
   755 	lexstop = 0;
       
   756 	return AMPER;
       
   757     case LX1_BAR:
       
   758 	d = hgetc();
       
   759 	if (d == '|')
       
   760 	    return DBAR;
       
   761 	else if (d == '&')
       
   762 	    return BARAMP;
       
   763 	hungetc(d);
       
   764 	lexstop = 0;
       
   765 	return BAR;
       
   766     case LX1_INPAR:
       
   767 	d = hgetc();
       
   768 	if (d == '(') {
       
   769 	    if (infor) {
       
   770 		dbparens = 1;
       
   771 		return DINPAR;
       
   772 	    }
       
   773 	    if (incmdpos) {
       
   774 		len = 0;
       
   775 		bptr = tokstr = (char *) hcalloc(bsiz = 32);
       
   776 		return cmd_or_math(CS_MATH) ? DINPAR : INPAR;
       
   777 	    }
       
   778 	} else if (d == ')')
       
   779 	    return INOUTPAR;
       
   780 	hungetc(d);
       
   781 	lexstop = 0;
       
   782 	if (!(incond == 1 || incmdpos))
       
   783 	    break;
       
   784 	return INPAR;
       
   785     case LX1_OUTPAR:
       
   786 	return OUTPAR;
       
   787     case LX1_INANG:
       
   788 	d = hgetc();
       
   789 	if (!incmdpos && d == '(') {
       
   790 	    hungetc(d);
       
   791 	    lexstop = 0;
       
   792 	    unpeekfd:
       
   793 	    if(peekfd != -1) {
       
   794 		hungetc(c);
       
   795 		c = '0' + peekfd;
       
   796 	    }
       
   797 	    break;
       
   798 	}
       
   799 	if (d == '>') {
       
   800 	    peek = INOUTANG;
       
   801 	} else if (d == '<') {
       
   802 	    int e = hgetc();
       
   803 
       
   804 	    if (e == '(') {
       
   805 		hungetc(e);
       
   806 		hungetc(d);
       
   807 		peek = INANG;
       
   808 	    } else if (e == '<')
       
   809 		peek = TRINANG;
       
   810 	    else if (e == '-')
       
   811 		peek = DINANGDASH;
       
   812 	    else {
       
   813 		hungetc(e);
       
   814 		lexstop = 0;
       
   815 		peek = DINANG;
       
   816 	    }
       
   817 	} else if (d == '&') {
       
   818 	    peek = INANGAMP;
       
   819 	} else {
       
   820 	    hungetc(d);
       
   821 	    if(isnumglob())
       
   822 		goto unpeekfd;
       
   823 	    peek = INANG;
       
   824 	}
       
   825 	tokfd = peekfd;
       
   826 	return peek;
       
   827     case LX1_OUTANG:
       
   828 	d = hgetc();
       
   829 	if (d == '(') {
       
   830 	    hungetc(d);
       
   831 	    goto unpeekfd;
       
   832 	} else if (d == '&') {
       
   833 	    d = hgetc();
       
   834 	    if (d == '!' || d == '|')
       
   835 		peek = OUTANGAMPBANG;
       
   836 	    else {
       
   837 		hungetc(d);
       
   838 		lexstop = 0;
       
   839 		peek = OUTANGAMP;
       
   840 	    }
       
   841 	} else if (d == '!' || d == '|')
       
   842 	    peek = OUTANGBANG;
       
   843 	else if (d == '>') {
       
   844 	    d = hgetc();
       
   845 	    if (d == '&') {
       
   846 		d = hgetc();
       
   847 		if (d == '!' || d == '|')
       
   848 		    peek = DOUTANGAMPBANG;
       
   849 		else {
       
   850 		    hungetc(d);
       
   851 		    lexstop = 0;
       
   852 		    peek = DOUTANGAMP;
       
   853 		}
       
   854 	    } else if (d == '!' || d == '|')
       
   855 		peek = DOUTANGBANG;
       
   856 	    else if (d == '(') {
       
   857 		hungetc(d);
       
   858 		hungetc('>');
       
   859 		peek = OUTANG;
       
   860 	    } else {
       
   861 		hungetc(d);
       
   862 		lexstop = 0;
       
   863 		peek = DOUTANG;
       
   864 		if (isset(HISTALLOWCLOBBER))
       
   865 		    hwaddc('|');
       
   866 	    }
       
   867 	} else {
       
   868 	    hungetc(d);
       
   869 	    lexstop = 0;
       
   870 	    peek = OUTANG;
       
   871 	    if (!incond && isset(HISTALLOWCLOBBER))
       
   872 		hwaddc('|');
       
   873 	}
       
   874 	tokfd = peekfd;
       
   875 	return peek;
       
   876     }
       
   877 
       
   878     /* we've started a string, now get the *
       
   879      * rest of it, performing tokenization */
       
   880     return gettokstr(c, 0);
       
   881 }
       
   882 
       
   883 /**/
       
   884 static int
       
   885 gettokstr(int c, int sub)
       
   886 {
       
   887     int bct = 0, pct = 0, brct = 0, fdpar = 0;
       
   888     int intpos = 1, in_brace_param = 0;
       
   889     int peek, inquote, unmatched = 0;
       
   890     char endchar='"';
       
   891 #ifdef DEBUG
       
   892     int ocmdsp = cmdsp;
       
   893 #endif
       
   894 
       
   895     peek = STRING;
       
   896     if (!sub) {
       
   897 	len = 0;
       
   898 	bptr = tokstr = (char *) hcalloc(bsiz = 32);
       
   899     }
       
   900     for (;;) {
       
   901 	int act;
       
   902 	int e;
       
   903 	int inbl = inblank(c);
       
   904 	
       
   905 	if (fdpar && !inbl && c != ')')
       
   906 	    fdpar = 0;
       
   907 
       
   908 	if (inbl && !in_brace_param && !pct)
       
   909 	    act = LX2_BREAK;
       
   910 	else {
       
   911 	    act = lexact2[STOUC(c)];
       
   912 	    c = lextok2[STOUC(c)];
       
   913 	}
       
   914 	switch (act) {
       
   915 	case LX2_BREAK:
       
   916 	    if (!in_brace_param && !sub)
       
   917 		goto brk;
       
   918 	    break;
       
   919 	case LX2_META:
       
   920 	    c = hgetc();
       
   921 #ifdef DEBUG
       
   922 	    if (lexstop) {
       
   923 		fputs("BUG: input terminated by Meta\n", stderr);
       
   924 		fflush(stderr);
       
   925 		goto brk;
       
   926 	    }
       
   927 #endif
       
   928 	    add(Meta);
       
   929 	    break;
       
   930 	case LX2_OUTPAR:
       
   931 	    if (fdpar) {
       
   932 		/* this is a single word `(   )', treat as INOUTPAR */
       
   933 		add(c);
       
   934 		*bptr = '\0';
       
   935 		return INOUTPAR;
       
   936 	    }
       
   937 	    if ((sub || in_brace_param) && isset(SHGLOB))
       
   938 		break;
       
   939 	    if (!in_brace_param && !pct--) {
       
   940 		if (sub) {
       
   941 		    pct = 0;
       
   942 		    break;
       
   943 		} else
       
   944 		    goto brk;
       
   945 	    }
       
   946 	    c = Outpar;
       
   947 	    break;
       
   948 	case LX2_BAR:
       
   949 	    if (!pct && !in_brace_param) {
       
   950 		if (sub)
       
   951 		    break;
       
   952 		else
       
   953 		    goto brk;
       
   954 	    }
       
   955 	    if (unset(SHGLOB) || (!sub && !in_brace_param))
       
   956 		c = Bar;
       
   957 	    break;
       
   958 	case LX2_STRING:
       
   959 	    e = hgetc();
       
   960 	    if (e == '[') {
       
   961 		cmdpush(CS_MATHSUBST);
       
   962 		add(String);
       
   963 		add(Inbrack);
       
   964 		c = dquote_parse(']', sub);
       
   965 		cmdpop();
       
   966 		if (c) {
       
   967 		    peek = LEXERR;
       
   968 		    goto brk;
       
   969 		}
       
   970 		c = Outbrack;
       
   971 	    } else if (e == '(') {
       
   972 		add(String);
       
   973 		c = cmd_or_math_sub();
       
   974 		if (c) {
       
   975 		    peek = LEXERR;
       
   976 		    goto brk;
       
   977 		}
       
   978 		c = Outpar;
       
   979 	    } else {
       
   980 		if (e == '{') {
       
   981 		    add(c);
       
   982 		    c = Inbrace;
       
   983 		    ++bct;
       
   984 		    cmdpush(CS_BRACEPAR);
       
   985 		    if (!in_brace_param)
       
   986 			in_brace_param = bct;
       
   987 		} else {
       
   988 		    hungetc(e);
       
   989 		    lexstop = 0;
       
   990 		}
       
   991 	    }
       
   992 	    break;
       
   993 	case LX2_INBRACK:
       
   994 	    if (!in_brace_param)
       
   995 		brct++;
       
   996 	    c = Inbrack;
       
   997 	    break;
       
   998 	case LX2_OUTBRACK:
       
   999 	    if (!in_brace_param)
       
  1000 		brct--;
       
  1001 	    if (brct < 0)
       
  1002 		brct = 0;
       
  1003 	    c = Outbrack;
       
  1004 	    break;
       
  1005 	case LX2_INPAR:
       
  1006 	    if (isset(SHGLOB)) {
       
  1007 		if (sub || in_brace_param)
       
  1008 		    break;
       
  1009 		if (incasepat && !len)
       
  1010 		    return INPAR;
       
  1011 	    }
       
  1012 	    if (!in_brace_param) {
       
  1013 		if (!sub) {
       
  1014 		    e = hgetc();
       
  1015 		    hungetc(e);
       
  1016 		    lexstop = 0;
       
  1017 		    /* For command words, parentheses are only
       
  1018 		     * special at the start.  But now we're tokenising
       
  1019 		     * the remaining string.  So I don't see what
       
  1020 		     * the old incmdpos test here is for.
       
  1021 		     *   pws 1999/6/8
       
  1022 		     *
       
  1023 		     * Oh, no.
       
  1024 		     *  func1(   )
       
  1025 		     * is a valid function definition in [k]sh.  The best
       
  1026 		     * thing we can do, without really nasty lookahead tricks,
       
  1027 		     * is break if we find a blank after a parenthesis.  At
       
  1028 		     * least this can't happen inside braces or brackets.  We
       
  1029 		     * only allow this with SHGLOB (set for both sh and ksh).
       
  1030 		     *
       
  1031 		     * Things like `print @( |foo)' should still
       
  1032 		     * work, because [k]sh don't allow multiple words
       
  1033 		     * in a function definition, so we only do this
       
  1034 		     * in command position.
       
  1035 		     *   pws 1999/6/14
       
  1036 		     */
       
  1037 		    if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct &&
       
  1038 				     !brct && !intpos && incmdpos))
       
  1039 			goto brk;
       
  1040 		}
       
  1041 		/*
       
  1042 		 * This also handles the [k]sh `foo( )' function definition.
       
  1043 		 * Maintain a variable fdpar, set as long as a single set of
       
  1044 		 * parentheses contains only space.  Then if we get to the
       
  1045 		 * closing parenthesis and it is still set, we can assume we
       
  1046 		 * have a function definition.  Only do this at the start of
       
  1047 		 * the word, since the (...) must be a separate token.
       
  1048 		 */
       
  1049 		if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct)
       
  1050 		    fdpar = 1;
       
  1051 	    }
       
  1052 	    c = Inpar;
       
  1053 	    break;
       
  1054 	case LX2_INBRACE:
       
  1055 	    if (isset(IGNOREBRACES) || sub)
       
  1056 		c = '{';
       
  1057 	    else {
       
  1058 		if (!len && incmdpos) {
       
  1059 		    add('{');
       
  1060 		    *bptr = '\0';
       
  1061 		    return STRING;
       
  1062 		}
       
  1063 		if (in_brace_param) {
       
  1064 		    cmdpush(CS_BRACE);
       
  1065 		}
       
  1066 		bct++;
       
  1067 	    }
       
  1068 	    break;
       
  1069 	case LX2_OUTBRACE:
       
  1070 	    if ((isset(IGNOREBRACES) || sub) && !in_brace_param)
       
  1071 		break;
       
  1072 	    if (!bct)
       
  1073 		break;
       
  1074 	    if (in_brace_param) {
       
  1075 		cmdpop();
       
  1076 	    }
       
  1077 	    if (bct-- == in_brace_param)
       
  1078 		in_brace_param = 0;
       
  1079 	    c = Outbrace;
       
  1080 	    break;
       
  1081 	case LX2_COMMA:
       
  1082 	    if (unset(IGNOREBRACES) && !sub && bct > in_brace_param)
       
  1083 		c = Comma;
       
  1084 	    break;
       
  1085 	case LX2_OUTANG:
       
  1086 	    if (!intpos) {
       
  1087 		if (in_brace_param || sub)
       
  1088 		    break;
       
  1089 		else
       
  1090 		    goto brk;
       
  1091 	    }
       
  1092 	    e = hgetc();
       
  1093 	    if (e != '(') {
       
  1094 		hungetc(e);
       
  1095 		lexstop = 0;
       
  1096 		goto brk;
       
  1097 	    }
       
  1098 	    add(Outang);
       
  1099 	    if (skipcomm()) {
       
  1100 		peek = LEXERR;
       
  1101 		goto brk;
       
  1102 	    }
       
  1103 	    c = Outpar;
       
  1104 	    break;
       
  1105 	case LX2_INANG:
       
  1106 	    if (isset(SHGLOB) && sub)
       
  1107 		break;
       
  1108 	    e = hgetc();
       
  1109 	    if(e == '(' && intpos) {
       
  1110 		add(Inang);
       
  1111 		if (skipcomm()) {
       
  1112 		    peek = LEXERR;
       
  1113 		    goto brk;
       
  1114 		}
       
  1115 		c = Outpar;
       
  1116 		break;
       
  1117 	    }
       
  1118 	    hungetc(e);
       
  1119 	    if(isnumglob()) {
       
  1120 		add(Inang);
       
  1121 		while ((c = hgetc()) != '>')
       
  1122 		    add(c);
       
  1123 		c = Outang;
       
  1124 		break;
       
  1125 	    }
       
  1126 	    lexstop = 0;
       
  1127 	    if (in_brace_param || sub)
       
  1128 		break;
       
  1129 	    goto brk;
       
  1130 	case LX2_EQUALS:
       
  1131 	    if (intpos) {
       
  1132 		e = hgetc();
       
  1133 		if (e != '(') {
       
  1134 		    hungetc(e);
       
  1135 		    lexstop = 0;
       
  1136 		    c = Equals;
       
  1137 		} else {
       
  1138 		    add(Equals);
       
  1139 		    if (skipcomm()) {
       
  1140 			peek = LEXERR;
       
  1141 			goto brk;
       
  1142 		    }
       
  1143 		    c = Outpar;
       
  1144 		}
       
  1145 	    } else if (!sub && peek != ENVSTRING &&
       
  1146 		       incmdpos && !bct && !brct) {
       
  1147 		char *t = tokstr;
       
  1148 		if (idigit(*t))
       
  1149 		    while (++t < bptr && idigit(*t));
       
  1150 		else {
       
  1151 		    while (iident(*t) && ++t < bptr);
       
  1152 		    if (t < bptr) {
       
  1153 			*bptr = '\0';
       
  1154 			skipparens(Inbrack, Outbrack, &t);
       
  1155 		    }
       
  1156 		}
       
  1157 		if (*t == '+')
       
  1158                     t++;
       
  1159 		if (t == bptr) {
       
  1160 		    e = hgetc();
       
  1161 		    if (e == '(' && incmdpos) {
       
  1162 			*bptr = '\0';
       
  1163 			return ENVARRAY;
       
  1164 		    }
       
  1165 		    hungetc(e);
       
  1166 		    lexstop = 0;
       
  1167 		    peek = ENVSTRING;
       
  1168 		    intpos = 2;
       
  1169 		} else
       
  1170 		    c = Equals;
       
  1171 	    } else
       
  1172 		c = Equals;
       
  1173 	    break;
       
  1174 #ifndef __SYMBIAN32__	    
       
  1175 	case LX2_BKSLASH:
       
  1176 	    c = hgetc();
       
  1177 	    if (c == '\n') {
       
  1178 		c = hgetc();
       
  1179 		if (!lexstop)
       
  1180 		    continue;
       
  1181 	    } else
       
  1182 		add(Bnull);
       
  1183 	    if (lexstop)
       
  1184 		goto brk;
       
  1185 	    break;
       
  1186 #endif	    
       
  1187 	case LX2_QUOTE: {
       
  1188 	    int strquote = (len && bptr[-1] == String);
       
  1189 
       
  1190 	    add(Snull);
       
  1191 	    cmdpush(CS_QUOTE);
       
  1192 	    for (;;) {
       
  1193 		STOPHIST
       
  1194 		while ((c = hgetc()) != '\'' && !lexstop) {
       
  1195 		    if (strquote && c == '\\') {
       
  1196 			add(c);
       
  1197 			c = hgetc();
       
  1198 			if (lexstop)
       
  1199 			    break;
       
  1200 		    } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
       
  1201 			if (bptr[-1] == '\\')
       
  1202 			    bptr--, len--;
       
  1203 			else
       
  1204 			    break;
       
  1205 		    }
       
  1206 		    add(c);
       
  1207 		}
       
  1208 		ALLOWHIST
       
  1209 		if (c != '\'') {
       
  1210 		    unmatched = '\'';
       
  1211 		    peek = LEXERR;
       
  1212 		    cmdpop();
       
  1213 		    goto brk;
       
  1214 		}
       
  1215 		e = hgetc();
       
  1216 		if (e != '\'' || unset(RCQUOTES) || strquote)
       
  1217 		    break;
       
  1218 		add(c);
       
  1219 	    }
       
  1220 	    cmdpop();
       
  1221 	    hungetc(e);
       
  1222 	    lexstop = 0;
       
  1223 	    c = Snull;
       
  1224 	    break;
       
  1225 	}
       
  1226 	case LX2_DQUOTE:
       
  1227 	    add(Dnull);
       
  1228 	    cmdpush(CS_DQUOTE);
       
  1229 	    c = dquote_parse('"', sub);
       
  1230 	    cmdpop();
       
  1231 	    if (c) {
       
  1232 		unmatched = '"';
       
  1233 		peek = LEXERR;
       
  1234 		goto brk;
       
  1235 	    }
       
  1236 	    c = Dnull;
       
  1237 	    break;
       
  1238 	case LX2_BQUOTE:
       
  1239 	    add(Tick);
       
  1240 	    cmdpush(CS_BQUOTE);
       
  1241 	    SETPARBEGIN
       
  1242 	    inquote = 0;
       
  1243 	    while ((c = hgetc()) != '`' && !lexstop) {
       
  1244 		if (c == '\\') {
       
  1245 		    c = hgetc();
       
  1246 		    if (c != '\n') {
       
  1247 			add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\');
       
  1248 			add(c);
       
  1249 		    }
       
  1250 		    else if (!sub && isset(CSHJUNKIEQUOTES))
       
  1251 			add(c);
       
  1252 		} else {
       
  1253 		    if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') {
       
  1254 			break;
       
  1255 		    }
       
  1256 		    add(c);
       
  1257 		    if (c == '\'') {
       
  1258 			if ((inquote = !inquote))
       
  1259 			    STOPHIST
       
  1260 			else
       
  1261 			    ALLOWHIST
       
  1262 		    }
       
  1263 		}
       
  1264 	    }
       
  1265 	    if (inquote)
       
  1266 		ALLOWHIST
       
  1267 	    cmdpop();
       
  1268 	    if (c != '`') {
       
  1269 		unmatched = '`';
       
  1270 		peek = LEXERR;
       
  1271 		goto brk;
       
  1272 	    }
       
  1273 	    c = Tick;
       
  1274 	    SETPAREND
       
  1275 	    break;
       
  1276 	}
       
  1277 	#ifdef __SYMBIAN32__	
       
  1278 	if(c=='\\') 
       
  1279 		{
       
  1280 	    c = hgetc();
       
  1281 	    if (c != '\n') {
       
  1282 		if (c == endchar)
       
  1283 		    add(Bnull);
       
  1284 		else {
       
  1285 		    /* lexstop is implicitly handled here */
       
  1286 		    add('\\');
       
  1287 		    
       
  1288 		}
       
  1289 	    } 
       
  1290 	}
       
  1291 	#endif
       
  1292 	add(c);
       
  1293 	c = hgetc();
       
  1294 	if (intpos)
       
  1295 	    intpos--;
       
  1296 	if (lexstop)
       
  1297 	    break;
       
  1298     }
       
  1299   brk:
       
  1300     hungetc(c);
       
  1301     if (unmatched)
       
  1302 	zerr("unmatched %c", NULL, unmatched);
       
  1303     if (in_brace_param) {
       
  1304 	while(bct-- >= in_brace_param)
       
  1305 	    cmdpop();
       
  1306 	zerr("closing brace expected", NULL, 0);
       
  1307     } else if (unset(IGNOREBRACES) && !sub && len > 1 &&
       
  1308 	       peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) {
       
  1309 	/* hack to get {foo} command syntax work */
       
  1310 	bptr--;
       
  1311 	len--;
       
  1312 	lexstop = 0;
       
  1313 	hungetc('}');
       
  1314     }
       
  1315     *bptr = '\0';
       
  1316     DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed.");
       
  1317     return peek;
       
  1318 }
       
  1319 
       
  1320 /**/
       
  1321 static int
       
  1322 dquote_parse(char endchar, int sub)
       
  1323 {
       
  1324     int pct = 0, brct = 0, bct = 0, intick = 0, err = 0;
       
  1325     int c;
       
  1326     int math = endchar == ')' || endchar == ']';
       
  1327     int zlemath = math && cs > ll + addedx - inbufct;
       
  1328 
       
  1329     while (((c = hgetc()) != endchar || bct ||
       
  1330 	    (math && ((pct > 0) || (brct > 0))) ||
       
  1331 	    intick) && !lexstop) {
       
  1332       cont:
       
  1333 	switch (c) {
       
  1334 	case '\\':
       
  1335 	    c = hgetc();
       
  1336 	    if (c != '\n') {
       
  1337 		if (c == '$' || c == '\\' || (c == '}' && !intick && bct) ||
       
  1338 		    c == endchar || c == '`' ||
       
  1339 		    (endchar == ']' && (c == '[' || c == ']' ||
       
  1340 					c == '(' || c == ')' ||
       
  1341 					c == '{' || c == '}' ||
       
  1342 					(c == '"' && sub))))
       
  1343 		    add(Bnull);
       
  1344 		else {
       
  1345 		    /* lexstop is implicitly handled here */
       
  1346 		    add('\\');
       
  1347 		    goto cont;
       
  1348 		}
       
  1349 	    } else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"')
       
  1350 		continue;
       
  1351 	    break;
       
  1352 	case '\n':
       
  1353 	    err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"';
       
  1354 	    break;
       
  1355 	case '$':
       
  1356 	    if (intick)
       
  1357 		break;
       
  1358 	    c = hgetc();
       
  1359 	    if (c == '(') {
       
  1360 		add(Qstring);
       
  1361 		err = cmd_or_math_sub();
       
  1362 		c = Outpar;
       
  1363 	    } else if (c == '[') {
       
  1364 		add(String);
       
  1365 		add(Inbrack);
       
  1366 		cmdpush(CS_MATHSUBST);
       
  1367 		err = dquote_parse(']', sub);
       
  1368 		cmdpop();
       
  1369 		c = Outbrack;
       
  1370 	    } else if (c == '{') {
       
  1371 		add(Qstring);
       
  1372 		c = Inbrace;
       
  1373 		cmdpush(CS_BRACEPAR);
       
  1374 		bct++;
       
  1375 	    } else if (c == '$')
       
  1376 		add(Qstring);
       
  1377 	    else {
       
  1378 		hungetc(c);
       
  1379 		lexstop = 0;
       
  1380 		c = Qstring;
       
  1381 	    }
       
  1382 	    break;
       
  1383 	case '}':
       
  1384 	    if (intick || !bct)
       
  1385 		break;
       
  1386 	    c = Outbrace;
       
  1387 	    bct--;
       
  1388 	    cmdpop();
       
  1389 	    break;
       
  1390 	case '`':
       
  1391 	    c = Qtick;
       
  1392 	    if (intick == 2)
       
  1393 		ALLOWHIST
       
  1394 	    if ((intick = !intick)) {
       
  1395 		SETPARBEGIN
       
  1396 		cmdpush(CS_BQUOTE);
       
  1397 	    } else {
       
  1398 		SETPAREND
       
  1399 	        cmdpop();
       
  1400 	    }
       
  1401 	    break;
       
  1402 	case '\'':
       
  1403 	    if (!intick)
       
  1404 		break;
       
  1405 	    if (intick == 1)
       
  1406 		intick = 2, STOPHIST
       
  1407 	    else
       
  1408 		intick = 1, ALLOWHIST
       
  1409 	    break;
       
  1410 	case '(':
       
  1411 	    if (!math || !bct)
       
  1412 		pct++;
       
  1413 	    break;
       
  1414 	case ')':
       
  1415 	    if (!math || !bct)
       
  1416 		err = (!pct-- && math);
       
  1417 	    break;
       
  1418 	case '[':
       
  1419 	    if (!math || !bct)
       
  1420 		brct++;
       
  1421 	    break;
       
  1422 	case ']':
       
  1423 	    if (!math || !bct)
       
  1424 		err = (!brct-- && math);
       
  1425 	    break;
       
  1426 	case '"':
       
  1427 	    if (intick || ((endchar == ']' || !endchar) && !bct))
       
  1428 		break;
       
  1429 	    if (bct) {
       
  1430 		add(Dnull);
       
  1431 		cmdpush(CS_DQUOTE);
       
  1432 		err = dquote_parse('"', sub);
       
  1433 		cmdpop();
       
  1434 		c = Dnull;
       
  1435 	    } else
       
  1436 		err = 1;
       
  1437 	    break;
       
  1438 	}
       
  1439 	if (err || lexstop)
       
  1440 	    break;
       
  1441 	add(c);
       
  1442     }
       
  1443     if (intick == 2)
       
  1444 	ALLOWHIST
       
  1445     if (intick) {
       
  1446 	cmdpop();
       
  1447     }
       
  1448     while (bct--)
       
  1449 	cmdpop();
       
  1450     if (lexstop)
       
  1451 	err = intick || endchar || err;
       
  1452     else if (err == 1)
       
  1453 	err = c;
       
  1454     if (zlemath && cs <= ll + 1 - inbufct)
       
  1455 	inwhat = IN_MATH;
       
  1456     return err;
       
  1457 }
       
  1458 
       
  1459 /* Tokenize a string given in s. Parsing is done as in double *
       
  1460  * quotes.  This is usually called before singsub().          */
       
  1461 
       
  1462 /**/
       
  1463 mod_export int
       
  1464 parsestr(char *s)
       
  1465 {
       
  1466     int err;
       
  1467 
       
  1468     if ((err = parsestrnoerr(s))) {
       
  1469 	untokenize(s);
       
  1470 	if (err > 32 && err < 127)
       
  1471 	    zerr("parse error near `%c'", NULL, err);
       
  1472 	else
       
  1473 	    zerr("parse error", NULL, 0);
       
  1474     }
       
  1475     return err;
       
  1476 }
       
  1477 
       
  1478 /**/
       
  1479 mod_export int
       
  1480 parsestrnoerr(char *s)
       
  1481 {
       
  1482     int l = strlen(s), err;
       
  1483 
       
  1484     lexsave();
       
  1485     untokenize(s);
       
  1486     inpush(dupstring(s), 0, NULL);
       
  1487     strinbeg(0);
       
  1488     len = 0;
       
  1489     bptr = tokstr = s;
       
  1490     bsiz = l + 1;
       
  1491     err = dquote_parse('\0', 1);
       
  1492     *bptr = '\0';
       
  1493     strinend();
       
  1494     inpop();
       
  1495     DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
       
  1496     lexrestore();
       
  1497     return err;
       
  1498 }
       
  1499 
       
  1500 /**/
       
  1501 mod_export char *
       
  1502 parse_subscript(char *s, int sub)
       
  1503 {
       
  1504     int l = strlen(s), err;
       
  1505     char *t;
       
  1506 
       
  1507     if (!*s || *s == ']')
       
  1508 	return 0;
       
  1509     lexsave();
       
  1510     untokenize(t = dupstring(s));
       
  1511     inpush(t, 0, NULL);
       
  1512     strinbeg(0);
       
  1513     len = 0;
       
  1514     bptr = tokstr = s;
       
  1515     bsiz = l + 1;
       
  1516     err = dquote_parse(']', sub);
       
  1517     if (err) {
       
  1518 	err = *bptr;
       
  1519 	*bptr = 0;
       
  1520 	untokenize(s);
       
  1521 	*bptr = err;
       
  1522 	s = 0;
       
  1523     } else
       
  1524 	s = bptr;
       
  1525     strinend();
       
  1526     inpop();
       
  1527     DPUTS(cmdsp, "BUG: parse_subscript: cmdstack not empty.");
       
  1528     lexrestore();
       
  1529     return s;
       
  1530 }
       
  1531 
       
  1532 /* Tokenize a string given in s. Parsing is done as if s were a normal *
       
  1533  * command-line argument but it may contain separators.  This is used  *
       
  1534  * to parse the right-hand side of ${...%...} substitutions.           */
       
  1535 
       
  1536 /**/
       
  1537 mod_export int
       
  1538 parse_subst_string(char *s)
       
  1539 {
       
  1540     int c, l = strlen(s), err, olen, lexstop_ret;
       
  1541 
       
  1542     if (!*s || !strcmp(s, nulstring))
       
  1543 	return 0;
       
  1544     lexsave();
       
  1545     untokenize(s);
       
  1546     inpush(dupstring(s), 0, NULL);
       
  1547     strinbeg(0);
       
  1548     len = 0;
       
  1549     bptr = tokstr = s;
       
  1550     bsiz = l + 1;
       
  1551     c = hgetc();
       
  1552     lexstop_ret = lexstop;
       
  1553     c = gettokstr(c, 1);
       
  1554     err = errflag;
       
  1555     strinend();
       
  1556     inpop();
       
  1557     DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty.");
       
  1558     olen = len;
       
  1559     lexrestore();
       
  1560     errflag = err;
       
  1561     if (c == LEXERR) {
       
  1562 	untokenize(s);
       
  1563 	return 1;
       
  1564     }
       
  1565 #ifdef DEBUG
       
  1566     if (c != STRING || olen != l || errflag) {
       
  1567 	fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n",
       
  1568 		olen < l ? "len < l" : errflag ? "errflag" : "c != STRING");
       
  1569 	fflush(stderr);
       
  1570 	untokenize(s);
       
  1571 	return 1;
       
  1572     }
       
  1573 #endif
       
  1574     return 0;
       
  1575 }
       
  1576 
       
  1577 /* Called below to report word positions. */
       
  1578 
       
  1579 /**/
       
  1580 mod_export void
       
  1581 gotword(void)
       
  1582 {
       
  1583     we = ll + 1 - inbufct + (addedx == 2 ? 1 : 0);
       
  1584     if (cs <= we) {
       
  1585 	wb = ll - wordbeg + addedx;
       
  1586 	zleparse = 0;
       
  1587     }
       
  1588 }
       
  1589 
       
  1590 /* expand aliases and reserved words */
       
  1591 
       
  1592 /**/
       
  1593 int
       
  1594 exalias(void)
       
  1595 {
       
  1596     Alias an;
       
  1597     Reswd rw;
       
  1598 
       
  1599     hwend();
       
  1600     if (interact && isset(SHINSTDIN) && !strin && !incasepat &&
       
  1601 	tok == STRING && !nocorrect && !(inbufflags & INP_ALIAS) &&
       
  1602 	(isset(CORRECTALL) || (isset(CORRECT) && incmdpos)))
       
  1603 	spckword(&tokstr, 1, incmdpos, 1);
       
  1604 
       
  1605     if (!tokstr) {
       
  1606 	yytext = tokstrings[tok];
       
  1607 
       
  1608 	return 0;
       
  1609     } else {
       
  1610 	VARARR(char, copy, (strlen(tokstr) + 1));
       
  1611 
       
  1612 	if (has_token(tokstr)) {
       
  1613 	    char *p, *t;
       
  1614 
       
  1615 	    yytext = p = copy;
       
  1616 	    for (t = tokstr;
       
  1617 		 (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
       
  1618 	} else
       
  1619 	    yytext = tokstr;
       
  1620 
       
  1621 	if (zleparse && !(inbufflags & INP_ALIAS)) {
       
  1622 	    int zp = zleparse;
       
  1623 
       
  1624 	    gotword();
       
  1625 	    if (zp == 1 && !zleparse) {
       
  1626 		if (yytext == copy)
       
  1627 		    yytext = tokstr;
       
  1628 		return 0;
       
  1629 	    }
       
  1630 	}
       
  1631 
       
  1632 	if (tok == STRING) {
       
  1633 	    /* Check for an alias */
       
  1634 	    if (!noaliases && isset(ALIASESOPT)) {
       
  1635 		char *suf;
       
  1636 		
       
  1637 		an = (Alias) aliastab->getnode(aliastab, yytext);
       
  1638 		if (an && !an->inuse &&
       
  1639 		    ((an->flags & ALIAS_GLOBAL) || incmdpos || inalmore)) {
       
  1640 		    inpush(an->text, INP_ALIAS, an);
       
  1641 		    if (an->text[0] == ' ')
       
  1642 			aliasspaceflag = 1;
       
  1643 		    lexstop = 0;
       
  1644 		    if (yytext == copy)
       
  1645 			yytext = tokstr;
       
  1646 		    return 1;
       
  1647 		}
       
  1648 		if ((suf = strrchr(yytext, '.')) && suf[1] &&
       
  1649 		    suf > yytext && suf[-1] != Meta &&
       
  1650 		    (an = (Alias)sufaliastab->getnode(sufaliastab, suf+1)) &&
       
  1651 		    !an->inuse && incmdpos) {
       
  1652 		    inpush(dupstring(yytext), INP_ALIAS, NULL);
       
  1653 		    inpush(" ", INP_ALIAS, NULL);
       
  1654 		    inpush(an->text, INP_ALIAS, an);
       
  1655 		    lexstop = 0;
       
  1656 		    if (yytext == copy)
       
  1657 			yytext = tokstr;
       
  1658 		    return 1;
       
  1659 		}
       
  1660 	    }
       
  1661 
       
  1662 	    /* Then check for a reserved word */
       
  1663 	    if ((incmdpos ||
       
  1664 		 (unset(IGNOREBRACES) && yytext[0] == '}' && !yytext[1])) &&
       
  1665 		(rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) {
       
  1666 		tok = rw->token;
       
  1667 		if (tok == DINBRACK)
       
  1668 		    incond = 1;
       
  1669 	    } else if (incond && !strcmp(yytext, "]]")) {
       
  1670 		tok = DOUTBRACK;
       
  1671 		incond = 0;
       
  1672 	    } else if (incond == 1 && yytext[0] == '!' && !yytext[1])
       
  1673 		tok = BANG;
       
  1674 	}
       
  1675 	inalmore = 0;
       
  1676 	if (yytext == copy)
       
  1677 	    yytext = tokstr;
       
  1678     }
       
  1679     return 0;
       
  1680 }
       
  1681 
       
  1682 /* skip (...) */
       
  1683 
       
  1684 /**/
       
  1685 static int
       
  1686 skipcomm(void)
       
  1687 {
       
  1688     int pct = 1, c;
       
  1689 
       
  1690     cmdpush(CS_CMDSUBST);
       
  1691     SETPARBEGIN
       
  1692     c = Inpar;
       
  1693     do {
       
  1694 	add(c);
       
  1695 	c = hgetc();
       
  1696 	if (itok(c) || lexstop)
       
  1697 	    break;
       
  1698 	switch (c) {
       
  1699 	case '(':
       
  1700 	    pct++;
       
  1701 	    break;
       
  1702 	case ')':
       
  1703 	    pct--;
       
  1704 	    break;
       
  1705 	case '\\':
       
  1706 	    add(c);
       
  1707 	    c = hgetc();
       
  1708 	    break;
       
  1709 	case '\'': {
       
  1710 	    int strquote = bptr[-1] == '$';
       
  1711 	    add(c);
       
  1712 	    STOPHIST
       
  1713 	    while ((c = hgetc()) != '\'' && !lexstop) {
       
  1714 		if (c == '\\' && strquote) {
       
  1715 		    add(c);
       
  1716 		    c = hgetc();
       
  1717 		}
       
  1718 		add(c);
       
  1719 	    }
       
  1720 	    ALLOWHIST
       
  1721 	    break;
       
  1722 	}
       
  1723 	case '\"':
       
  1724 	    add(c);
       
  1725 	    while ((c = hgetc()) != '\"' && !lexstop)
       
  1726 		if (c == '\\') {
       
  1727 		    add(c);
       
  1728 		    add(hgetc());
       
  1729 		} else
       
  1730 		    add(c);
       
  1731 	    break;
       
  1732 	case '`':
       
  1733 	    add(c);
       
  1734 	    while ((c = hgetc()) != '`' && !lexstop)
       
  1735 		if (c == '\\')
       
  1736 		    add(c), add(hgetc());
       
  1737 		else
       
  1738 		    add(c);
       
  1739 	    break;
       
  1740 	}
       
  1741     }
       
  1742     while (pct);
       
  1743     if (!lexstop)
       
  1744 	SETPAREND
       
  1745     cmdpop();
       
  1746     return lexstop;
       
  1747 }