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