run.c revision 201951
185587Sobrien/**************************************************************** 285587SobrienCopyright (C) Lucent Technologies 1997 385587SobrienAll Rights Reserved 485587Sobrien 585587SobrienPermission to use, copy, modify, and distribute this software and 685587Sobrienits documentation for any purpose and without fee is hereby 785587Sobriengranted, provided that the above copyright notice appear in all 885587Sobriencopies and that both that the copyright notice and this 985587Sobrienpermission notice and warranty disclaimer appear in supporting 1085587Sobriendocumentation, and that the name Lucent Technologies or any of 1185587Sobrienits entities not be used in advertising or publicity pertaining 1285587Sobriento distribution of the software without specific, written prior 1385587Sobrienpermission. 1485587Sobrien 1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 2285587SobrienTHIS SOFTWARE. 2385587Sobrien****************************************************************/ 2485587Sobrien 2585587Sobrien#define DEBUG 2685587Sobrien#include <stdio.h> 2785587Sobrien#include <ctype.h> 2885587Sobrien#include <setjmp.h> 29146299Sru#include <limits.h> 3085587Sobrien#include <math.h> 3185587Sobrien#include <string.h> 3285587Sobrien#include <stdlib.h> 3385587Sobrien#include <time.h> 3485587Sobrien#include "awk.h" 3585587Sobrien#include "ytab.h" 3685587Sobrien 3785587Sobrien#define tempfree(x) if (istemp(x)) tfree(x); else 3885587Sobrien 3985587Sobrien/* 4085587Sobrien#undef tempfree 4185587Sobrien 4285587Sobrienvoid tempfree(Cell *p) { 4385587Sobrien if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) { 4485587Sobrien WARNING("bad csub %d in Cell %d %s", 4585587Sobrien p->csub, p->ctype, p->sval); 4685587Sobrien } 4785587Sobrien if (istemp(p)) 4885587Sobrien tfree(p); 4985587Sobrien} 5085587Sobrien*/ 5185587Sobrien 52170331Srafan/* do we really need these? */ 53170331Srafan/* #ifdef _NFILE */ 54170331Srafan/* #ifndef FOPEN_MAX */ 55170331Srafan/* #define FOPEN_MAX _NFILE */ 56170331Srafan/* #endif */ 57170331Srafan/* #endif */ 58170331Srafan/* */ 59170331Srafan/* #ifndef FOPEN_MAX */ 60170331Srafan/* #define FOPEN_MAX 40 */ /* max number of open files */ 61170331Srafan/* #endif */ 62170331Srafan/* */ 63170331Srafan/* #ifndef RAND_MAX */ 64170331Srafan/* #define RAND_MAX 32767 */ /* all that ansi guarantees */ 65170331Srafan/* #endif */ 6685587Sobrien 6785587Sobrienjmp_buf env; 6885587Sobrienextern int pairstack[]; 6985587Sobrien 7085587SobrienNode *winner = NULL; /* root of parse tree */ 7185587SobrienCell *tmps; /* free temporary cells for execution */ 7285587Sobrien 7385587Sobrienstatic Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; 7485587SobrienCell *True = &truecell; 7585587Sobrienstatic Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; 7685587SobrienCell *False = &falsecell; 7785587Sobrienstatic Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; 7885587SobrienCell *jbreak = &breakcell; 7985587Sobrienstatic Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; 8085587SobrienCell *jcont = &contcell; 8185587Sobrienstatic Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; 8285587SobrienCell *jnext = &nextcell; 8385587Sobrienstatic Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; 8485587SobrienCell *jnextfile = &nextfilecell; 8585587Sobrienstatic Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; 8685587SobrienCell *jexit = &exitcell; 8785587Sobrienstatic Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; 8885587SobrienCell *jret = &retcell; 8985587Sobrienstatic Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; 9085587Sobrien 9185587SobrienNode *curnode = NULL; /* the node being executed, for debugging */ 9285587Sobrien 9385587Sobrien/* buffer memory management */ 9485587Sobrienint adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, 95107806Sobrien const char *whatrtn) 9685587Sobrien/* pbuf: address of pointer to buffer being managed 9785587Sobrien * psiz: address of buffer size variable 9885587Sobrien * minlen: minimum length of buffer needed 9985587Sobrien * quantum: buffer size quantum 10085587Sobrien * pbptr: address of movable pointer into buffer, or 0 if none 10185587Sobrien * whatrtn: name of the calling routine if failure should cause fatal error 10285587Sobrien * 10385587Sobrien * return 0 for realloc failure, !=0 for success 10485587Sobrien */ 10585587Sobrien{ 10685587Sobrien if (minlen > *psiz) { 10785587Sobrien char *tbuf; 10885587Sobrien int rminlen = quantum ? minlen % quantum : 0; 10985587Sobrien int boff = pbptr ? *pbptr - *pbuf : 0; 11085587Sobrien /* round up to next multiple of quantum */ 11185587Sobrien if (rminlen) 11285587Sobrien minlen += quantum - rminlen; 11385587Sobrien tbuf = (char *) realloc(*pbuf, minlen); 114170331Srafan dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) ); 11585587Sobrien if (tbuf == NULL) { 11685587Sobrien if (whatrtn) 11785587Sobrien FATAL("out of memory in %s", whatrtn); 11885587Sobrien return 0; 11985587Sobrien } 12085587Sobrien *pbuf = tbuf; 12185587Sobrien *psiz = minlen; 12285587Sobrien if (pbptr) 12385587Sobrien *pbptr = tbuf + boff; 12485587Sobrien } 12585587Sobrien return 1; 12685587Sobrien} 12785587Sobrien 12885587Sobrienvoid run(Node *a) /* execution of parse tree starts here */ 12985587Sobrien{ 13085587Sobrien extern void stdinit(void); 13185587Sobrien 13285587Sobrien stdinit(); 13385587Sobrien execute(a); 13485587Sobrien closeall(); 13585587Sobrien} 13685587Sobrien 13785587SobrienCell *execute(Node *u) /* execute a node of the parse tree */ 13885587Sobrien{ 13985587Sobrien Cell *(*proc)(Node **, int); 14085587Sobrien Cell *x; 14185587Sobrien Node *a; 14285587Sobrien 14385587Sobrien if (u == NULL) 14485587Sobrien return(True); 14585587Sobrien for (a = u; ; a = a->nnext) { 14685587Sobrien curnode = a; 14785587Sobrien if (isvalue(a)) { 14885587Sobrien x = (Cell *) (a->narg[0]); 14985587Sobrien if (isfld(x) && !donefld) 15085587Sobrien fldbld(); 15185587Sobrien else if (isrec(x) && !donerec) 15285587Sobrien recbld(); 15385587Sobrien return(x); 15485587Sobrien } 15585587Sobrien if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ 15685587Sobrien FATAL("illegal statement"); 15785587Sobrien proc = proctab[a->nobj-FIRSTTOKEN]; 15885587Sobrien x = (*proc)(a->narg, a->nobj); 15985587Sobrien if (isfld(x) && !donefld) 16085587Sobrien fldbld(); 16185587Sobrien else if (isrec(x) && !donerec) 16285587Sobrien recbld(); 16385587Sobrien if (isexpr(a)) 16485587Sobrien return(x); 16585587Sobrien if (isjump(x)) 16685587Sobrien return(x); 16785587Sobrien if (a->nnext == NULL) 16885587Sobrien return(x); 16985587Sobrien tempfree(x); 17085587Sobrien } 17185587Sobrien} 17285587Sobrien 17385587Sobrien 17485587SobrienCell *program(Node **a, int n) /* execute an awk program */ 17585587Sobrien{ /* a[0] = BEGIN, a[1] = body, a[2] = END */ 17685587Sobrien Cell *x; 17785587Sobrien 17885587Sobrien if (setjmp(env) != 0) 17985587Sobrien goto ex; 18085587Sobrien if (a[0]) { /* BEGIN */ 18185587Sobrien x = execute(a[0]); 18285587Sobrien if (isexit(x)) 18385587Sobrien return(True); 18485587Sobrien if (isjump(x)) 18585587Sobrien FATAL("illegal break, continue, next or nextfile from BEGIN"); 18685587Sobrien tempfree(x); 18785587Sobrien } 18885587Sobrien if (a[1] || a[2]) 18985587Sobrien while (getrec(&record, &recsize, 1) > 0) { 19085587Sobrien x = execute(a[1]); 19185587Sobrien if (isexit(x)) 19285587Sobrien break; 19385587Sobrien tempfree(x); 19485587Sobrien } 19585587Sobrien ex: 19685587Sobrien if (setjmp(env) != 0) /* handles exit within END */ 19785587Sobrien goto ex1; 19885587Sobrien if (a[2]) { /* END */ 19985587Sobrien x = execute(a[2]); 20085587Sobrien if (isbreak(x) || isnext(x) || iscont(x)) 20185587Sobrien FATAL("illegal break, continue, next or nextfile from END"); 20285587Sobrien tempfree(x); 20385587Sobrien } 20485587Sobrien ex1: 20585587Sobrien return(True); 20685587Sobrien} 20785587Sobrien 20885587Sobrienstruct Frame { /* stack frame for awk function calls */ 20985587Sobrien int nargs; /* number of arguments in this call */ 21085587Sobrien Cell *fcncell; /* pointer to Cell for function */ 21185587Sobrien Cell **args; /* pointer to array of arguments after execute */ 21285587Sobrien Cell *retval; /* return value */ 21385587Sobrien}; 21485587Sobrien 21585587Sobrien#define NARGS 50 /* max args in a call */ 21685587Sobrien 21785587Sobrienstruct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ 21885587Sobrienint nframe = 0; /* number of frames allocated */ 21985587Sobrienstruct Frame *fp = NULL; /* frame pointer. bottom level unused */ 22085587Sobrien 22185587SobrienCell *call(Node **a, int n) /* function call. very kludgy and fragile */ 22285587Sobrien{ 22385587Sobrien static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; 22485587Sobrien int i, ncall, ndef; 225125601Sru int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */ 22685587Sobrien Node *x; 22785587Sobrien Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */ 22885587Sobrien Cell *y, *z, *fcn; 22985587Sobrien char *s; 23085587Sobrien 23185587Sobrien fcn = execute(a[0]); /* the function itself */ 23285587Sobrien s = fcn->nval; 23385587Sobrien if (!isfcn(fcn)) 23485587Sobrien FATAL("calling undefined function %s", s); 23585587Sobrien if (frame == NULL) { 23685587Sobrien fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); 23785587Sobrien if (frame == NULL) 23885587Sobrien FATAL("out of space for stack frames calling %s", s); 23985587Sobrien } 24085587Sobrien for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ 24185587Sobrien ncall++; 24285587Sobrien ndef = (int) fcn->fval; /* args in defn */ 24385587Sobrien dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) ); 24485587Sobrien if (ncall > ndef) 24585587Sobrien WARNING("function %s called with %d args, uses only %d", 24685587Sobrien s, ncall, ndef); 24785587Sobrien if (ncall + ndef > NARGS) 24885587Sobrien FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS); 24985587Sobrien for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ 25085587Sobrien dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) ); 25185587Sobrien y = execute(x); 25285587Sobrien oargs[i] = y; 25385587Sobrien dprintf( ("args[%d]: %s %f <%s>, t=%o\n", 254107806Sobrien i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) ); 25585587Sobrien if (isfcn(y)) 25685587Sobrien FATAL("can't use function %s as argument in %s", y->nval, s); 25785587Sobrien if (isarr(y)) 25885587Sobrien args[i] = y; /* arrays by ref */ 25985587Sobrien else 26085587Sobrien args[i] = copycell(y); 26185587Sobrien tempfree(y); 26285587Sobrien } 26385587Sobrien for ( ; i < ndef; i++) { /* add null args for ones not provided */ 26485587Sobrien args[i] = gettemp(); 26585587Sobrien *args[i] = newcopycell; 26685587Sobrien } 26785587Sobrien fp++; /* now ok to up frame */ 26885587Sobrien if (fp >= frame + nframe) { 26985587Sobrien int dfp = fp - frame; /* old index */ 27085587Sobrien frame = (struct Frame *) 27185587Sobrien realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); 27285587Sobrien if (frame == NULL) 27385587Sobrien FATAL("out of space for stack frames in %s", s); 27485587Sobrien fp = frame + dfp; 27585587Sobrien } 27685587Sobrien fp->fcncell = fcn; 27785587Sobrien fp->args = args; 27885587Sobrien fp->nargs = ndef; /* number defined with (excess are locals) */ 27985587Sobrien fp->retval = gettemp(); 28085587Sobrien 28185587Sobrien dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); 28285587Sobrien y = execute((Node *)(fcn->sval)); /* execute body */ 28385587Sobrien dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) ); 28485587Sobrien 28585587Sobrien for (i = 0; i < ndef; i++) { 28685587Sobrien Cell *t = fp->args[i]; 28785587Sobrien if (isarr(t)) { 28885587Sobrien if (t->csub == CCOPY) { 28985587Sobrien if (i >= ncall) { 29085587Sobrien freesymtab(t); 29185587Sobrien t->csub = CTEMP; 29285587Sobrien tempfree(t); 29385587Sobrien } else { 29485587Sobrien oargs[i]->tval = t->tval; 29585587Sobrien oargs[i]->tval &= ~(STR|NUM|DONTFREE); 29685587Sobrien oargs[i]->sval = t->sval; 29785587Sobrien tempfree(t); 29885587Sobrien } 29985587Sobrien } 30085587Sobrien } else if (t != y) { /* kludge to prevent freeing twice */ 30185587Sobrien t->csub = CTEMP; 30285587Sobrien tempfree(t); 303125601Sru } else if (t == y && t->csub == CCOPY) { 304125601Sru t->csub = CTEMP; 305125601Sru tempfree(t); 306125601Sru freed = 1; 30785587Sobrien } 30885587Sobrien } 30985587Sobrien tempfree(fcn); 31085587Sobrien if (isexit(y) || isnext(y)) 31185587Sobrien return y; 312125601Sru if (freed == 0) { 313125601Sru tempfree(y); /* don't free twice! */ 314125601Sru } 31585587Sobrien z = fp->retval; /* return value */ 31685587Sobrien dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); 31785587Sobrien fp--; 31885587Sobrien return(z); 31985587Sobrien} 32085587Sobrien 32185587SobrienCell *copycell(Cell *x) /* make a copy of a cell in a temp */ 32285587Sobrien{ 32385587Sobrien Cell *y; 32485587Sobrien 32585587Sobrien y = gettemp(); 32685587Sobrien y->csub = CCOPY; /* prevents freeing until call is over */ 32785587Sobrien y->nval = x->nval; /* BUG? */ 32885587Sobrien if (isstr(x)) 32985587Sobrien y->sval = tostring(x->sval); 33085587Sobrien y->fval = x->fval; 33185587Sobrien y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ 33285587Sobrien /* is DONTFREE right? */ 33385587Sobrien return y; 33485587Sobrien} 33585587Sobrien 33685587SobrienCell *arg(Node **a, int n) /* nth argument of a function */ 33785587Sobrien{ 33885587Sobrien 33985587Sobrien n = ptoi(a[0]); /* argument number, counting from 0 */ 34085587Sobrien dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); 34185587Sobrien if (n+1 > fp->nargs) 34285587Sobrien FATAL("argument #%d of function %s was not supplied", 34385587Sobrien n+1, fp->fcncell->nval); 34485587Sobrien return fp->args[n]; 34585587Sobrien} 34685587Sobrien 34785587SobrienCell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ 34885587Sobrien{ 34985587Sobrien Cell *y; 35085587Sobrien 35185587Sobrien switch (n) { 35285587Sobrien case EXIT: 35385587Sobrien if (a[0] != NULL) { 35485587Sobrien y = execute(a[0]); 35585587Sobrien errorflag = (int) getfval(y); 35685587Sobrien tempfree(y); 35785587Sobrien } 35885587Sobrien longjmp(env, 1); 35985587Sobrien case RETURN: 36085587Sobrien if (a[0] != NULL) { 36185587Sobrien y = execute(a[0]); 36285587Sobrien if ((y->tval & (STR|NUM)) == (STR|NUM)) { 36385587Sobrien setsval(fp->retval, getsval(y)); 36485587Sobrien fp->retval->fval = getfval(y); 36585587Sobrien fp->retval->tval |= NUM; 36685587Sobrien } 36785587Sobrien else if (y->tval & STR) 36885587Sobrien setsval(fp->retval, getsval(y)); 36985587Sobrien else if (y->tval & NUM) 37085587Sobrien setfval(fp->retval, getfval(y)); 37185587Sobrien else /* can't happen */ 37285587Sobrien FATAL("bad type variable %d", y->tval); 37385587Sobrien tempfree(y); 37485587Sobrien } 37585587Sobrien return(jret); 37685587Sobrien case NEXT: 37785587Sobrien return(jnext); 37885587Sobrien case NEXTFILE: 37985587Sobrien nextfile(); 38085587Sobrien return(jnextfile); 38185587Sobrien case BREAK: 38285587Sobrien return(jbreak); 38385587Sobrien case CONTINUE: 38485587Sobrien return(jcont); 38585587Sobrien default: /* can't happen */ 38685587Sobrien FATAL("illegal jump type %d", n); 38785587Sobrien } 38885587Sobrien return 0; /* not reached */ 38985587Sobrien} 39085587Sobrien 391201951SruCell *awkgetline(Node **a, int n) /* get next line from specific input */ 39285587Sobrien{ /* a[0] is variable, a[1] is operator, a[2] is filename */ 39385587Sobrien Cell *r, *x; 39485587Sobrien extern Cell **fldtab; 39585587Sobrien FILE *fp; 39685587Sobrien char *buf; 39785587Sobrien int bufsize = recsize; 39885587Sobrien int mode; 39985587Sobrien 40085587Sobrien if ((buf = (char *) malloc(bufsize)) == NULL) 40185587Sobrien FATAL("out of memory in getline"); 40285587Sobrien 40385587Sobrien fflush(stdout); /* in case someone is waiting for a prompt */ 40485587Sobrien r = gettemp(); 40585587Sobrien if (a[1] != NULL) { /* getline < file */ 40685587Sobrien x = execute(a[2]); /* filename */ 40785587Sobrien mode = ptoi(a[1]); 40885587Sobrien if (mode == '|') /* input pipe */ 40985587Sobrien mode = LE; /* arbitrary flag */ 41085587Sobrien fp = openfile(mode, getsval(x)); 41185587Sobrien tempfree(x); 41285587Sobrien if (fp == NULL) 41385587Sobrien n = -1; 41485587Sobrien else 41585587Sobrien n = readrec(&buf, &bufsize, fp); 41685587Sobrien if (n <= 0) { 41785587Sobrien ; 41885587Sobrien } else if (a[0] != NULL) { /* getline var <file */ 41985587Sobrien x = execute(a[0]); 42085587Sobrien setsval(x, buf); 42185587Sobrien tempfree(x); 42285587Sobrien } else { /* getline <file */ 42385587Sobrien setsval(fldtab[0], buf); 42485587Sobrien if (is_number(fldtab[0]->sval)) { 42585587Sobrien fldtab[0]->fval = atof(fldtab[0]->sval); 42685587Sobrien fldtab[0]->tval |= NUM; 42785587Sobrien } 42885587Sobrien } 42985587Sobrien } else { /* bare getline; use current input */ 43085587Sobrien if (a[0] == NULL) /* getline */ 43185587Sobrien n = getrec(&record, &recsize, 1); 43285587Sobrien else { /* getline var */ 43385587Sobrien n = getrec(&buf, &bufsize, 0); 43485587Sobrien x = execute(a[0]); 43585587Sobrien setsval(x, buf); 43685587Sobrien tempfree(x); 43785587Sobrien } 43885587Sobrien } 43985587Sobrien setfval(r, (Awkfloat) n); 44085587Sobrien free(buf); 44185587Sobrien return r; 44285587Sobrien} 44385587Sobrien 44485587SobrienCell *getnf(Node **a, int n) /* get NF */ 44585587Sobrien{ 44685587Sobrien if (donefld == 0) 44785587Sobrien fldbld(); 44885587Sobrien return (Cell *) a[0]; 44985587Sobrien} 45085587Sobrien 45185587SobrienCell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 45285587Sobrien{ 45385587Sobrien Cell *x, *y, *z; 45485587Sobrien char *s; 45585587Sobrien Node *np; 45685587Sobrien char *buf; 45785587Sobrien int bufsz = recsize; 45885587Sobrien int nsub = strlen(*SUBSEP); 45985587Sobrien 46085587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 46185587Sobrien FATAL("out of memory in array"); 46285587Sobrien 46385587Sobrien x = execute(a[0]); /* Cell* for symbol table */ 46485587Sobrien buf[0] = 0; 46585587Sobrien for (np = a[1]; np; np = np->nnext) { 46685587Sobrien y = execute(np); /* subscript */ 46785587Sobrien s = getsval(y); 468170331Srafan if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array")) 46985587Sobrien FATAL("out of memory for %s[%s...]", x->nval, buf); 47085587Sobrien strcat(buf, s); 47185587Sobrien if (np->nnext) 47285587Sobrien strcat(buf, *SUBSEP); 47385587Sobrien tempfree(y); 47485587Sobrien } 47585587Sobrien if (!isarr(x)) { 476107806Sobrien dprintf( ("making %s into an array\n", NN(x->nval)) ); 47785587Sobrien if (freeable(x)) 47885587Sobrien xfree(x->sval); 47985587Sobrien x->tval &= ~(STR|NUM|DONTFREE); 48085587Sobrien x->tval |= ARR; 48185587Sobrien x->sval = (char *) makesymtab(NSYMTAB); 48285587Sobrien } 48385587Sobrien z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); 48485587Sobrien z->ctype = OCELL; 48585587Sobrien z->csub = CVAR; 48685587Sobrien tempfree(x); 48785587Sobrien free(buf); 48885587Sobrien return(z); 48985587Sobrien} 49085587Sobrien 49185587SobrienCell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 49285587Sobrien{ 49385587Sobrien Cell *x, *y; 49485587Sobrien Node *np; 49585587Sobrien char *s; 49685587Sobrien int nsub = strlen(*SUBSEP); 49785587Sobrien 49885587Sobrien x = execute(a[0]); /* Cell* for symbol table */ 49985587Sobrien if (!isarr(x)) 50085587Sobrien return True; 50185587Sobrien if (a[1] == 0) { /* delete the elements, not the table */ 50285587Sobrien freesymtab(x); 50385587Sobrien x->tval &= ~STR; 50485587Sobrien x->tval |= ARR; 50585587Sobrien x->sval = (char *) makesymtab(NSYMTAB); 50685587Sobrien } else { 50785587Sobrien int bufsz = recsize; 50885587Sobrien char *buf; 50985587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 51085587Sobrien FATAL("out of memory in adelete"); 51185587Sobrien buf[0] = 0; 51285587Sobrien for (np = a[1]; np; np = np->nnext) { 51385587Sobrien y = execute(np); /* subscript */ 51485587Sobrien s = getsval(y); 515170331Srafan if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete")) 51685587Sobrien FATAL("out of memory deleting %s[%s...]", x->nval, buf); 51785587Sobrien strcat(buf, s); 51885587Sobrien if (np->nnext) 51985587Sobrien strcat(buf, *SUBSEP); 52085587Sobrien tempfree(y); 52185587Sobrien } 52285587Sobrien freeelem(x, buf); 52385587Sobrien free(buf); 52485587Sobrien } 52585587Sobrien tempfree(x); 52685587Sobrien return True; 52785587Sobrien} 52885587Sobrien 52985587SobrienCell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ 53085587Sobrien{ 53185587Sobrien Cell *x, *ap, *k; 53285587Sobrien Node *p; 53385587Sobrien char *buf; 53485587Sobrien char *s; 53585587Sobrien int bufsz = recsize; 53685587Sobrien int nsub = strlen(*SUBSEP); 53785587Sobrien 53885587Sobrien ap = execute(a[1]); /* array name */ 53985587Sobrien if (!isarr(ap)) { 54085587Sobrien dprintf( ("making %s into an array\n", ap->nval) ); 54185587Sobrien if (freeable(ap)) 54285587Sobrien xfree(ap->sval); 54385587Sobrien ap->tval &= ~(STR|NUM|DONTFREE); 54485587Sobrien ap->tval |= ARR; 54585587Sobrien ap->sval = (char *) makesymtab(NSYMTAB); 54685587Sobrien } 54785587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) { 54885587Sobrien FATAL("out of memory in intest"); 54985587Sobrien } 55085587Sobrien buf[0] = 0; 55185587Sobrien for (p = a[0]; p; p = p->nnext) { 55285587Sobrien x = execute(p); /* expr */ 55385587Sobrien s = getsval(x); 554170331Srafan if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest")) 55585587Sobrien FATAL("out of memory deleting %s[%s...]", x->nval, buf); 55685587Sobrien strcat(buf, s); 55785587Sobrien tempfree(x); 55885587Sobrien if (p->nnext) 55985587Sobrien strcat(buf, *SUBSEP); 56085587Sobrien } 56185587Sobrien k = lookup(buf, (Array *) ap->sval); 56285587Sobrien tempfree(ap); 56385587Sobrien free(buf); 56485587Sobrien if (k == NULL) 56585587Sobrien return(False); 56685587Sobrien else 56785587Sobrien return(True); 56885587Sobrien} 56985587Sobrien 57085587Sobrien 57185587SobrienCell *matchop(Node **a, int n) /* ~ and match() */ 57285587Sobrien{ 57385587Sobrien Cell *x, *y; 57485587Sobrien char *s, *t; 57585587Sobrien int i; 57685587Sobrien fa *pfa; 577107806Sobrien int (*mf)(fa *, const char *) = match, mode = 0; 57885587Sobrien 57985587Sobrien if (n == MATCHFCN) { 58085587Sobrien mf = pmatch; 58185587Sobrien mode = 1; 58285587Sobrien } 58385587Sobrien x = execute(a[1]); /* a[1] = target text */ 58485587Sobrien s = getsval(x); 58585587Sobrien if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ 58685587Sobrien i = (*mf)((fa *) a[2], s); 58785587Sobrien else { 58885587Sobrien y = execute(a[2]); /* a[2] = regular expr */ 58985587Sobrien t = getsval(y); 59085587Sobrien pfa = makedfa(t, mode); 59185587Sobrien i = (*mf)(pfa, s); 59285587Sobrien tempfree(y); 59385587Sobrien } 59485587Sobrien tempfree(x); 59585587Sobrien if (n == MATCHFCN) { 59685587Sobrien int start = patbeg - s + 1; 59785587Sobrien if (patlen < 0) 59885587Sobrien start = 0; 59985587Sobrien setfval(rstartloc, (Awkfloat) start); 60085587Sobrien setfval(rlengthloc, (Awkfloat) patlen); 60185587Sobrien x = gettemp(); 60285587Sobrien x->tval = NUM; 60385587Sobrien x->fval = start; 60485587Sobrien return x; 60585587Sobrien } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0)) 60685587Sobrien return(True); 60785587Sobrien else 60885587Sobrien return(False); 60985587Sobrien} 61085587Sobrien 61185587Sobrien 61285587SobrienCell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ 61385587Sobrien{ 61485587Sobrien Cell *x, *y; 61585587Sobrien int i; 61685587Sobrien 61785587Sobrien x = execute(a[0]); 61885587Sobrien i = istrue(x); 61985587Sobrien tempfree(x); 62085587Sobrien switch (n) { 62185587Sobrien case BOR: 62285587Sobrien if (i) return(True); 62385587Sobrien y = execute(a[1]); 62485587Sobrien i = istrue(y); 62585587Sobrien tempfree(y); 62685587Sobrien if (i) return(True); 62785587Sobrien else return(False); 62885587Sobrien case AND: 62985587Sobrien if ( !i ) return(False); 63085587Sobrien y = execute(a[1]); 63185587Sobrien i = istrue(y); 63285587Sobrien tempfree(y); 63385587Sobrien if (i) return(True); 63485587Sobrien else return(False); 63585587Sobrien case NOT: 63685587Sobrien if (i) return(False); 63785587Sobrien else return(True); 63885587Sobrien default: /* can't happen */ 63985587Sobrien FATAL("unknown boolean operator %d", n); 64085587Sobrien } 64185587Sobrien return 0; /*NOTREACHED*/ 64285587Sobrien} 64385587Sobrien 64485587SobrienCell *relop(Node **a, int n) /* a[0 < a[1], etc. */ 64585587Sobrien{ 64685587Sobrien int i; 64785587Sobrien Cell *x, *y; 64885587Sobrien Awkfloat j; 64985587Sobrien 65085587Sobrien x = execute(a[0]); 65185587Sobrien y = execute(a[1]); 65285587Sobrien if (x->tval&NUM && y->tval&NUM) { 65385587Sobrien j = x->fval - y->fval; 65485587Sobrien i = j<0? -1: (j>0? 1: 0); 65585587Sobrien } else { 65685587Sobrien i = strcmp(getsval(x), getsval(y)); 65785587Sobrien } 65885587Sobrien tempfree(x); 65985587Sobrien tempfree(y); 66085587Sobrien switch (n) { 66185587Sobrien case LT: if (i<0) return(True); 66285587Sobrien else return(False); 66385587Sobrien case LE: if (i<=0) return(True); 66485587Sobrien else return(False); 66585587Sobrien case NE: if (i!=0) return(True); 66685587Sobrien else return(False); 66785587Sobrien case EQ: if (i == 0) return(True); 66885587Sobrien else return(False); 66985587Sobrien case GE: if (i>=0) return(True); 67085587Sobrien else return(False); 67185587Sobrien case GT: if (i>0) return(True); 67285587Sobrien else return(False); 67385587Sobrien default: /* can't happen */ 67485587Sobrien FATAL("unknown relational operator %d", n); 67585587Sobrien } 67685587Sobrien return 0; /*NOTREACHED*/ 67785587Sobrien} 67885587Sobrien 67985587Sobrienvoid tfree(Cell *a) /* free a tempcell */ 68085587Sobrien{ 68185587Sobrien if (freeable(a)) { 682107806Sobrien dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) ); 68385587Sobrien xfree(a->sval); 68485587Sobrien } 68585587Sobrien if (a == tmps) 68685587Sobrien FATAL("tempcell list is curdled"); 68785587Sobrien a->cnext = tmps; 68885587Sobrien tmps = a; 68985587Sobrien} 69085587Sobrien 69185587SobrienCell *gettemp(void) /* get a tempcell */ 69285587Sobrien{ int i; 69385587Sobrien Cell *x; 69485587Sobrien 69585587Sobrien if (!tmps) { 69685587Sobrien tmps = (Cell *) calloc(100, sizeof(Cell)); 69785587Sobrien if (!tmps) 69885587Sobrien FATAL("out of space for temporaries"); 69985587Sobrien for(i = 1; i < 100; i++) 70085587Sobrien tmps[i-1].cnext = &tmps[i]; 70185587Sobrien tmps[i-1].cnext = 0; 70285587Sobrien } 70385587Sobrien x = tmps; 70485587Sobrien tmps = x->cnext; 70585587Sobrien *x = tempcell; 70685587Sobrien return(x); 70785587Sobrien} 70885587Sobrien 70985587SobrienCell *indirect(Node **a, int n) /* $( a[0] ) */ 71085587Sobrien{ 711146299Sru Awkfloat val; 71285587Sobrien Cell *x; 71385587Sobrien int m; 71485587Sobrien char *s; 71585587Sobrien 71685587Sobrien x = execute(a[0]); 717146299Sru val = getfval(x); /* freebsd: defend against super large field numbers */ 718146299Sru if ((Awkfloat)INT_MAX < val) 719146299Sru FATAL("trying to access out of range field %s", x->nval); 720146299Sru m = (int) val; 72185587Sobrien if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */ 72285587Sobrien FATAL("illegal field $(%s), name \"%s\"", s, x->nval); 72385587Sobrien /* BUG: can x->nval ever be null??? */ 72485587Sobrien tempfree(x); 72585587Sobrien x = fieldadr(m); 72685587Sobrien x->ctype = OCELL; /* BUG? why are these needed? */ 72785587Sobrien x->csub = CFLD; 72885587Sobrien return(x); 72985587Sobrien} 73085587Sobrien 73185587SobrienCell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ 73285587Sobrien{ 73385587Sobrien int k, m, n; 73485587Sobrien char *s; 73585587Sobrien int temp; 73685587Sobrien Cell *x, *y, *z = 0; 73785587Sobrien 73885587Sobrien x = execute(a[0]); 73985587Sobrien y = execute(a[1]); 74085587Sobrien if (a[2] != 0) 74185587Sobrien z = execute(a[2]); 74285587Sobrien s = getsval(x); 74385587Sobrien k = strlen(s) + 1; 74485587Sobrien if (k <= 1) { 74585587Sobrien tempfree(x); 74685587Sobrien tempfree(y); 74785587Sobrien if (a[2] != 0) { 74885587Sobrien tempfree(z); 74985587Sobrien } 75085587Sobrien x = gettemp(); 75185587Sobrien setsval(x, ""); 75285587Sobrien return(x); 75385587Sobrien } 75485587Sobrien m = (int) getfval(y); 75585587Sobrien if (m <= 0) 75685587Sobrien m = 1; 75785587Sobrien else if (m > k) 75885587Sobrien m = k; 75985587Sobrien tempfree(y); 76085587Sobrien if (a[2] != 0) { 76185587Sobrien n = (int) getfval(z); 76285587Sobrien tempfree(z); 76385587Sobrien } else 76485587Sobrien n = k - 1; 76585587Sobrien if (n < 0) 76685587Sobrien n = 0; 76785587Sobrien else if (n > k - m) 76885587Sobrien n = k - m; 76985587Sobrien dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); 77085587Sobrien y = gettemp(); 77185587Sobrien temp = s[n+m-1]; /* with thanks to John Linderman */ 77285587Sobrien s[n+m-1] = '\0'; 77385587Sobrien setsval(y, s + m - 1); 77485587Sobrien s[n+m-1] = temp; 77585587Sobrien tempfree(x); 77685587Sobrien return(y); 77785587Sobrien} 77885587Sobrien 77985587SobrienCell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ 78085587Sobrien{ 78185587Sobrien Cell *x, *y, *z; 78285587Sobrien char *s1, *s2, *p1, *p2, *q; 78385587Sobrien Awkfloat v = 0.0; 78485587Sobrien 78585587Sobrien x = execute(a[0]); 78685587Sobrien s1 = getsval(x); 78785587Sobrien y = execute(a[1]); 78885587Sobrien s2 = getsval(y); 78985587Sobrien 79085587Sobrien z = gettemp(); 79185587Sobrien for (p1 = s1; *p1 != '\0'; p1++) { 79285587Sobrien for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) 79385587Sobrien ; 79485587Sobrien if (*p2 == '\0') { 79585587Sobrien v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */ 79685587Sobrien break; 79785587Sobrien } 79885587Sobrien } 79985587Sobrien tempfree(x); 80085587Sobrien tempfree(y); 80185587Sobrien setfval(z, v); 80285587Sobrien return(z); 80385587Sobrien} 80485587Sobrien 80585587Sobrien#define MAXNUMSIZE 50 80685587Sobrien 807107806Sobrienint format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */ 80885587Sobrien{ 80985587Sobrien char *fmt; 810107806Sobrien char *p, *t; 811107806Sobrien const char *os; 81285587Sobrien Cell *x; 81385587Sobrien int flag = 0, n; 81485587Sobrien int fmtwd; /* format width */ 81585587Sobrien int fmtsz = recsize; 81685587Sobrien char *buf = *pbuf; 81785587Sobrien int bufsize = *pbufsize; 81885587Sobrien 81985587Sobrien os = s; 82085587Sobrien p = buf; 82185587Sobrien if ((fmt = (char *) malloc(fmtsz)) == NULL) 82285587Sobrien FATAL("out of memory in format()"); 82385587Sobrien while (*s) { 824170331Srafan adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1"); 82585587Sobrien if (*s != '%') { 82685587Sobrien *p++ = *s++; 82785587Sobrien continue; 82885587Sobrien } 82985587Sobrien if (*(s+1) == '%') { 83085587Sobrien *p++ = '%'; 83185587Sobrien s += 2; 83285587Sobrien continue; 83385587Sobrien } 83485587Sobrien /* have to be real careful in case this is a huge number, eg, %100000d */ 83585587Sobrien fmtwd = atoi(s+1); 83685587Sobrien if (fmtwd < 0) 83785587Sobrien fmtwd = -fmtwd; 838170331Srafan adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2"); 83985587Sobrien for (t = fmt; (*t++ = *s) != '\0'; s++) { 840170331Srafan if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3")) 84185587Sobrien FATAL("format item %.30s... ran format() out of memory", os); 84285587Sobrien if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') 84385587Sobrien break; /* the ansi panoply */ 84485587Sobrien if (*s == '*') { 84585587Sobrien x = execute(a); 84685587Sobrien a = a->nnext; 84785587Sobrien sprintf(t-1, "%d", fmtwd=(int) getfval(x)); 84885587Sobrien if (fmtwd < 0) 84985587Sobrien fmtwd = -fmtwd; 85085587Sobrien adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); 85185587Sobrien t = fmt + strlen(fmt); 85285587Sobrien tempfree(x); 85385587Sobrien } 85485587Sobrien } 85585587Sobrien *t = '\0'; 85685587Sobrien if (fmtwd < 0) 85785587Sobrien fmtwd = -fmtwd; 858170331Srafan adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4"); 85985587Sobrien 86085587Sobrien switch (*s) { 86185587Sobrien case 'f': case 'e': case 'g': case 'E': case 'G': 862107806Sobrien flag = 'f'; 86385587Sobrien break; 86485587Sobrien case 'd': case 'i': 865107806Sobrien flag = 'd'; 86685587Sobrien if(*(s-1) == 'l') break; 86785587Sobrien *(t-1) = 'l'; 86885587Sobrien *t = 'd'; 86985587Sobrien *++t = '\0'; 87085587Sobrien break; 87185587Sobrien case 'o': case 'x': case 'X': case 'u': 872107806Sobrien flag = *(s-1) == 'l' ? 'd' : 'u'; 87385587Sobrien break; 87485587Sobrien case 's': 875107806Sobrien flag = 's'; 87685587Sobrien break; 87785587Sobrien case 'c': 878107806Sobrien flag = 'c'; 87985587Sobrien break; 88085587Sobrien default: 88185587Sobrien WARNING("weird printf conversion %s", fmt); 882107806Sobrien flag = '?'; 88385587Sobrien break; 88485587Sobrien } 88585587Sobrien if (a == NULL) 88685587Sobrien FATAL("not enough args in printf(%s)", os); 88785587Sobrien x = execute(a); 88885587Sobrien a = a->nnext; 88985587Sobrien n = MAXNUMSIZE; 89085587Sobrien if (fmtwd > n) 89185587Sobrien n = fmtwd; 892170331Srafan adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5"); 89385587Sobrien switch (flag) { 894107806Sobrien case '?': sprintf(p, "%s", fmt); /* unknown, so dump it too */ 89585587Sobrien t = getsval(x); 89685587Sobrien n = strlen(t); 89785587Sobrien if (fmtwd > n) 89885587Sobrien n = fmtwd; 899170331Srafan adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6"); 90085587Sobrien p += strlen(p); 90185587Sobrien sprintf(p, "%s", t); 90285587Sobrien break; 903107806Sobrien case 'f': sprintf(p, fmt, getfval(x)); break; 904107806Sobrien case 'd': sprintf(p, fmt, (long) getfval(x)); break; 905107806Sobrien case 'u': sprintf(p, fmt, (int) getfval(x)); break; 906107806Sobrien case 's': 90785587Sobrien t = getsval(x); 90885587Sobrien n = strlen(t); 90985587Sobrien if (fmtwd > n) 91085587Sobrien n = fmtwd; 911170331Srafan if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7")) 91285587Sobrien FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t); 91385587Sobrien sprintf(p, fmt, t); 91485587Sobrien break; 915107806Sobrien case 'c': 91685587Sobrien if (isnum(x)) { 91785587Sobrien if (getfval(x)) 91885587Sobrien sprintf(p, fmt, (int) getfval(x)); 919107806Sobrien else { 920107806Sobrien *p++ = '\0'; /* explicit null byte */ 921107806Sobrien *p = '\0'; /* next output will start here */ 922107806Sobrien } 92385587Sobrien } else 92485587Sobrien sprintf(p, fmt, getsval(x)[0]); 92585587Sobrien break; 926107806Sobrien default: 927107806Sobrien FATAL("can't happen: bad conversion %c in format()", flag); 92885587Sobrien } 92985587Sobrien tempfree(x); 93085587Sobrien p += strlen(p); 93185587Sobrien s++; 93285587Sobrien } 93385587Sobrien *p = '\0'; 93485587Sobrien free(fmt); 93585587Sobrien for ( ; a; a = a->nnext) /* evaluate any remaining args */ 93685587Sobrien execute(a); 93785587Sobrien *pbuf = buf; 93885587Sobrien *pbufsize = bufsize; 93985587Sobrien return p - buf; 94085587Sobrien} 94185587Sobrien 94285587SobrienCell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ 94385587Sobrien{ 94485587Sobrien Cell *x; 94585587Sobrien Node *y; 94685587Sobrien char *buf; 94785587Sobrien int bufsz=3*recsize; 94885587Sobrien 94985587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 95085587Sobrien FATAL("out of memory in awksprintf"); 95185587Sobrien y = a[0]->nnext; 95285587Sobrien x = execute(a[0]); 95385587Sobrien if (format(&buf, &bufsz, getsval(x), y) == -1) 95485587Sobrien FATAL("sprintf string %.30s... too long. can't happen.", buf); 95585587Sobrien tempfree(x); 95685587Sobrien x = gettemp(); 95785587Sobrien x->sval = buf; 95885587Sobrien x->tval = STR; 95985587Sobrien return(x); 96085587Sobrien} 96185587Sobrien 96285587SobrienCell *awkprintf(Node **a, int n) /* printf */ 96385587Sobrien{ /* a[0] is list of args, starting with format string */ 96485587Sobrien /* a[1] is redirection operator, a[2] is redirection file */ 96585587Sobrien FILE *fp; 96685587Sobrien Cell *x; 96785587Sobrien Node *y; 96885587Sobrien char *buf; 96985587Sobrien int len; 97085587Sobrien int bufsz=3*recsize; 97185587Sobrien 97285587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 97385587Sobrien FATAL("out of memory in awkprintf"); 97485587Sobrien y = a[0]->nnext; 97585587Sobrien x = execute(a[0]); 97685587Sobrien if ((len = format(&buf, &bufsz, getsval(x), y)) == -1) 97785587Sobrien FATAL("printf string %.30s... too long. can't happen.", buf); 97885587Sobrien tempfree(x); 97985587Sobrien if (a[1] == NULL) { 98085587Sobrien /* fputs(buf, stdout); */ 98185587Sobrien fwrite(buf, len, 1, stdout); 98285587Sobrien if (ferror(stdout)) 98385587Sobrien FATAL("write error on stdout"); 98485587Sobrien } else { 98585587Sobrien fp = redirect(ptoi(a[1]), a[2]); 98685587Sobrien /* fputs(buf, fp); */ 98785587Sobrien fwrite(buf, len, 1, fp); 98885587Sobrien fflush(fp); 98985587Sobrien if (ferror(fp)) 99085587Sobrien FATAL("write error on %s", filename(fp)); 99185587Sobrien } 99285587Sobrien free(buf); 99385587Sobrien return(True); 99485587Sobrien} 99585587Sobrien 99685587SobrienCell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ 99785587Sobrien{ 99885587Sobrien Awkfloat i, j = 0; 99985587Sobrien double v; 100085587Sobrien Cell *x, *y, *z; 100185587Sobrien 100285587Sobrien x = execute(a[0]); 100385587Sobrien i = getfval(x); 100485587Sobrien tempfree(x); 100585587Sobrien if (n != UMINUS) { 100685587Sobrien y = execute(a[1]); 100785587Sobrien j = getfval(y); 100885587Sobrien tempfree(y); 100985587Sobrien } 101085587Sobrien z = gettemp(); 101185587Sobrien switch (n) { 101285587Sobrien case ADD: 101385587Sobrien i += j; 101485587Sobrien break; 101585587Sobrien case MINUS: 101685587Sobrien i -= j; 101785587Sobrien break; 101885587Sobrien case MULT: 101985587Sobrien i *= j; 102085587Sobrien break; 102185587Sobrien case DIVIDE: 102285587Sobrien if (j == 0) 102385587Sobrien FATAL("division by zero"); 102485587Sobrien i /= j; 102585587Sobrien break; 102685587Sobrien case MOD: 102785587Sobrien if (j == 0) 102885587Sobrien FATAL("division by zero in mod"); 102985587Sobrien modf(i/j, &v); 103085587Sobrien i = i - j * v; 103185587Sobrien break; 103285587Sobrien case UMINUS: 103385587Sobrien i = -i; 103485587Sobrien break; 103585587Sobrien case POWER: 103685587Sobrien if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ 103785587Sobrien i = ipow(i, (int) j); 103885587Sobrien else 103985587Sobrien i = errcheck(pow(i, j), "pow"); 104085587Sobrien break; 104185587Sobrien default: /* can't happen */ 104285587Sobrien FATAL("illegal arithmetic operator %d", n); 104385587Sobrien } 104485587Sobrien setfval(z, i); 104585587Sobrien return(z); 104685587Sobrien} 104785587Sobrien 104885587Sobriendouble ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ 104985587Sobrien{ 105085587Sobrien double v; 105185587Sobrien 105285587Sobrien if (n <= 0) 105385587Sobrien return 1; 105485587Sobrien v = ipow(x, n/2); 105585587Sobrien if (n % 2 == 0) 105685587Sobrien return v * v; 105785587Sobrien else 105885587Sobrien return x * v * v; 105985587Sobrien} 106085587Sobrien 106185587SobrienCell *incrdecr(Node **a, int n) /* a[0]++, etc. */ 106285587Sobrien{ 106385587Sobrien Cell *x, *z; 106485587Sobrien int k; 106585587Sobrien Awkfloat xf; 106685587Sobrien 106785587Sobrien x = execute(a[0]); 106885587Sobrien xf = getfval(x); 106985587Sobrien k = (n == PREINCR || n == POSTINCR) ? 1 : -1; 107085587Sobrien if (n == PREINCR || n == PREDECR) { 107185587Sobrien setfval(x, xf + k); 107285587Sobrien return(x); 107385587Sobrien } 107485587Sobrien z = gettemp(); 107585587Sobrien setfval(z, xf); 107685587Sobrien setfval(x, xf + k); 107785587Sobrien tempfree(x); 107885587Sobrien return(z); 107985587Sobrien} 108085587Sobrien 108185587SobrienCell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ 108285587Sobrien{ /* this is subtle; don't muck with it. */ 108385587Sobrien Cell *x, *y; 108485587Sobrien Awkfloat xf, yf; 108585587Sobrien double v; 108685587Sobrien 108785587Sobrien y = execute(a[1]); 108885587Sobrien x = execute(a[0]); 108985587Sobrien if (n == ASSIGN) { /* ordinary assignment */ 109085587Sobrien if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ 109185587Sobrien ; /* leave alone unless it's a field */ 109285587Sobrien else if ((y->tval & (STR|NUM)) == (STR|NUM)) { 109385587Sobrien setsval(x, getsval(y)); 109485587Sobrien x->fval = getfval(y); 109585587Sobrien x->tval |= NUM; 109685587Sobrien } 109785587Sobrien else if (isstr(y)) 109885587Sobrien setsval(x, getsval(y)); 109985587Sobrien else if (isnum(y)) 110085587Sobrien setfval(x, getfval(y)); 110185587Sobrien else 110285587Sobrien funnyvar(y, "read value of"); 110385587Sobrien tempfree(y); 110485587Sobrien return(x); 110585587Sobrien } 110685587Sobrien xf = getfval(x); 110785587Sobrien yf = getfval(y); 110885587Sobrien switch (n) { 110985587Sobrien case ADDEQ: 111085587Sobrien xf += yf; 111185587Sobrien break; 111285587Sobrien case SUBEQ: 111385587Sobrien xf -= yf; 111485587Sobrien break; 111585587Sobrien case MULTEQ: 111685587Sobrien xf *= yf; 111785587Sobrien break; 111885587Sobrien case DIVEQ: 111985587Sobrien if (yf == 0) 112085587Sobrien FATAL("division by zero in /="); 112185587Sobrien xf /= yf; 112285587Sobrien break; 112385587Sobrien case MODEQ: 112485587Sobrien if (yf == 0) 112585587Sobrien FATAL("division by zero in %%="); 112685587Sobrien modf(xf/yf, &v); 112785587Sobrien xf = xf - yf * v; 112885587Sobrien break; 112985587Sobrien case POWEQ: 113085587Sobrien if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ 113185587Sobrien xf = ipow(xf, (int) yf); 113285587Sobrien else 113385587Sobrien xf = errcheck(pow(xf, yf), "pow"); 113485587Sobrien break; 113585587Sobrien default: 113685587Sobrien FATAL("illegal assignment operator %d", n); 113785587Sobrien break; 113885587Sobrien } 113985587Sobrien tempfree(y); 114085587Sobrien setfval(x, xf); 114185587Sobrien return(x); 114285587Sobrien} 114385587Sobrien 114485587SobrienCell *cat(Node **a, int q) /* a[0] cat a[1] */ 114585587Sobrien{ 114685587Sobrien Cell *x, *y, *z; 114785587Sobrien int n1, n2; 114885587Sobrien char *s; 114985587Sobrien 115085587Sobrien x = execute(a[0]); 115185587Sobrien y = execute(a[1]); 115285587Sobrien getsval(x); 115385587Sobrien getsval(y); 115485587Sobrien n1 = strlen(x->sval); 115585587Sobrien n2 = strlen(y->sval); 115685587Sobrien s = (char *) malloc(n1 + n2 + 1); 115785587Sobrien if (s == NULL) 115885587Sobrien FATAL("out of space concatenating %.15s... and %.15s...", 115985587Sobrien x->sval, y->sval); 116085587Sobrien strcpy(s, x->sval); 116185587Sobrien strcpy(s+n1, y->sval); 1162201951Sru tempfree(x); 116385587Sobrien tempfree(y); 116485587Sobrien z = gettemp(); 116585587Sobrien z->sval = s; 116685587Sobrien z->tval = STR; 116785587Sobrien return(z); 116885587Sobrien} 116985587Sobrien 117085587SobrienCell *pastat(Node **a, int n) /* a[0] { a[1] } */ 117185587Sobrien{ 117285587Sobrien Cell *x; 117385587Sobrien 117485587Sobrien if (a[0] == 0) 117585587Sobrien x = execute(a[1]); 117685587Sobrien else { 117785587Sobrien x = execute(a[0]); 117885587Sobrien if (istrue(x)) { 117985587Sobrien tempfree(x); 118085587Sobrien x = execute(a[1]); 118185587Sobrien } 118285587Sobrien } 118385587Sobrien return x; 118485587Sobrien} 118585587Sobrien 118685587SobrienCell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ 118785587Sobrien{ 118885587Sobrien Cell *x; 118985587Sobrien int pair; 119085587Sobrien 119185587Sobrien pair = ptoi(a[3]); 119285587Sobrien if (pairstack[pair] == 0) { 119385587Sobrien x = execute(a[0]); 119485587Sobrien if (istrue(x)) 119585587Sobrien pairstack[pair] = 1; 119685587Sobrien tempfree(x); 119785587Sobrien } 119885587Sobrien if (pairstack[pair] == 1) { 119985587Sobrien x = execute(a[1]); 120085587Sobrien if (istrue(x)) 120185587Sobrien pairstack[pair] = 0; 120285587Sobrien tempfree(x); 120385587Sobrien x = execute(a[2]); 120485587Sobrien return(x); 120585587Sobrien } 120685587Sobrien return(False); 120785587Sobrien} 120885587Sobrien 120985587SobrienCell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ 121085587Sobrien{ 121185587Sobrien Cell *x = 0, *y, *ap; 121285587Sobrien char *s; 121385587Sobrien int sep; 121485587Sobrien char *t, temp, num[50], *fs = 0; 121585587Sobrien int n, tempstat, arg3type; 121685587Sobrien 121785587Sobrien y = execute(a[0]); /* source string */ 121885587Sobrien s = getsval(y); 121985587Sobrien arg3type = ptoi(a[3]); 122085587Sobrien if (a[2] == 0) /* fs string */ 122185587Sobrien fs = *FS; 122285587Sobrien else if (arg3type == STRING) { /* split(str,arr,"string") */ 122385587Sobrien x = execute(a[2]); 122485587Sobrien fs = getsval(x); 122585587Sobrien } else if (arg3type == REGEXPR) 122685587Sobrien fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ 122785587Sobrien else 122885587Sobrien FATAL("illegal type of split"); 122985587Sobrien sep = *fs; 123085587Sobrien ap = execute(a[1]); /* array name */ 123185587Sobrien freesymtab(ap); 1232107806Sobrien dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) ); 123385587Sobrien ap->tval &= ~STR; 123485587Sobrien ap->tval |= ARR; 123585587Sobrien ap->sval = (char *) makesymtab(NSYMTAB); 123685587Sobrien 123785587Sobrien n = 0; 1238118194Sru if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */ 123985587Sobrien fa *pfa; 124085587Sobrien if (arg3type == REGEXPR) { /* it's ready already */ 124185587Sobrien pfa = (fa *) a[2]; 124285587Sobrien } else { 124385587Sobrien pfa = makedfa(fs, 1); 124485587Sobrien } 124585587Sobrien if (nematch(pfa,s)) { 124685587Sobrien tempstat = pfa->initstat; 124785587Sobrien pfa->initstat = 2; 124885587Sobrien do { 124985587Sobrien n++; 125085587Sobrien sprintf(num, "%d", n); 125185587Sobrien temp = *patbeg; 125285587Sobrien *patbeg = '\0'; 125385587Sobrien if (is_number(s)) 125485587Sobrien setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); 125585587Sobrien else 125685587Sobrien setsymtab(num, s, 0.0, STR, (Array *) ap->sval); 125785587Sobrien *patbeg = temp; 125885587Sobrien s = patbeg + patlen; 125985587Sobrien if (*(patbeg+patlen-1) == 0 || *s == 0) { 126085587Sobrien n++; 126185587Sobrien sprintf(num, "%d", n); 126285587Sobrien setsymtab(num, "", 0.0, STR, (Array *) ap->sval); 126385587Sobrien pfa->initstat = tempstat; 126485587Sobrien goto spdone; 126585587Sobrien } 126685587Sobrien } while (nematch(pfa,s)); 1267146299Sru pfa->initstat = tempstat; /* bwk: has to be here to reset */ 1268146299Sru /* cf gsub and refldbld */ 126985587Sobrien } 127085587Sobrien n++; 127185587Sobrien sprintf(num, "%d", n); 127285587Sobrien if (is_number(s)) 127385587Sobrien setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); 127485587Sobrien else 127585587Sobrien setsymtab(num, s, 0.0, STR, (Array *) ap->sval); 127685587Sobrien spdone: 127785587Sobrien pfa = NULL; 127885587Sobrien } else if (sep == ' ') { 127985587Sobrien for (n = 0; ; ) { 128085587Sobrien while (*s == ' ' || *s == '\t' || *s == '\n') 128185587Sobrien s++; 128285587Sobrien if (*s == 0) 128385587Sobrien break; 128485587Sobrien n++; 128585587Sobrien t = s; 128685587Sobrien do 128785587Sobrien s++; 128885587Sobrien while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); 128985587Sobrien temp = *s; 129085587Sobrien *s = '\0'; 129185587Sobrien sprintf(num, "%d", n); 129285587Sobrien if (is_number(t)) 129385587Sobrien setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 129485587Sobrien else 129585587Sobrien setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 129685587Sobrien *s = temp; 129785587Sobrien if (*s != 0) 129885587Sobrien s++; 129985587Sobrien } 130085587Sobrien } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */ 130185587Sobrien for (n = 0; *s != 0; s++) { 130285587Sobrien char buf[2]; 130385587Sobrien n++; 130485587Sobrien sprintf(num, "%d", n); 130585587Sobrien buf[0] = *s; 130685587Sobrien buf[1] = 0; 130785587Sobrien if (isdigit((uschar)buf[0])) 130885587Sobrien setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval); 130985587Sobrien else 131085587Sobrien setsymtab(num, buf, 0.0, STR, (Array *) ap->sval); 131185587Sobrien } 131285587Sobrien } else if (*s != 0) { 131385587Sobrien for (;;) { 131485587Sobrien n++; 131585587Sobrien t = s; 131685587Sobrien while (*s != sep && *s != '\n' && *s != '\0') 131785587Sobrien s++; 131885587Sobrien temp = *s; 131985587Sobrien *s = '\0'; 132085587Sobrien sprintf(num, "%d", n); 132185587Sobrien if (is_number(t)) 132285587Sobrien setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); 132385587Sobrien else 132485587Sobrien setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 132585587Sobrien *s = temp; 132685587Sobrien if (*s++ == 0) 132785587Sobrien break; 132885587Sobrien } 132985587Sobrien } 133085587Sobrien tempfree(ap); 133185587Sobrien tempfree(y); 133285587Sobrien if (a[2] != 0 && arg3type == STRING) { 133385587Sobrien tempfree(x); 133485587Sobrien } 133585587Sobrien x = gettemp(); 133685587Sobrien x->tval = NUM; 133785587Sobrien x->fval = n; 133885587Sobrien return(x); 133985587Sobrien} 134085587Sobrien 134185587SobrienCell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ 134285587Sobrien{ 134385587Sobrien Cell *x; 134485587Sobrien 134585587Sobrien x = execute(a[0]); 134685587Sobrien if (istrue(x)) { 134785587Sobrien tempfree(x); 134885587Sobrien x = execute(a[1]); 134985587Sobrien } else { 135085587Sobrien tempfree(x); 135185587Sobrien x = execute(a[2]); 135285587Sobrien } 135385587Sobrien return(x); 135485587Sobrien} 135585587Sobrien 135685587SobrienCell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ 135785587Sobrien{ 135885587Sobrien Cell *x; 135985587Sobrien 136085587Sobrien x = execute(a[0]); 136185587Sobrien if (istrue(x)) { 136285587Sobrien tempfree(x); 136385587Sobrien x = execute(a[1]); 136485587Sobrien } else if (a[2] != 0) { 136585587Sobrien tempfree(x); 136685587Sobrien x = execute(a[2]); 136785587Sobrien } 136885587Sobrien return(x); 136985587Sobrien} 137085587Sobrien 137185587SobrienCell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ 137285587Sobrien{ 137385587Sobrien Cell *x; 137485587Sobrien 137585587Sobrien for (;;) { 137685587Sobrien x = execute(a[0]); 137785587Sobrien if (!istrue(x)) 137885587Sobrien return(x); 137985587Sobrien tempfree(x); 138085587Sobrien x = execute(a[1]); 138185587Sobrien if (isbreak(x)) { 138285587Sobrien x = True; 138385587Sobrien return(x); 138485587Sobrien } 138585587Sobrien if (isnext(x) || isexit(x) || isret(x)) 138685587Sobrien return(x); 138785587Sobrien tempfree(x); 138885587Sobrien } 138985587Sobrien} 139085587Sobrien 139185587SobrienCell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ 139285587Sobrien{ 139385587Sobrien Cell *x; 139485587Sobrien 139585587Sobrien for (;;) { 139685587Sobrien x = execute(a[0]); 139785587Sobrien if (isbreak(x)) 139885587Sobrien return True; 139985587Sobrien if (isnext(x) || isexit(x) || isret(x)) 140085587Sobrien return(x); 140185587Sobrien tempfree(x); 140285587Sobrien x = execute(a[1]); 140385587Sobrien if (!istrue(x)) 140485587Sobrien return(x); 140585587Sobrien tempfree(x); 140685587Sobrien } 140785587Sobrien} 140885587Sobrien 140985587SobrienCell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ 141085587Sobrien{ 141185587Sobrien Cell *x; 141285587Sobrien 141385587Sobrien x = execute(a[0]); 141485587Sobrien tempfree(x); 141585587Sobrien for (;;) { 141685587Sobrien if (a[1]!=0) { 141785587Sobrien x = execute(a[1]); 141885587Sobrien if (!istrue(x)) return(x); 141985587Sobrien else tempfree(x); 142085587Sobrien } 142185587Sobrien x = execute(a[3]); 142285587Sobrien if (isbreak(x)) /* turn off break */ 142385587Sobrien return True; 142485587Sobrien if (isnext(x) || isexit(x) || isret(x)) 142585587Sobrien return(x); 142685587Sobrien tempfree(x); 142785587Sobrien x = execute(a[2]); 142885587Sobrien tempfree(x); 142985587Sobrien } 143085587Sobrien} 143185587Sobrien 143285587SobrienCell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ 143385587Sobrien{ 143485587Sobrien Cell *x, *vp, *arrayp, *cp, *ncp; 143585587Sobrien Array *tp; 143685587Sobrien int i; 143785587Sobrien 143885587Sobrien vp = execute(a[0]); 143985587Sobrien arrayp = execute(a[1]); 144085587Sobrien if (!isarr(arrayp)) { 144185587Sobrien return True; 144285587Sobrien } 144385587Sobrien tp = (Array *) arrayp->sval; 144485587Sobrien tempfree(arrayp); 144585587Sobrien for (i = 0; i < tp->size; i++) { /* this routine knows too much */ 144685587Sobrien for (cp = tp->tab[i]; cp != NULL; cp = ncp) { 144785587Sobrien setsval(vp, cp->nval); 144885587Sobrien ncp = cp->cnext; 144985587Sobrien x = execute(a[2]); 145085587Sobrien if (isbreak(x)) { 145185587Sobrien tempfree(vp); 145285587Sobrien return True; 145385587Sobrien } 145485587Sobrien if (isnext(x) || isexit(x) || isret(x)) { 145585587Sobrien tempfree(vp); 145685587Sobrien return(x); 145785587Sobrien } 145885587Sobrien tempfree(x); 145985587Sobrien } 146085587Sobrien } 146185587Sobrien return True; 146285587Sobrien} 146385587Sobrien 146485587SobrienCell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ 146585587Sobrien{ 146685587Sobrien Cell *x, *y; 146785587Sobrien Awkfloat u; 146885587Sobrien int t; 146985587Sobrien char *p, *buf; 147085587Sobrien Node *nextarg; 147185587Sobrien FILE *fp; 147290902Sdes void flush_all(void); 147385587Sobrien 147485587Sobrien t = ptoi(a[0]); 147585587Sobrien x = execute(a[1]); 147685587Sobrien nextarg = a[1]->nnext; 147785587Sobrien switch (t) { 147885587Sobrien case FLENGTH: 147990902Sdes if (isarr(x)) 148090902Sdes u = ((Array *) x->sval)->nelem; /* GROT. should be function*/ 148190902Sdes else 148290902Sdes u = strlen(getsval(x)); 148390902Sdes break; 148485587Sobrien case FLOG: 148585587Sobrien u = errcheck(log(getfval(x)), "log"); break; 148685587Sobrien case FINT: 148785587Sobrien modf(getfval(x), &u); break; 148885587Sobrien case FEXP: 148985587Sobrien u = errcheck(exp(getfval(x)), "exp"); break; 149085587Sobrien case FSQRT: 149185587Sobrien u = errcheck(sqrt(getfval(x)), "sqrt"); break; 149285587Sobrien case FSIN: 149385587Sobrien u = sin(getfval(x)); break; 149485587Sobrien case FCOS: 149585587Sobrien u = cos(getfval(x)); break; 149685587Sobrien case FATAN: 149785587Sobrien if (nextarg == 0) { 149885587Sobrien WARNING("atan2 requires two arguments; returning 1.0"); 149985587Sobrien u = 1.0; 150085587Sobrien } else { 150185587Sobrien y = execute(a[1]->nnext); 150285587Sobrien u = atan2(getfval(x), getfval(y)); 150385587Sobrien tempfree(y); 150485587Sobrien nextarg = nextarg->nnext; 150585587Sobrien } 150685587Sobrien break; 150785587Sobrien case FSYSTEM: 150885587Sobrien fflush(stdout); /* in case something is buffered already */ 150985587Sobrien u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ 151085587Sobrien break; 151185587Sobrien case FRAND: 151285587Sobrien /* in principle, rand() returns something in 0..RAND_MAX */ 151385587Sobrien u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; 151485587Sobrien break; 151585587Sobrien case FSRAND: 151685587Sobrien if (isrec(x)) /* no argument provided */ 151785587Sobrien u = time((time_t *)0); 151885587Sobrien else 151985587Sobrien u = getfval(x); 152085587Sobrien srand((unsigned int) u); 152185587Sobrien break; 152285587Sobrien case FTOUPPER: 152385587Sobrien case FTOLOWER: 152485587Sobrien buf = tostring(getsval(x)); 152585587Sobrien if (t == FTOUPPER) { 152685587Sobrien for (p = buf; *p; p++) 152785587Sobrien if (islower((uschar) *p)) 1528112336Sobrien *p = toupper((uschar)*p); 152985587Sobrien } else { 153085587Sobrien for (p = buf; *p; p++) 153185587Sobrien if (isupper((uschar) *p)) 1532112336Sobrien *p = tolower((uschar)*p); 153385587Sobrien } 153485587Sobrien tempfree(x); 153585587Sobrien x = gettemp(); 153685587Sobrien setsval(x, buf); 153785587Sobrien free(buf); 153885587Sobrien return x; 153985587Sobrien case FFLUSH: 154090902Sdes if (isrec(x) || strlen(getsval(x)) == 0) { 154190902Sdes flush_all(); /* fflush() or fflush("") -> all */ 154290902Sdes u = 0; 154390902Sdes } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL) 154485587Sobrien u = EOF; 154585587Sobrien else 154685587Sobrien u = fflush(fp); 154785587Sobrien break; 154885587Sobrien default: /* can't happen */ 154985587Sobrien FATAL("illegal function type %d", t); 155085587Sobrien break; 155185587Sobrien } 155285587Sobrien tempfree(x); 155385587Sobrien x = gettemp(); 155485587Sobrien setfval(x, u); 155585587Sobrien if (nextarg != 0) { 155685587Sobrien WARNING("warning: function has too many arguments"); 155785587Sobrien for ( ; nextarg; nextarg = nextarg->nnext) 155885587Sobrien execute(nextarg); 155985587Sobrien } 156085587Sobrien return(x); 156185587Sobrien} 156285587Sobrien 156385587SobrienCell *printstat(Node **a, int n) /* print a[0] */ 156485587Sobrien{ 156585587Sobrien Node *x; 156685587Sobrien Cell *y; 156785587Sobrien FILE *fp; 156885587Sobrien 156985587Sobrien if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ 157085587Sobrien fp = stdout; 157185587Sobrien else 157285587Sobrien fp = redirect(ptoi(a[1]), a[2]); 157385587Sobrien for (x = a[0]; x != NULL; x = x->nnext) { 157485587Sobrien y = execute(x); 1575107806Sobrien fputs(getpssval(y), fp); 157685587Sobrien tempfree(y); 157785587Sobrien if (x->nnext == NULL) 157885587Sobrien fputs(*ORS, fp); 157985587Sobrien else 158085587Sobrien fputs(*OFS, fp); 158185587Sobrien } 158285587Sobrien if (a[1] != 0) 158385587Sobrien fflush(fp); 158485587Sobrien if (ferror(fp)) 158585587Sobrien FATAL("write error on %s", filename(fp)); 158685587Sobrien return(True); 158785587Sobrien} 158885587Sobrien 158985587SobrienCell *nullproc(Node **a, int n) 159085587Sobrien{ 159185587Sobrien n = n; 159285587Sobrien a = a; 159385587Sobrien return 0; 159485587Sobrien} 159585587Sobrien 159685587Sobrien 159785587SobrienFILE *redirect(int a, Node *b) /* set up all i/o redirections */ 159885587Sobrien{ 159985587Sobrien FILE *fp; 160085587Sobrien Cell *x; 160185587Sobrien char *fname; 160285587Sobrien 160385587Sobrien x = execute(b); 160485587Sobrien fname = getsval(x); 160585587Sobrien fp = openfile(a, fname); 160685587Sobrien if (fp == NULL) 160785587Sobrien FATAL("can't open file %s", fname); 160885587Sobrien tempfree(x); 160985587Sobrien return fp; 161085587Sobrien} 161185587Sobrien 161285587Sobrienstruct files { 161385587Sobrien FILE *fp; 1614107806Sobrien const char *fname; 161585587Sobrien int mode; /* '|', 'a', 'w' => LE/LT, GT */ 161685587Sobrien} files[FOPEN_MAX] ={ 161785587Sobrien { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */ 161885587Sobrien { NULL, "/dev/stdout", GT }, 161985587Sobrien { NULL, "/dev/stderr", GT } 162085587Sobrien}; 162185587Sobrien 162285587Sobrienvoid stdinit(void) /* in case stdin, etc., are not constants */ 162385587Sobrien{ 162485587Sobrien files[0].fp = stdin; 162585587Sobrien files[1].fp = stdout; 162685587Sobrien files[2].fp = stderr; 162785587Sobrien} 162885587Sobrien 1629107806SobrienFILE *openfile(int a, const char *us) 163085587Sobrien{ 1631107806Sobrien const char *s = us; 163285587Sobrien int i, m; 163385587Sobrien FILE *fp = 0; 163485587Sobrien 163585587Sobrien if (*s == '\0') 163685587Sobrien FATAL("null file name in print or getline"); 163785587Sobrien for (i=0; i < FOPEN_MAX; i++) 163885587Sobrien if (files[i].fname && strcmp(s, files[i].fname) == 0) { 163985587Sobrien if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) 164085587Sobrien return files[i].fp; 164185587Sobrien if (a == FFLUSH) 164285587Sobrien return files[i].fp; 164385587Sobrien } 164485587Sobrien if (a == FFLUSH) /* didn't find it, so don't create it! */ 164585587Sobrien return NULL; 164685587Sobrien 164785587Sobrien for (i=0; i < FOPEN_MAX; i++) 164885587Sobrien if (files[i].fp == 0) 164985587Sobrien break; 165085587Sobrien if (i >= FOPEN_MAX) 165185587Sobrien FATAL("%s makes too many open files", s); 165285587Sobrien fflush(stdout); /* force a semblance of order */ 165385587Sobrien m = a; 165485587Sobrien if (a == GT) { 165585587Sobrien fp = fopen(s, "w"); 165685587Sobrien } else if (a == APPEND) { 165785587Sobrien fp = fopen(s, "a"); 165885587Sobrien m = GT; /* so can mix > and >> */ 165985587Sobrien } else if (a == '|') { /* output pipe */ 166085587Sobrien fp = popen(s, "w"); 166185587Sobrien } else if (a == LE) { /* input pipe */ 166285587Sobrien fp = popen(s, "r"); 166385587Sobrien } else if (a == LT) { /* getline <file */ 166485587Sobrien fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */ 166585587Sobrien } else /* can't happen */ 166685587Sobrien FATAL("illegal redirection %d", a); 166785587Sobrien if (fp != NULL) { 166885587Sobrien files[i].fname = tostring(s); 166985587Sobrien files[i].fp = fp; 167085587Sobrien files[i].mode = m; 167185587Sobrien } 167285587Sobrien return fp; 167385587Sobrien} 167485587Sobrien 1675107806Sobrienconst char *filename(FILE *fp) 167685587Sobrien{ 167785587Sobrien int i; 167885587Sobrien 167985587Sobrien for (i = 0; i < FOPEN_MAX; i++) 168085587Sobrien if (fp == files[i].fp) 168185587Sobrien return files[i].fname; 168285587Sobrien return "???"; 168385587Sobrien} 168485587Sobrien 168585587SobrienCell *closefile(Node **a, int n) 168685587Sobrien{ 168785587Sobrien Cell *x; 168885587Sobrien int i, stat; 168985587Sobrien 169085587Sobrien n = n; 169185587Sobrien x = execute(a[0]); 169285587Sobrien getsval(x); 169385587Sobrien stat = -1; 169485587Sobrien for (i = 0; i < FOPEN_MAX; i++) { 169585587Sobrien if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { 169685587Sobrien if (ferror(files[i].fp)) 169785587Sobrien WARNING( "i/o error occurred on %s", files[i].fname ); 169885587Sobrien if (files[i].mode == '|' || files[i].mode == LE) 169985587Sobrien stat = pclose(files[i].fp); 170085587Sobrien else 170185587Sobrien stat = fclose(files[i].fp); 170285587Sobrien if (stat == EOF) 170385587Sobrien WARNING( "i/o error occurred closing %s", files[i].fname ); 170485587Sobrien if (i > 2) /* don't do /dev/std... */ 170585587Sobrien xfree(files[i].fname); 170685587Sobrien files[i].fname = NULL; /* watch out for ref thru this */ 170785587Sobrien files[i].fp = NULL; 170885587Sobrien } 170985587Sobrien } 171085587Sobrien tempfree(x); 171185587Sobrien x = gettemp(); 171285587Sobrien setfval(x, (Awkfloat) stat); 171385587Sobrien return(x); 171485587Sobrien} 171585587Sobrien 171685587Sobrienvoid closeall(void) 171785587Sobrien{ 171885587Sobrien int i, stat; 171985587Sobrien 172085587Sobrien for (i = 0; i < FOPEN_MAX; i++) { 172185587Sobrien if (files[i].fp) { 172285587Sobrien if (ferror(files[i].fp)) 172385587Sobrien WARNING( "i/o error occurred on %s", files[i].fname ); 172485587Sobrien if (files[i].mode == '|' || files[i].mode == LE) 172585587Sobrien stat = pclose(files[i].fp); 172685587Sobrien else 172785587Sobrien stat = fclose(files[i].fp); 172885587Sobrien if (stat == EOF) 172985587Sobrien WARNING( "i/o error occurred while closing %s", files[i].fname ); 173085587Sobrien } 173185587Sobrien } 173285587Sobrien} 173385587Sobrien 173490902Sdesvoid flush_all(void) 173590902Sdes{ 173690902Sdes int i; 173790902Sdes 173890902Sdes for (i = 0; i < FOPEN_MAX; i++) 173990902Sdes if (files[i].fp) 174090902Sdes fflush(files[i].fp); 174190902Sdes} 174290902Sdes 174385587Sobrienvoid backsub(char **pb_ptr, char **sptr_ptr); 174485587Sobrien 174585587SobrienCell *sub(Node **a, int nnn) /* substitute command */ 174685587Sobrien{ 174785587Sobrien char *sptr, *pb, *q; 174885587Sobrien Cell *x, *y, *result; 174985587Sobrien char *t, *buf; 175085587Sobrien fa *pfa; 175185587Sobrien int bufsz = recsize; 175285587Sobrien 175385587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 175485587Sobrien FATAL("out of memory in sub"); 175585587Sobrien x = execute(a[3]); /* target string */ 175685587Sobrien t = getsval(x); 175785587Sobrien if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 175885587Sobrien pfa = (fa *) a[1]; /* regular expression */ 175985587Sobrien else { 176085587Sobrien y = execute(a[1]); 176185587Sobrien pfa = makedfa(getsval(y), 1); 176285587Sobrien tempfree(y); 176385587Sobrien } 176485587Sobrien y = execute(a[2]); /* replacement string */ 176585587Sobrien result = False; 176685587Sobrien if (pmatch(pfa, t)) { 176785587Sobrien sptr = t; 176885587Sobrien adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub"); 176985587Sobrien pb = buf; 177085587Sobrien while (sptr < patbeg) 177185587Sobrien *pb++ = *sptr++; 177285587Sobrien sptr = getsval(y); 177385587Sobrien while (*sptr != 0) { 177485587Sobrien adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub"); 177585587Sobrien if (*sptr == '\\') { 177685587Sobrien backsub(&pb, &sptr); 177785587Sobrien } else if (*sptr == '&') { 177885587Sobrien sptr++; 177985587Sobrien adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub"); 178085587Sobrien for (q = patbeg; q < patbeg+patlen; ) 178185587Sobrien *pb++ = *q++; 178285587Sobrien } else 178385587Sobrien *pb++ = *sptr++; 178485587Sobrien } 178585587Sobrien *pb = '\0'; 178685587Sobrien if (pb > buf + bufsz) 178785587Sobrien FATAL("sub result1 %.30s too big; can't happen", buf); 178885587Sobrien sptr = patbeg + patlen; 178985587Sobrien if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) { 179085587Sobrien adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub"); 179185587Sobrien while ((*pb++ = *sptr++) != 0) 179285587Sobrien ; 179385587Sobrien } 179485587Sobrien if (pb > buf + bufsz) 179585587Sobrien FATAL("sub result2 %.30s too big; can't happen", buf); 179685587Sobrien setsval(x, buf); /* BUG: should be able to avoid copy */ 179785587Sobrien result = True;; 179885587Sobrien } 179985587Sobrien tempfree(x); 180085587Sobrien tempfree(y); 180185587Sobrien free(buf); 180285587Sobrien return result; 180385587Sobrien} 180485587Sobrien 180585587SobrienCell *gsub(Node **a, int nnn) /* global substitute */ 180685587Sobrien{ 180785587Sobrien Cell *x, *y; 180885587Sobrien char *rptr, *sptr, *t, *pb, *q; 180985587Sobrien char *buf; 181085587Sobrien fa *pfa; 181185587Sobrien int mflag, tempstat, num; 181285587Sobrien int bufsz = recsize; 181385587Sobrien 181485587Sobrien if ((buf = (char *) malloc(bufsz)) == NULL) 181585587Sobrien FATAL("out of memory in gsub"); 181685587Sobrien mflag = 0; /* if mflag == 0, can replace empty string */ 181785587Sobrien num = 0; 181885587Sobrien x = execute(a[3]); /* target string */ 181985587Sobrien t = getsval(x); 182085587Sobrien if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 182185587Sobrien pfa = (fa *) a[1]; /* regular expression */ 182285587Sobrien else { 182385587Sobrien y = execute(a[1]); 182485587Sobrien pfa = makedfa(getsval(y), 1); 182585587Sobrien tempfree(y); 182685587Sobrien } 182785587Sobrien y = execute(a[2]); /* replacement string */ 182885587Sobrien if (pmatch(pfa, t)) { 182985587Sobrien tempstat = pfa->initstat; 183085587Sobrien pfa->initstat = 2; 183185587Sobrien pb = buf; 183285587Sobrien rptr = getsval(y); 183385587Sobrien do { 183485587Sobrien if (patlen == 0 && *patbeg != 0) { /* matched empty string */ 183585587Sobrien if (mflag == 0) { /* can replace empty */ 183685587Sobrien num++; 183785587Sobrien sptr = rptr; 183885587Sobrien while (*sptr != 0) { 183985587Sobrien adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); 184085587Sobrien if (*sptr == '\\') { 184185587Sobrien backsub(&pb, &sptr); 184285587Sobrien } else if (*sptr == '&') { 184385587Sobrien sptr++; 184485587Sobrien adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); 184585587Sobrien for (q = patbeg; q < patbeg+patlen; ) 184685587Sobrien *pb++ = *q++; 184785587Sobrien } else 184885587Sobrien *pb++ = *sptr++; 184985587Sobrien } 185085587Sobrien } 185185587Sobrien if (*t == 0) /* at end */ 185285587Sobrien goto done; 185385587Sobrien adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub"); 185485587Sobrien *pb++ = *t++; 185585587Sobrien if (pb > buf + bufsz) /* BUG: not sure of this test */ 185685587Sobrien FATAL("gsub result0 %.30s too big; can't happen", buf); 185785587Sobrien mflag = 0; 185885587Sobrien } 185985587Sobrien else { /* matched nonempty string */ 186085587Sobrien num++; 186185587Sobrien sptr = t; 186285587Sobrien adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub"); 186385587Sobrien while (sptr < patbeg) 186485587Sobrien *pb++ = *sptr++; 186585587Sobrien sptr = rptr; 186685587Sobrien while (*sptr != 0) { 186785587Sobrien adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub"); 186885587Sobrien if (*sptr == '\\') { 186985587Sobrien backsub(&pb, &sptr); 187085587Sobrien } else if (*sptr == '&') { 187185587Sobrien sptr++; 187285587Sobrien adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub"); 187385587Sobrien for (q = patbeg; q < patbeg+patlen; ) 187485587Sobrien *pb++ = *q++; 187585587Sobrien } else 187685587Sobrien *pb++ = *sptr++; 187785587Sobrien } 187885587Sobrien t = patbeg + patlen; 187985587Sobrien if (patlen == 0 || *t == 0 || *(t-1) == 0) 188085587Sobrien goto done; 188185587Sobrien if (pb > buf + bufsz) 188285587Sobrien FATAL("gsub result1 %.30s too big; can't happen", buf); 188385587Sobrien mflag = 1; 188485587Sobrien } 188585587Sobrien } while (pmatch(pfa,t)); 188685587Sobrien sptr = t; 188785587Sobrien adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); 188885587Sobrien while ((*pb++ = *sptr++) != 0) 188985587Sobrien ; 189085587Sobrien done: if (pb > buf + bufsz) 189185587Sobrien FATAL("gsub result2 %.30s too big; can't happen", buf); 189285587Sobrien *pb = '\0'; 189385587Sobrien setsval(x, buf); /* BUG: should be able to avoid copy + free */ 189485587Sobrien pfa->initstat = tempstat; 189585587Sobrien } 189685587Sobrien tempfree(x); 189785587Sobrien tempfree(y); 189885587Sobrien x = gettemp(); 189985587Sobrien x->tval = NUM; 190085587Sobrien x->fval = num; 190185587Sobrien free(buf); 190285587Sobrien return(x); 190385587Sobrien} 190485587Sobrien 190585587Sobrienvoid backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ 190685587Sobrien{ /* sptr[0] == '\\' */ 190785587Sobrien char *pb = *pb_ptr, *sptr = *sptr_ptr; 190885587Sobrien 190985587Sobrien if (sptr[1] == '\\') { 191085587Sobrien if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ 191185587Sobrien *pb++ = '\\'; 191285587Sobrien *pb++ = '&'; 191385587Sobrien sptr += 4; 191485587Sobrien } else if (sptr[2] == '&') { /* \\& -> \ + matched */ 191585587Sobrien *pb++ = '\\'; 191685587Sobrien sptr += 2; 191785587Sobrien } else { /* \\x -> \\x */ 191885587Sobrien *pb++ = *sptr++; 191985587Sobrien *pb++ = *sptr++; 192085587Sobrien } 192185587Sobrien } else if (sptr[1] == '&') { /* literal & */ 192285587Sobrien sptr++; 192385587Sobrien *pb++ = *sptr++; 192485587Sobrien } else /* literal \ */ 192585587Sobrien *pb++ = *sptr++; 192685587Sobrien 192785587Sobrien *pb_ptr = pb; 192885587Sobrien *sptr_ptr = sptr; 192985587Sobrien} 1930