Annotation of src/usr.bin/awk/run.c, Revision 1.4
1.4 ! kstailey 1: /* $OpenBSD: run.c,v 1.3 1997/01/21 21:14:06 kstailey Exp $ */
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.4 ! kstailey 794: p += len += strlen(p);
1.1 tholo 795: sprintf((char *)p, "%s", getsval(x));
796: break;
797: case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break;
798: case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
799: case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
800: case 4:
801: t = getsval(x);
802: n = strlen(t);
803: if (n >= bufsize)
804: ERROR "huge string (%d chars) in printf %.30s...",
805: n, t FATAL;
806: sprintf((char *)p, (char *)fmt, t);
807: break;
808: case 5:
1.3 kstailey 809: isnum(x) ?
810: (getfval(x) ?
811: sprintf((char *)p, (char *)fmt, (int) getfval(x))
812: : len++)
1.1 tholo 813: : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
814: break;
815: }
816: tempfree(x);
1.4 ! kstailey 817: p += len += strlen(p);
1.1 tholo 818: s++;
819: }
820: *p = '\0';
821: for ( ; a; a = a->nnext) /* evaluate any remaining args */
822: execute(a);
1.3 kstailey 823: return (len);
1.1 tholo 824: }
825:
826: Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
827: {
828: Cell *x;
829: Node *y;
830: char buf[3*RECSIZE];
831:
832: y = a[0]->nnext;
833: x = execute(a[0]);
834: if (format(buf, sizeof buf, getsval(x), y) == -1)
835: ERROR "sprintf string %.30s... too long", buf FATAL;
836: tempfree(x);
837: x = gettemp();
838: x->sval = tostring(buf);
839: x->tval = STR;
840: return(x);
841: }
842:
843: Cell *awkprintf(Node **a, int n) /* printf */
844: { /* a[0] is list of args, starting with format string */
845: /* a[1] is redirection operator, a[2] is redirection file */
846: FILE *fp;
847: Cell *x;
848: Node *y;
849: char buf[3*RECSIZE];
1.3 kstailey 850: int len;
1.1 tholo 851:
852: y = a[0]->nnext;
853: x = execute(a[0]);
1.3 kstailey 854: if ((len = format(buf, sizeof buf, getsval(x), y)) == -1)
1.1 tholo 855: ERROR "printf string %.30s... too long", buf FATAL;
856: tempfree(x);
857: if (a[1] == NULL) {
1.3 kstailey 858: if (write(1, buf, len) != len)
1.1 tholo 859: ERROR "write error on stdout" FATAL;
860: } else {
861: fp = redirect((int)a[1], a[2]);
1.3 kstailey 862: ferror(fp); /* XXX paranoia */
863: if (write(fileno(fp), buf, len) != len)
1.1 tholo 864: ERROR "write error on %s", filename(fp) FATAL;
865: }
866: return(true);
867: }
868:
869: Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
870: {
871: Awkfloat i, j = 0;
872: double v;
873: Cell *x, *y, *z;
874:
875: x = execute(a[0]);
876: i = getfval(x);
877: tempfree(x);
878: if (n != UMINUS) {
879: y = execute(a[1]);
880: j = getfval(y);
881: tempfree(y);
882: }
883: z = gettemp();
884: switch (n) {
885: case ADD:
886: i += j;
887: break;
888: case MINUS:
889: i -= j;
890: break;
891: case MULT:
892: i *= j;
893: break;
894: case DIVIDE:
895: if (j == 0)
896: ERROR "division by zero" FATAL;
897: i /= j;
898: break;
899: case MOD:
900: if (j == 0)
901: ERROR "division by zero in mod" FATAL;
902: modf(i/j, &v);
903: i = i - j * v;
904: break;
905: case UMINUS:
906: i = -i;
907: break;
908: case POWER:
909: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
910: i = ipow(i, (int) j);
911: else
912: i = errcheck(pow(i, j), "pow");
913: break;
914: default: /* can't happen */
915: ERROR "illegal arithmetic operator %d", n FATAL;
916: }
917: setfval(z, i);
918: return(z);
919: }
920:
921: double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
922: {
923: double v;
924:
925: if (n <= 0)
926: return 1;
927: v = ipow(x, n/2);
928: if (n % 2 == 0)
929: return v * v;
930: else
931: return x * v * v;
932: }
933:
934: Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
935: {
936: Cell *x, *z;
937: int k;
938: Awkfloat xf;
939:
940: x = execute(a[0]);
941: xf = getfval(x);
942: k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
943: if (n == PREINCR || n == PREDECR) {
944: setfval(x, xf + k);
945: return(x);
946: }
947: z = gettemp();
948: setfval(z, xf);
949: setfval(x, xf + k);
950: tempfree(x);
951: return(z);
952: }
953:
954: Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
955: { /* this is subtle; don't muck with it. */
956: Cell *x, *y;
957: Awkfloat xf, yf;
958: double v;
959:
960: y = execute(a[1]);
961: x = execute(a[0]);
962: if (n == ASSIGN) { /* ordinary assignment */
963: if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
964: ; /* leave alone unless it's a field */
965: else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
966: setsval(x, getsval(y));
967: x->fval = getfval(y);
968: x->tval |= NUM;
969: }
970: else if (y->tval & STR)
971: setsval(x, getsval(y));
972: else if (y->tval & NUM)
973: setfval(x, getfval(y));
974: else
975: funnyvar(y, "read value of");
976: tempfree(y);
977: return(x);
978: }
979: xf = getfval(x);
980: yf = getfval(y);
981: switch (n) {
982: case ADDEQ:
983: xf += yf;
984: break;
985: case SUBEQ:
986: xf -= yf;
987: break;
988: case MULTEQ:
989: xf *= yf;
990: break;
991: case DIVEQ:
992: if (yf == 0)
993: ERROR "division by zero in /=" FATAL;
994: xf /= yf;
995: break;
996: case MODEQ:
997: if (yf == 0)
998: ERROR "division by zero in %%=" FATAL;
999: modf(xf/yf, &v);
1000: xf = xf - yf * v;
1001: break;
1002: case POWEQ:
1003: if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
1004: xf = ipow(xf, (int) yf);
1005: else
1006: xf = errcheck(pow(xf, yf), "pow");
1007: break;
1008: default:
1009: ERROR "illegal assignment operator %d", n FATAL;
1010: break;
1011: }
1012: tempfree(y);
1013: setfval(x, xf);
1014: return(x);
1015: }
1016:
1017: Cell *cat(Node **a, int q) /* a[0] cat a[1] */
1018: {
1019: Cell *x, *y, *z;
1020: int n1, n2;
1021: char *s;
1022:
1023: x = execute(a[0]);
1024: y = execute(a[1]);
1025: getsval(x);
1026: getsval(y);
1027: n1 = strlen(x->sval);
1028: n2 = strlen(y->sval);
1029: s = (char *) malloc(n1 + n2 + 1);
1030: if (s == NULL)
1031: ERROR "out of space concatenating %.15s... and %.15s...",
1032: x->sval, y->sval FATAL;
1033: strcpy(s, x->sval);
1034: strcpy(s+n1, y->sval);
1035: tempfree(y);
1036: z = gettemp();
1037: z->sval = s;
1038: z->tval = STR;
1039: tempfree(x);
1040: return(z);
1041: }
1042:
1043: Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
1044: {
1045: Cell *x;
1046:
1047: if (a[0] == 0)
1048: x = execute(a[1]);
1049: else {
1050: x = execute(a[0]);
1051: if (istrue(x)) {
1052: tempfree(x);
1053: x = execute(a[1]);
1054: }
1055: }
1056: return x;
1057: }
1058:
1059: Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
1060: {
1061: Cell *x;
1062: int pair;
1063:
1064: pair = (int) a[3];
1065: if (pairstack[pair] == 0) {
1066: x = execute(a[0]);
1067: if (istrue(x))
1068: pairstack[pair] = 1;
1069: tempfree(x);
1070: }
1071: if (pairstack[pair] == 1) {
1072: x = execute(a[1]);
1073: if (istrue(x))
1074: pairstack[pair] = 0;
1075: tempfree(x);
1076: x = execute(a[2]);
1077: return(x);
1078: }
1079: return(false);
1080: }
1081:
1082: Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
1083: {
1084: Cell *x = 0, *y, *ap;
1085: char *s;
1086: int sep;
1087: char *t, temp, num[10], *fs = 0;
1088: int n, tempstat;
1089:
1090: y = execute(a[0]); /* source string */
1091: s = getsval(y);
1092: if (a[2] == 0) /* fs string */
1093: fs = *FS;
1094: else if ((int) a[3] == STRING) { /* split(str,arr,"string") */
1095: x = execute(a[2]);
1096: fs = getsval(x);
1097: } else if ((int) a[3] == REGEXPR)
1098: fs = (char*) "(regexpr)"; /* split(str,arr,/regexpr/) */
1099: else
1100: ERROR "illegal type of split()" FATAL;
1101: sep = *fs;
1102: ap = execute(a[1]); /* array name */
1103: freesymtab(ap);
1104: dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
1105: ap->tval &= ~STR;
1106: ap->tval |= ARR;
1107: ap->sval = (char *) makesymtab(NSYMTAB);
1108:
1109: n = 0;
1110: if ((*s != '\0' && strlen(fs) > 1) || (int) a[3] == REGEXPR) { /* reg expr */
1111: fa *pfa;
1112: if ((int) a[3] == REGEXPR) { /* it's ready already */
1113: pfa = (fa *) a[2];
1114: } else {
1115: pfa = makedfa(fs, 1);
1116: }
1117: if (nematch(pfa,s)) {
1118: tempstat = pfa->initstat;
1119: pfa->initstat = 2;
1120: do {
1121: n++;
1122: sprintf((char *)num, "%d", n);
1123: temp = *patbeg;
1124: *patbeg = '\0';
1125: if (isnumber(s))
1126: setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
1127: else
1128: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1129: *patbeg = temp;
1130: s = patbeg + patlen;
1131: if (*(patbeg+patlen-1) == 0 || *s == 0) {
1132: n++;
1133: sprintf((char *)num, "%d", n);
1134: setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
1135: pfa->initstat = tempstat;
1136: goto spdone;
1137: }
1138: } while (nematch(pfa,s));
1139: }
1140: n++;
1141: sprintf((char *)num, "%d", n);
1142: if (isnumber(s))
1143: setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
1144: else
1145: setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
1146: spdone:
1147: pfa = NULL;
1148: } else if (sep == ' ') {
1149: for (n = 0; ; ) {
1150: while (*s == ' ' || *s == '\t' || *s == '\n')
1151: s++;
1152: if (*s == 0)
1153: break;
1154: n++;
1155: t = s;
1156: do
1157: s++;
1158: while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
1159: temp = *s;
1160: *s = '\0';
1161: sprintf((char *)num, "%d", n);
1162: if (isnumber(t))
1163: setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
1164: else
1165: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1166: *s = temp;
1167: if (*s != 0)
1168: s++;
1169: }
1170: } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1171: for (n = 0; *s != 0; s++) {
1172: char buf[2];
1173: n++;
1174: sprintf((char *)num, "%d", n);
1175: buf[0] = *s;
1176: buf[1] = 0;
1177: if (isdigit(buf[0]))
1178: setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
1179: else
1180: setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
1181: }
1182: } else if (*s != 0) {
1183: for (;;) {
1184: n++;
1185: t = s;
1186: while (*s != sep && *s != '\n' && *s != '\0')
1187: s++;
1188: temp = *s;
1189: *s = '\0';
1190: sprintf((char *)num, "%d", n);
1191: if (isnumber(t))
1192: setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
1193: else
1194: setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
1195: *s = temp;
1196: if (*s++ == 0)
1197: break;
1198: }
1199: }
1200: tempfree(ap);
1201: tempfree(y);
1202: if (a[2] != 0 && (int) a[3] == STRING)
1203: tempfree(x);
1204: x = gettemp();
1205: x->tval = NUM;
1206: x->fval = n;
1207: return(x);
1208: }
1209:
1210: Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
1211: {
1212: Cell *x;
1213:
1214: x = execute(a[0]);
1215: if (istrue(x)) {
1216: tempfree(x);
1217: x = execute(a[1]);
1218: } else {
1219: tempfree(x);
1220: x = execute(a[2]);
1221: }
1222: return(x);
1223: }
1224:
1225: Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
1226: {
1227: Cell *x;
1228:
1229: x = execute(a[0]);
1230: if (istrue(x)) {
1231: tempfree(x);
1232: x = execute(a[1]);
1233: } else if (a[2] != 0) {
1234: tempfree(x);
1235: x = execute(a[2]);
1236: }
1237: return(x);
1238: }
1239:
1240: Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
1241: {
1242: Cell *x;
1243:
1244: for (;;) {
1245: x = execute(a[0]);
1246: if (!istrue(x))
1247: return(x);
1248: tempfree(x);
1249: x = execute(a[1]);
1250: if (isbreak(x)) {
1251: x = true;
1252: return(x);
1253: }
1254: if (isnext(x) || isexit(x) || isret(x))
1255: return(x);
1256: tempfree(x);
1257: }
1258: }
1259:
1260: Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
1261: {
1262: Cell *x;
1263:
1264: for (;;) {
1265: x = execute(a[0]);
1266: if (isbreak(x))
1267: return true;
1268: if (isnext(x) || isnextfile(x) || isexit(x) || isret(x))
1269: return(x);
1270: tempfree(x);
1271: x = execute(a[1]);
1272: if (!istrue(x))
1273: return(x);
1274: tempfree(x);
1275: }
1276: }
1277:
1278: Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
1279: {
1280: Cell *x;
1281:
1282: x = execute(a[0]);
1283: tempfree(x);
1284: for (;;) {
1285: if (a[1]!=0) {
1286: x = execute(a[1]);
1287: if (!istrue(x)) return(x);
1288: else tempfree(x);
1289: }
1290: x = execute(a[3]);
1291: if (isbreak(x)) /* turn off break */
1292: return true;
1293: if (isnext(x) || isexit(x) || isret(x))
1294: return(x);
1295: tempfree(x);
1296: x = execute(a[2]);
1297: tempfree(x);
1298: }
1299: }
1300:
1301: Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1302: {
1303: Cell *x, *vp, *arrayp, *cp, *ncp;
1304: Array *tp;
1305: int i;
1306:
1307: vp = execute(a[0]);
1308: arrayp = execute(a[1]);
1309: if (!isarr(arrayp)) {
1310: return true;
1311: }
1312: tp = (Array *) arrayp->sval;
1313: tempfree(arrayp);
1314: for (i = 0; i < tp->size; i++) { /* this routine knows too much */
1315: for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
1316: setsval(vp, cp->nval);
1317: ncp = cp->cnext;
1318: x = execute(a[2]);
1319: if (isbreak(x)) {
1320: tempfree(vp);
1321: return true;
1322: }
1323: if (isnext(x) || isexit(x) || isret(x)) {
1324: tempfree(vp);
1325: return(x);
1326: }
1327: tempfree(x);
1328: }
1329: }
1330: return true;
1331: }
1332:
1333: #if 0
1334: /* if someone ever wants to run over the arrays in sorted order, */
1335: /* here it is. but it will likely run slower, not faster. */
1336:
1337: int qstrcmp(p, q)
1338: char **p, **q;
1339: {
1340: return strcmp(*p, *q);
1341: }
1342:
1343: Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
1344: {
1345: Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
1346: Array *tp;
1347: int i, ne;
1348: #define BIGENOUGH 1000
1349: char *elems[BIGENOUGH], **ep;
1350:
1351: vp = execute(a[0]);
1352: arrayp = execute(a[1]);
1353: if (!isarr(arrayp))
1354: ERROR "%s is not an array", arrayp->nval FATAL;
1355: tp = (Array *) arrayp->sval;
1356: tempfree(arrayp);
1357: ep = elems;
1358: ret = true;
1359: if (tp->nelem >= BIGENOUGH)
1360: ep = (char **) malloc(tp->nelem * sizeof(char *));
1361:
1362: for (i = ne = 0; i < tp->size; i++)
1363: for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
1364: ep[ne++] = cp->nval;
1365: if (ne != tp->nelem)
1366: ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
1367: qsort(ep, ne, sizeof(char *), qstrcmp);
1368: for (i = 0; i < ne; i++) {
1369: setsval(vp, ep[i]);
1370: x = execute(a[2]);
1371: if (isbreak(x)) {
1372: tempfree(vp);
1373: break;
1374: }
1375: if (isnext(x) || isnextfile(x) || isexit(x) || isret(x)) {
1376: tempfree(vp);
1377: ret = x;
1378: break;
1379: }
1380: tempfree(x);
1381: }
1382: if (ep != elems)
1383: free(ep);
1384: return ret;
1385: }
1386: #endif
1387:
1388:
1389: Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
1390: {
1391: Cell *x, *y;
1392: Awkfloat u;
1393: int t;
1394: char *p, buf[RECSIZE];
1395: Node *nextarg;
1396: FILE *fp;
1397:
1398: t = (int) a[0];
1399: x = execute(a[1]);
1400: nextarg = a[1]->nnext;
1401: switch (t) {
1402: case FLENGTH:
1403: u = strlen(getsval(x)); break;
1404: case FLOG:
1405: u = errcheck(log(getfval(x)), "log"); break;
1406: case FINT:
1407: modf(getfval(x), &u); break;
1408: case FEXP:
1409: u = errcheck(exp(getfval(x)), "exp"); break;
1410: case FSQRT:
1411: u = errcheck(sqrt(getfval(x)), "sqrt"); break;
1412: case FSIN:
1413: u = sin(getfval(x)); break;
1414: case FCOS:
1415: u = cos(getfval(x)); break;
1416: case FATAN:
1417: if (nextarg == 0) {
1418: ERROR "atan2 requires two arguments; returning 1.0" WARNING;
1419: u = 1.0;
1420: } else {
1421: y = execute(a[1]->nnext);
1422: u = atan2(getfval(x), getfval(y));
1423: tempfree(y);
1424: nextarg = nextarg->nnext;
1425: }
1426: break;
1427: case FSYSTEM:
1428: fflush(stdout); /* in case something is buffered already */
1429: u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */
1430: break;
1431: case FRAND:
1432: /* in principle, rand() returns something in 0..RAND_MAX */
1433: u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
1434: break;
1435: case FSRAND:
1436: if (x->tval & REC) /* no argument provided */
1437: u = time((time_t *)0);
1438: else
1439: u = getfval(x);
1440: srand((int) u); u = (int) u;
1441: break;
1442: case FTOUPPER:
1443: case FTOLOWER:
1444: strcpy(buf, getsval(x));
1445: if (t == FTOUPPER) {
1446: for (p = buf; *p; p++)
1447: if (islower(*p))
1448: *p = toupper(*p);
1449: } else {
1450: for (p = buf; *p; p++)
1451: if (isupper(*p))
1452: *p = tolower(*p);
1453: }
1454: tempfree(x);
1455: x = gettemp();
1456: setsval(x, buf);
1457: return x;
1458: case FFLUSH:
1459: if ((fp = openfile(GT, getsval(x))) == NULL)
1460: u = EOF;
1461: else
1462: u = fflush(fp);
1463: break;
1464: default: /* can't happen */
1465: ERROR "illegal function type %d", t FATAL;
1466: break;
1467: }
1468: tempfree(x);
1469: x = gettemp();
1470: setfval(x, u);
1471: if (nextarg != 0) {
1472: ERROR "warning: function has too many arguments" WARNING;
1473: for ( ; nextarg; nextarg = nextarg->nnext)
1474: execute(nextarg);
1475: }
1476: return(x);
1477: }
1478:
1479: Cell *printstat(Node **a, int n) /* print a[0] */
1480: {
1481: Node *x;
1482: Cell *y;
1483: FILE *fp;
1484:
1485: if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
1486: fp = stdout;
1487: else
1488: fp = redirect((int)a[1], a[2]);
1489: for (x = a[0]; x != NULL; x = x->nnext) {
1490: y = execute(x);
1491: fputs((char *)getsval(y), fp);
1492: tempfree(y);
1493: if (x->nnext == NULL)
1494: fputs((char *)*ORS, fp);
1495: else
1496: fputs((char *)*OFS, fp);
1497: }
1498: if (a[1] != 0)
1499: fflush(fp);
1500: if (ferror(fp))
1501: ERROR "write error on %s", filename(fp) FATAL;
1502: return(true);
1503: }
1504:
1505: Cell *nullproc(Node **a, int n)
1506: {
1507: n = 0;
1508: a = 0;
1509: return 0;
1510: }
1511:
1512:
1513: FILE *redirect(int a, Node *b) /* set up all i/o redirections */
1514: {
1515: FILE *fp;
1516: Cell *x;
1517: char *fname;
1518:
1519: x = execute(b);
1520: fname = getsval(x);
1521: fp = openfile(a, fname);
1522: if (fp == NULL)
1523: ERROR "can't open file %s", fname FATAL;
1524: tempfree(x);
1525: return fp;
1526: }
1527:
1528: struct files {
1529: FILE *fp;
1530: char *fname;
1531: int mode; /* '|', 'a', 'w' => LE/LT, GT */
1532: } files[FOPEN_MAX] ={
1533: { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */
1534: { stdout, "/dev/stdout", GT },
1535: { stderr, "/dev/stderr", GT }
1536: };
1537:
1538: FILE *openfile(int a, char *us)
1539: {
1540: char *s = us;
1541: int i, m;
1542: FILE *fp = 0;
1543:
1544: if (*s == '\0')
1545: ERROR "null file name in print or getline" FATAL;
1546: for (i=0; i < FOPEN_MAX; i++)
1547: if (files[i].fname && strcmp(s, files[i].fname) == 0)
1548: if (a == files[i].mode || (a==APPEND && files[i].mode==GT))
1549: return files[i].fp;
1550: for (i=0; i < FOPEN_MAX; i++)
1551: if (files[i].fp == 0)
1552: break;
1553: if (i >= FOPEN_MAX)
1554: ERROR "%s makes too many open files", s FATAL;
1555: fflush(stdout); /* force a semblance of order */
1556: m = a;
1557: if (a == GT) {
1558: fp = fopen(s, "w");
1559: } else if (a == APPEND) {
1560: fp = fopen(s, "a");
1561: m = GT; /* so can mix > and >> */
1562: } else if (a == '|') { /* output pipe */
1563: fp = popen(s, "w");
1564: } else if (a == LE) { /* input pipe */
1565: fp = popen(s, "r");
1566: } else if (a == LT) { /* getline <file */
1567: fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
1568: } else /* can't happen */
1569: ERROR "illegal redirection %d", a FATAL;
1570: if (fp != NULL) {
1571: files[i].fname = tostring(s);
1572: files[i].fp = fp;
1573: files[i].mode = m;
1574: }
1575: return fp;
1576: }
1577:
1578: char *filename(FILE *fp)
1579: {
1580: int i;
1581:
1582: for (i = 0; i < FOPEN_MAX; i++)
1583: if (fp == files[i].fp)
1584: return files[i].fname;
1585: return "???";
1586: }
1587:
1588: Cell *closefile(Node **a, int n)
1589: {
1590: Cell *x;
1591: int i, stat;
1592:
1593: n = 0;
1594: x = execute(a[0]);
1595: getsval(x);
1596: for (i = 0; i < FOPEN_MAX; i++)
1597: if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
1598: if (ferror(files[i].fp))
1599: ERROR "i/o error occurred on %s", files[i].fname WARNING;
1600: if (files[i].mode == '|' || files[i].mode == LE)
1601: stat = pclose(files[i].fp);
1602: else
1603: stat = fclose(files[i].fp);
1604: if (stat == EOF)
1605: ERROR "i/o error occurred closing %s", files[i].fname WARNING;
1606: if (i > 2) /* don't do /dev/std... */
1607: xfree(files[i].fname);
1608: files[i].fname = NULL; /* watch out for ref thru this */
1609: files[i].fp = NULL;
1610: }
1611: tempfree(x);
1612: return(true);
1613: }
1614:
1615: void closeall(void)
1616: {
1617: int i, stat;
1618:
1619: for (i = 0; i < FOPEN_MAX; i++)
1620: if (files[i].fp) {
1621: if (ferror(files[i].fp))
1622: ERROR "i/o error occurred on %s", files[i].fname WARNING;
1623: if (files[i].mode == '|' || files[i].mode == LE)
1624: stat = pclose(files[i].fp);
1625: else
1626: stat = fclose(files[i].fp);
1627: if (stat == EOF)
1628: ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
1629: }
1630: }
1631:
1632: #define SUBSIZE (20 * RECSIZE)
1633:
1634: Cell *sub(Node **a, int nnn) /* substitute command */
1635: {
1636: char *sptr, *pb, *q;
1637: Cell *x, *y, *result;
1638: char buf[SUBSIZE], *t;
1639: fa *pfa;
1640:
1641: x = execute(a[3]); /* target string */
1642: t = getsval(x);
1643: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1644: pfa = (fa *) a[1]; /* regular expression */
1645: else {
1646: y = execute(a[1]);
1647: pfa = makedfa(getsval(y), 1);
1648: tempfree(y);
1649: }
1650: y = execute(a[2]); /* replacement string */
1651: result = false;
1652: if (pmatch(pfa, t)) {
1653: pb = buf;
1654: sptr = t;
1655: while (sptr < patbeg)
1656: *pb++ = *sptr++;
1657: sptr = getsval(y);
1658: while (*sptr != 0 && pb < buf + SUBSIZE - 1)
1659: if (*sptr == '\\' && *(sptr+1) == '&') {
1660: sptr++; /* skip \, */
1661: *pb++ = *sptr++; /* add & */
1662: } else if (*sptr == '&') {
1663: sptr++;
1664: for (q = patbeg; q < patbeg+patlen; )
1665: *pb++ = *q++;
1666: } else
1667: *pb++ = *sptr++;
1668: *pb = '\0';
1669: if (pb >= buf + SUBSIZE)
1670: ERROR "sub() result %.30s too big", buf FATAL;
1671: sptr = patbeg + patlen;
1672: if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
1673: while ((*pb++ = *sptr++) != 0)
1674: ;
1675: if (pb >= buf + SUBSIZE)
1676: ERROR "sub() result %.30s too big", buf FATAL;
1677: setsval(x, buf);
1678: result = true;;
1679: }
1680: tempfree(x);
1681: tempfree(y);
1682: return result;
1683: }
1684:
1685: Cell *gsub(Node **a, int nnn) /* global substitute */
1686: {
1687: Cell *x, *y;
1688: char *rptr, *sptr, *t, *pb;
1689: char buf[SUBSIZE];
1690: fa *pfa;
1691: int mflag, tempstat, num;
1692:
1693: mflag = 0; /* if mflag == 0, can replace empty string */
1694: num = 0;
1695: x = execute(a[3]); /* target string */
1696: t = getsval(x);
1697: if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
1698: pfa = (fa *) a[1]; /* regular expression */
1699: else {
1700: y = execute(a[1]);
1701: pfa = makedfa(getsval(y), 1);
1702: tempfree(y);
1703: }
1704: y = execute(a[2]); /* replacement string */
1705: if (pmatch(pfa, t)) {
1706: tempstat = pfa->initstat;
1707: pfa->initstat = 2;
1708: pb = buf;
1709: rptr = getsval(y);
1710: do {
1711: /*
1712: char *p;
1713: int i;
1714: printf("target string: %s, *patbeg = %o, patlen = %d\n",
1715: t, *patbeg, patlen);
1716: printf(" match found: ");
1717: p=patbeg;
1718: for (i=0; i<patlen; i++)
1719: printf("%c", *p++);
1720: printf("\n");
1721: */
1722: if (patlen == 0 && *patbeg != 0) { /* matched empty string */
1723: if (mflag == 0) { /* can replace empty */
1724: num++;
1725: sptr = rptr;
1726: while (*sptr != 0 && pb < buf + SUBSIZE-1)
1727: if (*sptr == '\\' && *(sptr+1) == '&') {
1728: sptr++;
1729: *pb++ = *sptr++;
1730: } else if (*sptr == '&') {
1731: char *q;
1732: sptr++;
1733: for (q = patbeg; q < patbeg+patlen; )
1734: *pb++ = *q++;
1735: } else
1736: *pb++ = *sptr++;
1737: }
1738: if (*t == 0) /* at end */
1739: goto done;
1740: *pb++ = *t++;
1741: if (pb >= buf + SUBSIZE-1)
1742: ERROR "gsub() result %.30s too big", buf FATAL;
1743: mflag = 0;
1744: }
1745: else { /* matched nonempty string */
1746: num++;
1747: /* if (patlen <= 0)
1748: ERROR "4: buf=%s, patlen %d, t=%s, patbeg=%s", buf, patlen, t, patbeg WARNING; */
1749: sptr = t;
1750: while (sptr < patbeg && pb < buf + SUBSIZE-1)
1751: *pb++ = *sptr++;
1752: sptr = rptr;
1753: while (*sptr != 0 && pb < buf + SUBSIZE-1)
1754: if (*sptr == '\\' && *(sptr+1) == '&') {
1755: sptr++;
1756: *pb++ = *sptr++;
1757: } else if (*sptr == '&') {
1758: char *q;
1759: sptr++;
1760: for (q = patbeg; q < patbeg+patlen; )
1761: *pb++ = *q++;
1762: } else
1763: *pb++ = *sptr++;
1764: t = patbeg + patlen;
1765: if (patlen == 0 || *t == 0 || *(t-1) == 0)
1766: goto done;
1767: if (pb >= buf + SUBSIZE-1)
1768: ERROR "gsub() result %.30s too big", buf FATAL;
1769: mflag = 1;
1770: }
1771: } while (pmatch(pfa,t));
1772: sptr = t;
1773: while ((*pb++ = *sptr++) != 0)
1774: ;
1775: done: if (pb >= buf + SUBSIZE-1)
1776: ERROR "gsub() result %.30s too big", buf FATAL;
1777: *pb = '\0';
1778: setsval(x, buf);
1779: pfa->initstat = tempstat;
1780: }
1781: tempfree(x);
1782: tempfree(y);
1783: x = gettemp();
1784: x->tval = NUM;
1785: x->fval = num;
1786: return(x);
1787: }