openenvutils/commandshell/shell/src/parse.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // parse.c - parser
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. 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 "parse.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #ifdef __WINSCW__
       
    37 #pragma warn_possunwant off
       
    38 #endif//__WINSCW__
       
    39 #endif//__SYMBIAN32__
       
    40 
       
    41 /* != 0 if we are about to read a command word */
       
    42  
       
    43 /**/
       
    44 mod_export int incmdpos;
       
    45 
       
    46 /**/
       
    47 int aliasspaceflag;
       
    48 
       
    49 /* != 0 if we are in the middle of a [[ ... ]] */
       
    50  
       
    51 /**/
       
    52 mod_export int incond;
       
    53  
       
    54 /* != 0 if we are after a redirection (for ctxtlex only) */
       
    55  
       
    56 /**/
       
    57 mod_export int inredir;
       
    58  
       
    59 /* != 0 if we are about to read a case pattern */
       
    60  
       
    61 /**/
       
    62 int incasepat;
       
    63  
       
    64 /* != 0 if we just read a newline */
       
    65  
       
    66 /**/
       
    67 int isnewlin;
       
    68 
       
    69 /* != 0 if we are after a for keyword */
       
    70 
       
    71 /**/
       
    72 int infor;
       
    73 
       
    74 /* list of here-documents */
       
    75 
       
    76 /**/
       
    77 struct heredocs *hdocs;
       
    78  
       
    79 
       
    80 #define YYERROR(O)  { tok = LEXERR; ecused = (O); return 0; }
       
    81 #define YYERRORV(O) { tok = LEXERR; ecused = (O); return; }
       
    82 #define COND_ERROR(X,Y) do { \
       
    83   zwarn(X,Y,0); \
       
    84   herrflush(); \
       
    85   if (noerrs != 2) \
       
    86     errflag = 1; \
       
    87   YYERROR(ecused) \
       
    88 } while(0)
       
    89 
       
    90 
       
    91 /* 
       
    92  * Word code.
       
    93  *
       
    94  * The parser now produces word code, reducing memory consumption compared
       
    95  * to the nested structs we had before.
       
    96  *
       
    97  * Word code layout:
       
    98  *
       
    99  *   WC_END
       
   100  *     - end of program code
       
   101  *
       
   102  *   WC_LIST
       
   103  *     - data contains type (sync, ...)
       
   104  *     - followed by code for this list
       
   105  *     - if not (type & Z_END), followed by next WC_LIST
       
   106  *
       
   107  *   WC_SUBLIST
       
   108  *     - data contains type (&&, ||, END) and flags (coprog, not)
       
   109  *     - followed by code for sublist
       
   110  *     - if not (type == END), followed by next WC_SUBLIST
       
   111  *
       
   112  *   WC_PIPE
       
   113  *     - data contains type (end, mid) and LINENO
       
   114  *     - if not (type == END), followed by offset to next WC_PIPE
       
   115  *     - followed by command
       
   116  *     - if not (type == END), followed by next WC_PIPE
       
   117  *
       
   118  *   WC_REDIR
       
   119  *     - must precede command-code (or WC_ASSIGN)
       
   120  *     - data contains type (<, >, ...)
       
   121  *     - followed by fd1 and name from struct redir
       
   122  *
       
   123  *   WC_ASSIGN
       
   124  *     - data contains type (scalar, array) and number of array-elements
       
   125  *     - followed by name and value
       
   126  *
       
   127  *   WC_SIMPLE
       
   128  *     - data contains the number of arguments (plus command)
       
   129  *     - followed by strings
       
   130  *
       
   131  *   WC_SUBSH
       
   132  *     - data unused
       
   133  *     - followed by list
       
   134  *
       
   135  *   WC_CURSH
       
   136  *     - data unused
       
   137  *     - followed by list
       
   138  *
       
   139  *   WC_TIMED
       
   140  *     - data contains type (followed by pipe or not)
       
   141  *     - if (type == PIPE), followed by pipe
       
   142  *
       
   143  *   WC_FUNCDEF
       
   144  *     - data contains offset to after body
       
   145  *     - followed by number of names
       
   146  *     - followed by names
       
   147  *     - followed by offset to first string
       
   148  *     - followed by length of string table
       
   149  *     - followed by number of patterns for body
       
   150  *     - followed by codes for body
       
   151  *     - followed by strings for body
       
   152  *
       
   153  *   WC_FOR
       
   154  *     - data contains type (list, ...) and offset to after body
       
   155  *     - if (type == COND), followed by init, cond, advance expressions
       
   156  *     - else if (type == PPARAM), followed by param name
       
   157  *     - else if (type == LIST), followed by param name, num strings, strings
       
   158  *     - followed by body
       
   159  *
       
   160  *   WC_SELECT
       
   161  *     - data contains type (list, ...) and offset to after body
       
   162  *     - if (type == PPARAM), followed by param name
       
   163  *     - else if (type == LIST), followed by param name, num strings, strings
       
   164  *     - followed by body
       
   165  *
       
   166  *   WC_WHILE
       
   167  *     - data contains type (while, until) and offset to after body
       
   168  *     - followed by condition
       
   169  *     - followed by body
       
   170  *
       
   171  *   WC_REPEAT
       
   172  *     - data contains offset to after body
       
   173  *     - followed by number-string
       
   174  *     - followed by body
       
   175  *
       
   176  *   WC_CASE
       
   177  *     - first CASE is always of type HEAD, data contains offset to esac
       
   178  *     - after that CASEs of type OR (;;) and AND (;&), data is offset to
       
   179  *       next case
       
   180  *     - each OR/AND case is followed by pattern, pattern-number, list
       
   181  *
       
   182  *   WC_IF
       
   183  *     - first IF is of type HEAD, data contains offset to fi
       
   184  *     - after that IFs of type IF, ELIF, ELSE, data is offset to next
       
   185  *     - each non-HEAD is followed by condition (only IF, ELIF) and body
       
   186  *
       
   187  *   WC_COND
       
   188  *     - data contains type
       
   189  *     - if (type == AND/OR), data contains offset to after this one,
       
   190  *       followed by two CONDs
       
   191  *     - else if (type == NOT), followed by COND
       
   192  *     - else if (type == MOD), followed by name and strings
       
   193  *     - else if (type == MODI), followed by name, left, right
       
   194  *     - else if (type == STR[N]EQ), followed by left, right, pattern-number
       
   195  *     - else if (has two args) followed by left, right
       
   196  *     - else followed by string
       
   197  *
       
   198  *   WC_ARITH
       
   199  *     - followed by string (there's only one)
       
   200  *
       
   201  *   WC_AUTOFN
       
   202  *     - only used by the autoload builtin
       
   203  *
       
   204  * Lists and sublists may also be simplified, indicated by the presence
       
   205  * of the Z_SIMPLE or WC_SUBLIST_SIMPLE flags. In this case they are only
       
   206  * followed by a slot containing the line number, not by a WC_SUBLIST or
       
   207  * WC_PIPE, respectively. The real advantage of simplified lists and
       
   208  * sublists is that they can be executed faster, see exec.c. In the
       
   209  * parser, the test if a list can be simplified is done quite simply
       
   210  * by passing a int* around which gets set to non-zero if the thing
       
   211  * just parsed is `complex', i.e. may need to be run by forking or 
       
   212  * some such.
       
   213  *
       
   214  * In each of the above, strings are encoded as one word code. For empty
       
   215  * strings this is the bit pattern 11x, the lowest bit is non-zero if the
       
   216  * string contains tokens and zero otherwise (this is true for the other
       
   217  * ways to encode strings, too). For short strings (one to three
       
   218  * characters), this is the marker 01x with the 24 bits above that
       
   219  * containing the characters. Longer strings are encoded as the offset
       
   220  * into the strs character array stored in the eprog struct shifted by
       
   221  * two and ored with the bit pattern 0x.
       
   222  * The ecstrcode() function that adds the code for a string uses a simple
       
   223  * binary tree of strings already added so that long strings are encoded
       
   224  * only once.
       
   225  *
       
   226  * Note also that in the eprog struct the pattern, code, and string
       
   227  * arrays all point to the same memory block.
       
   228  *
       
   229  *
       
   230  * To make things even faster in future versions, we could not only 
       
   231  * test if the strings contain tokens, but instead what kind of
       
   232  * expansions need to be done on strings. In the execution code we
       
   233  * could then use these flags for a specialized version of prefork()
       
   234  * to avoid a lot of string parsing and some more string duplication.
       
   235  */
       
   236 
       
   237 /**/
       
   238 int eclen, ecused, ecnpats;
       
   239 /**/
       
   240 Wordcode ecbuf;
       
   241 /**/
       
   242 Eccstr ecstrs;
       
   243 /**/
       
   244 int ecsoffs, ecssub, ecnfunc;
       
   245 
       
   246 #define EC_INIT_SIZE         256
       
   247 #define EC_DOUBLE_THRESHOLD  32768
       
   248 #define EC_INCREMENT         1024
       
   249 
       
   250 
       
   251 /* Adjust pointers in here-doc structs. */
       
   252 
       
   253 static void
       
   254 ecadjusthere(int p, int d)
       
   255 {
       
   256     struct heredocs *h;
       
   257 
       
   258     for (h = hdocs; h; h = h->next)
       
   259 	if (h->pc >= p)
       
   260 	    h->pc += d;
       
   261 }
       
   262 
       
   263 /* Insert n free code-slots at position p. */
       
   264 
       
   265 static void
       
   266 ecispace(int p, int n)
       
   267 {
       
   268     int m;
       
   269 
       
   270     if ((eclen - ecused) < n) {
       
   271 	int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT);
       
   272 
       
   273 	if (n > a) a = n;
       
   274 
       
   275 	ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode));
       
   276 	eclen += a;
       
   277     }
       
   278     if ((m = ecused - p) > 0)
       
   279 	memmove(ecbuf + p + n, ecbuf + p, m * sizeof(wordcode));
       
   280     ecused += n;
       
   281     ecadjusthere(p, n);
       
   282 }
       
   283 
       
   284 /* Add one wordcode. */
       
   285 
       
   286 static int
       
   287 ecadd(wordcode c)
       
   288 {
       
   289     if ((eclen - ecused) < 1) {
       
   290 	int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT);
       
   291 
       
   292 	ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode));
       
   293 	eclen += a;
       
   294     }
       
   295     ecbuf[ecused] = c;
       
   296     ecused++;
       
   297 
       
   298     return ecused - 1;
       
   299 }
       
   300 
       
   301 /* Delete a wordcode. */
       
   302 
       
   303 static void
       
   304 ecdel(int p)
       
   305 {
       
   306     int n = ecused - p - 1;
       
   307 
       
   308     if (n > 0)
       
   309 	memmove(ecbuf + p, ecbuf + p + 1, n * sizeof(wordcode));
       
   310     ecused--;
       
   311     ecadjusthere(p, -1);
       
   312 }
       
   313 
       
   314 /* Build the wordcode for a string. */
       
   315 
       
   316 static wordcode
       
   317 ecstrcode(char *s)
       
   318 {
       
   319     int l, t = has_token(s);
       
   320 
       
   321     if ((l = strlen(s) + 1) && l <= 4) {
       
   322 	wordcode c = (t ? 3 : 2);
       
   323 	switch (l) {
       
   324 	case 4: c |= ((wordcode) STOUC(s[2])) << 19;
       
   325 	case 3: c |= ((wordcode) STOUC(s[1])) << 11;
       
   326 	case 2: c |= ((wordcode) STOUC(s[0])) <<  3; break;
       
   327 	case 1: c = (t ? 7 : 6); break;
       
   328 	}
       
   329 	return c;
       
   330     } else {
       
   331 	Eccstr p, *pp;
       
   332 	int cmp;
       
   333 
       
   334 	for (pp = &ecstrs; (p = *pp); ) {
       
   335 	    if (!(cmp = p->nfunc - ecnfunc) && !(cmp = strcmp(p->str, s)))
       
   336 		return p->offs;
       
   337 	    pp = (cmp < 0 ? &(p->left) : &(p->right));
       
   338 	}
       
   339 	p = *pp = (Eccstr) zhalloc(sizeof(*p));
       
   340 	p->left = p->right = 0;
       
   341 	p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0);
       
   342 	p->aoffs = ecsoffs;
       
   343 	p->str = s;
       
   344 	p->nfunc = ecnfunc;
       
   345 	ecsoffs += l;
       
   346 
       
   347 	return p->offs;
       
   348     }
       
   349 }
       
   350 
       
   351 #define ecstr(S) ecadd(ecstrcode(S))
       
   352 
       
   353 #define par_save_list(C) \
       
   354     do { \
       
   355         int eu = ecused; \
       
   356         par_list(C); \
       
   357         if (eu == ecused) ecadd(WCB_END()); \
       
   358     } while (0)
       
   359 #define par_save_list1(C) \
       
   360     do { \
       
   361         int eu = ecused; \
       
   362         par_list1(C); \
       
   363         if (eu == ecused) ecadd(WCB_END()); \
       
   364     } while (0)
       
   365 
       
   366 
       
   367 /* Initialise wordcode buffer. */
       
   368 
       
   369 static void
       
   370 init_parse(void)
       
   371 {
       
   372     if (ecbuf) zfree(ecbuf, eclen);
       
   373 
       
   374     ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode));
       
   375     ecused = 0;
       
   376     ecstrs = NULL;
       
   377     ecsoffs = ecnpats = 0;
       
   378     ecssub = 0;
       
   379     ecnfunc = 0;
       
   380 }
       
   381 
       
   382 /* Build eprog. */
       
   383 
       
   384 static void
       
   385 copy_ecstr(Eccstr s, char *p)
       
   386 {
       
   387     while (s) {
       
   388 	memcpy(p + s->aoffs, s->str, strlen(s->str) + 1);
       
   389 	copy_ecstr(s->left, p);
       
   390 	s = s->right;
       
   391     }
       
   392 }
       
   393 
       
   394 static Eprog
       
   395 bld_eprog(void)
       
   396 {
       
   397     Eprog ret;
       
   398     int l;
       
   399 
       
   400     ecadd(WCB_END());
       
   401 
       
   402     ret = (Eprog) zhalloc(sizeof(*ret));
       
   403     ret->len = ((ecnpats * sizeof(Patprog)) +
       
   404 		(ecused * sizeof(wordcode)) +
       
   405 		ecsoffs);
       
   406     ret->npats = ecnpats;
       
   407     ret->nref = -1;		/* Eprog is on the heap */
       
   408     ret->pats = (Patprog *) zhalloc(ret->len);
       
   409     ret->prog = (Wordcode) (ret->pats + ecnpats);
       
   410     ret->strs = (char *) (ret->prog + ecused);
       
   411     ret->shf = NULL;
       
   412     ret->flags = EF_HEAP;
       
   413     ret->dump = NULL;
       
   414     for (l = 0; l < ecnpats; l++)
       
   415 	ret->pats[l] = dummy_patprog1;
       
   416     memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode));
       
   417     copy_ecstr(ecstrs, ret->strs);
       
   418 
       
   419     zfree(ecbuf, eclen);
       
   420     ecbuf = NULL;
       
   421 
       
   422     return ret;
       
   423 }
       
   424 
       
   425 /**/
       
   426 mod_export int
       
   427 empty_eprog(Eprog p)
       
   428 {
       
   429     return (!p || !p->prog || *p->prog == WCB_END());
       
   430 }
       
   431 
       
   432 static void
       
   433 clear_hdocs()
       
   434 {
       
   435     struct heredocs *p, *n;
       
   436 
       
   437     for (p = hdocs; p; p = n) {
       
   438         n = p->next;
       
   439         zfree(p, sizeof(struct heredocs));
       
   440     }
       
   441     hdocs = NULL;
       
   442 }
       
   443 
       
   444 /*
       
   445  * event	: ENDINPUT
       
   446  *			| SEPER
       
   447  *			| sublist [ SEPER | AMPER | AMPERBANG ]
       
   448  */
       
   449 
       
   450 /**/
       
   451 Eprog
       
   452 parse_event(void)
       
   453 {
       
   454     tok = ENDINPUT;
       
   455     incmdpos = 1;
       
   456     aliasspaceflag = 0;
       
   457     yylex();
       
   458     init_parse();
       
   459 
       
   460     if (!par_event()) {
       
   461         clear_hdocs();
       
   462         return NULL;
       
   463     }
       
   464     return bld_eprog();
       
   465 }
       
   466 
       
   467 /**/
       
   468 static int
       
   469 par_event(void)
       
   470 {
       
   471     int r = 0, p, c = 0;
       
   472 
       
   473     while (tok == SEPER) {
       
   474 	if (isnewlin > 0)
       
   475 	    return 0;
       
   476 	yylex();
       
   477     }
       
   478     if (tok == ENDINPUT)
       
   479 	return 0;
       
   480 
       
   481     p = ecadd(0);
       
   482 
       
   483     if (par_sublist(&c)) {
       
   484 	if (tok == ENDINPUT) {
       
   485 	    set_list_code(p, Z_SYNC, c);
       
   486 	    r = 1;
       
   487 	} else if (tok == SEPER) {
       
   488 	    set_list_code(p, Z_SYNC, c);
       
   489 	    if (isnewlin <= 0)
       
   490 		yylex();
       
   491 	    r = 1;
       
   492 	} else if (tok == AMPER) {
       
   493 	    set_list_code(p, Z_ASYNC, c);
       
   494 	    yylex();
       
   495 	    r = 1;
       
   496 	} else if (tok == AMPERBANG) {
       
   497 	    set_list_code(p, (Z_ASYNC | Z_DISOWN), c);
       
   498 	    yylex();
       
   499 	    r = 1;
       
   500 	}
       
   501     }
       
   502     if (!r) {
       
   503 	tok = LEXERR;
       
   504 	if (errflag) {
       
   505 	    yyerror(0);
       
   506 	    ecused--;
       
   507 	    return 0;
       
   508 	}
       
   509 	yyerror(1);
       
   510 	herrflush();
       
   511 	if (noerrs != 2)
       
   512 	    errflag = 1;
       
   513 	ecused--;
       
   514 	return 0;
       
   515     } else {
       
   516 	int oec = ecused;
       
   517 
       
   518 	if (!par_event()) {
       
   519 	    ecused = oec;
       
   520 	    ecbuf[p] |= wc_bdata(Z_END);
       
   521 	}
       
   522     }
       
   523     return 1;
       
   524 }
       
   525 
       
   526 /**/
       
   527 mod_export Eprog
       
   528 parse_list(void)
       
   529 {
       
   530     int c = 0;
       
   531 
       
   532     tok = ENDINPUT;
       
   533     incmdpos = 1;
       
   534     yylex();
       
   535     init_parse();
       
   536     par_list(&c);
       
   537     if (tok != ENDINPUT) {
       
   538         clear_hdocs();
       
   539 	tok = LEXERR;
       
   540 	yyerror(0);
       
   541 	return NULL;
       
   542     }
       
   543     return bld_eprog();
       
   544 }
       
   545 
       
   546 /**/
       
   547 mod_export Eprog
       
   548 parse_cond(void)
       
   549 {
       
   550     init_parse();
       
   551 
       
   552     if (!par_cond()) {
       
   553         clear_hdocs();
       
   554 	return NULL;
       
   555     }
       
   556     return bld_eprog();
       
   557 }
       
   558 
       
   559 /* This adds a list wordcode. The important bit about this is that it also
       
   560  * tries to optimise this to a Z_SIMPLE list code. */
       
   561 
       
   562 /**/
       
   563 static void
       
   564 set_list_code(int p, int type, int complex)
       
   565 {
       
   566     if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) &&
       
   567 	WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) {
       
   568 	int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE);
       
   569 	ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p);
       
   570 	ecdel(p + 1);
       
   571 	if (ispipe)
       
   572 	    ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]);
       
   573     } else
       
   574 	ecbuf[p] = WCB_LIST(type, 0);
       
   575 }
       
   576 
       
   577 /* The same for sublists. */
       
   578 
       
   579 /**/
       
   580 static void
       
   581 set_sublist_code(int p, int type, int flags, int skip, int complex)
       
   582 {
       
   583     if (complex)
       
   584 	ecbuf[p] = WCB_SUBLIST(type, flags, skip);
       
   585     else {
       
   586 	ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip);
       
   587 	ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]);
       
   588     }
       
   589 }
       
   590 
       
   591 /*
       
   592  * list	: { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ]
       
   593  */
       
   594 
       
   595 /**/
       
   596 static int
       
   597 par_list(int *complex)
       
   598 {
       
   599     int p, lp = -1, c;
       
   600 
       
   601  rec:
       
   602 
       
   603     while (tok == SEPER)
       
   604 	yylex();
       
   605 
       
   606     p = ecadd(0);
       
   607     c = 0;
       
   608 
       
   609     if (par_sublist(&c)) {
       
   610 	*complex |= c;
       
   611 	if (tok == SEPER || tok == AMPER || tok == AMPERBANG) {
       
   612 	    if (tok != SEPER)
       
   613 		*complex = 1;
       
   614 	    set_list_code(p, ((tok == SEPER) ? Z_SYNC :
       
   615 			      (tok == AMPER) ? Z_ASYNC :
       
   616 			      (Z_ASYNC | Z_DISOWN)), c);
       
   617 	    incmdpos = 1;
       
   618 	    do {
       
   619 		yylex();
       
   620 	    } while (tok == SEPER);
       
   621 	    lp = p;
       
   622 	    goto rec;
       
   623 	} else
       
   624 	    set_list_code(p, (Z_SYNC | Z_END), c);
       
   625 	return 1;
       
   626     } else {
       
   627 	ecused--;
       
   628 	if (lp >= 0) {
       
   629 	    ecbuf[lp] |= wc_bdata(Z_END);
       
   630 	    return 1;
       
   631 	}
       
   632 	return 0;
       
   633     }
       
   634 }
       
   635 
       
   636 /**/
       
   637 static int
       
   638 par_list1(int *complex)
       
   639 {
       
   640     int p = ecadd(0), c = 0;
       
   641 
       
   642     if (par_sublist(&c)) {
       
   643 	set_list_code(p, (Z_SYNC | Z_END), c);
       
   644 	*complex |= c;
       
   645 	return 1;
       
   646     } else {
       
   647 	ecused--;
       
   648 	return 0;
       
   649     }
       
   650 }
       
   651 
       
   652 /*
       
   653  * sublist	: sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ]
       
   654  */
       
   655 
       
   656 /**/
       
   657 static int
       
   658 par_sublist(int *complex)
       
   659 {
       
   660     int f, p, c = 0;
       
   661 
       
   662     p = ecadd(0);
       
   663 
       
   664     if ((f = par_sublist2(&c)) != -1) {
       
   665 	int e = ecused;
       
   666 
       
   667 	*complex |= c;
       
   668 	if (tok == DBAR || tok == DAMPER) {
       
   669 	    int qtok = tok, sl;
       
   670 
       
   671 	    cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND);
       
   672 	    yylex();
       
   673 	    while (tok == SEPER)
       
   674 		yylex();
       
   675 	    sl = par_sublist(complex);
       
   676 	    set_sublist_code(p, (sl ? (qtok == DBAR ?
       
   677 				       WC_SUBLIST_OR : WC_SUBLIST_AND) :
       
   678 				 WC_SUBLIST_END),
       
   679 			     f, (e - 1 - p), c);
       
   680 	    cmdpop();
       
   681 	} else
       
   682 	    set_sublist_code(p, WC_SUBLIST_END, f, (e - 1 - p), c);
       
   683 	return 1;
       
   684     } else {
       
   685 	ecused--;
       
   686 	return 0;
       
   687     }
       
   688 }
       
   689 
       
   690 /*
       
   691  * sublist2	: [ COPROC | BANG ] pline
       
   692  */
       
   693 
       
   694 /**/
       
   695 static int
       
   696 par_sublist2(int *complex)
       
   697 {
       
   698     int f = 0;
       
   699 
       
   700     if (tok == COPROC) {
       
   701 	*complex = 1;
       
   702 	f |= WC_SUBLIST_COPROC;
       
   703 	yylex();
       
   704     } else if (tok == BANG) {
       
   705 	*complex = 1;
       
   706 	f |= WC_SUBLIST_NOT;
       
   707 	yylex();
       
   708     }
       
   709     if (!par_pline(complex) && !f)
       
   710 	return -1;
       
   711 
       
   712     return f;
       
   713 }
       
   714 
       
   715 /*
       
   716  * pline	: cmd [ ( BAR | BARAMP ) { SEPER } pline ]
       
   717  */
       
   718 
       
   719 /**/
       
   720 static int
       
   721 par_pline(int *complex)
       
   722 {
       
   723     int p, line = lineno;
       
   724 
       
   725     p = ecadd(0);
       
   726 
       
   727     if (!par_cmd(complex)) {
       
   728 	ecused--;
       
   729 	return 0;
       
   730     }
       
   731     if (tok == BAR) {
       
   732 	*complex = 1;
       
   733 	cmdpush(CS_PIPE);
       
   734 	yylex();
       
   735 	while (tok == SEPER)
       
   736 	    yylex();
       
   737 	ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0));
       
   738 	ecispace(p + 1, 1);
       
   739 	ecbuf[p + 1] = ecused - 1 - p;
       
   740 	if (!par_pline(complex)) {
       
   741 	    tok = LEXERR;
       
   742 	}
       
   743 	cmdpop();
       
   744 	return 1;
       
   745     } else if (tok == BARAMP) {
       
   746 	int r;
       
   747 
       
   748 	for (r = p + 1; wc_code(ecbuf[r]) == WC_REDIR; r += 3);
       
   749 
       
   750 	ecispace(r, 3);
       
   751 	ecbuf[r] = WCB_REDIR(REDIR_MERGEOUT);
       
   752 	ecbuf[r + 1] = 2;
       
   753 	ecbuf[r + 2] = ecstrcode("1");
       
   754 
       
   755 	*complex = 1;
       
   756 	cmdpush(CS_ERRPIPE);
       
   757 	yylex();
       
   758 	while (tok == SEPER)
       
   759 	    yylex();
       
   760 	ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0));
       
   761 	ecispace(p + 1, 1);
       
   762 	ecbuf[p + 1] = ecused - 1 - p;
       
   763 	if (!par_pline(complex)) {
       
   764 	    tok = LEXERR;
       
   765 	}
       
   766 	cmdpop();
       
   767 	return 1;
       
   768     } else {
       
   769 	ecbuf[p] = WCB_PIPE(WC_PIPE_END, (line >= 0 ? line + 1 : 0));
       
   770 	return 1;
       
   771     }
       
   772 }
       
   773 
       
   774 /*
       
   775  * cmd	: { redir } ( for | case | if | while | repeat |
       
   776  *				subsh | funcdef | time | dinbrack | dinpar | simple ) { redir }
       
   777  */
       
   778 
       
   779 /**/
       
   780 static int
       
   781 par_cmd(int *complex)
       
   782 {
       
   783     int r, nr = 0;
       
   784 
       
   785     r = ecused;
       
   786 
       
   787     if (IS_REDIROP(tok)) {
       
   788 	*complex = 1;
       
   789 	while (IS_REDIROP(tok)) {
       
   790 	    nr++;
       
   791 	    par_redir(&r);
       
   792 	}
       
   793     }
       
   794     switch (tok) {
       
   795     case FOR:
       
   796 	cmdpush(CS_FOR);
       
   797 	par_for(complex);
       
   798 	cmdpop();
       
   799 	break;
       
   800     case FOREACH:
       
   801 	cmdpush(CS_FOREACH);
       
   802 	par_for(complex);
       
   803 	cmdpop();
       
   804 	break;
       
   805     case SELECT:
       
   806 	*complex = 1;
       
   807 	cmdpush(CS_SELECT);
       
   808 	par_for(complex);
       
   809 	cmdpop();
       
   810 	break;
       
   811     case CASE:
       
   812 	cmdpush(CS_CASE);
       
   813 	par_case(complex);
       
   814 	cmdpop();
       
   815 	break;
       
   816     case IF:
       
   817 	par_if(complex);
       
   818 	break;
       
   819     case WHILE:
       
   820 	cmdpush(CS_WHILE);
       
   821 	par_while(complex);
       
   822 	cmdpop();
       
   823 	break;
       
   824     case UNTIL:
       
   825 	cmdpush(CS_UNTIL);
       
   826 	par_while(complex);
       
   827 	cmdpop();
       
   828 	break;
       
   829     case REPEAT:
       
   830 	cmdpush(CS_REPEAT);
       
   831 	par_repeat(complex);
       
   832 	cmdpop();
       
   833 	break;
       
   834     case INPAR:
       
   835 	*complex = 1;
       
   836 	cmdpush(CS_SUBSH);
       
   837 	par_subsh(complex);
       
   838 	cmdpop();
       
   839 	break;
       
   840     case INBRACE:
       
   841 	cmdpush(CS_CURSH);
       
   842 	par_subsh(complex);
       
   843 	cmdpop();
       
   844 	break;
       
   845     case FUNC:
       
   846 	cmdpush(CS_FUNCDEF);
       
   847 	par_funcdef();
       
   848 	cmdpop();
       
   849 	break;
       
   850     case DINBRACK:
       
   851 	cmdpush(CS_COND);
       
   852 	par_dinbrack();
       
   853 	cmdpop();
       
   854 	break;
       
   855     case DINPAR:
       
   856 	ecadd(WCB_ARITH());
       
   857 	ecstr(tokstr);
       
   858 	yylex();
       
   859 	break;
       
   860     case TIME:
       
   861 	{
       
   862 	    static int inpartime = 0;
       
   863 
       
   864 	    if (!inpartime) {
       
   865 		*complex = 1;
       
   866 		inpartime = 1;
       
   867 		par_time();
       
   868 		inpartime = 0;
       
   869 		break;
       
   870 	    }
       
   871 	}
       
   872 	tok = STRING;
       
   873 	/* fall through */
       
   874     default:
       
   875 	{
       
   876 	    int sr;
       
   877 
       
   878 	    if (!(sr = par_simple(complex, nr))) {
       
   879 		if (!nr)
       
   880 		    return 0;
       
   881 	    } else {
       
   882 		/* Three codes per redirection. */
       
   883 		if (sr > 1) {
       
   884 		    *complex = 1;
       
   885 		    r += (sr - 1) * 3;
       
   886 		}
       
   887 	    }
       
   888 	}
       
   889 	break;
       
   890     }
       
   891     if (IS_REDIROP(tok)) {
       
   892 	*complex = 1;
       
   893 	while (IS_REDIROP(tok))
       
   894 	    par_redir(&r);
       
   895     }
       
   896     incmdpos = 1;
       
   897     incasepat = 0;
       
   898     incond = 0;
       
   899     return 1;
       
   900 }
       
   901 
       
   902 /*
       
   903  * for  : ( FOR DINPAR expr SEMI expr SEMI expr DOUTPAR |
       
   904  *    ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR ) )
       
   905  *	{ SEPER } ( DO list DONE | INBRACE list OUTBRACE | list ZEND | list1 )
       
   906  */
       
   907 
       
   908 /**/
       
   909 static void
       
   910 par_for(int *complex)
       
   911 {
       
   912     int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT);
       
   913     int type;
       
   914 
       
   915     p = ecadd(0);
       
   916 
       
   917     incmdpos = 0;
       
   918     infor = tok == FOR ? 2 : 0;
       
   919     yylex();
       
   920     if (tok == DINPAR) {
       
   921 	yylex();
       
   922 	if (tok != DINPAR)
       
   923 	    YYERRORV(oecused);
       
   924 	ecstr(tokstr);
       
   925 	yylex();
       
   926 	if (tok != DINPAR)
       
   927 	    YYERRORV(oecused);
       
   928 	ecstr(tokstr);
       
   929 	yylex();
       
   930 	if (tok != DOUTPAR)
       
   931 	    YYERRORV(oecused);
       
   932 	ecstr(tokstr);
       
   933 	infor = 0;
       
   934 	incmdpos = 1;
       
   935 	yylex();
       
   936 	type = WC_FOR_COND;
       
   937     } else {
       
   938 	int np = 0, n, posix_in, ona = noaliases, onc = nocorrect;
       
   939 	infor = 0;
       
   940 	if (tok != STRING || !isident(tokstr))
       
   941 	    YYERRORV(oecused);
       
   942 	if (!sel)
       
   943 	    np = ecadd(0);
       
   944 	n = 0;
       
   945 	incmdpos = 1;
       
   946 	noaliases = nocorrect = 1;
       
   947 	for (;;) {
       
   948 	    n++;
       
   949 	    ecstr(tokstr);
       
   950 	    yylex();
       
   951 	    if (tok != STRING || !strcmp(tokstr, "in") || sel)
       
   952 		break;
       
   953 	    if (!isident(tokstr) || errflag)
       
   954 	    {
       
   955 		noaliases = ona;
       
   956 		nocorrect = onc;
       
   957 		YYERRORV(oecused);
       
   958 	    }
       
   959 	}
       
   960 	noaliases = ona;
       
   961 	nocorrect = onc;
       
   962 	if (!sel)
       
   963 	    ecbuf[np] = n;
       
   964 	posix_in = isnewlin;
       
   965 	while (isnewlin)
       
   966 	    yylex();
       
   967         if (tok == STRING && !strcmp(tokstr, "in")) {
       
   968 	    incmdpos = 0;
       
   969 	    yylex();
       
   970 	    np = ecadd(0);
       
   971 	    n = par_wordlist();
       
   972 	    if (tok != SEPER)
       
   973 		YYERRORV(oecused);
       
   974 	    ecbuf[np] = n;
       
   975 	    type = (sel ? WC_SELECT_LIST : WC_FOR_LIST);
       
   976 	} else if (!posix_in && tok == INPAR) {
       
   977 	    incmdpos = 0;
       
   978 	    yylex();
       
   979 	    np = ecadd(0);
       
   980 	    n = par_nl_wordlist();
       
   981 	    if (tok != OUTPAR)
       
   982 		YYERRORV(oecused);
       
   983 	    ecbuf[np] = n;
       
   984 	    incmdpos = 1;
       
   985 	    yylex();
       
   986 	    type = (sel ? WC_SELECT_LIST : WC_FOR_LIST);
       
   987 	} else
       
   988 	    type = (sel ? WC_SELECT_PPARAM : WC_FOR_PPARAM);
       
   989     }
       
   990     incmdpos = 1;
       
   991     while (tok == SEPER)
       
   992 	yylex();
       
   993     if (tok == DOLOOP) {
       
   994 	yylex();
       
   995 	par_save_list(complex);
       
   996 	if (tok != DONE)
       
   997 	    YYERRORV(oecused);
       
   998 	yylex();
       
   999     } else if (tok == INBRACE) {
       
  1000 	yylex();
       
  1001 	par_save_list(complex);
       
  1002 	if (tok != OUTBRACE)
       
  1003 	    YYERRORV(oecused);
       
  1004 	yylex();
       
  1005     } else if (csh || isset(CSHJUNKIELOOPS)) {
       
  1006 	par_save_list(complex);
       
  1007 	if (tok != ZEND)
       
  1008 	    YYERRORV(oecused);
       
  1009 	yylex();
       
  1010     } else if (unset(SHORTLOOPS)) {
       
  1011 	YYERRORV(oecused);
       
  1012     } else
       
  1013 	par_save_list1(complex);
       
  1014 
       
  1015     ecbuf[p] = (sel ?
       
  1016 		WCB_SELECT(type, ecused - 1 - p) :
       
  1017 		WCB_FOR(type, ecused - 1 - p));
       
  1018 }
       
  1019 
       
  1020 /*
       
  1021  * case	: CASE STRING { SEPER } ( "in" | INBRACE )
       
  1022 				{ { SEPER } STRING { BAR STRING } OUTPAR
       
  1023 					list [ DSEMI | SEMIAMP ] }
       
  1024 				{ SEPER } ( "esac" | OUTBRACE )
       
  1025  */
       
  1026 
       
  1027 /**/
       
  1028 static void
       
  1029 par_case(int *complex)
       
  1030 {
       
  1031     int oecused = ecused, brflag, p, pp, n = 1, type;
       
  1032 
       
  1033     p = ecadd(0);
       
  1034 
       
  1035     incmdpos = 0;
       
  1036     yylex();
       
  1037     if (tok != STRING)
       
  1038 	YYERRORV(oecused);
       
  1039     ecstr(tokstr);
       
  1040 
       
  1041     incmdpos = 1;
       
  1042     yylex();
       
  1043     while (tok == SEPER)
       
  1044 	yylex();
       
  1045     if (!(tok == STRING && !strcmp(tokstr, "in")) && tok != INBRACE)
       
  1046 	YYERRORV(oecused);
       
  1047     brflag = (tok == INBRACE);
       
  1048     incasepat = 1;
       
  1049     incmdpos = 0;
       
  1050     yylex();
       
  1051 
       
  1052     for (;;) {
       
  1053 	char *str;
       
  1054 
       
  1055 	while (tok == SEPER)
       
  1056 	    yylex();
       
  1057 	if (tok == OUTBRACE)
       
  1058 	    break;
       
  1059 	if (tok == INPAR)
       
  1060 	    yylex();
       
  1061 	if (tok != STRING)
       
  1062 	    YYERRORV(oecused);
       
  1063 	if (!strcmp(tokstr, "esac"))
       
  1064 	    break;
       
  1065 	str = dupstring(tokstr);
       
  1066 	incasepat = 0;
       
  1067 	incmdpos = 1;
       
  1068 	type = WC_CASE_OR;
       
  1069 	for (;;) {
       
  1070 	    yylex();
       
  1071 	    if (tok == OUTPAR) {
       
  1072 		incasepat = 0;
       
  1073 		incmdpos = 1;
       
  1074 		yylex();
       
  1075 		break;
       
  1076 	    } else if (tok == BAR) {
       
  1077 		char *str2;
       
  1078 		int sl = strlen(str);
       
  1079 
       
  1080 		incasepat = 1;
       
  1081 		incmdpos = 0;
       
  1082 		str2 = hcalloc(sl + 2);
       
  1083 		strcpy(str2, str);
       
  1084 		str2[sl] = Bar;
       
  1085 		str2[sl+1] = '\0';
       
  1086 		str = str2;
       
  1087 	    } else {
       
  1088 		int sl = strlen(str);
       
  1089 
       
  1090 		if (!sl || str[sl - 1] != Bar) {
       
  1091 		    /* POSIX allows (foo*) patterns */
       
  1092 		    int pct;
       
  1093 		    char *s;
       
  1094 
       
  1095 		    for (s = str, pct = 0; *s; s++) {
       
  1096 			if (*s == Inpar)
       
  1097 			    pct++;
       
  1098 			if (!pct)
       
  1099 			    break;
       
  1100 			if (pct == 1) {
       
  1101 			    if (*s == Bar || *s == Inpar)
       
  1102 				while (iblank(s[1]))
       
  1103 				    chuck(s+1);
       
  1104 			    if (*s == Bar || *s == Outpar)
       
  1105 				while (iblank(s[-1]) &&
       
  1106 				       (s < str + 1 || s[-2] != Meta))
       
  1107 				    chuck(--s);
       
  1108 			}
       
  1109 			if (*s == Outpar)
       
  1110 			    pct--;
       
  1111 		    }
       
  1112 		    if (*s || pct || s == str)
       
  1113 			YYERRORV(oecused);
       
  1114 		    /* Simplify pattern by removing surrounding (...) */
       
  1115 		    sl = strlen(str);
       
  1116 		    DPUTS(*str != Inpar || str[sl - 1] != Outpar,
       
  1117 			  "BUG: strange case pattern");
       
  1118 		    str[sl - 1] = '\0';
       
  1119 		    chuck(str);
       
  1120 		    break;
       
  1121 		} else {
       
  1122 		    char *str2;
       
  1123 
       
  1124 		    if (tok != STRING)
       
  1125 			YYERRORV(oecused);
       
  1126 		    str2 = hcalloc(sl + strlen(tokstr) + 1);
       
  1127 		    strcpy(str2, str);
       
  1128 		    strcpy(str2 + sl, tokstr);
       
  1129 		    str = str2;
       
  1130 		}
       
  1131 	    }
       
  1132 	}
       
  1133 	pp = ecadd(0);
       
  1134 	ecstr(str);
       
  1135 	ecadd(ecnpats++);
       
  1136 	par_save_list(complex);
       
  1137 	n++;
       
  1138 	if (tok == SEMIAMP)
       
  1139 	    type = WC_CASE_AND;
       
  1140 	ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
       
  1141 	if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
       
  1142 	    break;
       
  1143 	if (tok != DSEMI && tok != SEMIAMP)
       
  1144 	    YYERRORV(oecused);
       
  1145 	incasepat = 1;
       
  1146 	incmdpos = 0;
       
  1147 	yylex();
       
  1148     }
       
  1149     incmdpos = 1;
       
  1150     yylex();
       
  1151 
       
  1152     ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p);
       
  1153 }
       
  1154 
       
  1155 /*
       
  1156  * if	: { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list )
       
  1157 			{ SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) }
       
  1158 			[ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ]
       
  1159 			(you get the idea...?)
       
  1160  */
       
  1161 
       
  1162 /**/
       
  1163 static void
       
  1164 par_if(int *complex)
       
  1165 {
       
  1166     int oecused = ecused, xtok, p, pp, type, usebrace = 0;
       
  1167     unsigned char nc;
       
  1168 
       
  1169     p = ecadd(0);
       
  1170 
       
  1171     for (;;) {
       
  1172 	xtok = tok;
       
  1173 	cmdpush(xtok == IF ? CS_IF : CS_ELIF);
       
  1174 	yylex();
       
  1175 	if (xtok == FI)
       
  1176 	    break;
       
  1177 	if (xtok == ELSE)
       
  1178 	    break;
       
  1179 	while (tok == SEPER)
       
  1180 	    yylex();
       
  1181 	if (!(xtok == IF || xtok == ELIF)) {
       
  1182 	    cmdpop();
       
  1183 	    YYERRORV(oecused);
       
  1184 	}
       
  1185 	pp = ecadd(0);
       
  1186 	type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF);
       
  1187 	par_save_list(complex);
       
  1188 	incmdpos = 1;
       
  1189 	while (tok == SEPER)
       
  1190 	    yylex();
       
  1191 	xtok = FI;
       
  1192 	nc = cmdstack[cmdsp - 1] == CS_IF ? CS_IFTHEN : CS_ELIFTHEN;
       
  1193 	if (tok == THEN) {
       
  1194 	    usebrace = 0;
       
  1195 	    cmdpop();
       
  1196 	    cmdpush(nc);
       
  1197 	    yylex();
       
  1198 	    par_save_list(complex);
       
  1199 	    ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
       
  1200 	    incmdpos = 1;
       
  1201 	    cmdpop();
       
  1202 	} else if (tok == INBRACE) {
       
  1203 	    usebrace = 1;
       
  1204 	    cmdpop();
       
  1205 	    cmdpush(nc);
       
  1206 	    yylex();
       
  1207 	    par_save_list(complex);
       
  1208 	    if (tok != OUTBRACE) {
       
  1209 		cmdpop();
       
  1210 		YYERRORV(oecused);
       
  1211 	    }
       
  1212 	    ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
       
  1213 	    yylex();
       
  1214 	    incmdpos = 1;
       
  1215 	    if (tok == SEPER)
       
  1216 		break;
       
  1217 	    cmdpop();
       
  1218 	} else if (unset(SHORTLOOPS)) {
       
  1219 	    cmdpop();
       
  1220 	    YYERRORV(oecused);
       
  1221 	} else {
       
  1222 	    cmdpop();
       
  1223 	    cmdpush(nc);
       
  1224 	    par_save_list1(complex);
       
  1225 	    ecbuf[pp] = WCB_IF(type, ecused - 1 - pp);
       
  1226 	    incmdpos = 1;
       
  1227 	    break;
       
  1228 	}
       
  1229     }
       
  1230     cmdpop();
       
  1231     if (xtok == ELSE) {
       
  1232 	pp = ecadd(0);
       
  1233 	cmdpush(CS_ELSE);
       
  1234 	while (tok == SEPER)
       
  1235 	    yylex();
       
  1236 	if (tok == INBRACE && usebrace) {
       
  1237 	    yylex();
       
  1238 	    par_save_list(complex);
       
  1239 	    if (tok != OUTBRACE) {
       
  1240 		cmdpop();
       
  1241 		YYERRORV(oecused);
       
  1242 	    }
       
  1243 	} else {
       
  1244 	    par_save_list(complex);
       
  1245 	    if (tok != FI) {
       
  1246 		cmdpop();
       
  1247 		YYERRORV(oecused);
       
  1248 	    }
       
  1249 	}
       
  1250 	ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp);
       
  1251 	yylex();
       
  1252 	cmdpop();
       
  1253     }
       
  1254     ecbuf[p] = WCB_IF(WC_IF_HEAD, ecused - 1 - p);
       
  1255 }
       
  1256 
       
  1257 /*
       
  1258  * while	: ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER }
       
  1259 				( DO list DONE | INBRACE list OUTBRACE | list ZEND )
       
  1260  */
       
  1261 
       
  1262 /**/
       
  1263 static void
       
  1264 par_while(int *complex)
       
  1265 {
       
  1266     int oecused = ecused, p;
       
  1267     int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE);
       
  1268 
       
  1269     p = ecadd(0);
       
  1270     yylex();
       
  1271     par_save_list(complex);
       
  1272     incmdpos = 1;
       
  1273     while (tok == SEPER)
       
  1274 	yylex();
       
  1275     if (tok == DOLOOP) {
       
  1276 	yylex();
       
  1277 	par_save_list(complex);
       
  1278 	if (tok != DONE)
       
  1279 	    YYERRORV(oecused);
       
  1280 	yylex();
       
  1281     } else if (tok == INBRACE) {
       
  1282 	yylex();
       
  1283 	par_save_list(complex);
       
  1284 	if (tok != OUTBRACE)
       
  1285 	    YYERRORV(oecused);
       
  1286 	yylex();
       
  1287     } else if (isset(CSHJUNKIELOOPS)) {
       
  1288 	par_save_list(complex);
       
  1289 	if (tok != ZEND)
       
  1290 	    YYERRORV(oecused);
       
  1291 	yylex();
       
  1292     } else
       
  1293 	YYERRORV(oecused);
       
  1294 
       
  1295     ecbuf[p] = WCB_WHILE(type, ecused - 1 - p);
       
  1296 }
       
  1297 
       
  1298 /*
       
  1299  * repeat	: REPEAT STRING { SEPER } ( DO list DONE | list1 )
       
  1300  */
       
  1301 
       
  1302 /**/
       
  1303 static void
       
  1304 par_repeat(int *complex)
       
  1305 {
       
  1306     int oecused = ecused, p;
       
  1307 
       
  1308     p = ecadd(0);
       
  1309 
       
  1310     incmdpos = 0;
       
  1311     yylex();
       
  1312     if (tok != STRING)
       
  1313 	YYERRORV(oecused);
       
  1314     ecstr(tokstr);
       
  1315     incmdpos = 1;
       
  1316     yylex();
       
  1317     while (tok == SEPER)
       
  1318 	yylex();
       
  1319     if (tok == DOLOOP) {
       
  1320 	yylex();
       
  1321 	par_save_list(complex);
       
  1322 	if (tok != DONE)
       
  1323 	    YYERRORV(oecused);
       
  1324 	yylex();
       
  1325     } else if (tok == INBRACE) {
       
  1326 	yylex();
       
  1327 	par_save_list(complex);
       
  1328 	if (tok != OUTBRACE)
       
  1329 	    YYERRORV(oecused);
       
  1330 	yylex();
       
  1331     } else if (isset(CSHJUNKIELOOPS)) {
       
  1332 	par_save_list(complex);
       
  1333 	if (tok != ZEND)
       
  1334 	    YYERRORV(oecused);
       
  1335 	yylex();
       
  1336     } else if (unset(SHORTLOOPS)) {
       
  1337 	YYERRORV(oecused);
       
  1338     } else
       
  1339 	par_save_list1(complex);
       
  1340 
       
  1341     ecbuf[p] = WCB_REPEAT(ecused - 1 - p);
       
  1342 }
       
  1343 
       
  1344 /*
       
  1345  * subsh	: INPAR list OUTPAR |
       
  1346  *                INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ]
       
  1347  */
       
  1348 
       
  1349 /**/
       
  1350 static void
       
  1351 par_subsh(int *complex)
       
  1352 {
       
  1353     int oecused = ecused, otok = tok, p, pp;
       
  1354 
       
  1355     p = ecadd(0);
       
  1356     /* Extra word only needed for always block */
       
  1357     pp = ecadd(0);
       
  1358     yylex();
       
  1359     par_list(complex);
       
  1360     ecadd(WCB_END());
       
  1361     if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE))
       
  1362 	YYERRORV(oecused);
       
  1363     incmdpos = 1;
       
  1364     yylex();
       
  1365 
       
  1366     /* Optional always block.  No intervening SEPERs allowed. */
       
  1367     if (otok == INBRACE && tok == STRING && !strcmp(tokstr, "always")) {
       
  1368 	ecbuf[pp] = WCB_TRY(ecused - 1 - pp);
       
  1369 	incmdpos = 1;
       
  1370 	do {
       
  1371 	    yylex();
       
  1372 	} while (tok == SEPER);
       
  1373 
       
  1374 	if (tok != INBRACE)
       
  1375 	    YYERRORV(oecused);
       
  1376 	cmdpop();
       
  1377 	cmdpush(CS_ALWAYS);
       
  1378 
       
  1379 	yylex();
       
  1380 	par_save_list(complex);
       
  1381 	while (tok == SEPER)
       
  1382 	    yylex();
       
  1383 
       
  1384 	incmdpos = 1;
       
  1385 
       
  1386 	if (tok != OUTBRACE)
       
  1387 	    YYERRORV(oecused);
       
  1388 	yylex();
       
  1389 	ecbuf[p] = WCB_TRY(ecused - 1 - p);
       
  1390     } else {
       
  1391 	ecbuf[p] = (otok == INPAR ? WCB_SUBSH(ecused - 1 - p) :
       
  1392 		    WCB_CURSH(ecused - 1 - p));
       
  1393     }
       
  1394 }
       
  1395 
       
  1396 /*
       
  1397  * funcdef	: FUNCTION wordlist [ INOUTPAR ] { SEPER }
       
  1398  *					( list1 | INBRACE list OUTBRACE )
       
  1399  */
       
  1400 
       
  1401 /**/
       
  1402 static void
       
  1403 par_funcdef(void)
       
  1404 {
       
  1405     int oecused = ecused, oldlineno = lineno, num = 0, onp, p, c = 0;
       
  1406     int so, oecssub = ecssub;
       
  1407 
       
  1408     lineno = 0;
       
  1409     nocorrect = 1;
       
  1410     incmdpos = 0;
       
  1411     yylex();
       
  1412 
       
  1413     p = ecadd(0);
       
  1414     ecadd(0);
       
  1415 
       
  1416     incmdpos = 1;
       
  1417     while (tok == STRING) {
       
  1418 	if (*tokstr == Inbrace && !tokstr[1]) {
       
  1419 	    tok = INBRACE;
       
  1420 	    break;
       
  1421 	}
       
  1422 	ecstr(tokstr);
       
  1423 	num++;
       
  1424 	yylex();
       
  1425     }
       
  1426     ecadd(0);
       
  1427     ecadd(0);
       
  1428     ecadd(0);
       
  1429 
       
  1430     nocorrect = 0;
       
  1431     if (tok == INOUTPAR)
       
  1432 	yylex();
       
  1433     while (tok == SEPER)
       
  1434 	yylex();
       
  1435 
       
  1436     ecnfunc++;
       
  1437     ecssub = so = ecsoffs;
       
  1438     onp = ecnpats;
       
  1439     ecnpats = 0;
       
  1440 
       
  1441     if (tok == INBRACE) {
       
  1442 	yylex();
       
  1443 	par_list(&c);
       
  1444 	if (tok != OUTBRACE) {
       
  1445 	    lineno += oldlineno;
       
  1446 	    ecnpats = onp;
       
  1447 	    ecssub = oecssub;
       
  1448 	    YYERRORV(oecused);
       
  1449 	}
       
  1450 	yylex();
       
  1451     } else if (unset(SHORTLOOPS)) {
       
  1452 	lineno += oldlineno;
       
  1453 	ecnpats = onp;
       
  1454 	ecssub = oecssub;
       
  1455 	YYERRORV(oecused);
       
  1456     } else
       
  1457 	par_list1(&c);
       
  1458 
       
  1459     ecadd(WCB_END());
       
  1460     ecbuf[p + num + 2] = so - oecssub;
       
  1461     ecbuf[p + num + 3] = ecsoffs - so;
       
  1462     ecbuf[p + num + 4] = ecnpats;
       
  1463     ecbuf[p + 1] = num;
       
  1464 
       
  1465     lineno += oldlineno;
       
  1466     ecnpats = onp;
       
  1467     ecssub = oecssub;
       
  1468     ecnfunc++;
       
  1469 
       
  1470     ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
       
  1471 }
       
  1472 
       
  1473 /*
       
  1474  * time	: TIME sublist2
       
  1475  */
       
  1476 
       
  1477 /**/
       
  1478 static void
       
  1479 par_time(void)
       
  1480 {
       
  1481     int p, f, c = 0;
       
  1482 
       
  1483     yylex();
       
  1484 
       
  1485     p = ecadd(0);
       
  1486     ecadd(0);
       
  1487     if ((f = par_sublist2(&c)) < 0) {
       
  1488 	ecused--;
       
  1489 	ecbuf[p] = WCB_TIMED(WC_TIMED_EMPTY);
       
  1490     } else {
       
  1491 	ecbuf[p] = WCB_TIMED(WC_TIMED_PIPE);
       
  1492 	set_sublist_code(p + 1, WC_SUBLIST_END, f, ecused - 2 - p, c);
       
  1493     }
       
  1494 }
       
  1495 
       
  1496 /*
       
  1497  * dinbrack	: DINBRACK cond DOUTBRACK
       
  1498  */
       
  1499 
       
  1500 /**/
       
  1501 static void
       
  1502 par_dinbrack(void)
       
  1503 {
       
  1504     int oecused = ecused;
       
  1505 
       
  1506     incond = 1;
       
  1507     incmdpos = 0;
       
  1508     yylex();
       
  1509     par_cond();
       
  1510     if (tok != DOUTBRACK)
       
  1511 	YYERRORV(oecused);
       
  1512     incond = 0;
       
  1513     incmdpos = 1;
       
  1514     yylex();
       
  1515 }
       
  1516 
       
  1517 /*
       
  1518  * simple	: { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH }
       
  1519 					{ STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir }
       
  1520 					[ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ]
       
  1521  */
       
  1522 
       
  1523 /**/
       
  1524 static int
       
  1525 par_simple(int *complex, int nr)
       
  1526 {
       
  1527     int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0;
       
  1528     int c = *complex;
       
  1529 
       
  1530     r = ecused;
       
  1531     for (;;) {
       
  1532 	if (tok == NOCORRECT) {
       
  1533 	    *complex = c = 1;
       
  1534 	    nocorrect = 1;
       
  1535 	} else if (tok == ENVSTRING) {
       
  1536 	    char *p, *name, *str;
       
  1537 
       
  1538 	    name = tokstr;
       
  1539 	    for (p = tokstr; *p && *p != Inbrack && *p != '=' && *p != '+';
       
  1540 	         p++);
       
  1541 	    if (*p == Inbrack) skipparens(Inbrack, Outbrack, &p);
       
  1542 	    if (*p == '+') {
       
  1543 	    	*p++ = '\0';
       
  1544 	    	ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0));
       
  1545 	    } else
       
  1546 		ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_NEW, 0));
       
  1547     	
       
  1548 	    if (*p == '=') {
       
  1549 		*p = '\0';
       
  1550 		str = p + 1;
       
  1551 	    } else
       
  1552 		equalsplit(tokstr, &str);
       
  1553 	    ecstr(name);
       
  1554 	    ecstr(str);
       
  1555 	    isnull = 0;
       
  1556 	} else if (tok == ENVARRAY) {
       
  1557 	    int oldcmdpos = incmdpos, n, type2;
       
  1558 
       
  1559 	    p = ecadd(0);
       
  1560 	    incmdpos = 0;
       
  1561 	    if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') {
       
  1562 	    	tokstr[type2] = '\0';
       
  1563 		type2 = WC_ASSIGN_INC;
       
  1564     	    } else
       
  1565 		type2 = WC_ASSIGN_NEW;
       
  1566 	    ecstr(tokstr);
       
  1567 	    cmdpush(CS_ARRAY);
       
  1568 	    yylex();
       
  1569 	    n = par_nl_wordlist();
       
  1570 	    ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, type2, n);
       
  1571 	    cmdpop();
       
  1572 	    if (tok != OUTPAR)
       
  1573 		YYERROR(oecused);
       
  1574 	    incmdpos = oldcmdpos;
       
  1575 	    isnull = 0;
       
  1576 	} else
       
  1577 	    break;
       
  1578 	yylex();
       
  1579     }
       
  1580     if (tok == AMPER || tok == AMPERBANG)
       
  1581 	YYERROR(oecused);
       
  1582 
       
  1583     p = ecadd(WCB_SIMPLE(0));
       
  1584 
       
  1585     for (;;) {
       
  1586 	if (tok == STRING) {
       
  1587 	    *complex = 1;
       
  1588 	    incmdpos = 0;
       
  1589 	    ecstr(tokstr);
       
  1590 	    argc++;
       
  1591 	    yylex();
       
  1592 	} else if (IS_REDIROP(tok)) {
       
  1593 	    *complex = c = 1;
       
  1594 	    par_redir(&r);
       
  1595 	    p += 3;		/* 3 codes per redirection */
       
  1596 	    sr++;
       
  1597 	} else if (tok == INOUTPAR) {
       
  1598 	    int oldlineno = lineno, onp, so, oecssub = ecssub;
       
  1599 
       
  1600 	    *complex = c;
       
  1601 	    lineno = 0;
       
  1602 	    incmdpos = 1;
       
  1603 	    cmdpush(CS_FUNCDEF);
       
  1604 	    yylex();
       
  1605 	    while (tok == SEPER)
       
  1606 		yylex();
       
  1607 
       
  1608 	    ecispace(p + 1, 1);
       
  1609 	    ecbuf[p + 1] = argc;
       
  1610 	    ecadd(0);
       
  1611 	    ecadd(0);
       
  1612 	    ecadd(0);
       
  1613 
       
  1614 	    ecnfunc++;
       
  1615 	    ecssub = so = ecsoffs;
       
  1616 	    onp = ecnpats;
       
  1617 	    ecnpats = 0;
       
  1618 
       
  1619 	    if (tok == INBRACE) {
       
  1620 		int c = 0;
       
  1621 
       
  1622 		yylex();
       
  1623 		par_list(&c);
       
  1624 		if (tok != OUTBRACE) {
       
  1625 		    cmdpop();
       
  1626 		    lineno += oldlineno;
       
  1627 		    ecnpats = onp;
       
  1628 		    ecssub = oecssub;
       
  1629 		    YYERROR(oecused);
       
  1630 		}
       
  1631 		yylex();
       
  1632 	    } else {
       
  1633 		int ll, sl, pl, c = 0;
       
  1634 
       
  1635 		ll = ecadd(0);
       
  1636 		sl = ecadd(0);
       
  1637 		pl = ecadd(WCB_PIPE(WC_PIPE_END, 0));
       
  1638 
       
  1639 		par_cmd(&c);
       
  1640 		if (!c)
       
  1641 		    YYERROR(oecused);
       
  1642 
       
  1643 		set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c);
       
  1644 		set_list_code(ll, (Z_SYNC | Z_END), c);
       
  1645 	    }
       
  1646 	    cmdpop();
       
  1647 
       
  1648 	    ecadd(WCB_END());
       
  1649 	    ecbuf[p + argc + 2] = so - oecssub;
       
  1650 	    ecbuf[p + argc + 3] = ecsoffs - so;
       
  1651 	    ecbuf[p + argc + 4] = ecnpats;
       
  1652 
       
  1653 	    lineno += oldlineno;
       
  1654 	    ecnpats = onp;
       
  1655 	    ecssub = oecssub;
       
  1656 	    ecnfunc++;
       
  1657 
       
  1658 	    ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
       
  1659 
       
  1660 	    isfunc = 1;
       
  1661 	    isnull = 0;
       
  1662 	    break;
       
  1663 	} else
       
  1664 	    break;
       
  1665 	isnull = 0;
       
  1666     }
       
  1667     if (isnull && !(sr + nr)) {
       
  1668 	ecused = p;
       
  1669 	return 0;
       
  1670     }
       
  1671     incmdpos = 1;
       
  1672 
       
  1673     if (!isfunc)
       
  1674 	ecbuf[p] = WCB_SIMPLE(argc);
       
  1675 
       
  1676     return sr + 1;
       
  1677 }
       
  1678 
       
  1679 /*
       
  1680  * redir	: ( OUTANG | ... | TRINANG ) STRING
       
  1681  */
       
  1682 
       
  1683 static int redirtab[TRINANG - OUTANG + 1] = {
       
  1684     REDIR_WRITE,
       
  1685     REDIR_WRITENOW,
       
  1686     REDIR_APP,
       
  1687     REDIR_APPNOW,
       
  1688     REDIR_READ,
       
  1689     REDIR_READWRITE,
       
  1690     REDIR_HEREDOC,
       
  1691     REDIR_HEREDOCDASH,
       
  1692     REDIR_MERGEIN,
       
  1693     REDIR_MERGEOUT,
       
  1694     REDIR_ERRWRITE,
       
  1695     REDIR_ERRWRITENOW,
       
  1696     REDIR_ERRAPP,
       
  1697     REDIR_ERRAPPNOW,
       
  1698     REDIR_HERESTR,
       
  1699 };
       
  1700 
       
  1701 /**/
       
  1702 static void
       
  1703 par_redir(int *rp)
       
  1704 {
       
  1705     int r = *rp, type, fd1, oldcmdpos, oldnc;
       
  1706     char *name;
       
  1707 
       
  1708     oldcmdpos = incmdpos;
       
  1709     incmdpos = 0;
       
  1710     oldnc = nocorrect;
       
  1711     if (tok != INANG && tok != INOUTANG)
       
  1712 	nocorrect = 1;
       
  1713     type = redirtab[tok - OUTANG];
       
  1714     fd1 = tokfd;
       
  1715     yylex();
       
  1716     if (tok != STRING && tok != ENVSTRING)
       
  1717 	YYERRORV(ecused);
       
  1718     incmdpos = oldcmdpos;
       
  1719     nocorrect = oldnc;
       
  1720 
       
  1721     /* assign default fd */
       
  1722     if (fd1 == -1)
       
  1723 	fd1 = IS_READFD(type) ? 0 : 1;
       
  1724 
       
  1725     name = tokstr;
       
  1726 
       
  1727     switch (type) {
       
  1728     case REDIR_HEREDOC:
       
  1729     case REDIR_HEREDOCDASH: {
       
  1730 	/* <<[-] name */
       
  1731 	struct heredocs **hd;
       
  1732 
       
  1733 	/* If we ever need more than three codes (or less), we have to change
       
  1734 	 * the factors in par_cmd() and par_simple(), too. */
       
  1735 	ecispace(r, 3);
       
  1736 	*rp = r + 3;
       
  1737 	ecbuf[r] = WCB_REDIR(type);
       
  1738 	ecbuf[r + 1] = fd1;
       
  1739 
       
  1740 	for (hd = &hdocs; *hd; hd = &(*hd)->next);
       
  1741 	*hd = zalloc(sizeof(struct heredocs));
       
  1742 	(*hd)->next = NULL;
       
  1743 	(*hd)->type = type;
       
  1744 	(*hd)->pc = r;
       
  1745 	(*hd)->str = tokstr;
       
  1746 
       
  1747 	yylex();
       
  1748 	return;
       
  1749     }
       
  1750     case REDIR_WRITE:
       
  1751     case REDIR_WRITENOW:
       
  1752 	if (tokstr[0] == Outang && tokstr[1] == Inpar)
       
  1753 	    /* > >(...) */
       
  1754 	    type = REDIR_OUTPIPE;
       
  1755 	else if (tokstr[0] == Inang && tokstr[1] == Inpar)
       
  1756 	    YYERRORV(ecused);
       
  1757 	break;
       
  1758     case REDIR_READ:
       
  1759 	if (tokstr[0] == Inang && tokstr[1] == Inpar)
       
  1760 	    /* < <(...) */
       
  1761 	    type = REDIR_INPIPE;
       
  1762 	else if (tokstr[0] == Outang && tokstr[1] == Inpar)
       
  1763 	    YYERRORV(ecused);
       
  1764 	break;
       
  1765     case REDIR_READWRITE:
       
  1766 	if ((tokstr[0] == Inang || tokstr[0] == Outang) && tokstr[1] == Inpar)
       
  1767 	    type = tokstr[0] == Inang ? REDIR_INPIPE : REDIR_OUTPIPE;
       
  1768 	break;
       
  1769     }
       
  1770     yylex();
       
  1771 
       
  1772     /* If we ever need more than three codes (or less), we have to change
       
  1773      * the factors in par_cmd() and par_simple(), too. */
       
  1774     ecispace(r, 3);
       
  1775     *rp = r + 3;
       
  1776     ecbuf[r] = WCB_REDIR(type);
       
  1777     ecbuf[r + 1] = fd1;
       
  1778     ecbuf[r + 2] = ecstrcode(name);
       
  1779 }
       
  1780 
       
  1781 /**/
       
  1782 void
       
  1783 setheredoc(int pc, int type, char *str)
       
  1784 {
       
  1785     ecbuf[pc] = WCB_REDIR(type);
       
  1786     ecbuf[pc + 2] = ecstrcode(str);
       
  1787 }
       
  1788 
       
  1789 /*
       
  1790  * wordlist	: { STRING }
       
  1791  */
       
  1792 
       
  1793 /**/
       
  1794 static int
       
  1795 par_wordlist(void)
       
  1796 {
       
  1797     int num = 0;
       
  1798     while (tok == STRING) {
       
  1799 	ecstr(tokstr);
       
  1800 	num++;
       
  1801 	yylex();
       
  1802     }
       
  1803     return num;
       
  1804 }
       
  1805 
       
  1806 /*
       
  1807  * nl_wordlist	: { STRING | SEPER }
       
  1808  */
       
  1809 
       
  1810 /**/
       
  1811 static int
       
  1812 par_nl_wordlist(void)
       
  1813 {
       
  1814     int num = 0;
       
  1815 
       
  1816     while (tok == STRING || tok == SEPER) {
       
  1817 	if (tok != SEPER) {
       
  1818 	    ecstr(tokstr);
       
  1819 	    num++;
       
  1820 	}
       
  1821 	yylex();
       
  1822     }
       
  1823     return num;
       
  1824 }
       
  1825 
       
  1826 /*
       
  1827  * condlex is yylex for normal parsing, but is altered to allow
       
  1828  * the test builtin to use par_cond.
       
  1829  */
       
  1830 
       
  1831 /**/
       
  1832 void (*condlex) _((void)) = yylex;
       
  1833 
       
  1834 /*
       
  1835  * cond	: cond_1 { SEPER } [ DBAR { SEPER } cond ]
       
  1836  */
       
  1837 
       
  1838 /**/
       
  1839 static int
       
  1840 par_cond(void)
       
  1841 {
       
  1842     int p = ecused, r;
       
  1843 
       
  1844     r = par_cond_1();
       
  1845     while (tok == SEPER)
       
  1846 	condlex();
       
  1847     if (tok == DBAR) {
       
  1848 	condlex();
       
  1849 	while (tok == SEPER)
       
  1850 	    condlex();
       
  1851 	ecispace(p, 1);
       
  1852 	par_cond();
       
  1853 	ecbuf[p] = WCB_COND(COND_OR, ecused - 1 - p);
       
  1854 	return 1;
       
  1855     }
       
  1856     return r;
       
  1857 }
       
  1858 
       
  1859 /*
       
  1860  * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ]
       
  1861  */
       
  1862 
       
  1863 /**/
       
  1864 static int
       
  1865 par_cond_1(void)
       
  1866 {
       
  1867     int r, p = ecused;
       
  1868 
       
  1869     r = par_cond_2();
       
  1870     while (tok == SEPER)
       
  1871 	condlex();
       
  1872     if (tok == DAMPER) {
       
  1873 	condlex();
       
  1874 	while (tok == SEPER)
       
  1875 	    condlex();
       
  1876 	ecispace(p, 1);
       
  1877 	par_cond_1();
       
  1878 	ecbuf[p] = WCB_COND(COND_AND, ecused - 1 - p);
       
  1879 	return 1;
       
  1880     }
       
  1881     return r;
       
  1882 }
       
  1883 
       
  1884 /*
       
  1885  * cond_2	: BANG cond_2
       
  1886 				| INPAR { SEPER } cond_2 { SEPER } OUTPAR
       
  1887 				| STRING STRING STRING
       
  1888 				| STRING STRING
       
  1889 				| STRING ( INANG | OUTANG ) STRING
       
  1890  */
       
  1891 
       
  1892 /**/
       
  1893 static int
       
  1894 par_cond_2(void)
       
  1895 {
       
  1896     char *s1, *s2, *s3;
       
  1897     int dble = 0;
       
  1898 
       
  1899     if (condlex == testlex) {
       
  1900 	/* See the description of test in POSIX 1003.2 */
       
  1901 	if (tok == NULLTOK)
       
  1902 	    /* no arguments: false */
       
  1903 	    return par_cond_double(dupstring("-n"), dupstring(""));
       
  1904 	if (!*testargs) {
       
  1905 	    /* one argument: [ foo ] is equivalent to [ -n foo ] */
       
  1906 	    s1 = tokstr;
       
  1907 	    condlex();
       
  1908 	    return par_cond_double(dupstring("-n"), s1);
       
  1909 	}
       
  1910 	if (testargs[1]) {
       
  1911 	    /* three arguments: if the second argument is a binary operator, *
       
  1912 	     * perform that binary test on the first and the third argument  */
       
  1913 	    if (!strcmp(*testargs, "=")  ||
       
  1914 		!strcmp(*testargs, "==") ||
       
  1915 		!strcmp(*testargs, "!=") ||
       
  1916 		(**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) {
       
  1917 		s1 = tokstr;
       
  1918 		condlex();
       
  1919 		s2 = tokstr;
       
  1920 		condlex();
       
  1921 		s3 = tokstr;
       
  1922 		condlex();
       
  1923 		return par_cond_triple(s1, s2, s3);
       
  1924 	    }
       
  1925 	}
       
  1926     }
       
  1927     if (tok == BANG) {
       
  1928 	condlex();
       
  1929 	ecadd(WCB_COND(COND_NOT, 0));
       
  1930 	return par_cond_2();
       
  1931     }
       
  1932     if (tok == INPAR) {
       
  1933 	int r;
       
  1934 
       
  1935 	condlex();
       
  1936 	while (tok == SEPER)
       
  1937 	    condlex();
       
  1938 	r = par_cond();
       
  1939 	while (tok == SEPER)
       
  1940 	    condlex();
       
  1941 	if (tok != OUTPAR)
       
  1942 	    YYERROR(ecused);
       
  1943 	condlex();
       
  1944 	return r;
       
  1945     }
       
  1946     if (tok != STRING) {
       
  1947 	if (tok && tok != LEXERR && condlex == testlex) {
       
  1948 	    s1 = tokstr;
       
  1949 	    condlex();
       
  1950 	    return par_cond_double("-n", s1);
       
  1951 	} else
       
  1952 	    YYERROR(ecused);
       
  1953     }
       
  1954     s1 = tokstr;
       
  1955     if (condlex == testlex)
       
  1956 	dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1
       
  1957 		  && !s1[2]);
       
  1958     condlex();
       
  1959     if (tok == INANG || tok == OUTANG) {
       
  1960 	int xtok = tok;
       
  1961 	condlex();
       
  1962 	if (tok != STRING)
       
  1963 	    YYERROR(ecused);
       
  1964 	s3 = tokstr;
       
  1965 	condlex();
       
  1966 	ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0));
       
  1967 	ecstr(s1);
       
  1968 	ecstr(s3);
       
  1969 	return 1;
       
  1970     }
       
  1971     if (tok != STRING) {
       
  1972 	if (tok != LEXERR && condlex == testlex) {
       
  1973 	    if (!dble)
       
  1974 		return par_cond_double("-n", s1);
       
  1975 	    else if (!strcmp(s1, "-t"))
       
  1976 		return par_cond_double(s1, "1");
       
  1977 	} else
       
  1978 	    YYERROR(ecused);
       
  1979     }
       
  1980     s2 = tokstr;
       
  1981     incond++;			/* parentheses do globbing */
       
  1982     condlex();
       
  1983     incond--;			/* parentheses do grouping */
       
  1984     if (tok == STRING && !dble) {
       
  1985 	s3 = tokstr;
       
  1986 	condlex();
       
  1987 	if (tok == STRING) {
       
  1988 	    LinkList l = newlinklist();
       
  1989 
       
  1990 	    addlinknode(l, s2);
       
  1991 	    addlinknode(l, s3);
       
  1992 
       
  1993 	    while (tok == STRING) {
       
  1994 		addlinknode(l, tokstr);
       
  1995 		condlex();
       
  1996 	    }
       
  1997 	    return par_cond_multi(s1, l);
       
  1998 	} else
       
  1999 	    return par_cond_triple(s1, s2, s3);
       
  2000     } else
       
  2001 	return par_cond_double(s1, s2);
       
  2002 }
       
  2003 
       
  2004 /**/
       
  2005 static int
       
  2006 par_cond_double(char *a, char *b)
       
  2007 {
       
  2008     if (a[0] != '-' || !a[1])
       
  2009 	COND_ERROR("parse error: condition expected: %s", a);
       
  2010     else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) {
       
  2011 	ecadd(WCB_COND(a[1], 0));
       
  2012 	ecstr(b);
       
  2013     } else {
       
  2014 	ecadd(WCB_COND(COND_MOD, 1));
       
  2015 	ecstr(a);
       
  2016 	ecstr(b);
       
  2017     }
       
  2018     return 1;
       
  2019 }
       
  2020 
       
  2021 /**/
       
  2022 static int
       
  2023 get_cond_num(char *tst)
       
  2024 {
       
  2025     static char *condstrs[] =
       
  2026     {
       
  2027 	"nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL
       
  2028     };
       
  2029     int t0;
       
  2030 
       
  2031     for (t0 = 0; condstrs[t0]; t0++)
       
  2032 	if (!strcmp(condstrs[t0], tst))
       
  2033 	    return t0;
       
  2034     return -1;
       
  2035 }
       
  2036 
       
  2037 /**/
       
  2038 static int
       
  2039 par_cond_triple(char *a, char *b, char *c)
       
  2040 {
       
  2041     int t0;
       
  2042 
       
  2043     if ((b[0] == Equals || b[0] == '=') &&
       
  2044 	(!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) {
       
  2045 	ecadd(WCB_COND(COND_STREQ, 0));
       
  2046 	ecstr(a);
       
  2047 	ecstr(c);
       
  2048 	ecadd(ecnpats++);
       
  2049     } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) {
       
  2050 	ecadd(WCB_COND(COND_STRNEQ, 0));
       
  2051 	ecstr(a);
       
  2052 	ecstr(c);
       
  2053 	ecadd(ecnpats++);
       
  2054     } else if (b[0] == '-') {
       
  2055 	if ((t0 = get_cond_num(b + 1)) > -1) {
       
  2056 	    ecadd(WCB_COND(t0 + COND_NT, 0));
       
  2057 	    ecstr(a);
       
  2058 	    ecstr(c);
       
  2059 	} else {
       
  2060 	    ecadd(WCB_COND(COND_MODI, 0));
       
  2061 	    ecstr(b);
       
  2062 	    ecstr(a);
       
  2063 	    ecstr(c);
       
  2064 	}
       
  2065     } else if (a[0] == '-' && a[1]) {
       
  2066 	ecadd(WCB_COND(COND_MOD, 2));
       
  2067 	ecstr(a);
       
  2068 	ecstr(b);
       
  2069 	ecstr(c);
       
  2070     } else
       
  2071 	COND_ERROR("condition expected: %s", b);
       
  2072 
       
  2073     return 1;
       
  2074 }
       
  2075 
       
  2076 /**/
       
  2077 static int
       
  2078 par_cond_multi(char *a, LinkList l)
       
  2079 {
       
  2080     if (a[0] != '-' || !a[1])
       
  2081 	COND_ERROR("condition expected: %s", a);
       
  2082     else {
       
  2083 	LinkNode n;
       
  2084 
       
  2085 	ecadd(WCB_COND(COND_MOD, countlinknodes(l)));
       
  2086 	ecstr(a);
       
  2087 	for (n = firstnode(l); n; incnode(n))
       
  2088 	    ecstr((char *) getdata(n));
       
  2089     }
       
  2090     return 1;
       
  2091 }
       
  2092 
       
  2093 /**/
       
  2094 static void
       
  2095 yyerror(int noerr)
       
  2096 {
       
  2097     int t0;
       
  2098     char *t;
       
  2099 
       
  2100     if ((t = dupstring(yytext)))
       
  2101 	untokenize(t);
       
  2102 
       
  2103     for (t0 = 0; t0 != 20; t0++)
       
  2104 	if (!t || !t[t0] || t[t0] == '\n')
       
  2105 	    break;
       
  2106     if (t0 == 20)
       
  2107 	zwarn("parse error near `%l...'", t, 20);
       
  2108     else if (t0)
       
  2109 	zwarn("parse error near `%l'", t, t0);
       
  2110     else
       
  2111 	zwarn("parse error", NULL, 0);
       
  2112     if (!noerr && noerrs != 2)
       
  2113 	errflag = 1;
       
  2114 }
       
  2115 
       
  2116 /**/
       
  2117 mod_export Eprog
       
  2118 dupeprog(Eprog p, int heap)
       
  2119 {
       
  2120     Eprog r;
       
  2121     int i;
       
  2122     Patprog *pp;
       
  2123 
       
  2124     if (p == &dummy_eprog)
       
  2125 	return p;
       
  2126 
       
  2127     r = (heap ? (Eprog) zhalloc(sizeof(*r)) : (Eprog) zalloc(sizeof(*r)));
       
  2128     r->flags = (heap ? EF_HEAP : EF_REAL) | (p->flags & EF_RUN);
       
  2129     r->dump = NULL;
       
  2130     r->len = p->len;
       
  2131     r->npats = p->npats;
       
  2132     /*
       
  2133      * If Eprog is on the heap, reference count is not valid.
       
  2134      * Otherwise, initialise reference count to 1 so that a freeeprog()
       
  2135      * will delete it if it is not in use.
       
  2136      */
       
  2137     r->nref = heap ? -1 : 1;
       
  2138     pp = r->pats = (heap ? (Patprog *) hcalloc(r->len) :
       
  2139 		    (Patprog *) zshcalloc(r->len));
       
  2140     r->prog = (Wordcode) (r->pats + r->npats);
       
  2141     r->strs = ((char *) r->prog) + (p->strs - ((char *) p->prog));
       
  2142     memcpy(r->prog, p->prog, r->len - (p->npats * sizeof(Patprog)));
       
  2143     r->shf = NULL;
       
  2144 
       
  2145     for (i = r->npats; i--; pp++)
       
  2146 	*pp = dummy_patprog1;
       
  2147 
       
  2148     return r;
       
  2149 }
       
  2150 
       
  2151 
       
  2152 /*
       
  2153  * Pair of functions to mark an Eprog as in use, and to delete it
       
  2154  * when it is no longer in use, by means of the reference count in
       
  2155  * then nref element.
       
  2156  *
       
  2157  * If nref is negative, the Eprog is on the heap and is never freed.
       
  2158  */
       
  2159 
       
  2160 /* Increase the reference count of an Eprog so it won't be deleted. */
       
  2161 
       
  2162 /**/
       
  2163 mod_export void
       
  2164 useeprog(Eprog p)
       
  2165 {
       
  2166     if (p && p != &dummy_eprog && p->nref >= 0)
       
  2167 	p->nref++;
       
  2168 }
       
  2169 
       
  2170 /* Free an Eprog if we have finished with it */
       
  2171 
       
  2172 /**/
       
  2173 mod_export void
       
  2174 freeeprog(Eprog p)
       
  2175 {
       
  2176     int i;
       
  2177     Patprog *pp;
       
  2178 
       
  2179     if (p && p != &dummy_eprog) {
       
  2180 	/* paranoia */
       
  2181 	DPUTS(p->nref > 0 && (p->flags & EF_HEAP), "Heap EPROG has nref > 0");
       
  2182 	DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0");
       
  2183 	DPUTS(p->nref < -1, "Uninitialised EPROG nref");
       
  2184 #ifdef MAX_FUNCTION_DEPTH
       
  2185 	DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref");
       
  2186 #endif
       
  2187 	if (p->nref > 0 && !--p->nref) {
       
  2188 	    for (i = p->npats, pp = p->pats; i--; pp++)
       
  2189 		freepatprog(*pp);
       
  2190 	    if (p->dump) {
       
  2191 		decrdumpcount(p->dump);
       
  2192 		zfree(p->pats, p->npats * sizeof(Patprog));
       
  2193 	    } else
       
  2194 		zfree(p->pats, p->len);
       
  2195 	    zfree(p, sizeof(*p));
       
  2196 	}
       
  2197     }
       
  2198 }
       
  2199 
       
  2200 /**/
       
  2201 char *
       
  2202 ecgetstr(Estate s, int dup, int *tok)
       
  2203 {
       
  2204     static char buf[4];
       
  2205     wordcode c = *s->pc++;
       
  2206     char *r;
       
  2207 
       
  2208     if (c == 6 || c == 7)
       
  2209 	r = "";
       
  2210     else if (c & 2) {
       
  2211 	buf[0] = (char) ((c >>  3) & 0xff);
       
  2212 	buf[1] = (char) ((c >> 11) & 0xff);
       
  2213 	buf[2] = (char) ((c >> 19) & 0xff);
       
  2214 	buf[3] = '\0';
       
  2215 	r = dupstring(buf);
       
  2216 	dup = EC_NODUP;
       
  2217     } else {
       
  2218 	r = s->strs + (c >> 2);
       
  2219     }
       
  2220     if (tok)
       
  2221 	*tok = (c & 1);
       
  2222 
       
  2223     /*** Since function dump files are mapped read-only, avoiding to
       
  2224      *   to duplicate strings when they don't contain tokens may fail
       
  2225      *   when one of the many utility functions happens to write to
       
  2226      *   one of the strings (without really modifying it).
       
  2227      *   If that happens to you and you don't feel like debugging it,
       
  2228      *   just change the line below to:
       
  2229      *
       
  2230      *     return (dup ? dupstring(r) : r);
       
  2231      */
       
  2232 
       
  2233     return ((dup == EC_DUP || (dup && (c & 1)))  ? dupstring(r) : r);
       
  2234 }
       
  2235 
       
  2236 /**/
       
  2237 char *
       
  2238 ecrawstr(Eprog p, Wordcode pc, int *tok)
       
  2239 {
       
  2240     static char buf[4];
       
  2241     wordcode c = *pc;
       
  2242 
       
  2243     if (c == 6 || c == 7) {
       
  2244 	if (tok)
       
  2245 	    *tok = (c & 1);
       
  2246 	return "";
       
  2247     } else if (c & 2) {
       
  2248 	buf[0] = (char) ((c >>  3) & 0xff);
       
  2249 	buf[1] = (char) ((c >> 11) & 0xff);
       
  2250 	buf[2] = (char) ((c >> 19) & 0xff);
       
  2251 	buf[3] = '\0';
       
  2252 	if (tok)
       
  2253 	    *tok = (c & 1);
       
  2254 	return buf;
       
  2255     } else {
       
  2256 	if (tok)
       
  2257 	    *tok = (c & 1);
       
  2258 	return p->strs + (c >> 2);
       
  2259     }
       
  2260 }
       
  2261 
       
  2262 /**/
       
  2263 char **
       
  2264 ecgetarr(Estate s, int num, int dup, int *tok)
       
  2265 {
       
  2266     char **ret, **rp;
       
  2267     int tf = 0, tmp = 0;
       
  2268 
       
  2269     ret = rp = (char **) zhalloc((num + 1) * sizeof(char *));
       
  2270 
       
  2271     while (num--) {
       
  2272 	*rp++ = ecgetstr(s, dup, &tmp);
       
  2273 	tf |=  tmp;
       
  2274     }
       
  2275     *rp = NULL;
       
  2276     if (tok)
       
  2277 	*tok = tf;
       
  2278 
       
  2279     return ret;
       
  2280 }
       
  2281 
       
  2282 /**/
       
  2283 LinkList
       
  2284 ecgetlist(Estate s, int num, int dup, int *tok)
       
  2285 {
       
  2286     if (num) {
       
  2287 	LinkList ret;
       
  2288 	int i, tf = 0, tmp = 0;
       
  2289 
       
  2290 	ret = newsizedlist(num);
       
  2291 	for (i = 0; i < num; i++) {
       
  2292 	    setsizednode(ret, i, ecgetstr(s, dup, &tmp));
       
  2293 	    tf |= tmp;
       
  2294 	}
       
  2295 	if (tok)
       
  2296 	    *tok = tf;
       
  2297 	return ret;
       
  2298     }
       
  2299     if (tok)
       
  2300 	*tok = 0;
       
  2301     return NULL;
       
  2302 }
       
  2303 
       
  2304 /**/
       
  2305 LinkList
       
  2306 ecgetredirs(Estate s)
       
  2307 {
       
  2308     LinkList ret = newlinklist();
       
  2309     wordcode code = *s->pc++;
       
  2310 
       
  2311     while (wc_code(code) == WC_REDIR) {
       
  2312 	Redir r = (Redir) zhalloc(sizeof(*r));
       
  2313 
       
  2314 	r->type = WC_REDIR_TYPE(code);
       
  2315 	r->fd1 = *s->pc++;
       
  2316 	r->name = ecgetstr(s, EC_DUP, NULL);
       
  2317 
       
  2318 	addlinknode(ret, r);
       
  2319 
       
  2320 	code = *s->pc++;
       
  2321     }
       
  2322     s->pc--;
       
  2323 
       
  2324     return ret;
       
  2325 }
       
  2326 
       
  2327 /**/
       
  2328 mod_export struct eprog dummy_eprog;
       
  2329 
       
  2330 static wordcode dummy_eprog_code;
       
  2331 
       
  2332 /**/
       
  2333 void
       
  2334 init_eprog(void)
       
  2335 {
       
  2336     dummy_eprog_code = WCB_END();
       
  2337     dummy_eprog.len = sizeof(wordcode);
       
  2338     dummy_eprog.prog = &dummy_eprog_code;
       
  2339     dummy_eprog.strs = NULL;
       
  2340 }
       
  2341 
       
  2342 /* Code for function dump files.
       
  2343  *
       
  2344  * Dump files consist of a header and the function bodies (the wordcode
       
  2345  * plus the string table) and that twice: once for the byte-order of the
       
  2346  * host the file was created on and once for the other byte-order. The
       
  2347  * header describes where the beginning of the `other' version is and it
       
  2348  * is up to the shell reading the file to decide which version it needs.
       
  2349  * This is done by checking if the first word is FD_MAGIC (then the 
       
  2350  * shell reading the file has the same byte order as the one that created
       
  2351  * the file) or if it is FD_OMAGIC, then the `other' version has to be
       
  2352  * read.
       
  2353  * The header is the magic number, a word containing the flags (if the
       
  2354  * file should be mapped or read and if this header is the `other' one),
       
  2355  * the version string in a field of 40 characters and the descriptions
       
  2356  * for the functions in the dump file.
       
  2357  *
       
  2358  * NOTES:
       
  2359  *  - This layout has to be kept; everything after it may be changed.
       
  2360  *  - When incompatible changes are made, the FD_MAGIC and FD_OMAGIC
       
  2361  *    numbers have to be changed.
       
  2362  *
       
  2363  * Each description consists of a struct fdhead followed by the name,
       
  2364  * aligned to sizeof(wordcode) (i.e. 4 bytes).
       
  2365  */
       
  2366 
       
  2367 #include "version.h"
       
  2368 
       
  2369 #define FD_EXT ".zwc"
       
  2370 #define FD_MINMAP 4096
       
  2371 
       
  2372 #define FD_PRELEN 12
       
  2373 #define FD_MAGIC  0x04050607
       
  2374 #define FD_OMAGIC 0x07060504
       
  2375 
       
  2376 #define FDF_MAP   1
       
  2377 #define FDF_OTHER 2
       
  2378 
       
  2379 typedef struct fdhead *FDHead;
       
  2380 
       
  2381 struct fdhead {
       
  2382     wordcode start;		/* offset to function definition */
       
  2383     wordcode len;		/* length of wordcode/strings */
       
  2384     wordcode npats;		/* number of patterns needed */
       
  2385     wordcode strs;		/* offset to strings */
       
  2386     wordcode hlen;		/* header length (incl. name) */
       
  2387     wordcode flags;		/* flags and offset to name tail */
       
  2388 };
       
  2389 
       
  2390 #define fdheaderlen(f) (((Wordcode) (f))[FD_PRELEN])
       
  2391 
       
  2392 #define fdmagic(f)       (((Wordcode) (f))[0])
       
  2393 #define fdsetbyte(f,i,v) \
       
  2394     ((((unsigned char *) (((Wordcode) (f)) + 1))[i]) = ((unsigned char) (v)))
       
  2395 #define fdbyte(f,i)      ((wordcode) (((unsigned char *) (((Wordcode) (f)) + 1))[i]))
       
  2396 #define fdflags(f)       fdbyte(f, 0)
       
  2397 #define fdsetflags(f,v)  fdsetbyte(f, 0, v)
       
  2398 #define fdother(f)       (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16))
       
  2399 #define fdsetother(f, o) \
       
  2400     do { \
       
  2401         fdsetbyte(f, 1, ((o) & 0xff)); \
       
  2402         fdsetbyte(f, 2, (((o) >> 8) & 0xff)); \
       
  2403         fdsetbyte(f, 3, (((o) >> 16) & 0xff)); \
       
  2404     } while (0)
       
  2405 #define fdversion(f)     ((char *) ((f) + 2))
       
  2406 
       
  2407 #define firstfdhead(f) ((FDHead) (((Wordcode) (f)) + FD_PRELEN))
       
  2408 #define nextfdhead(f)  ((FDHead) (((Wordcode) (f)) + (f)->hlen))
       
  2409 
       
  2410 #define fdhflags(f)      (((FDHead) (f))->flags)
       
  2411 #define fdhtail(f)       (((FDHead) (f))->flags >> 2)
       
  2412 #define fdhbldflags(f,t) ((f) | ((t) << 2))
       
  2413 
       
  2414 #define FDHF_KSHLOAD 1
       
  2415 #define FDHF_ZSHLOAD 2
       
  2416 
       
  2417 #define fdname(f)      ((char *) (((FDHead) (f)) + 1))
       
  2418 
       
  2419 /* This is used when building wordcode files. */
       
  2420 
       
  2421 typedef struct wcfunc *WCFunc;
       
  2422 
       
  2423 struct wcfunc {
       
  2424     char *name;
       
  2425     Eprog prog;
       
  2426     int flags;
       
  2427 };
       
  2428 
       
  2429 /* Try to find the description for the given function name. */
       
  2430 
       
  2431 static FDHead
       
  2432 dump_find_func(Wordcode h, char *name)
       
  2433 {
       
  2434     FDHead n, e = (FDHead) (h + fdheaderlen(h));
       
  2435 
       
  2436     for (n = firstfdhead(h); n < e; n = nextfdhead(n))
       
  2437 	if (!strcmp(name, fdname(n) + fdhtail(n)))
       
  2438 	    return n;
       
  2439 
       
  2440     return NULL;
       
  2441 }
       
  2442 #ifndef __SYMBIAN32__
       
  2443 /**/
       
  2444 int
       
  2445 bin_zcompile(char *nam, char **args, Options ops, UNUSED(int func))
       
  2446 {
       
  2447     int map, flags, ret;
       
  2448     char *dump;
       
  2449 #ifdef __SYMBIAN32__
       
  2450 	func=func;
       
  2451 #endif
       
  2452     if ((OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) ||
       
  2453 	(OPT_ISSET(ops,'R') && OPT_ISSET(ops,'M')) ||
       
  2454 	(OPT_ISSET(ops,'c') &&
       
  2455 	 (OPT_ISSET(ops,'U') || OPT_ISSET(ops,'k') || OPT_ISSET(ops,'z'))) ||
       
  2456 	(!(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && OPT_ISSET(ops,'m'))) {
       
  2457 	zwarnnam(nam, "illegal combination of options", NULL, 0);
       
  2458 	return 1;
       
  2459     }
       
  2460     if ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && isset(KSHAUTOLOAD))
       
  2461 	zwarnnam(nam, "functions will use zsh style autoloading", NULL, 0);
       
  2462 
       
  2463     flags = (OPT_ISSET(ops,'k') ? FDHF_KSHLOAD :
       
  2464 	     (OPT_ISSET(ops,'z') ? FDHF_ZSHLOAD : 0));
       
  2465 
       
  2466     if (OPT_ISSET(ops,'t')) {
       
  2467 	Wordcode f;
       
  2468 
       
  2469 	if (!*args) {
       
  2470 	    zwarnnam(nam, "too few arguments", NULL, 0);
       
  2471 	    return 1;
       
  2472 	}
       
  2473 	if (!(f = load_dump_header(nam, (strsfx(FD_EXT, *args) ? *args :
       
  2474 					 dyncat(*args, FD_EXT)), 1)))
       
  2475 		return 1;
       
  2476 
       
  2477 	if (args[1]) {
       
  2478 	    for (args++; *args; args++)
       
  2479 		if (!dump_find_func(f, *args))
       
  2480 		    return 1;
       
  2481 	    return 0;
       
  2482 	} else {
       
  2483 	    FDHead h, e = (FDHead) (f + fdheaderlen(f));
       
  2484 
       
  2485 	    printf("zwc file (%s) for zsh-%s\n",
       
  2486 		   ((fdflags(f) & FDF_MAP) ? "mapped" : "read"), fdversion(f));
       
  2487 	    for (h = firstfdhead(f); h < e; h = nextfdhead(h))
       
  2488 		printf("%s\n", fdname(h));
       
  2489 	    return 0;
       
  2490 	}
       
  2491     }
       
  2492     if (!*args) {
       
  2493 	zwarnnam(nam, "too few arguments", NULL, 0);
       
  2494 	return 1;
       
  2495     }
       
  2496     map = (OPT_ISSET(ops,'M') ? 2 : (OPT_ISSET(ops,'R') ? 0 : 1));
       
  2497 
       
  2498     if (!args[1] && !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a'))) {
       
  2499 	queue_signals();
       
  2500 	ret = build_dump(nam, dyncat(*args, FD_EXT), args, OPT_ISSET(ops,'U'),
       
  2501 			 map, flags);
       
  2502 	unqueue_signals();
       
  2503 	return ret;
       
  2504     }
       
  2505     dump = (strsfx(FD_EXT, *args) ? *args : dyncat(*args, FD_EXT));
       
  2506 
       
  2507     queue_signals();
       
  2508     ret = ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) ?
       
  2509 	   build_cur_dump(nam, dump, args + 1, OPT_ISSET(ops,'m'), map,
       
  2510 			  (OPT_ISSET(ops,'c') ? 1 : 0) | 
       
  2511 			  (OPT_ISSET(ops,'a') ? 2 : 0)) :
       
  2512 	   build_dump(nam, dump, args + 1, OPT_ISSET(ops,'U'), map, flags));
       
  2513     unqueue_signals();
       
  2514 
       
  2515     return ret;
       
  2516 }
       
  2517 #endif //__SYMBIAN32__
       
  2518 
       
  2519 /* Load the header of a dump file. Returns NULL if the file isn't a
       
  2520  * valid dump file. */
       
  2521 
       
  2522 /**/
       
  2523 static Wordcode
       
  2524 load_dump_header(char *nam, char *name, int err)
       
  2525 {
       
  2526     int fd, v = 0;
       
  2527     wordcode buf[FD_PRELEN + 1];
       
  2528 
       
  2529     if ((fd = open(name, O_RDONLY)) < 0) {
       
  2530 	if (err)
       
  2531 	    zwarnnam(nam, "can't open zwc file: %s", name, 0);
       
  2532 	return NULL;
       
  2533     }
       
  2534     if (read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
       
  2535 	((FD_PRELEN + 1) * sizeof(wordcode)) ||
       
  2536 	(v = (fdmagic(buf) != FD_MAGIC && fdmagic(buf) != FD_OMAGIC))) {
       
  2537 	if (err) {
       
  2538 	    if (v) {
       
  2539 		char msg[80];
       
  2540 
       
  2541 		sprintf(msg, "zwc file has wrong version (zsh-%s): %%s",
       
  2542 			fdversion(buf));
       
  2543 		zwarnnam(nam, msg , name, 0);
       
  2544 	    } else
       
  2545 		zwarnnam(nam, "invalid zwc file: %s" , name, 0);
       
  2546 	}
       
  2547 	close(fd);
       
  2548 	return NULL;
       
  2549     } else {
       
  2550 	int len;
       
  2551 	Wordcode head;
       
  2552 
       
  2553 	if (fdmagic(buf) == FD_MAGIC) {
       
  2554 	    len = fdheaderlen(buf) * sizeof(wordcode);
       
  2555 	    head = (Wordcode) zhalloc(len);
       
  2556 	}
       
  2557 	else {
       
  2558 	    int o = fdother(buf);
       
  2559 
       
  2560 	    if (lseek(fd, o, 0) == -1 ||
       
  2561 		read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
       
  2562 		((FD_PRELEN + 1) * sizeof(wordcode))) {
       
  2563 		zwarnnam(nam, "invalid zwc file: %s" , name, 0);
       
  2564 		close(fd);
       
  2565 		return NULL;
       
  2566 	    }
       
  2567 	    len = fdheaderlen(buf) * sizeof(wordcode);
       
  2568 	    head = (Wordcode) zhalloc(len);
       
  2569 	}
       
  2570 	memcpy(head, buf, (FD_PRELEN + 1) * sizeof(wordcode));
       
  2571 
       
  2572 	len -= (FD_PRELEN + 1) * sizeof(wordcode);
       
  2573 	if (read(fd, head + (FD_PRELEN + 1), len) != len) {
       
  2574 	    close(fd);
       
  2575 	    zwarnnam(nam, "invalid zwc file: %s" , name, 0);
       
  2576 	    return NULL;
       
  2577 	}
       
  2578 	close(fd);
       
  2579 	return head;
       
  2580     }
       
  2581 }
       
  2582 
       
  2583 /* Swap the bytes in a wordcode. */
       
  2584 
       
  2585 static void
       
  2586 fdswap(Wordcode p, int n)
       
  2587 {
       
  2588     wordcode c;
       
  2589 
       
  2590     for (; n--; p++) {
       
  2591 	c = *p;
       
  2592 	*p = (((c & 0xff) << 24) |
       
  2593 	      ((c & 0xff00) << 8) |
       
  2594 	      ((c & 0xff0000) >> 8) |
       
  2595 	      ((c & 0xff000000) >> 24));
       
  2596     }
       
  2597 }
       
  2598 
       
  2599 /* Write a dump file. */
       
  2600 
       
  2601 static void
       
  2602 write_dump(int dfd, LinkList progs, int map, int hlen, int tlen)
       
  2603 {
       
  2604     LinkNode node;
       
  2605     WCFunc wcf;
       
  2606     int other = 0, ohlen, tmp;
       
  2607     wordcode pre[FD_PRELEN];
       
  2608     char *tail, *n;
       
  2609     struct fdhead head;
       
  2610     Eprog prog;
       
  2611 
       
  2612     if (map == 1)
       
  2613 	map = (tlen >= FD_MINMAP);
       
  2614 
       
  2615     for (ohlen = hlen; ; hlen = ohlen) {
       
  2616 	fdmagic(pre) = (other ? FD_OMAGIC : FD_MAGIC);
       
  2617 	fdsetflags(pre, ((map ? FDF_MAP : 0) | other));
       
  2618 	fdsetother(pre, tlen);
       
  2619 	strcpy(fdversion(pre), ZSH_VERSION);
       
  2620 	write(dfd, pre, FD_PRELEN * sizeof(wordcode));
       
  2621 
       
  2622 	for (node = firstnode(progs); node; incnode(node)) {
       
  2623 	    wcf = (WCFunc) getdata(node);
       
  2624 	    n = wcf->name;
       
  2625 	    prog = wcf->prog;
       
  2626 	    head.start = hlen;
       
  2627 	    hlen += (prog->len - (prog->npats * sizeof(Patprog)) +
       
  2628 		     sizeof(wordcode) - 1) / sizeof(wordcode);
       
  2629 	    head.len = prog->len - (prog->npats * sizeof(Patprog));
       
  2630 	    head.npats = prog->npats;
       
  2631 	    head.strs = prog->strs - ((char *) prog->prog);
       
  2632 	    head.hlen = (sizeof(struct fdhead) / sizeof(wordcode)) +
       
  2633 		(strlen(n) + sizeof(wordcode)) / sizeof(wordcode);
       
  2634 	    if ((tail = strrchr(n, '/')))
       
  2635 		tail++;
       
  2636 	    else
       
  2637 		tail = n;
       
  2638 	    head.flags = fdhbldflags(wcf->flags, (tail - n));
       
  2639 	    if (other)
       
  2640 		fdswap((Wordcode) &head, sizeof(head) / sizeof(wordcode));
       
  2641 	    write(dfd, &head, sizeof(head));
       
  2642 	    tmp = strlen(n) + 1;
       
  2643 	    write(dfd, n, tmp);
       
  2644 	    if ((tmp &= (sizeof(wordcode) - 1)))
       
  2645 		write(dfd, &head, sizeof(wordcode) - tmp);
       
  2646 	}
       
  2647 	for (node = firstnode(progs); node; incnode(node)) {
       
  2648 	    prog = ((WCFunc) getdata(node))->prog;
       
  2649 	    tmp = (prog->len - (prog->npats * sizeof(Patprog)) +
       
  2650 		   sizeof(wordcode) - 1) / sizeof(wordcode);
       
  2651 	    if (other)
       
  2652 		fdswap(prog->prog, (((Wordcode) prog->strs) - prog->prog));
       
  2653 	    write(dfd, prog->prog, tmp * sizeof(wordcode));
       
  2654 	}
       
  2655 	if (other)
       
  2656 	    break;
       
  2657 	other = FDF_OTHER;
       
  2658     }
       
  2659 }
       
  2660 
       
  2661 /**/
       
  2662 static int
       
  2663 build_dump(char *nam, char *dump, char **files, int ali, int map, int flags)
       
  2664 {
       
  2665     int dfd, fd, hlen, tlen, flen, ona = noaliases;
       
  2666     LinkList progs;
       
  2667     char *file;
       
  2668     Eprog prog;
       
  2669     WCFunc wcf;
       
  2670 
       
  2671     if (!strsfx(FD_EXT, dump))
       
  2672 	dump = dyncat(dump, FD_EXT);
       
  2673 
       
  2674     unlink(dump);
       
  2675     if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) {
       
  2676 	zwarnnam(nam, "can't write zwc file: %s", dump, 0);
       
  2677 	return 1;
       
  2678     }
       
  2679     progs = newlinklist();
       
  2680     noaliases = ali;
       
  2681 
       
  2682     for (hlen = FD_PRELEN, tlen = 0; *files; files++) {
       
  2683 	if (!strcmp(*files, "-k")) {
       
  2684 	    flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD;
       
  2685 	    continue;
       
  2686 	} else if (!strcmp(*files, "-z")) {
       
  2687 	    flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD;
       
  2688 	    continue;
       
  2689 	}
       
  2690 	if ((fd = open(*files, O_RDONLY)) < 0 ||
       
  2691 	    (flen = lseek(fd, 0, 2)) == -1) {
       
  2692 	    if (fd >= 0)
       
  2693 		close(fd);
       
  2694 	    close(dfd);
       
  2695 	    zwarnnam(nam, "can't open file: %s", *files, 0);
       
  2696 	    noaliases = ona;
       
  2697 	    unlink(dump);
       
  2698 	    return 1;
       
  2699 	}
       
  2700 	file = (char *) zalloc(flen + 1);
       
  2701 	file[flen] = '\0';
       
  2702 	lseek(fd, 0, 0);
       
  2703 	if (read(fd, file, flen) != flen) {
       
  2704 	    close(fd);
       
  2705 	    close(dfd);
       
  2706 	    zfree(file, flen);
       
  2707 	    zwarnnam(nam, "can't read file: %s", *files, 0);
       
  2708 	    noaliases = ona;
       
  2709 	    unlink(dump);
       
  2710 	    return 1;
       
  2711 	}
       
  2712 	close(fd);
       
  2713 	file = metafy(file, flen, META_REALLOC);
       
  2714 
       
  2715 	if (!(prog = parse_string(file)) || errflag) {
       
  2716 	    errflag = 0;
       
  2717 	    close(dfd);
       
  2718 	    zfree(file, flen);
       
  2719 	    zwarnnam(nam, "can't read file: %s", *files, 0);
       
  2720 	    noaliases = ona;
       
  2721 	    unlink(dump);
       
  2722 	    return 1;
       
  2723 	}
       
  2724 	zfree(file, flen);
       
  2725 
       
  2726 	wcf = (WCFunc) zhalloc(sizeof(*wcf));
       
  2727 	wcf->name = *files;
       
  2728 	wcf->prog = prog;
       
  2729 	wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : flags);
       
  2730 	addlinknode(progs, wcf);
       
  2731 
       
  2732 	flen = (strlen(*files) + sizeof(wordcode)) / sizeof(wordcode);
       
  2733 	hlen += (sizeof(struct fdhead) / sizeof(wordcode)) + flen;
       
  2734 
       
  2735 	tlen += (prog->len - (prog->npats * sizeof(Patprog)) +
       
  2736 		 sizeof(wordcode) - 1) / sizeof(wordcode);
       
  2737     }
       
  2738     noaliases = ona;
       
  2739 
       
  2740     tlen = (tlen + hlen) * sizeof(wordcode);
       
  2741 
       
  2742     write_dump(dfd, progs, map, hlen, tlen);
       
  2743 
       
  2744     close(dfd);
       
  2745 
       
  2746     return 0;
       
  2747 }
       
  2748 
       
  2749 static int
       
  2750 cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
       
  2751 	     int *hlen, int *tlen, int what)
       
  2752 {
       
  2753     Eprog prog;
       
  2754     WCFunc wcf;
       
  2755 
       
  2756     if (shf->flags & PM_UNDEFINED) {
       
  2757 	int ona = noaliases;
       
  2758 
       
  2759 	if (!(what & 2)) {
       
  2760 	    zwarnnam(nam, "function is not loaded: %s", shf->nam, 0);
       
  2761 	    return 1;
       
  2762 	}
       
  2763 	noaliases = (shf->flags & PM_UNALIASED);
       
  2764 	if (!(prog = getfpfunc(shf->nam, NULL)) || prog == &dummy_eprog) {
       
  2765 	    noaliases = ona;
       
  2766 	    zwarnnam(nam, "can't load function: %s", shf->nam, 0);
       
  2767 	    return 1;
       
  2768 	}
       
  2769 	if (prog->dump)
       
  2770 	    prog = dupeprog(prog, 1);
       
  2771 	noaliases = ona;
       
  2772     } else {
       
  2773 	if (!(what & 1)) {
       
  2774 	    zwarnnam(nam, "function is already loaded: %s", shf->nam, 0);
       
  2775 	    return 1;
       
  2776 	}
       
  2777 	prog = dupeprog(shf->funcdef, 1);
       
  2778     }
       
  2779     wcf = (WCFunc) zhalloc(sizeof(*wcf));
       
  2780     wcf->name = shf->nam;
       
  2781     wcf->prog = prog;
       
  2782     wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : FDHF_ZSHLOAD);
       
  2783     addlinknode(progs, wcf);
       
  2784     addlinknode(names, shf->nam);
       
  2785 
       
  2786     *hlen += ((sizeof(struct fdhead) / sizeof(wordcode)) +
       
  2787 	      ((strlen(shf->nam) + sizeof(wordcode)) / sizeof(wordcode)));
       
  2788     *tlen += (prog->len - (prog->npats * sizeof(Patprog)) +
       
  2789 	      sizeof(wordcode) - 1) / sizeof(wordcode);
       
  2790 
       
  2791     return 0;
       
  2792 }
       
  2793 
       
  2794 /**/
       
  2795 static int
       
  2796 build_cur_dump(char *nam, char *dump, char **names, int match, int map,
       
  2797 	       int what)
       
  2798 {
       
  2799     int dfd, hlen, tlen;
       
  2800     LinkList progs, lnames;
       
  2801     Shfunc shf = NULL;
       
  2802 
       
  2803     if (!strsfx(FD_EXT, dump))
       
  2804 	dump = dyncat(dump, FD_EXT);
       
  2805 
       
  2806     unlink(dump);
       
  2807     if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) {
       
  2808 	zwarnnam(nam, "can't write zwc file: %s", dump, 0);
       
  2809 	return 1;
       
  2810     }
       
  2811     progs = newlinklist();
       
  2812     lnames = newlinklist();
       
  2813 
       
  2814     hlen = FD_PRELEN;
       
  2815     tlen = 0;
       
  2816 
       
  2817     if (!*names) {
       
  2818 	int i;
       
  2819 	HashNode hn;
       
  2820 
       
  2821 	for (i = 0; i < shfunctab->hsize; i++)
       
  2822 	    for (hn = shfunctab->nodes[i]; hn; hn = hn->next)
       
  2823 		if (cur_add_func(nam, (Shfunc) hn, lnames, progs,
       
  2824 				 &hlen, &tlen, what)) {
       
  2825 		    errflag = 0;
       
  2826 		    close(dfd);
       
  2827 		    unlink(dump);
       
  2828 		    return 1;
       
  2829 		}
       
  2830     } else if (match) {
       
  2831 	char *pat;
       
  2832 	Patprog pprog;
       
  2833 	int i;
       
  2834 	HashNode hn;
       
  2835 
       
  2836 	for (; *names; names++) {
       
  2837 	    tokenize(pat = dupstring(*names));
       
  2838 	    if (!(pprog = patcompile(pat, PAT_STATIC, NULL))) {
       
  2839 		zwarnnam(nam, "bad pattern: %s", *names, 0);
       
  2840 		close(dfd);
       
  2841 		unlink(dump);
       
  2842 		return 1;
       
  2843 	    }
       
  2844 	    for (i = 0; i < shfunctab->hsize; i++)
       
  2845 		for (hn = shfunctab->nodes[i]; hn; hn = hn->next)
       
  2846 		    if (!listcontains(lnames, hn->nam) &&
       
  2847 			pattry(pprog, hn->nam) &&
       
  2848 			cur_add_func(nam, (Shfunc) hn, lnames, progs,
       
  2849 				     &hlen, &tlen, what)) {
       
  2850 			errflag = 0;
       
  2851 			close(dfd);
       
  2852 			unlink(dump);
       
  2853 			return 1;
       
  2854 		    }
       
  2855 	}
       
  2856     } else {
       
  2857 	for (; *names; names++) {
       
  2858 	    if (errflag ||
       
  2859 		!(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) {
       
  2860 		zwarnnam(nam, "unknown function: %s", *names, 0);
       
  2861 		errflag = 0;
       
  2862 		close(dfd);
       
  2863 		unlink(dump);
       
  2864 		return 1;
       
  2865 	    }
       
  2866 	    if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) {
       
  2867 		errflag = 0;
       
  2868 		close(dfd);
       
  2869 		unlink(dump);
       
  2870 		return 1;
       
  2871 	    }
       
  2872 	}
       
  2873     }
       
  2874     if (empty(progs)) {
       
  2875 	zwarnnam(nam, "no functions", NULL, 0);
       
  2876 	errflag = 0;
       
  2877 	close(dfd);
       
  2878 	unlink(dump);
       
  2879 	return 1;
       
  2880     }
       
  2881     tlen = (tlen + hlen) * sizeof(wordcode);
       
  2882 
       
  2883     write_dump(dfd, progs, map, hlen, tlen);
       
  2884 
       
  2885     close(dfd);
       
  2886 
       
  2887     return 0;
       
  2888 }
       
  2889 
       
  2890 #if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
       
  2891 
       
  2892 #include <sys/mman.h>
       
  2893 
       
  2894 #if defined(MAP_SHARED) && defined(PROT_READ)
       
  2895 
       
  2896 #define USE_MMAP 1
       
  2897 
       
  2898 #endif
       
  2899 #endif
       
  2900 
       
  2901 #ifdef USE_MMAP
       
  2902 
       
  2903 /* List of dump files mapped. */
       
  2904 
       
  2905 static FuncDump dumps;
       
  2906 
       
  2907 /**/
       
  2908 static int
       
  2909 zwcstat(char *filename, struct stat *buf, FuncDump dumps)
       
  2910 {
       
  2911     if (stat(filename, buf)) {
       
  2912 #ifdef HAVE_FSTAT
       
  2913         FuncDump f;
       
  2914     
       
  2915 	for (f = dumps; f; f = f->next) {
       
  2916 	    if (!strncmp(filename, f->filename, strlen(f->filename)) &&
       
  2917 		!fstat(f->fd, buf))
       
  2918 		return 0;
       
  2919 	}
       
  2920 #endif
       
  2921 	return 1;
       
  2922     } else return 0;
       
  2923 }
       
  2924 
       
  2925 /* Load a dump file (i.e. map it). */
       
  2926 
       
  2927 static void
       
  2928 load_dump_file(char *dump, struct stat *sbuf, int other, int len)
       
  2929 {
       
  2930     FuncDump d;
       
  2931     Wordcode addr;
       
  2932     int fd, off, mlen;
       
  2933 
       
  2934     if (other) {
       
  2935 	static size_t pgsz = 0;
       
  2936 
       
  2937 	if (!pgsz) {
       
  2938 
       
  2939 #ifdef _SC_PAGESIZE
       
  2940 	    pgsz = sysconf(_SC_PAGESIZE);     /* SVR4 */
       
  2941 #else
       
  2942 # ifdef _SC_PAGE_SIZE
       
  2943 	    pgsz = sysconf(_SC_PAGE_SIZE);    /* HPUX */
       
  2944 # else
       
  2945 	    pgsz = getpagesize();
       
  2946 # endif
       
  2947 #endif
       
  2948 
       
  2949 	    pgsz--;
       
  2950 	}
       
  2951 	off = len & ~pgsz;
       
  2952         mlen = len + (len - off);
       
  2953     } else {
       
  2954 	off = 0;
       
  2955         mlen = len;
       
  2956     }
       
  2957     if ((fd = open(dump, O_RDONLY)) < 0)
       
  2958 	return;
       
  2959 
       
  2960     fd = movefd(fd);
       
  2961 
       
  2962     if ((addr = (Wordcode) mmap(NULL, mlen, PROT_READ, MAP_SHARED, fd, off)) ==
       
  2963 	((Wordcode) -1)) {
       
  2964 	close(fd);
       
  2965 	return;
       
  2966     }
       
  2967     d = (FuncDump) zalloc(sizeof(*d));
       
  2968     d->next = dumps;
       
  2969     dumps = d;
       
  2970     d->dev = sbuf->st_dev;
       
  2971     d->ino = sbuf->st_ino;
       
  2972     d->fd = fd;
       
  2973     d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0);
       
  2974     d->addr = addr;
       
  2975     d->len = len;
       
  2976     d->count = 0;
       
  2977     d->filename = ztrdup(dump);
       
  2978 }
       
  2979 
       
  2980 #else
       
  2981 
       
  2982 #define zwcstat(f, b, d) stat(f, b)
       
  2983 
       
  2984 #endif
       
  2985 
       
  2986 /* Try to load a function from one of the possible wordcode files for it.
       
  2987  * The first argument is a element of $fpath, the second one is the name
       
  2988  * of the function searched and the last one is the possible name for the
       
  2989  * uncompiled function file (<path>/<func>). */
       
  2990 
       
  2991 /**/
       
  2992 Eprog
       
  2993 try_dump_file(char *path, char *name, char *file, int *ksh)
       
  2994 {
       
  2995     Eprog prog;
       
  2996     struct stat std, stc, stn;
       
  2997     int rd, rc, rn;
       
  2998     char *dig, *wc;
       
  2999 
       
  3000     if (strsfx(FD_EXT, path)) {
       
  3001 	queue_signals();
       
  3002 	prog = check_dump_file(path, NULL, name, ksh);
       
  3003 	unqueue_signals();
       
  3004 	return prog;
       
  3005     }
       
  3006     dig = dyncat(path, FD_EXT);
       
  3007     wc = dyncat(file, FD_EXT);
       
  3008 
       
  3009     rd = zwcstat(dig, &std, dumps);
       
  3010     rc = stat(wc, &stc);
       
  3011     rn = stat(file, &stn);
       
  3012 
       
  3013     /* See if there is a digest file for the directory, it is younger than
       
  3014      * both the uncompiled function file and its compiled version (or they
       
  3015      * don't exist) and the digest file contains the definition for the
       
  3016      * function. */
       
  3017     queue_signals();
       
  3018     if (!rd &&
       
  3019 	(rc || std.st_mtime > stc.st_mtime) &&
       
  3020 	(rn || std.st_mtime > stn.st_mtime) &&
       
  3021 	(prog = check_dump_file(dig, &std, name, ksh))) {
       
  3022 	unqueue_signals();
       
  3023 	return prog;
       
  3024     }
       
  3025     /* No digest file. Now look for the per-function compiled file. */
       
  3026     if (!rc &&
       
  3027 	(rn || stc.st_mtime > stn.st_mtime) &&
       
  3028 	(prog = check_dump_file(wc, &stc, name, ksh))) {
       
  3029 	unqueue_signals();
       
  3030 	return prog;
       
  3031     }
       
  3032     /* No compiled file for the function. The caller (getfpfunc() will
       
  3033      * check if the directory contains the uncompiled file for it. */
       
  3034     unqueue_signals();
       
  3035     return NULL;
       
  3036 }
       
  3037 
       
  3038 /* Almost the same, but for sourced files. */
       
  3039 
       
  3040 /**/
       
  3041 Eprog
       
  3042 try_source_file(char *file)
       
  3043 {
       
  3044     Eprog prog;
       
  3045     struct stat stc, stn;
       
  3046     int rc, rn;
       
  3047     char *wc, *tail;
       
  3048 
       
  3049     if ((tail = strrchr(file, '/')) || (tail = strrchr(file, '\\')))
       
  3050 	tail++;
       
  3051     else
       
  3052 	tail = file;
       
  3053 
       
  3054     if (strsfx(FD_EXT, file)) {
       
  3055 	queue_signals();
       
  3056 	prog = check_dump_file(file, NULL, tail, NULL);
       
  3057 	unqueue_signals();
       
  3058 	return prog;
       
  3059     }
       
  3060     wc = dyncat(file, FD_EXT);
       
  3061 
       
  3062     rc = stat(wc, &stc);
       
  3063     rn = stat(file, &stn);
       
  3064 
       
  3065     queue_signals();
       
  3066     if (!rc && (rn || stc.st_mtime > stn.st_mtime) &&
       
  3067 	(prog = check_dump_file(wc, &stc, tail, NULL))) {
       
  3068 	unqueue_signals();
       
  3069 	return prog;
       
  3070     }
       
  3071     unqueue_signals();
       
  3072     return NULL;
       
  3073 }
       
  3074 
       
  3075 /* See if `file' names a wordcode dump file and that contains the
       
  3076  * definition for the function `name'. If so, return an eprog for it. */
       
  3077 
       
  3078 /**/
       
  3079 static Eprog
       
  3080 check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
       
  3081 {
       
  3082     int isrec = 0;
       
  3083     Wordcode d;
       
  3084     FDHead h;
       
  3085     FuncDump f;
       
  3086     struct stat lsbuf;
       
  3087 
       
  3088     if (!sbuf) {
       
  3089 	if (zwcstat(file, &lsbuf, dumps))
       
  3090 	    return NULL;
       
  3091 	sbuf = &lsbuf;
       
  3092     }
       
  3093 
       
  3094 #ifdef USE_MMAP
       
  3095 
       
  3096  rec:
       
  3097 
       
  3098 #endif
       
  3099 
       
  3100     d = NULL;
       
  3101 
       
  3102 #ifdef USE_MMAP
       
  3103 
       
  3104     for (f = dumps; f; f = f->next)
       
  3105 	if (f->dev == sbuf->st_dev && f->ino == sbuf->st_ino) {
       
  3106 	    d = f->map;
       
  3107 	    break;
       
  3108 	}
       
  3109 
       
  3110 #else
       
  3111 
       
  3112     f = NULL;
       
  3113 
       
  3114 #endif
       
  3115 
       
  3116     if (!f && (isrec || !(d = load_dump_header(NULL, file, 0))))
       
  3117 	return NULL;
       
  3118 
       
  3119     if ((h = dump_find_func(d, name))) {
       
  3120 	/* Found the name. If the file is already mapped, return the eprog,
       
  3121 	 * otherwise map it and just go up. */
       
  3122 
       
  3123 #ifdef USE_MMAP
       
  3124 
       
  3125 	if (f) {
       
  3126 	    Eprog prog = (Eprog) zalloc(sizeof(*prog));
       
  3127 	    Patprog *pp;
       
  3128 	    int np;
       
  3129 
       
  3130 	    prog->flags = EF_MAP;
       
  3131 	    prog->len = h->len;
       
  3132 	    prog->npats = np = h->npats;
       
  3133 	    prog->nref = 1;	/* allocated from permanent storage */
       
  3134 	    prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog));
       
  3135 	    prog->prog = f->map + h->start;
       
  3136 	    prog->strs = ((char *) prog->prog) + h->strs;
       
  3137 	    prog->shf = NULL;
       
  3138 	    prog->dump = f;
       
  3139 
       
  3140 	    incrdumpcount(f);
       
  3141 
       
  3142 	    while (np--)
       
  3143 		*pp++ = dummy_patprog1;
       
  3144 
       
  3145 	    if (ksh)
       
  3146 		*ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 :
       
  3147 			((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1));
       
  3148 
       
  3149 	    return prog;
       
  3150 	} else if (fdflags(d) & FDF_MAP) {
       
  3151 	    load_dump_file(file, sbuf, (fdflags(d) & FDF_OTHER), fdother(d));
       
  3152 	    isrec = 1;
       
  3153 	    goto rec;
       
  3154 	} else
       
  3155 
       
  3156 #endif
       
  3157 
       
  3158 	    {
       
  3159 	    Eprog prog;
       
  3160 	    Patprog *pp;
       
  3161 	    int np, fd, po = h->npats * sizeof(Patprog);
       
  3162 
       
  3163 	    if ((fd = open(file, O_RDONLY)) < 0 ||
       
  3164 		lseek(fd, ((h->start * sizeof(wordcode)) +
       
  3165 			   ((fdflags(d) & FDF_OTHER) ? fdother(d) : 0)), 0) < 0) {
       
  3166 		if (fd >= 0)
       
  3167 		    close(fd);
       
  3168 		return NULL;
       
  3169 	    }
       
  3170 	    d = (Wordcode) zalloc(h->len + po);
       
  3171 
       
  3172 	    if (read(fd, ((char *) d) + po, h->len) != (int)h->len) {
       
  3173 		close(fd);
       
  3174 		zfree(d, h->len);
       
  3175 
       
  3176 		return NULL;
       
  3177 	    }
       
  3178 	    close(fd);
       
  3179 
       
  3180 	    prog = (Eprog) zalloc(sizeof(*prog));
       
  3181 
       
  3182 	    prog->flags = EF_REAL;
       
  3183 	    prog->len = h->len + po;
       
  3184 	    prog->npats = np = h->npats;
       
  3185 	    prog->nref = 1; /* allocated from permanent storage */
       
  3186 	    prog->pats = pp = (Patprog *) d;
       
  3187 	    prog->prog = (Wordcode) (((char *) d) + po);
       
  3188 	    prog->strs = ((char *) prog->prog) + h->strs;
       
  3189 	    prog->shf = NULL;
       
  3190 	    prog->dump = f;
       
  3191 
       
  3192 	    while (np--)
       
  3193 		*pp++ = dummy_patprog1;
       
  3194 
       
  3195 	    if (ksh)
       
  3196 		*ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 :
       
  3197 			((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1));
       
  3198 
       
  3199 	    return prog;
       
  3200 	}
       
  3201     }
       
  3202     return NULL;
       
  3203 }
       
  3204 
       
  3205 #ifdef USE_MMAP
       
  3206 
       
  3207 /* Increment the reference counter for a dump file. */
       
  3208 
       
  3209 /**/
       
  3210 void
       
  3211 incrdumpcount(FuncDump f)
       
  3212 {
       
  3213     f->count++;
       
  3214 }
       
  3215 
       
  3216 /* Decrement the reference counter for a dump file. If zero, unmap the file. */
       
  3217 
       
  3218 /**/
       
  3219 void
       
  3220 decrdumpcount(FuncDump f)
       
  3221 {
       
  3222     f->count--;
       
  3223     if (!f->count) {
       
  3224 	FuncDump p, q;
       
  3225 
       
  3226 	for (q = NULL, p = dumps; p && p != f; q = p, p = p->next);
       
  3227 	if (p) {
       
  3228 	    if (q)
       
  3229 		q->next = p->next;
       
  3230 	    else
       
  3231 		dumps = p->next;
       
  3232 	    munmap((void *) f->addr, f->len);
       
  3233 	    zclose(f->fd);
       
  3234 	    zsfree(f->filename);
       
  3235 	    zfree(f, sizeof(*f));
       
  3236 	}
       
  3237     }
       
  3238 }
       
  3239 
       
  3240 /**/
       
  3241 mod_export void
       
  3242 closedumps(void)
       
  3243 {
       
  3244     FuncDump p;
       
  3245 
       
  3246     for (p = dumps; p; p = p->next)
       
  3247 	zclose(p->fd);
       
  3248 }
       
  3249 
       
  3250 #else
       
  3251 
       
  3252 void
       
  3253 incrdumpcount(FuncDump f)
       
  3254 {
       
  3255 }
       
  3256 
       
  3257 void
       
  3258 decrdumpcount(FuncDump f)
       
  3259 {
       
  3260 }
       
  3261 
       
  3262 /**/
       
  3263 mod_export void
       
  3264 closedumps(void)
       
  3265 {
       
  3266 }
       
  3267 
       
  3268 #endif
       
  3269 
       
  3270 /**/
       
  3271 int
       
  3272 dump_autoload(char *nam, char *file, int on, Options ops, int func)
       
  3273 {
       
  3274     Wordcode h;
       
  3275     FDHead n, e;
       
  3276     Shfunc shf;
       
  3277     int ret = 0;
       
  3278 
       
  3279     if (!strsfx(FD_EXT, file))
       
  3280 	file = dyncat(file, FD_EXT);
       
  3281 
       
  3282     if (!(h = load_dump_header(nam, file, 1)))
       
  3283 	return 1;
       
  3284 
       
  3285     for (n = firstfdhead(h), e = (FDHead) (h + fdheaderlen(h)); n < e;
       
  3286 	 n = nextfdhead(n)) {
       
  3287 	shf = (Shfunc) zshcalloc(sizeof *shf);
       
  3288 	shf->flags = on;
       
  3289 	shf->funcdef = mkautofn(shf);
       
  3290 	shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf);
       
  3291 	if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->nam, ops, func))
       
  3292 	    ret = 1;
       
  3293     }
       
  3294     return ret;
       
  3295 }
       
  3296