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