1 /*
2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
8
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
13 */
14
15 #include "sh.h"
16 #include "sh.tconst.h"
17
18 /*
19 * C shell
20 */
21
22 void asyntax(struct wordent *, struct wordent *);
23 void asyn0(struct wordent *, struct wordent *);
24 void asyn3(struct wordent *, struct wordent *);
25 void chr_blkfree(char **);
26 struct command *syn0(struct wordent *, struct wordent *, int);
27 struct command *syn1(struct wordent *, struct wordent *, int);
28 struct command *syn1a(struct wordent *, struct wordent *, int);
29 struct command *syn1b(struct wordent *, struct wordent *, int);
30 struct command *syn2(struct wordent *, struct wordent *, int);
31 struct command *syn3(struct wordent *, struct wordent *, int);
32 struct wordent *freenod(struct wordent *, struct wordent *);
33
34 /*
35 * Perform aliasing on the word list lex
36 * Do a (very rudimentary) parse to separate into commands.
37 * If word 0 of a command has an alias, do it.
38 * Repeat a maximum of 20 times.
39 */
40 void
alias(struct wordent * lex)41 alias(struct wordent *lex)
42 {
43 int aleft = 21;
44 jmp_buf osetexit;
45
46 #ifdef TRACE
47 tprintf("TRACE- alias()\n");
48 #endif
49 getexit(osetexit);
50 setexit();
51 if (haderr) {
52 resexit(osetexit);
53 reset();
54 }
55 if (--aleft == 0)
56 error("Alias loop");
57 asyntax(lex->next, lex);
58 resexit(osetexit);
59 }
60
61 void
asyntax(struct wordent * p1,struct wordent * p2)62 asyntax(struct wordent *p1, struct wordent *p2)
63 {
64 #ifdef TRACE
65 tprintf("TRACE- asyntax()\n");
66 #endif
67
68 while (p1 != p2)
69 /* if (any(p1->word[0], ";&\n")) */ /* For char -> tchar */
70 if (p1->word[0] == ';' ||
71 p1->word[0] == '&' ||
72 p1->word[0] == '\n')
73 p1 = p1->next;
74 else {
75 asyn0(p1, p2);
76 return;
77 }
78 }
79
80 void
asyn0(struct wordent * p1,struct wordent * p2)81 asyn0(struct wordent *p1, struct wordent *p2)
82 {
83 struct wordent *p;
84 int l = 0;
85
86 #ifdef TRACE
87 tprintf("TRACE- asyn0()\n");
88 #endif
89 for (p = p1; p != p2; p = p->next)
90 switch (p->word[0]) {
91
92 case '(':
93 l++;
94 continue;
95
96 case ')':
97 l--;
98 if (l < 0)
99 error("Too many )'s");
100 continue;
101
102 case '>':
103 if (p->next != p2 && eq(p->next->word, S_AND /* "&"*/))
104 p = p->next;
105 continue;
106
107 case '&':
108 case '|':
109 case ';':
110 case '\n':
111 if (l != 0)
112 continue;
113 asyn3(p1, p);
114 asyntax(p->next, p2);
115 return;
116 }
117 if (l == 0)
118 asyn3(p1, p2);
119 }
120
121 void
asyn3(struct wordent * p1,struct wordent * p2)122 asyn3(struct wordent *p1, struct wordent *p2)
123 {
124 struct varent *ap;
125 struct wordent alout;
126 bool redid;
127
128 #ifdef TRACE
129 tprintf("TRACE- asyn3()\n");
130 #endif
131 if (p1 == p2)
132 return;
133 if (p1->word[0] == '(') {
134 for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
135 if (p2 == p1)
136 return;
137 if (p2 == p1->next)
138 return;
139 asyn0(p1->next, p2);
140 return;
141 }
142 ap = adrof1(p1->word, &aliases);
143 if (ap == 0)
144 return;
145 alhistp = p1->prev;
146 alhistt = p2;
147 alvec = ap->vec;
148 redid = lex(&alout);
149 alhistp = alhistt = 0;
150 alvec = 0;
151 if (err_msg) {
152 freelex(&alout);
153 error("%s", gettext(err_msg));
154 }
155 if (p1->word[0] && eq(p1->word, alout.next->word)) {
156 tchar *cp = alout.next->word;
157
158 alout.next->word = strspl(S_TOPBIT /* "\200" */, cp);
159 xfree(cp);
160 }
161 p1 = freenod(p1, redid ? p2 : p1->next);
162 if (alout.next != &alout) {
163 p1->next->prev = alout.prev->prev;
164 alout.prev->prev->next = p1->next;
165 alout.next->prev = p1;
166 p1->next = alout.next;
167 xfree(alout.prev->word);
168 xfree(alout.prev);
169 }
170 reset(); /* throw! */
171 }
172
173 struct wordent *
freenod(struct wordent * p1,struct wordent * p2)174 freenod(struct wordent *p1, struct wordent *p2)
175 {
176 struct wordent *retp = p1->prev;
177
178 #ifdef TRACE
179 tprintf("TRACE- freenod()\n");
180 #endif
181 while (p1 != p2) {
182 xfree(p1->word);
183 p1 = p1->next;
184 xfree(p1->prev);
185 }
186 retp->next = p2;
187 p2->prev = retp;
188 return (retp);
189 }
190
191 #define PHERE 1
192 #define PIN 2
193 #define POUT 4
194 #define PDIAG 8
195
196 /*
197 * syntax
198 * empty
199 * syn0
200 */
201 struct command *
syntax(struct wordent * p1,struct wordent * p2,int flags)202 syntax(struct wordent *p1, struct wordent *p2, int flags)
203 {
204 #ifdef TRACE
205 tprintf("TRACE- syntax()\n");
206 #endif
207
208 while (p1 != p2)
209 /* if (any(p1->word[0], ";&\n")) */ /* for char -> tchar */
210 if (p1->word[0] == ';' ||
211 p1->word[0] == '&' ||
212 p1->word[0] == '\n')
213 p1 = p1->next;
214 else
215 return (syn0(p1, p2, flags));
216 return (0);
217 }
218
219 /*
220 * syn0
221 * syn1
222 * syn1 & syntax
223 */
224 struct command *
syn0(struct wordent * p1,struct wordent * p2,int flags)225 syn0(struct wordent *p1, struct wordent *p2, int flags)
226 {
227 struct wordent *p;
228 struct command *t, *t1;
229 int l;
230
231 #ifdef TRACE
232 tprintf("TRACE- syn0()\n");
233 #endif
234 l = 0;
235 for (p = p1; p != p2; p = p->next)
236 switch (p->word[0]) {
237
238 case '(':
239 l++;
240 continue;
241
242 case ')':
243 l--;
244 if (l < 0)
245 seterr("Too many )'s");
246 continue;
247
248 case '|':
249 if (p->word[1] == '|')
250 continue;
251 /* fall into ... */
252
253 case '>':
254 if (p->next != p2 && eq(p->next->word, S_AND /* "&" */))
255 p = p->next;
256 continue;
257
258 case '&':
259 if (l != 0)
260 break;
261 if (p->word[1] == '&')
262 continue;
263 t1 = syn1(p1, p, flags);
264 if (t1->t_dtyp == TLST ||
265 t1->t_dtyp == TAND ||
266 t1->t_dtyp == TOR) {
267 t = (struct command *)xcalloc(1, sizeof (*t));
268 t->t_dtyp = TPAR;
269 t->t_dflg = FAND|FINT;
270 t->t_dspr = t1;
271 t1 = t;
272 } else
273 t1->t_dflg |= FAND|FINT;
274 t = (struct command *)xcalloc(1, sizeof (*t));
275 t->t_dtyp = TLST;
276 t->t_dflg = 0;
277 t->t_dcar = t1;
278 t->t_dcdr = syntax(p, p2, flags);
279 return (t);
280 }
281 if (l == 0)
282 return (syn1(p1, p2, flags));
283 seterr("Too many ('s");
284 return (0);
285 }
286
287 /*
288 * syn1
289 * syn1a
290 * syn1a ; syntax
291 */
292 struct command *
syn1(struct wordent * p1,struct wordent * p2,int flags)293 syn1(struct wordent *p1, struct wordent *p2, int flags)
294 {
295 struct wordent *p;
296 struct command *t;
297 int l;
298
299 #ifdef TRACE
300 tprintf("TRACE- syn1()\n");
301 #endif
302 l = 0;
303 for (p = p1; p != p2; p = p->next)
304 switch (p->word[0]) {
305
306 case '(':
307 l++;
308 continue;
309
310 case ')':
311 l--;
312 continue;
313
314 case ';':
315 case '\n':
316 if (l != 0)
317 break;
318 t = (struct command *)xcalloc(1, sizeof (*t));
319 t->t_dtyp = TLST;
320 t->t_dcar = syn1a(p1, p, flags);
321 t->t_dcdr = syntax(p->next, p2, flags);
322 if (t->t_dcdr == 0)
323 t->t_dcdr = t->t_dcar, t->t_dcar = 0;
324 return (t);
325 }
326 return (syn1a(p1, p2, flags));
327 }
328
329 /*
330 * syn1a
331 * syn1b
332 * syn1b || syn1a
333 */
334 struct command *
syn1a(struct wordent * p1,struct wordent * p2,int flags)335 syn1a(struct wordent *p1, struct wordent *p2, int flags)
336 {
337 struct wordent *p;
338 struct command *t;
339 int l = 0;
340
341 #ifdef TRACE
342 tprintf("TRACE- syn1a()\n");
343 #endif
344 for (p = p1; p != p2; p = p->next)
345 switch (p->word[0]) {
346
347 case '(':
348 l++;
349 continue;
350
351 case ')':
352 l--;
353 continue;
354
355 case '|':
356 if (p->word[1] != '|')
357 continue;
358 if (l == 0) {
359 t = (struct command *)xcalloc(1, sizeof (*t));
360 t->t_dtyp = TOR;
361 t->t_dcar = syn1b(p1, p, flags);
362 t->t_dcdr = syn1a(p->next, p2, flags);
363 t->t_dflg = 0;
364 return (t);
365 }
366 continue;
367 }
368 return (syn1b(p1, p2, flags));
369 }
370
371 /*
372 * syn1b
373 * syn2
374 * syn2 && syn1b
375 */
376 struct command *
syn1b(struct wordent * p1,struct wordent * p2,int flags)377 syn1b(struct wordent *p1, struct wordent *p2, int flags)
378 {
379 struct wordent *p;
380 struct command *t;
381 int l = 0;
382
383 #ifdef TRACE
384 tprintf("TRACE- syn1b()\n");
385 #endif
386 l = 0;
387 for (p = p1; p != p2; p = p->next)
388 switch (p->word[0]) {
389
390 case '(':
391 l++;
392 continue;
393
394 case ')':
395 l--;
396 continue;
397
398 case '&':
399 if (p->word[1] == '&' && l == 0) {
400 t = (struct command *)xcalloc(1, sizeof (*t));
401 t->t_dtyp = TAND;
402 t->t_dcar = syn2(p1, p, flags);
403 t->t_dcdr = syn1b(p->next, p2, flags);
404 t->t_dflg = 0;
405 return (t);
406 }
407 continue;
408 }
409 return (syn2(p1, p2, flags));
410 }
411
412 /*
413 * syn2
414 * syn3
415 * syn3 | syn2
416 * syn3 |& syn2
417 */
418 struct command *
syn2(struct wordent * p1,struct wordent * p2,int flags)419 syn2(struct wordent *p1, struct wordent *p2, int flags)
420 {
421 struct wordent *p, *pn;
422 struct command *t;
423 int l = 0;
424 int f;
425
426 #ifdef TRACE
427 tprintf("TRACE- syn2()\n");
428 #endif
429 for (p = p1; p != p2; p = p->next)
430 switch (p->word[0]) {
431
432 case '(':
433 l++;
434 continue;
435
436 case ')':
437 l--;
438 continue;
439
440 case '|':
441 if (l != 0)
442 continue;
443 t = (struct command *)xcalloc(1, sizeof (*t));
444 f = flags | POUT;
445 pn = p->next;
446 if (pn != p2 && pn->word[0] == '&') {
447 f |= PDIAG;
448 t->t_dflg |= FDIAG;
449 }
450 t->t_dtyp = TFIL;
451 t->t_dcar = syn3(p1, p, f);
452 if (pn != p2 && pn->word[0] == '&')
453 p = pn;
454 t->t_dcdr = syn2(p->next, p2, flags | PIN);
455 return (t);
456 }
457 return (syn3(p1, p2, flags));
458 }
459
460 tchar RELPAR[] = {'<', '>', '(', ')', 0}; /* "<>()" */
461
462 /*
463 * syn3
464 * ( syn0 ) [ < in ] [ > out ]
465 * word word* [ < in ] [ > out ]
466 * KEYWORD ( word* ) word* [ < in ] [ > out ]
467 *
468 * KEYWORD = (@ exit foreach if set switch test while)
469 */
470 struct command *
syn3(struct wordent * p1,struct wordent * p2,int flags)471 syn3(struct wordent *p1, struct wordent *p2, int flags)
472 {
473 struct wordent *p;
474 struct wordent *lp, *rp;
475 struct command *t;
476 int l;
477 tchar **av;
478 int n, c;
479 bool specp = 0;
480
481 #ifdef TRACE
482 tprintf("TRACE- syn3()\n");
483 #endif
484 if (p1 != p2) {
485 p = p1;
486 again:
487 switch (srchx(p->word)) {
488
489 case ZELSE:
490 p = p->next;
491 if (p != p2)
492 goto again;
493 break;
494
495 case ZEXIT:
496 case ZFOREACH:
497 case ZIF:
498 case ZLET:
499 case ZSET:
500 case ZSWITCH:
501 case ZWHILE:
502 specp = 1;
503 break;
504 }
505 }
506 n = 0;
507 l = 0;
508 for (p = p1; p != p2; p = p->next)
509 switch (p->word[0]) {
510
511 case '(':
512 if (specp)
513 n++;
514 l++;
515 continue;
516
517 case ')':
518 if (specp)
519 n++;
520 l--;
521 continue;
522
523 case '>':
524 case '<':
525 if (l != 0) {
526 if (specp)
527 n++;
528 continue;
529 }
530 if (p->next == p2)
531 continue;
532 if (any(p->next->word[0], RELPAR))
533 continue;
534 n--;
535 continue;
536
537 default:
538 if (!specp && l != 0)
539 continue;
540 n++;
541 continue;
542 }
543 if (n < 0)
544 n = 0;
545 t = (struct command *)xcalloc(1, sizeof (*t));
546 av = (tchar **)xcalloc((unsigned)(n + 1), sizeof (tchar **));
547 t->t_dcom = av;
548 n = 0;
549 if (p2->word[0] == ')')
550 t->t_dflg = FPAR;
551 lp = 0;
552 rp = 0;
553 l = 0;
554 for (p = p1; p != p2; p = p->next) {
555 c = p->word[0];
556 switch (c) {
557
558 case '(':
559 if (l == 0) {
560 if (lp != 0 && !specp)
561 seterr("Badly placed (");
562 lp = p->next;
563 }
564 l++;
565 goto savep;
566
567 case ')':
568 l--;
569 if (l == 0)
570 rp = p;
571 goto savep;
572
573 case '>':
574 if (l != 0)
575 goto savep;
576 if (p->word[1] == '>')
577 t->t_dflg |= FCAT;
578 if (p->next != p2 && eq(p->next->word, S_AND /* "&" */)) {
579 t->t_dflg |= FDIAG, p = p->next;
580 if (flags & (POUT|PDIAG))
581 goto badout;
582 }
583 if (p->next != p2 && eq(p->next->word, S_EXAS /* "!" */))
584 t->t_dflg |= FANY, p = p->next;
585 if (p->next == p2) {
586 missfile:
587 seterr("Missing name for redirect");
588 continue;
589 }
590 p = p->next;
591 if (any(p->word[0], RELPAR))
592 goto missfile;
593 if ((flags & POUT) && (flags & PDIAG) == 0 || t->t_drit)
594 badout:
595 seterr("Ambiguous output redirect");
596 else
597 t->t_drit = savestr(p->word);
598 continue;
599
600 case '<':
601 if (l != 0)
602 goto savep;
603 if (p->word[1] == '<')
604 t->t_dflg |= FHERE;
605 if (p->next == p2)
606 goto missfile;
607 p = p->next;
608 if (any(p->word[0], RELPAR))
609 goto missfile;
610 if ((flags & PHERE) && (t->t_dflg & FHERE))
611 seterr("Can't << within ()'s");
612 else if ((flags & PIN) || t->t_dlef)
613 seterr("Ambiguous input redirect");
614 else
615 t->t_dlef = savestr(p->word);
616 continue;
617
618 savep:
619 if (!specp)
620 continue;
621 default:
622 if (l != 0 && !specp)
623 continue;
624 if (err_msg == NULL)
625 av[n] = savestr(p->word);
626 n++;
627 continue;
628 }
629 }
630 if (lp != 0 && !specp) {
631 if (n != 0)
632 seterr("Badly placed ()'s");
633 t->t_dtyp = TPAR;
634 t->t_dspr = syn0(lp, rp, PHERE);
635 } else {
636 if (n == 0)
637 seterr("Invalid null command");
638 t->t_dtyp = TCOM;
639 }
640 return (t);
641 }
642
643 void
freesyn(struct command * t)644 freesyn(struct command *t)
645 {
646 #ifdef TRACE
647 tprintf("TRACE- freesyn()\n");
648 #endif
649 if (t == 0)
650 return;
651 switch (t->t_dtyp) {
652
653 case TCOM:
654 blkfree(t->t_dcom);
655 if (t->cfname)
656 xfree(t->cfname);
657 if (t->cargs)
658 chr_blkfree(t->cargs);
659 goto lr;
660
661 case TPAR:
662 freesyn(t->t_dspr);
663 /* fall into ... */
664
665 lr:
666 xfree(t->t_dlef);
667 xfree(t->t_drit);
668 break;
669
670 case TAND:
671 case TOR:
672 case TFIL:
673 case TLST:
674 freesyn(t->t_dcar), freesyn(t->t_dcdr);
675 break;
676 }
677 xfree(t);
678 }
679
680
681 void
chr_blkfree(char ** vec)682 chr_blkfree(char **vec)
683 {
684 char **av;
685
686 for (av = vec; *av; av++)
687 xfree(*av);
688 xfree(vec);
689 }
690