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