2011 lines · 42.8 KB · C
RawDownload
/****************************************************************Copyright (C) Lucent Technologies 1997All Rights Reserved Permission to use, copy, modify, and distribute this software andits documentation for any purpose and without fee is herebygranted, provided that the above copyright notice appear in allcopies and that both that the copyright notice and thispermission notice and warranty disclaimer appear in supportingdocumentation, and that the name Lucent Technologies or any ofits entities not be used in advertising or publicity pertainingto distribution of the software without specific, written priorpermission. LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANYSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGESWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHERIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OFTHIS SOFTWARE.****************************************************************/ #include <u.h>#include <libc.h>#include <ctype.h>#include <bio.h>#include "awk.h"#include "y.tab.h" jmp_buf env;extern	int	pairstack[];extern	Awkfloat	srand_seed; Node	*winner = nil;	/* root of parse tree */Cell	*tmps;		/* free temporary cells for execution */ static Cell	truecell	={ OBOOL, BTRUE, NUM, 0, 0, 1.0 };Cell	*True	= &truecell;static Cell	falsecell	={ OBOOL, BFALSE, NUM, 0, 0, 0.0 };Cell	*False	= &falsecell;static Cell	breakcell	={ OJUMP, JBREAK, NUM, 0, 0, 0.0 };Cell	*jbreak	= &breakcell;static Cell	contcell	={ OJUMP, JCONT, NUM, 0, 0, 0.0 };Cell	*jcont	= &contcell;static Cell	nextcell	={ OJUMP, JNEXT, NUM, 0, 0, 0.0 };Cell	*jnext	= &nextcell;static Cell	nextfilecell	={ OJUMP, JNEXTFILE, NUM, 0, 0, 0.0 };Cell	*jnextfile	= &nextfilecell;static Cell	exitcell	={ OJUMP, JEXIT, NUM, 0, 0, 0.0 };Cell	*jexit	= &exitcell;static Cell	retcell		={ OJUMP, JRET, NUM, 0, 0, 0.0 };Cell	*jret	= &retcell;static Cell	tempcell	={ OCELL, CTEMP, NUM|STR|DONTFREE, 0, EMPTY, 0.0 }; Node	*curnode = nil;	/* the node being executed, for debugging */ intsystem(const char *s){	Waitmsg *status;	int pid; 	if(s == nil)		return 1;	pid = fork();	if(pid == 0) {		execl("/bin/rc", "rc", "-c", s, nil);		exits("exec");	}	if(pid < 0){		return -1;	}	for(;;) {		status = wait();		if(status == nil)			FATAL("Out of memory");		if(status->pid == pid)			break;		free(status);	} 	if(status->msg[0] != '\0') {		free(status);		return 1;	}	free(status);	return 0;} /* buffer memory management */int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,	char *whatrtn)/* pbuf:    address of pointer to buffer being managed * psiz:    address of buffer size variable * minlen:  minimum length of buffer needed * quantum: buffer size quantum * pbptr:   address of movable pointer into buffer, or 0 if none * whatrtn: name of the calling routine if failure should cause fatal error * * return   0 for realloc failure, !=0 for success */{	if (minlen > *psiz) {		char *tbuf;		int rminlen = quantum ? minlen % quantum : 0;		int boff = pbptr ? *pbptr - *pbuf : 0;		/* round up to next multiple of quantum */		if (rminlen)			minlen += quantum - rminlen;		tbuf = (char *) realloc(*pbuf, minlen);		if (tbuf == nil) {			if (whatrtn)				FATAL("out of memory in %s", whatrtn);			return 0;		}		*pbuf = tbuf;		*psiz = minlen;		if (pbptr)			*pbptr = tbuf + boff;	}	return 1;} void run(Node *a)	/* execution of parse tree starts here */{	extern void stdinit(void); 	stdinit();	execute(a);	closeall();} Cell *execute(Node *u)	/* execute a node of the parse tree */{	int nobj;	Cell *(*proc)(Node **, int);	Cell *x;	Node *a; 	if (u == nil)		return(True);	for (a = u; ; a = a->nnext) {		curnode = a;		if (isvalue(a)) {			x = (Cell *) (a->narg[0]);			if (isfld(x) && !donefld)				fldbld();			else if (isrec(x) && !donerec)				recbld();			return(x);		}		nobj = a->nobj;		if (notlegal(nobj))	/* probably a Cell* but too risky to print */			FATAL("illegal statement");		proc = proctab[nobj-FIRSTTOKEN];		x = (*proc)(a->narg, nobj);		if (isfld(x) && !donefld)			fldbld();		else if (isrec(x) && !donerec)			recbld();		if (isexpr(a))			return(x);		if (isjump(x))			return(x);		if (a->nnext == nil)			return(x);		if(istemp(x))			tfree(x);	}}  Cell *program(Node **a, int)	/* execute an awk program */{				/* a[0] = BEGIN, a[1] = body, a[2] = END */	Cell *x; 	if (setjmp(env) != 0)		goto ex;	if (a[0]) {		/* BEGIN */		x = execute(a[0]);		if (isexit(x))			return(True);		if (isjump(x))			FATAL("illegal break, continue, next or nextfile from BEGIN");		if (istemp(x))			tfree(x);	}	if (a[1] || a[2])		while (getrec(&record, &recsize, 1) > 0) {			x = execute(a[1]);			if (isexit(x))				break;			if (istemp(x))				tfree(x);		}  ex:	if (setjmp(env) != 0)	/* handles exit within END */		goto ex1;	if (a[2]) {		/* END */		x = execute(a[2]);		if (isbreak(x) || isnext(x) || iscont(x))			FATAL("illegal break, continue, next or nextfile from END");			if (istemp(x))				tfree(x);	}  ex1:	return(True);} struct Frame {	/* stack frame for awk function calls */	int nargs;	/* number of arguments in this call */	Cell *fcncell;	/* pointer to Cell for function */	Cell **args;	/* pointer to array of arguments after execute */	Cell *retval;	/* return value */}; #define	NARGS	50	/* max args in a call */ struct Frame *fp = nil;	/* frame pointer. bottom level unused */ Cell *call(Node **a, int)	/* function call.  very kludgy and fragile */{	static Cell newcopycell = { OCELL, CCOPY, NUM|STR|DONTFREE, 0, EMPTY, 0.0 };	int i, ncall, ndef;	Node *x;	Cell *args[NARGS], **oargs;	Cell *y, *z, *fcn;	struct Frame frame, *up;	char *s; 	fcn = execute(a[0]);	/* the function itself */	s = fcn->nval;	if (!isfcn(fcn))		FATAL("calling undefined function %s", s);	for (ncall = 0, x = a[1]; x != nil; x = x->nnext)	/* args in call */		ncall++;	ndef = (int) fcn->fval;			/* args in defn */	   dprint( ("calling %s, %d args (%d in defn)\n", s, ncall, ndef) );	if (ncall > ndef) {		WARNING("function %s called with %d args, uses only %d",			s, ncall, ndef);		ncall = ndef;	}	if (ndef+ncall > NARGS)		FATAL("function %s has %d arguments, limit %d", s, ndef+ncall, NARGS);	oargs = args+ndef;	for (i = 0, x = a[1]; i < ncall && x != nil; i++, x = x->nnext) {	/* get call args */		   dprint( ("evaluate args[%d]:\n", i) );		y = execute(x);		   dprint( ("args[%d]: %s %f <%s>, t=%o\n",			   i, y->nval, y->fval, isarr(y) ? "(array)" : y->sval, y->tval) );		if (isfcn(y))			FATAL("can't use function %s as argument in %s", y->nval, s);		if (isarr(y)) {			args[i] = y;	/* arrays by ref */			y = nil;		} else if (istemp(y)) {			y->csub = CCOPY;			args[i] = y;		} else			args[i] = copycell(y);		oargs[i] = y;	/* potential output arg for arrays */	}	for ( ; i < ndef; i++) {	/* add null args for ones not provided */		args[i] = gettemp();		*args[i] = newcopycell;	}	/* now ok to up frame */	up = fp;	fp = &frame;	fp->fcncell = fcn;	fp->args = args;	fp->nargs = ndef;	/* number defined with (excess are locals) */	fp->retval = gettemp(); 	dprint( ("start exec of %s\n", s) );	y = execute((Node *)(fcn->sval));	/* execute body */	dprint( ("finished exec of %s\n", s) ); 	for (i = 0; i < ndef; i++) {		Cell *t = args[i];		if (isarr(t)) {			if (t->csub == CCOPY) {				if (i >= ncall) {					freesymtab(t);					tfree(t);				} else if(oargs[i] != nil) {					oargs[i]->tval = t->tval;					oargs[i]->tval &= ~(STR|NUM|DONTFREE);					oargs[i]->sval = t->sval;				}			}		} else if (t != y)	/* kludge to prevent freeing twice */			tfree(t);	}	if (istemp(fcn))		tfree(fcn);	if (isexit(y) || isnext(y) || isnextfile(y))		return y;	if (istemp(y))		tfree(y);		/* this can free twice! */	z = fp->retval;			/* return value */	   dprint( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );	fp = up;	return(z);} Cell *copycell(Cell *x)	/* make a copy of a cell in a temp */{	Cell *y; 	y = gettemp();	y->csub = CCOPY;	/* prevents freeing until call is over */	y->nval = x->nval;	/* BUG? */	y->sval = x->sval != nil && *x->sval ? tostring(x->sval) : EMPTY;	y->fval = x->fval;	y->tval = x->tval & ~(CON|FLD|REC|DONTFREE);	/* copy is not constant or field */	if (y->sval == EMPTY)		y->tval |= DONTFREE;	return y;} Cell *arg(Node **a, int n)	/* nth argument of a function */{ 	n = ptoi(a[0]);	/* argument number, counting from 0 */	   dprint( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );	if (n >= fp->nargs)		FATAL("argument #%d of function %s was not supplied",			n+1, fp->fcncell->nval);	return fp->args[n];} Cell *jump(Node **a, int n)	/* break, continue, next, nextfile, return */{	Cell *y; 	switch (n) {	case EXIT:		if (a[0] != nil) {			y = execute(a[0]);			if ((y->tval & (NUM|STR)) == STR) {				exitstatus = getsval(y);			} else if((int) getfval(y) != 0) {				exitstatus = "error";			}		}		longjmp(env, 1);	case RETURN:		if (a[0] != nil) {			y = execute(a[0]);			if ((y->tval & (STR|NUM)) == (STR|NUM)) {				setsval(fp->retval, getsval(y));				fp->retval->fval = getfval(y);				fp->retval->tval |= NUM;			}			else if (y->tval & STR)				setsval(fp->retval, getsval(y));			else if (y->tval & NUM)				setfval(fp->retval, getfval(y));			else		/* can't happen */				FATAL("bad type variable %d", y->tval);			if (istemp(y))				tfree(y);		}		return(jret);	case NEXT:		return(jnext);	case NEXTFILE:		nextfile();		return(jnextfile);	case BREAK:		return(jbreak);	case CONTINUE:		return(jcont);	default:	/* can't happen */		FATAL("illegal jump type %d", n);	}	return 0;	/* not reached */} Cell *getline(Node **a, int n)	/* get next line from specific input */{		/* a[0] is variable, a[1] is operator, a[2] is filename */	Cell *r, *x;	extern Cell **fldtab;	Biobuf *fp;	char *buf;	int bufsize = recsize;	int mode; 	if ((buf = (char *) malloc(bufsize)) == nil)		FATAL("out of memory in getline"); 	Bflush(&stdout);	/* in case someone is waiting for a prompt */	r = gettemp();	if (a[1] != nil) {		/* getline < file */		x = execute(a[2]);		/* filename */		mode = ptoi(a[1]);		if (mode == '|')		/* input pipe */			mode = LE;	/* arbitrary flag */		fp = openfile(mode, getsval(x));		if (istemp(x))			tfree(x);		if (fp == nil)			n = -1;		else			n = readrec(&buf, &bufsize, fp);		if (n <= 0) {			;		} else if (a[0] != nil) {	/* getline var <file */			x = execute(a[0]);			setsval(x, buf);			if (istemp(x))				tfree(x);		} else {			/* getline <file */			setsval(fldtab[0], buf);			if (to_number(fldtab[0]->sval, &fldtab[0]->fval, nil))				fldtab[0]->tval |= NUM;		}	} else {			/* bare getline; use current input */		if (a[0] == nil)	/* getline */			n = getrec(&record, &recsize, 1);		else {			/* getline var */			n = getrec(&buf, &bufsize, 0);			if (n > 0) {				x = execute(a[0]);				setsval(x, buf);				if (istemp(x))					tfree(x);			}		}	}	setfval(r, (Awkfloat) n);	free(buf);	return r;} Cell *getnf(Node **a, int)	/* get NF */{	if (donefld == 0)		fldbld();	return (Cell *) a[0];} Cell *array(Node **a, int)	/* a[0] is symtab, a[1] is list of subscripts */{	Cell *x, *y, *z;	char *s;	Node *np;	char *buf;	int bufsz = recsize;	int nsub = strlen(*SUBSEP); 	if ((buf = (char *) malloc(bufsz)) == nil)		FATAL("out of memory in array"); 	x = execute(a[0]);	/* Cell* for symbol table */	buf[0] = 0;	for (np = a[1]; np; np = np->nnext) {		y = execute(np);	/* subscript */		s = getsval(y);		if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))			FATAL("out of memory for %s[%s...]", x->nval, buf);		strcat(buf, s);		if (np->nnext)			strcat(buf, *SUBSEP);		if (istemp(y))			tfree(y);	}	if (!isarr(x)) {		   dprint( ("making %s into an array\n", x->nval) );		if (freeable(x))			xfree(x->sval);		x->tval &= ~(STR|NUM|DONTFREE);		x->tval |= ARR;		x->sval = (char *) makesymtab(NSYMTAB);	}	z = setsymtab(buf, EMPTY, 0.0, STR|NUM, (Array *) x->sval);	z->ctype = OCELL;	z->csub = CVAR;	if (istemp(x))		tfree(x);	free(buf);	return(z);} Cell *awkdelete(Node **a, int)	/* a[0] is symtab, a[1] is list of subscripts */{	Cell *x, *y;	Node *np;	char *s;	int nsub = strlen(*SUBSEP); 	x = execute(a[0]);	/* Cell* for symbol table */	if (!isarr(x))		return True;	if (a[1] == 0) {	/* delete the elements, not the table */		freesymtab(x);

Lines 1–500 of 2011.