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