141abc59cSbostic /****************************************************************
241abc59cSbostic Copyright (C) AT&T 1993
341abc59cSbostic All Rights Reserved
441abc59cSbostic
541abc59cSbostic Permission to use, copy, modify, and distribute this software and
641abc59cSbostic its documentation for any purpose and without fee is hereby
741abc59cSbostic granted, provided that the above copyright notice appear in all
841abc59cSbostic copies and that both that the copyright notice and this
941abc59cSbostic permission notice and warranty disclaimer appear in supporting
1041abc59cSbostic documentation, and that the name of AT&T or any of its entities
1141abc59cSbostic not be used in advertising or publicity pertaining to
1241abc59cSbostic distribution of the software without specific, written prior
1341abc59cSbostic permission.
1441abc59cSbostic
1541abc59cSbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1641abc59cSbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1741abc59cSbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1841abc59cSbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1941abc59cSbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2041abc59cSbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2141abc59cSbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2241abc59cSbostic THIS SOFTWARE.
2341abc59cSbostic ****************************************************************/
2441abc59cSbostic
2541abc59cSbostic #define tempfree(x) if (istemp(x)) tfree(x); else
2641abc59cSbostic
2741abc59cSbostic #define DEBUG
2841abc59cSbostic #include <stdio.h>
2941abc59cSbostic #include <ctype.h>
3041abc59cSbostic #include <setjmp.h>
3141abc59cSbostic #include <math.h>
3241abc59cSbostic #include <string.h>
3341abc59cSbostic #include <stdlib.h>
3441abc59cSbostic #include <time.h>
3541abc59cSbostic #include "awk.h"
3641abc59cSbostic #include "y.tab.h"
3741abc59cSbostic
3841abc59cSbostic #ifdef _NFILE
3941abc59cSbostic #ifndef FOPEN_MAX
4041abc59cSbostic #define FOPEN_MAX _NFILE
4141abc59cSbostic #endif
4241abc59cSbostic #endif
4341abc59cSbostic
4441abc59cSbostic #ifndef FOPEN_MAX
4541abc59cSbostic #define FOPEN_MAX 40 /* max number of open files */
4641abc59cSbostic #endif
4741abc59cSbostic
4841abc59cSbostic #ifndef RAND_MAX
4941abc59cSbostic #define RAND_MAX 32767 /* all that ansi guarantees */
5041abc59cSbostic #endif
5141abc59cSbostic
5241abc59cSbostic jmp_buf env;
5341abc59cSbostic
5441abc59cSbostic /* an attempt to go a bit faster: */
5541abc59cSbostic
5641abc59cSbostic /* #define execute(p) (isvalue(p) ? (Cell *)((p)->narg[0]) : r_execute(p)) */
5741abc59cSbostic #define execute(p) r_execute(p)
5841abc59cSbostic #define getfval(p) (((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
5941abc59cSbostic #define getsval(p) (((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
6041abc59cSbostic
6141abc59cSbostic
6241abc59cSbostic #define PA2NUM 29 /* max number of pat,pat patterns allowed */
6341abc59cSbostic int paircnt; /* number of them in use */
6441abc59cSbostic int pairstack[PA2NUM]; /* state of each pat,pat */
6541abc59cSbostic
6641abc59cSbostic Node *winner = NULL; /* root of parse tree */
6741abc59cSbostic Cell *tmps; /* free temporary cells for execution */
6841abc59cSbostic
6941abc59cSbostic static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM };
7041abc59cSbostic Cell *true = &truecell;
7141abc59cSbostic static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM };
7241abc59cSbostic Cell *false = &falsecell;
7341abc59cSbostic static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM };
7441abc59cSbostic Cell *jbreak = &breakcell;
7541abc59cSbostic static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM };
7641abc59cSbostic Cell *jcont = &contcell;
7741abc59cSbostic static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM };
7841abc59cSbostic Cell *jnext = &nextcell;
7941abc59cSbostic static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM };
8041abc59cSbostic Cell *jexit = &exitcell;
8141abc59cSbostic static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM };
8241abc59cSbostic Cell *jret = &retcell;
8341abc59cSbostic static Cell tempcell ={ OCELL, CTEMP, 0, 0, 0.0, NUM };
8441abc59cSbostic
8541abc59cSbostic Node *curnode = NULL; /* the node being executed, for debugging */
8641abc59cSbostic
run(Node * a)8741abc59cSbostic void run(Node *a) /* execution of parse tree starts here */
8841abc59cSbostic {
8941abc59cSbostic execute(a);
9041abc59cSbostic closeall();
9141abc59cSbostic }
9241abc59cSbostic
r_execute(Node * u)9341abc59cSbostic Cell *r_execute(Node *u) /* execute a node of the parse tree */
9441abc59cSbostic {
9541abc59cSbostic register Cell *(*proc)(Node **, int);
9641abc59cSbostic register Cell *x;
9741abc59cSbostic register Node *a;
9841abc59cSbostic
9941abc59cSbostic if (u == NULL)
10041abc59cSbostic return(true);
10141abc59cSbostic for (a = u; ; a = a->nnext) {
10241abc59cSbostic curnode = a;
10341abc59cSbostic if (isvalue(a)) {
10441abc59cSbostic x = (Cell *) (a->narg[0]);
10541abc59cSbostic if ((x->tval & FLD) && !donefld)
10641abc59cSbostic fldbld();
10741abc59cSbostic else if ((x->tval & REC) && !donerec)
10841abc59cSbostic recbld();
10941abc59cSbostic return(x);
11041abc59cSbostic }
11141abc59cSbostic if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
11241abc59cSbostic ERROR "illegal statement" FATAL;
11341abc59cSbostic proc = proctab[a->nobj-FIRSTTOKEN];
11441abc59cSbostic x = (*proc)(a->narg, a->nobj);
11541abc59cSbostic if ((x->tval & FLD) && !donefld)
11641abc59cSbostic fldbld();
11741abc59cSbostic else if ((x->tval & REC) && !donerec)
11841abc59cSbostic recbld();
11941abc59cSbostic if (isexpr(a))
12041abc59cSbostic return(x);
12141abc59cSbostic if (isjump(x))
12241abc59cSbostic return(x);
12341abc59cSbostic if (a->nnext == NULL)
12441abc59cSbostic return(x);
12541abc59cSbostic tempfree(x);
12641abc59cSbostic }
12741abc59cSbostic }
12841abc59cSbostic
12941abc59cSbostic
program(Node ** a,int n)13041abc59cSbostic Cell *program(Node **a, int n) /* execute an awk program */
13141abc59cSbostic { /* a[0] = BEGIN, a[1] = body, a[2] = END */
13241abc59cSbostic register Cell *x;
13341abc59cSbostic
13441abc59cSbostic if (setjmp(env) != 0)
13541abc59cSbostic goto ex;
13641abc59cSbostic if (a[0]) { /* BEGIN */
13741abc59cSbostic x = execute(a[0]);
13841abc59cSbostic if (isexit(x))
13941abc59cSbostic return(true);
14041abc59cSbostic if (isjump(x))
14141abc59cSbostic ERROR "illegal break, continue or next from BEGIN" FATAL;
14241abc59cSbostic tempfree(x);
14341abc59cSbostic }
14441abc59cSbostic loop:
14541abc59cSbostic if (a[1] || a[2])
14641abc59cSbostic while (getrec(record) > 0) {
14741abc59cSbostic x = execute(a[1]);
14841abc59cSbostic if (isexit(x))
14941abc59cSbostic break;
15041abc59cSbostic tempfree(x);
15141abc59cSbostic }
15241abc59cSbostic ex:
15341abc59cSbostic if (setjmp(env) != 0) /* handles exit within END */
15441abc59cSbostic goto ex1;
15541abc59cSbostic if (a[2]) { /* END */
15641abc59cSbostic x = execute(a[2]);
15741abc59cSbostic if (isbreak(x) || isnext(x) || iscont(x))
15841abc59cSbostic ERROR "illegal break, next, or continue from END" FATAL;
15941abc59cSbostic tempfree(x);
16041abc59cSbostic }
16141abc59cSbostic ex1:
16241abc59cSbostic return(true);
16341abc59cSbostic }
16441abc59cSbostic
16541abc59cSbostic struct Frame { /* stack frame for awk function calls */
16641abc59cSbostic int nargs; /* number of arguments in this call */
16741abc59cSbostic Cell *fcncell; /* pointer to Cell for function */
16841abc59cSbostic Cell **args; /* pointer to array of arguments after execute */
16941abc59cSbostic Cell *retval; /* return value */
17041abc59cSbostic };
17141abc59cSbostic
17241abc59cSbostic #define NARGS 50 /* max args in a call */
17341abc59cSbostic
17441abc59cSbostic struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
17541abc59cSbostic int nframe = 0; /* number of frames allocated */
17641abc59cSbostic struct Frame *fp = NULL; /* frame pointer. bottom level unused */
17741abc59cSbostic
call(Node ** a,int n)17841abc59cSbostic Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
17941abc59cSbostic {
18041abc59cSbostic static Cell newcopycell = { OCELL, CCOPY, 0, (uchar *) "", 0.0, NUM|STR|DONTFREE };
18141abc59cSbostic int i, ncall, ndef;
18241abc59cSbostic Node *x;
18341abc59cSbostic Cell *args[NARGS], *oargs[NARGS], *y, *z, *fcn;
18441abc59cSbostic uchar *s;
18541abc59cSbostic
18641abc59cSbostic fcn = execute(a[0]); /* the function itself */
18741abc59cSbostic s = fcn->nval;
18841abc59cSbostic if (!isfunc(fcn))
18941abc59cSbostic ERROR "calling undefined function %s", s FATAL;
19041abc59cSbostic if (frame == NULL) {
19141abc59cSbostic fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame));
19241abc59cSbostic if (frame == NULL)
19341abc59cSbostic ERROR "out of space for stack frames calling %s", s FATAL;
19441abc59cSbostic }
19541abc59cSbostic for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
19641abc59cSbostic ncall++;
19741abc59cSbostic ndef = (int) fcn->fval; /* args in defn */
19841abc59cSbostic dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, fp-frame) );
19941abc59cSbostic if (ncall > ndef)
20041abc59cSbostic ERROR "function %s called with %d args, uses only %d",
20141abc59cSbostic s, ncall, ndef WARNING;
20241abc59cSbostic if (ncall + ndef > NARGS)
20341abc59cSbostic ERROR "function %s has %d arguments, limit %d", s, ncall+ndef, NARGS FATAL;
20441abc59cSbostic for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
20541abc59cSbostic dprintf( ("evaluate args[%d], fp=%d:\n", i, fp-frame) );
20641abc59cSbostic y = execute(x);
20741abc59cSbostic oargs[i] = y;
20841abc59cSbostic dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
20941abc59cSbostic i, y->nval, y->fval, isarr(y) ? "(array)" : (char*) y->sval, y->tval) );
21041abc59cSbostic if (isfunc(y))
21141abc59cSbostic ERROR "can't use function %s as argument in %s", y->nval, s FATAL;
21241abc59cSbostic if (isarr(y))
21341abc59cSbostic args[i] = y; /* arrays by ref */
21441abc59cSbostic else
21541abc59cSbostic args[i] = copycell(y);
21641abc59cSbostic tempfree(y);
21741abc59cSbostic }
21841abc59cSbostic for ( ; i < ndef; i++) { /* add null args for ones not provided */
21941abc59cSbostic args[i] = gettemp();
22041abc59cSbostic *args[i] = newcopycell;
22141abc59cSbostic }
22241abc59cSbostic fp++; /* now ok to up frame */
22341abc59cSbostic if (fp >= frame + nframe) {
22441abc59cSbostic int dfp = fp - frame; /* old index */
22541abc59cSbostic frame = (struct Frame *)
22641abc59cSbostic realloc((char *) frame, (nframe += 100) * sizeof(struct Frame));
22741abc59cSbostic if (frame == NULL)
22841abc59cSbostic ERROR "out of space for stack frames in %s", s FATAL;
22941abc59cSbostic fp = frame + dfp;
23041abc59cSbostic }
23141abc59cSbostic fp->fcncell = fcn;
23241abc59cSbostic fp->args = args;
23341abc59cSbostic fp->nargs = ndef; /* number defined with (excess are locals) */
23441abc59cSbostic fp->retval = gettemp();
23541abc59cSbostic
23641abc59cSbostic dprintf( ("start exec of %s, fp=%d\n", s, fp-frame) );
23741abc59cSbostic y = execute((Node *)(fcn->sval)); /* execute body */
23841abc59cSbostic dprintf( ("finished exec of %s, fp=%d\n", s, fp-frame) );
23941abc59cSbostic
24041abc59cSbostic for (i = 0; i < ndef; i++) {
24141abc59cSbostic Cell *t = fp->args[i];
24241abc59cSbostic if (isarr(t)) {
24341abc59cSbostic if (t->csub == CCOPY) {
24441abc59cSbostic if (i >= ncall) {
24541abc59cSbostic freesymtab(t);
24641abc59cSbostic t->csub = CTEMP;
24741abc59cSbostic } else {
24841abc59cSbostic oargs[i]->tval = t->tval;
24941abc59cSbostic oargs[i]->tval &= ~(STR|NUM|DONTFREE);
25041abc59cSbostic oargs[i]->sval = t->sval;
25141abc59cSbostic tempfree(t);
25241abc59cSbostic }
25341abc59cSbostic }
25441abc59cSbostic } else if (t != y) { /* kludge to prevent freeing twice */
25541abc59cSbostic t->csub = CTEMP;
25641abc59cSbostic tempfree(t);
25741abc59cSbostic }
25841abc59cSbostic }
25941abc59cSbostic tempfree(fcn);
26041abc59cSbostic if (isexit(y) || isnext(y))
26141abc59cSbostic return y;
26241abc59cSbostic tempfree(y); /* this can free twice! */
26341abc59cSbostic z = fp->retval; /* return value */
26441abc59cSbostic dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
26541abc59cSbostic fp--;
26641abc59cSbostic return(z);
26741abc59cSbostic }
26841abc59cSbostic
copycell(Cell * x)26941abc59cSbostic Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
27041abc59cSbostic {
27141abc59cSbostic Cell *y;
27241abc59cSbostic
27341abc59cSbostic y = gettemp();
27441abc59cSbostic y->csub = CCOPY; /* prevents freeing until call is over */
27541abc59cSbostic y->nval = x->nval;
27641abc59cSbostic y->sval = x->sval ? tostring(x->sval) : NULL;
27741abc59cSbostic y->fval = x->fval;
27841abc59cSbostic y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */
27941abc59cSbostic /* is DONTFREE right? */
28041abc59cSbostic return y;
28141abc59cSbostic }
28241abc59cSbostic
arg(Node ** a,int n)28341abc59cSbostic Cell *arg(Node **a, int n) /* nth argument of a function */
28441abc59cSbostic {
28541abc59cSbostic
28641abc59cSbostic n = (int) a[0]; /* argument number, counting from 0 */
28741abc59cSbostic dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) );
28841abc59cSbostic if (n+1 > fp->nargs)
28941abc59cSbostic ERROR "argument #%d of function %s was not supplied",
29041abc59cSbostic n+1, fp->fcncell->nval FATAL;
29141abc59cSbostic return fp->args[n];
29241abc59cSbostic }
29341abc59cSbostic
jump(Node ** a,int n)29441abc59cSbostic Cell *jump(Node **a, int n) /* break, continue, next, continue, return */
29541abc59cSbostic {
29641abc59cSbostic register Cell *y;
29741abc59cSbostic
29841abc59cSbostic switch (n) {
29941abc59cSbostic case EXIT:
30041abc59cSbostic if (a[0] != NULL) {
30141abc59cSbostic y = execute(a[0]);
30241abc59cSbostic errorflag = getfval(y);
30341abc59cSbostic tempfree(y);
30441abc59cSbostic }
30541abc59cSbostic longjmp(env, 1);
30641abc59cSbostic case RETURN:
30741abc59cSbostic if (a[0] != NULL) {
30841abc59cSbostic y = execute(a[0]);
30941abc59cSbostic if ((y->tval & (STR|NUM)) == (STR|NUM)) {
31041abc59cSbostic setsval(fp->retval, getsval(y));
31141abc59cSbostic fp->retval->fval = getfval(y);
31241abc59cSbostic fp->retval->tval |= NUM;
31341abc59cSbostic }
31441abc59cSbostic else if (y->tval & STR)
31541abc59cSbostic setsval(fp->retval, getsval(y));
31641abc59cSbostic else if (y->tval & NUM)
31741abc59cSbostic setfval(fp->retval, getfval(y));
31841abc59cSbostic else /* can't happen */
31941abc59cSbostic ERROR "bad type variable %d", y->tval FATAL;
32041abc59cSbostic tempfree(y);
32141abc59cSbostic }
32241abc59cSbostic return(jret);
32341abc59cSbostic case NEXT:
32441abc59cSbostic return(jnext);
32541abc59cSbostic case BREAK:
32641abc59cSbostic return(jbreak);
32741abc59cSbostic case CONTINUE:
32841abc59cSbostic return(jcont);
32941abc59cSbostic default: /* can't happen */
33041abc59cSbostic ERROR "illegal jump type %d", n FATAL;
33141abc59cSbostic }
33241abc59cSbostic return 0; /* not reached */
33341abc59cSbostic }
33441abc59cSbostic
getline(Node ** a,int n)33541abc59cSbostic Cell *getline(Node **a, int n) /* get next line from specific input */
33641abc59cSbostic { /* a[0] is variable, a[1] is operator, a[2] is filename */
33741abc59cSbostic register Cell *r, *x;
33841abc59cSbostic uchar buf[RECSIZE];
33941abc59cSbostic FILE *fp;
34041abc59cSbostic
34141abc59cSbostic fflush(stdout); /* in case someone is waiting for a prompt */
34241abc59cSbostic r = gettemp();
34341abc59cSbostic if (a[1] != NULL) { /* getline < file */
34441abc59cSbostic x = execute(a[2]); /* filename */
34541abc59cSbostic if ((int) a[1] == '|') /* input pipe */
34641abc59cSbostic a[1] = (Node *) LE; /* arbitrary flag */
34741abc59cSbostic fp = openfile((int) a[1], getsval(x));
34841abc59cSbostic tempfree(x);
34941abc59cSbostic if (fp == NULL)
35041abc59cSbostic n = -1;
35141abc59cSbostic else
35241abc59cSbostic n = readrec(buf, sizeof(buf), fp);
35341abc59cSbostic if (n <= 0) {
35441abc59cSbostic ;
35541abc59cSbostic } else if (a[0] != NULL) { /* getline var <file */
35641abc59cSbostic setsval(execute(a[0]), buf);
35741abc59cSbostic } else { /* getline <file */
35841abc59cSbostic if (!(recloc->tval & DONTFREE))
35941abc59cSbostic xfree(recloc->sval);
36041abc59cSbostic strcpy(record, buf);
36141abc59cSbostic recloc->sval = record;
36241abc59cSbostic recloc->tval = REC | STR | DONTFREE;
363*72bcf366Sbostic if (is_a_number(recloc->sval)) {
36441abc59cSbostic recloc->fval = atof(recloc->sval);
36541abc59cSbostic recloc->tval |= NUM;
36641abc59cSbostic }
36741abc59cSbostic donerec = 1; donefld = 0;
36841abc59cSbostic }
36941abc59cSbostic } else { /* bare getline; use current input */
37041abc59cSbostic if (a[0] == NULL) /* getline */
37141abc59cSbostic n = getrec(record);
37241abc59cSbostic else { /* getline var */
37341abc59cSbostic n = getrec(buf);
37441abc59cSbostic setsval(execute(a[0]), buf);
37541abc59cSbostic }
37641abc59cSbostic }
37741abc59cSbostic setfval(r, (Awkfloat) n);
37841abc59cSbostic return r;
37941abc59cSbostic }
38041abc59cSbostic
getnf(Node ** a,int n)38141abc59cSbostic Cell *getnf(Node **a, int n) /* get NF */
38241abc59cSbostic {
38341abc59cSbostic if (donefld == 0)
38441abc59cSbostic fldbld();
38541abc59cSbostic return (Cell *) a[0];
38641abc59cSbostic }
38741abc59cSbostic
array(Node ** a,int n)38841abc59cSbostic Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
38941abc59cSbostic {
39041abc59cSbostic register Cell *x, *y, *z;
39141abc59cSbostic register uchar *s;
39241abc59cSbostic register Node *np;
39341abc59cSbostic uchar buf[RECSIZE];
39441abc59cSbostic
39541abc59cSbostic x = execute(a[0]); /* Cell* for symbol table */
39641abc59cSbostic buf[0] = 0;
39741abc59cSbostic for (np = a[1]; np; np = np->nnext) {
39841abc59cSbostic y = execute(np); /* subscript */
39941abc59cSbostic s = getsval(y);
40041abc59cSbostic strcat(buf, s);
40141abc59cSbostic if (np->nnext)
40241abc59cSbostic strcat(buf, *SUBSEP);
40341abc59cSbostic tempfree(y);
40441abc59cSbostic }
40541abc59cSbostic if (!isarr(x)) {
40641abc59cSbostic dprintf( ("making %s into an array\n", x->nval) );
40741abc59cSbostic if (freeable(x))
40841abc59cSbostic xfree(x->sval);
40941abc59cSbostic x->tval &= ~(STR|NUM|DONTFREE);
41041abc59cSbostic x->tval |= ARR;
41141abc59cSbostic x->sval = (uchar *) makesymtab(NSYMTAB);
41241abc59cSbostic }
41341abc59cSbostic z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
41441abc59cSbostic z->ctype = OCELL;
41541abc59cSbostic z->csub = CVAR;
41641abc59cSbostic tempfree(x);
41741abc59cSbostic return(z);
41841abc59cSbostic }
41941abc59cSbostic
adelete(Node ** a,int n)42041abc59cSbostic Cell *adelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
42141abc59cSbostic {
42241abc59cSbostic Cell *x, *y;
42341abc59cSbostic Node *np;
42441abc59cSbostic uchar buf[RECSIZE], *s;
42541abc59cSbostic
42641abc59cSbostic x = execute(a[0]); /* Cell* for symbol table */
42741abc59cSbostic if (!isarr(x))
42841abc59cSbostic return true;
42941abc59cSbostic buf[0] = 0;
43041abc59cSbostic for (np = a[1]; np; np = np->nnext) {
43141abc59cSbostic y = execute(np); /* subscript */
43241abc59cSbostic s = getsval(y);
43341abc59cSbostic strcat(buf, s);
43441abc59cSbostic if (np->nnext)
43541abc59cSbostic strcat(buf, *SUBSEP);
43641abc59cSbostic tempfree(y);
43741abc59cSbostic }
43841abc59cSbostic freeelem(x, buf);
43941abc59cSbostic tempfree(x);
44041abc59cSbostic return true;
44141abc59cSbostic }
44241abc59cSbostic
intest(Node ** a,int n)44341abc59cSbostic Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
44441abc59cSbostic {
44541abc59cSbostic register Cell *x, *ap, *k;
44641abc59cSbostic Node *p;
44741abc59cSbostic char buf[RECSIZE];
44841abc59cSbostic uchar *s;
44941abc59cSbostic
45041abc59cSbostic ap = execute(a[1]); /* array name */
45141abc59cSbostic if (!isarr(ap)) {
45241abc59cSbostic dprintf( ("making %s into an array\n", ap->nval) );
45341abc59cSbostic if (freeable(ap))
45441abc59cSbostic xfree(ap->sval);
45541abc59cSbostic ap->tval &= ~(STR|NUM|DONTFREE);
45641abc59cSbostic ap->tval |= ARR;
45741abc59cSbostic ap->sval = (uchar *) makesymtab(NSYMTAB);
45841abc59cSbostic }
45941abc59cSbostic buf[0] = 0;
46041abc59cSbostic for (p = a[0]; p; p = p->nnext) {
46141abc59cSbostic x = execute(p); /* expr */
46241abc59cSbostic s = getsval(x);
46341abc59cSbostic strcat(buf, s);
46441abc59cSbostic tempfree(x);
46541abc59cSbostic if (p->nnext)
46641abc59cSbostic strcat(buf, *SUBSEP);
46741abc59cSbostic }
46841abc59cSbostic k = lookup(buf, (Array *) ap->sval);
46941abc59cSbostic tempfree(ap);
47041abc59cSbostic if (k == NULL)
47141abc59cSbostic return(false);
47241abc59cSbostic else
47341abc59cSbostic return(true);
47441abc59cSbostic }
47541abc59cSbostic
47641abc59cSbostic
matchop(Node ** a,int n)47741abc59cSbostic Cell *matchop(Node **a, int n) /* ~ and match() */
47841abc59cSbostic {
47941abc59cSbostic register Cell *x, *y;
48041abc59cSbostic register uchar *s, *t;
48141abc59cSbostic register int i;
48241abc59cSbostic fa *pfa;
48341abc59cSbostic int (*mf)(fa *, uchar *) = match, mode = 0;
48441abc59cSbostic
48541abc59cSbostic if (n == MATCHFCN) {
48641abc59cSbostic mf = pmatch;
48741abc59cSbostic mode = 1;
48841abc59cSbostic }
48941abc59cSbostic x = execute(a[1]); /* a[1] = target text */
49041abc59cSbostic s = getsval(x);
49141abc59cSbostic if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
49241abc59cSbostic i = (*mf)((fa *) a[2], s);
49341abc59cSbostic else {
49441abc59cSbostic y = execute(a[2]); /* a[2] = regular expr */
49541abc59cSbostic t = getsval(y);
49641abc59cSbostic pfa = makedfa(t, mode);
49741abc59cSbostic i = (*mf)(pfa, s);
49841abc59cSbostic tempfree(y);
49941abc59cSbostic }
50041abc59cSbostic tempfree(x);
50141abc59cSbostic if (n == MATCHFCN) {
50241abc59cSbostic int start = patbeg - s + 1;
50341abc59cSbostic if (patlen < 0)
50441abc59cSbostic start = 0;
50541abc59cSbostic setfval(rstartloc, (Awkfloat) start);
50641abc59cSbostic setfval(rlengthloc, (Awkfloat) patlen);
50741abc59cSbostic x = gettemp();
50841abc59cSbostic x->tval = NUM;
50941abc59cSbostic x->fval = start;
51041abc59cSbostic return x;
51141abc59cSbostic } else if (n == MATCH && i == 1 || n == NOTMATCH && i == 0)
51241abc59cSbostic return(true);
51341abc59cSbostic else
51441abc59cSbostic return(false);
51541abc59cSbostic }
51641abc59cSbostic
51741abc59cSbostic
boolop(Node ** a,int n)51841abc59cSbostic Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
51941abc59cSbostic {
52041abc59cSbostic register Cell *x, *y;
52141abc59cSbostic register int i;
52241abc59cSbostic
52341abc59cSbostic x = execute(a[0]);
52441abc59cSbostic i = istrue(x);
52541abc59cSbostic tempfree(x);
52641abc59cSbostic switch (n) {
52741abc59cSbostic case BOR:
52841abc59cSbostic if (i) return(true);
52941abc59cSbostic y = execute(a[1]);
53041abc59cSbostic i = istrue(y);
53141abc59cSbostic tempfree(y);
53241abc59cSbostic if (i) return(true);
53341abc59cSbostic else return(false);
53441abc59cSbostic case AND:
53541abc59cSbostic if ( !i ) return(false);
53641abc59cSbostic y = execute(a[1]);
53741abc59cSbostic i = istrue(y);
53841abc59cSbostic tempfree(y);
53941abc59cSbostic if (i) return(true);
54041abc59cSbostic else return(false);
54141abc59cSbostic case NOT:
54241abc59cSbostic if (i) return(false);
54341abc59cSbostic else return(true);
54441abc59cSbostic default: /* can't happen */
54541abc59cSbostic ERROR "unknown boolean operator %d", n FATAL;
54641abc59cSbostic }
54741abc59cSbostic return 0; /*NOTREACHED*/
54841abc59cSbostic }
54941abc59cSbostic
relop(Node ** a,int n)55041abc59cSbostic Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
55141abc59cSbostic {
55241abc59cSbostic register int i;
55341abc59cSbostic register Cell *x, *y;
55441abc59cSbostic Awkfloat j;
55541abc59cSbostic
55641abc59cSbostic x = execute(a[0]);
55741abc59cSbostic y = execute(a[1]);
55841abc59cSbostic if (x->tval&NUM && y->tval&NUM) {
55941abc59cSbostic j = x->fval - y->fval;
56041abc59cSbostic i = j<0? -1: (j>0? 1: 0);
56141abc59cSbostic } else {
56241abc59cSbostic i = strcmp(getsval(x), getsval(y));
56341abc59cSbostic }
56441abc59cSbostic tempfree(x);
56541abc59cSbostic tempfree(y);
56641abc59cSbostic switch (n) {
56741abc59cSbostic case LT: if (i<0) return(true);
56841abc59cSbostic else return(false);
56941abc59cSbostic case LE: if (i<=0) return(true);
57041abc59cSbostic else return(false);
57141abc59cSbostic case NE: if (i!=0) return(true);
57241abc59cSbostic else return(false);
57341abc59cSbostic case EQ: if (i == 0) return(true);
57441abc59cSbostic else return(false);
57541abc59cSbostic case GE: if (i>=0) return(true);
57641abc59cSbostic else return(false);
57741abc59cSbostic case GT: if (i>0) return(true);
57841abc59cSbostic else return(false);
57941abc59cSbostic default: /* can't happen */
58041abc59cSbostic ERROR "unknown relational operator %d", n FATAL;
58141abc59cSbostic }
58241abc59cSbostic return 0; /*NOTREACHED*/
58341abc59cSbostic }
58441abc59cSbostic
tfree(Cell * a)58541abc59cSbostic void tfree(Cell *a) /* free a tempcell */
58641abc59cSbostic {
58741abc59cSbostic if (freeable(a))
58841abc59cSbostic xfree(a->sval);
58941abc59cSbostic if (a == tmps)
59041abc59cSbostic ERROR "tempcell list is curdled" FATAL;
59141abc59cSbostic a->cnext = tmps;
59241abc59cSbostic tmps = a;
59341abc59cSbostic }
59441abc59cSbostic
gettemp(void)59541abc59cSbostic Cell *gettemp(void) /* get a tempcell */
59641abc59cSbostic { int i;
59741abc59cSbostic register Cell *x;
59841abc59cSbostic
59941abc59cSbostic if (!tmps) {
60041abc59cSbostic tmps = (Cell *) calloc(100, sizeof(Cell));
60141abc59cSbostic if (!tmps)
60241abc59cSbostic ERROR "out of space for temporaries" FATAL;
60341abc59cSbostic for(i = 1; i < 100; i++)
60441abc59cSbostic tmps[i-1].cnext = &tmps[i];
60541abc59cSbostic tmps[i-1].cnext = 0;
60641abc59cSbostic }
60741abc59cSbostic x = tmps;
60841abc59cSbostic tmps = x->cnext;
60941abc59cSbostic *x = tempcell;
61041abc59cSbostic return(x);
61141abc59cSbostic }
61241abc59cSbostic
indirect(Node ** a,int n)61341abc59cSbostic Cell *indirect(Node **a, int n) /* $( a[0] ) */
61441abc59cSbostic {
61541abc59cSbostic register Cell *x;
61641abc59cSbostic register int m;
61741abc59cSbostic register uchar *s;
61841abc59cSbostic
61941abc59cSbostic x = execute(a[0]);
62041abc59cSbostic m = getfval(x);
621*72bcf366Sbostic if (m == 0 && !is_a_number(s = getsval(x))) /* suspicion! */
62241abc59cSbostic ERROR "illegal field $(%s), name \"%s\"", s, x->nval FATAL;
62341abc59cSbostic /* can x->nval ever be null??? */
62441abc59cSbostic /* ERROR "illegal field $(%s)", s FATAL; */
62541abc59cSbostic tempfree(x);
62641abc59cSbostic x = fieldadr(m);
62741abc59cSbostic x->ctype = OCELL;
62841abc59cSbostic x->csub = CFLD;
62941abc59cSbostic return(x);
63041abc59cSbostic }
63141abc59cSbostic
substr(Node ** a,int nnn)63241abc59cSbostic Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
63341abc59cSbostic {
63441abc59cSbostic register int k, m, n;
63541abc59cSbostic register uchar *s;
63641abc59cSbostic int temp;
63741abc59cSbostic register Cell *x, *y, *z;
63841abc59cSbostic
63941abc59cSbostic x = execute(a[0]);
64041abc59cSbostic y = execute(a[1]);
64141abc59cSbostic if (a[2] != 0)
64241abc59cSbostic z = execute(a[2]);
64341abc59cSbostic s = getsval(x);
64441abc59cSbostic k = strlen(s) + 1;
64541abc59cSbostic if (k <= 1) {
64641abc59cSbostic tempfree(x);
64741abc59cSbostic tempfree(y);
64841abc59cSbostic if (a[2] != 0)
64941abc59cSbostic tempfree(z);
65041abc59cSbostic x = gettemp();
65141abc59cSbostic setsval(x, "");
65241abc59cSbostic return(x);
65341abc59cSbostic }
65441abc59cSbostic m = getfval(y);
65541abc59cSbostic if (m <= 0)
65641abc59cSbostic m = 1;
65741abc59cSbostic else if (m > k)
65841abc59cSbostic m = k;
65941abc59cSbostic tempfree(y);
66041abc59cSbostic if (a[2] != 0) {
66141abc59cSbostic n = getfval(z);
66241abc59cSbostic tempfree(z);
66341abc59cSbostic } else
66441abc59cSbostic n = k - 1;
66541abc59cSbostic if (n < 0)
66641abc59cSbostic n = 0;
66741abc59cSbostic else if (n > k - m)
66841abc59cSbostic n = k - m;
66941abc59cSbostic dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
67041abc59cSbostic y = gettemp();
67141abc59cSbostic temp = s[n+m-1]; /* with thanks to John Linderman */
67241abc59cSbostic s[n+m-1] = '\0';
67341abc59cSbostic setsval(y, s + m - 1);
67441abc59cSbostic s[n+m-1] = temp;
67541abc59cSbostic tempfree(x);
67641abc59cSbostic return(y);
67741abc59cSbostic }
67841abc59cSbostic
sindex(Node ** a,int nnn)67941abc59cSbostic Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
68041abc59cSbostic {
68141abc59cSbostic register Cell *x, *y, *z;
68241abc59cSbostic register uchar *s1, *s2, *p1, *p2, *q;
68341abc59cSbostic Awkfloat v = 0.0;
68441abc59cSbostic
68541abc59cSbostic x = execute(a[0]);
68641abc59cSbostic s1 = getsval(x);
68741abc59cSbostic y = execute(a[1]);
68841abc59cSbostic s2 = getsval(y);
68941abc59cSbostic
69041abc59cSbostic z = gettemp();
69141abc59cSbostic for (p1 = s1; *p1 != '\0'; p1++) {
69241abc59cSbostic for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
69341abc59cSbostic ;
69441abc59cSbostic if (*p2 == '\0') {
69541abc59cSbostic v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
69641abc59cSbostic break;
69741abc59cSbostic }
69841abc59cSbostic }
69941abc59cSbostic tempfree(x);
70041abc59cSbostic tempfree(y);
70141abc59cSbostic setfval(z, v);
70241abc59cSbostic return(z);
70341abc59cSbostic }
70441abc59cSbostic
format(uchar * buf,int bufsize,uchar * s,Node * a)70541abc59cSbostic format(uchar *buf, int bufsize, uchar *s, Node *a) /* printf-like conversions */
70641abc59cSbostic {
70741abc59cSbostic uchar fmt[RECSIZE];
70841abc59cSbostic register uchar *p, *t, *os;
70941abc59cSbostic register Cell *x;
71041abc59cSbostic int flag = 0, n;
71141abc59cSbostic
71241abc59cSbostic os = s;
71341abc59cSbostic p = buf;
71441abc59cSbostic while (*s) {
71541abc59cSbostic if (p - buf >= bufsize)
71641abc59cSbostic return -1;
71741abc59cSbostic if (*s != '%') {
71841abc59cSbostic *p++ = *s++;
71941abc59cSbostic continue;
72041abc59cSbostic }
72141abc59cSbostic if (*(s+1) == '%') {
72241abc59cSbostic *p++ = '%';
72341abc59cSbostic s += 2;
72441abc59cSbostic continue;
72541abc59cSbostic }
72641abc59cSbostic for (t=fmt; (*t++ = *s) != '\0'; s++) {
72741abc59cSbostic if (isalpha(*s) && *s != 'l' && *s != 'h' && *s != 'L')
72841abc59cSbostic break; /* the ansi panoply */
72941abc59cSbostic if (*s == '*') {
73041abc59cSbostic x = execute(a);
73141abc59cSbostic a = a->nnext;
73241abc59cSbostic sprintf((char *)t-1, "%d", (int) getfval(x));
73341abc59cSbostic t = fmt + strlen(fmt);
73441abc59cSbostic tempfree(x);
73541abc59cSbostic }
73641abc59cSbostic }
73741abc59cSbostic *t = '\0';
73841abc59cSbostic if (t >= fmt + sizeof(fmt))
73941abc59cSbostic ERROR "format item %.30s... too long", os FATAL;
74041abc59cSbostic switch (*s) {
74141abc59cSbostic case 'f': case 'e': case 'g': case 'E': case 'G':
74241abc59cSbostic flag = 1;
74341abc59cSbostic break;
74441abc59cSbostic case 'd': case 'i':
74541abc59cSbostic flag = 2;
74641abc59cSbostic if(*(s-1) == 'l') break;
74741abc59cSbostic *(t-1) = 'l';
74841abc59cSbostic *t = 'd';
74941abc59cSbostic *++t = '\0';
75041abc59cSbostic break;
75141abc59cSbostic case 'o': case 'x': case 'X': case 'u':
75241abc59cSbostic flag = *(s-1) == 'l' ? 2 : 3;
75341abc59cSbostic break;
75441abc59cSbostic case 's':
75541abc59cSbostic flag = 4;
75641abc59cSbostic break;
75741abc59cSbostic case 'c':
75841abc59cSbostic flag = 5;
75941abc59cSbostic break;
76041abc59cSbostic default:
76141abc59cSbostic ERROR "weird printf conversion %s", fmt WARNING;
76241abc59cSbostic flag = 0;
76341abc59cSbostic break;
76441abc59cSbostic }
76541abc59cSbostic if (a == NULL)
76641abc59cSbostic ERROR "not enough args in printf(%s)", os FATAL;
76741abc59cSbostic x = execute(a);
76841abc59cSbostic a = a->nnext;
76941abc59cSbostic switch (flag) {
77041abc59cSbostic case 0: sprintf((char *)p, "%s", fmt); /* unknown, so dump it too */
77141abc59cSbostic p += strlen(p);
77241abc59cSbostic sprintf((char *)p, "%s", getsval(x));
77341abc59cSbostic break;
77441abc59cSbostic case 1: sprintf((char *)p, (char *)fmt, getfval(x)); break;
77541abc59cSbostic case 2: sprintf((char *)p, (char *)fmt, (long) getfval(x)); break;
77641abc59cSbostic case 3: sprintf((char *)p, (char *)fmt, (int) getfval(x)); break;
77741abc59cSbostic case 4:
77841abc59cSbostic t = getsval(x);
77941abc59cSbostic n = strlen(t);
78041abc59cSbostic if (n >= bufsize)
78141abc59cSbostic ERROR "huge string (%d chars) in printf %.30s...",
78241abc59cSbostic n, t FATAL;
78341abc59cSbostic sprintf((char *)p, (char *)fmt, t);
78441abc59cSbostic break;
78541abc59cSbostic case 5:
78641abc59cSbostic isnum(x) ? sprintf((char *)p, (char *)fmt, (int) getfval(x))
78741abc59cSbostic : sprintf((char *)p, (char *)fmt, getsval(x)[0]);
78841abc59cSbostic break;
78941abc59cSbostic }
79041abc59cSbostic tempfree(x);
79141abc59cSbostic p += strlen(p);
79241abc59cSbostic s++;
79341abc59cSbostic }
79441abc59cSbostic *p = '\0';
79541abc59cSbostic for ( ; a; a = a->nnext) /* evaluate any remaining args */
79641abc59cSbostic execute(a);
79741abc59cSbostic return 0;
79841abc59cSbostic }
79941abc59cSbostic
asprintf(Node ** a,int n)80041abc59cSbostic Cell *asprintf(Node **a, int n) /* sprintf(a[0]) */
80141abc59cSbostic {
80241abc59cSbostic register Cell *x;
80341abc59cSbostic register Node *y;
80441abc59cSbostic uchar buf[3*RECSIZE];
80541abc59cSbostic
80641abc59cSbostic y = a[0]->nnext;
80741abc59cSbostic x = execute(a[0]);
80841abc59cSbostic if (format(buf, sizeof buf, getsval(x), y) == -1)
80941abc59cSbostic ERROR "sprintf string %.30s... too long", buf FATAL;
81041abc59cSbostic tempfree(x);
81141abc59cSbostic x = gettemp();
81241abc59cSbostic x->sval = tostring(buf);
81341abc59cSbostic x->tval = STR;
81441abc59cSbostic return(x);
81541abc59cSbostic }
81641abc59cSbostic
aprintf(Node ** a,int n)81741abc59cSbostic Cell *aprintf(Node **a, int n) /* printf */
81841abc59cSbostic { /* a[0] is list of args, starting with format string */
81941abc59cSbostic /* a[1] is redirection operator, a[2] is redirection file */
82041abc59cSbostic FILE *fp;
82141abc59cSbostic register Cell *x;
82241abc59cSbostic register Node *y;
82341abc59cSbostic uchar buf[3*RECSIZE];
82441abc59cSbostic
82541abc59cSbostic y = a[0]->nnext;
82641abc59cSbostic x = execute(a[0]);
82741abc59cSbostic if (format(buf, sizeof buf, getsval(x), y) == -1)
82841abc59cSbostic ERROR "printf string %.30s... too long", buf FATAL;
82941abc59cSbostic tempfree(x);
83041abc59cSbostic if (a[1] == NULL) {
83141abc59cSbostic fputs((char *)buf, stdout);
83241abc59cSbostic if (ferror(stdout))
83341abc59cSbostic ERROR "write error on stdout" FATAL;
83441abc59cSbostic } else {
83541abc59cSbostic fp = redirect((int)a[1], a[2]);
83641abc59cSbostic fputs((char *)buf, fp);
83741abc59cSbostic fflush(fp);
83841abc59cSbostic if (ferror(fp))
83941abc59cSbostic ERROR "write error on %s", filename(fp) FATAL;
84041abc59cSbostic }
84141abc59cSbostic return(true);
84241abc59cSbostic }
84341abc59cSbostic
arith(Node ** a,int n)84441abc59cSbostic Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
84541abc59cSbostic {
84641abc59cSbostic Awkfloat i, j;
84741abc59cSbostic double v;
84841abc59cSbostic register Cell *x, *y, *z;
84941abc59cSbostic
85041abc59cSbostic x = execute(a[0]);
85141abc59cSbostic i = getfval(x);
85241abc59cSbostic tempfree(x);
85341abc59cSbostic if (n != UMINUS) {
85441abc59cSbostic y = execute(a[1]);
85541abc59cSbostic j = getfval(y);
85641abc59cSbostic tempfree(y);
85741abc59cSbostic }
85841abc59cSbostic z = gettemp();
85941abc59cSbostic switch (n) {
86041abc59cSbostic case ADD:
86141abc59cSbostic i += j;
86241abc59cSbostic break;
86341abc59cSbostic case MINUS:
86441abc59cSbostic i -= j;
86541abc59cSbostic break;
86641abc59cSbostic case MULT:
86741abc59cSbostic i *= j;
86841abc59cSbostic break;
86941abc59cSbostic case DIVIDE:
87041abc59cSbostic if (j == 0)
87141abc59cSbostic ERROR "division by zero" FATAL;
87241abc59cSbostic i /= j;
87341abc59cSbostic break;
87441abc59cSbostic case MOD:
87541abc59cSbostic if (j == 0)
87641abc59cSbostic ERROR "division by zero in mod" FATAL;
87741abc59cSbostic modf(i/j, &v);
87841abc59cSbostic i = i - j * v;
87941abc59cSbostic break;
88041abc59cSbostic case UMINUS:
88141abc59cSbostic i = -i;
88241abc59cSbostic break;
88341abc59cSbostic case POWER:
88441abc59cSbostic if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
88541abc59cSbostic i = ipow(i, (int) j);
88641abc59cSbostic else
88741abc59cSbostic i = errcheck(pow(i, j), "pow");
88841abc59cSbostic break;
88941abc59cSbostic default: /* can't happen */
89041abc59cSbostic ERROR "illegal arithmetic operator %d", n FATAL;
89141abc59cSbostic }
89241abc59cSbostic setfval(z, i);
89341abc59cSbostic return(z);
89441abc59cSbostic }
89541abc59cSbostic
ipow(double x,int n)89641abc59cSbostic double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
89741abc59cSbostic {
89841abc59cSbostic double v;
89941abc59cSbostic
90041abc59cSbostic if (n <= 0)
90141abc59cSbostic return 1;
90241abc59cSbostic v = ipow(x, n/2);
90341abc59cSbostic if (n % 2 == 0)
90441abc59cSbostic return v * v;
90541abc59cSbostic else
90641abc59cSbostic return x * v * v;
90741abc59cSbostic }
90841abc59cSbostic
incrdecr(Node ** a,int n)90941abc59cSbostic Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
91041abc59cSbostic {
91141abc59cSbostic register Cell *x, *z;
91241abc59cSbostic register int k;
91341abc59cSbostic Awkfloat xf;
91441abc59cSbostic
91541abc59cSbostic x = execute(a[0]);
91641abc59cSbostic xf = getfval(x);
91741abc59cSbostic k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
91841abc59cSbostic if (n == PREINCR || n == PREDECR) {
91941abc59cSbostic setfval(x, xf + k);
92041abc59cSbostic return(x);
92141abc59cSbostic }
92241abc59cSbostic z = gettemp();
92341abc59cSbostic setfval(z, xf);
92441abc59cSbostic setfval(x, xf + k);
92541abc59cSbostic tempfree(x);
92641abc59cSbostic return(z);
92741abc59cSbostic }
92841abc59cSbostic
assign(Node ** a,int n)92941abc59cSbostic Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
93041abc59cSbostic { /* this is subtle; don't muck with it. */
93141abc59cSbostic register Cell *x, *y;
93241abc59cSbostic Awkfloat xf, yf;
93341abc59cSbostic double v;
93441abc59cSbostic
93541abc59cSbostic y = execute(a[1]);
93641abc59cSbostic x = execute(a[0]);
93741abc59cSbostic if (n == ASSIGN) { /* ordinary assignment */
93841abc59cSbostic if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
93941abc59cSbostic ; /* leave alone unless it's a field */
94041abc59cSbostic else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
94141abc59cSbostic setsval(x, getsval(y));
94241abc59cSbostic x->fval = getfval(y);
94341abc59cSbostic x->tval |= NUM;
94441abc59cSbostic }
94541abc59cSbostic else if (y->tval & STR)
94641abc59cSbostic setsval(x, getsval(y));
94741abc59cSbostic else if (y->tval & NUM)
94841abc59cSbostic setfval(x, getfval(y));
94941abc59cSbostic else
95041abc59cSbostic funnyvar(y, "read value of");
95141abc59cSbostic tempfree(y);
95241abc59cSbostic return(x);
95341abc59cSbostic }
95441abc59cSbostic xf = getfval(x);
95541abc59cSbostic yf = getfval(y);
95641abc59cSbostic switch (n) {
95741abc59cSbostic case ADDEQ:
95841abc59cSbostic xf += yf;
95941abc59cSbostic break;
96041abc59cSbostic case SUBEQ:
96141abc59cSbostic xf -= yf;
96241abc59cSbostic break;
96341abc59cSbostic case MULTEQ:
96441abc59cSbostic xf *= yf;
96541abc59cSbostic break;
96641abc59cSbostic case DIVEQ:
96741abc59cSbostic if (yf == 0)
96841abc59cSbostic ERROR "division by zero in /=" FATAL;
96941abc59cSbostic xf /= yf;
97041abc59cSbostic break;
97141abc59cSbostic case MODEQ:
97241abc59cSbostic if (yf == 0)
97341abc59cSbostic ERROR "division by zero in %%=" FATAL;
97441abc59cSbostic modf(xf/yf, &v);
97541abc59cSbostic xf = xf - yf * v;
97641abc59cSbostic break;
97741abc59cSbostic case POWEQ:
97841abc59cSbostic if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
97941abc59cSbostic xf = ipow(xf, (int) yf);
98041abc59cSbostic else
98141abc59cSbostic xf = errcheck(pow(xf, yf), "pow");
98241abc59cSbostic break;
98341abc59cSbostic default:
98441abc59cSbostic ERROR "illegal assignment operator %d", n FATAL;
98541abc59cSbostic break;
98641abc59cSbostic }
98741abc59cSbostic tempfree(y);
98841abc59cSbostic setfval(x, xf);
98941abc59cSbostic return(x);
99041abc59cSbostic }
99141abc59cSbostic
cat(Node ** a,int q)99241abc59cSbostic Cell *cat(Node **a, int q) /* a[0] cat a[1] */
99341abc59cSbostic {
99441abc59cSbostic register Cell *x, *y, *z;
99541abc59cSbostic register int n1, n2;
99641abc59cSbostic register uchar *s;
99741abc59cSbostic
99841abc59cSbostic x = execute(a[0]);
99941abc59cSbostic y = execute(a[1]);
100041abc59cSbostic getsval(x);
100141abc59cSbostic getsval(y);
100241abc59cSbostic n1 = strlen(x->sval);
100341abc59cSbostic n2 = strlen(y->sval);
100441abc59cSbostic s = (uchar *) malloc(n1 + n2 + 1);
100541abc59cSbostic if (s == NULL)
100641abc59cSbostic ERROR "out of space concatenating %.15s... and %.15s...",
100741abc59cSbostic x->sval, y->sval FATAL;
100841abc59cSbostic strcpy(s, x->sval);
100941abc59cSbostic strcpy(s+n1, y->sval);
101041abc59cSbostic tempfree(y);
101141abc59cSbostic z = gettemp();
101241abc59cSbostic z->sval = s;
101341abc59cSbostic z->tval = STR;
101441abc59cSbostic tempfree(x);
101541abc59cSbostic return(z);
101641abc59cSbostic }
101741abc59cSbostic
pastat(Node ** a,int n)101841abc59cSbostic Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
101941abc59cSbostic {
102041abc59cSbostic register Cell *x;
102141abc59cSbostic
102241abc59cSbostic if (a[0] == 0)
102341abc59cSbostic x = execute(a[1]);
102441abc59cSbostic else {
102541abc59cSbostic x = execute(a[0]);
102641abc59cSbostic if (istrue(x)) {
102741abc59cSbostic tempfree(x);
102841abc59cSbostic x = execute(a[1]);
102941abc59cSbostic }
103041abc59cSbostic }
103141abc59cSbostic return x;
103241abc59cSbostic }
103341abc59cSbostic
dopa2(Node ** a,int n)103441abc59cSbostic Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
103541abc59cSbostic {
103641abc59cSbostic register Cell *x;
103741abc59cSbostic register int pair;
103841abc59cSbostic
103941abc59cSbostic pair = (int) a[3];
104041abc59cSbostic if (pairstack[pair] == 0) {
104141abc59cSbostic x = execute(a[0]);
104241abc59cSbostic if (istrue(x))
104341abc59cSbostic pairstack[pair] = 1;
104441abc59cSbostic tempfree(x);
104541abc59cSbostic }
104641abc59cSbostic if (pairstack[pair] == 1) {
104741abc59cSbostic x = execute(a[1]);
104841abc59cSbostic if (istrue(x))
104941abc59cSbostic pairstack[pair] = 0;
105041abc59cSbostic tempfree(x);
105141abc59cSbostic x = execute(a[2]);
105241abc59cSbostic return(x);
105341abc59cSbostic }
105441abc59cSbostic return(false);
105541abc59cSbostic }
105641abc59cSbostic
split(Node ** a,int nnn)105741abc59cSbostic Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
105841abc59cSbostic {
105941abc59cSbostic Cell *x, *y, *ap;
106041abc59cSbostic register uchar *s;
106141abc59cSbostic register int sep;
106241abc59cSbostic uchar *t, temp, num[10], *fs;
106341abc59cSbostic int n, tempstat;
106441abc59cSbostic
106541abc59cSbostic y = execute(a[0]); /* source string */
106641abc59cSbostic s = getsval(y);
106741abc59cSbostic if (a[2] == 0) /* fs string */
106841abc59cSbostic fs = *FS;
106941abc59cSbostic else if ((int) a[3] == STRING) { /* split(str,arr,"string") */
107041abc59cSbostic x = execute(a[2]);
107141abc59cSbostic fs = getsval(x);
107241abc59cSbostic } else if ((int) a[3] == REGEXPR)
107341abc59cSbostic fs = (uchar*) "(regexpr)"; /* split(str,arr,/regexpr/) */
107441abc59cSbostic else
107541abc59cSbostic ERROR "illegal type of split()" FATAL;
107641abc59cSbostic sep = *fs;
107741abc59cSbostic ap = execute(a[1]); /* array name */
107841abc59cSbostic freesymtab(ap);
107941abc59cSbostic dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, ap->nval, fs) );
108041abc59cSbostic ap->tval &= ~STR;
108141abc59cSbostic ap->tval |= ARR;
108241abc59cSbostic ap->sval = (uchar *) makesymtab(NSYMTAB);
108341abc59cSbostic
108441abc59cSbostic n = 0;
108541abc59cSbostic if (*s != '\0' && strlen(fs) > 1 || (int) a[3] == REGEXPR) { /* reg expr */
108641abc59cSbostic fa *pfa;
108741abc59cSbostic if ((int) a[3] == REGEXPR) { /* it's ready already */
108841abc59cSbostic pfa = (fa *) a[2];
108941abc59cSbostic } else {
109041abc59cSbostic pfa = makedfa(fs, 1);
109141abc59cSbostic }
109241abc59cSbostic if (nematch(pfa,s)) {
109341abc59cSbostic tempstat = pfa->initstat;
109441abc59cSbostic pfa->initstat = 2;
109541abc59cSbostic do {
109641abc59cSbostic n++;
109741abc59cSbostic sprintf((char *)num, "%d", n);
109841abc59cSbostic temp = *patbeg;
109941abc59cSbostic *patbeg = '\0';
1100*72bcf366Sbostic if (is_a_number(s))
110141abc59cSbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
110241abc59cSbostic else
110341abc59cSbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
110441abc59cSbostic *patbeg = temp;
110541abc59cSbostic s = patbeg + patlen;
110641abc59cSbostic if (*(patbeg+patlen-1) == 0 || *s == 0) {
110741abc59cSbostic n++;
110841abc59cSbostic sprintf((char *)num, "%d", n);
110941abc59cSbostic setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
111041abc59cSbostic pfa->initstat = tempstat;
111141abc59cSbostic goto spdone;
111241abc59cSbostic }
111341abc59cSbostic } while (nematch(pfa,s));
111441abc59cSbostic }
111541abc59cSbostic n++;
111641abc59cSbostic sprintf((char *)num, "%d", n);
1117*72bcf366Sbostic if (is_a_number(s))
111841abc59cSbostic setsymtab(num, s, atof((char *)s), STR|NUM, (Array *) ap->sval);
111941abc59cSbostic else
112041abc59cSbostic setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
112141abc59cSbostic spdone:
112241abc59cSbostic pfa = NULL;
112341abc59cSbostic } else if (sep == ' ') {
112441abc59cSbostic for (n = 0; ; ) {
112541abc59cSbostic while (*s == ' ' || *s == '\t' || *s == '\n')
112641abc59cSbostic s++;
112741abc59cSbostic if (*s == 0)
112841abc59cSbostic break;
112941abc59cSbostic n++;
113041abc59cSbostic t = s;
113141abc59cSbostic do
113241abc59cSbostic s++;
113341abc59cSbostic while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
113441abc59cSbostic temp = *s;
113541abc59cSbostic *s = '\0';
113641abc59cSbostic sprintf((char *)num, "%d", n);
1137*72bcf366Sbostic if (is_a_number(t))
113841abc59cSbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
113941abc59cSbostic else
114041abc59cSbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
114141abc59cSbostic *s = temp;
114241abc59cSbostic if (*s != 0)
114341abc59cSbostic s++;
114441abc59cSbostic }
114541abc59cSbostic } else if (*s != 0) {
114641abc59cSbostic for (;;) {
114741abc59cSbostic n++;
114841abc59cSbostic t = s;
114941abc59cSbostic while (*s != sep && *s != '\n' && *s != '\0')
115041abc59cSbostic s++;
115141abc59cSbostic temp = *s;
115241abc59cSbostic *s = '\0';
115341abc59cSbostic sprintf((char *)num, "%d", n);
1154*72bcf366Sbostic if (is_a_number(t))
115541abc59cSbostic setsymtab(num, t, atof((char *)t), STR|NUM, (Array *) ap->sval);
115641abc59cSbostic else
115741abc59cSbostic setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
115841abc59cSbostic *s = temp;
115941abc59cSbostic if (*s++ == 0)
116041abc59cSbostic break;
116141abc59cSbostic }
116241abc59cSbostic }
116341abc59cSbostic tempfree(ap);
116441abc59cSbostic tempfree(y);
116541abc59cSbostic if (a[2] != 0 && (int) a[3] == STRING)
116641abc59cSbostic tempfree(x);
116741abc59cSbostic x = gettemp();
116841abc59cSbostic x->tval = NUM;
116941abc59cSbostic x->fval = n;
117041abc59cSbostic return(x);
117141abc59cSbostic }
117241abc59cSbostic
condexpr(Node ** a,int n)117341abc59cSbostic Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
117441abc59cSbostic {
117541abc59cSbostic register Cell *x;
117641abc59cSbostic
117741abc59cSbostic x = execute(a[0]);
117841abc59cSbostic if (istrue(x)) {
117941abc59cSbostic tempfree(x);
118041abc59cSbostic x = execute(a[1]);
118141abc59cSbostic } else {
118241abc59cSbostic tempfree(x);
118341abc59cSbostic x = execute(a[2]);
118441abc59cSbostic }
118541abc59cSbostic return(x);
118641abc59cSbostic }
118741abc59cSbostic
ifstat(Node ** a,int n)118841abc59cSbostic Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
118941abc59cSbostic {
119041abc59cSbostic register Cell *x;
119141abc59cSbostic
119241abc59cSbostic x = execute(a[0]);
119341abc59cSbostic if (istrue(x)) {
119441abc59cSbostic tempfree(x);
119541abc59cSbostic x = execute(a[1]);
119641abc59cSbostic } else if (a[2] != 0) {
119741abc59cSbostic tempfree(x);
119841abc59cSbostic x = execute(a[2]);
119941abc59cSbostic }
120041abc59cSbostic return(x);
120141abc59cSbostic }
120241abc59cSbostic
whilestat(Node ** a,int n)120341abc59cSbostic Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
120441abc59cSbostic {
120541abc59cSbostic register Cell *x;
120641abc59cSbostic
120741abc59cSbostic for (;;) {
120841abc59cSbostic x = execute(a[0]);
120941abc59cSbostic if (!istrue(x))
121041abc59cSbostic return(x);
121141abc59cSbostic tempfree(x);
121241abc59cSbostic x = execute(a[1]);
121341abc59cSbostic if (isbreak(x)) {
121441abc59cSbostic x = true;
121541abc59cSbostic return(x);
121641abc59cSbostic }
121741abc59cSbostic if (isnext(x) || isexit(x) || isret(x))
121841abc59cSbostic return(x);
121941abc59cSbostic tempfree(x);
122041abc59cSbostic }
122141abc59cSbostic }
122241abc59cSbostic
dostat(Node ** a,int n)122341abc59cSbostic Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
122441abc59cSbostic {
122541abc59cSbostic register Cell *x;
122641abc59cSbostic
122741abc59cSbostic for (;;) {
122841abc59cSbostic x = execute(a[0]);
122941abc59cSbostic if (isbreak(x))
123041abc59cSbostic return true;
123141abc59cSbostic if (isnext(x) || isexit(x) || isret(x))
123241abc59cSbostic return(x);
123341abc59cSbostic tempfree(x);
123441abc59cSbostic x = execute(a[1]);
123541abc59cSbostic if (!istrue(x))
123641abc59cSbostic return(x);
123741abc59cSbostic tempfree(x);
123841abc59cSbostic }
123941abc59cSbostic }
124041abc59cSbostic
forstat(Node ** a,int n)124141abc59cSbostic Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
124241abc59cSbostic {
124341abc59cSbostic register Cell *x;
124441abc59cSbostic
124541abc59cSbostic x = execute(a[0]);
124641abc59cSbostic tempfree(x);
124741abc59cSbostic for (;;) {
124841abc59cSbostic if (a[1]!=0) {
124941abc59cSbostic x = execute(a[1]);
125041abc59cSbostic if (!istrue(x)) return(x);
125141abc59cSbostic else tempfree(x);
125241abc59cSbostic }
125341abc59cSbostic x = execute(a[3]);
125441abc59cSbostic if (isbreak(x)) /* turn off break */
125541abc59cSbostic return true;
125641abc59cSbostic if (isnext(x) || isexit(x) || isret(x))
125741abc59cSbostic return(x);
125841abc59cSbostic tempfree(x);
125941abc59cSbostic x = execute(a[2]);
126041abc59cSbostic tempfree(x);
126141abc59cSbostic }
126241abc59cSbostic }
126341abc59cSbostic
instat(Node ** a,int n)126441abc59cSbostic Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
126541abc59cSbostic {
126641abc59cSbostic register Cell *x, *vp, *arrayp, *cp, *ncp;
126741abc59cSbostic Array *tp;
126841abc59cSbostic int i;
126941abc59cSbostic
127041abc59cSbostic vp = execute(a[0]);
127141abc59cSbostic arrayp = execute(a[1]);
127241abc59cSbostic if (!isarr(arrayp)) {
127341abc59cSbostic return true;
127441abc59cSbostic }
127541abc59cSbostic tp = (Array *) arrayp->sval;
127641abc59cSbostic tempfree(arrayp);
127741abc59cSbostic for (i = 0; i < tp->size; i++) { /* this routine knows too much */
127841abc59cSbostic for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
127941abc59cSbostic setsval(vp, cp->nval);
128041abc59cSbostic ncp = cp->cnext;
128141abc59cSbostic x = execute(a[2]);
128241abc59cSbostic if (isbreak(x)) {
128341abc59cSbostic tempfree(vp);
128441abc59cSbostic return true;
128541abc59cSbostic }
128641abc59cSbostic if (isnext(x) || isexit(x) || isret(x)) {
128741abc59cSbostic tempfree(vp);
128841abc59cSbostic return(x);
128941abc59cSbostic }
129041abc59cSbostic tempfree(x);
129141abc59cSbostic }
129241abc59cSbostic }
129341abc59cSbostic return true;
129441abc59cSbostic }
129541abc59cSbostic
129641abc59cSbostic /* if someone ever wants to run over the arrays in sorted order, */
129741abc59cSbostic /* here it is. but it will likely run slower, not faster. */
129841abc59cSbostic
129941abc59cSbostic /*
130041abc59cSbostic *int qstrcmp(p, q)
130141abc59cSbostic * uchar **p, **q;
130241abc59cSbostic *{
130341abc59cSbostic * return strcmp(*p, *q);
130441abc59cSbostic *}
130541abc59cSbostic */
130641abc59cSbostic
130741abc59cSbostic /*Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
130841abc59cSbostic /*{
130941abc59cSbostic /* register Cell *x, *vp, *arrayp, *cp, *ncp, *ret;
131041abc59cSbostic /* Array *tp;
131141abc59cSbostic /* int i, ne;
131241abc59cSbostic /*#define BIGENOUGH 1000
131341abc59cSbostic /* uchar *elems[BIGENOUGH], **ep;
131441abc59cSbostic /*
131541abc59cSbostic /* vp = execute(a[0]);
131641abc59cSbostic /* arrayp = execute(a[1]);
131741abc59cSbostic /* if (!isarr(arrayp))
131841abc59cSbostic /* ERROR "%s is not an array", arrayp->nval FATAL;
131941abc59cSbostic /* tp = (Array *) arrayp->sval;
132041abc59cSbostic /* tempfree(arrayp);
132141abc59cSbostic /* ep = elems;
132241abc59cSbostic /* ret = true;
132341abc59cSbostic /* if (tp->nelem >= BIGENOUGH)
132441abc59cSbostic /* ep = (uchar **) malloc(tp->nelem * sizeof(char *));
132541abc59cSbostic /*
132641abc59cSbostic /* for (i = ne = 0; i < tp->size; i++)
132741abc59cSbostic /* for (cp = tp->tab[i]; cp != NULL; cp = cp->cnext)
132841abc59cSbostic /* ep[ne++] = cp->nval;
132941abc59cSbostic /* if (ne != tp->nelem)
133041abc59cSbostic /* ERROR "can't happen: lost elems %d vs. %d", ne, tp->nelem FATAL;
133141abc59cSbostic /* qsort(ep, ne, sizeof(char *), qstrcmp);
133241abc59cSbostic /* for (i = 0; i < ne; i++) {
133341abc59cSbostic /* setsval(vp, ep[i]);
133441abc59cSbostic /* x = execute(a[2]);
133541abc59cSbostic /* if (isbreak(x)) {
133641abc59cSbostic /* tempfree(vp);
133741abc59cSbostic /* break;
133841abc59cSbostic /* }
133941abc59cSbostic /* if (isnext(x) || isexit(x) || isret(x)) {
134041abc59cSbostic /* tempfree(vp);
134141abc59cSbostic /* ret = x;
134241abc59cSbostic /* break;
134341abc59cSbostic /* }
134441abc59cSbostic /* tempfree(x);
134541abc59cSbostic /* }
134641abc59cSbostic /* if (ep != elems)
134741abc59cSbostic /* free(ep);
134841abc59cSbostic /* return ret;
134941abc59cSbostic /*}
135041abc59cSbostic */
135141abc59cSbostic
135241abc59cSbostic
bltin(Node ** a,int n)135341abc59cSbostic Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
135441abc59cSbostic {
135541abc59cSbostic register Cell *x, *y;
135641abc59cSbostic Awkfloat u;
135741abc59cSbostic register int t;
135841abc59cSbostic uchar *p, buf[RECSIZE];
135941abc59cSbostic Node *nextarg;
136041abc59cSbostic FILE *fp;
136141abc59cSbostic
136241abc59cSbostic t = (int) a[0];
136341abc59cSbostic x = execute(a[1]);
136441abc59cSbostic nextarg = a[1]->nnext;
136541abc59cSbostic switch (t) {
136641abc59cSbostic case FLENGTH:
136741abc59cSbostic u = strlen(getsval(x)); break;
136841abc59cSbostic case FLOG:
136941abc59cSbostic u = errcheck(log(getfval(x)), "log"); break;
137041abc59cSbostic case FINT:
137141abc59cSbostic modf(getfval(x), &u); break;
137241abc59cSbostic case FEXP:
137341abc59cSbostic u = errcheck(exp(getfval(x)), "exp"); break;
137441abc59cSbostic case FSQRT:
137541abc59cSbostic u = errcheck(sqrt(getfval(x)), "sqrt"); break;
137641abc59cSbostic case FSIN:
137741abc59cSbostic u = sin(getfval(x)); break;
137841abc59cSbostic case FCOS:
137941abc59cSbostic u = cos(getfval(x)); break;
138041abc59cSbostic case FATAN:
138141abc59cSbostic if (nextarg == 0) {
138241abc59cSbostic ERROR "atan2 requires two arguments; returning 1.0" WARNING;
138341abc59cSbostic u = 1.0;
138441abc59cSbostic } else {
138541abc59cSbostic y = execute(a[1]->nnext);
138641abc59cSbostic u = atan2(getfval(x), getfval(y));
138741abc59cSbostic tempfree(y);
138841abc59cSbostic nextarg = nextarg->nnext;
138941abc59cSbostic }
139041abc59cSbostic break;
139141abc59cSbostic case FSYSTEM:
139241abc59cSbostic fflush(stdout); /* in case something is buffered already */
139341abc59cSbostic u = (Awkfloat) system((char *)getsval(x)) / 256; /* 256 is unix-dep */
139441abc59cSbostic break;
139541abc59cSbostic case FRAND:
139641abc59cSbostic /* in principle, rand() returns something in 0..RAND_MAX */
139741abc59cSbostic u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
139841abc59cSbostic break;
139941abc59cSbostic case FSRAND:
140041abc59cSbostic if (x->tval & REC) /* no argument provided */
140141abc59cSbostic u = time((long *)0);
140241abc59cSbostic else
140341abc59cSbostic u = getfval(x);
140441abc59cSbostic srand((int) u); u = (int) u;
140541abc59cSbostic break;
140641abc59cSbostic case FTOUPPER:
140741abc59cSbostic case FTOLOWER:
140841abc59cSbostic strcpy(buf, getsval(x));
140941abc59cSbostic if (t == FTOUPPER) {
141041abc59cSbostic for (p = buf; *p; p++)
141141abc59cSbostic if (islower(*p))
141241abc59cSbostic *p = toupper(*p);
141341abc59cSbostic } else {
141441abc59cSbostic for (p = buf; *p; p++)
141541abc59cSbostic if (isupper(*p))
141641abc59cSbostic *p = tolower(*p);
141741abc59cSbostic }
141841abc59cSbostic tempfree(x);
141941abc59cSbostic x = gettemp();
142041abc59cSbostic setsval(x, buf);
142141abc59cSbostic return x;
142241abc59cSbostic case FFLUSH:
142341abc59cSbostic if ((fp = openfile(GT, getsval(x))) == NULL)
142441abc59cSbostic u = EOF;
142541abc59cSbostic else
142641abc59cSbostic u = fflush(fp);
142741abc59cSbostic break;
142841abc59cSbostic default: /* can't happen */
142941abc59cSbostic ERROR "illegal function type %d", t FATAL;
143041abc59cSbostic break;
143141abc59cSbostic }
143241abc59cSbostic tempfree(x);
143341abc59cSbostic x = gettemp();
143441abc59cSbostic setfval(x, u);
143541abc59cSbostic if (nextarg != 0) {
143641abc59cSbostic ERROR "warning: function has too many arguments" WARNING;
143741abc59cSbostic for ( ; nextarg; nextarg = nextarg->nnext)
143841abc59cSbostic execute(nextarg);
143941abc59cSbostic }
144041abc59cSbostic return(x);
144141abc59cSbostic }
144241abc59cSbostic
printstat(Node ** a,int n)144341abc59cSbostic Cell *printstat(Node **a, int n) /* print a[0] */
144441abc59cSbostic {
144541abc59cSbostic register Node *x;
144641abc59cSbostic register Cell *y;
144741abc59cSbostic FILE *fp;
144841abc59cSbostic
144941abc59cSbostic if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
145041abc59cSbostic fp = stdout;
145141abc59cSbostic else
145241abc59cSbostic fp = redirect((int)a[1], a[2]);
145341abc59cSbostic for (x = a[0]; x != NULL; x = x->nnext) {
145441abc59cSbostic y = execute(x);
145541abc59cSbostic fputs((char *)getsval(y), fp);
145641abc59cSbostic tempfree(y);
145741abc59cSbostic if (x->nnext == NULL)
145841abc59cSbostic fputs((char *)*ORS, fp);
145941abc59cSbostic else
146041abc59cSbostic fputs((char *)*OFS, fp);
146141abc59cSbostic }
146241abc59cSbostic if (a[1] != 0)
146341abc59cSbostic fflush(fp);
146441abc59cSbostic if (ferror(fp))
146541abc59cSbostic ERROR "write error on %s", filename(fp) FATAL;
146641abc59cSbostic return(true);
146741abc59cSbostic }
146841abc59cSbostic
nullproc(Node ** a,int n)146941abc59cSbostic Cell *nullproc(Node **a, int n)
147041abc59cSbostic {
147141abc59cSbostic n;
147241abc59cSbostic a;
147341abc59cSbostic return 0;
147441abc59cSbostic }
147541abc59cSbostic
147641abc59cSbostic
redirect(int a,Node * b)147741abc59cSbostic FILE *redirect(int a, Node *b) /* set up all i/o redirections */
147841abc59cSbostic {
147941abc59cSbostic FILE *fp;
148041abc59cSbostic Cell *x;
148141abc59cSbostic uchar *fname;
148241abc59cSbostic
148341abc59cSbostic x = execute(b);
148441abc59cSbostic fname = getsval(x);
148541abc59cSbostic fp = openfile(a, fname);
148641abc59cSbostic if (fp == NULL)
148741abc59cSbostic ERROR "can't open file %s", fname FATAL;
148841abc59cSbostic tempfree(x);
148941abc59cSbostic return fp;
149041abc59cSbostic }
149141abc59cSbostic
149241abc59cSbostic struct files {
149341abc59cSbostic FILE *fp;
149441abc59cSbostic uchar *fname;
149541abc59cSbostic int mode; /* '|', 'a', 'w' => LE/LT, GT */
149641abc59cSbostic } files[FOPEN_MAX] ={
149741abc59cSbostic { stdin, "/dev/stdin", LT }, /* watch out: don't free this! */
149841abc59cSbostic { stdout, "/dev/stdout", GT },
149941abc59cSbostic { stderr, "/dev/stderr", GT }
150041abc59cSbostic };
150141abc59cSbostic
openfile(int a,uchar * us)150241abc59cSbostic FILE *openfile(int a, uchar *us)
150341abc59cSbostic {
150441abc59cSbostic char *s = us;
150541abc59cSbostic register int i, m;
150641abc59cSbostic register FILE *fp;
150741abc59cSbostic
150841abc59cSbostic if (*s == '\0')
150941abc59cSbostic ERROR "null file name in print or getline" FATAL;
151041abc59cSbostic for (i=0; i < FOPEN_MAX; i++)
151141abc59cSbostic if (files[i].fname && strcmp(s, files[i].fname) == 0)
151241abc59cSbostic if (a == files[i].mode || a==APPEND && files[i].mode==GT)
151341abc59cSbostic return files[i].fp;
151441abc59cSbostic for (i=0; i < FOPEN_MAX; i++)
151541abc59cSbostic if (files[i].fp == 0)
151641abc59cSbostic break;
151741abc59cSbostic if (i >= FOPEN_MAX)
151841abc59cSbostic ERROR "%s makes too many open files", s FATAL;
151941abc59cSbostic fflush(stdout); /* force a semblance of order */
152041abc59cSbostic m = a;
152141abc59cSbostic if (a == GT) {
152241abc59cSbostic fp = fopen(s, "w");
152341abc59cSbostic } else if (a == APPEND) {
152441abc59cSbostic fp = fopen(s, "a");
152541abc59cSbostic m = GT; /* so can mix > and >> */
152641abc59cSbostic } else if (a == '|') { /* output pipe */
152741abc59cSbostic fp = popen(s, "w");
152841abc59cSbostic } else if (a == LE) { /* input pipe */
152941abc59cSbostic fp = popen(s, "r");
153041abc59cSbostic } else if (a == LT) { /* getline <file */
153141abc59cSbostic fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
153241abc59cSbostic } else /* can't happen */
153341abc59cSbostic ERROR "illegal redirection %d", a FATAL;
153441abc59cSbostic if (fp != NULL) {
153541abc59cSbostic files[i].fname = tostring(s);
153641abc59cSbostic files[i].fp = fp;
153741abc59cSbostic files[i].mode = m;
153841abc59cSbostic }
153941abc59cSbostic return fp;
154041abc59cSbostic }
154141abc59cSbostic
filename(FILE * fp)154241abc59cSbostic uchar *filename(FILE *fp)
154341abc59cSbostic {
154441abc59cSbostic int i;
154541abc59cSbostic
154641abc59cSbostic for (i = 0; i < FOPEN_MAX; i++)
154741abc59cSbostic if (fp == files[i].fp)
154841abc59cSbostic return files[i].fname;
154941abc59cSbostic return "???";
155041abc59cSbostic }
155141abc59cSbostic
closefile(Node ** a,int n)155241abc59cSbostic Cell *closefile(Node **a, int n)
155341abc59cSbostic {
155441abc59cSbostic register Cell *x;
155541abc59cSbostic int i, stat;
155641abc59cSbostic
155741abc59cSbostic n;
155841abc59cSbostic x = execute(a[0]);
155941abc59cSbostic getsval(x);
156041abc59cSbostic for (i = 0; i < FOPEN_MAX; i++)
156141abc59cSbostic if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
156241abc59cSbostic if (ferror(files[i].fp))
156341abc59cSbostic ERROR "i/o error occurred on %s", files[i].fname WARNING;
156441abc59cSbostic if (files[i].mode == '|' || files[i].mode == LE)
156541abc59cSbostic stat = pclose(files[i].fp);
156641abc59cSbostic else
156741abc59cSbostic stat = fclose(files[i].fp);
156841abc59cSbostic if (stat == EOF)
156941abc59cSbostic ERROR "i/o error occurred closing %s", files[i].fname WARNING;
157041abc59cSbostic if (i > 2) /* don't do /dev/std... */
157141abc59cSbostic xfree(files[i].fname);
157241abc59cSbostic files[i].fname = NULL; /* watch out for ref thru this */
157341abc59cSbostic files[i].fp = NULL;
157441abc59cSbostic }
157541abc59cSbostic tempfree(x);
157641abc59cSbostic return(true);
157741abc59cSbostic }
157841abc59cSbostic
closeall(void)157941abc59cSbostic void closeall(void)
158041abc59cSbostic {
158141abc59cSbostic int i, stat;
158241abc59cSbostic
158341abc59cSbostic for (i = 0; i < FOPEN_MAX; i++)
158441abc59cSbostic if (files[i].fp) {
158541abc59cSbostic if (ferror(files[i].fp))
158641abc59cSbostic ERROR "i/o error occurred on %s", files[i].fname WARNING;
158741abc59cSbostic if (files[i].mode == '|' || files[i].mode == LE)
158841abc59cSbostic stat = pclose(files[i].fp);
158941abc59cSbostic else
159041abc59cSbostic stat = fclose(files[i].fp);
159141abc59cSbostic if (stat == EOF)
159241abc59cSbostic ERROR "i/o error occurred while closing %s", files[i].fname WARNING;
159341abc59cSbostic }
159441abc59cSbostic }
159541abc59cSbostic
159641abc59cSbostic #define SUBSIZE (20 * RECSIZE)
159741abc59cSbostic
sub(Node ** a,int nnn)159841abc59cSbostic Cell *sub(Node **a, int nnn) /* substitute command */
159941abc59cSbostic {
160041abc59cSbostic register uchar *sptr, *pb, *q;
160141abc59cSbostic register Cell *x, *y, *result;
160241abc59cSbostic uchar buf[SUBSIZE], *t;
160341abc59cSbostic fa *pfa;
160441abc59cSbostic
160541abc59cSbostic x = execute(a[3]); /* target string */
160641abc59cSbostic t = getsval(x);
160741abc59cSbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
160841abc59cSbostic pfa = (fa *) a[1]; /* regular expression */
160941abc59cSbostic else {
161041abc59cSbostic y = execute(a[1]);
161141abc59cSbostic pfa = makedfa(getsval(y), 1);
161241abc59cSbostic tempfree(y);
161341abc59cSbostic }
161441abc59cSbostic y = execute(a[2]); /* replacement string */
161541abc59cSbostic result = false;
161641abc59cSbostic if (pmatch(pfa, t)) {
161741abc59cSbostic pb = buf;
161841abc59cSbostic sptr = t;
161941abc59cSbostic while (sptr < patbeg)
162041abc59cSbostic *pb++ = *sptr++;
162141abc59cSbostic sptr = getsval(y);
162241abc59cSbostic while (*sptr != 0 && pb < buf + SUBSIZE - 1)
162341abc59cSbostic if (*sptr == '\\' && *(sptr+1) == '&') {
162441abc59cSbostic sptr++; /* skip \, */
162541abc59cSbostic *pb++ = *sptr++; /* add & */
162641abc59cSbostic } else if (*sptr == '&') {
162741abc59cSbostic sptr++;
162841abc59cSbostic for (q = patbeg; q < patbeg+patlen; )
162941abc59cSbostic *pb++ = *q++;
163041abc59cSbostic } else
163141abc59cSbostic *pb++ = *sptr++;
163241abc59cSbostic *pb = '\0';
163341abc59cSbostic if (pb >= buf + SUBSIZE)
163441abc59cSbostic ERROR "sub() result %30s too big", buf FATAL;
163541abc59cSbostic sptr = patbeg + patlen;
163641abc59cSbostic if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1)))
163741abc59cSbostic while (*pb++ = *sptr++)
163841abc59cSbostic ;
163941abc59cSbostic if (pb >= buf + SUBSIZE)
164041abc59cSbostic ERROR "sub() result %.30s too big", buf FATAL;
164141abc59cSbostic setsval(x, buf);
164241abc59cSbostic result = true;;
164341abc59cSbostic }
164441abc59cSbostic tempfree(x);
164541abc59cSbostic tempfree(y);
164641abc59cSbostic return result;
164741abc59cSbostic }
164841abc59cSbostic
gsub(Node ** a,int nnn)164941abc59cSbostic Cell *gsub(Node **a, int nnn) /* global substitute */
165041abc59cSbostic {
165141abc59cSbostic register Cell *x, *y;
165241abc59cSbostic register uchar *rptr, *sptr, *t, *pb;
165341abc59cSbostic uchar buf[SUBSIZE];
165441abc59cSbostic register fa *pfa;
165541abc59cSbostic int mflag, tempstat, num;
165641abc59cSbostic
165741abc59cSbostic mflag = 0; /* if mflag == 0, can replace empty string */
165841abc59cSbostic num = 0;
165941abc59cSbostic x = execute(a[3]); /* target string */
166041abc59cSbostic t = getsval(x);
166141abc59cSbostic if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
166241abc59cSbostic pfa = (fa *) a[1]; /* regular expression */
166341abc59cSbostic else {
166441abc59cSbostic y = execute(a[1]);
166541abc59cSbostic pfa = makedfa(getsval(y), 1);
166641abc59cSbostic tempfree(y);
166741abc59cSbostic }
166841abc59cSbostic y = execute(a[2]); /* replacement string */
166941abc59cSbostic if (pmatch(pfa, t)) {
167041abc59cSbostic tempstat = pfa->initstat;
167141abc59cSbostic pfa->initstat = 2;
167241abc59cSbostic pb = buf;
167341abc59cSbostic rptr = getsval(y);
167441abc59cSbostic do {
167541abc59cSbostic /*
167641abc59cSbostic uchar *p;
167741abc59cSbostic int i;
167841abc59cSbostic printf("target string: %s, *patbeg = %o, patlen = %d\n",
167941abc59cSbostic t, *patbeg, patlen);
168041abc59cSbostic printf(" match found: ");
168141abc59cSbostic p=patbeg;
168241abc59cSbostic for (i=0; i<patlen; i++)
168341abc59cSbostic printf("%c", *p++);
168441abc59cSbostic printf("\n");
168541abc59cSbostic */
168641abc59cSbostic if (patlen == 0 && *patbeg != 0) { /* matched empty string */
168741abc59cSbostic if (mflag == 0) { /* can replace empty */
168841abc59cSbostic num++;
168941abc59cSbostic sptr = rptr;
169041abc59cSbostic while (*sptr != 0 && pb < buf + SUBSIZE-1)
169141abc59cSbostic if (*sptr == '\\' && *(sptr+1) == '&') {
169241abc59cSbostic sptr++;
169341abc59cSbostic *pb++ = *sptr++;
169441abc59cSbostic } else if (*sptr == '&') {
169541abc59cSbostic uchar *q;
169641abc59cSbostic sptr++;
169741abc59cSbostic for (q = patbeg; q < patbeg+patlen; )
169841abc59cSbostic *pb++ = *q++;
169941abc59cSbostic } else
170041abc59cSbostic *pb++ = *sptr++;
170141abc59cSbostic }
170241abc59cSbostic if (*t == 0) /* at end */
170341abc59cSbostic goto done;
170441abc59cSbostic *pb++ = *t++;
170541abc59cSbostic if (pb >= buf + SUBSIZE-1)
170641abc59cSbostic ERROR "gsub() result %.30s too big", buf FATAL;
170741abc59cSbostic mflag = 0;
170841abc59cSbostic }
170941abc59cSbostic else { /* matched nonempty string */
171041abc59cSbostic num++;
171141abc59cSbostic sptr = t;
171241abc59cSbostic while (sptr < patbeg && pb < buf + SUBSIZE-1)
171341abc59cSbostic *pb++ = *sptr++;
171441abc59cSbostic sptr = rptr;
171541abc59cSbostic while (*sptr != 0 && pb < buf + SUBSIZE-1)
171641abc59cSbostic if (*sptr == '\\' && *(sptr+1) == '&') {
171741abc59cSbostic sptr++;
171841abc59cSbostic *pb++ = *sptr++;
171941abc59cSbostic } else if (*sptr == '&') {
172041abc59cSbostic uchar *q;
172141abc59cSbostic sptr++;
172241abc59cSbostic for (q = patbeg; q < patbeg+patlen; )
172341abc59cSbostic *pb++ = *q++;
172441abc59cSbostic } else
172541abc59cSbostic *pb++ = *sptr++;
172641abc59cSbostic t = patbeg + patlen;
172741abc59cSbostic if ((*(t-1) == 0) || (*t == 0))
172841abc59cSbostic goto done;
172941abc59cSbostic if (pb >= buf + SUBSIZE-1)
173041abc59cSbostic ERROR "gsub() result %.30s too big", buf FATAL;
173141abc59cSbostic mflag = 1;
173241abc59cSbostic }
173341abc59cSbostic } while (pmatch(pfa,t));
173441abc59cSbostic sptr = t;
173541abc59cSbostic while (*pb++ = *sptr++)
173641abc59cSbostic ;
173741abc59cSbostic done: if (pb >= buf + SUBSIZE-1)
173841abc59cSbostic ERROR "gsub() result %.30s too big", buf FATAL;
173941abc59cSbostic *pb = '\0';
174041abc59cSbostic setsval(x, buf);
174141abc59cSbostic pfa->initstat = tempstat;
174241abc59cSbostic }
174341abc59cSbostic tempfree(x);
174441abc59cSbostic tempfree(y);
174541abc59cSbostic x = gettemp();
174641abc59cSbostic x->tval = NUM;
174741abc59cSbostic x->fval = num;
174841abc59cSbostic return(x);
174941abc59cSbostic }
1750