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