1 #define Extern extern
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <dirent.h>
5 #include <limits.h>
6 #include <signal.h>
7 #define _NSIG NSIG
8 #include <errno.h>
9 #include <setjmp.h>
10 #include "sh.h"
11
12 /* -------- eval.c -------- */
13 /* #include "sh.h" */
14 /* #include "word.h" */
15
16 /*
17 * ${}
18 * `command`
19 * blank interpretation
20 * quoting
21 * glob
22 */
23
24 _PROTOTYPE(static int expand, (char *cp, struct wdblock **wbp, int f ));
25 _PROTOTYPE(static char *blank, (int f ));
26 _PROTOTYPE(static int dollar, (int quoted ));
27 _PROTOTYPE(static int grave, (int quoted ));
28 _PROTOTYPE(void globname, (char *we, char *pp ));
29 _PROTOTYPE(static char *generate, (char *start1, char *end1, char *middle, char *end ));
30 _PROTOTYPE(static int anyspcl, (struct wdblock *wb ));
31 _PROTOTYPE(static int xstrcmp, (char *p1, char *p2 ));
32 _PROTOTYPE(void glob0, (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *)));
33 _PROTOTYPE(void glob1, (char *base, char *lim ));
34 _PROTOTYPE(void glob2, (char *i, char *j ));
35 _PROTOTYPE(void glob3, (char *i, char *j, char *k ));
36 _PROTOTYPE(char *memcopy, (char *ato, char *from, int nb ));
37
38 char **
eval(ap,f)39 eval(ap, f)
40 register char **ap;
41 int f;
42 {
43 struct wdblock *wb;
44 char **wp;
45 char **wf;
46 jmp_buf ev;
47
48 wp = NULL;
49 wb = NULL;
50 wf = NULL;
51 if (newenv(setjmp(errpt = ev)) == 0) {
52 while (*ap && isassign(*ap))
53 expand(*ap++, &wb, f & ~DOGLOB);
54 if (flag['k']) {
55 for (wf = ap; *wf; wf++) {
56 if (isassign(*wf))
57 expand(*wf, &wb, f & ~DOGLOB);
58 }
59 }
60 for (wb = addword((char *)0, wb); *ap; ap++) {
61 if (!flag['k'] || !isassign(*ap))
62 expand(*ap, &wb, f & ~DOKEY);
63 }
64 wb = addword((char *)0, wb);
65 wp = getwords(wb);
66 quitenv();
67 } else
68 gflg = 1;
69 return(gflg? (char **)NULL: wp);
70 }
71
72 /*
73 * Make the exported environment from the exported
74 * names in the dictionary. Keyword assignments
75 * will already have been done.
76 */
77 char **
makenv()78 makenv()
79
80 {
81 register struct wdblock *wb;
82 register struct var *vp;
83
84 wb = NULL;
85 for (vp = vlist; vp; vp = vp->next)
86 if (vp->status & EXPORT)
87 wb = addword(vp->name, wb);
88 wb = addword((char *)0, wb);
89 return(getwords(wb));
90 }
91
92 char *
evalstr(cp,f)93 evalstr(cp, f)
94 register char *cp;
95 int f;
96 {
97 struct wdblock *wb;
98
99 wb = NULL;
100 if (expand(cp, &wb, f)) {
101 if (wb == NULL || wb->w_nword == 0 || (cp = wb->w_words[0]) == NULL)
102 cp = "";
103 DELETE(wb);
104 } else
105 cp = NULL;
106 return(cp);
107 }
108
109 static int
expand(cp,wbp,f)110 expand(cp, wbp, f)
111 register char *cp;
112 register struct wdblock **wbp;
113 int f;
114 {
115 jmp_buf ev;
116
117 gflg = 0;
118 if (cp == NULL)
119 return(0);
120 if (!anys("$`'\"", cp) &&
121 !anys(ifs->value, cp) &&
122 ((f&DOGLOB)==0 || !anys("[*?", cp))) {
123 cp = strsave(cp, areanum);
124 if (f & DOTRIM)
125 unquote(cp);
126 *wbp = addword(cp, *wbp);
127 return(1);
128 }
129 if (newenv(setjmp(errpt = ev)) == 0) {
130 PUSHIO(aword, cp, strchar);
131 e.iobase = e.iop;
132 while ((cp = blank(f)) && gflg == 0) {
133 e.linep = cp;
134 cp = strsave(cp, areanum);
135 if ((f&DOGLOB) == 0) {
136 if (f & DOTRIM)
137 unquote(cp);
138 *wbp = addword(cp, *wbp);
139 } else
140 *wbp = glob(cp, *wbp);
141 }
142 quitenv();
143 } else
144 gflg = 1;
145 return(gflg == 0);
146 }
147
148 /*
149 * Blank interpretation and quoting
150 */
151 static char *
blank(f)152 blank(f)
153 int f;
154 {
155 register c, c1;
156 register char *sp;
157 int scanequals, foundequals;
158
159 sp = e.linep;
160 scanequals = f & DOKEY;
161 foundequals = 0;
162
163 loop:
164 switch (c = subgetc('"', foundequals)) {
165 case 0:
166 if (sp == e.linep)
167 return(0);
168 *e.linep++ = 0;
169 return(sp);
170
171 default:
172 if (f & DOBLANK && any(c, ifs->value))
173 goto loop;
174 break;
175
176 case '"':
177 case '\'':
178 scanequals = 0;
179 if (INSUB())
180 break;
181 for (c1 = c; (c = subgetc(c1, 1)) != c1;) {
182 if (c == 0)
183 break;
184 if (c == '\'' || !any(c, "$`\""))
185 c |= QUOTE;
186 *e.linep++ = c;
187 }
188 c = 0;
189 }
190 unget(c);
191 if (!letter(c))
192 scanequals = 0;
193 for (;;) {
194 c = subgetc('"', foundequals);
195 if (c == 0 ||
196 f & (DOBLANK && any(c, ifs->value)) ||
197 (!INSUB() && any(c, "\"'"))) {
198 scanequals = 0;
199 unget(c);
200 if (any(c, "\"'"))
201 goto loop;
202 break;
203 }
204 if (scanequals)
205 if (c == '=') {
206 foundequals = 1;
207 scanequals = 0;
208 }
209 else if (!letnum(c))
210 scanequals = 0;
211 *e.linep++ = c;
212 }
213 *e.linep++ = 0;
214 return(sp);
215 }
216
217 /*
218 * Get characters, substituting for ` and $
219 */
220 int
subgetc(ec,quoted)221 subgetc(ec, quoted)
222 register char ec;
223 int quoted;
224 {
225 register char c;
226
227 again:
228 c = getc(ec);
229 if (!INSUB() && ec != '\'') {
230 if (c == '`') {
231 if (grave(quoted) == 0)
232 return(0);
233 e.iop->task = XGRAVE;
234 goto again;
235 }
236 if (c == '$' && (c = dollar(quoted)) == 0) {
237 e.iop->task = XDOLL;
238 goto again;
239 }
240 }
241 return(c);
242 }
243
244 /*
245 * Prepare to generate the string returned by ${} substitution.
246 */
247 static int
dollar(quoted)248 dollar(quoted)
249 int quoted;
250 {
251 int otask;
252 struct io *oiop;
253 char *dolp;
254 register char *s, c, *cp;
255 struct var *vp;
256
257 c = readc();
258 s = e.linep;
259 if (c != '{') {
260 *e.linep++ = c;
261 if (letter(c)) {
262 while ((c = readc())!=0 && letnum(c))
263 if (e.linep < elinep)
264 *e.linep++ = c;
265 unget(c);
266 }
267 c = 0;
268 } else {
269 oiop = e.iop;
270 otask = e.iop->task;
271 e.iop->task = XOTHER;
272 while ((c = subgetc('"', 0))!=0 && c!='}' && c!='\n')
273 if (e.linep < elinep)
274 *e.linep++ = c;
275 if (oiop == e.iop)
276 e.iop->task = otask;
277 if (c != '}') {
278 err("unclosed ${");
279 gflg++;
280 return(c);
281 }
282 }
283 if (e.linep >= elinep) {
284 err("string in ${} too long");
285 gflg++;
286 e.linep -= 10;
287 }
288 *e.linep = 0;
289 if (*s)
290 for (cp = s+1; *cp; cp++)
291 if (any(*cp, "=-+?")) {
292 c = *cp;
293 *cp++ = 0;
294 break;
295 }
296 if (s[1] == 0 && (*s == '*' || *s == '@')) {
297 if (dolc > 1) {
298 /* currently this does not distinguish $* and $@ */
299 /* should check dollar */
300 e.linep = s;
301 PUSHIO(awordlist, dolv+1, dolchar);
302 return(0);
303 } else { /* trap the nasty ${=} */
304 s[0] = '1';
305 s[1] = 0;
306 }
307 }
308 vp = lookup(s);
309 if ((dolp = vp->value) == null) {
310 switch (c) {
311 case '=':
312 if (digit(*s)) {
313 err("cannot use ${...=...} with $n");
314 gflg++;
315 break;
316 }
317 setval(vp, cp);
318 dolp = vp->value;
319 break;
320
321 case '-':
322 dolp = strsave(cp, areanum);
323 break;
324
325 case '?':
326 if (*cp == 0) {
327 prs("missing value for ");
328 err(s);
329 } else
330 err(cp);
331 gflg++;
332 break;
333 }
334 } else if (c == '+')
335 dolp = strsave(cp, areanum);
336 if (flag['u'] && dolp == null) {
337 prs("unset variable: ");
338 err(s);
339 gflg++;
340 }
341 e.linep = s;
342 PUSHIO(aword, dolp, quoted ? qstrchar : strchar);
343 return(0);
344 }
345
346 /*
347 * Run the command in `...` and read its output.
348 */
349 static int
grave(quoted)350 grave(quoted)
351 int quoted;
352 {
353 register char *cp;
354 register int i;
355 int pf[2];
356
357 for (cp = e.iop->argp->aword; *cp != '`'; cp++)
358 if (*cp == 0) {
359 err("no closing `");
360 return(0);
361 }
362 if (openpipe(pf) < 0)
363 return(0);
364 if ((i = fork()) == -1) {
365 closepipe(pf);
366 err("try again");
367 return(0);
368 }
369 if (i != 0) {
370 e.iop->argp->aword = ++cp;
371 close(pf[1]);
372 PUSHIO(afile, remap(pf[0]), quoted? qgravechar: gravechar);
373 return(1);
374 }
375 *cp = 0;
376 /* allow trapped signals */
377 for (i=0; i<=_NSIG; i++)
378 if (ourtrap[i] && signal(i, SIG_IGN) != SIG_IGN)
379 signal(i, SIG_DFL);
380 dup2(pf[1], 1);
381 closepipe(pf);
382 flag['e'] = 0;
383 flag['v'] = 0;
384 flag['n'] = 0;
385 cp = strsave(e.iop->argp->aword, 0);
386 areanum = 1;
387 freehere(areanum);
388 freearea(areanum); /* free old space */
389 e.oenv = NULL;
390 e.iop = (e.iobase = iostack) - 1;
391 unquote(cp);
392 talking = 0;
393 PUSHIO(aword, cp, nlchar);
394 onecommand();
395 exit(1);
396 }
397
398 char *
unquote(as)399 unquote(as)
400 register char *as;
401 {
402 register char *s;
403
404 if ((s = as) != NULL)
405 while (*s)
406 *s++ &= ~QUOTE;
407 return(as);
408 }
409
410 /* -------- glob.c -------- */
411 /* #include "sh.h" */
412
413 /*
414 * glob
415 */
416
417 #define scopy(x) strsave((x), areanum)
418 #define BLKSIZ 512
419 #define NDENT ((BLKSIZ+sizeof(struct dirent)-1)/sizeof(struct dirent))
420
421 static struct wdblock *cl, *nl;
422 static char spcl[] = "[?*";
423
424 struct wdblock *
glob(cp,wb)425 glob(cp, wb)
426 char *cp;
427 struct wdblock *wb;
428 {
429 register i;
430 register char *pp;
431
432 if (cp == 0)
433 return(wb);
434 i = 0;
435 for (pp = cp; *pp; pp++)
436 if (any(*pp, spcl))
437 i++;
438 else if (!any(*pp & ~QUOTE, spcl))
439 *pp &= ~QUOTE;
440 if (i != 0) {
441 for (cl = addword(scopy(cp), (struct wdblock *)0); anyspcl(cl); cl = nl) {
442 nl = newword(cl->w_nword*2);
443 for(i=0; i<cl->w_nword; i++) { /* for each argument */
444 for (pp = cl->w_words[i]; *pp; pp++)
445 if (any(*pp, spcl)) {
446 globname(cl->w_words[i], pp);
447 break;
448 }
449 if (*pp == '\0')
450 nl = addword(scopy(cl->w_words[i]), nl);
451 }
452 for(i=0; i<cl->w_nword; i++)
453 DELETE(cl->w_words[i]);
454 DELETE(cl);
455 }
456 for(i=0; i<cl->w_nword; i++)
457 unquote(cl->w_words[i]);
458 glob0((char *)cl->w_words, cl->w_nword, sizeof(char *), xstrcmp);
459 if (cl->w_nword) {
460 for (i=0; i<cl->w_nword; i++)
461 wb = addword(cl->w_words[i], wb);
462 DELETE(cl);
463 return(wb);
464 }
465 }
466 wb = addword(unquote(cp), wb);
467 return(wb);
468 }
469
470 void
globname(we,pp)471 globname(we, pp)
472 char *we;
473 register char *pp;
474 {
475 register char *np, *cp;
476 char *name, *gp, *dp;
477 int dn, j, n, k;
478 DIR *dirp;
479 struct dirent *de;
480 char dname[NAME_MAX+1];
481 struct stat dbuf;
482
483 for (np = we; np != pp; pp--)
484 if (pp[-1] == '/')
485 break;
486 for (dp = cp = space((int)(pp-np)+3); np < pp;)
487 *cp++ = *np++;
488 *cp++ = '.';
489 *cp = '\0';
490 for (gp = cp = space(strlen(pp)+1); *np && *np != '/';)
491 *cp++ = *np++;
492 *cp = '\0';
493 dirp = opendir(dp);
494 if (dirp == 0) {
495 DELETE(dp);
496 DELETE(gp);
497 return;
498 }
499 dname[NAME_MAX] = '\0';
500 while ((de=readdir(dirp))!=NULL) {
501 /* XXX Hmmm... What this could be? (abial) */
502 /*
503 if (ent[j].d_ino == 0)
504 continue;
505 */
506 strncpy(dname, de->d_name, NAME_MAX);
507 if (dname[0] == '.')
508 if (*gp != '.')
509 continue;
510 for(k=0; k<NAME_MAX; k++)
511 if (any(dname[k], spcl))
512 dname[k] |= QUOTE;
513 if (gmatch(dname, gp)) {
514 name = generate(we, pp, dname, np);
515 if (*np && !anys(np, spcl)) {
516 if (stat(name,&dbuf)) {
517 DELETE(name);
518 continue;
519 }
520 }
521 nl = addword(name, nl);
522 }
523 }
524 closedir(dirp);
525 DELETE(dp);
526 DELETE(gp);
527 }
528
529 /*
530 * generate a pathname as below.
531 * start..end1 / middle end
532 * the slashes come for free
533 */
534 static char *
generate(start1,end1,middle,end)535 generate(start1, end1, middle, end)
536 char *start1;
537 register char *end1;
538 char *middle, *end;
539 {
540 char *p;
541 register char *op, *xp;
542
543 p = op = space((int)(end1-start1)+strlen(middle)+strlen(end)+2);
544 for (xp = start1; xp != end1;)
545 *op++ = *xp++;
546 for (xp = middle; (*op++ = *xp++) != '\0';)
547 ;
548 op--;
549 for (xp = end; (*op++ = *xp++) != '\0';)
550 ;
551 return(p);
552 }
553
554 static int
anyspcl(wb)555 anyspcl(wb)
556 register struct wdblock *wb;
557 {
558 register i;
559 register char **wd;
560
561 wd = wb->w_words;
562 for (i=0; i<wb->w_nword; i++)
563 if (anys(spcl, *wd++))
564 return(1);
565 return(0);
566 }
567
568 static int
xstrcmp(p1,p2)569 xstrcmp(p1, p2)
570 char *p1, *p2;
571 {
572 return(strcmp(*(char **)p1, *(char **)p2));
573 }
574
575 /* -------- word.c -------- */
576 /* #include "sh.h" */
577 /* #include "word.h" */
578
579 #define NSTART 16 /* default number of words to allow for initially */
580
581 struct wdblock *
newword(nw)582 newword(nw)
583 register int nw;
584 {
585 register struct wdblock *wb;
586
587 wb = (struct wdblock *) space(sizeof(*wb) + nw*sizeof(char *));
588 wb->w_bsize = nw;
589 wb->w_nword = 0;
590 return(wb);
591 }
592
593 struct wdblock *
addword(wd,wb)594 addword(wd, wb)
595 char *wd;
596 register struct wdblock *wb;
597 {
598 register struct wdblock *wb2;
599 register nw;
600
601 if (wb == NULL)
602 wb = newword(NSTART);
603 if ((nw = wb->w_nword) >= wb->w_bsize) {
604 wb2 = newword(nw * 2);
605 memcopy((char *)wb2->w_words, (char *)wb->w_words, nw*sizeof(char *));
606 wb2->w_nword = nw;
607 DELETE(wb);
608 wb = wb2;
609 }
610 wb->w_words[wb->w_nword++] = wd;
611 return(wb);
612 }
613
614 char **
getwords(wb)615 getwords(wb)
616 register struct wdblock *wb;
617 {
618 register char **wd;
619 register nb;
620
621 if (wb == NULL)
622 return((char **)NULL);
623 if (wb->w_nword == 0) {
624 DELETE(wb);
625 return((char **)NULL);
626 }
627 wd = (char **) space(nb = sizeof(*wd) * wb->w_nword);
628 memcopy((char *)wd, (char *)wb->w_words, nb);
629 DELETE(wb); /* perhaps should done by caller */
630 return(wd);
631 }
632
633 _PROTOTYPE(int (*func), (char *, char *));
634 int globv;
635
636 void
glob0(a0,a1,a2,a3)637 glob0(a0, a1, a2, a3)
638 char *a0;
639 unsigned a1;
640 int a2;
641 _PROTOTYPE(int (*a3), (char *, char *));
642 {
643 func = a3;
644 globv = a2;
645 glob1(a0, a0 + a1 * a2);
646 }
647
648 void
glob1(base,lim)649 glob1(base, lim)
650 char *base, *lim;
651 {
652 register char *i, *j;
653 int v2;
654 char *lptr, *hptr;
655 int c;
656 unsigned n;
657
658
659 v2 = globv;
660
661 top:
662 if ((n=(int)(lim-base)) <= v2)
663 return;
664 n = v2 * (n / (2*v2));
665 hptr = lptr = base+n;
666 i = base;
667 j = lim-v2;
668 for(;;) {
669 if (i < lptr) {
670 if ((c = (*func)(i, lptr)) == 0) {
671 glob2(i, lptr -= v2);
672 continue;
673 }
674 if (c < 0) {
675 i += v2;
676 continue;
677 }
678 }
679
680 begin:
681 if (j > hptr) {
682 if ((c = (*func)(hptr, j)) == 0) {
683 glob2(hptr += v2, j);
684 goto begin;
685 }
686 if (c > 0) {
687 if (i == lptr) {
688 glob3(i, hptr += v2, j);
689 i = lptr += v2;
690 goto begin;
691 }
692 glob2(i, j);
693 j -= v2;
694 i += v2;
695 continue;
696 }
697 j -= v2;
698 goto begin;
699 }
700
701
702 if (i == lptr) {
703 if (lptr-base >= lim-hptr) {
704 glob1(hptr+v2, lim);
705 lim = lptr;
706 } else {
707 glob1(base, lptr);
708 base = hptr+v2;
709 }
710 goto top;
711 }
712
713
714 glob3(j, lptr -= v2, i);
715 j = hptr -= v2;
716 }
717 }
718
719 void
glob2(i,j)720 glob2(i, j)
721 char *i, *j;
722 {
723 register char *index1, *index2, c;
724 int m;
725
726 m = globv;
727 index1 = i;
728 index2 = j;
729 do {
730 c = *index1;
731 *index1++ = *index2;
732 *index2++ = c;
733 } while(--m);
734 }
735
736 void
glob3(i,j,k)737 glob3(i, j, k)
738 char *i, *j, *k;
739 {
740 register char *index1, *index2, *index3;
741 int c;
742 int m;
743
744 m = globv;
745 index1 = i;
746 index2 = j;
747 index3 = k;
748 do {
749 c = *index1;
750 *index1++ = *index3;
751 *index3++ = *index2;
752 *index2++ = c;
753 } while(--m);
754 }
755
756 char *
memcopy(ato,from,nb)757 memcopy(ato, from, nb)
758 register char *ato, *from;
759 register int nb;
760 {
761 register char *to;
762
763 to = ato;
764 while (--nb >= 0)
765 *to++ = *from++;
766 return(ato);
767 }
768