sh.lex.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,440 行 · 第 1/2 页

C
1,440
字号
#ifndef lintstatic  char    *sccsid = "@(#)sh.lex.c	4.2  (ULTRIX)        8/13/90";#endif lint/************************************************************************ *									* *			Copyright (c) 1988 by				* *		Digital Equipment Corporation, Maynard, MA		* *			All rights reserved.				* *									* *   This software is furnished under a license and may be used and	* *   copied  only  in accordance with the terms of such license and	* *   with the  inclusion  of  the  above  copyright  notice.   This	* *   software  or  any  other copies thereof may not be provided or	* *   otherwise made available to any other person.  No title to and	* *   ownership of the software is hereby transferred.			* *									* *   This software is  derived  from  software  received  from  the	* *   University    of   California,   Berkeley,   and   from   Bell	* *   Laboratories.  Use, duplication, or disclosure is  subject  to	* *   restrictions  under  license  agreements  with  University  of	* *   California and with AT&T.						* *									* *   The information in this software is subject to change  without	* *   notice  and should not be construed as a commitment by Digital	* *   Equipment Corporation.						* *									* *   Digital assumes no responsibility for the use  or  reliability	* *   of its software on equipment which is not supplied by Digital.	* *									* ************************************************************************/#include "sh.h"#include <sgtty.h>/* * C shell * Modification History:	sh.lex.c * * 005 - Bob Fontaine	-  Fri Jun 22 09:53:01 EDT 1990 *	 Changed call to internal printf function to csh_printf to avoid *	 confusion with stdio library routine. * * 004 - Gary A. Gaudet - Tue Jan  2 11:43:04 EST 1990 *	changed register char *wp to register unsigned char *	changed char wbuf[] to unsigned char wbuf[] *	added some (castings) *	added return value check for ioctl() * * 03 12-Nov-88, Al Delorey (afd) *	ifdef the TENEX & CSHEDIT code. * * 02 20-Sep-88, Al Delorey (afd). *	Removed Mips tsh code (file completion & line edit). *	Added 'tenex' completion & dcsh style command line edit capability. *	Major mod to "bgetc()" for completion. * * 01 Sat Aug 13 15:28:57 EDT 1988, Gary A. Gaudet *	merging mips & ultrix for 8 bit clean and bug fixes *//* * These lexical routines read input and form lists of words. * There is some involved processing here, because of the complications * of input buffering, and especially because of history substitution. */char	*word();#ifdef CSHEDITchar	*editword();#endif/* * Peekc is a peek characer for getC, peekread for readc. * There is a subtlety here in many places... history routines * will read ahead and then insert stuff into the input stream. * If they push back a character then they must push it behind * the text substituted by the history substitution.  On the other * hand in several places we need 2 peek characters.  To make this * all work, the history routines read with getC, and make use both * of ungetC and unreadc.  The key observation is that the state * of getC at the call of a history reference is such that calls * to getC from the history routines will always yield calls of * readc, unless this peeking is involved.  That is to say that during * getexcl the variables lap, exclp, and exclnxt are all zero. * * Getdol invokes history substitution, hence the extra peek, peekd, * which it can ungetD to be before history substitutions. */CHTYPE	peekc, peekd;CHTYPE	peekread;char	*exclp;			/* (Tail of) current word from ! subst */struct	wordent *exclnxt;	/* The rest of the ! subst words */int	exclc;			/* Count of remainig words in ! subst */char	*alvecp;		/* "Globp" for alias resubstitution *//* * Lex returns to its caller not only a wordlist (as a "var" parameter) * but also whether a history substitution occurred.  This is used in * the main (process) routine to determine whether to echo, and also * when called by the alias routine to determine whether to keep the * argument list. */bool	hadhist;CHTYPE getCtmp;#define getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))#define	ungetC(c)	peekc = c#define	ungetD(c)	peekd = c#ifdef CSHEDITlex(hp, didedit)	register struct wordent *hp;	int didedit;			/* set true if we edited a cmd line */#elselex(hp)	register struct wordent *hp;#endif{	register struct wordent *wdp;	int c;	lineloc = btell();	hp->next = hp->prev = hp;	hp->word = "";	alvecp = 0, hadhist = 0;#ifdef CSHEDIT	if (! didedit) {#endif		do			c = readc(0);		while (c == ' ' || c == '\t'); /* strip leading spaces and tabs */		if (c == HISTSUB && intty)			/* ^lef^rit	from tty is short !:s^lef^rit */			getexcl(c);		else			unreadc(c);#ifdef CSHEDIT	}#endif	wdp = hp;	/*	 * The following loop is written so that the links needed	 * by freelex will be ready and rarin to go even if it is	 * interrupted.	 */	do {		register struct wordent *new = (struct wordent *) xalloc((unsigned)sizeof *wdp);		new->word = 0;		new->prev = wdp;		new->next = hp;		wdp->next = new;		wdp = new;#ifdef CSHEDIT		wdp->word = (didedit ? editword() : word());#else		wdp->word = word();#endif	} while (wdp->word[0] != '\n');	hp->prev = wdp;	return (hadhist);}prlex(sp0)	struct wordent *sp0;{	register struct wordent *sp = sp0->next;	char *stripstr;	for (;;) {		stripstr = savestr(sp->word);		csh_printf("%s", strip(stripstr)); 	/* 005 RNF */		xfree(stripstr);		sp = sp->next;		if (sp == sp0)			break;		if (sp->word[0] != '\n')			putchar(' ');	}}copylex(hp, fp)	register struct wordent *hp;	register struct wordent *fp;{	register struct wordent *wdp;	wdp = hp;	fp = fp->next;	do {		register struct wordent *new = (struct wordent *) xalloc((unsigned)sizeof *wdp);		new->prev = wdp;		new->next = hp;		wdp->next = new;		wdp = new;		wdp->word = savestr(fp->word);		fp = fp->next;	} while (wdp->word[0] != '\n');	hp->prev = wdp;}freelex(vp)	register struct wordent *vp;{	register struct wordent *fp;	while (vp->next != vp) {		fp = vp->next;		vp->next = fp->next;		XFREE(fp->word)		XFREE((char *)fp)	}	vp->prev = vp;}char *word(){	register CHTYPE c, c1;	register unsigned char *wp;	/* 004 - GAG */	unsigned char wbuf[BUFSIZ*2];	/* 004 - GAG */	register bool dolflg;	register int i;	wp = wbuf;	i = BUFSIZ*2 - 4*2;loop:	while ((c = getC(DOALL)) == ' ' || c == '\t')		;	if (any(c, "\t\n #&();<>|\\")) {		switch (c) {		case '&':		case '|':		case '<':		case '>':			*wp++ = c;			c1 = getC(DOALL);			if (c1 == c)				*wp++ = c1;			else				ungetC(c1);			goto ret;		case '#':			if (intty)				break;			c = 0;			do {				c1 = c;				c = getC(0);			} while (c != '\n');			if (c1 == '\\')				goto loop;			/* fall into ... */		case ';':		case '(':		case ')':		case '\n':			*wp++ = c;			goto ret;		case '\\':			c = getC(0);			if (c == '\n') {				if (onelflg == 1)					onelflg = 2;				goto loop;			}			if (c != HIST)				*wp++ = '\\', --i;			c |= QUOTE;		}	}	c1 = 0;	dolflg = DOALL;	for (;;) {		if (c1) {			if (c == c1) {				c1 = 0;				dolflg = DOALL;			} else if (c == '\\') {				c = getC(0);				if (c == HIST)					c |= QUOTE;				else {					if (c == '\n')						/*						if (c1 == '`')							c = ' ';						else						*/							c |= QUOTE;					ungetC(c);					c = '\\';				}			} else if (c == '\n') {				seterrc("Unmatched ", (char) c1);				ungetC(c);				break;			}			} else if (any(c, "\t\n #&();<>|\"'`\\")) {			if (c == '\\') {				c = getC(0);				if (c == '\n') {					if (onelflg == 1)						onelflg = 2;					break;				}				if (c != HIST)					*wp++ = '\\', --i;				c |= QUOTE;			} else if (any(c, "\"`'")) {				c1 = c;				dolflg = c == '"' ? DOALL : DOEXCL;			} else if (c != '#' || !intty) {				ungetC(c);				break;			}		}		if (--i > 0) {			if ((c & QUOTE) || (c == QUOTECHAR)) {				*wp++ = QUOTECHAR;				i--;			}			*wp++ = c & TRIM;			c = getC(dolflg);		} else {			seterr("Word too long");			wp = &wbuf[1];			break;		}	}ret:	*wp = 0;	return (savestr(wbuf));}getC1(flag)	register int flag;{	register CHTYPE c;top:	if (c = peekc) {		peekc = 0;		return (c);	}	if (lap) {		if ((c = *lap++) == 0)			lap = 0;		else {			if (any(c, "\t\n #&();<>|\"'`"))				c |= QUOTE;			return (c);		}	}	if (c = peekd) {		peekd = 0;		return (c);	}	if (exclp) {				/* restore Quote bit !!! */		if ((c = (*exclp++ & TRIM)) == QUOTECHAR)			c = QUOTE | (*exclp++ & TRIM);		if (c)			return (c);		if (exclnxt && --exclc >= 0) {			exclnxt = exclnxt->next;			setexclp(exclnxt->word);			return (' ');		}		exclp = 0;		exclnxt = 0;	}	if (exclnxt) {		exclnxt = exclnxt->next;		if (--exclc < 0)			exclnxt = 0;		else			setexclp(exclnxt->word);		goto top;	}	c = readc(0);	if (c == '$' && (flag & DODOL)) {		getdol();		goto top;	}	if (c == HIST && (flag & DOEXCL)) {		getexcl(0);		goto top;	}	return (c);}getdol(){	register char *np;	char name[40];	register int c;	int sc;	bool special = 0;	np = name, *np++ = '$';	c = sc = getC(DOEXCL);	if (any(c, "\t \n")) {		ungetD(c);		ungetC('$' | QUOTE);		return;	}	if (c == '{')		*np++ = c, c = getC(DOEXCL);	if (c == '#' || c == '?')		special++, *np++ = c, c = getC(DOEXCL);	*np++ = c;	switch (c) {		case '<':	case '$':		if (special)			goto vsyn;		goto ret;	case '\n':		ungetD(c);		np--;		goto vsyn;	case '*':		if (special)			goto vsyn;		goto ret;	default:		if (digit(c)) {/* * let $?0 pass for now			if (special)				goto vsyn;*/			while (digit(c = getC(DOEXCL))) {				if (np < &name[sizeof name / 2])					*np++ = c;			}		/*		 GT01: changed letter() to alnum() below to allow		 variables like a2z to be expanded.		 No, is it a valid variable name?		*/		} else if (alnum(c)) {/* *			alnum(c) is a macro *			getC(DOEXCL) will execute twice *			so don't use alnum(c = getC(DOEXCL) */			c = getC(DOEXCL);			while (alnum(c)) {				if (np < &name[sizeof name / 2])					*np++ = c;				c = getC(DOEXCL);			}		 } else			goto vsyn;	}	if (c == '[') {		*np++ = c;		do {			c = getC(DOEXCL);			if (c == '\n') {				ungetD(c);				np--;				goto vsyn;			}			if (np >= &name[sizeof name - 8])				goto vsyn;			*np++ = c;		} while (c != ']');		c = getC(DOEXCL);	}	if (c == ':') {		*np++ = c, c = getC(DOEXCL);		if (c == 'g')			*np++ = c, c = getC(DOEXCL);		*np++ = c;		if (!any(c, "htrqxe"))			goto vsyn;	} else		ungetD(c);	if (sc == '{') {		c = getC(DOEXCL);		if (c != '}') {			ungetC(c);			goto vsyn;		}		*np++ = c;	}ret:	*np = 0;	addla(name);	return;vsyn:	seterr("Variable syntax");	goto ret;}addla(cp)	char *cp;{	char buf[BUFSIZ];	if (lap != 0 && strlen(cp) + strlen(lap) >= sizeof (labuf) - 4) {		seterr("Expansion buf ovflo");		return;	}	if (lap)		(void) strcpy(buf, lap);	(void) strcpy(labuf, cp);	if (lap)		(void) strcat(labuf, buf);	lap = labuf;}char	lhsb[32];char	slhs[32];char	rhsb[64];int	quesarg;getexcl(sc)	char sc;{	register struct wordent *hp, *ip;	int left, right, dol;	register int c;	if (sc == 0) {		sc = getC(0);		if (sc != '{') {			ungetC(sc);			sc = 0;		}	}	quesarg = -1;	lastev = eventno;	hp = gethent(sc);	if (hp == 0)		return;	hadhist = 1;	dol = 0;	if (hp == alhistp)		for (ip = hp->next->next; ip != alhistt; ip = ip->next)			dol++;	else		for (ip = hp->next->next; ip != hp->prev; ip = ip->next)			dol++;	left = 0, right = dol;	if (sc == HISTSUB) {		ungetC('s'), unreadc(HISTSUB), c = ':';		goto subst;	}	c = getC(0);	if (!any(c, ":^$*-%"))		goto subst;	left = right = -1;	if (c == ':') {		c = getC(0);		unreadc(c);		if (letter(c) || c == '&') {			c = ':';			left = 0, right = dol;			goto subst;		}	} else		ungetC(c);	if (!getsel(&left, &right, dol))		return;	c = getC(0);	if (c == '*')		ungetC(c), c = '-';	if (c == '-') {		if (!getsel(&left, &right, dol))			return;		c = getC(0);	}subst:	exclc = right - left + 1;	while (--left >= 0)		hp = hp->next;	if (sc == HISTSUB || c == ':') {		do {			hp = getsub(hp);			c = getC(0);		} while (c == ':');	}	unreadc(c);	if (sc == '{') {		c = getC(0);		if (c != '}')			seterr("Bad ! form");	}	exclnxt = hp;}struct wordent *getsub(en)	struct wordent *en;{	register char *cp;	int delim;	register int c;	int sc;	bool global = 0;	char orhsb[sizeof rhsb];	exclnxt = 0;	sc = c = getC(0);	if (c == 'g')		global++, c = getC(0);	switch (c) {	case 'p':		justpr++;		goto ret;#ifdef CSHEDIT	case 'v':			/* modifier for line edit - afd */		editline++;		goto ret;#endif	case 'x':	case 'q':		global++;		/* fall into ... */	case 'h':	case 'r':	case 't':	case 'e':		break;	case '&':		if (slhs[0] == 0) {			seterr("No prev sub");			goto ret;		}		(void) strcpy(lhsb, slhs);		break;/*	case '~':		if (lhsb[0] == 0)			goto badlhs;		break;*/	case 's':		delim = getC(0);		if (letter(delim) || digit(delim) || any(delim, " \t\n")) {			unreadc(delim);bads:			lhsb[0] = 0;			seterr("Bad substitute");			goto ret;		}		cp = lhsb;		for (;;) {			c = getC(0);			if (c == '\n') {				unreadc(c);				break;			}			if (c == delim)				break;			if (cp > &lhsb[sizeof lhsb - 2])				goto bads;			if (c == '\\') {				c = getC(0);				if (c != delim && c != '\\')					*cp++ = '\\';			}			*cp++ = c;		}		if (cp != lhsb)			*cp++ = 0;		else if (lhsb[0] == 0) {/*badlhs:*/			seterr("No prev lhs");			goto ret;		}		cp = rhsb;		(void) strcpy(orhsb, cp);		for (;;) {			c = getC(0);			if (c == '\n') {				unreadc(c);				break;			}			if (c == delim)				break;/*			if (c == '~') {				if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2])					goto toorhs;				(void) strcpy(cp, orhsb);				cp = strend(cp);				continue;			}*/			if (cp > &rhsb[sizeof rhsb - 2]) {/*toorhs:*/				seterr("Rhs too long");				goto ret;			}			if (c == '\\') {				c = getC(0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?