source: trunk/minix/commands/sh/sh1.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 14.5 KB
Line 
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
10 */
11
12/* #include "sh.h" */
13
14int intr;
15int inparse;
16char flags['z'-'a'+1];
17char *flag = flags-'a';
18char *elinep = line+sizeof(line)-5;
19char *null = "";
20int heedint =1;
21struct env e ={line, iostack, iostack-1,
22 (xint *)NULL, FDBASE, (struct env *)NULL};
23
24extern char **environ; /* environment pointer */
25
26/*
27 * default shell, search rules
28 */
29char shellname[] = "/bin/sh";
30char search[] = ":/bin:/usr/bin";
31
32_PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
33
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));
39
40int main(argc, argv)
41int argc;
42register char **argv;
43{
44 register int f;
45 register char *s;
46 int cflag;
47 char *name, **ap;
48 int (*iof)();
49
50 initarea();
51 if ((ap = environ) != NULL) {
52 while (*ap)
53 assign(*ap++, !COPYV);
54 for (ap = environ; *ap;)
55 export(lookup(*ap++));
56 }
57 closeall();
58 areanum = 1;
59
60 shell = lookup("SHELL");
61 if (shell->value == null)
62 setval(shell, shellname);
63 export(shell);
64
65 homedir = lookup("HOME");
66 if (homedir->value == null)
67 setval(homedir, "/");
68 export(homedir);
69
70 setval(lookup("$"), itoa(getpid(), 5));
71
72 path = lookup("PATH");
73 if (path->value == null)
74 setval(path, search);
75 export(path);
76
77 ifs = lookup("IFS");
78 if (ifs->value == null)
79 setval(ifs, " \t\n");
80
81 prompt = lookup("PS1");
82 if (prompt->value == null)
83#ifndef UNIXSHELL
84 setval(prompt, "$ ");
85#else
86 setval(prompt, "% ");
87#endif
88
89 if (geteuid() == 0) {
90 setval(prompt, "# ");
91 prompt->status &= ~EXPORT;
92 }
93 cprompt = lookup("PS2");
94 if (cprompt->value == null)
95 setval(cprompt, "> ");
96
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;
113
114 case 'q':
115 qflag = SIG_DFL;
116 break;
117
118 case 's':
119 /* standard input */
120 break;
121
122 case 't':
123 prompt->status &= ~EXPORT;
124 setval(prompt, "");
125 iof = linechar;
126 break;
127
128 case 'i':
129 talking++;
130 default:
131 if (*s>='a' && *s<='z')
132 flag[*s]++;
133 }
134 } else {
135 argv--;
136 argc++;
137 }
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);
145 }
146 }
147 setdash();
148 if (e.iop < iostack) {
149 PUSHIO(afile, 0, iof);
150 if (isatty(0) && isatty(1) && !cflag)
151 talking++;
152 }
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));
160 }
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));
175
176 for (;;) {
177 if (talking && e.iop <= iostack)
178 prs(prompt->value);
179 onecommand();
180 }
181}
182
183void
184setdash()
185{
186 register char *cp, c;
187 char m['z'-'a'+1];
188
189 cp = m;
190 for (c='a'; c<='z'; c++)
191 if (flag[c])
192 *cp++ = c;
193 *cp = 0;
194 setval(lookup("-"), m);
195}
196
197int
198newfile(s)
199register char *s;
200{
201 register f;
202
203 if (strcmp(s, "-") != 0) {
204 f = open(s, 0);
205 if (f < 0) {
206 prs(s);
207 err(": cannot open");
208 return(1);
209 }
210 } else
211 f = 0;
212 next(remap(f));
213 return(0);
214}
215
216void
217onecommand()
218{
219 register i;
220 jmp_buf m1;
221
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;
247 }
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();
257 }
258 if ((i = trapset) != 0) {
259 trapset = 0;
260 runtrap(i);
261 }
262}
263
264void
265fail()
266{
267 longjmp(failpt, 1);
268 /* NOTREACHED */
269}
270
271void
272leave()
273{
274 if (execflg)
275 fail();
276 scraphere();
277 freehere(1);
278 runtrap(0);
279 exit(exstat);
280 /* NOTREACHED */
281}
282
283void
284warn(s)
285register char *s;
286{
287 if(*s) {
288 prs(s);
289 exstat = -1;
290 }
291 prs("\n");
292 if (flag['e'])
293 leave();
294}
295
296void
297err(s)
298char *s;
299{
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;
309}
310
311int
312newenv(f)
313int f;
314{
315 register struct env *ep;
316
317 if (f) {
318 quitenv();
319 return(1);
320 }
321 ep = (struct env *) space(sizeof(*ep));
322 if (ep == NULL) {
323 while (e.oenv)
324 quitenv();
325 fail();
326 }
327 *ep = e;
328 e.oenv = ep;
329 e.errpt = errpt;
330 return(0);
331}
332
333void
334quitenv()
335{
336 register struct env *ep;
337 register fd;
338
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);
346 }
347}
348
349/*
350 * Is any character from s1 in s2?
351 */
352int
353anys(s1, s2)
354register char *s1, *s2;
355{
356 while (*s1)
357 if (any(*s1++, s2))
358 return(1);
359 return(0);
360}
361
362/*
363 * Is character c in s?
364 */
365int
366any(c, s)
367register int c;
368register char *s;
369{
370 while (*s)
371 if (*s++ == c)
372 return(1);
373 return(0);
374}
375
376char *
377putn(n)
378register int n;
379{
380 return(itoa(n, -1));
381}
382
383char *
384itoa(u, n)
385register unsigned u;
386int n;
387{
388 register char *cp;
389 static char s[20];
390 int m;
391
392 m = 0;
393 if (n < 0 && (int) u < 0) {
394 m++;
395 u = -u;
396 }
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);
406}
407
408void
409next(f)
410int f;
411{
412 PUSHIO(afile, f, filechar);
413}
414
415void
416onintr(s)
417int s; /* ANSI C requires a parameter */
418{
419 signal(SIGINT, onintr);
420 intr = 1;
421 if (talking) {
422 if (inparse) {
423 prs("\n");
424 fail();
425 }
426 }
427 else if (heedint) {
428 execflg = 0;
429 leave();
430 }
431}
432
433int
434letter(c)
435register c;
436{
437 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
438}
439
440int
441digit(c)
442register c;
443{
444 return(c >= '0' && c <= '9');
445}
446
447int
448letnum(c)
449register c;
450{
451 return(letter(c) || digit(c));
452}
453
454char *
455space(n)
456int n;
457{
458 register char *cp;
459
460 if ((cp = getcell(n)) == 0)
461 err("out of string space");
462 return(cp);
463}
464
465char *
466strsave(s, a)
467register char *s;
468int a;
469{
470 register char *cp, *xp;
471
472 if ((cp = space(strlen(s)+1)) != NULL) {
473 setarea((char *)cp, a);
474 for (xp = cp; (*xp++ = *s++) != '\0';)
475 ;
476 return(cp);
477 }
478 return("");
479}
480
481void
482xfree(s)
483register char *s;
484{
485 DELETE(s);
486}
487
488/*
489 * trap handling
490 */
491void
492sig(i)
493register int i;
494{
495 trapset = i;
496 signal(i, sig);
497}
498
499void runtrap(i)
500int i;
501{
502 char *trapstr;
503
504 if ((trapstr = trap[i]) == NULL)
505 return;
506 if (i == 0)
507 trap[i] = 0;
508 RUN(aword, trapstr, nlchar);
509}
510
511/* -------- var.c -------- */
512/* #include "sh.h" */
513
514/*
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.
519 */
520struct var *
521lookup(n)
522register char *n;
523{
524 register struct var *vp;
525 register char *cp;
526 register int c;
527 static struct var dummy;
528
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);
536 }
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);
545 }
546 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
547 ;
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);
558}
559
560/*
561 * give variable at `vp' the value `val'.
562 */
563void
564setval(vp, val)
565struct var *vp;
566char *val;
567{
568 nameval(vp, val, (char *)NULL);
569}
570
571/*
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.
577 */
578void
579nameval(vp, val, name)
580register struct var *vp;
581char *val, *name;
582{
583 register char *cp, *xp;
584 char *nv;
585 int fl;
586
587 if (vp->status & RONLY) {
588 for (xp = vp->name; *xp && *xp != '=';)
589 putc(*xp++);
590 err(" is read-only");
591 return;
592 }
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++)
602 ;
603 if (*xp++ == 0)
604 xp[-1] = '=';
605 nv = xp;
606 for (cp = val; (*xp++ = *cp++) != '\0';)
607 ;
608 val = nv;
609 fl = GETCELL;
610 }
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;
616}
617
618void
619export(vp)
620struct var *vp;
621{
622 vp->status |= EXPORT;
623}
624
625void
626ronly(vp)
627struct var *vp;
628{
629 if (letter(vp->name[0])) /* not an internal symbol ($# etc) */
630 vp->status |= RONLY;
631}
632
633int
634isassign(s)
635register char *s;
636{
637 if (!letter((int)*s))
638 return(0);
639 for (; *s != '='; s++)
640 if (*s == 0 || !letnum(*s))
641 return(0);
642 return(1);
643}
644
645int
646assign(s, cf)
647register char *s;
648int cf;
649{
650 register char *cp;
651 struct var *vp;
652
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);
663}
664
665int
666checkname(cp)
667register char *cp;
668{
669 if (!letter(*cp++))
670 return(0);
671 while (*cp)
672 if (!letnum(*cp++))
673 return(0);
674 return(1);
675}
676
677void
678putvlist(f, out)
679register int f, out;
680{
681 register struct var *vp;
682
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);
691 }
692}
693
694int
695eqname(n1, n2)
696register char *n1, *n2;
697{
698 for (; *n1 != '=' && *n1 != 0; n1++)
699 if (*n2++ != *n1)
700 return(0);
701 return(*n2 == 0 || *n2 == '=');
702}
703
704static char *
705findeq(cp)
706register char *cp;
707{
708 while (*cp != '\0' && *cp != '=')
709 cp++;
710 return(cp);
711}
712
713/* -------- gmatch.c -------- */
714/*
715 * int gmatch(string, pattern)
716 * char *string, *pattern;
717 *
718 * Match a pattern as in sh(1).
719 */
720
721#define CMASK 0377
722#define QUOTE 0200
723#define QMASK (CMASK&~QUOTE)
724#define NOT '!' /* might use ^ */
725
726int
727gmatch(s, p)
728register char *s, *p;
729{
730 register int sc, pc;
731
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;
741
742 case '?':
743 if (sc == 0)
744 return(0);
745 break;
746
747 case '*':
748 s--;
749 do {
750 if (*p == '\0' || gmatch(s, p))
751 return(1);
752 } while (*s++ != '\0');
753 return(0);
754
755 default:
756 if (sc != (pc&~QUOTE))
757 return(0);
758 }
759 }
760 return(*s == 0);
761}
762
763static char *
764cclass(p, sub)
765register char *p;
766register int sub;
767{
768 register int c, d, not, found;
769
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);
786}
787
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)
795
796/* #include "area.h" */
797
798struct region {
799 struct region *next;
800 int area;
801};
802
803/*
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.
807 */
808static struct region *areabot; /* bottom of area */
809static struct region *areatop; /* top of area */
810static struct region *areanxt; /* starting point of scan */
811
812void
813initarea()
814{
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;
822}
823
824char *
825getcell(nbytes)
826unsigned nbytes;
827{
828 register int nregio;
829 register struct region *p, *q;
830 register i;
831
832 if (nbytes == 0)
833 abort(); /* silly and defeats the algorithm */
834 /*
835 * round upwards and add administration area
836 */
837 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
838 for (p = areanxt;;) {
839 if (p->area > areanum) {
840 /*
841 * merge free cells
842 */
843 while ((q = p->next)->area > areanum && q != areanxt)
844 p->next = q->next;
845 /*
846 * exit loop if cell big enough
847 */
848 if (q >= p + nregio)
849 goto found;
850 }
851 p = p->next;
852 if (p == areanxt)
853 break;
854 }
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;
868found:
869 /*
870 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
871 */
872 areanxt = p + nregio;
873 if (areanxt < q) {
874 /*
875 * split into requested area and rest
876 */
877 if (areanxt+1 > q)
878 abort(); /* insufficient space left for admin */
879 areanxt->next = q;
880 areanxt->area = FREE;
881 p->next = areanxt;
882 }
883 p->area = areanum;
884 return((char *)(p+1));
885}
886
887void
888freecell(cp)
889char *cp;
890{
891 register struct region *p;
892
893 if ((p = (struct region *)cp) != NULL) {
894 p--;
895 if (p < areanxt)
896 areanxt = p;
897 p->area = FREE;
898 }
899}
900
901void
902freearea(a)
903register int a;
904{
905 register struct region *p, *top;
906
907 top = areatop;
908 for (p = areabot; p != top; p = p->next)
909 if (p->area >= a)
910 p->area = FREE;
911}
912
913void
914setarea(cp,a)
915char *cp;
916int a;
917{
918 register struct region *p;
919
920 if ((p = (struct region *)cp) != NULL)
921 (p-1)->area = a;
922}
923
924int
925getarea(cp)
926char *cp;
927{
928 return ((struct region*)cp-1)->area;
929}
930
931void
932garbage()
933{
934 register struct region *p, *q, *top;
935
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;
942 }
943 }
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;
950 }
951#endif
952}
Note: See TracBrowser for help on using the repository browser.