Annotation of src/usr.bin/awk/run.c, Revision 1.14
1.14 ! millert 1: /* $OpenBSD: run.c,v 1.13 1997/08/25 16:17:14 kstailey Exp $ */
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;
1.14 ! millert 286: tempfree(t);
1.1 tholo 287: } else {
288: oargs[i]->tval = t->tval;
289: oargs[i]->tval &= ~(STR|NUM|DONTFREE);
290: oargs[i]->sval = t->sval;
291: tempfree(t);
292: }
293: }
294: } else if (t != y) { /* kludge to prevent freeing twice */
295: t->csub = CTEMP;
296: tempfree(t);
297: }
298: }
299: tempfree(fcn);
300: if (isexit(y) || isnext(y) || isnextfile(y))
301: return y;
302: tempfree(y); /* this can free twice! */
303: z = fp->retval; /* return value */
1.13 kstailey 304: dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
1.1 tholo 305: fp--;
306: return(z);
307: }
308:
309: Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
310: {
311: Cell *y;
312:
313: y = gettemp();
314: y->csub = CCOPY; /* prevents freeing until call is over */
1.13 kstailey 315: y->nval = x->nval; /* BUG? */
1.1 tholo 316: y->sval = x->sval ? tostring(x->sval) : NULL;
317: y->fval = x->fval;
318: y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
319: /* is DONTFREE right? */
320: return y;
321: }
322:
323: Cell *arg(Node **a, int n) /* nth argument of a function */
324: {
325:
1.12 millert 326: n = (int) a[0]; /* argument number, counting from 0 */
1.13 kstailey 327: dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
1.1 tholo 328: if (n+1 > fp->nargs)
329: ERROR "argument #%d of function %s was not supplied",
330: n+1, fp->fcncell->nval FATAL;
331: return fp->args[n];
332: }
333:
334: Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
335: {
336: Cell *y;
337:
338: switch (n) {
339: case EXIT:
340: if (a[0] != NULL) {
341: y = execute(a[0]);
1.14 ! millert 342: errorflag = (int) getfval(y);
1.1 tholo 343: tempfree(y);
344: }
345: longjmp(env, 1);
346: case RETURN:
347: if (a[0] != NULL) {
348: y = execute(a[0]);
349: if ((y->tval & (STR|NUM)) == (STR|NUM)) {
350: setsval(fp->retval, getsval(y));
351: fp->retval->fval = getfval(y);
352: fp->retval->tval |= NUM;
353: }
354: else if (y->tval & STR)
355: setsval(fp->retval, getsval(y));
356: else if (y->tval & NUM)
357: setfval(fp->retval, getfval(y));
358: else /* can't happen */
359: ERROR "bad type variable %d", y->tval FATAL;
360: tempfree(y);
361: }
362: return(jret);
363: case NEXT:
364: return(jnext);
365: case NEXTFILE:
366: nextfile();
367: return(jnextfile);
368: case BREAK:
369: return(jbreak);
370: case CONTINUE:
371: return(jcont);
372: default: /* can't happen */
373: ERROR "illegal jump type %d", n FATAL;
374: }
375: return 0; /* not reached */
376: }
377:
378: Cell *getline(Node **a, int n) /* get next line from specific input */
379: { /* a[0] is variable, a[1] is operator, a[2] is filename */
380: Cell *r, *x;
1.13 kstailey 381: extern Cell **fldtab;
1.1 tholo 382: FILE *fp;
1.13 kstailey 383: char *buf;
384: int bufsize = recsize;
385:
386: if ((buf = (char *) malloc(bufsize)) == NULL)
387: ERROR "out of memory in getline" FATAL;
1.1 tholo 388:
389: fflush(stdout); /* in case someone is waiting for a prompt */
390: r = gettemp();
391: if (a[1] != NULL) { /* getline < file */
392: x = execute(a[2]); /* filename */
1.13 kstailey 393: if ((int) a[1] == '|') /* input pipe */
1.1 tholo 394: a[1] = (Node *) LE; /* arbitrary flag */
1.12 millert 395: fp = openfile((int) a[1], getsval(x));
1.1 tholo 396: tempfree(x);
397: if (fp == NULL)
398: n = -1;
399: else
1.13 kstailey 400: n = readrec(&buf, &bufsize, fp);
1.1 tholo 401: if (n <= 0) {
402: ;
403: } else if (a[0] != NULL) { /* getline var <file */
1.13 kstailey 404: x = execute(a[0]);
405: setsval(x, buf);
406: tempfree(x);
1.1 tholo 407: } else { /* getline <file */
1.13 kstailey 408: setsval(fldtab[0], buf);
1.14 ! millert 409: if (is_number(fldtab[0]->sval)) {
1.13 kstailey 410: fldtab[0]->fval = atof(fldtab[0]->sval);
411: fldtab[0]->tval |= NUM;
1.1 tholo 412: }
413: }
414: } else { /* bare getline; use current input */
415: if (a[0] == NULL) /* getline */
1.13 kstailey 416: n = getrec(&record, &recsize, 1);
1.1 tholo 417: else { /* getline var */
1.13 kstailey 418: n = getrec(&buf, &bufsize, 0);
419: x = execute(a[0]);
420: setsval(x, buf);
421: tempfree(x);
1.1 tholo 422: }
423: }
424: setfval(r, (Awkfloat) n);
1.13 kstailey 425: free(buf);
1.1 tholo 426: return r;
427: }
428:
429: Cell *getnf(Node **a, int n) /* get NF */
430: {
431: if (donefld == 0)
432: fldbld();
433: return (Cell *) a[0];
434: }
435:
436: Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
437: {
438: Cell *x, *y, *z;
439: char *s;
440: Node *np;
1.13 kstailey 441: char *buf;
442: int bufsz = recsize;
443: int nsub = strlen(*SUBSEP);
444:
445: if ((buf = malloc(bufsz)) == NULL)
446: ERROR "out of memory in array" FATAL;
1.1 tholo 447:
448: x = execute(a[0]); /* Cell* for symbol table */
449: buf[0] = 0;
450: for (np = a[1]; np; np = np->nnext) {
451: y = execute(np); /* subscript */
452: s = getsval(y);
1.13 kstailey 453: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
454: ERROR "out of memory for %s[%s...]", x->nval, buf FATAL;
455: strcat(buf, s);
1.1 tholo 456: if (np->nnext)
457: strcat(buf, *SUBSEP);
458: tempfree(y);
459: }
460: if (!isarr(x)) {
1.13 kstailey 461: dprintf( ("making %s into an array\n", x->nval) );
1.1 tholo 462: if (freeable(x))
463: xfree(x->sval);
464: x->tval &= ~(STR|NUM|DONTFREE);
465: x->tval |= ARR;
466: x->sval = (char *) makesymtab(NSYMTAB);
467: }
468: z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
469: z->ctype = OCELL;
470: z->csub = CVAR;
471: tempfree(x);
1.13 kstailey 472: free(buf);
1.1 tholo 473: return(z);
474: }
475:
1.14 ! millert 476: Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
1.1 tholo 477: {
478: Cell *x, *y;
479: Node *np;
1.13 kstailey 480: char *s;
481: int nsub = strlen(*SUBSEP);
1.1 tholo 482:
483: x = execute(a[0]); /* Cell* for symbol table */
484: if (!isarr(x))
485: return true;
486: if (a[1] == 0) { /* delete the elements, not the table */
487: freesymtab(x);
488: x->tval &= ~STR;
489: x->tval |= ARR;
490: x->sval = (char *) makesymtab(NSYMTAB);
491: } else {
1.13 kstailey 492: int bufsz = recsize;
493: char *buf;
494: if ((buf = malloc(bufsz)) == NULL)
495: ERROR "out of memory in adelete" FATAL;
1.1 tholo 496: buf[0] = 0;
497: for (np = a[1]; np; np = np->nnext) {
498: y = execute(np); /* subscript */
499: s = getsval(y);
1.13 kstailey 500: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
501: ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL;
502: strcat(buf, s);
1.1 tholo 503: if (np->nnext)
504: strcat(buf, *SUBSEP);
505: tempfree(y);
506: }
507: freeelem(x, buf);
1.13 kstailey 508: free(buf);
1.1 tholo 509: }
510: tempfree(x);
511: return true;
512: }
513:
514: Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
515: {
516: Cell *x, *ap, *k;
517: Node *p;
1.13 kstailey 518: char *buf;
1.1 tholo 519: char *s;
1.13 kstailey 520: int bufsz = recsize;
521: int nsub = strlen(*SUBSEP);
1.1 tholo 522:
523: ap = execute(a[1]); /* array name */
524: if (!isarr(ap)) {
1.13 kstailey 525: dprintf( ("making %s into an array\n", ap->nval) );
1.1 tholo 526: if (freeable(ap))
527: xfree(ap->sval);
528: ap->tval &= ~(STR|NUM|DONTFREE);
529: ap->tval |= ARR;
530: ap->sval = (char *) makesymtab(NSYMTAB);
531: }
1.13 kstailey 532: if ((buf = malloc(bufsz)) == NULL) {
533: ERROR "out of memory in intest" FATAL;
534: }
1.1 tholo 535: buf[0] = 0;
536: for (p = a[0]; p; p = p->nnext) {
537: x = execute(p); /* expr */
538: s = getsval(x);
1.13 kstailey 539: if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, 0))
540: ERROR "out of memory deleting %s[%s...]", x->nval, buf FATAL;
1.1 tholo 541: strcat(buf, s);
542: tempfree(x);
543: if (p->nnext)
544: strcat(buf, *SUBSEP);
545: }
546: k = lookup(buf, (Array *) ap->sval);
547: tempfree(ap);
1.13 kstailey 548: free(buf);
1.1 tholo 549: if (k == NULL)
550: return(false);
551: else
552: return(true);
553: }
554:
555:
556: Cell *matchop(Node **a, int n) /* ~ and match() */
557: {
558: Cell *x, *y;
559: char *s, *t;
560: int i;
561: fa *pfa;
562: int (*mf)(fa *, char *) = match, mode = 0;
563:
564: if (n == MATCHFCN) {
565: mf = pmatch;
566: mode = 1;
567: }
568: x = execute(a[1]); /* a[1] = target text */
569: s = getsval(x);
570: if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
571: i = (*mf)((fa *) a[2], s);
572: else {
573: y = execute(a[2]); /* a[2] = regular expr */
574: t = getsval(y);
575: pfa = makedfa(t, mode);
576: i = (*mf)(pfa, s);
577: tempfree(y);
578: }
579: tempfree(x);
580: if (n == MATCHFCN) {
581: int start = patbeg - s + 1;
582: if (patlen < 0)
583: start = 0;
584: setfval(rstartloc, (Awkfloat) start);
585: setfval(rlengthloc, (Awkfloat) patlen);
586: x = gettemp();
587: x->tval = NUM;
588: x->fval = start;
589: return x;
590: } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
591: return(true);
592: else
593: return(false);
594: }
595:
596:
597: Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
598: {
599: Cell *x, *y;
600: int i;
601:
602: x = execute(a[0]);
603: i = istrue(x);
604: tempfree(x);
605: switch (n) {
606: case BOR:
607: if (i) return(true);
608: y = execute(a[1]);
609: i = istrue(y);
610: tempfree(y);
611: if (i) return(true);
612: else return(false);
613: case AND:
614: if ( !i ) return(false);
615: y = execute(a[1]);
616: i = istrue(y);
617: tempfree(y);
618: if (i) return(true);
619: else return(false);
620: case NOT:
621: if (i) return(false);
622: else return(true);
623: default: /* can't happen */
624: ERROR "unknown boolean operator %d", n FATAL;
625: }
626: return 0; /*NOTREACHED*/
627: }
628:
629: Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
630: {
631: int i;
632: Cell *x, *y;
633: Awkfloat j;
634:
635: x = execute(a[0]);
636: y = execute(a[1]);
637: if (x->tval&NUM && y->tval&NUM) {
638: j = x->fval - y->fval;
639: i = j<0? -1: (j>0? 1: 0);
640: } else {
641: i = strcmp(getsval(x), getsval(y));
642: }
643: tempfree(x);
644: tempfree(y);
645: switch (n) {
646: case LT: if (i<0) return(true);
647: else return(false);
648: case LE: if (i<=0) return(true);
649: else return(false);
650: case NE: if (i!=0) return(true);
651: else return(false);
652: case EQ: if (i == 0) return(true);
653: else return(false);
654: case GE: if (i>=0) return(true);
655: else return(false);
656: case GT: if (i>0) return(true);
657: else return(false);
658: default: /* can't happen */
659: ERROR "unknown relational operator %d", n FATAL;
660: }
661: return 0; /*NOTREACHED*/
662: }
663:
664: void tfree(Cell *a) /* free a tempcell */
665: {
1.13 kstailey 666: if (freeable(a)) {
667: dprintf( ("freeing %s %s %o\n", a->nval, a->sval, a->tval) );
1.1 tholo 668: xfree(a->sval);
1.13 kstailey 669: }
1.1 tholo 670: if (a == tmps)
671: ERROR "tempcell list is curdled" FATAL;
672: a->cnext = tmps;
673: tmps = a;
674: }
675:
676: Cell *gettemp(void) /* get a tempcell */
677: { int i;
678: Cell *x;
679:
680: if (!tmps) {
681: tmps = (Cell *) calloc(100, sizeof(Cell));
682: if (!tmps)
683: ERROR "out of space for temporaries" FATAL;
684: for(i = 1; i < 100; i++)
685: tmps[i-1].cnext = &tmps[i];
686: tmps[i-1].cnext = 0;
687: }
688: x = tmps;
689: tmps = x->cnext;
690: *x = tempcell;
691: return(x);
692: }
693:
694: Cell *indirect(Node **a, int n) /* $( a[0] ) */
695: {
696: Cell *x;
697: int m;
698: char *s;
699:
700: x = execute(a[0]);
1.14 ! millert 701: m = (int) getfval(x);
! 702: if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
1.1 tholo 703: ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
1.13 kstailey 704: /* BUG: can x->nval ever be null??? */
1.1 tholo 705: tempfree(x);
706: x = fieldadr(m);
1.13 kstailey 707: x->ctype = OCELL; /* BUG? why are these needed? */
1.1 tholo 708: x->csub = CFLD;
709: return(x);
710: }
711:
712: Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
713: {
714: int k, m, n;
715: char *s;
716: int temp;
717: Cell *x, *y, *z = 0;
718:
719: x = execute(a[0]);
720: y = execute(a[1]);
721: if (a[2] != 0)
722: z = execute(a[2]);
723: s = getsval(x);
724: k = strlen(s) + 1;
725: if (k <= 1) {
726: tempfree(x);
727: tempfree(y);
728: if (a[2] != 0)
729: tempfree(z);
730: x = gettemp();
731: setsval(x, "");
732: return(x);
733: }
1.14 ! millert 734: m = (int) getfval(y);
1.1 tholo 735: if (m <= 0)
736: m = 1;
737: else if (m > k)
738: m = k;
739: tempfree(y);
740: if (a[2] != 0) {
1.14 ! millert 741: n = (int) getfval(z);
1.1 tholo 742: tempfree(z);
743: } else
744: n = k - 1;
745: if (n < 0)
746: n = 0;
747: else if (n > k - m)
748: n = k - m;
1.13 kstailey 749: dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
1.1 tholo 750: y = gettemp();
751: temp = s[n+m-1]; /* with thanks to John Linderman */
752: s[n+m-1] = '\0';
753: setsval(y, s + m - 1);
754: s[n+m-1] = temp;
755: tempfree(x);
756: return(y);
757: }
758:
759: Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
760: {
761: Cell *x, *y, *z;
762: char *s1, *s2, *p1, *p2, *q;
763: Awkfloat v = 0.0;
764:
765: x = execute(a[0]);
766: s1 = getsval(x);
767: y = execute(a[1]);
768: s2 = getsval(y);
769:
770: z = gettemp();
771: for (p1 = s1; *p1 != '\0'; p1++) {
772: for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
773: ;
774: if (*p2 == '\0') {
775: v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
776: break;
777: }
778: }
779: tempfree(x);
780: tempfree(y);
781: setfval(z, v);
782: return(z);
783: }
784:
1.13 kstailey 785: #define MAXNUMSIZE 50
786:
787: int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversions */
1.1 tholo 788: {
1.13 kstailey 789: char *fmt;
1.1 tholo 790: char *p, *t, *os;
791: Cell *x;
1.10 kstailey 792: int flag = 0, n;
1.13 kstailey 793: int fmtwd; /* format width */
794: int fmtsz = recsize;
795: char *buf = *pbuf;
796: int bufsize = *pbufsize;
1.1 tholo 797:
798: os = s;
799: p = buf;
1.13 kstailey 800: if ((fmt = malloc(fmtsz)) == NULL)
801: ERROR "out of memory in format()" FATAL;
1.1 tholo 802: while (*s) {
1.13 kstailey 803: adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format");
1.1 tholo 804: if (*s != '%') {
805: *p++ = *s++;
806: continue;
807: }
808: if (*(s+1) == '%') {
809: *p++ = '%';
810: s += 2;
811: continue;
812: }
1.13 kstailey 813: /* have to be real careful in case this is a huge number, eg, %100000d */
814: fmtwd = atoi(s+1);
815: if (fmtwd < 0)
816: fmtwd = -fmtwd;
817: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
818: for (t = fmt; (*t++ = *s) != '\0'; s++) {
819: if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, 0))
820: ERROR "format item %.30s... ran format() out of memory", os FATAL;
1.1 tholo 821: if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
822: break; /* the ansi panoply */
823: if (*s == '*') {
824: x = execute(a);
825: a = a->nnext;
1.13 kstailey 826: sprintf(t-1, "%d", fmtwd=(int) getfval(x));
827: if (fmtwd < 0)
828: fmtwd = -fmtwd;
829: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
1.1 tholo 830: t = fmt + strlen(fmt);
831: tempfree(x);
832: }
833: }
834: *t = '\0';
1.13 kstailey 835: if (fmtwd < 0)
836: fmtwd = -fmtwd;
837: adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
838:
1.1 tholo 839: switch (*s) {
840: case 'f': case 'e': case 'g': case 'E': case 'G':
841: flag = 1;
842: break;
843: case 'd': case 'i':
844: flag = 2;
845: if(*(s-1) == 'l') break;
846: *(t-1) = 'l';
847: *t = 'd';
848: *++t = '\0';
849: break;
850: case 'o': case 'x': case 'X': case 'u':
851: flag = *(s-1) == 'l' ? 2 : 3;
852: break;
853: case 's':
854: flag = 4;
855: break;
856: case 'c':
857: flag = 5;
858: break;
859: default:
860: ERROR "weird printf conversion %s", fmt WARNING;
861: flag = 0;
862: break;
863: }
864: if (a == NULL)
865: ERROR "not enough args in printf(%s)", os FATAL;
866: x = execute(a);
867: a = a->nnext;
1.13 kstailey 868: n = MAXNUMSIZE;
869: if (fmtwd > n)
870: n = fmtwd;
871: adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format");
1.1 tholo 872: switch (flag) {
1.13 kstailey 873: case 0: sprintf(p, "%s", fmt); /* unknown, so dump it too */
874: t = getsval(x);
875: n = strlen(t);
876: if (fmtwd > n)
877: n = fmtwd;
878: adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format");
1.5 kstailey 879: p += strlen(p);
1.13 kstailey 880: sprintf(p, "%s", t);
1.1 tholo 881: break;
1.13 kstailey 882: case 1: sprintf(p, fmt, getfval(x)); break;
883: case 2: sprintf(p, fmt, (long) getfval(x)); break;
884: case 3: sprintf(p, fmt, (int) getfval(x)); break;
1.1 tholo 885: case 4:
886: t = getsval(x);
887: n = strlen(t);
1.13 kstailey 888: if (fmtwd > n)
889: n = fmtwd;
890: if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, 0))
891: ERROR "huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t FATAL;
892: sprintf(p, fmt, t);
1.1 tholo 893: break;
894: case 5:
1.13 kstailey 895: if (isnum(x)) {
896: if (getfval(x))
897: sprintf(p, fmt, (int) getfval(x));
898: else
899: *p++ = '\0';
900: } else
901: sprintf(p, fmt, getsval(x)[0]);
1.1 tholo 902: break;
903: }
904: tempfree(x);
1.5 kstailey 905: p += strlen(p);
1.1 tholo 906: s++;
907: }
908: *p = '\0';
1.13 kstailey 909: free(fmt);
1.1 tholo 910: for ( ; a; a = a->nnext) /* evaluate any remaining args */
911: execute(a);
1.13 kstailey 912: *pbuf = buf;
913: *pbufsize = bufsize;
914: return p - buf;
1.1 tholo 915: }
916:
917: Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
918: {
919: Cell *x;
920: Node *y;
1.13 kstailey 921: char *buf;
922: int bufsz=3*recsize;
1.1 tholo 923:
1.13 kstailey 924: if ((buf=malloc(bufsz)) == NULL)
925: ERROR "out of memory in awksprintf" FATAL;
1.1 tholo 926: y = a[0]->nnext;
927: x = execute(a[0]);
1.13 kstailey 928: if (format(&buf, &bufsz, getsval(x), y) == -1)
929: ERROR "sprintf string %.30s... too long. can't happen.", buf FATAL;
1.1 tholo 930: tempfree(x);
931: x = gettemp();
1.13 kstailey 932: x->sval = buf;
1.1 tholo 933: x->tval = STR;
934: return(x);
935: }
936:
937: Cell *awkprintf(Node **a, int n) /* printf */
938: { /* a[0] is list of args, starting with format string */
939: /* a[1] is redirection operator, a[2] is redirection file */
940: FILE *fp;
941: Cell *x;
942: Node *y;
1.13 kstailey 943: char *buf;
1.9 kstailey 944: int len;
1.13 kstailey 945: int bufsz=3*recsize;
1.1 tholo 946:
1.13 kstailey 947: if ((buf=malloc(bufsz)) == NULL)
948: ERROR "out of memory in awkprintf" FATAL;
1.1 tholo 949: y = a[0]->nnext;
950: x = execute(a[0]);
1.13 kstailey 951: if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
952: ERROR "printf string %.30s... too long. can't happen.", buf FATAL;
1.1 tholo 953: tempfree(x);
954: if (a[1] == NULL) {
1.13 kstailey 955: /* fputs(buf, stdout); */
1.9 kstailey 956: fwrite(buf, len, 1, stdout);
1.8 kstailey 957: if (ferror(stdout))
1.1 tholo 958: ERROR "write error on stdout" FATAL;
959: } else {
1.12 millert 960: fp = redirect((int)a[1], a[2]);
1.13 kstailey 961: /* fputs(buf, fp); */
1.9 kstailey 962: fwrite(buf, len, 1, fp);
1.8 kstailey 963: fflush(fp);
964: if (ferror(fp))
1.1 tholo 965: ERROR "write error on %s", filename(fp) FATAL;
966: }
1.13 kstailey 967: free(buf);
1.1 tholo 968: return(true);
969: }
970:
971: Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
972: {
973: Awkfloat i, j = 0;
974: double v;
975: Cell *x, *y, *z;
976:
977: x = execute(a[0]);
978: i = getfval(x);
979: tempfree(x);
980: if (n != UMINUS) {
981: y = execute(a[1]);
982: j = getfval(y);
983: tempfree(y);
984: }
985: z = gettemp();
986: switch (n) {
987: case ADD:
988: i += j;
989: break;
990: case MINUS:
991: i -= j;
992: break;
993: case MULT:
994: i *= j;
995: break;
996: case DIVIDE:
997: if (j == 0)
998: ERROR "division by zero" FATAL;
999: i /= j;
1000: break;
1001: case MOD:
1002: if (j == 0)
1003: ERROR "division by zero in mod" FATAL;
1004: modf(i/j, &v);
1005: i = i - j * v;
1006: break;
1007: case UMINUS:
1008: i = -i;
1009: break;
1010: case POWER:
1011: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
1.12 millert 1012: i = ipow(i, (int) j);
1.1 tholo 1013: else
1014: i = errcheck(pow(i, j), "pow");
1015: break;
1016: default: /* can't happen */
1017: ERROR "illegal arithmetic operator %d", n FATAL;
1018: }
1019: setfval(z, i);
1020: return(z);
1021: }
1022:
1023: double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
1024: {
1025: double v;
1026:
1027: if (n <= 0)
1028: return 1;
1029: v = ipow(x, n/2);
1030: if (n % 2 == 0)
1031: return v * v;
1032: else
1033: return x * v * v;
1034: }
1035:
1036: Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
1037: {
1038: Cell *x, *z;
1039: int k;
1040: Awkfloat xf;
1041:
1042: x = execute(a[0]);
1043: xf = getfval(x);
1044: k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
1045: if (n == PREINCR || n == PREDECR) {
1046: setfval(x, xf + k);
1047: return(x);
1048: }
1049: z = gettemp();
1050: setfval(z, xf);
1051: setfval(x, xf + k);
1052: tempfree(x);
1053: return(z);
1054: }
1055:
1056: Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
1057: { /* this is subtle; don't muck with it. */
1058: Cell *x, *y;
1059: Awkfloat xf, yf;
1060: double v;
1061:
1062: y = execute(a[1]);
1063: x = execute(a[0]);
1064: if (n == ASSIGN) { /* ordinary assignment */
1065: if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
1066: ; /* leave alone unless it's a field */
1067: else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1068: setsval(x, getsval(y));
1069: x->fval = getfval(y);
1070: x->tval |= NUM;
1071: }
1.13 kstailey 1072: else if (isstr(y))
1.1 tholo 1073: setsval(x, getsval(y));
1.13 kstailey 1074: else if (isnum(y))
1.1 tholo 1075: setfval(x, getfval(y));
1076: else
1077: funnyvar(y, "read value of");
1078: tempfree(y);
1079: return(x);
1080: }
1081: xf = getfval(x);
1082: yf = getfval(y);
1083: switch (n) {
1084: case ADDEQ:
1085: xf += yf;
1086: break;
1087: case SUBEQ:
1088: xf -= yf;
1089: break;
1090: case MULTEQ:
1091: xf *= yf;
1092: break;
1093: case DIVEQ:
1094: if (yf == 0)
1095: ERROR "division by zero in /=" FATAL;
1096: xf /= yf;
1097: break;
1098: case MODEQ:
1099: if (yf == 0)
1100: ERROR "division by zero in %%=" FATAL;
1101: modf(xf/yf, &v);
1102: xf = xf - yf * v;
1103: break;
1104: case POWEQ:
1105: if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1.12 millert 1106: xf = ipow(xf, (int) yf);
1.1 tholo 1107: else
1108: xf = errcheck(pow(xf, yf), "pow");
1109: break;
1110: default:
1111: ERROR "illegal assignment operator %d", n FATAL;
1112: break;
1113: }
1114: tempfree(y);
1115: setfval(x, xf);
1116: return(x);
1117: }
1118:
1119: Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1120: {
1121: Cell *x, *y, *z;
1122: int n1, n2;
1123: char *s;
1124:
1125: x = execute(a[0]);
1126: y = execute(a[1]);
1127: getsval(x);
1128: getsval(y);
1129: n1 = strlen(x->sval);
1130: n2 = strlen(y->sval);
1131: s = (char *) malloc(n1 + n2 + 1);
1132: if (s == NULL)
1133: ERROR "out of space concatenating %.15s... and %.15s...",
1134: x->sval, y->sval FATAL;
1135: strcpy(s, x->sval);
1136: strcpy(s+n1, y->sval);
1137: tempfree(y);
1138: z = gettemp();
1139: z->sval = s;
1140: z->tval = STR;
1141: tempfree(x);
1142: return(z);
1143: }
1144:
1145: Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1146: {
1147: Cell *x;
1148:
1149: if (a[0] == 0)
1150: x = execute(a[1]);
1151: else {
1152: x = execute(a[0]);
1153: if (istrue(x)) {
1154: tempfree(x);
1155: x = execute(a[1]);
1156: }
1157: }
1158: return x;
1159: }
1160:
1161: Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1162: {
1163: Cell *x;
1164: int pair;
1165:
1.12 millert 1166: pair = (int) a[3];
1.1 tholo 1167: if (pairstack[pair] == 0) {
1168: x = execute(a[0]);
1169: if (istrue(x))
1170: pairstack[pair] = 1;
1171: tempfree(x);
1172: }
1173: if (pairstack[pair] == 1) {
1174: x = execute(a[1]);
1175: if (istrue(x))
1176: pairstack[pair] = 0;
1177: tempfree(x);
1178: x = execute(a[2]);
1179: return(x);
1180: }
1181: return(false);
1182: }
1183:
1184: Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1185: {
1186: Cell *x = 0, *y, *ap;
1187: char *s;
1188: int sep;
1.13 kstailey 1189: char *t, temp, num[50], *fs = 0;
1.1 tholo 1190: int n, tempstat;
1191:
1192: y = execute(a[0]); /* source string */
1193: s = getsval(y);
1194: if (a[2] == 0) /* fs string */
1195: fs = *FS;
1.12 millert 1196: else if ((int) a[3] == STRING) { /* split(str,arr,"string") */
1.1 tholo 1197: x = execute(a[2]);
1198: fs = getsval(x);
1.12 millert 1199: } else if ((int) a[3] == REGEXPR)
1.13 kstailey 1200: fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1.1 tholo 1201: else
1.13 kstailey 1202: ERROR "illegal type of split" FATAL;
1.1 tholo 1203: sep = *fs;
1204: ap = execute(a[1]); /* array name */
1205: freesymtab(ap);
1.13 kstailey 1206: dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1.1 tholo 1207: ap->tval &= ~STR;
1208: ap->tval |= ARR;
1209: ap->sval = (char *) makesymtab(NSYMTAB);
1210:
1211: n = 0;
1.12 millert 1212: if ((*s != '\0' && strlen(fs) > 1) || (int) a[3] == REGEXPR) { /* reg expr */
1.1 tholo 1213: fa *pfa;
1.12 millert 1214: if ((int) a[3] == REGEXPR) { /* it's ready already */
1.1 tholo 1215: pfa = (fa *) a[2];
1216: } else {
1217: pfa = makedfa(fs, 1);
1218: }
1219: if (nematch(pfa,s)) {
1220: tempstat = pfa->initstat;
1221: pfa->initstat = 2;
1222: do {
1223: n++;
1.13 kstailey 1224: sprintf(num, "%d", n);
1.1 tholo 1225: temp = *patbeg;
1226: *patbeg = '\0';
1.14 ! millert 1227: if (is_number(s))
1.13 kstailey 1228: setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1.1 tholo 1229: else
1230: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1231: *patbeg = temp;
1232: s = patbeg + patlen;
1233: if (*(patbeg+patlen-1) == 0 || *s == 0) {
1234: n++;
1.13 kstailey 1235: sprintf(num, "%d", n);
1.1 tholo 1236: setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1237: pfa->initstat = tempstat;
1238: goto spdone;
1239: }
1240: } while (nematch(pfa,s));
1241: }
1242: n++;
1.13 kstailey 1243: sprintf(num, "%d", n);
1.14 ! millert 1244: if (is_number(s))
1.13 kstailey 1245: setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
1.1 tholo 1246: else
1247: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1248: spdone:
1249: pfa = NULL;
1250: } else if (sep == ' ') {
1251: for (n = 0; ; ) {
1252: while (*s == ' ' || *s == '\t' || *s == '\n')
1253: s++;
1254: if (*s == 0)
1255: break;
1256: n++;
1257: t = s;
1258: do
1259: s++;
1260: while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1261: temp = *s;
1262: *s = '\0';
1.13 kstailey 1263: sprintf(num, "%d", n);
1.14 ! millert 1264: if (is_number(t))
1.13 kstailey 1265: setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1.1 tholo 1266: else
1267: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1268: *s = temp;
1269: if (*s != 0)
1270: s++;
1271: }
1272: } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1273: for (n = 0; *s != 0; s++) {
1274: char buf[2];
1275: n++;
1.13 kstailey 1276: sprintf(num, "%d", n);
1.1 tholo 1277: buf[0] = *s;
1278: buf[1] = 0;
1279: if (isdigit(buf[0]))
1280: setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1281: else
1282: setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1283: }
1284: } else if (*s != 0) {
1285: for (;;) {
1286: n++;
1287: t = s;
1288: while (*s != sep && *s != '\n' && *s != '\0')
1289: s++;
1290: temp = *s;
1291: *s = '\0';
1.13 kstailey 1292: sprintf(num, "%d", n);
1.14 ! millert 1293: if (is_number(t))
1.13 kstailey 1294: setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
1.1 tholo 1295: else
1296: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1297: *s = temp;
1298: if (*s++ == 0)
1299: break;
1300: }
1301: }
1302: tempfree(ap);
1303: tempfree(y);
1.12 millert 1304: if (a[2] != 0 && (int) a[3] == STRING)
1.1 tholo 1305: tempfree(x);
1306: x = gettemp();
1307: x->tval = NUM;
1308: x->fval = n;
1309: return(x);
1310: }
1311:
1312: Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1313: {
1314: Cell *x;
1315:
1316: x = execute(a[0]);
1317: if (istrue(x)) {
1318: tempfree(x);
1319: x = execute(a[1]);
1320: } else {
1321: tempfree(x);
1322: x = execute(a[2]);
1323: }
1324: return(x);
1325: }
1326:
1327: Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1328: {
1329: Cell *x;
1330:
1331: x = execute(a[0]);
1332: if (istrue(x)) {
1333: tempfree(x);
1334: x = execute(a[1]);
1335: } else if (a[2] != 0) {
1336: tempfree(x);
1337: x = execute(a[2]);
1338: }
1339: return(x);
1340: }
1341:
1342: Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1343: {
1344: Cell *x;
1345:
1346: for (;;) {
1347: x = execute(a[0]);
1348: if (!istrue(x))
1349: return(x);
1350: tempfree(x);
1351: x = execute(a[1]);
1352: if (isbreak(x)) {
1353: x = true;
1354: return(x);
1355: }
1356: if (isnext(x) || isexit(x) || isret(x))
1357: return(x);
1358: tempfree(x);
1359: }
1360: }
1361:
1362: Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1363: {
1364: Cell *x;
1365:
1366: for (;;) {
1367: x = execute(a[0]);
1368: if (isbreak(x))
1369: return true;
1370: if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1371: return(x);
1372: tempfree(x);
1373: x = execute(a[1]);
1374: if (!istrue(x))
1375: return(x);
1376: tempfree(x);
1377: }
1378: }
1379:
1380: Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1381: {
1382: Cell *x;
1383:
1384: x = execute(a[0]);
1385: tempfree(x);
1386: for (;;) {
1387: if (a[1]!=0) {
1388: x = execute(a[1]);
1389: if (!istrue(x)) return(x);
1390: else tempfree(x);
1391: }
1392: x = execute(a[3]);
1393: if (isbreak(x)) /* turn off break */
1394: return true;
1395: if (isnext(x) || isexit(x) || isret(x))
1396: return(x);
1397: tempfree(x);
1398: x = execute(a[2]);
1399: tempfree(x);
1400: }
1401: }
1402:
1403: Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1404: {
1405: Cell *x, *vp, *arrayp, *cp, *ncp;
1406: Array *tp;
1407: int i;
1408:
1409: vp = execute(a[0]);
1410: arrayp = execute(a[1]);
1411: if (!isarr(arrayp)) {
1412: return true;
1413: }
1414: tp = (Array *) arrayp->sval;
1415: tempfree(arrayp);
1416: for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1417: for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1418: setsval(vp, cp->nval);
1419: ncp = cp->cnext;
1420: x = execute(a[2]);
1421: if (isbreak(x)) {
1422: tempfree(vp);
1423: return true;
1424: }
1425: if (isnext(x) || isexit(x) || isret(x)) {
1426: tempfree(vp);
1427: return(x);
1428: }
1429: tempfree(x);
1430: }
1431: }
1432: return true;
1433: }
1434:
1435: Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1436: {
1437: Cell *x, *y;
1438: Awkfloat u;
1439: int t;
1.13 kstailey 1440: char *p, *buf;
1.1 tholo 1441: Node *nextarg;
1442: FILE *fp;
1443:
1.12 millert 1444: t = (int) a[0];
1.1 tholo 1445: x = execute(a[1]);
1446: nextarg = a[1]->nnext;
1447: switch (t) {
1448: case FLENGTH:
1449: u = strlen(getsval(x)); break;
1450: case FLOG:
1451: u = errcheck(log(getfval(x)), "log"); break;
1452: case FINT:
1453: modf(getfval(x), &u); break;
1454: case FEXP:
1455: u = errcheck(exp(getfval(x)), "exp"); break;
1456: case FSQRT:
1457: u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1458: case FSIN:
1459: u = sin(getfval(x)); break;
1460: case FCOS:
1461: u = cos(getfval(x)); break;
1462: case FATAN:
1463: if (nextarg == 0) {
1464: ERROR "atan2 requires two arguments; returning 1.0" WARNING;
1465: u = 1.0;
1466: } else {
1467: y = execute(a[1]->nnext);
1468: u = atan2(getfval(x), getfval(y));
1469: tempfree(y);
1470: nextarg = nextarg->nnext;
1471: }
1472: break;
1473: case FSYSTEM:
1474: fflush(stdout); /* in case something is buffered already */
1.13 kstailey 1475: u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
1.1 tholo 1476: break;
1477: case FRAND:
1478: /* in principle, rand() returns something in 0..RAND_MAX */
1479: u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1480: break;
1481: case FSRAND:
1.13 kstailey 1482: if (isrec(x)) /* no argument provided */
1.1 tholo 1483: u = time((time_t *)0);
1484: else
1485: u = getfval(x);
1.14 ! millert 1486: srand((unsigned int) u);
1.1 tholo 1487: break;
1488: case FTOUPPER:
1489: case FTOLOWER:
1.13 kstailey 1490: buf = tostring(getsval(x));
1.1 tholo 1491: if (t == FTOUPPER) {
1492: for (p = buf; *p; p++)
1493: if (islower(*p))
1494: *p = toupper(*p);
1495: } else {
1496: for (p = buf; *p; p++)
1497: if (isupper(*p))
1498: *p = tolower(*p);
1499: }
1500: tempfree(x);
1501: x = gettemp();
1502: setsval(x, buf);
1.13 kstailey 1503: free(buf);
1.1 tholo 1504: return x;
1505: case FFLUSH:
1.13 kstailey 1506: if ((fp = openfile(FFLUSH, getsval(x))) == NULL)
1.1 tholo 1507: u = EOF;
1508: else
1509: u = fflush(fp);
1510: break;
1511: default: /* can't happen */
1512: ERROR "illegal function type %d", t FATAL;
1513: break;
1514: }
1515: tempfree(x);
1516: x = gettemp();
1517: setfval(x, u);
1518: if (nextarg != 0) {
1519: ERROR "warning: function has too many arguments" WARNING;
1520: for ( ; nextarg; nextarg = nextarg->nnext)
1521: execute(nextarg);
1522: }
1523: return(x);
1524: }
1525:
1526: Cell *printstat(Node **a, int n) /* print a[0] */
1527: {
1528: Node *x;
1529: Cell *y;
1530: FILE *fp;
1531:
1532: if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1533: fp = stdout;
1534: else
1.12 millert 1535: fp = redirect((int)a[1], a[2]);
1.1 tholo 1536: for (x = a[0]; x != NULL; x = x->nnext) {
1537: y = execute(x);
1.13 kstailey 1538: fputs(getsval(y), fp);
1.1 tholo 1539: tempfree(y);
1540: if (x->nnext == NULL)
1.13 kstailey 1541: fputs(*ORS, fp);
1.1 tholo 1542: else
1.13 kstailey 1543: fputs(*OFS, fp);
1.1 tholo 1544: }
1545: if (a[1] != 0)
1546: fflush(fp);
1547: if (ferror(fp))
1548: ERROR "write error on %s", filename(fp) FATAL;
1549: return(true);
1550: }
1551:
1552: Cell *nullproc(Node **a, int n)
1553: {
1554: n = 0;
1555: a = 0;
1556: return 0;
1557: }
1558:
1559:
1560: FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1561: {
1562: FILE *fp;
1563: Cell *x;
1564: char *fname;
1565:
1566: x = execute(b);
1567: fname = getsval(x);
1568: fp = openfile(a, fname);
1569: if (fp == NULL)
1570: ERROR "can't open file %s", fname FATAL;
1571: tempfree(x);
1572: return fp;
1573: }
1574:
1575: struct files {
1576: FILE *fp;
1577: char *fname;
1578: int mode; /* '|', 'a', 'w' => LE/LT, GT */
1579: } files[FOPEN_MAX] ={
1580: { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */
1581: { stdout, "/dev/stdout", GT },
1582: { stderr, "/dev/stderr", GT }
1583: };
1584:
1585: FILE *openfile(int a, char *us)
1586: {
1587: char *s = us;
1588: int i, m;
1589: FILE *fp = 0;
1590:
1591: if (*s == '\0')
1592: ERROR "null file name in print or getline" FATAL;
1593: for (i=0; i < FOPEN_MAX; i++)
1.13 kstailey 1594: if (files[i].fname && strcmp(s, files[i].fname) == 0) {
1.1 tholo 1595: if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1596: return files[i].fp;
1.13 kstailey 1597: if (a == FFLUSH)
1598: return files[i].fp;
1599: }
1600: if (a == FFLUSH) /* didn't find it, so don't create it! */
1601: return NULL;
1602:
1.1 tholo 1603: for (i=0; i < FOPEN_MAX; i++)
1604: if (files[i].fp == 0)
1605: break;
1606: if (i >= FOPEN_MAX)
1607: ERROR "%s makes too many open files", s FATAL;
1608: fflush(stdout); /* force a semblance of order */
1609: m = a;
1610: if (a == GT) {
1611: fp = fopen(s, "w");
1612: } else if (a == APPEND) {
1613: fp = fopen(s, "a");
1614: m = GT; /* so can mix > and >> */
1615: } else if (a == '|') { /* output pipe */
1616: fp = popen(s, "w");
1617: } else if (a == LE) { /* input pipe */
1618: fp = popen(s, "r");
1619: } else if (a == LT) { /* getline <file */
1620: fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1621: } else /* can't happen */
1622: ERROR "illegal redirection %d", a FATAL;
1623: if (fp != NULL) {
1624: files[i].fname = tostring(s);
1625: files[i].fp = fp;
1626: files[i].mode = m;
1627: }
1628: return fp;
1629: }
1630:
1631: char *filename(FILE *fp)
1632: {
1633: int i;
1634:
1635: for (i = 0; i < FOPEN_MAX; i++)
1636: if (fp == files[i].fp)
1637: return files[i].fname;
1638: return "???";
1639: }
1640:
1641: Cell *closefile(Node **a, int n)
1642: {
1643: Cell *x;
1644: int i, stat;
1645:
1646: n = 0;
1647: x = execute(a[0]);
1648: getsval(x);
1649: for (i = 0; i < FOPEN_MAX; i++)
1650: if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1651: if (ferror(files[i].fp))
1652: ERROR "i/o error occurred on %s", files[i].fname WARNING;
1653: if (files[i].mode == '|' || files[i].mode == LE)
1654: stat = pclose(files[i].fp);
1655: else
1656: stat = fclose(files[i].fp);
1657: if (stat == EOF)
1658: ERROR "i/o error occurred closing %s", files[i].fname WARNING;
1659: if (i > 2) /* don't do /dev/std... */
1660: xfree(files[i].fname);
1661: files[i].fname = NULL; /* watch out for ref thru this */
1662: files[i].fp = NULL;
1663: }
1664: tempfree(x);
1665: return(true);
1666: }
1667:
1668: void closeall(void)
1669: {
1670: int i, stat;
1671:
1672: for (i = 0; i < FOPEN_MAX; i++)
1673: if (files[i].fp) {
1674: if (ferror(files[i].fp))
1675: ERROR "i/o error occurred on %s", files[i].fname WARNING;
1676: if (files[i].mode == '|' || files[i].mode == LE)
1677: stat = pclose(files[i].fp);
1678: else
1679: stat = fclose(files[i].fp);
1680: if (stat == EOF)
1681: ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
1682: }
1683: }
1684:
1.13 kstailey 1685: void backsub(char **pb_ptr, char **sptr_ptr);
1.1 tholo 1686:
1687: Cell *sub(Node **a, int nnn) /* substitute command */
1688: {
1689: char *sptr, *pb, *q;
1690: Cell *x, *y, *result;
1.13 kstailey 1691: char *t, *buf;
1.1 tholo 1692: fa *pfa;
1.13 kstailey 1693: int bufsz = recsize;
1.1 tholo 1694:
1.13 kstailey 1695: if ((buf=malloc(bufsz)) == NULL)
1696: ERROR "out of memory in sub" FATAL;
1.1 tholo 1697: x = execute(a[3]); /* target string */
1698: t = getsval(x);
1699: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1700: pfa = (fa *) a[1]; /* regular expression */
1701: else {
1702: y = execute(a[1]);
1703: pfa = makedfa(getsval(y), 1);
1704: tempfree(y);
1705: }
1706: y = execute(a[2]); /* replacement string */
1707: result = false;
1708: if (pmatch(pfa, t)) {
1.13 kstailey 1709: sptr = t;
1710: adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
1.1 tholo 1711: pb = buf;
1712: while (sptr < patbeg)
1713: *pb++ = *sptr++;
1714: sptr = getsval(y);
1.13 kstailey 1715: while (*sptr != 0) {
1716: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
1717: if (*sptr == '\\') {
1718: backsub(&pb, &sptr);
1.1 tholo 1719: } else if (*sptr == '&') {
1720: sptr++;
1.13 kstailey 1721: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
1.1 tholo 1722: for (q = patbeg; q < patbeg+patlen; )
1723: *pb++ = *q++;
1724: } else
1725: *pb++ = *sptr++;
1.13 kstailey 1726: }
1.1 tholo 1727: *pb = '\0';
1.13 kstailey 1728: if (pb > buf + bufsz)
1729: ERROR "sub result1 %.30s too big; can't happen", buf FATAL;
1.1 tholo 1730: sptr = patbeg + patlen;
1.13 kstailey 1731: if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
1732: adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
1.1 tholo 1733: while ((*pb++ = *sptr++) != 0)
1734: ;
1.13 kstailey 1735: }
1736: if (pb > buf + bufsz)
1737: ERROR "sub result2 %.30s too big; can't happen", buf FATAL;
1738: setsval(x, buf); /* BUG: should be able to avoid copy */
1.1 tholo 1739: result = true;;
1740: }
1741: tempfree(x);
1742: tempfree(y);
1.13 kstailey 1743: free(buf);
1.1 tholo 1744: return result;
1745: }
1746:
1747: Cell *gsub(Node **a, int nnn) /* global substitute */
1748: {
1749: Cell *x, *y;
1.13 kstailey 1750: char *rptr, *sptr, *t, *pb, *q;
1751: char *buf;
1.1 tholo 1752: fa *pfa;
1753: int mflag, tempstat, num;
1.13 kstailey 1754: int bufsz = recsize;
1.1 tholo 1755:
1.13 kstailey 1756: if ((buf=malloc(bufsz)) == NULL)
1757: ERROR "out of memory in gsub" FATAL;
1.1 tholo 1758: mflag = 0; /* if mflag == 0, can replace empty string */
1759: num = 0;
1760: x = execute(a[3]); /* target string */
1761: t = getsval(x);
1762: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1763: pfa = (fa *) a[1]; /* regular expression */
1764: else {
1765: y = execute(a[1]);
1766: pfa = makedfa(getsval(y), 1);
1767: tempfree(y);
1768: }
1769: y = execute(a[2]); /* replacement string */
1770: if (pmatch(pfa, t)) {
1771: tempstat = pfa->initstat;
1772: pfa->initstat = 2;
1773: pb = buf;
1774: rptr = getsval(y);
1775: do {
1776: if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1777: if (mflag == 0) { /* can replace empty */
1778: num++;
1779: sptr = rptr;
1.13 kstailey 1780: while (*sptr != 0) {
1781: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1782: if (*sptr == '\\') {
1783: backsub(&pb, &sptr);
1.1 tholo 1784: } else if (*sptr == '&') {
1785: sptr++;
1.13 kstailey 1786: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1787: for (q = patbeg; q < patbeg+patlen; )
1788: *pb++ = *q++;
1789: } else
1790: *pb++ = *sptr++;
1.13 kstailey 1791: }
1.1 tholo 1792: }
1793: if (*t == 0) /* at end */
1794: goto done;
1.13 kstailey 1795: adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1796: *pb++ = *t++;
1.13 kstailey 1797: if (pb > buf + bufsz) /* BUG: not sure of this test */
1798: ERROR "gsub result0 %.30s too big; can't happen", buf FATAL;
1.1 tholo 1799: mflag = 0;
1800: }
1801: else { /* matched nonempty string */
1802: num++;
1803: sptr = t;
1.13 kstailey 1804: adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
1805: while (sptr < patbeg)
1.1 tholo 1806: *pb++ = *sptr++;
1807: sptr = rptr;
1.13 kstailey 1808: while (*sptr != 0) {
1809: adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
1810: if (*sptr == '\\') {
1811: backsub(&pb, &sptr);
1.1 tholo 1812: } else if (*sptr == '&') {
1813: sptr++;
1.13 kstailey 1814: adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
1.1 tholo 1815: for (q = patbeg; q < patbeg+patlen; )
1816: *pb++ = *q++;
1817: } else
1818: *pb++ = *sptr++;
1.13 kstailey 1819: }
1.1 tholo 1820: t = patbeg + patlen;
1821: if (patlen == 0 || *t == 0 || *(t-1) == 0)
1822: goto done;
1.13 kstailey 1823: if (pb > buf + bufsz)
1824: ERROR "gsub result1 %.30s too big; can't happen", buf FATAL;
1.1 tholo 1825: mflag = 1;
1826: }
1827: } while (pmatch(pfa,t));
1828: sptr = t;
1.13 kstailey 1829: adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
1.1 tholo 1830: while ((*pb++ = *sptr++) != 0)
1831: ;
1.13 kstailey 1832: done: if (pb > buf + bufsz)
1833: ERROR "gsub result2 %.30s too big; can't happen", buf FATAL;
1.1 tholo 1834: *pb = '\0';
1.13 kstailey 1835: setsval(x, buf); /* BUG: should be able to avoid copy + free */
1.1 tholo 1836: pfa->initstat = tempstat;
1837: }
1838: tempfree(x);
1839: tempfree(y);
1840: x = gettemp();
1841: x->tval = NUM;
1842: x->fval = num;
1.13 kstailey 1843: free(buf);
1.1 tholo 1844: return(x);
1.13 kstailey 1845: }
1846:
1847: void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
1848: { /* sptr[0] == '\\' */
1849: char *pb = *pb_ptr, *sptr = *sptr_ptr;
1850:
1851: if (sptr[1] == '\\') {
1852: if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
1853: *pb++ = '\\';
1854: *pb++ = '&';
1855: sptr += 4;
1856: } else if (sptr[2] == '&') { /* \\& -> \ + matched */
1857: *pb++ = '\\';
1858: sptr += 2;
1859: } else { /* \\x -> \\x */
1860: *pb++ = *sptr++;
1861: *pb++ = *sptr++;
1862: }
1863: } else if (sptr[1] == '&') { /* literal & */
1864: sptr++;
1865: *pb++ = *sptr++;
1866: } else /* literal \ */
1867: *pb++ = *sptr++;
1868:
1869: *pb_ptr = pb;
1870: *sptr_ptr = sptr;
1.1 tholo 1871: }