📄 csh.c
字号:
}Char *jobargv[2] = {STRjobs, 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. *//* ARGSUSED */voidpintr(notused) int notused;{ pintr1(1);}voidpintr1(wantnl) bool wantnl;{ Char **v; sigset_t omask; omask = sigblock((sigset_t) 0); if (setintr) { (void) sigsetmask(omask & ~sigmask(SIGINT)); if (pjobs) { pjobs = 0; (void) fprintf(cshout, "\n"); dojobs(jobargv, NULL); stderror(ERR_NAME | ERR_INTR); } } (void) sigsetmask(omask & ~sigmask(SIGCHLD)); (void) fpurge(cshout); (void) endpwent(); /* * 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) { gotolab(gointr); timflg = 0; if ((v = pargv) != NULL) pargv = 0, blkfree(v); if ((v = gargv) != NULL) gargv = 0, blkfree(v); reset(); } else if (intty && wantnl) { (void) fputc('\r', cshout); (void) fputc('\n', cshout); } stderror(ERR_SILENT);}/* * 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. */static struct command *savet = NULL;voidprocess(catch) bool catch;{ jmp_buf osetexit; struct command *t = savet; savet = NULL; getexit(osetexit); for (;;) { pendjob(); paraml.next = paraml.prev = ¶ml; paraml.word = STRNULL; (void) setexit(); justpr = enterhist; /* execute if not entering history */ /* * Interruptible during interactive reads */ if (setintr) (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT)); /* * For the sake of reset() */ freelex(¶ml); if (savet) freesyn(savet), savet = NULL; if (haderr) { if (!catch) { /* unwind */ doneinp = 0; resexit(osetexit); savet = t; 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 (aret == F_SEEK && fseekp == feobp) printprompt(); (void) fflush(cshout); } if (seterr) { xfree((ptr_t) seterr); seterr = NULL; } /* * Echo not only on VERBOSE, but also with history expansion. If there * is a lexical error then we forego history echo. */ if ((lex(¶ml) && !seterr && intty) || adrof(STRverbose)) { prlex(csherr, ¶ml); } /* * 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. * * PWP: entry of items in the history list while in a while loop is done * elsewhere... */ if (enterhist || (catch && intty && !whyles)) savehist(¶ml); /* * Print lexical error messages, except when sourcing history lists. */ if (!enterhist && seterr) stderror(ERR_OLD); /* * If had a history command :p modifier then this is as far as we * should go */ if (justpr) reset(); alias(¶ml); /* * Parse the words of the input into a parse tree. */ savet = syntax(paraml.next, ¶ml, 0); if (seterr) stderror(ERR_OLD); execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL); /* * Made it! */ freelex(¶ml); freesyn((struct command *) savet), savet = NULL; } resexit(osetexit); savet = t;}void/*ARGSUSED*/dosource(v, t) Char **v; struct command *t;{ register Char *f; bool hflg = 0; Char buf[BUFSIZ]; v++; if (*v && eq(*v, STRmh)) { if (*++v == NULL) stderror(ERR_NAME | ERR_HFLAG); hflg++; } (void) Strcpy(buf, *v); f = globone(buf, G_ERROR); (void) strcpy((char *) buf, short2str(f)); xfree((ptr_t) f); if (!srcfile((char *) buf, 0, hflg) && !hflg) stderror(ERR_SYSTEM, (char *) buf, strerror(errno));}/* * 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." */static voidmailchk(){ register struct varent *v; register Char **vp; time_t t; int intvl, cnt; struct stat stb; bool new; v = adrof(STRmail); 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(short2str(*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) (void) fprintf(cshout, "You have %smail.\n", new ? "new " : ""); else (void) fprintf(cshout, "%s in %s.\n", new ? "New mail" : "Mail", vis_str(*vp)); } chktim = t;}/* * 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. */intgethdir(home) Char *home;{ Char *h; struct passwd *pw; /* * Is it us? */ if (*home == '\0') { if ((h = value(STRhome)) != NULL) { (void) Strcpy(home, h); return 0; } else return 1; } if ((pw = getpwnam(short2str(home))) != NULL) { (void) Strcpy(home, str2short(pw->pw_dir)); return 0; } else return 1;}/* * When didfds is set, we do I/O from 0, 1, 2 otherwise from 15, 16, 17 * We also check if the shell has already changed the decriptor to point to * 0, 1, 2 when didfds is set. */#define DESC(a) (*((int *) (a)) - (didfds && *((int *) a) >= FSHIN ? FSHIN : 0))static intreadf(oreo, buf, siz) void *oreo; char *buf; int siz;{ return read(DESC(oreo), buf, siz);}static intwritef(oreo, buf, siz) void *oreo; const char *buf; int siz;{ return write(DESC(oreo), buf, siz);}static fpos_tseekf(oreo, off, whence) void *oreo; fpos_t off; int whence;{ return lseek(DESC(oreo), off, whence);}static intclosef(oreo) void *oreo;{ return close(DESC(oreo));}/* * Print the visible version of a string. */intvis_fputc(ch, fp) int ch; FILE *fp;{ char uenc[5]; /* 4 + NULL */ if (ch & QUOTE) return fputc(ch & TRIM, fp); /* * XXX: When we are in AsciiOnly we want all characters >= 0200 to * be encoded, but currently there is no way in vis to do that. */ (void) vis(uenc, ch & TRIM, VIS_NOSLASH, 0); return fputs(uenc, fp);}/* * Move the initial descriptors to their eventual * resting places, closin all other units. */voidinitdesc(){ didfds = 0; /* 0, 1, 2 aren't set up */ (void) ioctl(SHIN = dcopy(0, FSHIN), FIOCLEX, NULL); (void) ioctl(SHOUT = dcopy(1, FSHOUT), FIOCLEX, NULL); (void) ioctl(SHERR = dcopy(2, FSHERR), FIOCLEX, NULL); (void) ioctl(OLDSTD = dcopy(SHIN, FOLDSTD), FIOCLEX, NULL); closem();}void#ifdef PROFdone(i)#elsexexit(i)#endif int i;{ untty(); _exit(i);}static Char **defaultpath(){ char *ptr; Char **blk, **blkp; struct stat stb; blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10);#define DIRAPPEND(a) \ if (stat(ptr = a, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) \ *blkp++ = SAVE(ptr) DIRAPPEND(_PATH_BIN); DIRAPPEND(_PATH_USRBIN);#undef DIRAPPEND if (euid != 0 && uid != 0) *blkp++ = Strsave(STRdot); *blkp = NULL; return (blk);}voidprintprompt(){ register Char *cp; if (!whyles) { for (cp = value(STRprompt); *cp; cp++) if (*cp == HIST) (void) fprintf(cshout, "%d", eventno + 1); else { if (*cp == '\\' && cp[1] == HIST) cp++; (void) vis_fputc(*cp | QUOTE, cshout); } } else /* * Prompt for forward reading loop body content. */ (void) fprintf(cshout, "? "); (void) fflush(cshout);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -