sh.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,098 行 · 第 1/2 页
C
1,098 行
* We could avoid the critical region by grouping all the stuff * in a single structure and pointing at it to move it all at * once. This is less efficient globally on many variable references * however. */ getexit(oldexit); reenter = 0; if (setintr) omask = sigblock(sigmask(SIGINT)); setexit(); reenter++; if (reenter == 1) { /* Setup the new values of the state stuff saved above */ copy((char *)&saveB, (char *)&B, sizeof saveB); fbuf = (char **) 0; fseekp = feobp = fblocks = 0; oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; intty = isatty(SHIN), whyles = 0, gointr = 0; evalvec = 0; evalp = 0; enterhist = hflg; if (enterhist) HIST = '\0'; /* * Now if we are allowing commands to be interrupted, * we let ourselves be interrupted. */ if (setintr) (void) sigsetmask(omask);#ifdef TELL settell();#endif process(0); /* 0 -> blow away on errors */ } if (setintr) (void) sigsetmask(omask); if (oSHIN >= 0) { register int i; /* We made it to the new state... free up its storage */ /* This code could get run twice but xfree doesn't care */ for (i = 0; i < fblocks; i++) xfree(fbuf[i]); xfree((char *)fbuf); /* Reset input arena */ copy((char *)&B, (char *)&saveB, sizeof B); (void) close(SHIN), SHIN = oSHIN; arginp = oarginp, onelflg = oonelflg; evalp = oevalp, evalvec = oevalvec; intty = oldintty, whyles = oldwhyl, gointr = ogointr; if (enterhist) HIST = OHIST; enterhist = oenterhist;#ifdef TELL cantell = otell;#endif } resexit(oldexit); /* * If process reset() (effectively an unwind) then * we must also unwind. */ if (reenter >= 2) error(NOSTR);}rechist(){ char buf[BUFSIZ]; int fp, ftmp, oldidfds; if (!fast) { if (value("savehist")[0] == '\0') return; (void) strcpy(buf, value("home")); (void) strcat(buf, "/.history"); fp = creat(buf, 0666); if (fp == -1) return; oldidfds = didfds; didfds = 0; ftmp = SHOUT; SHOUT = fp; (void) strcpy(buf, value("savehist")); dumphist[2] = buf; dohist(dumphist); (void) close(fp); SHOUT = ftmp; didfds = oldidfds; }}goodbye(){ if (loginsh) { (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); setintr = 0; /* No interrupts after "logout" */ if (adrof("home")) srccat(value("home"), "/.logout"); } rechist(); exitstat();}exitstat(){#ifdef PROF monitor(0);#endif /* * Note that if STATUS is corrupted (i.e. getn bombs) * then error will exit directly because we poke child here. * Otherwise we might continue unwarrantedly (sic). */ child++; exit(getn(value("status")));}/* * in the event of a HUP we want to save the history */phup(){ rechist(); exit(1);}char *jobargv[2] = { "jobs", 0 };/* * Catch an interrupt, e.g. during lexical input. * If we are an interactive shell, we reset the interrupt catch * immediately. In any case we drain the shell output, * and finally go through the normal error mechanism, which * gets a chance to make the shell go away. */pintr(){ pintr1(1);}pintr1(wantnl) bool wantnl;{ register char **v; int omask; omask = sigblock(0); if (setintr) { (void) sigsetmask(omask & ~sigmask(SIGINT)); if (pjobs) { pjobs = 0; csh_printf("\n"); /* 005 RNF */ dojobs(jobargv); bferr("Interrupted"); } } (void) sigsetmask(omask & ~sigmask(SIGCHLD)); draino(); /* * If we have an active "onintr" then we search for the label. * Note that if one does "onintr -" then we shan't be interruptible * so we needn't worry about that here. */ if (gointr) { search(ZGOTO, 0, gointr); timflg = 0; if (v = pargv) pargv = 0, blkfree(v); if (v = gargv) gargv = 0, blkfree(v); reset(); } else if (intty && wantnl) csh_printf("\n");/* 005 RNF */ /* Some like this, others don't */ error(NOSTR);}/* * Process is the main driving routine for the shell. * It runs all command processing, except for those within { ... } * in expressions (which is run by a routine evalav in sh.exp.c which * is a stripped down process), and `...` evaluation which is run * also by a subset of this code in sh.glob.c in the routine backeval. * * The code here is a little strange because part of it is interruptible * and hence freeing of structures appears to occur when none is necessary * if this is ignored. * * Note that if catch is not set then we will unwind on any error. * If an end-of-file occurs, we return. */process(catch) bool catch;{ jmp_buf osetexit; register struct command *t; getexit(osetexit); for (;;) { pendjob(); paraml.next = paraml.prev = ¶ml; paraml.word = ""; t = 0; setexit(); justpr = enterhist; /* execute if not entering history */#ifdef CSHEDIT editline = 0; /* clear flag */#endif /* * Interruptible during interactive reads */ if (setintr) (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); /* * For the sake of reset() */ freelex(¶ml), freesyn(t), t = 0; if (haderr) { if (!catch) { /* unwind */ doneinp = 0; resexit(osetexit); reset(); } haderr = 0; /* * Every error is eventually caught here or * the shell dies. It is at this * point that we clean up any left-over open * files, by closing all but a fixed number * of pre-defined files. Thus routines don't * have to worry about leaving files open due * to deeper errors... they will get closed here. */ closem(); continue; } if (doneinp) { doneinp = 0; break; } if (chkstop) chkstop--; if (neednote) pnote(); if (intty && prompt && evalvec == 0) { mailchk(); /* * If we are at the end of the input buffer * then we are going to read fresh stuff. * Otherwise, we are rereading input and don't * need or want to prompt. */ if (fseekp == feobp) printprompt(); flush(); } err = 0; /* * Initialize the last event here so that relative history * accesses (ie !$ !*) remain relative. */ lastev = eventno; /* * Echo not only on VERBOSE, but also with history expansion. * If there is a lexical error then we forego history echo. * If :v option was given (for edit) then skip echo. */#ifdef CSHEDIT if (lex(¶ml, 0) && !err && intty && !editline || adrof("verbose")) {#else if (lex(¶ml) && !err && intty || adrof("verbose")) {#endif haderr = 1; prlex(¶ml); haderr = 0; }#ifdef CSHEDIT /* * If had a history command :v modifier then * go into edit mode. - afd */ if (editline) { editcmd(¶ml); editline = 0; paraml.next = paraml.prev = ¶ml; paraml.word = ""; err = 0; /* * Echo new command line. */ if (lex(¶ml, 1) && !err && intty || adrof("verbose")) { haderr = 1; prlex(¶ml); haderr = 0; } }#endif /* * The parser may lose space if interrupted. */ if (setintr) (void) sigblock(sigmask(SIGINT)); /* * Save input text on the history list if * reading in old history, or it * is from the terminal at the top level and not * in a loop. */ if (enterhist || catch && intty && !whyles) savehist(¶ml); /* * Print lexical error messages, except when sourcing * history lists. */ if (!enterhist && err) /* * It would be nice if we could bury eventno++ in * error(). * To many "uninteresting events" use error() to * jump back here. */ eventno++, error(err); /* * If had a history command :p modifier then * this is as far as we should go */ if (justpr) eventno++, reset(); alias(¶ml); /* * Parse the words of the input into a parse tree. */ t = syntax(paraml.next, ¶ml, 0); if (err) eventno++, error(err); /* * Increment the acutal event number here. * If we waited till after execute(), interupted commands * would not get their history counter incremented. * We pad the eventno when savehist() above calls enthist() * to place the current command in the history list. */ if ( t && intty && !whyles ) eventno++; /* * Execute the parse tree */ execute(t, tpgrp); /* * Made it! */ freelex(¶ml), freesyn(t); } resexit(osetexit);}dosource(t) register char **t;{ register char *f; register int u; bool hflg = 0; char buf[BUFSIZ]; struct stat stb; t++; if (*t && eq(*t, "-h")) { t++; hflg++; } (void) strcpy(buf, *t); f = globone(buf); if(!hflg) /* 004 RNF */ { if(stat(f, &stb) < 0) Perror(f); else if((stb.st_mode & S_IFMT) != S_IFREG) { seterr2(f, ": Not a regular file"); error(err); } } u = dmove(open(f, 0), -1); xfree(f); if (u < 0 && !hflg) Perror(f); srcunit(u, 0, hflg);}/* * Check for mail. * If we are a login shell, then we don't want to tell * about any mail file unless its been modified * after the time we started. * This prevents us from telling the user things he already * knows, since the login program insists on saying * "You have mail." */mailchk(){ register struct varent *v; register char **vp; time_t t; int intvl, cnt; struct stat stb; bool new; v = adrof("mail"); if (v == 0) return; (void) time(&t); vp = v->vec; cnt = blklen(vp); intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; if (intvl < 1) intvl = 1; if (chktim + intvl > t) return; for (; *vp; vp++) { if (stat(*vp, &stb) < 0) continue; new = stb.st_mtime > time0.tv_sec; if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || (stb.st_atime < chktim && stb.st_mtime < chktim) || loginsh && !new) continue; if (cnt == 1) csh_printf("You have %smail.\n", new ? "new " : ""); /* 005 RNF */ else csh_printf("%s in %s.\n", new ? "New mail" : "Mail", *vp); /* 005 RNF */ } chktim = t;}#include <pwd.h>/* * Extract a home directory from the password file * The argument points to a buffer where the name of the * user whose home directory is sought is currently. * We write the home directory of the user back there. */gethdir(home) char *home;{ register struct passwd *pp = getpwnam(home); if (pp == 0) return (1); (void) strcpy(home, pp->pw_dir); return (0);}/* * Move the initial descriptors to their eventual * resting places, closin all other units. */initdesc(){ didfds = 0; /* 0, 1, 2 aren't set up */ SHIN = dcopy(0, FSHIN); SHOUT = dcopy(1, FSHOUT); SHDIAG = dcopy(2, FSHDIAG); OLDSTD = dcopy(SHIN, FOLDSTD); closem();}#ifdef PROFdone(i)#elseexit(i)#endif int i;{ untty(); _exit(i);}printprompt (){ register char *cp; register char **promptv; register struct varent *pvar; static int next_prompt = 0; register int pcount; if (!whyles) { /* * Find end of prompts or next_prompt'th member */ pvar = adrof("prompt"); if (pvar == 0 || (promptv = pvar->vec) == 0 || promptv[0] == 0) { cp = ""; } else { pcount = 0; while (pcount <= next_prompt) { if (promptv[pcount] == 0) { next_prompt = 0; break; } pcount++; } cp = promptv[next_prompt]; next_prompt++; } while (*cp) { if (*cp == HIST) { csh_printf ("%d", eventno + 1); /* 005 RNF */ } else { if (*cp == '\\' && cp[1] == HIST) { cp++; } putchar (*cp | QUOTE); } cp++; } } else { /* * Prompt for forward reading loop * body content. */ csh_printf ("? "); /* 005 RNF */ } flush ();}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?