8 /* -------- sh.c -------- */
17 char flags['z'-'a'+1];
18 char *flag = flags-'a';
19 char *elinep = line+sizeof(line)-5;
22 struct env e ={line, iostack, iostack-1,
23 (xint *)NULL, FDBASE, (struct env *)NULL};
25 extern char **environ; /* environment pointer */
28 * default shell, search rules
30 char shellname[] = "/bin/sh";
31 char search[] = ":/bin:/usr/bin";
33 _PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
35 _PROTOTYPE(int main, (int argc, char **argv ));
36 _PROTOTYPE(int newfile, (char *s ));
37 _PROTOTYPE(static char *findeq, (char *cp ));
38 _PROTOTYPE(static char *cclass, (char *p, int sub ));
39 _PROTOTYPE(void initarea, (void));
52 if ((ap = environ) != NULL) {
54 assign(*ap++, !COPYV);
55 for (ap = environ; *ap;)
56 export(lookup(*ap++));
61 shell = lookup("SHELL");
62 if (shell->value == null)
63 setval(shell, shellname);
66 homedir = lookup("HOME");
67 if (homedir->value == null)
71 setval(lookup("$"), itoa(getpid(), 5));
73 path = lookup("PATH");
74 if (path->value == null)
79 if (ifs->value == null)
82 prompt = lookup("PS1");
83 if (prompt->value == null)
92 prompt->status &= ~EXPORT;
94 cprompt = lookup("PS2");
95 if (cprompt->value == null)
96 setval(cprompt, "> ");
102 if(argv[0][0] == '-' && argv[0][1] != '\0') {
103 for (s = argv[0]+1; *s; s++)
106 prompt->status &= ~EXPORT;
107 cprompt->status &= ~EXPORT;
112 PUSHIO(aword, *++argv, iof = nlchar);
124 prompt->status &= ~EXPORT;
132 if (*s>='a' && *s<='z')
139 if (iof == filechar && --argc > 0) {
142 prompt->status &= ~EXPORT;
143 cprompt->status &= ~EXPORT;
144 if (newfile(name = *++argv))
149 if (e.iop < iostack) {
150 PUSHIO(afile, 0, iof);
151 if (isatty(0) && isatty(1) && !cflag)
154 signal(SIGQUIT, qflag);
155 if (name && name[0] == '-') {
157 if ((f = open(".profile", 0)) >= 0)
159 if ((f = open("/etc/profile", 0)) >= 0)
163 signal(SIGTERM, sig);
164 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
165 signal(SIGINT, onintr);
170 for (ap = ++argv; --argc > 0;)
171 if (assign(*ap = *argv++, !COPYV))
172 dolc--; /* keyword */
175 setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
178 if (talking && e.iop <= iostack)
187 register char *cp, c;
191 for (c='a'; c<='z'; c++)
195 setval(lookup("-"), m);
204 if (strcmp(s, "-") != 0) {
208 err(": cannot open");
238 setjmp(failpt = m1); /* Bruce Evans' fix */
239 if (setjmp(failpt = m1) || yyparse() || intr) {
243 if (!talking && intr)
254 execute(outtree, NOPIPE, NOPIPE, 0);
255 if (!talking && intr) {
259 if ((i = trapset) != 0) {
309 e.iop = e.iobase = iostack;
316 register struct env *ep;
322 ep = (struct env *) space(sizeof(*ep));
337 register struct env *ep;
340 if ((ep = e.oenv) != NULL) {
343 /* should close `'d files */
345 while (--fd >= e.iofd)
351 * Is any character from s1 in s2?
355 register char *s1, *s2;
364 * Is character c in s?
394 if (n < 0 && (int) u < 0) {
403 } while (--n > 0 || u);
413 PUSHIO(afile, f, filechar);
418 int s; /* ANSI C requires a parameter */
420 signal(SIGINT, onintr);
438 return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
445 return(c >= '0' && c <= '9');
452 return(letter(c) || digit(c));
461 if ((cp = getcell(n)) == 0)
462 err("out of string space");
471 register char *cp, *xp;
473 if ((cp = space(strlen(s)+1)) != NULL) {
474 setarea((char *)cp, a);
475 for (xp = cp; (*xp++ = *s++) != '\0';)
505 if ((trapstr = trap[i]) == NULL)
509 RUN(aword, trapstr, nlchar);
512 /* -------- var.c -------- */
513 /* #include "sh.h" */
516 * Find the given name in the dictionary
517 * and return its value. If the name was
518 * not previously there, enter it now and
519 * return a null value.
525 register struct var *vp;
528 static struct var dummy;
532 for (c = 0; digit(*n) && c < 1000; n++)
534 dummy.status = RONLY;
535 dummy.value = c <= dolc? dolv[c]: null;
538 for (vp = vlist; vp; vp = vp->next)
539 if (eqname(vp->name, n))
542 vp = (struct var *)space(sizeof(*vp));
543 if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
544 dummy.name = dummy.value = "";
547 for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
552 setarea((char *)vp, 0);
553 setarea((char *)vp->name, 0);
556 vp->status = GETCELL;
562 * give variable at `vp' the value `val'.
569 nameval(vp, val, (char *)NULL);
573 * if name is not NULL, it must be
574 * a prefix of the space `val',
576 * this is all so that exporting
577 * values is reasonably painless.
580 nameval(vp, val, name)
581 register struct var *vp;
584 register char *cp, *xp;
588 if (vp->status & RONLY) {
589 for (xp = vp->name; *xp && *xp != '=';)
591 err(" is read-only");
596 xp = space(strlen(vp->name)+strlen(val)+2);
599 /* make string: name=value */
600 setarea((char *)xp, 0);
602 for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
607 for (cp = val; (*xp++ = *cp++) != '\0';)
612 if (vp->status & GETCELL)
613 xfree(vp->name); /* form new string `name=value' */
623 vp->status |= EXPORT;
630 if (letter(vp->name[0])) /* not an internal symbol ($# etc) */
638 if (!letter((int)*s))
640 for (; *s != '='; s++)
641 if (*s == 0 || !letnum(*s))
656 for (cp = s; *cp != '='; cp++)
657 if (*cp == 0 || !letnum(*cp))
660 nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
662 vp->status &= ~GETCELL;
682 register struct var *vp;
684 for (vp = vlist; vp; vp = vp->next)
685 if (vp->status & f && letter(*vp->name)) {
686 if (vp->status & EXPORT)
687 write(out, "export ", 7);
688 if (vp->status & RONLY)
689 write(out, "readonly ", 9);
690 write(out, vp->name, (int)(findeq(vp->name) - vp->name));
697 register char *n1, *n2;
699 for (; *n1 != '=' && *n1 != 0; n1++)
702 return(*n2 == 0 || *n2 == '=');
709 while (*cp != '\0' && *cp != '=')
714 /* -------- gmatch.c -------- */
716 * int gmatch(string, pattern)
717 * char *string, *pattern;
719 * Match a pattern as in sh(1).
724 #define QMASK (CMASK&~QUOTE)
725 #define NOT '!' /* might use ^ */
729 register char *s, *p;
733 if (s == NULL || p == NULL)
735 while ((pc = *p++ & CMASK) != '\0') {
739 if ((p = cclass(p, sc)) == NULL)
751 if (*p == '\0' || gmatch(s, p))
753 } while (*s++ != '\0');
757 if (sc != (pc&~QUOTE))
769 register int c, d, not, found;
771 if ((not = *p == NOT) != 0)
776 return((char *)NULL);
778 if (p[1] == '-' && p[2] != ']') {
783 if (c == sub || (c <= sub && sub <= d))
785 } while (*++p != ']');
786 return(found? p+1: (char *)NULL);
789 /* -------- area.c -------- */
790 #define REGSIZE sizeof(struct region)
795 #define ALIGN (sizeof(int)-1)
797 /* #include "area.h" */
805 * All memory between (char *)areabot and (char *)(areatop+1) is
806 * exclusively administered by the area management routines.
807 * It is assumed that sbrk() and brk() manipulate the high end.
809 static struct region *areabot; /* bottom of area */
810 static struct region *areatop; /* top of area */
811 static struct region *areanxt; /* starting point of scan */
816 while ((int)sbrk(0) & ALIGN)
818 areabot = (struct region *)sbrk(REGSIZE);
819 areabot->next = areabot;
820 areabot->area = BUSY;
830 register struct region *p, *q;
834 abort(); /* silly and defeats the algorithm */
836 * round upwards and add administration area
838 nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
839 for (p = areanxt;;) {
840 if (p->area > areanum) {
844 while ((q = p->next)->area > areanum && q != areanxt)
847 * exit loop if cell big enough
856 i = nregio >= GROWBY ? nregio : GROWBY;
857 p = (struct region *)sbrk(i * REGSIZE);
858 if (p == (struct region *)-1)
859 return((char *)NULL);
862 abort(); /* allocated areas are contiguous */
871 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
873 areanxt = p + nregio;
876 * split into requested area and rest
879 abort(); /* insufficient space left for admin */
881 areanxt->area = FREE;
885 return((char *)(p+1));
892 register struct region *p;
894 if ((p = (struct region *)cp) != NULL) {
906 register struct region *p, *top;
909 for (p = areabot; p != top; p = p->next)
919 register struct region *p;
921 if ((p = (struct region *)cp) != NULL)
929 return ((struct region*)cp-1)->area;
935 register struct region *p, *q, *top;
938 for (p = areabot; p != top; p = p->next) {
939 if (p->area > areanum) {
940 while ((q = p->next)->area > areanum)
946 if (areatop >= q + SHRINKBY && q->area > areanum) {