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