📄 sh1.c
字号:
#define Extern extern#include <sys/types.h>#include <signal.h>#include <errno.h>#include <setjmp.h>#include "sh.h"/* -------- sh.c -------- *//* * shell *//* #include "sh.h" */int intr;int inparse;char flags['z'-'a'+1];char *flag = flags-'a';char *elinep = line+sizeof(line)-5;char *null = "";int heedint =1;struct env e ={line, iostack, iostack-1, (xint *)NULL, FDBASE, (struct env *)NULL};extern char **environ; /* environment pointer *//* * default shell, search rules */char shellname[] = "/bin/sh";char search[] = ":/bin:/usr/bin";_PROTOTYPE(void (*qflag), (int)) = SIG_IGN;_PROTOTYPE(int main, (int argc, char **argv ));_PROTOTYPE(int newfile, (char *s ));_PROTOTYPE(static char *findeq, (char *cp ));_PROTOTYPE(static char *cclass, (char *p, int sub ));_PROTOTYPE(void initarea, (void));int main(argc, argv)int argc;register char **argv;{ register int f; register char *s; int cflag; char *name, **ap; int (*iof)(); initarea(); if ((ap = environ) != NULL) { while (*ap) assign(*ap++, !COPYV); for (ap = environ; *ap;) export(lookup(*ap++)); } closeall(); areanum = 1; shell = lookup("SHELL"); if (shell->value == null) setval(shell, shellname); export(shell); homedir = lookup("HOME"); if (homedir->value == null) setval(homedir, "/"); export(homedir); setval(lookup("$"), itoa(getpid(), 5)); path = lookup("PATH"); if (path->value == null) setval(path, search); export(path); ifs = lookup("IFS"); if (ifs->value == null) setval(ifs, " \t\n"); prompt = lookup("PS1"); if (prompt->value == null)#ifndef UNIXSHELL setval(prompt, "$ ");#else setval(prompt, "% ");#endif if (geteuid() == 0) { setval(prompt, "# "); prompt->status &= ~EXPORT; } cprompt = lookup("PS2"); if (cprompt->value == null) setval(cprompt, "> "); iof = filechar; cflag = 0; name = *argv++; if (--argc >= 1) { if(argv[0][0] == '-' && argv[0][1] != '\0') { for (s = argv[0]+1; *s; s++) switch (*s) { case 'c': prompt->status &= ~EXPORT; cprompt->status &= ~EXPORT; setval(prompt, ""); setval(cprompt, ""); cflag = 1; if (--argc > 0) PUSHIO(aword, *++argv, iof = nlchar); break; case 'q': qflag = SIG_DFL; break; case 's': /* standard input */ break; case 't': prompt->status &= ~EXPORT; setval(prompt, ""); iof = linechar; break; case 'i': talking++; default: if (*s>='a' && *s<='z') flag[*s]++; } } else { argv--; argc++; } if (iof == filechar && --argc > 0) { setval(prompt, ""); setval(cprompt, ""); prompt->status &= ~EXPORT; cprompt->status &= ~EXPORT; if (newfile(name = *++argv)) exit(1); } } setdash(); if (e.iop < iostack) { PUSHIO(afile, 0, iof); if (isatty(0) && isatty(1) && !cflag) talking++; } signal(SIGQUIT, qflag); if (name && name[0] == '-') { talking++; if ((f = open(".profile", 0)) >= 0) next(remap(f)); if ((f = open("/etc/profile", 0)) >= 0) next(remap(f)); } if (talking) signal(SIGTERM, sig); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); dolv = argv; dolc = argc; dolv[0] = name; if (dolc > 1) for (ap = ++argv; --argc > 0;) if (assign(*ap = *argv++, !COPYV)) dolc--; /* keyword */ else ap++; setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); for (;;) { if (talking && e.iop <= iostack) prs(prompt->value); onecommand(); }}voidsetdash(){ register char *cp, c; char m['z'-'a'+1]; cp = m; for (c='a'; c<='z'; c++) if (flag[c]) *cp++ = c; *cp = 0; setval(lookup("-"), m);}intnewfile(s)register char *s;{ register f; if (strcmp(s, "-") != 0) { f = open(s, 0); if (f < 0) { prs(s); err(": cannot open"); return(1); } } else f = 0; next(remap(f)); return(0);}voidonecommand(){ register i; jmp_buf m1; while (e.oenv) quitenv(); areanum = 1; freehere(areanum); freearea(areanum); garbage(); wdlist = 0; iolist = 0; e.errpt = 0; e.linep = line; yynerrs = 0; multiline = 0; inparse = 1; intr = 0; execflg = 0; setjmp(failpt = m1); /* Bruce Evans' fix */ if (setjmp(failpt = m1) || yyparse() || intr) { while (e.oenv) quitenv(); scraphere(); if (!talking && intr) leave(); inparse = 0; intr = 0; return; } inparse = 0; brklist = 0; intr = 0; execflg = 0; if (!flag['n']) execute(outtree, NOPIPE, NOPIPE, 0); if (!talking && intr) { execflg = 0; leave(); } if ((i = trapset) != 0) { trapset = 0; runtrap(i); }}voidfail(){ longjmp(failpt, 1); /* NOTREACHED */}voidleave(){ if (execflg) fail(); scraphere(); freehere(1); runtrap(0); exit(exstat); /* NOTREACHED */}voidwarn(s)register char *s;{ if(*s) { prs(s); exstat = -1; } prs("\n"); if (flag['e']) leave();}voiderr(s)char *s;{ warn(s); if (flag['n']) return; if (!talking) leave(); if (e.errpt) longjmp(e.errpt, 1); closeall(); e.iop = e.iobase = iostack;}intnewenv(f)int f;{ register struct env *ep; if (f) { quitenv(); return(1); } ep = (struct env *) space(sizeof(*ep)); if (ep == NULL) { while (e.oenv) quitenv(); fail(); } *ep = e; e.oenv = ep; e.errpt = errpt; return(0);}voidquitenv(){ register struct env *ep; register fd; if ((ep = e.oenv) != NULL) { fd = e.iofd; e = *ep; /* should close `'d files */ DELETE(ep); while (--fd >= e.iofd) close(fd); }}/* * Is any character from s1 in s2? */intanys(s1, s2)register char *s1, *s2;{ while (*s1) if (any(*s1++, s2)) return(1); return(0);}/* * Is character c in s? */intany(c, s)register int c;register char *s;{ while (*s) if (*s++ == c) return(1); return(0);}char *putn(n)register int n;{ return(itoa(n, -1));}char *itoa(u, n)register unsigned u;int n;{ register char *cp; static char s[20]; int m; m = 0; if (n < 0 && (int) u < 0) { m++; u = -u; } cp = s+sizeof(s); *--cp = 0; do { *--cp = u%10 + '0'; u /= 10; } while (--n > 0 || u); if (m) *--cp = '-'; return(cp);}voidnext(f)int f;{ PUSHIO(afile, f, filechar);}voidonintr(s)int s; /* ANSI C requires a parameter */{ signal(SIGINT, onintr); intr = 1; if (talking) { if (inparse) { prs("\n"); fail(); } } else if (heedint) { execflg = 0; leave(); }}intletter(c)register c;{ return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');}intdigit(c)register c;{ return(c >= '0' && c <= '9');}intletnum(c)register c;{ return(letter(c) || digit(c));}char *space(n)int n;{ register char *cp; if ((cp = getcell(n)) == 0) err("out of string space"); return(cp);}char *strsave(s, a)register char *s;int a;{ register char *cp, *xp; if ((cp = space(strlen(s)+1)) != NULL) { setarea((char *)cp, a); for (xp = cp; (*xp++ = *s++) != '\0';) ; return(cp); } return("");}voidxfree(s)register char *s;{ DELETE(s);}/* * trap handling */voidsig(i)register int i;{ trapset = i; signal(i, sig);}void runtrap(i)int i;{ char *trapstr; if ((trapstr = trap[i]) == NULL) return; if (i == 0) trap[i] = 0; RUN(aword, trapstr, nlchar);}/* -------- var.c -------- *//* #include "sh.h" *//* * Find the given name in the dictionary * and return its value. If the name was * not previously there, enter it now and * return a null value. */struct var *lookup(n)register char *n;{ register struct var *vp; register char *cp; register int c; static struct var dummy; if (digit(*n)) { dummy.name = n; for (c = 0; digit(*n) && c < 1000; n++) c = c*10 + *n-'0'; dummy.status = RONLY; dummy.value = c <= dolc? dolv[c]: null; return(&dummy); } for (vp = vlist; vp; vp = vp->next) if (eqname(vp->name, n)) return(vp); cp = findeq(n); vp = (struct var *)space(sizeof(*vp)); if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) { dummy.name = dummy.value = ""; return(&dummy); } for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++) ; if (*cp == 0) *cp = '='; *++cp = 0; setarea((char *)vp, 0); setarea((char *)vp->name, 0); vp->value = null; vp->next = vlist; vp->status = GETCELL; vlist = vp; return(vp);}/* * give variable at `vp' the value `val'. */voidsetval(vp, val)struct var *vp;char *val;{ nameval(vp, val, (char *)NULL);}/* * if name is not NULL, it must be * a prefix of the space `val', * and end with `='. * this is all so that exporting * values is reasonably painless. */voidnameval(vp, val, name)register struct var *vp;char *val, *name;{ register char *cp, *xp; char *nv; int fl; if (vp->status & RONLY) { for (xp = vp->name; *xp && *xp != '=';) putc(*xp++); err(" is read-only"); return; } fl = 0; if (name == NULL) { xp = space(strlen(vp->name)+strlen(val)+2); if (xp == 0) return; /* make string: name=value */ setarea((char *)xp, 0); name = xp; for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++) ; if (*xp++ == 0) xp[-1] = '='; nv = xp; for (cp = val; (*xp++ = *cp++) != '\0';) ; val = nv; fl = GETCELL; } if (vp->status & GETCELL) xfree(vp->name); /* form new string `name=value' */ vp->name = name; vp->value = val; vp->status |= fl;}voidexport(vp)struct var *vp;{ vp->status |= EXPORT;}voidronly(vp)struct var *vp;{ if (letter(vp->name[0])) /* not an internal symbol ($# etc) */ vp->status |= RONLY;}intisassign(s)register char *s;{ if (!letter((int)*s)) return(0); for (; *s != '='; s++) if (*s == 0 || !letnum(*s)) return(0); return(1);}intassign(s, cf)register char *s;int cf;{ register char *cp; struct var *vp; if (!letter(*s)) return(0); for (cp = s; *cp != '='; cp++) if (*cp == 0 || !letnum(*cp)) return(0); vp = lookup(s); nameval(vp, ++cp, cf == COPYV? (char *)NULL: s); if (cf != COPYV) vp->status &= ~GETCELL; return(1);}intcheckname(cp)register char *cp;{ if (!letter(*cp++)) return(0); while (*cp) if (!letnum(*cp++)) return(0); return(1);}voidputvlist(f, out)register int f, out;{ register struct var *vp; for (vp = vlist; vp; vp = vp->next) if (vp->status & f && letter(*vp->name)) { if (vp->status & EXPORT) write(out, "export ", 7); if (vp->status & RONLY) write(out, "readonly ", 9); write(out, vp->name, (int)(findeq(vp->name) - vp->name)); write(out, "\n", 1); }}inteqname(n1, n2)register char *n1, *n2;{ for (; *n1 != '=' && *n1 != 0; n1++) if (*n2++ != *n1) return(0); return(*n2 == 0 || *n2 == '=');}static char *findeq(cp)register char *cp;{ while (*cp != '\0' && *cp != '=') cp++; return(cp);}/* -------- gmatch.c -------- *//* * int gmatch(string, pattern) * char *string, *pattern; * * Match a pattern as in sh(1). */#define CMASK 0377#define QUOTE 0200#define QMASK (CMASK&~QUOTE)#define NOT '!' /* might use ^ */intgmatch(s, p)register char *s, *p;{ register int sc, pc; if (s == NULL || p == NULL) return(0); while ((pc = *p++ & CMASK) != '\0') { sc = *s++ & QMASK; switch (pc) { case '[': if ((p = cclass(p, sc)) == NULL) return(0); break; case '?': if (sc == 0) return(0); break; case '*': s--; do { if (*p == '\0' || gmatch(s, p)) return(1); } while (*s++ != '\0'); return(0); default: if (sc != (pc&~QUOTE)) return(0); } } return(*s == 0);}static char *cclass(p, sub)register char *p;register int sub;{ register int c, d, not, found; if ((not = *p == NOT) != 0) p++; found = not; do { if (*p == '\0') return((char *)NULL); c = *p & CMASK; if (p[1] == '-' && p[2] != ']') { d = p[2] & CMASK; p++; } else d = c; if (c == sub || (c <= sub && sub <= d)) found = !not; } while (*++p != ']'); return(found? p+1: (char *)NULL);}/* -------- area.c -------- */#define REGSIZE sizeof(struct region)#define GROWBY 256#undef SHRINKBY 64#define FREE 32767#define BUSY 0#define ALIGN (sizeof(int)-1)/* #include "area.h" */struct region { struct region *next; int area;};/* * All memory between (char *)areabot and (char *)(areatop+1) is * exclusively administered by the area management routines. * It is assumed that sbrk() and brk() manipulate the high end. */static struct region *areabot; /* bottom of area */static struct region *areatop; /* top of area */static struct region *areanxt; /* starting point of scan */voidinitarea(){ while ((int)sbrk(0) & ALIGN) sbrk(1); areabot = (struct region *)sbrk(REGSIZE); areabot->next = areabot; areabot->area = BUSY; areatop = areabot; areanxt = areabot;}char *getcell(nbytes)unsigned nbytes;{ register int nregio; register struct region *p, *q; register i; if (nbytes == 0) abort(); /* silly and defeats the algorithm */ /* * round upwards and add administration area */ nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1; for (p = areanxt;;) { if (p->area > areanum) { /* * merge free cells */ while ((q = p->next)->area > areanum && q != areanxt) p->next = q->next; /* * exit loop if cell big enough */ if (q >= p + nregio) goto found; } p = p->next; if (p == areanxt) break; } i = nregio >= GROWBY ? nregio : GROWBY; p = (struct region *)sbrk(i * REGSIZE); if (p == (struct region *)-1) return((char *)NULL); p--; if (p != areatop) abort(); /* allocated areas are contiguous */ q = p + i; p->next = q; p->area = FREE; q->next = areabot; q->area = BUSY; areatop = q;found: /* * we found a FREE area big enough, pointed to by 'p', and up to 'q' */ areanxt = p + nregio; if (areanxt < q) { /* * split into requested area and rest */ if (areanxt+1 > q) abort(); /* insufficient space left for admin */ areanxt->next = q; areanxt->area = FREE; p->next = areanxt; } p->area = areanum; return((char *)(p+1));}voidfreecell(cp)char *cp;{ register struct region *p; if ((p = (struct region *)cp) != NULL) { p--; if (p < areanxt) areanxt = p; p->area = FREE; }}voidfreearea(a)register int a;{ register struct region *p, *top; top = areatop; for (p = areabot; p != top; p = p->next) if (p->area >= a) p->area = FREE;}voidsetarea(cp,a)char *cp;int a;{ register struct region *p; if ((p = (struct region *)cp) != NULL) (p-1)->area = a;}intgetarea(cp)char *cp;{ return ((struct region*)cp-1)->area;}voidgarbage(){ register struct region *p, *q, *top; top = areatop; for (p = areabot; p != top; p = p->next) { if (p->area > areanum) { while ((q = p->next)->area > areanum) p->next = q->next; areanxt = p; } }#ifdef SHRINKBY if (areatop >= q + SHRINKBY && q->area > areanum) { brk((char *)(q+1)); q->next = areabot; q->area = BUSY; areatop = q; }#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -