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 = &paraml;		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(&paraml), 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(&paraml, 0) && !err && intty && !editline ||		    adrof("verbose")) {#else		if (lex(&paraml) && !err && intty ||		    adrof("verbose")) {#endif			haderr = 1;			prlex(&paraml);			haderr = 0;		}#ifdef CSHEDIT		/*		 * If had a history command :v modifier then		 * go into edit mode. - afd		 */		if (editline) {			editcmd(&paraml);			editline = 0;			paraml.next = paraml.prev = &paraml;			paraml.word = "";			err = 0;			/*			 * Echo new command line.			 */			if (lex(&paraml, 1) && !err && intty ||			    adrof("verbose")) {				haderr = 1;				prlex(&paraml);				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(&paraml);		/*		 * 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(&paraml);		/*		 * Parse the words of the input into a parse tree.		 */		t = syntax(paraml.next, &paraml, 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(&paraml), 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 + -
显示快捷键?