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