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