1*65393Sbostic /**************************************************************** 2*65393Sbostic Copyright (C) AT&T 1993 3*65393Sbostic All Rights Reserved 4*65393Sbostic 5*65393Sbostic Permission to use, copy, modify, and distribute this software and 6*65393Sbostic its documentation for any purpose and without fee is hereby 7*65393Sbostic granted, provided that the above copyright notice appear in all 8*65393Sbostic copies and that both that the copyright notice and this 9*65393Sbostic permission notice and warranty disclaimer appear in supporting 10*65393Sbostic documentation, and that the name of AT&T or any of its entities 11*65393Sbostic not be used in advertising or publicity pertaining to 12*65393Sbostic distribution of the software without specific, written prior 13*65393Sbostic permission. 14*65393Sbostic 15*65393Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16*65393Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 17*65393Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 18*65393Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19*65393Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 20*65393Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 21*65393Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 22*65393Sbostic THIS SOFTWARE. 23*65393Sbostic ****************************************************************/ 24*65393Sbostic 25*65393Sbostic #define tempfree(x) if (istemp(x)) tfree(x); else 26*65393Sbostic 27*65393Sbostic #define DEBUG 28*65393Sbostic #include <stdio.h> 29*65393Sbostic #include <ctype.h> 30*65393Sbostic #include <setjmp.h> 31*65393Sbostic #include <math.h> 32*65393Sbostic #include <string.h> 33*65393Sbostic #include <stdlib.h> 34*65393Sbostic #include <time.h> 35*65393Sbostic #include "awk.h" 36*65393Sbostic #include "y.tab.h" 37*65393Sbostic 38*65393Sbostic #ifdef _NFILE 39*65393Sbostic #ifndef FOPEN_MAX 40*65393Sbostic #define FOPEN_MAX _NFILE 41*65393Sbostic #endif 42*65393Sbostic #endif 43*65393Sbostic 44*65393Sbostic #ifndef FOPEN_MAX 45*65393Sbostic #define FOPEN_MAX 40 /* max number of open files */ 46*65393Sbostic #endif 47*65393Sbostic 48*65393Sbostic #ifndef RAND_MAX 49*65393Sbostic #define RAND_MAX 32767 /* all that ansi guarantees */ 50*65393Sbostic #endif 51*65393Sbostic 52*65393Sbostic jmp_buf env; 53*65393Sbostic 54*65393Sbostic /* an attempt to go a bit faster: */ 55*65393Sbostic 56*65393Sbostic /* #define execute(p) (isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */ 57*65393Sbostic #define execute(p) r_execute(p) 58*65393Sbostic #define getfval(p) (((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p)) 59*65393Sbostic #define getsval(p) (((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p)) 60*65393Sbostic 61*65393Sbostic 62*65393Sbostic #define PA2NUM 29 /* max number of pat,pat patterns allowed */ 63*65393Sbostic int paircnt; /* number of them in use */ 64*65393Sbostic int pairstack[PA2NUM]; /* state of each pat,pat */ 65*65393Sbostic 66*65393Sbostic Node *winner = NULL; /* root of parse tree */ 67*65393Sbostic Cell *tmps; /* free temporary cells for execution */ 68*65393Sbostic 69*65393Sbostic static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; 70*65393Sbostic Cell *true = &truecell; 71*65393Sbostic static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; 72*65393Sbostic Cell *false = &falsecell; 73*65393Sbostic static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; 74*65393Sbostic Cell *jbreak = &breakcell; 75*65393Sbostic static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; 76*65393Sbostic Cell *jcont = &contcell; 77*65393Sbostic static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; 78*65393Sbostic Cell *jnext = &nextcell; 79*65393Sbostic static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; 80*65393Sbostic Cell *jexit = &exitcell; 81*65393Sbostic static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; 82*65393Sbostic Cell *jret = &retcell; 83*65393Sbostic static Cell tempcell ={ OCELL, CTEMP, 0, 0, 0.0, NUM }; 84*65393Sbostic 85*65393Sbostic Node *curnode = NULL; /* the node being executed, for debugging */ 86*65393Sbostic 87*65393Sbostic void run(Node *a) /* execution of parse tree starts here */ 88*65393Sbostic { 89*65393Sbostic execute(a); 90*65393Sbostic closeall(); 91*65393Sbostic } 92*65393Sbostic 93*65393Sbostic Cell *r_execute(Node *u) /* execute a node of the parse tree */ 94*65393Sbostic { 95*65393Sbostic register Cell *(*proc)(Node **, int); 96*65393Sbostic register Cell *x; 97*65393Sbostic register Node *a; 98*65393Sbostic 99*65393Sbostic if (u == NULL) 100*65393Sbostic return(true); 101*65393Sbostic for (a = u; ; a = a->nnext) { 102*65393Sbostic curnode = a; 103*65393Sbostic if (isvalue(a)) { 104*65393Sbostic x = (Cell *) (a->narg[0]); 105*65393Sbostic if ((x->tval & FLD) && !donefld) 106*65393Sbostic fldbld(); 107*65393Sbostic else if ((x->tval & REC) && !donerec) 108*65393Sbostic recbld(); 109*65393Sbostic return(x); 110*65393Sbostic } 111*65393Sbostic if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ 112*65393Sbostic ERROR "illegal statement" FATAL; 113*65393Sbostic proc = proctab[a->nobj-FIRSTTOKEN]; 114*65393Sbostic x = (*proc)(a->narg, a->nobj); 115*65393Sbostic if ((x->tval & FLD) && !donefld) 116*65393Sbostic fldbld(); 117*65393Sbostic else if ((x->tval & REC) && !donerec) 118*65393Sbostic recbld(); 119*65393Sbostic if (isexpr(a)) 120*65393Sbostic return(x); 121*65393Sbostic if (isjump(x)) 122*65393Sbostic return(x); 123*65393Sbostic if (a->nnext == NULL) 124*65393Sbostic return(x); 125*65393Sbostic tempfree(x); 126*65393Sbostic } 127*65393Sbostic } 128*65393Sbostic 129*65393Sbostic 130*65393Sbostic Cell *program(Node **a, int n) /* execute an awk program */ 131*65393Sbostic { /* a[0] = BEGIN, a[1] = body, a[2] = END */ 132*65393Sbostic register Cell *x; 133*65393Sbostic 134*65393Sbostic if (setjmp(env) != 0) 135*65393Sbostic goto ex; 136*65393Sbostic if (a[0]) { /* BEGIN */ 137*65393Sbostic x = execute(a[0]); 138*65393Sbostic if (isexit(x)) 139*65393Sbostic return(true); 140*65393Sbostic if (isjump(x)) 141*65393Sbostic ERROR "illegal break, continue or next from BEGIN" FATAL; 142*65393Sbostic tempfree(x); 143*65393Sbostic } 144*65393Sbostic loop: 145*65393Sbostic if (a[1] || a[2]) 146*65393Sbostic while (getrec(record) > 0) { 147*65393Sbostic x = execute(a[1]); 148*65393Sbostic if (isexit(x)) 149*65393Sbostic break; 150*65393Sbostic tempfree(x); 151*65393Sbostic } 152*65393Sbostic ex: 153*65393Sbostic if (setjmp(env) != 0) /* handles exit within END */ 154*65393Sbostic goto ex1; 155*65393Sbostic if (a[2]) { /* END */ 156*65393Sbostic x = execute(a[2]); 157*65393Sbostic if (isbreak(x) || isnext(x) || iscont(x)) 158*65393Sbostic ERROR "illegal break, next, or continue from END" FATAL; 159*65393Sbostic tempfree(x); 160*65393Sbostic } 161*65393Sbostic ex1: 162*65393Sbostic return(true); 163*65393Sbostic } 164*65393Sbostic 165*65393Sbostic struct Frame { /* stack frame for awk function calls */ 166*65393Sbostic int nargs; /* number of arguments in this call */ 167*65393Sbostic Cell *fcncell; /* pointer to Cell for function */ 168*65393Sbostic Cell **args; /* pointer to array of arguments after execute */ 169*65393Sbostic Cell *retval; /* return value */ 170*65393Sbostic }; 171*65393Sbostic 172*65393Sbostic #define NARGS 50 /* max args in a call */ 173*65393Sbostic 174*65393Sbostic struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ 175*65393Sbostic int nframe = 0; /* number of frames allocated */ 176*65393Sbostic struct Frame *fp = NULL; /* frame pointer. bottom level unused */ 177*65393Sbostic 178*65393Sbostic Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ 179*65393Sbostic { 180*65393Sbostic static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE }; 181*65393Sbostic int i, ncall, ndef; 182*65393Sbostic Node *x; 183*65393Sbostic Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn; 184*65393Sbostic uchar *s; 185*65393Sbostic 186*65393Sbostic fcn = execute(a[0]); /* the function itself */ 187*65393Sbostic s = fcn->nval; 188*65393Sbostic if (!isfunc(fcn)) 189*65393Sbostic ERROR "calling undefined function %s", s FATAL; 190*65393Sbostic if (frame == NULL) { 191*65393Sbostic fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); 192*65393Sbostic if (frame == NULL) 193*65393Sbostic ERROR "out of space for stack frames calling %s", s FATAL; 194*65393Sbostic } 195*65393Sbostic for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ 196*65393Sbostic ncall++; 197*65393Sbostic ndef = (int) fcn->fval; /* args in defn */ 198*65393Sbostic dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) ); 199*65393Sbostic if (ncall > ndef) 200*65393Sbostic ERROR "function %s called with %d args, uses only %d", 201*65393Sbostic s, ncall, ndef WARNING; 202*65393Sbostic if (ncall + ndef > NARGS) 203*65393Sbostic ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL; 204*65393Sbostic for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ 205*65393Sbostic dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) ); 206*65393Sbostic y = execute(x); 207*65393Sbostic oargs[i] = y; 208*65393Sbostic dprintf( ("args[%d]: %s %f <%s>, t=%o\n", 209*65393Sbostic i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) ); 210*65393Sbostic if (isfunc(y)) 211*65393Sbostic ERROR "can't use function %s as argument in %s", y->nval, s FATAL; 212*65393Sbostic if (isarr(y)) 213*65393Sbostic args[i] = y; /* arrays by ref */ 214*65393Sbostic else 215*65393Sbostic args[i] = copycell(y); 216*65393Sbostic tempfree(y); 217*65393Sbostic } 218*65393Sbostic for ( ; i < ndef; i++) { /* add null args for ones not provided */ 219*65393Sbostic args[i] = gettemp(); 220*65393Sbostic *args[i] = newcopycell; 221*65393Sbostic } 222*65393Sbostic fp++; /* now ok to up frame */ 223*65393Sbostic if (fp >= frame + nframe) { 224*65393Sbostic int dfp = fp - frame; /* old index */ 225*65393Sbostic frame = (struct Frame *) 226*65393Sbostic realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); 227*65393Sbostic if (frame == NULL) 228*65393Sbostic ERROR "out of space for stack frames in %s", s FATAL; 229*65393Sbostic fp = frame + dfp; 230*65393Sbostic } 231*65393Sbostic fp->fcncell = fcn; 232*65393Sbostic fp->args = args; 233*65393Sbostic fp->nargs = ndef; /* number defined with (excess are locals) */ 234*65393Sbostic fp->retval = gettemp(); 235*65393Sbostic 236*65393Sbostic dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) ); 237*65393Sbostic y = execute((Node *)(fcn->sval)); /* execute body */ 238*65393Sbostic dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) ); 239*65393Sbostic 240*65393Sbostic for (i = 0; i < ndef; i++) { 241*65393Sbostic Cell *t = fp->args[i]; 242*65393Sbostic if (isarr(t)) { 243*65393Sbostic if (t->csub == CCOPY) { 244*65393Sbostic if (i >= ncall) { 245*65393Sbostic freesymtab(t); 246*65393Sbostic t->csub = CTEMP; 247*65393Sbostic } else { 248*65393Sbostic oargs[i]->tval = t->tval; 249*65393Sbostic oargs[i]->tval &= ~(STR|NUM|DONTFREE); 250*65393Sbostic oargs[i]->sval = t->sval; 251*65393Sbostic tempfree(t); 252*65393Sbostic } 253*65393Sbostic } 254*65393Sbostic } else if (t != y) { /* kludge to prevent freeing twice */ 255*65393Sbostic t->csub = CTEMP; 256*65393Sbostic tempfree(t); 257*65393Sbostic } 258*65393Sbostic } 259*65393Sbostic tempfree(fcn); 260*65393Sbostic if (isexit(y) || isnext(y)) 261*65393Sbostic return y; 262*65393Sbostic tempfree(y); /* this can free twice! */ 263*65393Sbostic z = fp->retval; /* return value */ 264*65393Sbostic dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); 265*65393Sbostic fp--; 266*65393Sbostic return(z); 267*65393Sbostic } 268*65393Sbostic 269*65393Sbostic Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ 270*65393Sbostic { 271*65393Sbostic Cell *y; 272*65393Sbostic 273*65393Sbostic y = gettemp(); 274*65393Sbostic y->csub = CCOPY; /* prevents freeing until call is over */ 275*65393Sbostic y->nval = x->nval; 276*65393Sbostic y->sval = x->sval ? tostring(x->sval) : NULL; 277*65393Sbostic y->fval = x->fval; 278*65393Sbostic y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ 279*65393Sbostic /* is DONTFREE right? */ 280*65393Sbostic return y; 281*65393Sbostic } 282*65393Sbostic 283*65393Sbostic Cell *arg(Node **a, int n) /* nth argument of a function */ 284*65393Sbostic { 285*65393Sbostic 286*65393Sbostic n = (int) a[0]; /* argument number, counting from 0 */ 287*65393Sbostic dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); 288*65393Sbostic if (n+1 > fp->nargs) 289*65393Sbostic ERROR "argument #%d of function %s was not supplied", 290*65393Sbostic n+1, fp->fcncell->nval FATAL; 291*65393Sbostic return fp->args[n]; 292*65393Sbostic } 293*65393Sbostic 294*65393Sbostic Cell *jump(Node **a, int n) /* break, continue, next, continue, return */ 295*65393Sbostic { 296*65393Sbostic register Cell *y; 297*65393Sbostic 298*65393Sbostic switch (n) { 299*65393Sbostic case EXIT: 300*65393Sbostic if (a[0] != NULL) { 301*65393Sbostic y = execute(a[0]); 302*65393Sbostic errorflag = getfval(y); 303*65393Sbostic tempfree(y); 304*65393Sbostic } 305*65393Sbostic longjmp(env, 1); 306*65393Sbostic case RETURN: 307*65393Sbostic if (a[0] != NULL) { 308*65393Sbostic y = execute(a[0]); 309*65393Sbostic if ((y->tval & (STR|NUM)) == (STR|NUM)) { 310*65393Sbostic setsval(fp->retval, getsval(y)); 311*65393Sbostic fp->retval->fval = getfval(y); 312*65393Sbostic fp->retval->tval |= NUM; 313*65393Sbostic } 314*65393Sbostic else if (y->tval & STR) 315*65393Sbostic setsval(fp->retval, getsval(y)); 316*65393Sbostic else if (y->tval & NUM) 317*65393Sbostic setfval(fp->retval, getfval(y)); 318*65393Sbostic else /* can't happen */ 319*65393Sbostic ERROR "bad type variable %d", y->tval FATAL; 320*65393Sbostic tempfree(y); 321*65393Sbostic } 322*65393Sbostic return(jret); 323*65393Sbostic case NEXT: 324*65393Sbostic return(jnext); 325*65393Sbostic case BREAK: 326*65393Sbostic return(jbreak); 327*65393Sbostic case CONTINUE: 328*65393Sbostic return(jcont); 329*65393Sbostic default: /* can't happen */ 330*65393Sbostic ERROR "illegal jump type %d", n FATAL; 331*65393Sbostic } 332*65393Sbostic return 0; /* not reached */ 333*65393Sbostic } 334*65393Sbostic 335*65393Sbostic Cell *getline(Node **a, int n) /* get next line from specific input */ 336*65393Sbostic { /* a[0] is variable, a[1] is operator, a[2] is filename */ 337*65393Sbostic register Cell *r, *x; 338*65393Sbostic uchar buf[RECSIZE]; 339*65393Sbostic FILE *fp; 340*65393Sbostic 341*65393Sbostic fflush(stdout); /* in case someone is waiting for a prompt */ 342*65393Sbostic r = gettemp(); 343*65393Sbostic if (a[1] != NULL) { /* getline < file */ 344*65393Sbostic x = execute(a[2]); /* filename */ 345*65393Sbostic if ((int) a[1] == '|') /* input pipe */ 346*65393Sbostic a[1] = (Node *) LE; /* arbitrary flag */ 347*65393Sbostic fp = openfile((int) a[1], getsval(x)); 348*65393Sbostic tempfree(x); 349*65393Sbostic if (fp == NULL) 350*65393Sbostic n = -1; 351*65393Sbostic else 352*65393Sbostic n = readrec(buf, sizeof(buf), fp); 353*65393Sbostic if (n <= 0) { 354*65393Sbostic ; 355*65393Sbostic } else if (a[0] != NULL) { /* getline var <file */ 356*65393Sbostic setsval(execute(a[0]), buf); 357*65393Sbostic } else { /* getline <file */ 358*65393Sbostic if (!(recloc->tval & DONTFREE)) 359*65393Sbostic xfree(recloc->sval); 360*65393Sbostic strcpy(record, buf); 361*65393Sbostic recloc->sval = record; 362*65393Sbostic recloc->tval = REC | STR | DONTFREE; 363*65393Sbostic if (isnumber(recloc->sval)) { 364*65393Sbostic recloc->fval = atof(recloc->sval); 365*65393Sbostic recloc->tval |= NUM; 366*65393Sbostic } 367*65393Sbostic donerec = 1; donefld = 0; 368*65393Sbostic } 369*65393Sbostic } else { /* bare getline; use current input */ 370*65393Sbostic if (a[0] == NULL) /* getline */ 371*65393Sbostic n = getrec(record); 372*65393Sbostic else { /* getline var */ 373*65393Sbostic n = getrec(buf); 374*65393Sbostic setsval(execute(a[0]), buf); 375*65393Sbostic } 376*65393Sbostic } 377*65393Sbostic setfval(r, (Awkfloat) n); 378*65393Sbostic return r; 379*65393Sbostic } 380*65393Sbostic 381*65393Sbostic Cell *getnf(Node **a, int n) /* get NF */ 382*65393Sbostic { 383*65393Sbostic if (donefld == 0) 384*65393Sbostic fldbld(); 385*65393Sbostic return (Cell *) a[0]; 386*65393Sbostic } 387*65393Sbostic 388*65393Sbostic Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 389*65393Sbostic { 390*65393Sbostic register Cell *x, *y, *z; 391*65393Sbostic register uchar *s; 392*65393Sbostic register Node *np; 393*65393Sbostic uchar buf[RECSIZE]; 394*65393Sbostic 395*65393Sbostic x = execute(a[0]); /* Cell* for symbol table */ 396*65393Sbostic buf[0] = 0; 397*65393Sbostic for (np = a[1]; np; np = np->nnext) { 398*65393Sbostic y = execute(np); /* subscript */ 399*65393Sbostic s = getsval(y); 400*65393Sbostic strcat(buf, s); 401*65393Sbostic if (np->nnext) 402*65393Sbostic strcat(buf, *SUBSEP); 403*65393Sbostic tempfree(y); 404*65393Sbostic } 405*65393Sbostic if (!isarr(x)) { 406*65393Sbostic dprintf( ("making %s into an array\n", x->nval) ); 407*65393Sbostic if (freeable(x)) 408*65393Sbostic xfree(x->sval); 409*65393Sbostic x->tval &= ~(STR|NUM|DONTFREE); 410*65393Sbostic x->tval |= ARR; 411*65393Sbostic x->sval = (uchar *) makesymtab(NSYMTAB); 412*65393Sbostic } 413*65393Sbostic z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval); 414*65393Sbostic z->ctype = OCELL; 415*65393Sbostic z->csub = CVAR; 416*65393Sbostic tempfree(x); 417*65393Sbostic return(z); 418*65393Sbostic } 419*65393Sbostic 420*65393Sbostic Cell *adelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */ 421*65393Sbostic { 422*65393Sbostic Cell *x, *y; 423*65393Sbostic Node *np; 424*65393Sbostic uchar buf[RECSIZE], *s; 425*65393Sbostic 426*65393Sbostic x = execute(a[0]); /* Cell* for symbol table */ 427*65393Sbostic if (!isarr(x)) 428*65393Sbostic return true; 429*65393Sbostic buf[0] = 0; 430*65393Sbostic for (np = a[1]; np; np = np->nnext) { 431*65393Sbostic y = execute(np); /* subscript */ 432*65393Sbostic s = getsval(y); 433*65393Sbostic strcat(buf, s); 434*65393Sbostic if (np->nnext) 435*65393Sbostic strcat(buf, *SUBSEP); 436*65393Sbostic tempfree(y); 437*65393Sbostic } 438*65393Sbostic freeelem(x, buf); 439*65393Sbostic tempfree(x); 440*65393Sbostic return true; 441*65393Sbostic } 442*65393Sbostic 443*65393Sbostic Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ 444*65393Sbostic { 445*65393Sbostic register Cell *x, *ap, *k; 446*65393Sbostic Node *p; 447*65393Sbostic char buf[RECSIZE]; 448*65393Sbostic uchar *s; 449*65393Sbostic 450*65393Sbostic ap = execute(a[1]); /* array name */ 451*65393Sbostic if (!isarr(ap)) { 452*65393Sbostic dprintf( ("making %s into an array\n", ap->nval) ); 453*65393Sbostic if (freeable(ap)) 454*65393Sbostic xfree(ap->sval); 455*65393Sbostic ap->tval &= ~(STR|NUM|DONTFREE); 456*65393Sbostic ap->tval |= ARR; 457*65393Sbostic ap->sval = (uchar *) makesymtab(NSYMTAB); 458*65393Sbostic } 459*65393Sbostic buf[0] = 0; 460*65393Sbostic for (p = a[0]; p; p = p->nnext) { 461*65393Sbostic x = execute(p); /* expr */ 462*65393Sbostic s = getsval(x); 463*65393Sbostic strcat(buf, s); 464*65393Sbostic tempfree(x); 465*65393Sbostic if (p->nnext) 466*65393Sbostic strcat(buf, *SUBSEP); 467*65393Sbostic } 468*65393Sbostic k = lookup(buf, (Array *) ap->sval); 469*65393Sbostic tempfree(ap); 470*65393Sbostic if (k == NULL) 471*65393Sbostic return(false); 472*65393Sbostic else 473*65393Sbostic return(true); 474*65393Sbostic } 475*65393Sbostic 476*65393Sbostic 477*65393Sbostic Cell *matchop(Node **a, int n) /* ~ and match() */ 478*65393Sbostic { 479*65393Sbostic register Cell *x, *y; 480*65393Sbostic register uchar *s, *t; 481*65393Sbostic register int i; 482*65393Sbostic fa *pfa; 483*65393Sbostic int (*mf)(fa *, uchar *) = match, mode = 0; 484*65393Sbostic 485*65393Sbostic if (n == MATCHFCN) { 486*65393Sbostic mf = pmatch; 487*65393Sbostic mode = 1; 488*65393Sbostic } 489*65393Sbostic x = execute(a[1]); /* a[1] = target text */ 490*65393Sbostic s = getsval(x); 491*65393Sbostic if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */ 492*65393Sbostic i = (*mf)((fa *) a[2], s); 493*65393Sbostic else { 494*65393Sbostic y = execute(a[2]); /* a[2] = regular expr */ 495*65393Sbostic t = getsval(y); 496*65393Sbostic pfa = makedfa(t, mode); 497*65393Sbostic i = (*mf)(pfa, s); 498*65393Sbostic tempfree(y); 499*65393Sbostic } 500*65393Sbostic tempfree(x); 501*65393Sbostic if (n == MATCHFCN) { 502*65393Sbostic int start = patbeg - s + 1; 503*65393Sbostic if (patlen < 0) 504*65393Sbostic start = 0; 505*65393Sbostic setfval(rstartloc, (Awkfloat) start); 506*65393Sbostic setfval(rlengthloc, (Awkfloat) patlen); 507*65393Sbostic x = gettemp(); 508*65393Sbostic x->tval = NUM; 509*65393Sbostic x->fval = start; 510*65393Sbostic return x; 511*65393Sbostic } else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0) 512*65393Sbostic return(true); 513*65393Sbostic else 514*65393Sbostic return(false); 515*65393Sbostic } 516*65393Sbostic 517*65393Sbostic 518*65393Sbostic Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */ 519*65393Sbostic { 520*65393Sbostic register Cell *x, *y; 521*65393Sbostic register int i; 522*65393Sbostic 523*65393Sbostic x = execute(a[0]); 524*65393Sbostic i = istrue(x); 525*65393Sbostic tempfree(x); 526*65393Sbostic switch (n) { 527*65393Sbostic case BOR: 528*65393Sbostic if (i) return(true); 529*65393Sbostic y = execute(a[1]); 530*65393Sbostic i = istrue(y); 531*65393Sbostic tempfree(y); 532*65393Sbostic if (i) return(true); 533*65393Sbostic else return(false); 534*65393Sbostic case AND: 535*65393Sbostic if ( !i ) return(false); 536*65393Sbostic y = execute(a[1]); 537*65393Sbostic i = istrue(y); 538*65393Sbostic tempfree(y); 539*65393Sbostic if (i) return(true); 540*65393Sbostic else return(false); 541*65393Sbostic case NOT: 542*65393Sbostic if (i) return(false); 543*65393Sbostic else return(true); 544*65393Sbostic default: /* can't happen */ 545*65393Sbostic ERROR "unknown boolean operator %d", n FATAL; 546*65393Sbostic } 547*65393Sbostic return 0; /*NOTREACHED*/ 548*65393Sbostic } 549*65393Sbostic 550*65393Sbostic Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */ 551*65393Sbostic { 552*65393Sbostic register int i; 553*65393Sbostic register Cell *x, *y; 554*65393Sbostic Awkfloat j; 555*65393Sbostic 556*65393Sbostic x = execute(a[0]); 557*65393Sbostic y = execute(a[1]); 558*65393Sbostic if (x->tval&NUM && y->tval&NUM) { 559*65393Sbostic j = x->fval - y->fval; 560*65393Sbostic i = j<0? -1: (j>0? 1: 0); 561*65393Sbostic } else { 562*65393Sbostic i = strcmp(getsval(x), getsval(y)); 563*65393Sbostic } 564*65393Sbostic tempfree(x); 565*65393Sbostic tempfree(y); 566*65393Sbostic switch (n) { 567*65393Sbostic case LT: if (i<0) return(true); 568*65393Sbostic else return(false); 569*65393Sbostic case LE: if (i<=0) return(true); 570*65393Sbostic else return(false); 571*65393Sbostic case NE: if (i!=0) return(true); 572*65393Sbostic else return(false); 573*65393Sbostic case EQ: if (i == 0) return(true); 574*65393Sbostic else return(false); 575*65393Sbostic case GE: if (i>=0) return(true); 576*65393Sbostic else return(false); 577*65393Sbostic case GT: if (i>0) return(true); 578*65393Sbostic else return(false); 579*65393Sbostic default: /* can't happen */ 580*65393Sbostic ERROR "unknown relational operator %d", n FATAL; 581*65393Sbostic } 582*65393Sbostic return 0; /*NOTREACHED*/ 583*65393Sbostic } 584*65393Sbostic 585*65393Sbostic void tfree(Cell *a) /* free a tempcell */ 586*65393Sbostic { 587*65393Sbostic if (freeable(a)) 588*65393Sbostic xfree(a->sval); 589*65393Sbostic if (a == tmps) 590*65393Sbostic ERROR "tempcell list is curdled" FATAL; 591*65393Sbostic a->cnext = tmps; 592*65393Sbostic tmps = a; 593*65393Sbostic } 594*65393Sbostic 595*65393Sbostic Cell *gettemp(void) /* get a tempcell */ 596*65393Sbostic { int i; 597*65393Sbostic register Cell *x; 598*65393Sbostic 599*65393Sbostic if (!tmps) { 600*65393Sbostic tmps = (Cell *) calloc(100, sizeof(Cell)); 601*65393Sbostic if (!tmps) 602*65393Sbostic ERROR "out of space for temporaries" FATAL; 603*65393Sbostic for(i = 1; i < 100; i++) 604*65393Sbostic tmps[i-1].cnext = &tmps[i]; 605*65393Sbostic tmps[i-1].cnext = 0; 606*65393Sbostic } 607*65393Sbostic x = tmps; 608*65393Sbostic tmps = x->cnext; 609*65393Sbostic *x = tempcell; 610*65393Sbostic return(x); 611*65393Sbostic } 612*65393Sbostic 613*65393Sbostic Cell *indirect(Node **a, int n) /* $( a[0] ) */ 614*65393Sbostic { 615*65393Sbostic register Cell *x; 616*65393Sbostic register int m; 617*65393Sbostic register uchar *s; 618*65393Sbostic 619*65393Sbostic x = execute(a[0]); 620*65393Sbostic m = getfval(x); 621*65393Sbostic if (m == 0 && !isnumber(s = getsval(x))) /* suspicion! */ 622*65393Sbostic ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL; 623*65393Sbostic /* can x->nval ever be null??? */ 624*65393Sbostic /* ERROR "illegal field $(%s)", s FATAL; */ 625*65393Sbostic tempfree(x); 626*65393Sbostic x = fieldadr(m); 627*65393Sbostic x->ctype = OCELL; 628*65393Sbostic x->csub = CFLD; 629*65393Sbostic return(x); 630*65393Sbostic } 631*65393Sbostic 632*65393Sbostic Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */ 633*65393Sbostic { 634*65393Sbostic register int k, m, n; 635*65393Sbostic register uchar *s; 636*65393Sbostic int temp; 637*65393Sbostic register Cell *x, *y, *z; 638*65393Sbostic 639*65393Sbostic x = execute(a[0]); 640*65393Sbostic y = execute(a[1]); 641*65393Sbostic if (a[2] != 0) 642*65393Sbostic z = execute(a[2]); 643*65393Sbostic s = getsval(x); 644*65393Sbostic k = strlen(s) + 1; 645*65393Sbostic if (k <= 1) { 646*65393Sbostic tempfree(x); 647*65393Sbostic tempfree(y); 648*65393Sbostic if (a[2] != 0) 649*65393Sbostic tempfree(z); 650*65393Sbostic x = gettemp(); 651*65393Sbostic setsval(x, ""); 652*65393Sbostic return(x); 653*65393Sbostic } 654*65393Sbostic m = getfval(y); 655*65393Sbostic if (m <= 0) 656*65393Sbostic m = 1; 657*65393Sbostic else if (m > k) 658*65393Sbostic m = k; 659*65393Sbostic tempfree(y); 660*65393Sbostic if (a[2] != 0) { 661*65393Sbostic n = getfval(z); 662*65393Sbostic tempfree(z); 663*65393Sbostic } else 664*65393Sbostic n = k - 1; 665*65393Sbostic if (n < 0) 666*65393Sbostic n = 0; 667*65393Sbostic else if (n > k - m) 668*65393Sbostic n = k - m; 669*65393Sbostic dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) ); 670*65393Sbostic y = gettemp(); 671*65393Sbostic temp = s[n+m-1]; /* with thanks to John Linderman */ 672*65393Sbostic s[n+m-1] = '\0'; 673*65393Sbostic setsval(y, s + m - 1); 674*65393Sbostic s[n+m-1] = temp; 675*65393Sbostic tempfree(x); 676*65393Sbostic return(y); 677*65393Sbostic } 678*65393Sbostic 679*65393Sbostic Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ 680*65393Sbostic { 681*65393Sbostic register Cell *x, *y, *z; 682*65393Sbostic register uchar *s1, *s2, *p1, *p2, *q; 683*65393Sbostic Awkfloat v = 0.0; 684*65393Sbostic 685*65393Sbostic x = execute(a[0]); 686*65393Sbostic s1 = getsval(x); 687*65393Sbostic y = execute(a[1]); 688*65393Sbostic s2 = getsval(y); 689*65393Sbostic 690*65393Sbostic z = gettemp(); 691*65393Sbostic for (p1 = s1; *p1 != '\0'; p1++) { 692*65393Sbostic for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++) 693*65393Sbostic ; 694*65393Sbostic if (*p2 == '\0') { 695*65393Sbostic v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */ 696*65393Sbostic break; 697*65393Sbostic } 698*65393Sbostic } 699*65393Sbostic tempfree(x); 700*65393Sbostic tempfree(y); 701*65393Sbostic setfval(z, v); 702*65393Sbostic return(z); 703*65393Sbostic } 704*65393Sbostic 705*65393Sbostic format(uchar *buf, int bufsize, uchar *s, Node *a) /* printf-like conversions */ 706*65393Sbostic { 707*65393Sbostic uchar fmt[RECSIZE]; 708*65393Sbostic register uchar *p, *t, *os; 709*65393Sbostic register Cell *x; 710*65393Sbostic int flag = 0, n; 711*65393Sbostic 712*65393Sbostic os = s; 713*65393Sbostic p = buf; 714*65393Sbostic while (*s) { 715*65393Sbostic if (p - buf >= bufsize) 716*65393Sbostic return -1; 717*65393Sbostic if (*s != '%') { 718*65393Sbostic *p++ = *s++; 719*65393Sbostic continue; 720*65393Sbostic } 721*65393Sbostic if (*(s+1) == '%') { 722*65393Sbostic *p++ = '%'; 723*65393Sbostic s += 2; 724*65393Sbostic continue; 725*65393Sbostic } 726*65393Sbostic for (t=fmt; (*t++ = *s) != '\0'; s++) { 727*65393Sbostic if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L') 728*65393Sbostic break; /* the ansi panoply */ 729*65393Sbostic if (*s == '*') { 730*65393Sbostic x = execute(a); 731*65393Sbostic a = a->nnext; 732*65393Sbostic sprintf((char *)t-1, "%d", (int) getfval(x)); 733*65393Sbostic t = fmt + strlen(fmt); 734*65393Sbostic tempfree(x); 735*65393Sbostic } 736*65393Sbostic } 737*65393Sbostic *t = '\0'; 738*65393Sbostic if (t >= fmt + sizeof(fmt)) 739*65393Sbostic ERROR "format item %.30s... too long", os FATAL; 740*65393Sbostic switch (*s) { 741*65393Sbostic case 'f': case 'e': case 'g': case 'E': case 'G': 742*65393Sbostic flag = 1; 743*65393Sbostic break; 744*65393Sbostic case 'd': case 'i': 745*65393Sbostic flag = 2; 746*65393Sbostic if(*(s-1) == 'l') break; 747*65393Sbostic *(t-1) = 'l'; 748*65393Sbostic *t = 'd'; 749*65393Sbostic *++t = '\0'; 750*65393Sbostic break; 751*65393Sbostic case 'o': case 'x': case 'X': case 'u': 752*65393Sbostic flag = *(s-1) == 'l' ? 2 : 3; 753*65393Sbostic break; 754*65393Sbostic case 's': 755*65393Sbostic flag = 4; 756*65393Sbostic break; 757*65393Sbostic case 'c': 758*65393Sbostic flag = 5; 759*65393Sbostic break; 760*65393Sbostic default: 761*65393Sbostic ERROR "weird printf conversion %s", fmt WARNING; 762*65393Sbostic flag = 0; 763*65393Sbostic break; 764*65393Sbostic } 765*65393Sbostic if (a == NULL) 766*65393Sbostic ERROR "not enough args in printf(%s)", os FATAL; 767*65393Sbostic x = execute(a); 768*65393Sbostic a = a->nnext; 769*65393Sbostic switch (flag) { 770*65393Sbostic case 0: sprintf((char *)p, "%s", fmt); /* unknown, so dump it too */ 771*65393Sbostic p += strlen(p); 772*65393Sbostic sprintf((char *)p, "%s", getsval(x)); 773*65393Sbostic break; 774*65393Sbostic case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break; 775*65393Sbostic case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break; 776*65393Sbostic case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break; 777*65393Sbostic case 4: 778*65393Sbostic t = getsval(x); 779*65393Sbostic n = strlen(t); 780*65393Sbostic if (n >= bufsize) 781*65393Sbostic ERROR "huge string (%d chars) in printf %.30s...", 782*65393Sbostic n, t FATAL; 783*65393Sbostic sprintf((char *)p, (char *)fmt, t); 784*65393Sbostic break; 785*65393Sbostic case 5: 786*65393Sbostic isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x)) 787*65393Sbostic : sprintf((char *)p, (char *)fmt, getsval(x)[0]); 788*65393Sbostic break; 789*65393Sbostic } 790*65393Sbostic tempfree(x); 791*65393Sbostic p += strlen(p); 792*65393Sbostic s++; 793*65393Sbostic } 794*65393Sbostic *p = '\0'; 795*65393Sbostic for ( ; a; a = a->nnext) /* evaluate any remaining args */ 796*65393Sbostic execute(a); 797*65393Sbostic return 0; 798*65393Sbostic } 799*65393Sbostic 800*65393Sbostic Cell *asprintf(Node **a, int n) /* sprintf(a[0]) */ 801*65393Sbostic { 802*65393Sbostic register Cell *x; 803*65393Sbostic register Node *y; 804*65393Sbostic uchar buf[3*RECSIZE]; 805*65393Sbostic 806*65393Sbostic y = a[0]->nnext; 807*65393Sbostic x = execute(a[0]); 808*65393Sbostic if (format(buf, sizeof buf, getsval(x), y) == -1) 809*65393Sbostic ERROR "sprintf string %.30s... too long", buf FATAL; 810*65393Sbostic tempfree(x); 811*65393Sbostic x = gettemp(); 812*65393Sbostic x->sval = tostring(buf); 813*65393Sbostic x->tval = STR; 814*65393Sbostic return(x); 815*65393Sbostic } 816*65393Sbostic 817*65393Sbostic Cell *aprintf(Node **a, int n) /* printf */ 818*65393Sbostic { /* a[0] is list of args, starting with format string */ 819*65393Sbostic /* a[1] is redirection operator, a[2] is redirection file */ 820*65393Sbostic FILE *fp; 821*65393Sbostic register Cell *x; 822*65393Sbostic register Node *y; 823*65393Sbostic uchar buf[3*RECSIZE]; 824*65393Sbostic 825*65393Sbostic y = a[0]->nnext; 826*65393Sbostic x = execute(a[0]); 827*65393Sbostic if (format(buf, sizeof buf, getsval(x), y) == -1) 828*65393Sbostic ERROR "printf string %.30s... too long", buf FATAL; 829*65393Sbostic tempfree(x); 830*65393Sbostic if (a[1] == NULL) { 831*65393Sbostic fputs((char *)buf, stdout); 832*65393Sbostic if (ferror(stdout)) 833*65393Sbostic ERROR "write error on stdout" FATAL; 834*65393Sbostic } else { 835*65393Sbostic fp = redirect((int)a[1], a[2]); 836*65393Sbostic fputs((char *)buf, fp); 837*65393Sbostic fflush(fp); 838*65393Sbostic if (ferror(fp)) 839*65393Sbostic ERROR "write error on %s", filename(fp) FATAL; 840*65393Sbostic } 841*65393Sbostic return(true); 842*65393Sbostic } 843*65393Sbostic 844*65393Sbostic Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ 845*65393Sbostic { 846*65393Sbostic Awkfloat i, j; 847*65393Sbostic double v; 848*65393Sbostic register Cell *x, *y, *z; 849*65393Sbostic 850*65393Sbostic x = execute(a[0]); 851*65393Sbostic i = getfval(x); 852*65393Sbostic tempfree(x); 853*65393Sbostic if (n != UMINUS) { 854*65393Sbostic y = execute(a[1]); 855*65393Sbostic j = getfval(y); 856*65393Sbostic tempfree(y); 857*65393Sbostic } 858*65393Sbostic z = gettemp(); 859*65393Sbostic switch (n) { 860*65393Sbostic case ADD: 861*65393Sbostic i += j; 862*65393Sbostic break; 863*65393Sbostic case MINUS: 864*65393Sbostic i -= j; 865*65393Sbostic break; 866*65393Sbostic case MULT: 867*65393Sbostic i *= j; 868*65393Sbostic break; 869*65393Sbostic case DIVIDE: 870*65393Sbostic if (j == 0) 871*65393Sbostic ERROR "division by zero" FATAL; 872*65393Sbostic i /= j; 873*65393Sbostic break; 874*65393Sbostic case MOD: 875*65393Sbostic if (j == 0) 876*65393Sbostic ERROR "division by zero in mod" FATAL; 877*65393Sbostic modf(i/j, &v); 878*65393Sbostic i = i - j * v; 879*65393Sbostic break; 880*65393Sbostic case UMINUS: 881*65393Sbostic i = -i; 882*65393Sbostic break; 883*65393Sbostic case POWER: 884*65393Sbostic if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ 885*65393Sbostic i = ipow(i, (int) j); 886*65393Sbostic else 887*65393Sbostic i = errcheck(pow(i, j), "pow"); 888*65393Sbostic break; 889*65393Sbostic default: /* can't happen */ 890*65393Sbostic ERROR "illegal arithmetic operator %d", n FATAL; 891*65393Sbostic } 892*65393Sbostic setfval(z, i); 893*65393Sbostic return(z); 894*65393Sbostic } 895*65393Sbostic 896*65393Sbostic double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */ 897*65393Sbostic { 898*65393Sbostic double v; 899*65393Sbostic 900*65393Sbostic if (n <= 0) 901*65393Sbostic return 1; 902*65393Sbostic v = ipow(x, n/2); 903*65393Sbostic if (n % 2 == 0) 904*65393Sbostic return v * v; 905*65393Sbostic else 906*65393Sbostic return x * v * v; 907*65393Sbostic } 908*65393Sbostic 909*65393Sbostic Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */ 910*65393Sbostic { 911*65393Sbostic register Cell *x, *z; 912*65393Sbostic register int k; 913*65393Sbostic Awkfloat xf; 914*65393Sbostic 915*65393Sbostic x = execute(a[0]); 916*65393Sbostic xf = getfval(x); 917*65393Sbostic k = (n == PREINCR || n == POSTINCR) ? 1 : -1; 918*65393Sbostic if (n == PREINCR || n == PREDECR) { 919*65393Sbostic setfval(x, xf + k); 920*65393Sbostic return(x); 921*65393Sbostic } 922*65393Sbostic z = gettemp(); 923*65393Sbostic setfval(z, xf); 924*65393Sbostic setfval(x, xf + k); 925*65393Sbostic tempfree(x); 926*65393Sbostic return(z); 927*65393Sbostic } 928*65393Sbostic 929*65393Sbostic Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ 930*65393Sbostic { /* this is subtle; don't muck with it. */ 931*65393Sbostic register Cell *x, *y; 932*65393Sbostic Awkfloat xf, yf; 933*65393Sbostic double v; 934*65393Sbostic 935*65393Sbostic y = execute(a[1]); 936*65393Sbostic x = execute(a[0]); 937*65393Sbostic if (n == ASSIGN) { /* ordinary assignment */ 938*65393Sbostic if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */ 939*65393Sbostic ; /* leave alone unless it's a field */ 940*65393Sbostic else if ((y->tval & (STR|NUM)) == (STR|NUM)) { 941*65393Sbostic setsval(x, getsval(y)); 942*65393Sbostic x->fval = getfval(y); 943*65393Sbostic x->tval |= NUM; 944*65393Sbostic } 945*65393Sbostic else if (y->tval & STR) 946*65393Sbostic setsval(x, getsval(y)); 947*65393Sbostic else if (y->tval & NUM) 948*65393Sbostic setfval(x, getfval(y)); 949*65393Sbostic else 950*65393Sbostic funnyvar(y, "read value of"); 951*65393Sbostic tempfree(y); 952*65393Sbostic return(x); 953*65393Sbostic } 954*65393Sbostic xf = getfval(x); 955*65393Sbostic yf = getfval(y); 956*65393Sbostic switch (n) { 957*65393Sbostic case ADDEQ: 958*65393Sbostic xf += yf; 959*65393Sbostic break; 960*65393Sbostic case SUBEQ: 961*65393Sbostic xf -= yf; 962*65393Sbostic break; 963*65393Sbostic case MULTEQ: 964*65393Sbostic xf *= yf; 965*65393Sbostic break; 966*65393Sbostic case DIVEQ: 967*65393Sbostic if (yf == 0) 968*65393Sbostic ERROR "division by zero in /=" FATAL; 969*65393Sbostic xf /= yf; 970*65393Sbostic break; 971*65393Sbostic case MODEQ: 972*65393Sbostic if (yf == 0) 973*65393Sbostic ERROR "division by zero in %%=" FATAL; 974*65393Sbostic modf(xf/yf, &v); 975*65393Sbostic xf = xf - yf * v; 976*65393Sbostic break; 977*65393Sbostic case POWEQ: 978*65393Sbostic if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */ 979*65393Sbostic xf = ipow(xf, (int) yf); 980*65393Sbostic else 981*65393Sbostic xf = errcheck(pow(xf, yf), "pow"); 982*65393Sbostic break; 983*65393Sbostic default: 984*65393Sbostic ERROR "illegal assignment operator %d", n FATAL; 985*65393Sbostic break; 986*65393Sbostic } 987*65393Sbostic tempfree(y); 988*65393Sbostic setfval(x, xf); 989*65393Sbostic return(x); 990*65393Sbostic } 991*65393Sbostic 992*65393Sbostic Cell *cat(Node **a, int q) /* a[0] cat a[1] */ 993*65393Sbostic { 994*65393Sbostic register Cell *x, *y, *z; 995*65393Sbostic register int n1, n2; 996*65393Sbostic register uchar *s; 997*65393Sbostic 998*65393Sbostic x = execute(a[0]); 999*65393Sbostic y = execute(a[1]); 1000*65393Sbostic getsval(x); 1001*65393Sbostic getsval(y); 1002*65393Sbostic n1 = strlen(x->sval); 1003*65393Sbostic n2 = strlen(y->sval); 1004*65393Sbostic s = (uchar *) malloc(n1 + n2 + 1); 1005*65393Sbostic if (s == NULL) 1006*65393Sbostic ERROR "out of space concatenating %.15s... and %.15s...", 1007*65393Sbostic x->sval, y->sval FATAL; 1008*65393Sbostic strcpy(s, x->sval); 1009*65393Sbostic strcpy(s+n1, y->sval); 1010*65393Sbostic tempfree(y); 1011*65393Sbostic z = gettemp(); 1012*65393Sbostic z->sval = s; 1013*65393Sbostic z->tval = STR; 1014*65393Sbostic tempfree(x); 1015*65393Sbostic return(z); 1016*65393Sbostic } 1017*65393Sbostic 1018*65393Sbostic Cell *pastat(Node **a, int n) /* a[0] { a[1] } */ 1019*65393Sbostic { 1020*65393Sbostic register Cell *x; 1021*65393Sbostic 1022*65393Sbostic if (a[0] == 0) 1023*65393Sbostic x = execute(a[1]); 1024*65393Sbostic else { 1025*65393Sbostic x = execute(a[0]); 1026*65393Sbostic if (istrue(x)) { 1027*65393Sbostic tempfree(x); 1028*65393Sbostic x = execute(a[1]); 1029*65393Sbostic } 1030*65393Sbostic } 1031*65393Sbostic return x; 1032*65393Sbostic } 1033*65393Sbostic 1034*65393Sbostic Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ 1035*65393Sbostic { 1036*65393Sbostic register Cell *x; 1037*65393Sbostic register int pair; 1038*65393Sbostic 1039*65393Sbostic pair = (int) a[3]; 1040*65393Sbostic if (pairstack[pair] == 0) { 1041*65393Sbostic x = execute(a[0]); 1042*65393Sbostic if (istrue(x)) 1043*65393Sbostic pairstack[pair] = 1; 1044*65393Sbostic tempfree(x); 1045*65393Sbostic } 1046*65393Sbostic if (pairstack[pair] == 1) { 1047*65393Sbostic x = execute(a[1]); 1048*65393Sbostic if (istrue(x)) 1049*65393Sbostic pairstack[pair] = 0; 1050*65393Sbostic tempfree(x); 1051*65393Sbostic x = execute(a[2]); 1052*65393Sbostic return(x); 1053*65393Sbostic } 1054*65393Sbostic return(false); 1055*65393Sbostic } 1056*65393Sbostic 1057*65393Sbostic Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ 1058*65393Sbostic { 1059*65393Sbostic Cell *x, *y, *ap; 1060*65393Sbostic register uchar *s; 1061*65393Sbostic register int sep; 1062*65393Sbostic uchar *t, temp, num[10], *fs; 1063*65393Sbostic int n, tempstat; 1064*65393Sbostic 1065*65393Sbostic y = execute(a[0]); /* source string */ 1066*65393Sbostic s = getsval(y); 1067*65393Sbostic if (a[2] == 0) /* fs string */ 1068*65393Sbostic fs = *FS; 1069*65393Sbostic else if ((int) a[3] == STRING) { /* split(str,arr,"string") */ 1070*65393Sbostic x = execute(a[2]); 1071*65393Sbostic fs = getsval(x); 1072*65393Sbostic } else if ((int) a[3] == REGEXPR) 1073*65393Sbostic fs = (uchar*) "(regexpr)"; /* split(str,arr,/regexpr/) */ 1074*65393Sbostic else 1075*65393Sbostic ERROR "illegal type of split()" FATAL; 1076*65393Sbostic sep = *fs; 1077*65393Sbostic ap = execute(a[1]); /* array name */ 1078*65393Sbostic freesymtab(ap); 1079*65393Sbostic dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) ); 1080*65393Sbostic ap->tval &= ~STR; 1081*65393Sbostic ap->tval |= ARR; 1082*65393Sbostic ap->sval = (uchar *) makesymtab(NSYMTAB); 1083*65393Sbostic 1084*65393Sbostic n = 0; 1085*65393Sbostic if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) { /* reg expr */ 1086*65393Sbostic fa *pfa; 1087*65393Sbostic if ((int) a[3] == REGEXPR) { /* it's ready already */ 1088*65393Sbostic pfa = (fa *) a[2]; 1089*65393Sbostic } else { 1090*65393Sbostic pfa = makedfa(fs, 1); 1091*65393Sbostic } 1092*65393Sbostic if (nematch(pfa,s)) { 1093*65393Sbostic tempstat = pfa->initstat; 1094*65393Sbostic pfa->initstat = 2; 1095*65393Sbostic do { 1096*65393Sbostic n++; 1097*65393Sbostic sprintf((char *)num, "%d", n); 1098*65393Sbostic temp = *patbeg; 1099*65393Sbostic *patbeg = '\0'; 1100*65393Sbostic if (isnumber(s)) 1101*65393Sbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval); 1102*65393Sbostic else 1103*65393Sbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval); 1104*65393Sbostic *patbeg = temp; 1105*65393Sbostic s = patbeg + patlen; 1106*65393Sbostic if (*(patbeg+patlen-1) == 0 || *s == 0) { 1107*65393Sbostic n++; 1108*65393Sbostic sprintf((char *)num, "%d", n); 1109*65393Sbostic setsymtab(num, "", 0.0, STR, (Array *) ap->sval); 1110*65393Sbostic pfa->initstat = tempstat; 1111*65393Sbostic goto spdone; 1112*65393Sbostic } 1113*65393Sbostic } while (nematch(pfa,s)); 1114*65393Sbostic } 1115*65393Sbostic n++; 1116*65393Sbostic sprintf((char *)num, "%d", n); 1117*65393Sbostic if (isnumber(s)) 1118*65393Sbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval); 1119*65393Sbostic else 1120*65393Sbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval); 1121*65393Sbostic spdone: 1122*65393Sbostic pfa = NULL; 1123*65393Sbostic } else if (sep == ' ') { 1124*65393Sbostic for (n = 0; ; ) { 1125*65393Sbostic while (*s == ' ' || *s == '\t' || *s == '\n') 1126*65393Sbostic s++; 1127*65393Sbostic if (*s == 0) 1128*65393Sbostic break; 1129*65393Sbostic n++; 1130*65393Sbostic t = s; 1131*65393Sbostic do 1132*65393Sbostic s++; 1133*65393Sbostic while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); 1134*65393Sbostic temp = *s; 1135*65393Sbostic *s = '\0'; 1136*65393Sbostic sprintf((char *)num, "%d", n); 1137*65393Sbostic if (isnumber(t)) 1138*65393Sbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval); 1139*65393Sbostic else 1140*65393Sbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1141*65393Sbostic *s = temp; 1142*65393Sbostic if (*s != 0) 1143*65393Sbostic s++; 1144*65393Sbostic } 1145*65393Sbostic } else if (*s != 0) { 1146*65393Sbostic for (;;) { 1147*65393Sbostic n++; 1148*65393Sbostic t = s; 1149*65393Sbostic while (*s != sep && *s != '\n' && *s != '\0') 1150*65393Sbostic s++; 1151*65393Sbostic temp = *s; 1152*65393Sbostic *s = '\0'; 1153*65393Sbostic sprintf((char *)num, "%d", n); 1154*65393Sbostic if (isnumber(t)) 1155*65393Sbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval); 1156*65393Sbostic else 1157*65393Sbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval); 1158*65393Sbostic *s = temp; 1159*65393Sbostic if (*s++ == 0) 1160*65393Sbostic break; 1161*65393Sbostic } 1162*65393Sbostic } 1163*65393Sbostic tempfree(ap); 1164*65393Sbostic tempfree(y); 1165*65393Sbostic if (a[2] != 0 && (int) a[3] == STRING) 1166*65393Sbostic tempfree(x); 1167*65393Sbostic x = gettemp(); 1168*65393Sbostic x->tval = NUM; 1169*65393Sbostic x->fval = n; 1170*65393Sbostic return(x); 1171*65393Sbostic } 1172*65393Sbostic 1173*65393Sbostic Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */ 1174*65393Sbostic { 1175*65393Sbostic register Cell *x; 1176*65393Sbostic 1177*65393Sbostic x = execute(a[0]); 1178*65393Sbostic if (istrue(x)) { 1179*65393Sbostic tempfree(x); 1180*65393Sbostic x = execute(a[1]); 1181*65393Sbostic } else { 1182*65393Sbostic tempfree(x); 1183*65393Sbostic x = execute(a[2]); 1184*65393Sbostic } 1185*65393Sbostic return(x); 1186*65393Sbostic } 1187*65393Sbostic 1188*65393Sbostic Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */ 1189*65393Sbostic { 1190*65393Sbostic register Cell *x; 1191*65393Sbostic 1192*65393Sbostic x = execute(a[0]); 1193*65393Sbostic if (istrue(x)) { 1194*65393Sbostic tempfree(x); 1195*65393Sbostic x = execute(a[1]); 1196*65393Sbostic } else if (a[2] != 0) { 1197*65393Sbostic tempfree(x); 1198*65393Sbostic x = execute(a[2]); 1199*65393Sbostic } 1200*65393Sbostic return(x); 1201*65393Sbostic } 1202*65393Sbostic 1203*65393Sbostic Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */ 1204*65393Sbostic { 1205*65393Sbostic register Cell *x; 1206*65393Sbostic 1207*65393Sbostic for (;;) { 1208*65393Sbostic x = execute(a[0]); 1209*65393Sbostic if (!istrue(x)) 1210*65393Sbostic return(x); 1211*65393Sbostic tempfree(x); 1212*65393Sbostic x = execute(a[1]); 1213*65393Sbostic if (isbreak(x)) { 1214*65393Sbostic x = true; 1215*65393Sbostic return(x); 1216*65393Sbostic } 1217*65393Sbostic if (isnext(x) || isexit(x) || isret(x)) 1218*65393Sbostic return(x); 1219*65393Sbostic tempfree(x); 1220*65393Sbostic } 1221*65393Sbostic } 1222*65393Sbostic 1223*65393Sbostic Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */ 1224*65393Sbostic { 1225*65393Sbostic register Cell *x; 1226*65393Sbostic 1227*65393Sbostic for (;;) { 1228*65393Sbostic x = execute(a[0]); 1229*65393Sbostic if (isbreak(x)) 1230*65393Sbostic return true; 1231*65393Sbostic if (isnext(x) || isexit(x) || isret(x)) 1232*65393Sbostic return(x); 1233*65393Sbostic tempfree(x); 1234*65393Sbostic x = execute(a[1]); 1235*65393Sbostic if (!istrue(x)) 1236*65393Sbostic return(x); 1237*65393Sbostic tempfree(x); 1238*65393Sbostic } 1239*65393Sbostic } 1240*65393Sbostic 1241*65393Sbostic Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */ 1242*65393Sbostic { 1243*65393Sbostic register Cell *x; 1244*65393Sbostic 1245*65393Sbostic x = execute(a[0]); 1246*65393Sbostic tempfree(x); 1247*65393Sbostic for (;;) { 1248*65393Sbostic if (a[1]!=0) { 1249*65393Sbostic x = execute(a[1]); 1250*65393Sbostic if (!istrue(x)) return(x); 1251*65393Sbostic else tempfree(x); 1252*65393Sbostic } 1253*65393Sbostic x = execute(a[3]); 1254*65393Sbostic if (isbreak(x)) /* turn off break */ 1255*65393Sbostic return true; 1256*65393Sbostic if (isnext(x) || isexit(x) || isret(x)) 1257*65393Sbostic return(x); 1258*65393Sbostic tempfree(x); 1259*65393Sbostic x = execute(a[2]); 1260*65393Sbostic tempfree(x); 1261*65393Sbostic } 1262*65393Sbostic } 1263*65393Sbostic 1264*65393Sbostic Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ 1265*65393Sbostic { 1266*65393Sbostic register Cell *x, *vp, *arrayp, *cp, *ncp; 1267*65393Sbostic Array *tp; 1268*65393Sbostic int i; 1269*65393Sbostic 1270*65393Sbostic vp = execute(a[0]); 1271*65393Sbostic arrayp = execute(a[1]); 1272*65393Sbostic if (!isarr(arrayp)) { 1273*65393Sbostic return true; 1274*65393Sbostic } 1275*65393Sbostic tp = (Array *) arrayp->sval; 1276*65393Sbostic tempfree(arrayp); 1277*65393Sbostic for (i = 0; i < tp->size; i++) { /* this routine knows too much */ 1278*65393Sbostic for (cp = tp->tab[i]; cp != NULL; cp = ncp) { 1279*65393Sbostic setsval(vp, cp->nval); 1280*65393Sbostic ncp = cp->cnext; 1281*65393Sbostic x = execute(a[2]); 1282*65393Sbostic if (isbreak(x)) { 1283*65393Sbostic tempfree(vp); 1284*65393Sbostic return true; 1285*65393Sbostic } 1286*65393Sbostic if (isnext(x) || isexit(x) || isret(x)) { 1287*65393Sbostic tempfree(vp); 1288*65393Sbostic return(x); 1289*65393Sbostic } 1290*65393Sbostic tempfree(x); 1291*65393Sbostic } 1292*65393Sbostic } 1293*65393Sbostic return true; 1294*65393Sbostic } 1295*65393Sbostic 1296*65393Sbostic /* if someone ever wants to run over the arrays in sorted order, */ 1297*65393Sbostic /* here it is. but it will likely run slower, not faster. */ 1298*65393Sbostic 1299*65393Sbostic /* 1300*65393Sbostic *int qstrcmp(p, q) 1301*65393Sbostic * uchar **p, **q; 1302*65393Sbostic *{ 1303*65393Sbostic * return strcmp(*p, *q); 1304*65393Sbostic *} 1305*65393Sbostic */ 1306*65393Sbostic 1307*65393Sbostic /*Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ 1308*65393Sbostic /*{ 1309*65393Sbostic /* register Cell *x, *vp, *arrayp, *cp, *ncp, *ret; 1310*65393Sbostic /* Array *tp; 1311*65393Sbostic /* int i, ne; 1312*65393Sbostic /*#define BIGENOUGH 1000 1313*65393Sbostic /* uchar *elems[BIGENOUGH], **ep; 1314*65393Sbostic /* 1315*65393Sbostic /* vp = execute(a[0]); 1316*65393Sbostic /* arrayp = execute(a[1]); 1317*65393Sbostic /* if (!isarr(arrayp)) 1318*65393Sbostic /* ERROR "%s is not an array", arrayp->nval FATAL; 1319*65393Sbostic /* tp = (Array *) arrayp->sval; 1320*65393Sbostic /* tempfree(arrayp); 1321*65393Sbostic /* ep = elems; 1322*65393Sbostic /* ret = true; 1323*65393Sbostic /* if (tp->nelem >= BIGENOUGH) 1324*65393Sbostic /* ep = (uchar **) malloc(tp->nelem * sizeof(char *)); 1325*65393Sbostic /* 1326*65393Sbostic /* for (i = ne = 0; i < tp->size; i++) 1327*65393Sbostic /* for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext) 1328*65393Sbostic /* ep[ne++] = cp->nval; 1329*65393Sbostic /* if (ne != tp->nelem) 1330*65393Sbostic /* ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL; 1331*65393Sbostic /* qsort(ep, ne, sizeof(char *), qstrcmp); 1332*65393Sbostic /* for (i = 0; i < ne; i++) { 1333*65393Sbostic /* setsval(vp, ep[i]); 1334*65393Sbostic /* x = execute(a[2]); 1335*65393Sbostic /* if (isbreak(x)) { 1336*65393Sbostic /* tempfree(vp); 1337*65393Sbostic /* break; 1338*65393Sbostic /* } 1339*65393Sbostic /* if (isnext(x) || isexit(x) || isret(x)) { 1340*65393Sbostic /* tempfree(vp); 1341*65393Sbostic /* ret = x; 1342*65393Sbostic /* break; 1343*65393Sbostic /* } 1344*65393Sbostic /* tempfree(x); 1345*65393Sbostic /* } 1346*65393Sbostic /* if (ep != elems) 1347*65393Sbostic /* free(ep); 1348*65393Sbostic /* return ret; 1349*65393Sbostic /*} 1350*65393Sbostic */ 1351*65393Sbostic 1352*65393Sbostic 1353*65393Sbostic Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ 1354*65393Sbostic { 1355*65393Sbostic register Cell *x, *y; 1356*65393Sbostic Awkfloat u; 1357*65393Sbostic register int t; 1358*65393Sbostic uchar *p, buf[RECSIZE]; 1359*65393Sbostic Node *nextarg; 1360*65393Sbostic FILE *fp; 1361*65393Sbostic 1362*65393Sbostic t = (int) a[0]; 1363*65393Sbostic x = execute(a[1]); 1364*65393Sbostic nextarg = a[1]->nnext; 1365*65393Sbostic switch (t) { 1366*65393Sbostic case FLENGTH: 1367*65393Sbostic u = strlen(getsval(x)); break; 1368*65393Sbostic case FLOG: 1369*65393Sbostic u = errcheck(log(getfval(x)), "log"); break; 1370*65393Sbostic case FINT: 1371*65393Sbostic modf(getfval(x), &u); break; 1372*65393Sbostic case FEXP: 1373*65393Sbostic u = errcheck(exp(getfval(x)), "exp"); break; 1374*65393Sbostic case FSQRT: 1375*65393Sbostic u = errcheck(sqrt(getfval(x)), "sqrt"); break; 1376*65393Sbostic case FSIN: 1377*65393Sbostic u = sin(getfval(x)); break; 1378*65393Sbostic case FCOS: 1379*65393Sbostic u = cos(getfval(x)); break; 1380*65393Sbostic case FATAN: 1381*65393Sbostic if (nextarg == 0) { 1382*65393Sbostic ERROR "atan2 requires two arguments; returning 1.0" WARNING; 1383*65393Sbostic u = 1.0; 1384*65393Sbostic } else { 1385*65393Sbostic y = execute(a[1]->nnext); 1386*65393Sbostic u = atan2(getfval(x), getfval(y)); 1387*65393Sbostic tempfree(y); 1388*65393Sbostic nextarg = nextarg->nnext; 1389*65393Sbostic } 1390*65393Sbostic break; 1391*65393Sbostic case FSYSTEM: 1392*65393Sbostic fflush(stdout); /* in case something is buffered already */ 1393*65393Sbostic u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */ 1394*65393Sbostic break; 1395*65393Sbostic case FRAND: 1396*65393Sbostic /* in principle, rand() returns something in 0..RAND_MAX */ 1397*65393Sbostic u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX; 1398*65393Sbostic break; 1399*65393Sbostic case FSRAND: 1400*65393Sbostic if (x->tval & REC) /* no argument provided */ 1401*65393Sbostic u = time((long *)0); 1402*65393Sbostic else 1403*65393Sbostic u = getfval(x); 1404*65393Sbostic srand((int) u); u = (int) u; 1405*65393Sbostic break; 1406*65393Sbostic case FTOUPPER: 1407*65393Sbostic case FTOLOWER: 1408*65393Sbostic strcpy(buf, getsval(x)); 1409*65393Sbostic if (t == FTOUPPER) { 1410*65393Sbostic for (p = buf; *p; p++) 1411*65393Sbostic if (islower(*p)) 1412*65393Sbostic *p = toupper(*p); 1413*65393Sbostic } else { 1414*65393Sbostic for (p = buf; *p; p++) 1415*65393Sbostic if (isupper(*p)) 1416*65393Sbostic *p = tolower(*p); 1417*65393Sbostic } 1418*65393Sbostic tempfree(x); 1419*65393Sbostic x = gettemp(); 1420*65393Sbostic setsval(x, buf); 1421*65393Sbostic return x; 1422*65393Sbostic case FFLUSH: 1423*65393Sbostic if ((fp = openfile(GT, getsval(x))) == NULL) 1424*65393Sbostic u = EOF; 1425*65393Sbostic else 1426*65393Sbostic u = fflush(fp); 1427*65393Sbostic break; 1428*65393Sbostic default: /* can't happen */ 1429*65393Sbostic ERROR "illegal function type %d", t FATAL; 1430*65393Sbostic break; 1431*65393Sbostic } 1432*65393Sbostic tempfree(x); 1433*65393Sbostic x = gettemp(); 1434*65393Sbostic setfval(x, u); 1435*65393Sbostic if (nextarg != 0) { 1436*65393Sbostic ERROR "warning: function has too many arguments" WARNING; 1437*65393Sbostic for ( ; nextarg; nextarg = nextarg->nnext) 1438*65393Sbostic execute(nextarg); 1439*65393Sbostic } 1440*65393Sbostic return(x); 1441*65393Sbostic } 1442*65393Sbostic 1443*65393Sbostic Cell *printstat(Node **a, int n) /* print a[0] */ 1444*65393Sbostic { 1445*65393Sbostic register Node *x; 1446*65393Sbostic register Cell *y; 1447*65393Sbostic FILE *fp; 1448*65393Sbostic 1449*65393Sbostic if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */ 1450*65393Sbostic fp = stdout; 1451*65393Sbostic else 1452*65393Sbostic fp = redirect((int)a[1], a[2]); 1453*65393Sbostic for (x = a[0]; x != NULL; x = x->nnext) { 1454*65393Sbostic y = execute(x); 1455*65393Sbostic fputs((char *)getsval(y), fp); 1456*65393Sbostic tempfree(y); 1457*65393Sbostic if (x->nnext == NULL) 1458*65393Sbostic fputs((char *)*ORS, fp); 1459*65393Sbostic else 1460*65393Sbostic fputs((char *)*OFS, fp); 1461*65393Sbostic } 1462*65393Sbostic if (a[1] != 0) 1463*65393Sbostic fflush(fp); 1464*65393Sbostic if (ferror(fp)) 1465*65393Sbostic ERROR "write error on %s", filename(fp) FATAL; 1466*65393Sbostic return(true); 1467*65393Sbostic } 1468*65393Sbostic 1469*65393Sbostic Cell *nullproc(Node **a, int n) 1470*65393Sbostic { 1471*65393Sbostic n; 1472*65393Sbostic a; 1473*65393Sbostic return 0; 1474*65393Sbostic } 1475*65393Sbostic 1476*65393Sbostic 1477*65393Sbostic FILE *redirect(int a, Node *b) /* set up all i/o redirections */ 1478*65393Sbostic { 1479*65393Sbostic FILE *fp; 1480*65393Sbostic Cell *x; 1481*65393Sbostic uchar *fname; 1482*65393Sbostic 1483*65393Sbostic x = execute(b); 1484*65393Sbostic fname = getsval(x); 1485*65393Sbostic fp = openfile(a, fname); 1486*65393Sbostic if (fp == NULL) 1487*65393Sbostic ERROR "can't open file %s", fname FATAL; 1488*65393Sbostic tempfree(x); 1489*65393Sbostic return fp; 1490*65393Sbostic } 1491*65393Sbostic 1492*65393Sbostic struct files { 1493*65393Sbostic FILE *fp; 1494*65393Sbostic uchar *fname; 1495*65393Sbostic int mode; /* '|', 'a', 'w' => LE/LT, GT */ 1496*65393Sbostic } files[FOPEN_MAX] ={ 1497*65393Sbostic { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */ 1498*65393Sbostic { stdout, "/dev/stdout", GT }, 1499*65393Sbostic { stderr, "/dev/stderr", GT } 1500*65393Sbostic }; 1501*65393Sbostic 1502*65393Sbostic FILE *openfile(int a, uchar *us) 1503*65393Sbostic { 1504*65393Sbostic char *s = us; 1505*65393Sbostic register int i, m; 1506*65393Sbostic register FILE *fp; 1507*65393Sbostic 1508*65393Sbostic if (*s == '\0') 1509*65393Sbostic ERROR "null file name in print or getline" FATAL; 1510*65393Sbostic for (i=0; i < FOPEN_MAX; i++) 1511*65393Sbostic if (files[i].fname && strcmp(s, files[i].fname) == 0) 1512*65393Sbostic if (a == files[i].mode || a==APPEND && files[i].mode==GT) 1513*65393Sbostic return files[i].fp; 1514*65393Sbostic for (i=0; i < FOPEN_MAX; i++) 1515*65393Sbostic if (files[i].fp == 0) 1516*65393Sbostic break; 1517*65393Sbostic if (i >= FOPEN_MAX) 1518*65393Sbostic ERROR "%s makes too many open files", s FATAL; 1519*65393Sbostic fflush(stdout); /* force a semblance of order */ 1520*65393Sbostic m = a; 1521*65393Sbostic if (a == GT) { 1522*65393Sbostic fp = fopen(s, "w"); 1523*65393Sbostic } else if (a == APPEND) { 1524*65393Sbostic fp = fopen(s, "a"); 1525*65393Sbostic m = GT; /* so can mix > and >> */ 1526*65393Sbostic } else if (a == '|') { /* output pipe */ 1527*65393Sbostic fp = popen(s, "w"); 1528*65393Sbostic } else if (a == LE) { /* input pipe */ 1529*65393Sbostic fp = popen(s, "r"); 1530*65393Sbostic } else if (a == LT) { /* getline <file */ 1531*65393Sbostic fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */ 1532*65393Sbostic } else /* can't happen */ 1533*65393Sbostic ERROR "illegal redirection %d", a FATAL; 1534*65393Sbostic if (fp != NULL) { 1535*65393Sbostic files[i].fname = tostring(s); 1536*65393Sbostic files[i].fp = fp; 1537*65393Sbostic files[i].mode = m; 1538*65393Sbostic } 1539*65393Sbostic return fp; 1540*65393Sbostic } 1541*65393Sbostic 1542*65393Sbostic uchar *filename(FILE *fp) 1543*65393Sbostic { 1544*65393Sbostic int i; 1545*65393Sbostic 1546*65393Sbostic for (i = 0; i < FOPEN_MAX; i++) 1547*65393Sbostic if (fp == files[i].fp) 1548*65393Sbostic return files[i].fname; 1549*65393Sbostic return "???"; 1550*65393Sbostic } 1551*65393Sbostic 1552*65393Sbostic Cell *closefile(Node **a, int n) 1553*65393Sbostic { 1554*65393Sbostic register Cell *x; 1555*65393Sbostic int i, stat; 1556*65393Sbostic 1557*65393Sbostic n; 1558*65393Sbostic x = execute(a[0]); 1559*65393Sbostic getsval(x); 1560*65393Sbostic for (i = 0; i < FOPEN_MAX; i++) 1561*65393Sbostic if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { 1562*65393Sbostic if (ferror(files[i].fp)) 1563*65393Sbostic ERROR "i/o error occurred on %s", files[i].fname WARNING; 1564*65393Sbostic if (files[i].mode == '|' || files[i].mode == LE) 1565*65393Sbostic stat = pclose(files[i].fp); 1566*65393Sbostic else 1567*65393Sbostic stat = fclose(files[i].fp); 1568*65393Sbostic if (stat == EOF) 1569*65393Sbostic ERROR "i/o error occurred closing %s", files[i].fname WARNING; 1570*65393Sbostic if (i > 2) /* don't do /dev/std... */ 1571*65393Sbostic xfree(files[i].fname); 1572*65393Sbostic files[i].fname = NULL; /* watch out for ref thru this */ 1573*65393Sbostic files[i].fp = NULL; 1574*65393Sbostic } 1575*65393Sbostic tempfree(x); 1576*65393Sbostic return(true); 1577*65393Sbostic } 1578*65393Sbostic 1579*65393Sbostic void closeall(void) 1580*65393Sbostic { 1581*65393Sbostic int i, stat; 1582*65393Sbostic 1583*65393Sbostic for (i = 0; i < FOPEN_MAX; i++) 1584*65393Sbostic if (files[i].fp) { 1585*65393Sbostic if (ferror(files[i].fp)) 1586*65393Sbostic ERROR "i/o error occurred on %s", files[i].fname WARNING; 1587*65393Sbostic if (files[i].mode == '|' || files[i].mode == LE) 1588*65393Sbostic stat = pclose(files[i].fp); 1589*65393Sbostic else 1590*65393Sbostic stat = fclose(files[i].fp); 1591*65393Sbostic if (stat == EOF) 1592*65393Sbostic ERROR "i/o error occurred while closing %s", files[i].fname WARNING; 1593*65393Sbostic } 1594*65393Sbostic } 1595*65393Sbostic 1596*65393Sbostic #define SUBSIZE (20 * RECSIZE) 1597*65393Sbostic 1598*65393Sbostic Cell *sub(Node **a, int nnn) /* substitute command */ 1599*65393Sbostic { 1600*65393Sbostic register uchar *sptr, *pb, *q; 1601*65393Sbostic register Cell *x, *y, *result; 1602*65393Sbostic uchar buf[SUBSIZE], *t; 1603*65393Sbostic fa *pfa; 1604*65393Sbostic 1605*65393Sbostic x = execute(a[3]); /* target string */ 1606*65393Sbostic t = getsval(x); 1607*65393Sbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 1608*65393Sbostic pfa = (fa *) a[1]; /* regular expression */ 1609*65393Sbostic else { 1610*65393Sbostic y = execute(a[1]); 1611*65393Sbostic pfa = makedfa(getsval(y), 1); 1612*65393Sbostic tempfree(y); 1613*65393Sbostic } 1614*65393Sbostic y = execute(a[2]); /* replacement string */ 1615*65393Sbostic result = false; 1616*65393Sbostic if (pmatch(pfa, t)) { 1617*65393Sbostic pb = buf; 1618*65393Sbostic sptr = t; 1619*65393Sbostic while (sptr < patbeg) 1620*65393Sbostic *pb++ = *sptr++; 1621*65393Sbostic sptr = getsval(y); 1622*65393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE - 1) 1623*65393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') { 1624*65393Sbostic sptr++; /* skip \, */ 1625*65393Sbostic *pb++ = *sptr++; /* add & */ 1626*65393Sbostic } else if (*sptr == '&') { 1627*65393Sbostic sptr++; 1628*65393Sbostic for (q = patbeg; q < patbeg+patlen; ) 1629*65393Sbostic *pb++ = *q++; 1630*65393Sbostic } else 1631*65393Sbostic *pb++ = *sptr++; 1632*65393Sbostic *pb = '\0'; 1633*65393Sbostic if (pb >= buf + SUBSIZE) 1634*65393Sbostic ERROR "sub() result %30s too big", buf FATAL; 1635*65393Sbostic sptr = patbeg + patlen; 1636*65393Sbostic if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) 1637*65393Sbostic while (*pb++ = *sptr++) 1638*65393Sbostic ; 1639*65393Sbostic if (pb >= buf + SUBSIZE) 1640*65393Sbostic ERROR "sub() result %.30s too big", buf FATAL; 1641*65393Sbostic setsval(x, buf); 1642*65393Sbostic result = true;; 1643*65393Sbostic } 1644*65393Sbostic tempfree(x); 1645*65393Sbostic tempfree(y); 1646*65393Sbostic return result; 1647*65393Sbostic } 1648*65393Sbostic 1649*65393Sbostic Cell *gsub(Node **a, int nnn) /* global substitute */ 1650*65393Sbostic { 1651*65393Sbostic register Cell *x, *y; 1652*65393Sbostic register uchar *rptr, *sptr, *t, *pb; 1653*65393Sbostic uchar buf[SUBSIZE]; 1654*65393Sbostic register fa *pfa; 1655*65393Sbostic int mflag, tempstat, num; 1656*65393Sbostic 1657*65393Sbostic mflag = 0; /* if mflag == 0, can replace empty string */ 1658*65393Sbostic num = 0; 1659*65393Sbostic x = execute(a[3]); /* target string */ 1660*65393Sbostic t = getsval(x); 1661*65393Sbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ 1662*65393Sbostic pfa = (fa *) a[1]; /* regular expression */ 1663*65393Sbostic else { 1664*65393Sbostic y = execute(a[1]); 1665*65393Sbostic pfa = makedfa(getsval(y), 1); 1666*65393Sbostic tempfree(y); 1667*65393Sbostic } 1668*65393Sbostic y = execute(a[2]); /* replacement string */ 1669*65393Sbostic if (pmatch(pfa, t)) { 1670*65393Sbostic tempstat = pfa->initstat; 1671*65393Sbostic pfa->initstat = 2; 1672*65393Sbostic pb = buf; 1673*65393Sbostic rptr = getsval(y); 1674*65393Sbostic do { 1675*65393Sbostic /* 1676*65393Sbostic uchar *p; 1677*65393Sbostic int i; 1678*65393Sbostic printf("target string: %s, *patbeg = %o, patlen = %d\n", 1679*65393Sbostic t, *patbeg, patlen); 1680*65393Sbostic printf(" match found: "); 1681*65393Sbostic p=patbeg; 1682*65393Sbostic for (i=0; i<patlen; i++) 1683*65393Sbostic printf("%c", *p++); 1684*65393Sbostic printf("\n"); 1685*65393Sbostic */ 1686*65393Sbostic if (patlen == 0 && *patbeg != 0) { /* matched empty string */ 1687*65393Sbostic if (mflag == 0) { /* can replace empty */ 1688*65393Sbostic num++; 1689*65393Sbostic sptr = rptr; 1690*65393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE-1) 1691*65393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') { 1692*65393Sbostic sptr++; 1693*65393Sbostic *pb++ = *sptr++; 1694*65393Sbostic } else if (*sptr == '&') { 1695*65393Sbostic uchar *q; 1696*65393Sbostic sptr++; 1697*65393Sbostic for (q = patbeg; q < patbeg+patlen; ) 1698*65393Sbostic *pb++ = *q++; 1699*65393Sbostic } else 1700*65393Sbostic *pb++ = *sptr++; 1701*65393Sbostic } 1702*65393Sbostic if (*t == 0) /* at end */ 1703*65393Sbostic goto done; 1704*65393Sbostic *pb++ = *t++; 1705*65393Sbostic if (pb >= buf + SUBSIZE-1) 1706*65393Sbostic ERROR "gsub() result %.30s too big", buf FATAL; 1707*65393Sbostic mflag = 0; 1708*65393Sbostic } 1709*65393Sbostic else { /* matched nonempty string */ 1710*65393Sbostic num++; 1711*65393Sbostic sptr = t; 1712*65393Sbostic while (sptr < patbeg && pb < buf + SUBSIZE-1) 1713*65393Sbostic *pb++ = *sptr++; 1714*65393Sbostic sptr = rptr; 1715*65393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE-1) 1716*65393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') { 1717*65393Sbostic sptr++; 1718*65393Sbostic *pb++ = *sptr++; 1719*65393Sbostic } else if (*sptr == '&') { 1720*65393Sbostic uchar *q; 1721*65393Sbostic sptr++; 1722*65393Sbostic for (q = patbeg; q < patbeg+patlen; ) 1723*65393Sbostic *pb++ = *q++; 1724*65393Sbostic } else 1725*65393Sbostic *pb++ = *sptr++; 1726*65393Sbostic t = patbeg + patlen; 1727*65393Sbostic if ((*(t-1) == 0) || (*t == 0)) 1728*65393Sbostic goto done; 1729*65393Sbostic if (pb >= buf + SUBSIZE-1) 1730*65393Sbostic ERROR "gsub() result %.30s too big", buf FATAL; 1731*65393Sbostic mflag = 1; 1732*65393Sbostic } 1733*65393Sbostic } while (pmatch(pfa,t)); 1734*65393Sbostic sptr = t; 1735*65393Sbostic while (*pb++ = *sptr++) 1736*65393Sbostic ; 1737*65393Sbostic done: if (pb >= buf + SUBSIZE-1) 1738*65393Sbostic ERROR "gsub() result %.30s too big", buf FATAL; 1739*65393Sbostic *pb = '\0'; 1740*65393Sbostic setsval(x, buf); 1741*65393Sbostic pfa->initstat = tempstat; 1742*65393Sbostic } 1743*65393Sbostic tempfree(x); 1744*65393Sbostic tempfree(y); 1745*65393Sbostic x = gettemp(); 1746*65393Sbostic x->tval = NUM; 1747*65393Sbostic x->fval = num; 1748*65393Sbostic return(x); 1749*65393Sbostic } 1750