improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / sh / sh1.c
blobcf45644c2826d7ea5aafa1eaffd2ccc3718a8a6a
1 #define Extern extern
2 #include <sys/types.h>
3 #include <signal.h>
4 #include <errno.h>
5 #include <setjmp.h>
6 #include "sh.h"
7 /* -------- sh.c -------- */
8 /*
9 * shell
12 /* #include "sh.h" */
14 int intr;
15 int inparse;
16 char flags['z'-'a'+1];
17 char *flag = flags-'a';
18 char *elinep = line+sizeof(line)-5;
19 char *null = "";
20 int heedint =1;
21 struct env e ={line, iostack, iostack-1,
22 (xint *)NULL, FDBASE, (struct env *)NULL};
24 extern char **environ; /* environment pointer */
27 * default shell, search rules
29 char shellname[] = "/bin/sh";
30 char search[] = ":/bin:/usr/bin";
32 _PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
34 _PROTOTYPE(int main, (int argc, char **argv ));
35 _PROTOTYPE(int newfile, (char *s ));
36 _PROTOTYPE(static char *findeq, (char *cp ));
37 _PROTOTYPE(static char *cclass, (char *p, int sub ));
38 _PROTOTYPE(void initarea, (void));
40 int main(argc, argv)
41 int argc;
42 register char **argv;
44 register int f;
45 register char *s;
46 int cflag;
47 char *name, **ap;
48 int (*iof)();
50 initarea();
51 if ((ap = environ) != NULL) {
52 while (*ap)
53 assign(*ap++, !COPYV);
54 for (ap = environ; *ap;)
55 export(lookup(*ap++));
57 closeall();
58 areanum = 1;
60 shell = lookup("SHELL");
61 if (shell->value == null)
62 setval(shell, shellname);
63 export(shell);
65 homedir = lookup("HOME");
66 if (homedir->value == null)
67 setval(homedir, "/");
68 export(homedir);
70 setval(lookup("$"), itoa(getpid(), 5));
72 path = lookup("PATH");
73 if (path->value == null)
74 setval(path, search);
75 export(path);
77 ifs = lookup("IFS");
78 if (ifs->value == null)
79 setval(ifs, " \t\n");
81 prompt = lookup("PS1");
82 if (prompt->value == null)
83 #ifndef UNIXSHELL
84 setval(prompt, "$ ");
85 #else
86 setval(prompt, "% ");
87 #endif
89 if (geteuid() == 0) {
90 setval(prompt, "# ");
91 prompt->status &= ~EXPORT;
93 cprompt = lookup("PS2");
94 if (cprompt->value == null)
95 setval(cprompt, "> ");
97 iof = filechar;
98 cflag = 0;
99 name = *argv++;
100 if (--argc >= 1) {
101 if(argv[0][0] == '-' && argv[0][1] != '\0') {
102 for (s = argv[0]+1; *s; s++)
103 switch (*s) {
104 case 'c':
105 prompt->status &= ~EXPORT;
106 cprompt->status &= ~EXPORT;
107 setval(prompt, "");
108 setval(cprompt, "");
109 cflag = 1;
110 if (--argc > 0)
111 PUSHIO(aword, *++argv, iof = nlchar);
112 break;
114 case 'q':
115 qflag = SIG_DFL;
116 break;
118 case 's':
119 /* standard input */
120 break;
122 case 't':
123 prompt->status &= ~EXPORT;
124 setval(prompt, "");
125 iof = linechar;
126 break;
128 case 'i':
129 talking++;
130 default:
131 if (*s>='a' && *s<='z')
132 flag[*s]++;
134 } else {
135 argv--;
136 argc++;
138 if (iof == filechar && --argc > 0) {
139 setval(prompt, "");
140 setval(cprompt, "");
141 prompt->status &= ~EXPORT;
142 cprompt->status &= ~EXPORT;
143 if (newfile(name = *++argv))
144 exit(1);
147 setdash();
148 if (e.iop < iostack) {
149 PUSHIO(afile, 0, iof);
150 if (isatty(0) && isatty(1) && !cflag)
151 talking++;
153 signal(SIGQUIT, qflag);
154 if (name && name[0] == '-') {
155 talking++;
156 if ((f = open(".profile", 0)) >= 0)
157 next(remap(f));
158 if ((f = open("/etc/profile", 0)) >= 0)
159 next(remap(f));
161 if (talking)
162 signal(SIGTERM, sig);
163 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
164 signal(SIGINT, onintr);
165 dolv = argv;
166 dolc = argc;
167 dolv[0] = name;
168 if (dolc > 1)
169 for (ap = ++argv; --argc > 0;)
170 if (assign(*ap = *argv++, !COPYV))
171 dolc--; /* keyword */
172 else
173 ap++;
174 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
176 for (;;) {
177 if (talking && e.iop <= iostack)
178 prs(prompt->value);
179 onecommand();
183 void
184 setdash()
186 register char *cp, c;
187 char m['z'-'a'+1];
189 cp = m;
190 for (c='a'; c<='z'; c++)
191 if (flag[c])
192 *cp++ = c;
193 *cp = 0;
194 setval(lookup("-"), m);
198 newfile(s)
199 register char *s;
201 register f;
203 if (strcmp(s, "-") != 0) {
204 f = open(s, 0);
205 if (f < 0) {
206 prs(s);
207 err(": cannot open");
208 return(1);
210 } else
211 f = 0;
212 next(remap(f));
213 return(0);
216 void
217 onecommand()
219 register i;
220 jmp_buf m1;
222 while (e.oenv)
223 quitenv();
224 areanum = 1;
225 freehere(areanum);
226 freearea(areanum);
227 garbage();
228 wdlist = 0;
229 iolist = 0;
230 e.errpt = 0;
231 e.linep = line;
232 yynerrs = 0;
233 multiline = 0;
234 inparse = 1;
235 intr = 0;
236 execflg = 0;
237 setjmp(failpt = m1); /* Bruce Evans' fix */
238 if (setjmp(failpt = m1) || yyparse() || intr) {
239 while (e.oenv)
240 quitenv();
241 scraphere();
242 if (!talking && intr)
243 leave();
244 inparse = 0;
245 intr = 0;
246 return;
248 inparse = 0;
249 brklist = 0;
250 intr = 0;
251 execflg = 0;
252 if (!flag['n'])
253 execute(outtree, NOPIPE, NOPIPE, 0);
254 if (!talking && intr) {
255 execflg = 0;
256 leave();
258 if ((i = trapset) != 0) {
259 trapset = 0;
260 runtrap(i);
264 void
265 fail()
267 longjmp(failpt, 1);
268 /* NOTREACHED */
271 void
272 leave()
274 if (execflg)
275 fail();
276 scraphere();
277 freehere(1);
278 runtrap(0);
279 exit(exstat);
280 /* NOTREACHED */
283 void
284 warn(s)
285 register char *s;
287 if(*s) {
288 prs(s);
289 exstat = -1;
291 prs("\n");
292 if (flag['e'])
293 leave();
296 void
297 err(s)
298 char *s;
300 warn(s);
301 if (flag['n'])
302 return;
303 if (!talking)
304 leave();
305 if (e.errpt)
306 longjmp(e.errpt, 1);
307 closeall();
308 e.iop = e.iobase = iostack;
312 newenv(f)
313 int f;
315 register struct env *ep;
317 if (f) {
318 quitenv();
319 return(1);
321 ep = (struct env *) space(sizeof(*ep));
322 if (ep == NULL) {
323 while (e.oenv)
324 quitenv();
325 fail();
327 *ep = e;
328 e.oenv = ep;
329 e.errpt = errpt;
330 return(0);
333 void
334 quitenv()
336 register struct env *ep;
337 register fd;
339 if ((ep = e.oenv) != NULL) {
340 fd = e.iofd;
341 e = *ep;
342 /* should close `'d files */
343 DELETE(ep);
344 while (--fd >= e.iofd)
345 close(fd);
350 * Is any character from s1 in s2?
353 anys(s1, s2)
354 register char *s1, *s2;
356 while (*s1)
357 if (any(*s1++, s2))
358 return(1);
359 return(0);
363 * Is character c in s?
366 any(c, s)
367 register int c;
368 register char *s;
370 while (*s)
371 if (*s++ == c)
372 return(1);
373 return(0);
376 char *
377 putn(n)
378 register int n;
380 return(itoa(n, -1));
383 char *
384 itoa(u, n)
385 register unsigned u;
386 int n;
388 register char *cp;
389 static char s[20];
390 int m;
392 m = 0;
393 if (n < 0 && (int) u < 0) {
394 m++;
395 u = -u;
397 cp = s+sizeof(s);
398 *--cp = 0;
399 do {
400 *--cp = u%10 + '0';
401 u /= 10;
402 } while (--n > 0 || u);
403 if (m)
404 *--cp = '-';
405 return(cp);
408 void
409 next(f)
410 int f;
412 PUSHIO(afile, f, filechar);
415 void
416 onintr(s)
417 int s; /* ANSI C requires a parameter */
419 signal(SIGINT, onintr);
420 intr = 1;
421 if (talking) {
422 if (inparse) {
423 prs("\n");
424 fail();
427 else if (heedint) {
428 execflg = 0;
429 leave();
434 letter(c)
435 register c;
437 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
441 digit(c)
442 register c;
444 return(c >= '0' && c <= '9');
448 letnum(c)
449 register c;
451 return(letter(c) || digit(c));
454 char *
455 space(n)
456 int n;
458 register char *cp;
460 if ((cp = getcell(n)) == 0)
461 err("out of string space");
462 return(cp);
465 char *
466 strsave(s, a)
467 register char *s;
468 int a;
470 register char *cp, *xp;
472 if ((cp = space(strlen(s)+1)) != NULL) {
473 setarea((char *)cp, a);
474 for (xp = cp; (*xp++ = *s++) != '\0';)
476 return(cp);
478 return("");
481 void
482 xfree(s)
483 register char *s;
485 DELETE(s);
489 * trap handling
491 void
492 sig(i)
493 register int i;
495 trapset = i;
496 signal(i, sig);
499 void runtrap(i)
500 int i;
502 char *trapstr;
504 if ((trapstr = trap[i]) == NULL)
505 return;
506 if (i == 0)
507 trap[i] = 0;
508 RUN(aword, trapstr, nlchar);
511 /* -------- var.c -------- */
512 /* #include "sh.h" */
515 * Find the given name in the dictionary
516 * and return its value. If the name was
517 * not previously there, enter it now and
518 * return a null value.
520 struct var *
521 lookup(n)
522 register char *n;
524 register struct var *vp;
525 register char *cp;
526 register int c;
527 static struct var dummy;
529 if (digit(*n)) {
530 dummy.name = n;
531 for (c = 0; digit(*n) && c < 1000; n++)
532 c = c*10 + *n-'0';
533 dummy.status = RONLY;
534 dummy.value = c <= dolc? dolv[c]: null;
535 return(&dummy);
537 for (vp = vlist; vp; vp = vp->next)
538 if (eqname(vp->name, n))
539 return(vp);
540 cp = findeq(n);
541 vp = (struct var *)space(sizeof(*vp));
542 if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
543 dummy.name = dummy.value = "";
544 return(&dummy);
546 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
548 if (*cp == 0)
549 *cp = '=';
550 *++cp = 0;
551 setarea((char *)vp, 0);
552 setarea((char *)vp->name, 0);
553 vp->value = null;
554 vp->next = vlist;
555 vp->status = GETCELL;
556 vlist = vp;
557 return(vp);
561 * give variable at `vp' the value `val'.
563 void
564 setval(vp, val)
565 struct var *vp;
566 char *val;
568 nameval(vp, val, (char *)NULL);
572 * if name is not NULL, it must be
573 * a prefix of the space `val',
574 * and end with `='.
575 * this is all so that exporting
576 * values is reasonably painless.
578 void
579 nameval(vp, val, name)
580 register struct var *vp;
581 char *val, *name;
583 register char *cp, *xp;
584 char *nv;
585 int fl;
587 if (vp->status & RONLY) {
588 for (xp = vp->name; *xp && *xp != '=';)
589 putc(*xp++);
590 err(" is read-only");
591 return;
593 fl = 0;
594 if (name == NULL) {
595 xp = space(strlen(vp->name)+strlen(val)+2);
596 if (xp == 0)
597 return;
598 /* make string: name=value */
599 setarea((char *)xp, 0);
600 name = xp;
601 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
603 if (*xp++ == 0)
604 xp[-1] = '=';
605 nv = xp;
606 for (cp = val; (*xp++ = *cp++) != '\0';)
608 val = nv;
609 fl = GETCELL;
611 if (vp->status & GETCELL)
612 xfree(vp->name); /* form new string `name=value' */
613 vp->name = name;
614 vp->value = val;
615 vp->status |= fl;
618 void
619 export(vp)
620 struct var *vp;
622 vp->status |= EXPORT;
625 void
626 ronly(vp)
627 struct var *vp;
629 if (letter(vp->name[0])) /* not an internal symbol ($# etc) */
630 vp->status |= RONLY;
634 isassign(s)
635 register char *s;
637 if (!letter((int)*s))
638 return(0);
639 for (; *s != '='; s++)
640 if (*s == 0 || !letnum(*s))
641 return(0);
642 return(1);
646 assign(s, cf)
647 register char *s;
648 int cf;
650 register char *cp;
651 struct var *vp;
653 if (!letter(*s))
654 return(0);
655 for (cp = s; *cp != '='; cp++)
656 if (*cp == 0 || !letnum(*cp))
657 return(0);
658 vp = lookup(s);
659 nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
660 if (cf != COPYV)
661 vp->status &= ~GETCELL;
662 return(1);
666 checkname(cp)
667 register char *cp;
669 if (!letter(*cp++))
670 return(0);
671 while (*cp)
672 if (!letnum(*cp++))
673 return(0);
674 return(1);
677 void
678 putvlist(f, out)
679 register int f, out;
681 register struct var *vp;
683 for (vp = vlist; vp; vp = vp->next)
684 if (vp->status & f && letter(*vp->name)) {
685 if (vp->status & EXPORT)
686 write(out, "export ", 7);
687 if (vp->status & RONLY)
688 write(out, "readonly ", 9);
689 write(out, vp->name, (int)(findeq(vp->name) - vp->name));
690 write(out, "\n", 1);
695 eqname(n1, n2)
696 register char *n1, *n2;
698 for (; *n1 != '=' && *n1 != 0; n1++)
699 if (*n2++ != *n1)
700 return(0);
701 return(*n2 == 0 || *n2 == '=');
704 static char *
705 findeq(cp)
706 register char *cp;
708 while (*cp != '\0' && *cp != '=')
709 cp++;
710 return(cp);
713 /* -------- gmatch.c -------- */
715 * int gmatch(string, pattern)
716 * char *string, *pattern;
718 * Match a pattern as in sh(1).
721 #define CMASK 0377
722 #define QUOTE 0200
723 #define QMASK (CMASK&~QUOTE)
724 #define NOT '!' /* might use ^ */
727 gmatch(s, p)
728 register char *s, *p;
730 register int sc, pc;
732 if (s == NULL || p == NULL)
733 return(0);
734 while ((pc = *p++ & CMASK) != '\0') {
735 sc = *s++ & QMASK;
736 switch (pc) {
737 case '[':
738 if ((p = cclass(p, sc)) == NULL)
739 return(0);
740 break;
742 case '?':
743 if (sc == 0)
744 return(0);
745 break;
747 case '*':
748 s--;
749 do {
750 if (*p == '\0' || gmatch(s, p))
751 return(1);
752 } while (*s++ != '\0');
753 return(0);
755 default:
756 if (sc != (pc&~QUOTE))
757 return(0);
760 return(*s == 0);
763 static char *
764 cclass(p, sub)
765 register char *p;
766 register int sub;
768 register int c, d, not, found;
770 if ((not = *p == NOT) != 0)
771 p++;
772 found = not;
773 do {
774 if (*p == '\0')
775 return((char *)NULL);
776 c = *p & CMASK;
777 if (p[1] == '-' && p[2] != ']') {
778 d = p[2] & CMASK;
779 p++;
780 } else
781 d = c;
782 if (c == sub || (c <= sub && sub <= d))
783 found = !not;
784 } while (*++p != ']');
785 return(found? p+1: (char *)NULL);
788 /* -------- area.c -------- */
789 #define REGSIZE sizeof(struct region)
790 #define GROWBY 256
791 #undef SHRINKBY 64
792 #define FREE 32767
793 #define BUSY 0
794 #define ALIGN (sizeof(int)-1)
796 /* #include "area.h" */
798 struct region {
799 struct region *next;
800 int area;
804 * All memory between (char *)areabot and (char *)(areatop+1) is
805 * exclusively administered by the area management routines.
806 * It is assumed that sbrk() and brk() manipulate the high end.
808 static struct region *areabot; /* bottom of area */
809 static struct region *areatop; /* top of area */
810 static struct region *areanxt; /* starting point of scan */
812 void
813 initarea()
815 while ((int)sbrk(0) & ALIGN)
816 sbrk(1);
817 areabot = (struct region *)sbrk(REGSIZE);
818 areabot->next = areabot;
819 areabot->area = BUSY;
820 areatop = areabot;
821 areanxt = areabot;
824 char *
825 getcell(nbytes)
826 unsigned nbytes;
828 register int nregio;
829 register struct region *p, *q;
830 register i;
832 if (nbytes == 0)
833 abort(); /* silly and defeats the algorithm */
835 * round upwards and add administration area
837 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
838 for (p = areanxt;;) {
839 if (p->area > areanum) {
841 * merge free cells
843 while ((q = p->next)->area > areanum && q != areanxt)
844 p->next = q->next;
846 * exit loop if cell big enough
848 if (q >= p + nregio)
849 goto found;
851 p = p->next;
852 if (p == areanxt)
853 break;
855 i = nregio >= GROWBY ? nregio : GROWBY;
856 p = (struct region *)sbrk(i * REGSIZE);
857 if (p == (struct region *)-1)
858 return((char *)NULL);
859 p--;
860 if (p != areatop)
861 abort(); /* allocated areas are contiguous */
862 q = p + i;
863 p->next = q;
864 p->area = FREE;
865 q->next = areabot;
866 q->area = BUSY;
867 areatop = q;
868 found:
870 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
872 areanxt = p + nregio;
873 if (areanxt < q) {
875 * split into requested area and rest
877 if (areanxt+1 > q)
878 abort(); /* insufficient space left for admin */
879 areanxt->next = q;
880 areanxt->area = FREE;
881 p->next = areanxt;
883 p->area = areanum;
884 return((char *)(p+1));
887 void
888 freecell(cp)
889 char *cp;
891 register struct region *p;
893 if ((p = (struct region *)cp) != NULL) {
894 p--;
895 if (p < areanxt)
896 areanxt = p;
897 p->area = FREE;
901 void
902 freearea(a)
903 register int a;
905 register struct region *p, *top;
907 top = areatop;
908 for (p = areabot; p != top; p = p->next)
909 if (p->area >= a)
910 p->area = FREE;
913 void
914 setarea(cp,a)
915 char *cp;
916 int a;
918 register struct region *p;
920 if ((p = (struct region *)cp) != NULL)
921 (p-1)->area = a;
925 getarea(cp)
926 char *cp;
928 return ((struct region*)cp-1)->area;
931 void
932 garbage()
934 register struct region *p, *q, *top;
936 top = areatop;
937 for (p = areabot; p != top; p = p->next) {
938 if (p->area > areanum) {
939 while ((q = p->next)->area > areanum)
940 p->next = q->next;
941 areanxt = p;
944 #ifdef SHRINKBY
945 if (areatop >= q + SHRINKBY && q->area > areanum) {
946 brk((char *)(q+1));
947 q->next = areabot;
948 q->area = BUSY;
949 areatop = q;
951 #endif