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