• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011
5  *	Thorsten Glaser <tg@mirbsd.org>
6  *
7  * Provided that these terms and disclaimer and all copyright notices
8  * are retained or reproduced in an accompanying document, permission
9  * is granted to deal in this work without restriction, including un-
10  * limited rights to use, publicly perform, distribute, sell, modify,
11  * merge, give away, or sublicence.
12  *
13  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14  * the utmost extent permitted by applicable law, neither express nor
15  * implied; without malicious intent or gross negligence. In no event
16  * may a licensor, author or contributor be held liable for indirect,
17  * direct, other damage, loss, or other issues arising in any way out
18  * of dealing in the work, even if advised of the possibility of such
19  * damage or existence of a defect, except proven that it results out
20  * of said person's immediate fault when using the work as intended.
21  */
22 
23 #include "sh.h"
24 
25 __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.69 2011/09/07 15:24:21 tg Exp $");
26 
27 extern short subshell_nesting_level;
28 extern void yyskiputf8bom(void);
29 
30 struct nesting_state {
31 	int start_token;	/* token than began nesting (eg, FOR) */
32 	int start_line;		/* line nesting began on */
33 };
34 
35 static void yyparse(void);
36 static struct op *pipeline(int);
37 static struct op *andor(void);
38 static struct op *c_list(bool);
39 static struct ioword *synio(int);
40 static struct op *nested(int, int, int);
41 static struct op *get_command(int);
42 static struct op *dogroup(void);
43 static struct op *thenpart(void);
44 static struct op *elsepart(void);
45 static struct op *caselist(void);
46 static struct op *casepart(int);
47 static struct op *function_body(char *, bool);
48 static char **wordlist(void);
49 static struct op *block(int, struct op *, struct op *, char **);
50 static struct op *newtp(int);
51 static void syntaxerr(const char *) MKSH_A_NORETURN;
52 static void nesting_push(struct nesting_state *, int);
53 static void nesting_pop(struct nesting_state *);
54 static int assign_command(char *);
55 static int inalias(struct source *);
56 static Test_op dbtestp_isa(Test_env *, Test_meta);
57 static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
58 static int dbtestp_eval(Test_env *, Test_op, const char *,
59     const char *, bool);
60 static void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN;
61 
62 static struct op *outtree;		/* yyparse output */
63 static struct nesting_state nesting;	/* \n changed to ; */
64 
65 static bool reject;			/* token(cf) gets symbol again */
66 static int symbol;			/* yylex value */
67 
68 #define REJECT		(reject = true)
69 #define ACCEPT		(reject = false)
70 #define token(cf)	((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
71 #define tpeek(cf)	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
72 #define musthave(c,cf)	do { if (token(cf) != (c)) syntaxerr(NULL); } while (/* CONSTCOND */ 0)
73 
74 static void
yyparse(void)75 yyparse(void)
76 {
77 	int c;
78 
79 	ACCEPT;
80 
81 	outtree = c_list(source->type == SSTRING);
82 	c = tpeek(0);
83 	if (c == 0 && !outtree)
84 		outtree = newtp(TEOF);
85 	else if (c != '\n' && c != 0)
86 		syntaxerr(NULL);
87 }
88 
89 static struct op *
pipeline(int cf)90 pipeline(int cf)
91 {
92 	struct op *t, *p, *tl = NULL;
93 
94 	t = get_command(cf);
95 	if (t != NULL) {
96 		while (token(0) == '|') {
97 			if ((p = get_command(CONTIN)) == NULL)
98 				syntaxerr(NULL);
99 			if (tl == NULL)
100 				t = tl = block(TPIPE, t, p, NOWORDS);
101 			else
102 				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
103 		}
104 		REJECT;
105 	}
106 	return (t);
107 }
108 
109 static struct op *
andor(void)110 andor(void)
111 {
112 	struct op *t, *p;
113 	int c;
114 
115 	t = pipeline(0);
116 	if (t != NULL) {
117 		while ((c = token(0)) == LOGAND || c == LOGOR) {
118 			if ((p = pipeline(CONTIN)) == NULL)
119 				syntaxerr(NULL);
120 			t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
121 		}
122 		REJECT;
123 	}
124 	return (t);
125 }
126 
127 static struct op *
c_list(bool multi)128 c_list(bool multi)
129 {
130 	struct op *t = NULL, *p, *tl = NULL;
131 	int c;
132 	bool have_sep;
133 
134 	while (/* CONSTCOND */ 1) {
135 		p = andor();
136 		/*
137 		 * Token has always been read/rejected at this point, so
138 		 * we don't worry about what flags to pass token()
139 		 */
140 		c = token(0);
141 		have_sep = true;
142 		if (c == '\n' && (multi || inalias(source))) {
143 			if (!p)
144 				/* ignore blank lines */
145 				continue;
146 		} else if (!p)
147 			break;
148 		else if (c == '&' || c == COPROC)
149 			p = block(c == '&' ? TASYNC : TCOPROC,
150 			    p, NOBLOCK, NOWORDS);
151 		else if (c != ';')
152 			have_sep = false;
153 		if (!t)
154 			t = p;
155 		else if (!tl)
156 			t = tl = block(TLIST, t, p, NOWORDS);
157 		else
158 			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
159 		if (!have_sep)
160 			break;
161 	}
162 	REJECT;
163 	return (t);
164 }
165 
166 static struct ioword *
synio(int cf)167 synio(int cf)
168 {
169 	struct ioword *iop;
170 	static struct ioword *nextiop;
171 	bool ishere;
172 
173 	if (nextiop != NULL) {
174 		iop = nextiop;
175 		nextiop = NULL;
176 		return (iop);
177 	}
178 
179 	if (tpeek(cf) != REDIR)
180 		return (NULL);
181 	ACCEPT;
182 	iop = yylval.iop;
183 	if (iop->flag & IONDELIM)
184 		goto gotnulldelim;
185 	ishere = (iop->flag & IOTYPE) == IOHERE;
186 	musthave(LWORD, ishere ? HEREDELIM : 0);
187 	if (ishere) {
188 		iop->delim = yylval.cp;
189 		if (*ident != 0)
190 			/* unquoted */
191  gotnulldelim:
192 			iop->flag |= IOEVAL;
193 		if (herep > &heres[HERES - 1])
194 			yyerror("too many %ss\n", "<<");
195 		*herep++ = iop;
196 	} else
197 		iop->name = yylval.cp;
198 
199 	if (iop->flag & IOBASH) {
200 		char *cp;
201 
202 		nextiop = alloc(sizeof(*iop), ATEMP);
203 		nextiop->name = cp = alloc(5, ATEMP);
204 
205 		if (iop->unit > 9) {
206 			*cp++ = CHAR;
207 			*cp++ = '0' + (iop->unit / 10);
208 		}
209 		*cp++ = CHAR;
210 		*cp++ = '0' + (iop->unit % 10);
211 		*cp = EOS;
212 
213 		iop->flag &= ~IOBASH;
214 		nextiop->unit = 2;
215 		nextiop->flag = IODUP;
216 		nextiop->delim = NULL;
217 		nextiop->heredoc = NULL;
218 	}
219 	return (iop);
220 }
221 
222 static struct op *
nested(int type,int smark,int emark)223 nested(int type, int smark, int emark)
224 {
225 	struct op *t;
226 	struct nesting_state old_nesting;
227 
228 	nesting_push(&old_nesting, smark);
229 	t = c_list(true);
230 	musthave(emark, KEYWORD|ALIAS);
231 	nesting_pop(&old_nesting);
232 	return (block(type, t, NOBLOCK, NOWORDS));
233 }
234 
235 static struct op *
get_command(int cf)236 get_command(int cf)
237 {
238 	struct op *t;
239 	int c, iopn = 0, syniocf;
240 	struct ioword *iop, **iops;
241 	XPtrV args, vars;
242 	struct nesting_state old_nesting;
243 
244 	/* NUFILE is small enough to leave this addition unchecked */
245 	iops = alloc2((NUFILE + 1), sizeof(struct ioword *), ATEMP);
246 	XPinit(args, 16);
247 	XPinit(vars, 16);
248 
249 	syniocf = KEYWORD|ALIAS;
250 	switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
251 	default:
252 		REJECT;
253 		afree(iops, ATEMP);
254 		XPfree(args);
255 		XPfree(vars);
256 		/* empty line */
257 		return (NULL);
258 
259 	case LWORD:
260 	case REDIR:
261 		REJECT;
262 		syniocf &= ~(KEYWORD|ALIAS);
263 		t = newtp(TCOM);
264 		t->lineno = source->line;
265 		while (/* CONSTCOND */ 1) {
266 			cf = (t->u.evalflags ? ARRAYVAR : 0) |
267 			    (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
268 			switch (tpeek(cf)) {
269 			case REDIR:
270 				while ((iop = synio(cf)) != NULL) {
271 					if (iopn >= NUFILE)
272 						yyerror("too many %ss\n",
273 						    "redirection");
274 					iops[iopn++] = iop;
275 				}
276 				break;
277 
278 			case LWORD:
279 				ACCEPT;
280 				/*
281 				 * the iopn == 0 and XPsize(vars) == 0 are
282 				 * dubious but AT&T ksh acts this way
283 				 */
284 				if (iopn == 0 && XPsize(vars) == 0 &&
285 				    XPsize(args) == 0 &&
286 				    assign_command(ident))
287 					t->u.evalflags = DOVACHECK;
288 				if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
289 				    is_wdvarassign(yylval.cp))
290 					XPput(vars, yylval.cp);
291 				else
292 					XPput(args, yylval.cp);
293 				break;
294 
295 			case '(':
296 #ifndef MKSH_SMALL
297 				if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
298 				    XPsize(vars) == 1 && is_wdvarassign(yylval.cp))
299 					goto is_wdarrassign;
300 #endif
301 				/*
302 				 * Check for "> foo (echo hi)" which AT&T ksh
303 				 * allows (not POSIX, but not disallowed)
304 				 */
305 				afree(t, ATEMP);
306 				if (XPsize(args) == 0 && XPsize(vars) == 0) {
307 					ACCEPT;
308 					goto Subshell;
309 				}
310 
311 				/* must be a function */
312 				if (iopn != 0 || XPsize(args) != 1 ||
313 				    XPsize(vars) != 0)
314 					syntaxerr(NULL);
315 				ACCEPT;
316 				musthave(/*(*/')', 0);
317 				t = function_body(XPptrv(args)[0], false);
318 				goto Leave;
319 #ifndef MKSH_SMALL
320  is_wdarrassign:
321 			{
322 				static const char set_cmd0[] = {
323 					CHAR, 's', CHAR, 'e',
324 					CHAR, 't', EOS
325 				};
326 				static const char set_cmd1[] = {
327 					CHAR, '-', CHAR, 'A', EOS
328 				};
329 				static const char set_cmd2[] = {
330 					CHAR, '-', CHAR, '-', EOS
331 				};
332 				char *tcp;
333 
334 				ACCEPT;
335 
336 				/* manipulate the vars string */
337 				tcp = *(--vars.cur);
338 				/* 'varname=' -> 'varname' */
339 				tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
340 
341 				/* construct new args strings */
342 				XPput(args, wdcopy(set_cmd0, ATEMP));
343 				XPput(args, wdcopy(set_cmd1, ATEMP));
344 				XPput(args, tcp);
345 				XPput(args, wdcopy(set_cmd2, ATEMP));
346 
347 				/* slurp in words till closing paren */
348 				while (token(CONTIN) == LWORD)
349 					XPput(args, yylval.cp);
350 				if (symbol != /*(*/ ')')
351 					syntaxerr(NULL);
352 
353 				goto Leave;
354 			}
355 #endif
356 
357 			default:
358 				goto Leave;
359 			}
360 		}
361  Leave:
362 		break;
363 
364 	case '(':
365  Subshell:
366 		++subshell_nesting_level;
367 		t = nested(TPAREN, '(', ')');
368 		--subshell_nesting_level;
369 		break;
370 
371 	case '{': /*}*/
372 		t = nested(TBRACE, '{', '}');
373 		break;
374 
375 	case MDPAREN: {
376 		int lno;
377 		static const char let_cmd[] = {
378 			CHAR, 'l', CHAR, 'e',
379 			CHAR, 't', EOS
380 		};
381 
382 		/* leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
383 		lno = source->line;
384 		ACCEPT;
385 		switch (token(LETEXPR)) {
386 		case LWORD:
387 			break;
388 		case '(': /*)*/
389 			goto Subshell;
390 		default:
391 			syntaxerr(NULL);
392 		}
393 		t = newtp(TCOM);
394 		t->lineno = lno;
395 		XPput(args, wdcopy(let_cmd, ATEMP));
396 		XPput(args, yylval.cp);
397 		break;
398 	}
399 
400 	case DBRACKET: /* [[ .. ]] */
401 		/* leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
402 		t = newtp(TDBRACKET);
403 		ACCEPT;
404 		{
405 			Test_env te;
406 
407 			te.flags = TEF_DBRACKET;
408 			te.pos.av = &args;
409 			te.isa = dbtestp_isa;
410 			te.getopnd = dbtestp_getopnd;
411 			te.eval = dbtestp_eval;
412 			te.error = dbtestp_error;
413 
414 			test_parse(&te);
415 		}
416 		break;
417 
418 	case FOR:
419 	case SELECT:
420 		t = newtp((c == FOR) ? TFOR : TSELECT);
421 		musthave(LWORD, ARRAYVAR);
422 		if (!is_wdvarname(yylval.cp, true))
423 			yyerror("%s: %s\n", c == FOR ? "for" : Tselect,
424 			    "bad identifier");
425 		strdupx(t->str, ident, ATEMP);
426 		nesting_push(&old_nesting, c);
427 		t->vars = wordlist();
428 		t->left = dogroup();
429 		nesting_pop(&old_nesting);
430 		break;
431 
432 	case WHILE:
433 	case UNTIL:
434 		nesting_push(&old_nesting, c);
435 		t = newtp((c == WHILE) ? TWHILE : TUNTIL);
436 		t->left = c_list(true);
437 		t->right = dogroup();
438 		nesting_pop(&old_nesting);
439 		break;
440 
441 	case CASE:
442 		t = newtp(TCASE);
443 		musthave(LWORD, 0);
444 		t->str = yylval.cp;
445 		nesting_push(&old_nesting, c);
446 		t->left = caselist();
447 		nesting_pop(&old_nesting);
448 		break;
449 
450 	case IF:
451 		nesting_push(&old_nesting, c);
452 		t = newtp(TIF);
453 		t->left = c_list(true);
454 		t->right = thenpart();
455 		musthave(FI, KEYWORD|ALIAS);
456 		nesting_pop(&old_nesting);
457 		break;
458 
459 	case BANG:
460 		syniocf &= ~(KEYWORD|ALIAS);
461 		t = pipeline(0);
462 		if (t == NULL)
463 			syntaxerr(NULL);
464 		t = block(TBANG, NOBLOCK, t, NOWORDS);
465 		break;
466 
467 	case TIME:
468 		syniocf &= ~(KEYWORD|ALIAS);
469 		t = pipeline(0);
470 		if (t) {
471 			t->str = alloc(2, ATEMP);
472 			/* TF_* flags */
473 			t->str[0] = '\0';
474 			t->str[1] = '\0';
475 		}
476 		t = block(TTIME, t, NOBLOCK, NOWORDS);
477 		break;
478 
479 	case FUNCTION:
480 		musthave(LWORD, 0);
481 		t = function_body(yylval.cp, true);
482 		break;
483 	}
484 
485 	while ((iop = synio(syniocf)) != NULL) {
486 		if (iopn >= NUFILE)
487 			yyerror("too many %ss\n", "redirection");
488 		iops[iopn++] = iop;
489 	}
490 
491 	if (iopn == 0) {
492 		afree(iops, ATEMP);
493 		t->ioact = NULL;
494 	} else {
495 		iops[iopn++] = NULL;
496 		iops = aresize2(iops, iopn, sizeof(struct ioword *), ATEMP);
497 		t->ioact = iops;
498 	}
499 
500 	if (t->type == TCOM || t->type == TDBRACKET) {
501 		XPput(args, NULL);
502 		t->args = (const char **)XPclose(args);
503 		XPput(vars, NULL);
504 		t->vars = (char **) XPclose(vars);
505 	} else {
506 		XPfree(args);
507 		XPfree(vars);
508 	}
509 
510 	return (t);
511 }
512 
513 static struct op *
dogroup(void)514 dogroup(void)
515 {
516 	int c;
517 	struct op *list;
518 
519 	c = token(CONTIN|KEYWORD|ALIAS);
520 	/*
521 	 * A {...} can be used instead of do...done for for/select loops
522 	 * but not for while/until loops - we don't need to check if it
523 	 * is a while loop because it would have been parsed as part of
524 	 * the conditional command list...
525 	 */
526 	if (c == DO)
527 		c = DONE;
528 	else if (c == '{')
529 		c = '}';
530 	else
531 		syntaxerr(NULL);
532 	list = c_list(true);
533 	musthave(c, KEYWORD|ALIAS);
534 	return (list);
535 }
536 
537 static struct op *
thenpart(void)538 thenpart(void)
539 {
540 	struct op *t;
541 
542 	musthave(THEN, KEYWORD|ALIAS);
543 	t = newtp(0);
544 	t->left = c_list(true);
545 	if (t->left == NULL)
546 		syntaxerr(NULL);
547 	t->right = elsepart();
548 	return (t);
549 }
550 
551 static struct op *
elsepart(void)552 elsepart(void)
553 {
554 	struct op *t;
555 
556 	switch (token(KEYWORD|ALIAS|VARASN)) {
557 	case ELSE:
558 		if ((t = c_list(true)) == NULL)
559 			syntaxerr(NULL);
560 		return (t);
561 
562 	case ELIF:
563 		t = newtp(TELIF);
564 		t->left = c_list(true);
565 		t->right = thenpart();
566 		return (t);
567 
568 	default:
569 		REJECT;
570 	}
571 	return (NULL);
572 }
573 
574 static struct op *
caselist(void)575 caselist(void)
576 {
577 	struct op *t, *tl;
578 	int c;
579 
580 	c = token(CONTIN|KEYWORD|ALIAS);
581 	/* A {...} can be used instead of in...esac for case statements */
582 	if (c == IN)
583 		c = ESAC;
584 	else if (c == '{')
585 		c = '}';
586 	else
587 		syntaxerr(NULL);
588 	t = tl = NULL;
589 	/* no ALIAS here */
590 	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) {
591 		struct op *tc = casepart(c);
592 		if (tl == NULL)
593 			t = tl = tc, tl->right = NULL;
594 		else
595 			tl->right = tc, tl = tc;
596 	}
597 	musthave(c, KEYWORD|ALIAS);
598 	return (t);
599 }
600 
601 static struct op *
casepart(int endtok)602 casepart(int endtok)
603 {
604 	struct op *t;
605 	XPtrV ptns;
606 
607 	XPinit(ptns, 16);
608 	t = newtp(TPAT);
609 	/* no ALIAS here */
610 	if (token(CONTIN | KEYWORD) != '(')
611 		REJECT;
612 	do {
613 		musthave(LWORD, 0);
614 		XPput(ptns, yylval.cp);
615 	} while (token(0) == '|');
616 	REJECT;
617 	XPput(ptns, NULL);
618 	t->vars = (char **) XPclose(ptns);
619 	musthave(')', 0);
620 
621 	t->left = c_list(true);
622 	/* Note: POSIX requires the ;; */
623 	if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
624 		switch (symbol) {
625 		default:
626 			syntaxerr(NULL);
627 		case BREAK:
628 		case BRKEV:
629 		case BRKFT:
630 			t->u.charflag =
631 			    (symbol == BRKEV) ? '|' :
632 			    (symbol == BRKFT) ? '&' : ';';
633 			ACCEPT;
634 		}
635 	return (t);
636 }
637 
638 static struct op *
function_body(char * name,bool ksh_func)639 function_body(char *name,
640     /* function foo { ... } vs foo() { .. } */
641     bool ksh_func)
642 {
643 	char *sname, *p;
644 	struct op *t;
645 	bool old_func_parse;
646 
647 	sname = wdstrip(name, 0);
648 	/*-
649 	 * Check for valid characters in name. POSIX and AT&T ksh93 say
650 	 * only allow [a-zA-Z_0-9] but this allows more as old pdkshs
651 	 * have allowed more; the following were never allowed:
652 	 *	NUL TAB NL SP " $ & ' ( ) ; < = > \ ` |
653 	 * C_QUOTE covers all but adds # * ? [ ]
654 	 */
655 	for (p = sname; *p; p++)
656 		if (ctype(*p, C_QUOTE))
657 			yyerror("%s: %s\n", sname, "invalid function name");
658 
659 	/*
660 	 * Note that POSIX allows only compound statements after foo(),
661 	 * sh and AT&T ksh allow any command, go with the later since it
662 	 * shouldn't break anything. However, for function foo, AT&T ksh
663 	 * only accepts an open-brace.
664 	 */
665 	if (ksh_func) {
666 		if (tpeek(CONTIN|KEYWORD|ALIAS) == '(' /*)*/) {
667 			/* function foo () { */
668 			ACCEPT;
669 			musthave(')', 0);
670 			/* degrade to POSIX function */
671 			ksh_func = false;
672 		}
673 		musthave('{' /*}*/, CONTIN|KEYWORD|ALIAS);
674 		REJECT;
675 	}
676 
677 	t = newtp(TFUNCT);
678 	t->str = sname;
679 	t->u.ksh_func = tobool(ksh_func);
680 	t->lineno = source->line;
681 
682 	old_func_parse = e->flags & EF_FUNC_PARSE;
683 	e->flags |= EF_FUNC_PARSE;
684 	if ((t->left = get_command(CONTIN)) == NULL) {
685 		char *tv;
686 		/*
687 		 * Probably something like foo() followed by EOF or ';'.
688 		 * This is accepted by sh and ksh88.
689 		 * To make "typeset -f foo" work reliably (so its output can
690 		 * be used as input), we pretend there is a colon here.
691 		 */
692 		t->left = newtp(TCOM);
693 		/* (2 * sizeof(char *)) is small enough */
694 		t->left->args = alloc(2 * sizeof(char *), ATEMP);
695 		t->left->args[0] = tv = alloc(3, ATEMP);
696 		tv[0] = CHAR;
697 		tv[1] = ':';
698 		tv[2] = EOS;
699 		t->left->args[1] = NULL;
700 		t->left->vars = alloc(sizeof(char *), ATEMP);
701 		t->left->vars[0] = NULL;
702 		t->left->lineno = 1;
703 	}
704 	if (!old_func_parse)
705 		e->flags &= ~EF_FUNC_PARSE;
706 
707 	return (t);
708 }
709 
710 static char **
wordlist(void)711 wordlist(void)
712 {
713 	int c;
714 	XPtrV args;
715 
716 	XPinit(args, 16);
717 	/* POSIX does not do alias expansion here... */
718 	if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {
719 		if (c != ';')
720 			/* non-POSIX, but AT&T ksh accepts a ; here */
721 			REJECT;
722 		return (NULL);
723 	}
724 	while ((c = token(0)) == LWORD)
725 		XPput(args, yylval.cp);
726 	if (c != '\n' && c != ';')
727 		syntaxerr(NULL);
728 	if (XPsize(args) == 0) {
729 		XPfree(args);
730 		return (NULL);
731 	} else {
732 		XPput(args, NULL);
733 		return ((char **)XPclose(args));
734 	}
735 }
736 
737 /*
738  * supporting functions
739  */
740 
741 static struct op *
block(int type,struct op * t1,struct op * t2,char ** wp)742 block(int type, struct op *t1, struct op *t2, char **wp)
743 {
744 	struct op *t;
745 
746 	t = newtp(type);
747 	t->left = t1;
748 	t->right = t2;
749 	t->vars = wp;
750 	return (t);
751 }
752 
753 const struct tokeninfo {
754 	const char *name;
755 	short val;
756 	short reserved;
757 } tokentab[] = {
758 	/* Reserved words */
759 	{ "if",		IF,	true },
760 	{ "then",	THEN,	true },
761 	{ "else",	ELSE,	true },
762 	{ "elif",	ELIF,	true },
763 	{ "fi",		FI,	true },
764 	{ "case",	CASE,	true },
765 	{ "esac",	ESAC,	true },
766 	{ "for",	FOR,	true },
767 	{ Tselect,	SELECT,	true },
768 	{ "while",	WHILE,	true },
769 	{ "until",	UNTIL,	true },
770 	{ "do",		DO,	true },
771 	{ "done",	DONE,	true },
772 	{ "in",		IN,	true },
773 	{ Tfunction,	FUNCTION, true },
774 	{ "time",	TIME,	true },
775 	{ "{",		'{',	true },
776 	{ "}",		'}',	true },
777 	{ "!",		BANG,	true },
778 	{ "[[",		DBRACKET, true },
779 	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
780 	{ "&&",		LOGAND,	false },
781 	{ "||",		LOGOR,	false },
782 	{ ";;",		BREAK,	false },
783 	{ ";|",		BRKEV,	false },
784 	{ ";&",		BRKFT,	false },
785 	{ "((",		MDPAREN, false },
786 	{ "|&",		COPROC,	false },
787 	/* and some special cases... */
788 	{ "newline",	'\n',	false },
789 	{ NULL,		0,	false }
790 };
791 
792 void
initkeywords(void)793 initkeywords(void)
794 {
795 	struct tokeninfo const *tt;
796 	struct tbl *p;
797 
798 	ktinit(APERM, &keywords,
799 	    /* currently 28 keywords -> 80% of 64 (2^6) */
800 	    6);
801 	for (tt = tokentab; tt->name; tt++) {
802 		if (tt->reserved) {
803 			p = ktenter(&keywords, tt->name, hash(tt->name));
804 			p->flag |= DEFINED|ISSET;
805 			p->type = CKEYWD;
806 			p->val.i = tt->val;
807 		}
808 	}
809 }
810 
811 static void
syntaxerr(const char * what)812 syntaxerr(const char *what)
813 {
814 	/* 2<<- is the longest redirection, I think */
815 	char redir[6];
816 	const char *s;
817 	struct tokeninfo const *tt;
818 	int c;
819 
820 	if (!what)
821 		what = "unexpected";
822 	REJECT;
823 	c = token(0);
824  Again:
825 	switch (c) {
826 	case 0:
827 		if (nesting.start_token) {
828 			c = nesting.start_token;
829 			source->errline = nesting.start_line;
830 			what = "unmatched";
831 			goto Again;
832 		}
833 		/* don't quote the EOF */
834 		yyerror("%s: %s %s\n", Tsynerr, "unexpected", "EOF");
835 		/* NOTREACHED */
836 
837 	case LWORD:
838 		s = snptreef(NULL, 32, "%S", yylval.cp);
839 		break;
840 
841 	case REDIR:
842 		s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
843 		break;
844 
845 	default:
846 		for (tt = tokentab; tt->name; tt++)
847 			if (tt->val == c)
848 			    break;
849 		if (tt->name)
850 			s = tt->name;
851 		else {
852 			if (c > 0 && c < 256) {
853 				redir[0] = c;
854 				redir[1] = '\0';
855 			} else
856 				shf_snprintf(redir, sizeof(redir),
857 					"?%d", c);
858 			s = redir;
859 		}
860 	}
861 	yyerror("%s: '%s' %s\n", Tsynerr, s, what);
862 }
863 
864 static void
nesting_push(struct nesting_state * save,int tok)865 nesting_push(struct nesting_state *save, int tok)
866 {
867 	*save = nesting;
868 	nesting.start_token = tok;
869 	nesting.start_line = source->line;
870 }
871 
872 static void
nesting_pop(struct nesting_state * saved)873 nesting_pop(struct nesting_state *saved)
874 {
875 	nesting = *saved;
876 }
877 
878 static struct op *
newtp(int type)879 newtp(int type)
880 {
881 	struct op *t;
882 
883 	t = alloc(sizeof(struct op), ATEMP);
884 	t->type = type;
885 	t->u.evalflags = 0;
886 	t->args = NULL;
887 	t->vars = NULL;
888 	t->ioact = NULL;
889 	t->left = t->right = NULL;
890 	t->str = NULL;
891 	return (t);
892 }
893 
894 struct op *
compile(Source * s,bool skiputf8bom)895 compile(Source *s, bool skiputf8bom)
896 {
897 	nesting.start_token = 0;
898 	nesting.start_line = 0;
899 	herep = heres;
900 	source = s;
901 	if (skiputf8bom)
902 		yyskiputf8bom();
903 	yyparse();
904 	return (outtree);
905 }
906 
907 /*-
908  * This kludge exists to take care of sh/AT&T ksh oddity in which
909  * the arguments of alias/export/readonly/typeset have no field
910  * splitting, file globbing, or (normal) tilde expansion done.
911  * AT&T ksh seems to do something similar to this since
912  *	$ touch a=a; typeset a=[ab]; echo "$a"
913  *	a=[ab]
914  *	$ x=typeset; $x a=[ab]; echo "$a"
915  *	a=a
916  *	$
917  */
918 static int
assign_command(char * s)919 assign_command(char *s)
920 {
921 	if (!*s)
922 		return (0);
923 	return ((strcmp(s, Talias) == 0) ||
924 	    (strcmp(s, "export") == 0) ||
925 	    (strcmp(s, "readonly") == 0) ||
926 	    (strcmp(s, Ttypeset) == 0));
927 }
928 
929 /* Check if we are in the middle of reading an alias */
930 static int
inalias(struct source * s)931 inalias(struct source *s)
932 {
933 	for (; s && s->type == SALIAS; s = s->next)
934 		if (!(s->flags & SF_ALIASEND))
935 			return (1);
936 	return (0);
937 }
938 
939 
940 /*
941  * Order important - indexed by Test_meta values
942  * Note that ||, &&, ( and ) can't appear in as unquoted strings
943  * in normal shell input, so these can be interpreted unambiguously
944  * in the evaluation pass.
945  */
946 static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
947 static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
948 static const char dbtest_not[] = { CHAR, '!', EOS };
949 static const char dbtest_oparen[] = { CHAR, '(', EOS };
950 static const char dbtest_cparen[] = { CHAR, ')', EOS };
951 const char *const dbtest_tokens[] = {
952 	dbtest_or, dbtest_and, dbtest_not,
953 	dbtest_oparen, dbtest_cparen
954 };
955 const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
956 const char db_lthan[] = { CHAR, '<', EOS };
957 const char db_gthan[] = { CHAR, '>', EOS };
958 
959 /*
960  * Test if the current token is a whatever. Accepts the current token if
961  * it is. Returns 0 if it is not, non-zero if it is (in the case of
962  * TM_UNOP and TM_BINOP, the returned value is a Test_op).
963  */
964 static Test_op
dbtestp_isa(Test_env * te,Test_meta meta)965 dbtestp_isa(Test_env *te, Test_meta meta)
966 {
967 	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
968 	int uqword;
969 	char *save = NULL;
970 	Test_op ret = TO_NONOP;
971 
972 	/* unquoted word? */
973 	uqword = c == LWORD && *ident;
974 
975 	if (meta == TM_OR)
976 		ret = c == LOGOR ? TO_NONNULL : TO_NONOP;
977 	else if (meta == TM_AND)
978 		ret = c == LOGAND ? TO_NONNULL : TO_NONOP;
979 	else if (meta == TM_NOT)
980 		ret = (uqword && !strcmp(yylval.cp,
981 		    dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP;
982 	else if (meta == TM_OPAREN)
983 		ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP;
984 	else if (meta == TM_CPAREN)
985 		ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
986 	else if (meta == TM_UNOP || meta == TM_BINOP) {
987 		if (meta == TM_BINOP && c == REDIR &&
988 		    (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
989 			ret = TO_NONNULL;
990 			save = wdcopy(yylval.iop->flag == IOREAD ?
991 			    db_lthan : db_gthan, ATEMP);
992 		} else if (uqword && (ret = test_isop(meta, ident)))
993 			save = yylval.cp;
994 	} else
995 		/* meta == TM_END */
996 		ret = (uqword && !strcmp(yylval.cp,
997 		    db_close)) ? TO_NONNULL : TO_NONOP;
998 	if (ret != TO_NONOP) {
999 		ACCEPT;
1000 		if (meta < NELEM(dbtest_tokens))
1001 			save = wdcopy(dbtest_tokens[(int)meta], ATEMP);
1002 		if (save)
1003 			XPput(*te->pos.av, save);
1004 	}
1005 	return (ret);
1006 }
1007 
1008 static const char *
dbtestp_getopnd(Test_env * te,Test_op op MKSH_A_UNUSED,bool do_eval MKSH_A_UNUSED)1009 dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
1010     bool do_eval MKSH_A_UNUSED)
1011 {
1012 	int c = tpeek(ARRAYVAR);
1013 
1014 	if (c != LWORD)
1015 		return (NULL);
1016 
1017 	ACCEPT;
1018 	XPput(*te->pos.av, yylval.cp);
1019 
1020 	return (null);
1021 }
1022 
1023 static int
dbtestp_eval(Test_env * te MKSH_A_UNUSED,Test_op op MKSH_A_UNUSED,const char * opnd1 MKSH_A_UNUSED,const char * opnd2 MKSH_A_UNUSED,bool do_eval MKSH_A_UNUSED)1024 dbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED,
1025     const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED,
1026     bool do_eval MKSH_A_UNUSED)
1027 {
1028 	return (1);
1029 }
1030 
1031 static void
dbtestp_error(Test_env * te,int offset,const char * msg)1032 dbtestp_error(Test_env *te, int offset, const char *msg)
1033 {
1034 	te->flags |= TEF_ERROR;
1035 
1036 	if (offset < 0) {
1037 		REJECT;
1038 		/* Kludgy to say the least... */
1039 		symbol = LWORD;
1040 		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
1041 		    offset);
1042 	}
1043 	syntaxerr(msg);
1044 }
1045 
1046 #if HAVE_SELECT
1047 
1048 #ifndef EOVERFLOW
1049 #ifdef ERANGE
1050 #define EOVERFLOW	ERANGE
1051 #else
1052 #define EOVERFLOW	EINVAL
1053 #endif
1054 #endif
1055 
1056 bool
parse_usec(const char * s,struct timeval * tv)1057 parse_usec(const char *s, struct timeval *tv)
1058 {
1059 	struct timeval tt;
1060 	int i;
1061 
1062 	tv->tv_sec = 0;
1063 	/* parse integral part */
1064 	while (ksh_isdigit(*s)) {
1065 		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0');
1066 		if (tt.tv_sec / 10 != tv->tv_sec) {
1067 			errno = EOVERFLOW;
1068 			return (true);
1069 		}
1070 		tv->tv_sec = tt.tv_sec;
1071 	}
1072 
1073 	tv->tv_usec = 0;
1074 	if (!*s)
1075 		/* no decimal fraction */
1076 		return (false);
1077 	else if (*s++ != '.') {
1078 		/* junk after integral part */
1079 		errno = EINVAL;
1080 		return (true);
1081 	}
1082 
1083 	/* parse decimal fraction */
1084 	i = 100000;
1085 	while (ksh_isdigit(*s)) {
1086 		tv->tv_usec += i * (*s++ - '0');
1087 		if (i == 1)
1088 			break;
1089 		i /= 10;
1090 	}
1091 	/* check for junk after fractional part */
1092 	while (ksh_isdigit(*s))
1093 		++s;
1094 	if (*s) {
1095 		errno = EINVAL;
1096 		return (true);
1097 	}
1098 
1099 	/* end of input string reached, no errors */
1100 	return (false);
1101 }
1102 #endif
1103 
1104 /*
1105  * Helper function called from within lex.c:yylex() to parse
1106  * a COMSUB recursively using the main shell parser and lexer
1107  */
1108 char *
yyrecursive(void)1109 yyrecursive(void)
1110 {
1111 	struct op *t;
1112 	char *cp;
1113 	bool old_reject;
1114 	int old_symbol;
1115 	struct ioword **old_herep;
1116 
1117 	/* tell the lexer to accept a closing parenthesis as EOD */
1118 	++subshell_nesting_level;
1119 
1120 	/* push reject state, parse recursively, pop reject state */
1121 	old_reject = reject;
1122 	old_symbol = symbol;
1123 	ACCEPT;
1124 	old_herep = herep;
1125 	/* we use TPAREN as a helper container here */
1126 	t = nested(TPAREN, '(', ')');
1127 	herep = old_herep;
1128 	reject = old_reject;
1129 	symbol = old_symbol;
1130 
1131 	/* t->left because nested(TPAREN, ...) hides our goodies there */
1132 	cp = snptreef(NULL, 0, "%T", t->left);
1133 	tfree(t, ATEMP);
1134 
1135 	--subshell_nesting_level;
1136 	return (cp);
1137 }
1138