165393Sbostic /****************************************************************
265393Sbostic Copyright (C) AT&T 1993
365393Sbostic All Rights Reserved
465393Sbostic
565393Sbostic Permission to use, copy, modify, and distribute this software and
665393Sbostic its documentation for any purpose and without fee is hereby
765393Sbostic granted, provided that the above copyright notice appear in all
865393Sbostic copies and that both that the copyright notice and this
965393Sbostic permission notice and warranty disclaimer appear in supporting
1065393Sbostic documentation, and that the name of AT&T or any of its entities
1165393Sbostic not be used in advertising or publicity pertaining to
1265393Sbostic distribution of the software without specific, written prior
1365393Sbostic permission.
1465393Sbostic
1565393Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1665393Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1765393Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1865393Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1965393Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2065393Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2165393Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2265393Sbostic THIS SOFTWARE.
2365393Sbostic ****************************************************************/
2465393Sbostic
2565393Sbostic #define tempfree(x) if (istemp(x)) tfree(x); else
2665393Sbostic
2765393Sbostic #define DEBUG
2865393Sbostic #include <stdio.h>
2965393Sbostic #include <ctype.h>
3065393Sbostic #include <setjmp.h>
3165393Sbostic #include <math.h>
3265393Sbostic #include <string.h>
3365393Sbostic #include <stdlib.h>
3465393Sbostic #include <time.h>
3565393Sbostic #include "awk.h"
3665393Sbostic #include "y.tab.h"
3765393Sbostic
3865393Sbostic #ifdef _NFILE
3965393Sbostic #ifndef FOPEN_MAX
4065393Sbostic #define FOPEN_MAX _NFILE
4165393Sbostic #endif
4265393Sbostic #endif
4365393Sbostic
4465393Sbostic #ifndef FOPEN_MAX
4565393Sbostic #define FOPEN_MAX 40 /* max number of open files */
4665393Sbostic #endif
4765393Sbostic
4865393Sbostic #ifndef RAND_MAX
4965393Sbostic #define RAND_MAX 32767 /* all that ansi guarantees */
5065393Sbostic #endif
5165393Sbostic
5265393Sbostic jmp_buf env;
5365393Sbostic
5465393Sbostic /* an attempt to go a bit faster: */
5565393Sbostic
5665393Sbostic /* #define execute(p) (isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
5765393Sbostic #define execute(p) r_execute(p)
5865393Sbostic #define getfval(p) (((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
5965393Sbostic #define getsval(p) (((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
6065393Sbostic
6165393Sbostic
6265393Sbostic #define PA2NUM 29 /* max number of pat,pat patterns allowed */
6365393Sbostic int paircnt; /* number of them in use */
6465393Sbostic int pairstack[PA2NUM]; /* state of each pat,pat */
6565393Sbostic
6665393Sbostic Node *winner = NULL; /* root of parse tree */
6765393Sbostic Cell *tmps; /* free temporary cells for execution */
6865393Sbostic
6965393Sbostic static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7065393Sbostic Cell *true = &truecell;
7165393Sbostic static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
7265393Sbostic Cell *false = &falsecell;
7365393Sbostic static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
7465393Sbostic Cell *jbreak = &breakcell;
7565393Sbostic static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
7665393Sbostic Cell *jcont = &contcell;
7765393Sbostic static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
7865393Sbostic Cell *jnext = &nextcell;
7965393Sbostic static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
8065393Sbostic Cell *jexit = &exitcell;
8165393Sbostic static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
8265393Sbostic Cell *jret = &retcell;
8365393Sbostic static Cell tempcell ={ OCELL, CTEMP, 0, 0, 0.0, NUM };
8465393Sbostic
8565393Sbostic Node *curnode = NULL; /* the node being executed, for debugging */
8665393Sbostic
run(Node * a)8765393Sbostic void run(Node *a) /* execution of parse tree starts here */
8865393Sbostic {
8965393Sbostic execute(a);
9065393Sbostic closeall();
9165393Sbostic }
9265393Sbostic
r_execute(Node * u)9365393Sbostic Cell *r_execute(Node *u) /* execute a node of the parse tree */
9465393Sbostic {
9565393Sbostic register Cell *(*proc)(Node **, int);
9665393Sbostic register Cell *x;
9765393Sbostic register Node *a;
9865393Sbostic
9965393Sbostic if (u == NULL)
10065393Sbostic return(true);
10165393Sbostic for (a = u; ; a = a->nnext) {
10265393Sbostic curnode = a;
10365393Sbostic if (isvalue(a)) {
10465393Sbostic x = (Cell *) (a->narg[0]);
10565393Sbostic if ((x->tval & FLD) && !donefld)
10665393Sbostic fldbld();
10765393Sbostic else if ((x->tval & REC) && !donerec)
10865393Sbostic recbld();
10965393Sbostic return(x);
11065393Sbostic }
11165393Sbostic if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
11265393Sbostic ERROR "illegal statement" FATAL;
11365393Sbostic proc = proctab[a->nobj-FIRSTTOKEN];
11465393Sbostic x = (*proc)(a->narg, a->nobj);
11565393Sbostic if ((x->tval & FLD) && !donefld)
11665393Sbostic fldbld();
11765393Sbostic else if ((x->tval & REC) && !donerec)
11865393Sbostic recbld();
11965393Sbostic if (isexpr(a))
12065393Sbostic return(x);
12165393Sbostic if (isjump(x))
12265393Sbostic return(x);
12365393Sbostic if (a->nnext == NULL)
12465393Sbostic return(x);
12565393Sbostic tempfree(x);
12665393Sbostic }
12765393Sbostic }
12865393Sbostic
12965393Sbostic
program(Node ** a,int n)13065393Sbostic Cell *program(Node **a, int n) /* execute an awk program */
13165393Sbostic { /* a[0] = BEGIN, a[1] = body, a[2] = END */
13265393Sbostic register Cell *x;
13365393Sbostic
13465393Sbostic if (setjmp(env) != 0)
13565393Sbostic goto ex;
13665393Sbostic if (a[0]) { /* BEGIN */
13765393Sbostic x = execute(a[0]);
13865393Sbostic if (isexit(x))
13965393Sbostic return(true);
14065393Sbostic if (isjump(x))
14165393Sbostic ERROR "illegal break, continue or next from BEGIN" FATAL;
14265393Sbostic tempfree(x);
14365393Sbostic }
14465393Sbostic loop:
14565393Sbostic if (a[1] || a[2])
14665393Sbostic while (getrec(record) > 0) {
14765393Sbostic x = execute(a[1]);
14865393Sbostic if (isexit(x))
14965393Sbostic break;
15065393Sbostic tempfree(x);
15165393Sbostic }
15265393Sbostic ex:
15365393Sbostic if (setjmp(env) != 0) /* handles exit within END */
15465393Sbostic goto ex1;
15565393Sbostic if (a[2]) { /* END */
15665393Sbostic x = execute(a[2]);
15765393Sbostic if (isbreak(x) || isnext(x) || iscont(x))
15865393Sbostic ERROR "illegal break, next, or continue from END" FATAL;
15965393Sbostic tempfree(x);
16065393Sbostic }
16165393Sbostic ex1:
16265393Sbostic return(true);
16365393Sbostic }
16465393Sbostic
16565393Sbostic struct Frame { /* stack frame for awk function calls */
16665393Sbostic int nargs; /* number of arguments in this call */
16765393Sbostic Cell *fcncell; /* pointer to Cell for function */
16865393Sbostic Cell **args; /* pointer to array of arguments after execute */
16965393Sbostic Cell *retval; /* return value */
17065393Sbostic };
17165393Sbostic
17265393Sbostic #define NARGS 50 /* max args in a call */
17365393Sbostic
17465393Sbostic struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
17565393Sbostic int nframe = 0; /* number of frames allocated */
17665393Sbostic struct Frame *fp = NULL; /* frame pointer. bottom level unused */
17765393Sbostic
call(Node ** a,int n)17865393Sbostic Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
17965393Sbostic {
18065393Sbostic static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
18165393Sbostic int i, ncall, ndef;
18265393Sbostic Node *x;
18365393Sbostic Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
18465393Sbostic uchar *s;
18565393Sbostic
18665393Sbostic fcn = execute(a[0]); /* the function itself */
18765393Sbostic s = fcn->nval;
18865393Sbostic if (!isfunc(fcn))
18965393Sbostic ERROR "calling undefined function %s", s FATAL;
19065393Sbostic if (frame == NULL) {
19165393Sbostic fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
19265393Sbostic if (frame == NULL)
19365393Sbostic ERROR "out of space for stack frames calling %s", s FATAL;
19465393Sbostic }
19565393Sbostic for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
19665393Sbostic ncall++;
19765393Sbostic ndef = (int) fcn->fval; /* args in defn */
19865393Sbostic dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
19965393Sbostic if (ncall > ndef)
20065393Sbostic ERROR "function %s called with %d args, uses only %d",
20165393Sbostic s, ncall, ndef WARNING;
20265393Sbostic if (ncall + ndef > NARGS)
20365393Sbostic ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
20465393Sbostic for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
20565393Sbostic dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
20665393Sbostic y = execute(x);
20765393Sbostic oargs[i] = y;
20865393Sbostic dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
20965393Sbostic i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
21065393Sbostic if (isfunc(y))
21165393Sbostic ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
21265393Sbostic if (isarr(y))
21365393Sbostic args[i] = y; /* arrays by ref */
21465393Sbostic else
21565393Sbostic args[i] = copycell(y);
21665393Sbostic tempfree(y);
21765393Sbostic }
21865393Sbostic for ( ; i < ndef; i++) { /* add null args for ones not provided */
21965393Sbostic args[i] = gettemp();
22065393Sbostic *args[i] = newcopycell;
22165393Sbostic }
22265393Sbostic fp++; /* now ok to up frame */
22365393Sbostic if (fp >= frame + nframe) {
22465393Sbostic int dfp = fp - frame; /* old index */
22565393Sbostic frame = (struct Frame *)
22665393Sbostic realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
22765393Sbostic if (frame == NULL)
22865393Sbostic ERROR "out of space for stack frames in %s", s FATAL;
22965393Sbostic fp = frame + dfp;
23065393Sbostic }
23165393Sbostic fp->fcncell = fcn;
23265393Sbostic fp->args = args;
23365393Sbostic fp->nargs = ndef; /* number defined with (excess are locals) */
23465393Sbostic fp->retval = gettemp();
23565393Sbostic
23665393Sbostic dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
23765393Sbostic y = execute((Node *)(fcn->sval)); /* execute body */
23865393Sbostic dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
23965393Sbostic
24065393Sbostic for (i = 0; i < ndef; i++) {
24165393Sbostic Cell *t = fp->args[i];
24265393Sbostic if (isarr(t)) {
24365393Sbostic if (t->csub == CCOPY) {
24465393Sbostic if (i >= ncall) {
24565393Sbostic freesymtab(t);
24665393Sbostic t->csub = CTEMP;
24765393Sbostic } else {
24865393Sbostic oargs[i]->tval = t->tval;
24965393Sbostic oargs[i]->tval &= ~(STR|NUM|DONTFREE);
25065393Sbostic oargs[i]->sval = t->sval;
25165393Sbostic tempfree(t);
25265393Sbostic }
25365393Sbostic }
25465393Sbostic } else if (t != y) { /* kludge to prevent freeing twice */
25565393Sbostic t->csub = CTEMP;
25665393Sbostic tempfree(t);
25765393Sbostic }
25865393Sbostic }
25965393Sbostic tempfree(fcn);
26065393Sbostic if (isexit(y) || isnext(y))
26165393Sbostic return y;
26265393Sbostic tempfree(y); /* this can free twice! */
26365393Sbostic z = fp->retval; /* return value */
26465393Sbostic dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
26565393Sbostic fp--;
26665393Sbostic return(z);
26765393Sbostic }
26865393Sbostic
copycell(Cell * x)26965393Sbostic Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
27065393Sbostic {
27165393Sbostic Cell *y;
27265393Sbostic
27365393Sbostic y = gettemp();
27465393Sbostic y->csub = CCOPY; /* prevents freeing until call is over */
27565393Sbostic y->nval = x->nval;
27665393Sbostic y->sval = x->sval ? tostring(x->sval) : NULL;
27765393Sbostic y->fval = x->fval;
27865393Sbostic y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
27965393Sbostic /* is DONTFREE right? */
28065393Sbostic return y;
28165393Sbostic }
28265393Sbostic
arg(Node ** a,int n)28365393Sbostic Cell *arg(Node **a, int n) /* nth argument of a function */
28465393Sbostic {
28565393Sbostic
28665393Sbostic n = (int) a[0]; /* argument number, counting from 0 */
28765393Sbostic dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
28865393Sbostic if (n+1 > fp->nargs)
28965393Sbostic ERROR "argument #%d of function %s was not supplied",
29065393Sbostic n+1, fp->fcncell->nval FATAL;
29165393Sbostic return fp->args[n];
29265393Sbostic }
29365393Sbostic
jump(Node ** a,int n)29465393Sbostic Cell *jump(Node **a, int n) /* break, continue, next, continue, return */
29565393Sbostic {
29665393Sbostic register Cell *y;
29765393Sbostic
29865393Sbostic switch (n) {
29965393Sbostic case EXIT:
30065393Sbostic if (a[0] != NULL) {
30165393Sbostic y = execute(a[0]);
30265393Sbostic errorflag = getfval(y);
30365393Sbostic tempfree(y);
30465393Sbostic }
30565393Sbostic longjmp(env, 1);
30665393Sbostic case RETURN:
30765393Sbostic if (a[0] != NULL) {
30865393Sbostic y = execute(a[0]);
30965393Sbostic if ((y->tval & (STR|NUM)) == (STR|NUM)) {
31065393Sbostic setsval(fp->retval, getsval(y));
31165393Sbostic fp->retval->fval = getfval(y);
31265393Sbostic fp->retval->tval |= NUM;
31365393Sbostic }
31465393Sbostic else if (y->tval & STR)
31565393Sbostic setsval(fp->retval, getsval(y));
31665393Sbostic else if (y->tval & NUM)
31765393Sbostic setfval(fp->retval, getfval(y));
31865393Sbostic else /* can't happen */
31965393Sbostic ERROR "bad type variable %d", y->tval FATAL;
32065393Sbostic tempfree(y);
32165393Sbostic }
32265393Sbostic return(jret);
32365393Sbostic case NEXT:
32465393Sbostic return(jnext);
32565393Sbostic case BREAK:
32665393Sbostic return(jbreak);
32765393Sbostic case CONTINUE:
32865393Sbostic return(jcont);
32965393Sbostic default: /* can't happen */
33065393Sbostic ERROR "illegal jump type %d", n FATAL;
33165393Sbostic }
33265393Sbostic return 0; /* not reached */
33365393Sbostic }
33465393Sbostic
getline(Node ** a,int n)33565393Sbostic Cell *getline(Node **a, int n) /* get next line from specific input */
33665393Sbostic { /* a[0] is variable, a[1] is operator, a[2] is filename */
33765393Sbostic register Cell *r, *x;
33865393Sbostic uchar buf[RECSIZE];
33965393Sbostic FILE *fp;
34065393Sbostic
34165393Sbostic fflush(stdout); /* in case someone is waiting for a prompt */
34265393Sbostic r = gettemp();
34365393Sbostic if (a[1] != NULL) { /* getline < file */
34465393Sbostic x = execute(a[2]); /* filename */
34565393Sbostic if ((int) a[1] == '|') /* input pipe */
34665393Sbostic a[1] = (Node *) LE; /* arbitrary flag */
34765393Sbostic fp = openfile((int) a[1], getsval(x));
34865393Sbostic tempfree(x);
34965393Sbostic if (fp == NULL)
35065393Sbostic n = -1;
35165393Sbostic else
35265393Sbostic n = readrec(buf, sizeof(buf), fp);
35365393Sbostic if (n <= 0) {
35465393Sbostic ;
35565393Sbostic } else if (a[0] != NULL) { /* getline var <file */
35665393Sbostic setsval(execute(a[0]), buf);
35765393Sbostic } else { /* getline <file */
35865393Sbostic if (!(recloc->tval & DONTFREE))
35965393Sbostic xfree(recloc->sval);
36065393Sbostic strcpy(record, buf);
36165393Sbostic recloc->sval = record;
36265393Sbostic recloc->tval = REC | STR | DONTFREE;
363*65396Sbostic if (is_a_number(recloc->sval)) {
36465393Sbostic recloc->fval = atof(recloc->sval);
36565393Sbostic recloc->tval |= NUM;
36665393Sbostic }
36765393Sbostic donerec = 1; donefld = 0;
36865393Sbostic }
36965393Sbostic } else { /* bare getline; use current input */
37065393Sbostic if (a[0] == NULL) /* getline */
37165393Sbostic n = getrec(record);
37265393Sbostic else { /* getline var */
37365393Sbostic n = getrec(buf);
37465393Sbostic setsval(execute(a[0]), buf);
37565393Sbostic }
37665393Sbostic }
37765393Sbostic setfval(r, (Awkfloat) n);
37865393Sbostic return r;
37965393Sbostic }
38065393Sbostic
getnf(Node ** a,int n)38165393Sbostic Cell *getnf(Node **a, int n) /* get NF */
38265393Sbostic {
38365393Sbostic if (donefld == 0)
38465393Sbostic fldbld();
38565393Sbostic return (Cell *) a[0];
38665393Sbostic }
38765393Sbostic
array(Node ** a,int n)38865393Sbostic Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
38965393Sbostic {
39065393Sbostic register Cell *x, *y, *z;
39165393Sbostic register uchar *s;
39265393Sbostic register Node *np;
39365393Sbostic uchar buf[RECSIZE];
39465393Sbostic
39565393Sbostic x = execute(a[0]); /* Cell* for symbol table */
39665393Sbostic buf[0] = 0;
39765393Sbostic for (np = a[1]; np; np = np->nnext) {
39865393Sbostic y = execute(np); /* subscript */
39965393Sbostic s = getsval(y);
40065393Sbostic strcat(buf, s);
40165393Sbostic if (np->nnext)
40265393Sbostic strcat(buf, *SUBSEP);
40365393Sbostic tempfree(y);
40465393Sbostic }
40565393Sbostic if (!isarr(x)) {
40665393Sbostic dprintf( ("making %s into an array\n", x->nval) );
40765393Sbostic if (freeable(x))
40865393Sbostic xfree(x->sval);
40965393Sbostic x->tval &= ~(STR|NUM|DONTFREE);
41065393Sbostic x->tval |= ARR;
41165393Sbostic x->sval = (uchar *) makesymtab(NSYMTAB);
41265393Sbostic }
41365393Sbostic z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
41465393Sbostic z->ctype = OCELL;
41565393Sbostic z->csub = CVAR;
41665393Sbostic tempfree(x);
41765393Sbostic return(z);
41865393Sbostic }
41965393Sbostic
adelete(Node ** a,int n)42065393Sbostic Cell *adelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
42165393Sbostic {
42265393Sbostic Cell *x, *y;
42365393Sbostic Node *np;
42465393Sbostic uchar buf[RECSIZE], *s;
42565393Sbostic
42665393Sbostic x = execute(a[0]); /* Cell* for symbol table */
42765393Sbostic if (!isarr(x))
42865393Sbostic return true;
42965393Sbostic buf[0] = 0;
43065393Sbostic for (np = a[1]; np; np = np->nnext) {
43165393Sbostic y = execute(np); /* subscript */
43265393Sbostic s = getsval(y);
43365393Sbostic strcat(buf, s);
43465393Sbostic if (np->nnext)
43565393Sbostic strcat(buf, *SUBSEP);
43665393Sbostic tempfree(y);
43765393Sbostic }
43865393Sbostic freeelem(x, buf);
43965393Sbostic tempfree(x);
44065393Sbostic return true;
44165393Sbostic }
44265393Sbostic
intest(Node ** a,int n)44365393Sbostic Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
44465393Sbostic {
44565393Sbostic register Cell *x, *ap, *k;
44665393Sbostic Node *p;
44765393Sbostic char buf[RECSIZE];
44865393Sbostic uchar *s;
44965393Sbostic
45065393Sbostic ap = execute(a[1]); /* array name */
45165393Sbostic if (!isarr(ap)) {
45265393Sbostic dprintf( ("making %s into an array\n", ap->nval) );
45365393Sbostic if (freeable(ap))
45465393Sbostic xfree(ap->sval);
45565393Sbostic ap->tval &= ~(STR|NUM|DONTFREE);
45665393Sbostic ap->tval |= ARR;
45765393Sbostic ap->sval = (uchar *) makesymtab(NSYMTAB);
45865393Sbostic }
45965393Sbostic buf[0] = 0;
46065393Sbostic for (p = a[0]; p; p = p->nnext) {
46165393Sbostic x = execute(p); /* expr */
46265393Sbostic s = getsval(x);
46365393Sbostic strcat(buf, s);
46465393Sbostic tempfree(x);
46565393Sbostic if (p->nnext)
46665393Sbostic strcat(buf, *SUBSEP);
46765393Sbostic }
46865393Sbostic k = lookup(buf, (Array *) ap->sval);
46965393Sbostic tempfree(ap);
47065393Sbostic if (k == NULL)
47165393Sbostic return(false);
47265393Sbostic else
47365393Sbostic return(true);
47465393Sbostic }
47565393Sbostic
47665393Sbostic
matchop(Node ** a,int n)47765393Sbostic Cell *matchop(Node **a, int n) /* ~ and match() */
47865393Sbostic {
47965393Sbostic register Cell *x, *y;
48065393Sbostic register uchar *s, *t;
48165393Sbostic register int i;
48265393Sbostic fa *pfa;
48365393Sbostic int (*mf)(fa *, uchar *) = match, mode = 0;
48465393Sbostic
48565393Sbostic if (n == MATCHFCN) {
48665393Sbostic mf = pmatch;
48765393Sbostic mode = 1;
48865393Sbostic }
48965393Sbostic x = execute(a[1]); /* a[1] = target text */
49065393Sbostic s = getsval(x);
49165393Sbostic if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
49265393Sbostic i = (*mf)((fa *) a[2], s);
49365393Sbostic else {
49465393Sbostic y = execute(a[2]); /* a[2] = regular expr */
49565393Sbostic t = getsval(y);
49665393Sbostic pfa = makedfa(t, mode);
49765393Sbostic i = (*mf)(pfa, s);
49865393Sbostic tempfree(y);
49965393Sbostic }
50065393Sbostic tempfree(x);
50165393Sbostic if (n == MATCHFCN) {
50265393Sbostic int start = patbeg - s + 1;
50365393Sbostic if (patlen < 0)
50465393Sbostic start = 0;
50565393Sbostic setfval(rstartloc, (Awkfloat) start);
50665393Sbostic setfval(rlengthloc, (Awkfloat) patlen);
50765393Sbostic x = gettemp();
50865393Sbostic x->tval = NUM;
50965393Sbostic x->fval = start;
51065393Sbostic return x;
51165393Sbostic } else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
51265393Sbostic return(true);
51365393Sbostic else
51465393Sbostic return(false);
51565393Sbostic }
51665393Sbostic
51765393Sbostic
boolop(Node ** a,int n)51865393Sbostic Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
51965393Sbostic {
52065393Sbostic register Cell *x, *y;
52165393Sbostic register int i;
52265393Sbostic
52365393Sbostic x = execute(a[0]);
52465393Sbostic i = istrue(x);
52565393Sbostic tempfree(x);
52665393Sbostic switch (n) {
52765393Sbostic case BOR:
52865393Sbostic if (i) return(true);
52965393Sbostic y = execute(a[1]);
53065393Sbostic i = istrue(y);
53165393Sbostic tempfree(y);
53265393Sbostic if (i) return(true);
53365393Sbostic else return(false);
53465393Sbostic case AND:
53565393Sbostic if ( !i ) return(false);
53665393Sbostic y = execute(a[1]);
53765393Sbostic i = istrue(y);
53865393Sbostic tempfree(y);
53965393Sbostic if (i) return(true);
54065393Sbostic else return(false);
54165393Sbostic case NOT:
54265393Sbostic if (i) return(false);
54365393Sbostic else return(true);
54465393Sbostic default: /* can't happen */
54565393Sbostic ERROR "unknown boolean operator %d", n FATAL;
54665393Sbostic }
54765393Sbostic return 0; /*NOTREACHED*/
54865393Sbostic }
54965393Sbostic
relop(Node ** a,int n)55065393Sbostic Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
55165393Sbostic {
55265393Sbostic register int i;
55365393Sbostic register Cell *x, *y;
55465393Sbostic Awkfloat j;
55565393Sbostic
55665393Sbostic x = execute(a[0]);
55765393Sbostic y = execute(a[1]);
55865393Sbostic if (x->tval&NUM && y->tval&NUM) {
55965393Sbostic j = x->fval - y->fval;
56065393Sbostic i = j<0? -1: (j>0? 1: 0);
56165393Sbostic } else {
56265393Sbostic i = strcmp(getsval(x), getsval(y));
56365393Sbostic }
56465393Sbostic tempfree(x);
56565393Sbostic tempfree(y);
56665393Sbostic switch (n) {
56765393Sbostic case LT: if (i<0) return(true);
56865393Sbostic else return(false);
56965393Sbostic case LE: if (i<=0) return(true);
57065393Sbostic else return(false);
57165393Sbostic case NE: if (i!=0) return(true);
57265393Sbostic else return(false);
57365393Sbostic case EQ: if (i == 0) return(true);
57465393Sbostic else return(false);
57565393Sbostic case GE: if (i>=0) return(true);
57665393Sbostic else return(false);
57765393Sbostic case GT: if (i>0) return(true);
57865393Sbostic else return(false);
57965393Sbostic default: /* can't happen */
58065393Sbostic ERROR "unknown relational operator %d", n FATAL;
58165393Sbostic }
58265393Sbostic return 0; /*NOTREACHED*/
58365393Sbostic }
58465393Sbostic
tfree(Cell * a)58565393Sbostic void tfree(Cell *a) /* free a tempcell */
58665393Sbostic {
58765393Sbostic if (freeable(a))
58865393Sbostic xfree(a->sval);
58965393Sbostic if (a == tmps)
59065393Sbostic ERROR "tempcell list is curdled" FATAL;
59165393Sbostic a->cnext = tmps;
59265393Sbostic tmps = a;
59365393Sbostic }
59465393Sbostic
gettemp(void)59565393Sbostic Cell *gettemp(void) /* get a tempcell */
59665393Sbostic { int i;
59765393Sbostic register Cell *x;
59865393Sbostic
59965393Sbostic if (!tmps) {
60065393Sbostic tmps = (Cell *) calloc(100, sizeof(Cell));
60165393Sbostic if (!tmps)
60265393Sbostic ERROR "out of space for temporaries" FATAL;
60365393Sbostic for(i = 1; i < 100; i++)
60465393Sbostic tmps[i-1].cnext = &tmps[i];
60565393Sbostic tmps[i-1].cnext = 0;
60665393Sbostic }
60765393Sbostic x = tmps;
60865393Sbostic tmps = x->cnext;
60965393Sbostic *x = tempcell;
61065393Sbostic return(x);
61165393Sbostic }
61265393Sbostic
indirect(Node ** a,int n)61365393Sbostic Cell *indirect(Node **a, int n) /* $( a[0] ) */
61465393Sbostic {
61565393Sbostic register Cell *x;
61665393Sbostic register int m;
61765393Sbostic register uchar *s;
61865393Sbostic
61965393Sbostic x = execute(a[0]);
62065393Sbostic m = getfval(x);
621*65396Sbostic if (m == 0 && !is_a_number(s = getsval(x))) /* suspicion! */
62265393Sbostic ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
62365393Sbostic /* can x->nval ever be null??? */
62465393Sbostic /* ERROR "illegal field $(%s)", s FATAL; */
62565393Sbostic tempfree(x);
62665393Sbostic x = fieldadr(m);
62765393Sbostic x->ctype = OCELL;
62865393Sbostic x->csub = CFLD;
62965393Sbostic return(x);
63065393Sbostic }
63165393Sbostic
substr(Node ** a,int nnn)63265393Sbostic Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
63365393Sbostic {
63465393Sbostic register int k, m, n;
63565393Sbostic register uchar *s;
63665393Sbostic int temp;
63765393Sbostic register Cell *x, *y, *z;
63865393Sbostic
63965393Sbostic x = execute(a[0]);
64065393Sbostic y = execute(a[1]);
64165393Sbostic if (a[2] != 0)
64265393Sbostic z = execute(a[2]);
64365393Sbostic s = getsval(x);
64465393Sbostic k = strlen(s) + 1;
64565393Sbostic if (k <= 1) {
64665393Sbostic tempfree(x);
64765393Sbostic tempfree(y);
64865393Sbostic if (a[2] != 0)
64965393Sbostic tempfree(z);
65065393Sbostic x = gettemp();
65165393Sbostic setsval(x, "");
65265393Sbostic return(x);
65365393Sbostic }
65465393Sbostic m = getfval(y);
65565393Sbostic if (m <= 0)
65665393Sbostic m = 1;
65765393Sbostic else if (m > k)
65865393Sbostic m = k;
65965393Sbostic tempfree(y);
66065393Sbostic if (a[2] != 0) {
66165393Sbostic n = getfval(z);
66265393Sbostic tempfree(z);
66365393Sbostic } else
66465393Sbostic n = k - 1;
66565393Sbostic if (n < 0)
66665393Sbostic n = 0;
66765393Sbostic else if (n > k - m)
66865393Sbostic n = k - m;
66965393Sbostic dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
67065393Sbostic y = gettemp();
67165393Sbostic temp = s[n+m-1]; /* with thanks to John Linderman */
67265393Sbostic s[n+m-1] = '\0';
67365393Sbostic setsval(y, s + m - 1);
67465393Sbostic s[n+m-1] = temp;
67565393Sbostic tempfree(x);
67665393Sbostic return(y);
67765393Sbostic }
67865393Sbostic
sindex(Node ** a,int nnn)67965393Sbostic Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
68065393Sbostic {
68165393Sbostic register Cell *x, *y, *z;
68265393Sbostic register uchar *s1, *s2, *p1, *p2, *q;
68365393Sbostic Awkfloat v = 0.0;
68465393Sbostic
68565393Sbostic x = execute(a[0]);
68665393Sbostic s1 = getsval(x);
68765393Sbostic y = execute(a[1]);
68865393Sbostic s2 = getsval(y);
68965393Sbostic
69065393Sbostic z = gettemp();
69165393Sbostic for (p1 = s1; *p1 != '\0'; p1++) {
69265393Sbostic for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
69365393Sbostic ;
69465393Sbostic if (*p2 == '\0') {
69565393Sbostic v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
69665393Sbostic break;
69765393Sbostic }
69865393Sbostic }
69965393Sbostic tempfree(x);
70065393Sbostic tempfree(y);
70165393Sbostic setfval(z, v);
70265393Sbostic return(z);
70365393Sbostic }
70465393Sbostic
format(uchar * buf,int bufsize,uchar * s,Node * a)70565393Sbostic format(uchar *buf, int bufsize, uchar *s, Node *a) /* printf-like conversions */
70665393Sbostic {
70765393Sbostic uchar fmt[RECSIZE];
70865393Sbostic register uchar *p, *t, *os;
70965393Sbostic register Cell *x;
71065393Sbostic int flag = 0, n;
71165393Sbostic
71265393Sbostic os = s;
71365393Sbostic p = buf;
71465393Sbostic while (*s) {
71565393Sbostic if (p - buf >= bufsize)
71665393Sbostic return -1;
71765393Sbostic if (*s != '%') {
71865393Sbostic *p++ = *s++;
71965393Sbostic continue;
72065393Sbostic }
72165393Sbostic if (*(s+1) == '%') {
72265393Sbostic *p++ = '%';
72365393Sbostic s += 2;
72465393Sbostic continue;
72565393Sbostic }
72665393Sbostic for (t=fmt; (*t++ = *s) != '\0'; s++) {
72765393Sbostic if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
72865393Sbostic break; /* the ansi panoply */
72965393Sbostic if (*s == '*') {
73065393Sbostic x = execute(a);
73165393Sbostic a = a->nnext;
73265393Sbostic sprintf((char *)t-1, "%d", (int) getfval(x));
73365393Sbostic t = fmt + strlen(fmt);
73465393Sbostic tempfree(x);
73565393Sbostic }
73665393Sbostic }
73765393Sbostic *t = '\0';
73865393Sbostic if (t >= fmt + sizeof(fmt))
73965393Sbostic ERROR "format item %.30s... too long", os FATAL;
74065393Sbostic switch (*s) {
74165393Sbostic case 'f': case 'e': case 'g': case 'E': case 'G':
74265393Sbostic flag = 1;
74365393Sbostic break;
74465393Sbostic case 'd': case 'i':
74565393Sbostic flag = 2;
74665393Sbostic if(*(s-1) == 'l') break;
74765393Sbostic *(t-1) = 'l';
74865393Sbostic *t = 'd';
74965393Sbostic *++t = '\0';
75065393Sbostic break;
75165393Sbostic case 'o': case 'x': case 'X': case 'u':
75265393Sbostic flag = *(s-1) == 'l' ? 2 : 3;
75365393Sbostic break;
75465393Sbostic case 's':
75565393Sbostic flag = 4;
75665393Sbostic break;
75765393Sbostic case 'c':
75865393Sbostic flag = 5;
75965393Sbostic break;
76065393Sbostic default:
76165393Sbostic ERROR "weird printf conversion %s", fmt WARNING;
76265393Sbostic flag = 0;
76365393Sbostic break;
76465393Sbostic }
76565393Sbostic if (a == NULL)
76665393Sbostic ERROR "not enough args in printf(%s)", os FATAL;
76765393Sbostic x = execute(a);
76865393Sbostic a = a->nnext;
76965393Sbostic switch (flag) {
77065393Sbostic case 0: sprintf((char *)p, "%s", fmt); /* unknown, so dump it too */
77165393Sbostic p += strlen(p);
77265393Sbostic sprintf((char *)p, "%s", getsval(x));
77365393Sbostic break;
77465393Sbostic case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break;
77565393Sbostic case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
77665393Sbostic case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
77765393Sbostic case 4:
77865393Sbostic t = getsval(x);
77965393Sbostic n = strlen(t);
78065393Sbostic if (n >= bufsize)
78165393Sbostic ERROR "huge string (%d chars) in printf %.30s...",
78265393Sbostic n, t FATAL;
78365393Sbostic sprintf((char *)p, (char *)fmt, t);
78465393Sbostic break;
78565393Sbostic case 5:
78665393Sbostic isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x))
78765393Sbostic : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
78865393Sbostic break;
78965393Sbostic }
79065393Sbostic tempfree(x);
79165393Sbostic p += strlen(p);
79265393Sbostic s++;
79365393Sbostic }
79465393Sbostic *p = '\0';
79565393Sbostic for ( ; a; a = a->nnext) /* evaluate any remaining args */
79665393Sbostic execute(a);
79765393Sbostic return 0;
79865393Sbostic }
79965393Sbostic
asprintf(Node ** a,int n)80065393Sbostic Cell *asprintf(Node **a, int n) /* sprintf(a[0]) */
80165393Sbostic {
80265393Sbostic register Cell *x;
80365393Sbostic register Node *y;
80465393Sbostic uchar buf[3*RECSIZE];
80565393Sbostic
80665393Sbostic y = a[0]->nnext;
80765393Sbostic x = execute(a[0]);
80865393Sbostic if (format(buf, sizeof buf, getsval(x), y) == -1)
80965393Sbostic ERROR "sprintf string %.30s... too long", buf FATAL;
81065393Sbostic tempfree(x);
81165393Sbostic x = gettemp();
81265393Sbostic x->sval = tostring(buf);
81365393Sbostic x->tval = STR;
81465393Sbostic return(x);
81565393Sbostic }
81665393Sbostic
aprintf(Node ** a,int n)81765393Sbostic Cell *aprintf(Node **a, int n) /* printf */
81865393Sbostic { /* a[0] is list of args, starting with format string */
81965393Sbostic /* a[1] is redirection operator, a[2] is redirection file */
82065393Sbostic FILE *fp;
82165393Sbostic register Cell *x;
82265393Sbostic register Node *y;
82365393Sbostic uchar buf[3*RECSIZE];
82465393Sbostic
82565393Sbostic y = a[0]->nnext;
82665393Sbostic x = execute(a[0]);
82765393Sbostic if (format(buf, sizeof buf, getsval(x), y) == -1)
82865393Sbostic ERROR "printf string %.30s... too long", buf FATAL;
82965393Sbostic tempfree(x);
83065393Sbostic if (a[1] == NULL) {
83165393Sbostic fputs((char *)buf, stdout);
83265393Sbostic if (ferror(stdout))
83365393Sbostic ERROR "write error on stdout" FATAL;
83465393Sbostic } else {
83565393Sbostic fp = redirect((int)a[1], a[2]);
83665393Sbostic fputs((char *)buf, fp);
83765393Sbostic fflush(fp);
83865393Sbostic if (ferror(fp))
83965393Sbostic ERROR "write error on %s", filename(fp) FATAL;
84065393Sbostic }
84165393Sbostic return(true);
84265393Sbostic }
84365393Sbostic
arith(Node ** a,int n)84465393Sbostic Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
84565393Sbostic {
84665393Sbostic Awkfloat i, j;
84765393Sbostic double v;
84865393Sbostic register Cell *x, *y, *z;
84965393Sbostic
85065393Sbostic x = execute(a[0]);
85165393Sbostic i = getfval(x);
85265393Sbostic tempfree(x);
85365393Sbostic if (n != UMINUS) {
85465393Sbostic y = execute(a[1]);
85565393Sbostic j = getfval(y);
85665393Sbostic tempfree(y);
85765393Sbostic }
85865393Sbostic z = gettemp();
85965393Sbostic switch (n) {
86065393Sbostic case ADD:
86165393Sbostic i += j;
86265393Sbostic break;
86365393Sbostic case MINUS:
86465393Sbostic i -= j;
86565393Sbostic break;
86665393Sbostic case MULT:
86765393Sbostic i *= j;
86865393Sbostic break;
86965393Sbostic case DIVIDE:
87065393Sbostic if (j == 0)
87165393Sbostic ERROR "division by zero" FATAL;
87265393Sbostic i /= j;
87365393Sbostic break;
87465393Sbostic case MOD:
87565393Sbostic if (j == 0)
87665393Sbostic ERROR "division by zero in mod" FATAL;
87765393Sbostic modf(i/j, &v);
87865393Sbostic i = i - j * v;
87965393Sbostic break;
88065393Sbostic case UMINUS:
88165393Sbostic i = -i;
88265393Sbostic break;
88365393Sbostic case POWER:
88465393Sbostic if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
88565393Sbostic i = ipow(i, (int) j);
88665393Sbostic else
88765393Sbostic i = errcheck(pow(i, j), "pow");
88865393Sbostic break;
88965393Sbostic default: /* can't happen */
89065393Sbostic ERROR "illegal arithmetic operator %d", n FATAL;
89165393Sbostic }
89265393Sbostic setfval(z, i);
89365393Sbostic return(z);
89465393Sbostic }
89565393Sbostic
ipow(double x,int n)89665393Sbostic double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
89765393Sbostic {
89865393Sbostic double v;
89965393Sbostic
90065393Sbostic if (n <= 0)
90165393Sbostic return 1;
90265393Sbostic v = ipow(x, n/2);
90365393Sbostic if (n % 2 == 0)
90465393Sbostic return v * v;
90565393Sbostic else
90665393Sbostic return x * v * v;
90765393Sbostic }
90865393Sbostic
incrdecr(Node ** a,int n)90965393Sbostic Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
91065393Sbostic {
91165393Sbostic register Cell *x, *z;
91265393Sbostic register int k;
91365393Sbostic Awkfloat xf;
91465393Sbostic
91565393Sbostic x = execute(a[0]);
91665393Sbostic xf = getfval(x);
91765393Sbostic k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
91865393Sbostic if (n == PREINCR || n == PREDECR) {
91965393Sbostic setfval(x, xf + k);
92065393Sbostic return(x);
92165393Sbostic }
92265393Sbostic z = gettemp();
92365393Sbostic setfval(z, xf);
92465393Sbostic setfval(x, xf + k);
92565393Sbostic tempfree(x);
92665393Sbostic return(z);
92765393Sbostic }
92865393Sbostic
assign(Node ** a,int n)92965393Sbostic Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
93065393Sbostic { /* this is subtle; don't muck with it. */
93165393Sbostic register Cell *x, *y;
93265393Sbostic Awkfloat xf, yf;
93365393Sbostic double v;
93465393Sbostic
93565393Sbostic y = execute(a[1]);
93665393Sbostic x = execute(a[0]);
93765393Sbostic if (n == ASSIGN) { /* ordinary assignment */
93865393Sbostic if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
93965393Sbostic ; /* leave alone unless it's a field */
94065393Sbostic else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
94165393Sbostic setsval(x, getsval(y));
94265393Sbostic x->fval = getfval(y);
94365393Sbostic x->tval |= NUM;
94465393Sbostic }
94565393Sbostic else if (y->tval & STR)
94665393Sbostic setsval(x, getsval(y));
94765393Sbostic else if (y->tval & NUM)
94865393Sbostic setfval(x, getfval(y));
94965393Sbostic else
95065393Sbostic funnyvar(y, "read value of");
95165393Sbostic tempfree(y);
95265393Sbostic return(x);
95365393Sbostic }
95465393Sbostic xf = getfval(x);
95565393Sbostic yf = getfval(y);
95665393Sbostic switch (n) {
95765393Sbostic case ADDEQ:
95865393Sbostic xf += yf;
95965393Sbostic break;
96065393Sbostic case SUBEQ:
96165393Sbostic xf -= yf;
96265393Sbostic break;
96365393Sbostic case MULTEQ:
96465393Sbostic xf *= yf;
96565393Sbostic break;
96665393Sbostic case DIVEQ:
96765393Sbostic if (yf == 0)
96865393Sbostic ERROR "division by zero in /=" FATAL;
96965393Sbostic xf /= yf;
97065393Sbostic break;
97165393Sbostic case MODEQ:
97265393Sbostic if (yf == 0)
97365393Sbostic ERROR "division by zero in %%=" FATAL;
97465393Sbostic modf(xf/yf, &v);
97565393Sbostic xf = xf - yf * v;
97665393Sbostic break;
97765393Sbostic case POWEQ:
97865393Sbostic if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
97965393Sbostic xf = ipow(xf, (int) yf);
98065393Sbostic else
98165393Sbostic xf = errcheck(pow(xf, yf), "pow");
98265393Sbostic break;
98365393Sbostic default:
98465393Sbostic ERROR "illegal assignment operator %d", n FATAL;
98565393Sbostic break;
98665393Sbostic }
98765393Sbostic tempfree(y);
98865393Sbostic setfval(x, xf);
98965393Sbostic return(x);
99065393Sbostic }
99165393Sbostic
cat(Node ** a,int q)99265393Sbostic Cell *cat(Node **a, int q) /* a[0] cat a[1] */
99365393Sbostic {
99465393Sbostic register Cell *x, *y, *z;
99565393Sbostic register int n1, n2;
99665393Sbostic register uchar *s;
99765393Sbostic
99865393Sbostic x = execute(a[0]);
99965393Sbostic y = execute(a[1]);
100065393Sbostic getsval(x);
100165393Sbostic getsval(y);
100265393Sbostic n1 = strlen(x->sval);
100365393Sbostic n2 = strlen(y->sval);
100465393Sbostic s = (uchar *) malloc(n1 + n2 + 1);
100565393Sbostic if (s == NULL)
100665393Sbostic ERROR "out of space concatenating %.15s... and %.15s...",
100765393Sbostic x->sval, y->sval FATAL;
100865393Sbostic strcpy(s, x->sval);
100965393Sbostic strcpy(s+n1, y->sval);
101065393Sbostic tempfree(y);
101165393Sbostic z = gettemp();
101265393Sbostic z->sval = s;
101365393Sbostic z->tval = STR;
101465393Sbostic tempfree(x);
101565393Sbostic return(z);
101665393Sbostic }
101765393Sbostic
pastat(Node ** a,int n)101865393Sbostic Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
101965393Sbostic {
102065393Sbostic register Cell *x;
102165393Sbostic
102265393Sbostic if (a[0] == 0)
102365393Sbostic x = execute(a[1]);
102465393Sbostic else {
102565393Sbostic x = execute(a[0]);
102665393Sbostic if (istrue(x)) {
102765393Sbostic tempfree(x);
102865393Sbostic x = execute(a[1]);
102965393Sbostic }
103065393Sbostic }
103165393Sbostic return x;
103265393Sbostic }
103365393Sbostic
dopa2(Node ** a,int n)103465393Sbostic Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
103565393Sbostic {
103665393Sbostic register Cell *x;
103765393Sbostic register int pair;
103865393Sbostic
103965393Sbostic pair = (int) a[3];
104065393Sbostic if (pairstack[pair] == 0) {
104165393Sbostic x = execute(a[0]);
104265393Sbostic if (istrue(x))
104365393Sbostic pairstack[pair] = 1;
104465393Sbostic tempfree(x);
104565393Sbostic }
104665393Sbostic if (pairstack[pair] == 1) {
104765393Sbostic x = execute(a[1]);
104865393Sbostic if (istrue(x))
104965393Sbostic pairstack[pair] = 0;
105065393Sbostic tempfree(x);
105165393Sbostic x = execute(a[2]);
105265393Sbostic return(x);
105365393Sbostic }
105465393Sbostic return(false);
105565393Sbostic }
105665393Sbostic
split(Node ** a,int nnn)105765393Sbostic Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
105865393Sbostic {
105965393Sbostic Cell *x, *y, *ap;
106065393Sbostic register uchar *s;
106165393Sbostic register int sep;
106265393Sbostic uchar *t, temp, num[10], *fs;
106365393Sbostic int n, tempstat;
106465393Sbostic
106565393Sbostic y = execute(a[0]); /* source string */
106665393Sbostic s = getsval(y);
106765393Sbostic if (a[2] == 0) /* fs string */
106865393Sbostic fs = *FS;
106965393Sbostic else if ((int) a[3] == STRING) { /* split(str,arr,"string") */
107065393Sbostic x = execute(a[2]);
107165393Sbostic fs = getsval(x);
107265393Sbostic } else if ((int) a[3] == REGEXPR)
107365393Sbostic fs = (uchar*) "(regexpr)"; /* split(str,arr,/regexpr/) */
107465393Sbostic else
107565393Sbostic ERROR "illegal type of split()" FATAL;
107665393Sbostic sep = *fs;
107765393Sbostic ap = execute(a[1]); /* array name */
107865393Sbostic freesymtab(ap);
107965393Sbostic dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
108065393Sbostic ap->tval &= ~STR;
108165393Sbostic ap->tval |= ARR;
108265393Sbostic ap->sval = (uchar *) makesymtab(NSYMTAB);
108365393Sbostic
108465393Sbostic n = 0;
108565393Sbostic if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) { /* reg expr */
108665393Sbostic fa *pfa;
108765393Sbostic if ((int) a[3] == REGEXPR) { /* it's ready already */
108865393Sbostic pfa = (fa *) a[2];
108965393Sbostic } else {
109065393Sbostic pfa = makedfa(fs, 1);
109165393Sbostic }
109265393Sbostic if (nematch(pfa,s)) {
109365393Sbostic tempstat = pfa->initstat;
109465393Sbostic pfa->initstat = 2;
109565393Sbostic do {
109665393Sbostic n++;
109765393Sbostic sprintf((char *)num, "%d", n);
109865393Sbostic temp = *patbeg;
109965393Sbostic *patbeg = '\0';
1100*65396Sbostic if (is_a_number(s))
110165393Sbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
110265393Sbostic else
110365393Sbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
110465393Sbostic *patbeg = temp;
110565393Sbostic s = patbeg + patlen;
110665393Sbostic if (*(patbeg+patlen-1) == 0 || *s == 0) {
110765393Sbostic n++;
110865393Sbostic sprintf((char *)num, "%d", n);
110965393Sbostic setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
111065393Sbostic pfa->initstat = tempstat;
111165393Sbostic goto spdone;
111265393Sbostic }
111365393Sbostic } while (nematch(pfa,s));
111465393Sbostic }
111565393Sbostic n++;
111665393Sbostic sprintf((char *)num, "%d", n);
1117*65396Sbostic if (is_a_number(s))
111865393Sbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
111965393Sbostic else
112065393Sbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
112165393Sbostic spdone:
112265393Sbostic pfa = NULL;
112365393Sbostic } else if (sep == ' ') {
112465393Sbostic for (n = 0; ; ) {
112565393Sbostic while (*s == ' ' || *s == '\t' || *s == '\n')
112665393Sbostic s++;
112765393Sbostic if (*s == 0)
112865393Sbostic break;
112965393Sbostic n++;
113065393Sbostic t = s;
113165393Sbostic do
113265393Sbostic s++;
113365393Sbostic while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
113465393Sbostic temp = *s;
113565393Sbostic *s = '\0';
113665393Sbostic sprintf((char *)num, "%d", n);
1137*65396Sbostic if (is_a_number(t))
113865393Sbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
113965393Sbostic else
114065393Sbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
114165393Sbostic *s = temp;
114265393Sbostic if (*s != 0)
114365393Sbostic s++;
114465393Sbostic }
114565393Sbostic } else if (*s != 0) {
114665393Sbostic for (;;) {
114765393Sbostic n++;
114865393Sbostic t = s;
114965393Sbostic while (*s != sep && *s != '\n' && *s != '\0')
115065393Sbostic s++;
115165393Sbostic temp = *s;
115265393Sbostic *s = '\0';
115365393Sbostic sprintf((char *)num, "%d", n);
1154*65396Sbostic if (is_a_number(t))
115565393Sbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
115665393Sbostic else
115765393Sbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
115865393Sbostic *s = temp;
115965393Sbostic if (*s++ == 0)
116065393Sbostic break;
116165393Sbostic }
116265393Sbostic }
116365393Sbostic tempfree(ap);
116465393Sbostic tempfree(y);
116565393Sbostic if (a[2] != 0 && (int) a[3] == STRING)
116665393Sbostic tempfree(x);
116765393Sbostic x = gettemp();
116865393Sbostic x->tval = NUM;
116965393Sbostic x->fval = n;
117065393Sbostic return(x);
117165393Sbostic }
117265393Sbostic
condexpr(Node ** a,int n)117365393Sbostic Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
117465393Sbostic {
117565393Sbostic register Cell *x;
117665393Sbostic
117765393Sbostic x = execute(a[0]);
117865393Sbostic if (istrue(x)) {
117965393Sbostic tempfree(x);
118065393Sbostic x = execute(a[1]);
118165393Sbostic } else {
118265393Sbostic tempfree(x);
118365393Sbostic x = execute(a[2]);
118465393Sbostic }
118565393Sbostic return(x);
118665393Sbostic }
118765393Sbostic
ifstat(Node ** a,int n)118865393Sbostic Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
118965393Sbostic {
119065393Sbostic register Cell *x;
119165393Sbostic
119265393Sbostic x = execute(a[0]);
119365393Sbostic if (istrue(x)) {
119465393Sbostic tempfree(x);
119565393Sbostic x = execute(a[1]);
119665393Sbostic } else if (a[2] != 0) {
119765393Sbostic tempfree(x);
119865393Sbostic x = execute(a[2]);
119965393Sbostic }
120065393Sbostic return(x);
120165393Sbostic }
120265393Sbostic
whilestat(Node ** a,int n)120365393Sbostic Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
120465393Sbostic {
120565393Sbostic register Cell *x;
120665393Sbostic
120765393Sbostic for (;;) {
120865393Sbostic x = execute(a[0]);
120965393Sbostic if (!istrue(x))
121065393Sbostic return(x);
121165393Sbostic tempfree(x);
121265393Sbostic x = execute(a[1]);
121365393Sbostic if (isbreak(x)) {
121465393Sbostic x = true;
121565393Sbostic return(x);
121665393Sbostic }
121765393Sbostic if (isnext(x) || isexit(x) || isret(x))
121865393Sbostic return(x);
121965393Sbostic tempfree(x);
122065393Sbostic }
122165393Sbostic }
122265393Sbostic
dostat(Node ** a,int n)122365393Sbostic Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
122465393Sbostic {
122565393Sbostic register Cell *x;
122665393Sbostic
122765393Sbostic for (;;) {
122865393Sbostic x = execute(a[0]);
122965393Sbostic if (isbreak(x))
123065393Sbostic return true;
123165393Sbostic if (isnext(x) || isexit(x) || isret(x))
123265393Sbostic return(x);
123365393Sbostic tempfree(x);
123465393Sbostic x = execute(a[1]);
123565393Sbostic if (!istrue(x))
123665393Sbostic return(x);
123765393Sbostic tempfree(x);
123865393Sbostic }
123965393Sbostic }
124065393Sbostic
forstat(Node ** a,int n)124165393Sbostic Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
124265393Sbostic {
124365393Sbostic register Cell *x;
124465393Sbostic
124565393Sbostic x = execute(a[0]);
124665393Sbostic tempfree(x);
124765393Sbostic for (;;) {
124865393Sbostic if (a[1]!=0) {
124965393Sbostic x = execute(a[1]);
125065393Sbostic if (!istrue(x)) return(x);
125165393Sbostic else tempfree(x);
125265393Sbostic }
125365393Sbostic x = execute(a[3]);
125465393Sbostic if (isbreak(x)) /* turn off break */
125565393Sbostic return true;
125665393Sbostic if (isnext(x) || isexit(x) || isret(x))
125765393Sbostic return(x);
125865393Sbostic tempfree(x);
125965393Sbostic x = execute(a[2]);
126065393Sbostic tempfree(x);
126165393Sbostic }
126265393Sbostic }
126365393Sbostic
instat(Node ** a,int n)126465393Sbostic Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
126565393Sbostic {
126665393Sbostic register Cell *x, *vp, *arrayp, *cp, *ncp;
126765393Sbostic Array *tp;
126865393Sbostic int i;
126965393Sbostic
127065393Sbostic vp = execute(a[0]);
127165393Sbostic arrayp = execute(a[1]);
127265393Sbostic if (!isarr(arrayp)) {
127365393Sbostic return true;
127465393Sbostic }
127565393Sbostic tp = (Array *) arrayp->sval;
127665393Sbostic tempfree(arrayp);
127765393Sbostic for (i = 0; i < tp->size; i++) { /* this routine knows too much */
127865393Sbostic for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
127965393Sbostic setsval(vp, cp->nval);
128065393Sbostic ncp = cp->cnext;
128165393Sbostic x = execute(a[2]);
128265393Sbostic if (isbreak(x)) {
128365393Sbostic tempfree(vp);
128465393Sbostic return true;
128565393Sbostic }
128665393Sbostic if (isnext(x) || isexit(x) || isret(x)) {
128765393Sbostic tempfree(vp);
128865393Sbostic return(x);
128965393Sbostic }
129065393Sbostic tempfree(x);
129165393Sbostic }
129265393Sbostic }
129365393Sbostic return true;
129465393Sbostic }
129565393Sbostic
129665393Sbostic /* if someone ever wants to run over the arrays in sorted order, */
129765393Sbostic /* here it is. but it will likely run slower, not faster. */
129865393Sbostic
129965393Sbostic /*
130065393Sbostic *int qstrcmp(p, q)
130165393Sbostic * uchar **p, **q;
130265393Sbostic *{
130365393Sbostic * return strcmp(*p, *q);
130465393Sbostic *}
130565393Sbostic */
130665393Sbostic
130765393Sbostic /*Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
130865393Sbostic /*{
130965393Sbostic /* register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
131065393Sbostic /* Array *tp;
131165393Sbostic /* int i, ne;
131265393Sbostic /*#define BIGENOUGH 1000
131365393Sbostic /* uchar *elems[BIGENOUGH], **ep;
131465393Sbostic /*
131565393Sbostic /* vp = execute(a[0]);
131665393Sbostic /* arrayp = execute(a[1]);
131765393Sbostic /* if (!isarr(arrayp))
131865393Sbostic /* ERROR "%s is not an array", arrayp->nval FATAL;
131965393Sbostic /* tp = (Array *) arrayp->sval;
132065393Sbostic /* tempfree(arrayp);
132165393Sbostic /* ep = elems;
132265393Sbostic /* ret = true;
132365393Sbostic /* if (tp->nelem >= BIGENOUGH)
132465393Sbostic /* ep = (uchar **) malloc(tp->nelem * sizeof(char *));
132565393Sbostic /*
132665393Sbostic /* for (i = ne = 0; i < tp->size; i++)
132765393Sbostic /* for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
132865393Sbostic /* ep[ne++] = cp->nval;
132965393Sbostic /* if (ne != tp->nelem)
133065393Sbostic /* ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
133165393Sbostic /* qsort(ep, ne, sizeof(char *), qstrcmp);
133265393Sbostic /* for (i = 0; i < ne; i++) {
133365393Sbostic /* setsval(vp, ep[i]);
133465393Sbostic /* x = execute(a[2]);
133565393Sbostic /* if (isbreak(x)) {
133665393Sbostic /* tempfree(vp);
133765393Sbostic /* break;
133865393Sbostic /* }
133965393Sbostic /* if (isnext(x) || isexit(x) || isret(x)) {
134065393Sbostic /* tempfree(vp);
134165393Sbostic /* ret = x;
134265393Sbostic /* break;
134365393Sbostic /* }
134465393Sbostic /* tempfree(x);
134565393Sbostic /* }
134665393Sbostic /* if (ep != elems)
134765393Sbostic /* free(ep);
134865393Sbostic /* return ret;
134965393Sbostic /*}
135065393Sbostic */
135165393Sbostic
135265393Sbostic
bltin(Node ** a,int n)135365393Sbostic Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
135465393Sbostic {
135565393Sbostic register Cell *x, *y;
135665393Sbostic Awkfloat u;
135765393Sbostic register int t;
135865393Sbostic uchar *p, buf[RECSIZE];
135965393Sbostic Node *nextarg;
136065393Sbostic FILE *fp;
136165393Sbostic
136265393Sbostic t = (int) a[0];
136365393Sbostic x = execute(a[1]);
136465393Sbostic nextarg = a[1]->nnext;
136565393Sbostic switch (t) {
136665393Sbostic case FLENGTH:
136765393Sbostic u = strlen(getsval(x)); break;
136865393Sbostic case FLOG:
136965393Sbostic u = errcheck(log(getfval(x)), "log"); break;
137065393Sbostic case FINT:
137165393Sbostic modf(getfval(x), &u); break;
137265393Sbostic case FEXP:
137365393Sbostic u = errcheck(exp(getfval(x)), "exp"); break;
137465393Sbostic case FSQRT:
137565393Sbostic u = errcheck(sqrt(getfval(x)), "sqrt"); break;
137665393Sbostic case FSIN:
137765393Sbostic u = sin(getfval(x)); break;
137865393Sbostic case FCOS:
137965393Sbostic u = cos(getfval(x)); break;
138065393Sbostic case FATAN:
138165393Sbostic if (nextarg == 0) {
138265393Sbostic ERROR "atan2 requires two arguments; returning 1.0" WARNING;
138365393Sbostic u = 1.0;
138465393Sbostic } else {
138565393Sbostic y = execute(a[1]->nnext);
138665393Sbostic u = atan2(getfval(x), getfval(y));
138765393Sbostic tempfree(y);
138865393Sbostic nextarg = nextarg->nnext;
138965393Sbostic }
139065393Sbostic break;
139165393Sbostic case FSYSTEM:
139265393Sbostic fflush(stdout); /* in case something is buffered already */
139365393Sbostic u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */
139465393Sbostic break;
139565393Sbostic case FRAND:
139665393Sbostic /* in principle, rand() returns something in 0..RAND_MAX */
139765393Sbostic u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
139865393Sbostic break;
139965393Sbostic case FSRAND:
140065393Sbostic if (x->tval & REC) /* no argument provided */
140165393Sbostic u = time((long *)0);
140265393Sbostic else
140365393Sbostic u = getfval(x);
140465393Sbostic srand((int) u); u = (int) u;
140565393Sbostic break;
140665393Sbostic case FTOUPPER:
140765393Sbostic case FTOLOWER:
140865393Sbostic strcpy(buf, getsval(x));
140965393Sbostic if (t == FTOUPPER) {
141065393Sbostic for (p = buf; *p; p++)
141165393Sbostic if (islower(*p))
141265393Sbostic *p = toupper(*p);
141365393Sbostic } else {
141465393Sbostic for (p = buf; *p; p++)
141565393Sbostic if (isupper(*p))
141665393Sbostic *p = tolower(*p);
141765393Sbostic }
141865393Sbostic tempfree(x);
141965393Sbostic x = gettemp();
142065393Sbostic setsval(x, buf);
142165393Sbostic return x;
142265393Sbostic case FFLUSH:
142365393Sbostic if ((fp = openfile(GT, getsval(x))) == NULL)
142465393Sbostic u = EOF;
142565393Sbostic else
142665393Sbostic u = fflush(fp);
142765393Sbostic break;
142865393Sbostic default: /* can't happen */
142965393Sbostic ERROR "illegal function type %d", t FATAL;
143065393Sbostic break;
143165393Sbostic }
143265393Sbostic tempfree(x);
143365393Sbostic x = gettemp();
143465393Sbostic setfval(x, u);
143565393Sbostic if (nextarg != 0) {
143665393Sbostic ERROR "warning: function has too many arguments" WARNING;
143765393Sbostic for ( ; nextarg; nextarg = nextarg->nnext)
143865393Sbostic execute(nextarg);
143965393Sbostic }
144065393Sbostic return(x);
144165393Sbostic }
144265393Sbostic
printstat(Node ** a,int n)144365393Sbostic Cell *printstat(Node **a, int n) /* print a[0] */
144465393Sbostic {
144565393Sbostic register Node *x;
144665393Sbostic register Cell *y;
144765393Sbostic FILE *fp;
144865393Sbostic
144965393Sbostic if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
145065393Sbostic fp = stdout;
145165393Sbostic else
145265393Sbostic fp = redirect((int)a[1], a[2]);
145365393Sbostic for (x = a[0]; x != NULL; x = x->nnext) {
145465393Sbostic y = execute(x);
145565393Sbostic fputs((char *)getsval(y), fp);
145665393Sbostic tempfree(y);
145765393Sbostic if (x->nnext == NULL)
145865393Sbostic fputs((char *)*ORS, fp);
145965393Sbostic else
146065393Sbostic fputs((char *)*OFS, fp);
146165393Sbostic }
146265393Sbostic if (a[1] != 0)
146365393Sbostic fflush(fp);
146465393Sbostic if (ferror(fp))
146565393Sbostic ERROR "write error on %s", filename(fp) FATAL;
146665393Sbostic return(true);
146765393Sbostic }
146865393Sbostic
nullproc(Node ** a,int n)146965393Sbostic Cell *nullproc(Node **a, int n)
147065393Sbostic {
147165393Sbostic n;
147265393Sbostic a;
147365393Sbostic return 0;
147465393Sbostic }
147565393Sbostic
147665393Sbostic
redirect(int a,Node * b)147765393Sbostic FILE *redirect(int a, Node *b) /* set up all i/o redirections */
147865393Sbostic {
147965393Sbostic FILE *fp;
148065393Sbostic Cell *x;
148165393Sbostic uchar *fname;
148265393Sbostic
148365393Sbostic x = execute(b);
148465393Sbostic fname = getsval(x);
148565393Sbostic fp = openfile(a, fname);
148665393Sbostic if (fp == NULL)
148765393Sbostic ERROR "can't open file %s", fname FATAL;
148865393Sbostic tempfree(x);
148965393Sbostic return fp;
149065393Sbostic }
149165393Sbostic
149265393Sbostic struct files {
149365393Sbostic FILE *fp;
149465393Sbostic uchar *fname;
149565393Sbostic int mode; /* '|', 'a', 'w' => LE/LT, GT */
149665393Sbostic } files[FOPEN_MAX] ={
149765393Sbostic { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */
149865393Sbostic { stdout, "/dev/stdout", GT },
149965393Sbostic { stderr, "/dev/stderr", GT }
150065393Sbostic };
150165393Sbostic
openfile(int a,uchar * us)150265393Sbostic FILE *openfile(int a, uchar *us)
150365393Sbostic {
150465393Sbostic char *s = us;
150565393Sbostic register int i, m;
150665393Sbostic register FILE *fp;
150765393Sbostic
150865393Sbostic if (*s == '\0')
150965393Sbostic ERROR "null file name in print or getline" FATAL;
151065393Sbostic for (i=0; i < FOPEN_MAX; i++)
151165393Sbostic if (files[i].fname && strcmp(s, files[i].fname) == 0)
151265393Sbostic if (a == files[i].mode || a==APPEND && files[i].mode==GT)
151365393Sbostic return files[i].fp;
151465393Sbostic for (i=0; i < FOPEN_MAX; i++)
151565393Sbostic if (files[i].fp == 0)
151665393Sbostic break;
151765393Sbostic if (i >= FOPEN_MAX)
151865393Sbostic ERROR "%s makes too many open files", s FATAL;
151965393Sbostic fflush(stdout); /* force a semblance of order */
152065393Sbostic m = a;
152165393Sbostic if (a == GT) {
152265393Sbostic fp = fopen(s, "w");
152365393Sbostic } else if (a == APPEND) {
152465393Sbostic fp = fopen(s, "a");
152565393Sbostic m = GT; /* so can mix > and >> */
152665393Sbostic } else if (a == '|') { /* output pipe */
152765393Sbostic fp = popen(s, "w");
152865393Sbostic } else if (a == LE) { /* input pipe */
152965393Sbostic fp = popen(s, "r");
153065393Sbostic } else if (a == LT) { /* getline <file */
153165393Sbostic fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
153265393Sbostic } else /* can't happen */
153365393Sbostic ERROR "illegal redirection %d", a FATAL;
153465393Sbostic if (fp != NULL) {
153565393Sbostic files[i].fname = tostring(s);
153665393Sbostic files[i].fp = fp;
153765393Sbostic files[i].mode = m;
153865393Sbostic }
153965393Sbostic return fp;
154065393Sbostic }
154165393Sbostic
filename(FILE * fp)154265393Sbostic uchar *filename(FILE *fp)
154365393Sbostic {
154465393Sbostic int i;
154565393Sbostic
154665393Sbostic for (i = 0; i < FOPEN_MAX; i++)
154765393Sbostic if (fp == files[i].fp)
154865393Sbostic return files[i].fname;
154965393Sbostic return "???";
155065393Sbostic }
155165393Sbostic
closefile(Node ** a,int n)155265393Sbostic Cell *closefile(Node **a, int n)
155365393Sbostic {
155465393Sbostic register Cell *x;
155565393Sbostic int i, stat;
155665393Sbostic
155765393Sbostic n;
155865393Sbostic x = execute(a[0]);
155965393Sbostic getsval(x);
156065393Sbostic for (i = 0; i < FOPEN_MAX; i++)
156165393Sbostic if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
156265393Sbostic if (ferror(files[i].fp))
156365393Sbostic ERROR "i/o error occurred on %s", files[i].fname WARNING;
156465393Sbostic if (files[i].mode == '|' || files[i].mode == LE)
156565393Sbostic stat = pclose(files[i].fp);
156665393Sbostic else
156765393Sbostic stat = fclose(files[i].fp);
156865393Sbostic if (stat == EOF)
156965393Sbostic ERROR "i/o error occurred closing %s", files[i].fname WARNING;
157065393Sbostic if (i > 2) /* don't do /dev/std... */
157165393Sbostic xfree(files[i].fname);
157265393Sbostic files[i].fname = NULL; /* watch out for ref thru this */
157365393Sbostic files[i].fp = NULL;
157465393Sbostic }
157565393Sbostic tempfree(x);
157665393Sbostic return(true);
157765393Sbostic }
157865393Sbostic
closeall(void)157965393Sbostic void closeall(void)
158065393Sbostic {
158165393Sbostic int i, stat;
158265393Sbostic
158365393Sbostic for (i = 0; i < FOPEN_MAX; i++)
158465393Sbostic if (files[i].fp) {
158565393Sbostic if (ferror(files[i].fp))
158665393Sbostic ERROR "i/o error occurred on %s", files[i].fname WARNING;
158765393Sbostic if (files[i].mode == '|' || files[i].mode == LE)
158865393Sbostic stat = pclose(files[i].fp);
158965393Sbostic else
159065393Sbostic stat = fclose(files[i].fp);
159165393Sbostic if (stat == EOF)
159265393Sbostic ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
159365393Sbostic }
159465393Sbostic }
159565393Sbostic
159665393Sbostic #define SUBSIZE (20 * RECSIZE)
159765393Sbostic
sub(Node ** a,int nnn)159865393Sbostic Cell *sub(Node **a, int nnn) /* substitute command */
159965393Sbostic {
160065393Sbostic register uchar *sptr, *pb, *q;
160165393Sbostic register Cell *x, *y, *result;
160265393Sbostic uchar buf[SUBSIZE], *t;
160365393Sbostic fa *pfa;
160465393Sbostic
160565393Sbostic x = execute(a[3]); /* target string */
160665393Sbostic t = getsval(x);
160765393Sbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
160865393Sbostic pfa = (fa *) a[1]; /* regular expression */
160965393Sbostic else {
161065393Sbostic y = execute(a[1]);
161165393Sbostic pfa = makedfa(getsval(y), 1);
161265393Sbostic tempfree(y);
161365393Sbostic }
161465393Sbostic y = execute(a[2]); /* replacement string */
161565393Sbostic result = false;
161665393Sbostic if (pmatch(pfa, t)) {
161765393Sbostic pb = buf;
161865393Sbostic sptr = t;
161965393Sbostic while (sptr < patbeg)
162065393Sbostic *pb++ = *sptr++;
162165393Sbostic sptr = getsval(y);
162265393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE - 1)
162365393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') {
162465393Sbostic sptr++; /* skip \, */
162565393Sbostic *pb++ = *sptr++; /* add & */
162665393Sbostic } else if (*sptr == '&') {
162765393Sbostic sptr++;
162865393Sbostic for (q = patbeg; q < patbeg+patlen; )
162965393Sbostic *pb++ = *q++;
163065393Sbostic } else
163165393Sbostic *pb++ = *sptr++;
163265393Sbostic *pb = '\0';
163365393Sbostic if (pb >= buf + SUBSIZE)
163465393Sbostic ERROR "sub() result %30s too big", buf FATAL;
163565393Sbostic sptr = patbeg + patlen;
163665393Sbostic if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
163765393Sbostic while (*pb++ = *sptr++)
163865393Sbostic ;
163965393Sbostic if (pb >= buf + SUBSIZE)
164065393Sbostic ERROR "sub() result %.30s too big", buf FATAL;
164165393Sbostic setsval(x, buf);
164265393Sbostic result = true;;
164365393Sbostic }
164465393Sbostic tempfree(x);
164565393Sbostic tempfree(y);
164665393Sbostic return result;
164765393Sbostic }
164865393Sbostic
gsub(Node ** a,int nnn)164965393Sbostic Cell *gsub(Node **a, int nnn) /* global substitute */
165065393Sbostic {
165165393Sbostic register Cell *x, *y;
165265393Sbostic register uchar *rptr, *sptr, *t, *pb;
165365393Sbostic uchar buf[SUBSIZE];
165465393Sbostic register fa *pfa;
165565393Sbostic int mflag, tempstat, num;
165665393Sbostic
165765393Sbostic mflag = 0; /* if mflag == 0, can replace empty string */
165865393Sbostic num = 0;
165965393Sbostic x = execute(a[3]); /* target string */
166065393Sbostic t = getsval(x);
166165393Sbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
166265393Sbostic pfa = (fa *) a[1]; /* regular expression */
166365393Sbostic else {
166465393Sbostic y = execute(a[1]);
166565393Sbostic pfa = makedfa(getsval(y), 1);
166665393Sbostic tempfree(y);
166765393Sbostic }
166865393Sbostic y = execute(a[2]); /* replacement string */
166965393Sbostic if (pmatch(pfa, t)) {
167065393Sbostic tempstat = pfa->initstat;
167165393Sbostic pfa->initstat = 2;
167265393Sbostic pb = buf;
167365393Sbostic rptr = getsval(y);
167465393Sbostic do {
167565393Sbostic /*
167665393Sbostic uchar *p;
167765393Sbostic int i;
167865393Sbostic printf("target string: %s, *patbeg = %o, patlen = %d\n",
167965393Sbostic t, *patbeg, patlen);
168065393Sbostic printf(" match found: ");
168165393Sbostic p=patbeg;
168265393Sbostic for (i=0; i<patlen; i++)
168365393Sbostic printf("%c", *p++);
168465393Sbostic printf("\n");
168565393Sbostic */
168665393Sbostic if (patlen == 0 && *patbeg != 0) { /* matched empty string */
168765393Sbostic if (mflag == 0) { /* can replace empty */
168865393Sbostic num++;
168965393Sbostic sptr = rptr;
169065393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE-1)
169165393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') {
169265393Sbostic sptr++;
169365393Sbostic *pb++ = *sptr++;
169465393Sbostic } else if (*sptr == '&') {
169565393Sbostic uchar *q;
169665393Sbostic sptr++;
169765393Sbostic for (q = patbeg; q < patbeg+patlen; )
169865393Sbostic *pb++ = *q++;
169965393Sbostic } else
170065393Sbostic *pb++ = *sptr++;
170165393Sbostic }
170265393Sbostic if (*t == 0) /* at end */
170365393Sbostic goto done;
170465393Sbostic *pb++ = *t++;
170565393Sbostic if (pb >= buf + SUBSIZE-1)
170665393Sbostic ERROR "gsub() result %.30s too big", buf FATAL;
170765393Sbostic mflag = 0;
170865393Sbostic }
170965393Sbostic else { /* matched nonempty string */
171065393Sbostic num++;
171165393Sbostic sptr = t;
171265393Sbostic while (sptr < patbeg && pb < buf + SUBSIZE-1)
171365393Sbostic *pb++ = *sptr++;
171465393Sbostic sptr = rptr;
171565393Sbostic while (*sptr != 0 && pb < buf + SUBSIZE-1)
171665393Sbostic if (*sptr == '\\' && *(sptr+1) == '&') {
171765393Sbostic sptr++;
171865393Sbostic *pb++ = *sptr++;
171965393Sbostic } else if (*sptr == '&') {
172065393Sbostic uchar *q;
172165393Sbostic sptr++;
172265393Sbostic for (q = patbeg; q < patbeg+patlen; )
172365393Sbostic *pb++ = *q++;
172465393Sbostic } else
172565393Sbostic *pb++ = *sptr++;
172665393Sbostic t = patbeg + patlen;
172765393Sbostic if ((*(t-1) == 0) || (*t == 0))
172865393Sbostic goto done;
172965393Sbostic if (pb >= buf + SUBSIZE-1)
173065393Sbostic ERROR "gsub() result %.30s too big", buf FATAL;
173165393Sbostic mflag = 1;
173265393Sbostic }
173365393Sbostic } while (pmatch(pfa,t));
173465393Sbostic sptr = t;
173565393Sbostic while (*pb++ = *sptr++)
173665393Sbostic ;
173765393Sbostic done: if (pb >= buf + SUBSIZE-1)
173865393Sbostic ERROR "gsub() result %.30s too big", buf FATAL;
173965393Sbostic *pb = '\0';
174065393Sbostic setsval(x, buf);
174165393Sbostic pfa->initstat = tempstat;
174265393Sbostic }
174365393Sbostic tempfree(x);
174465393Sbostic tempfree(y);
174565393Sbostic x = gettemp();
174665393Sbostic x->tval = NUM;
174765393Sbostic x->fval = num;
174865393Sbostic return(x);
174965393Sbostic }
1750