15ea9e707SThomas Veerman /****************************************************************
25ea9e707SThomas Veerman Copyright (C) Lucent Technologies 1997
35ea9e707SThomas Veerman All Rights Reserved
45ea9e707SThomas Veerman
55ea9e707SThomas Veerman Permission to use, copy, modify, and distribute this software and
65ea9e707SThomas Veerman its documentation for any purpose and without fee is hereby
75ea9e707SThomas Veerman granted, provided that the above copyright notice appear in all
85ea9e707SThomas Veerman copies and that both that the copyright notice and this
95ea9e707SThomas Veerman permission notice and warranty disclaimer appear in supporting
105ea9e707SThomas Veerman documentation, and that the name Lucent Technologies or any of
115ea9e707SThomas Veerman its entities not be used in advertising or publicity pertaining
125ea9e707SThomas Veerman to distribution of the software without specific, written prior
135ea9e707SThomas Veerman permission.
145ea9e707SThomas Veerman
155ea9e707SThomas Veerman LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
165ea9e707SThomas Veerman INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
175ea9e707SThomas Veerman IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
185ea9e707SThomas Veerman SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
195ea9e707SThomas Veerman WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
205ea9e707SThomas Veerman IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
215ea9e707SThomas Veerman ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
225ea9e707SThomas Veerman THIS SOFTWARE.
235ea9e707SThomas Veerman ****************************************************************/
245ea9e707SThomas Veerman
255ea9e707SThomas Veerman #if HAVE_NBTOOL_CONFIG_H
265ea9e707SThomas Veerman #include "nbtool_config.h"
275ea9e707SThomas Veerman #endif
285ea9e707SThomas Veerman
295ea9e707SThomas Veerman #define DEBUG
305ea9e707SThomas Veerman #include <stdio.h>
315ea9e707SThomas Veerman #include <ctype.h>
325ea9e707SThomas Veerman #include <wchar.h>
335ea9e707SThomas Veerman #include <wctype.h>
345ea9e707SThomas Veerman #include <setjmp.h>
355ea9e707SThomas Veerman #include <limits.h>
365ea9e707SThomas Veerman #include <math.h>
375ea9e707SThomas Veerman #include <string.h>
385ea9e707SThomas Veerman #include <stdlib.h>
395ea9e707SThomas Veerman #include <time.h>
405ea9e707SThomas Veerman #include <stdint.h>
415ea9e707SThomas Veerman #include "awk.h"
425ea9e707SThomas Veerman #include "awkgram.h"
435ea9e707SThomas Veerman
445ea9e707SThomas Veerman #define tempfree(x) do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
455ea9e707SThomas Veerman
465ea9e707SThomas Veerman void stdinit(void);
475ea9e707SThomas Veerman
485ea9e707SThomas Veerman /*
495ea9e707SThomas Veerman #undef tempfree
505ea9e707SThomas Veerman
515ea9e707SThomas Veerman void tempfree(Cell *p) {
525ea9e707SThomas Veerman if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
535ea9e707SThomas Veerman WARNING("bad csub %d in Cell %d %s",
545ea9e707SThomas Veerman p->csub, p->ctype, p->sval);
555ea9e707SThomas Veerman }
565ea9e707SThomas Veerman if (istemp(p))
575ea9e707SThomas Veerman tfree(p);
585ea9e707SThomas Veerman }
595ea9e707SThomas Veerman */
605ea9e707SThomas Veerman
615ea9e707SThomas Veerman /* do we really need these? */
625ea9e707SThomas Veerman /* #ifdef _NFILE */
635ea9e707SThomas Veerman /* #ifndef FOPEN_MAX */
645ea9e707SThomas Veerman /* #define FOPEN_MAX _NFILE */
655ea9e707SThomas Veerman /* #endif */
665ea9e707SThomas Veerman /* #endif */
675ea9e707SThomas Veerman /* */
685ea9e707SThomas Veerman /* #ifndef FOPEN_MAX */
695ea9e707SThomas Veerman /* #define FOPEN_MAX 40 */ /* max number of open files */
705ea9e707SThomas Veerman /* #endif */
715ea9e707SThomas Veerman /* */
725ea9e707SThomas Veerman /* #ifndef RAND_MAX */
735ea9e707SThomas Veerman /* #define RAND_MAX 32767 */ /* all that ansi guarantees */
745ea9e707SThomas Veerman /* #endif */
755ea9e707SThomas Veerman
765ea9e707SThomas Veerman jmp_buf env;
775ea9e707SThomas Veerman extern int pairstack[];
785ea9e707SThomas Veerman extern unsigned int srand_seed;
795ea9e707SThomas Veerman
805ea9e707SThomas Veerman Node *winner = NULL; /* root of parse tree */
815ea9e707SThomas Veerman Cell *tmps; /* free temporary cells for execution */
825ea9e707SThomas Veerman
835ea9e707SThomas Veerman static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL };
845ea9e707SThomas Veerman Cell *True = &truecell;
855ea9e707SThomas Veerman static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL };
865ea9e707SThomas Veerman Cell *False = &falsecell;
875ea9e707SThomas Veerman static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL };
885ea9e707SThomas Veerman Cell *jbreak = &breakcell;
895ea9e707SThomas Veerman static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL };
905ea9e707SThomas Veerman Cell *jcont = &contcell;
915ea9e707SThomas Veerman static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL };
925ea9e707SThomas Veerman Cell *jnext = &nextcell;
935ea9e707SThomas Veerman static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL};
945ea9e707SThomas Veerman Cell *jnextfile = &nextfilecell;
955ea9e707SThomas Veerman static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL };
965ea9e707SThomas Veerman Cell *jexit = &exitcell;
975ea9e707SThomas Veerman static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL };
985ea9e707SThomas Veerman Cell *jret = &retcell;
995ea9e707SThomas Veerman static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
1005ea9e707SThomas Veerman
1015ea9e707SThomas Veerman Node *curnode = NULL; /* the node being executed, for debugging */
1025ea9e707SThomas Veerman
1035ea9e707SThomas Veerman /* buffer memory management */
adjbuf(uschar ** pbuf,int * psiz,int minlen,int quantum,uschar ** pbptr,const char * whatrtn)1045ea9e707SThomas Veerman int adjbuf(uschar **pbuf, int *psiz, int minlen, int quantum, uschar **pbptr,
1055ea9e707SThomas Veerman const char *whatrtn)
1065ea9e707SThomas Veerman /* pbuf: address of pointer to buffer being managed
1075ea9e707SThomas Veerman * psiz: address of buffer size variable
1085ea9e707SThomas Veerman * minlen: minimum length of buffer needed
1095ea9e707SThomas Veerman * quantum: buffer size quantum
1105ea9e707SThomas Veerman * pbptr: address of movable pointer into buffer, or 0 if none
1115ea9e707SThomas Veerman * whatrtn: name of the calling routine if failure should cause fatal error
1125ea9e707SThomas Veerman *
1135ea9e707SThomas Veerman * return 0 for realloc failure, !=0 for success
1145ea9e707SThomas Veerman */
1155ea9e707SThomas Veerman {
1165ea9e707SThomas Veerman if (minlen > *psiz) {
1175ea9e707SThomas Veerman char *tbuf;
1185ea9e707SThomas Veerman int rminlen = quantum ? minlen % quantum : 0;
1195ea9e707SThomas Veerman int boff = pbptr ? *pbptr - *pbuf : 0;
1205ea9e707SThomas Veerman /* round up to next multiple of quantum */
1215ea9e707SThomas Veerman if (rminlen)
1225ea9e707SThomas Veerman minlen += quantum - rminlen;
1235ea9e707SThomas Veerman tbuf = realloc(*pbuf, minlen);
1245ea9e707SThomas Veerman dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) );
1255ea9e707SThomas Veerman if (tbuf == NULL) {
1265ea9e707SThomas Veerman if (whatrtn)
1275ea9e707SThomas Veerman FATAL("out of memory in %s", whatrtn);
1285ea9e707SThomas Veerman return 0;
1295ea9e707SThomas Veerman }
1305ea9e707SThomas Veerman *pbuf = tbuf;
1315ea9e707SThomas Veerman *psiz = minlen;
1325ea9e707SThomas Veerman if (pbptr)
1335ea9e707SThomas Veerman *pbptr = tbuf + boff;
1345ea9e707SThomas Veerman }
1355ea9e707SThomas Veerman return 1;
1365ea9e707SThomas Veerman }
1375ea9e707SThomas Veerman
run(Node * a)1385ea9e707SThomas Veerman void run(Node *a) /* execution of parse tree starts here */
1395ea9e707SThomas Veerman {
1405ea9e707SThomas Veerman stdinit();
1415ea9e707SThomas Veerman execute(a);
1425ea9e707SThomas Veerman closeall();
1435ea9e707SThomas Veerman }
1445ea9e707SThomas Veerman
execute(Node * u)1455ea9e707SThomas Veerman Cell *execute(Node *u) /* execute a node of the parse tree */
1465ea9e707SThomas Veerman {
1475ea9e707SThomas Veerman Cell *(*proc)(Node **, int);
1485ea9e707SThomas Veerman Cell *x;
1495ea9e707SThomas Veerman Node *a;
1505ea9e707SThomas Veerman
1515ea9e707SThomas Veerman if (u == NULL)
1525ea9e707SThomas Veerman return(True);
1535ea9e707SThomas Veerman for (a = u; ; a = a->nnext) {
1545ea9e707SThomas Veerman curnode = a;
1555ea9e707SThomas Veerman if (isvalue(a)) {
1565ea9e707SThomas Veerman x = (Cell *) (a->narg[0]);
1575ea9e707SThomas Veerman if (isfld(x) && !donefld)
1585ea9e707SThomas Veerman fldbld();
1595ea9e707SThomas Veerman else if (isrec(x) && !donerec)
1605ea9e707SThomas Veerman recbld();
1615ea9e707SThomas Veerman return(x);
1625ea9e707SThomas Veerman }
1635ea9e707SThomas Veerman if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
1645ea9e707SThomas Veerman FATAL("illegal statement");
1655ea9e707SThomas Veerman proc = proctab[a->nobj-FIRSTTOKEN];
1665ea9e707SThomas Veerman x = (*proc)(a->narg, a->nobj);
1675ea9e707SThomas Veerman if (isfld(x) && !donefld)
1685ea9e707SThomas Veerman fldbld();
1695ea9e707SThomas Veerman else if (isrec(x) && !donerec)
1705ea9e707SThomas Veerman recbld();
1715ea9e707SThomas Veerman if (isexpr(a))
1725ea9e707SThomas Veerman return(x);
1735ea9e707SThomas Veerman if (isjump(x))
1745ea9e707SThomas Veerman return(x);
1755ea9e707SThomas Veerman if (a->nnext == NULL)
1765ea9e707SThomas Veerman return(x);
1775ea9e707SThomas Veerman tempfree(x);
1785ea9e707SThomas Veerman }
1795ea9e707SThomas Veerman }
1805ea9e707SThomas Veerman
1815ea9e707SThomas Veerman
program(Node ** a,int n)1825ea9e707SThomas Veerman Cell *program(Node **a, int n) /* execute an awk program */
1835ea9e707SThomas Veerman { /* a[0] = BEGIN, a[1] = body, a[2] = END */
1845ea9e707SThomas Veerman Cell *x;
1855ea9e707SThomas Veerman
1865ea9e707SThomas Veerman if (setjmp(env) != 0)
1875ea9e707SThomas Veerman goto ex;
1885ea9e707SThomas Veerman if (a[0]) { /* BEGIN */
1895ea9e707SThomas Veerman x = execute(a[0]);
1905ea9e707SThomas Veerman if (isexit(x))
1915ea9e707SThomas Veerman return(True);
1925ea9e707SThomas Veerman if (isjump(x))
1935ea9e707SThomas Veerman FATAL("illegal break, continue, next or nextfile from BEGIN");
1945ea9e707SThomas Veerman tempfree(x);
1955ea9e707SThomas Veerman }
1965ea9e707SThomas Veerman if (a[1] || a[2])
1975ea9e707SThomas Veerman while (getrec(&record, &recsize, 1) > 0) {
1985ea9e707SThomas Veerman x = execute(a[1]);
1995ea9e707SThomas Veerman if (isexit(x))
2005ea9e707SThomas Veerman break;
2015ea9e707SThomas Veerman tempfree(x);
2025ea9e707SThomas Veerman }
2035ea9e707SThomas Veerman ex:
2045ea9e707SThomas Veerman if (setjmp(env) != 0) /* handles exit within END */
2055ea9e707SThomas Veerman goto ex1;
2065ea9e707SThomas Veerman if (a[2]) { /* END */
2075ea9e707SThomas Veerman x = execute(a[2]);
2085ea9e707SThomas Veerman if (isbreak(x) || isnext(x) || iscont(x))
2095ea9e707SThomas Veerman FATAL("illegal break, continue, next or nextfile from END");
2105ea9e707SThomas Veerman tempfree(x);
2115ea9e707SThomas Veerman }
2125ea9e707SThomas Veerman ex1:
2135ea9e707SThomas Veerman return(True);
2145ea9e707SThomas Veerman }
2155ea9e707SThomas Veerman
2165ea9e707SThomas Veerman struct Frame { /* stack frame for awk function calls */
2175ea9e707SThomas Veerman int nargs; /* number of arguments in this call */
2185ea9e707SThomas Veerman Cell *fcncell; /* pointer to Cell for function */
2195ea9e707SThomas Veerman Cell **args; /* pointer to array of arguments after execute */
2205ea9e707SThomas Veerman Cell *retval; /* return value */
2215ea9e707SThomas Veerman };
2225ea9e707SThomas Veerman
2235ea9e707SThomas Veerman #define NARGS 50 /* max args in a call */
2245ea9e707SThomas Veerman
2255ea9e707SThomas Veerman struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
2265ea9e707SThomas Veerman int nframe = 0; /* number of frames allocated */
2275ea9e707SThomas Veerman struct Frame *frp = NULL; /* frame pointer. bottom level unused */
2285ea9e707SThomas Veerman
call(Node ** a,int n)2295ea9e707SThomas Veerman Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
2305ea9e707SThomas Veerman {
2315ea9e707SThomas Veerman static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL };
2325ea9e707SThomas Veerman int i, ncall, ndef;
2335ea9e707SThomas Veerman int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
2345ea9e707SThomas Veerman Node *x;
2355ea9e707SThomas Veerman Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
2365ea9e707SThomas Veerman Cell *y, *z, *fcn;
2375ea9e707SThomas Veerman char *s;
2385ea9e707SThomas Veerman
2395ea9e707SThomas Veerman fcn = execute(a[0]); /* the function itself */
2405ea9e707SThomas Veerman s = fcn->nval;
2415ea9e707SThomas Veerman if (!isfcn(fcn))
2425ea9e707SThomas Veerman FATAL("calling undefined function %s", s);
2435ea9e707SThomas Veerman if (frame == NULL) {
2445ea9e707SThomas Veerman frp = frame = calloc(nframe += 100, sizeof(*frp));
2455ea9e707SThomas Veerman if (frame == NULL)
2465ea9e707SThomas Veerman FATAL("out of space for stack frames calling %s", s);
2475ea9e707SThomas Veerman }
2485ea9e707SThomas Veerman for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
2495ea9e707SThomas Veerman ncall++;
2505ea9e707SThomas Veerman ndef = (int) fcn->fval; /* args in defn */
2515ea9e707SThomas Veerman dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (frp-frame)) );
2525ea9e707SThomas Veerman if (ncall > ndef)
2535ea9e707SThomas Veerman WARNING("function %s called with %d args, uses only %d",
2545ea9e707SThomas Veerman s, ncall, ndef);
2555ea9e707SThomas Veerman if (ncall + ndef > NARGS)
2565ea9e707SThomas Veerman FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2575ea9e707SThomas Veerman for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
2585ea9e707SThomas Veerman dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (frp-frame)) );
2595ea9e707SThomas Veerman y = execute(x);
2605ea9e707SThomas Veerman oargs[i] = y;
2615ea9e707SThomas Veerman dprintf( ("args[%d]: %s %f <%s>, t=%o\n",
2625ea9e707SThomas Veerman i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval) );
2635ea9e707SThomas Veerman if (isfcn(y))
2645ea9e707SThomas Veerman FATAL("can't use function %s as argument in %s", y->nval, s);
2655ea9e707SThomas Veerman if (isarr(y))
2665ea9e707SThomas Veerman args[i] = y; /* arrays by ref */
2675ea9e707SThomas Veerman else
2685ea9e707SThomas Veerman args[i] = copycell(y);
2695ea9e707SThomas Veerman tempfree(y);
2705ea9e707SThomas Veerman }
2715ea9e707SThomas Veerman for ( ; i < ndef; i++) { /* add null args for ones not provided */
2725ea9e707SThomas Veerman args[i] = gettemp();
2735ea9e707SThomas Veerman *args[i] = newcopycell;
2745ea9e707SThomas Veerman }
2755ea9e707SThomas Veerman frp++; /* now ok to up frame */
2765ea9e707SThomas Veerman if (frp >= frame + nframe) {
2775ea9e707SThomas Veerman int dfp = frp - frame; /* old index */
2785ea9e707SThomas Veerman frame = realloc(frame, (nframe += 100) * sizeof(*frame));
2795ea9e707SThomas Veerman if (frame == NULL)
2805ea9e707SThomas Veerman FATAL("out of space for stack frames in %s", s);
2815ea9e707SThomas Veerman frp = frame + dfp;
2825ea9e707SThomas Veerman }
2835ea9e707SThomas Veerman frp->fcncell = fcn;
2845ea9e707SThomas Veerman frp->args = args;
2855ea9e707SThomas Veerman frp->nargs = ndef; /* number defined with (excess are locals) */
2865ea9e707SThomas Veerman frp->retval = gettemp();
2875ea9e707SThomas Veerman
2885ea9e707SThomas Veerman dprintf( ("start exec of %s, fp=%d\n", s, (int) (frp-frame)) );
2895ea9e707SThomas Veerman y = execute((Node *)(fcn->sval)); /* execute body */
2905ea9e707SThomas Veerman dprintf( ("finished exec of %s, fp=%d\n", s, (int) (frp-frame)) );
2915ea9e707SThomas Veerman
2925ea9e707SThomas Veerman for (i = 0; i < ndef; i++) {
2935ea9e707SThomas Veerman Cell *t = frp->args[i];
2945ea9e707SThomas Veerman if (isarr(t)) {
2955ea9e707SThomas Veerman if (t->csub == CCOPY) {
2965ea9e707SThomas Veerman if (i >= ncall) {
2975ea9e707SThomas Veerman freesymtab(t);
2985ea9e707SThomas Veerman t->csub = CTEMP;
2995ea9e707SThomas Veerman tempfree(t);
3005ea9e707SThomas Veerman } else {
3015ea9e707SThomas Veerman oargs[i]->tval = t->tval;
3025ea9e707SThomas Veerman oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3035ea9e707SThomas Veerman oargs[i]->sval = t->sval;
3045ea9e707SThomas Veerman tempfree(t);
3055ea9e707SThomas Veerman }
3065ea9e707SThomas Veerman }
3075ea9e707SThomas Veerman } else if (t != y) { /* kludge to prevent freeing twice */
3085ea9e707SThomas Veerman t->csub = CTEMP;
3095ea9e707SThomas Veerman tempfree(t);
3105ea9e707SThomas Veerman } else if (t == y && t->csub == CCOPY) {
3115ea9e707SThomas Veerman t->csub = CTEMP;
3125ea9e707SThomas Veerman tempfree(t);
3135ea9e707SThomas Veerman freed = 1;
3145ea9e707SThomas Veerman }
3155ea9e707SThomas Veerman }
3165ea9e707SThomas Veerman tempfree(fcn);
3175ea9e707SThomas Veerman if (isexit(y) || isnext(y))
3185ea9e707SThomas Veerman return y;
3195ea9e707SThomas Veerman if (freed == 0) {
3205ea9e707SThomas Veerman tempfree(y); /* don't free twice! */
3215ea9e707SThomas Veerman }
3225ea9e707SThomas Veerman z = frp->retval; /* return value */
3235ea9e707SThomas Veerman dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) );
3245ea9e707SThomas Veerman frp--;
3255ea9e707SThomas Veerman return(z);
3265ea9e707SThomas Veerman }
3275ea9e707SThomas Veerman
copycell(Cell * x)3285ea9e707SThomas Veerman Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
3295ea9e707SThomas Veerman {
3305ea9e707SThomas Veerman Cell *y;
3315ea9e707SThomas Veerman
3325ea9e707SThomas Veerman /* copy is not constant or field */
3335ea9e707SThomas Veerman
3345ea9e707SThomas Veerman y = gettemp();
3355ea9e707SThomas Veerman y->tval = x->tval & ~(CON|FLD|REC);
3365ea9e707SThomas Veerman y->csub = CCOPY; /* prevents freeing until call is over */
3375ea9e707SThomas Veerman y->nval = x->nval; /* BUG? */
3385ea9e707SThomas Veerman if (isstr(x) /* || x->ctype == OCELL */) {
3395ea9e707SThomas Veerman y->sval = tostring(x->sval);
3405ea9e707SThomas Veerman y->tval &= ~DONTFREE;
3415ea9e707SThomas Veerman } else
3425ea9e707SThomas Veerman y->tval |= DONTFREE;
3435ea9e707SThomas Veerman y->fval = x->fval;
3445ea9e707SThomas Veerman return y;
3455ea9e707SThomas Veerman }
3465ea9e707SThomas Veerman
arg(Node ** a,int n)3475ea9e707SThomas Veerman Cell *arg(Node **a, int n) /* nth argument of a function */
3485ea9e707SThomas Veerman {
3495ea9e707SThomas Veerman
3505ea9e707SThomas Veerman n = ptoi(a[0]); /* argument number, counting from 0 */
3515ea9e707SThomas Veerman dprintf( ("arg(%d), fp->nargs=%d\n", n, frp->nargs) );
3525ea9e707SThomas Veerman if (n+1 > frp->nargs)
3535ea9e707SThomas Veerman FATAL("argument #%d of function %s was not supplied",
3545ea9e707SThomas Veerman n+1, frp->fcncell->nval);
3555ea9e707SThomas Veerman return frp->args[n];
3565ea9e707SThomas Veerman }
3575ea9e707SThomas Veerman
jump(Node ** a,int n)3585ea9e707SThomas Veerman Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
3595ea9e707SThomas Veerman {
3605ea9e707SThomas Veerman Cell *y;
3615ea9e707SThomas Veerman
3625ea9e707SThomas Veerman switch (n) {
3635ea9e707SThomas Veerman case EXIT:
3645ea9e707SThomas Veerman if (a[0] != NULL) {
3655ea9e707SThomas Veerman y = execute(a[0]);
3665ea9e707SThomas Veerman errorflag = (int) getfval(y);
3675ea9e707SThomas Veerman tempfree(y);
3685ea9e707SThomas Veerman }
3695ea9e707SThomas Veerman longjmp(env, 1);
3705ea9e707SThomas Veerman case RETURN:
3715ea9e707SThomas Veerman if (a[0] != NULL) {
3725ea9e707SThomas Veerman y = execute(a[0]);
3735ea9e707SThomas Veerman if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3745ea9e707SThomas Veerman setsval(frp->retval, getsval(y));
3755ea9e707SThomas Veerman frp->retval->fval = getfval(y);
3765ea9e707SThomas Veerman frp->retval->tval |= NUM;
3775ea9e707SThomas Veerman }
3785ea9e707SThomas Veerman else if (y->tval & STR)
3795ea9e707SThomas Veerman setsval(frp->retval, getsval(y));
3805ea9e707SThomas Veerman else if (y->tval & NUM)
3815ea9e707SThomas Veerman setfval(frp->retval, getfval(y));
3825ea9e707SThomas Veerman else /* can't happen */
3835ea9e707SThomas Veerman FATAL("bad type variable %d", y->tval);
3845ea9e707SThomas Veerman tempfree(y);
3855ea9e707SThomas Veerman }
3865ea9e707SThomas Veerman return(jret);
3875ea9e707SThomas Veerman case NEXT:
3885ea9e707SThomas Veerman return(jnext);
3895ea9e707SThomas Veerman case NEXTFILE:
3905ea9e707SThomas Veerman nextfile();
3915ea9e707SThomas Veerman return(jnextfile);
3925ea9e707SThomas Veerman case BREAK:
3935ea9e707SThomas Veerman return(jbreak);
3945ea9e707SThomas Veerman case CONTINUE:
3955ea9e707SThomas Veerman return(jcont);
3965ea9e707SThomas Veerman default: /* can't happen */
3975ea9e707SThomas Veerman FATAL("illegal jump type %d", n);
3985ea9e707SThomas Veerman }
3995ea9e707SThomas Veerman return 0; /* not reached */
4005ea9e707SThomas Veerman }
4015ea9e707SThomas Veerman
awkgetline(Node ** a,int n)4025ea9e707SThomas Veerman Cell *awkgetline(Node **a, int n) /* get next line from specific input */
4035ea9e707SThomas Veerman { /* a[0] is variable, a[1] is operator, a[2] is filename */
4045ea9e707SThomas Veerman Cell *r, *x;
4055ea9e707SThomas Veerman extern Cell **fldtab;
4065ea9e707SThomas Veerman FILE *fp;
4075ea9e707SThomas Veerman uschar *buf;
4085ea9e707SThomas Veerman int bufsize = recsize;
4095ea9e707SThomas Veerman int mode, newflag;
4105ea9e707SThomas Veerman
4115ea9e707SThomas Veerman if ((buf = malloc(bufsize)) == NULL)
4125ea9e707SThomas Veerman FATAL("out of memory in getline");
4135ea9e707SThomas Veerman
4145ea9e707SThomas Veerman fflush(stdout); /* in case someone is waiting for a prompt */
4155ea9e707SThomas Veerman r = gettemp();
4165ea9e707SThomas Veerman if (a[1] != NULL) { /* getline < file */
4175ea9e707SThomas Veerman x = execute(a[2]); /* filename */
4185ea9e707SThomas Veerman mode = ptoi(a[1]);
4195ea9e707SThomas Veerman if (mode == '|') /* input pipe */
4205ea9e707SThomas Veerman mode = LE; /* arbitrary flag */
4215ea9e707SThomas Veerman fp = openfile(mode, getsval(x), &newflag);
4225ea9e707SThomas Veerman tempfree(x);
4235ea9e707SThomas Veerman if (fp == NULL)
4245ea9e707SThomas Veerman n = -1;
4255ea9e707SThomas Veerman else
4265ea9e707SThomas Veerman n = readrec(&buf, &bufsize, fp, newflag);
4275ea9e707SThomas Veerman if (n <= 0) {
4285ea9e707SThomas Veerman ;
4295ea9e707SThomas Veerman } else if (a[0] != NULL) { /* getline var <file */
4305ea9e707SThomas Veerman x = execute(a[0]);
4315ea9e707SThomas Veerman setsval(x, buf);
4325ea9e707SThomas Veerman tempfree(x);
4335ea9e707SThomas Veerman } else { /* getline <file */
4345ea9e707SThomas Veerman setsval(fldtab[0], buf);
4355ea9e707SThomas Veerman if (is_number(fldtab[0]->sval)) {
4365ea9e707SThomas Veerman fldtab[0]->fval = atof(fldtab[0]->sval);
4375ea9e707SThomas Veerman fldtab[0]->tval |= NUM;
4385ea9e707SThomas Veerman }
4395ea9e707SThomas Veerman }
4405ea9e707SThomas Veerman } else { /* bare getline; use current input */
4415ea9e707SThomas Veerman if (a[0] == NULL) /* getline */
4425ea9e707SThomas Veerman n = getrec(&record, &recsize, 1);
4435ea9e707SThomas Veerman else { /* getline var */
4445ea9e707SThomas Veerman n = getrec(&buf, &bufsize, 0);
4455ea9e707SThomas Veerman x = execute(a[0]);
4465ea9e707SThomas Veerman setsval(x, buf);
4475ea9e707SThomas Veerman tempfree(x);
4485ea9e707SThomas Veerman }
4495ea9e707SThomas Veerman }
4505ea9e707SThomas Veerman setfval(r, (Awkfloat) n);
4515ea9e707SThomas Veerman free(buf);
4525ea9e707SThomas Veerman return r;
4535ea9e707SThomas Veerman }
4545ea9e707SThomas Veerman
getnf(Node ** a,int n)4555ea9e707SThomas Veerman Cell *getnf(Node **a, int n) /* get NF */
4565ea9e707SThomas Veerman {
4575ea9e707SThomas Veerman if (donefld == 0)
4585ea9e707SThomas Veerman fldbld();
4595ea9e707SThomas Veerman return (Cell *) a[0];
4605ea9e707SThomas Veerman }
4615ea9e707SThomas Veerman
array(Node ** a,int n)4625ea9e707SThomas Veerman Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
4635ea9e707SThomas Veerman {
4645ea9e707SThomas Veerman Cell *x, *y, *z;
4655ea9e707SThomas Veerman char *s;
4665ea9e707SThomas Veerman Node *np;
4675ea9e707SThomas Veerman uschar *buf;
4685ea9e707SThomas Veerman int bufsz = recsize;
4695ea9e707SThomas Veerman int nsub = strlen(*SUBSEP);
4705ea9e707SThomas Veerman
4715ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
4725ea9e707SThomas Veerman FATAL("out of memory in array");
4735ea9e707SThomas Veerman
4745ea9e707SThomas Veerman x = execute(a[0]); /* Cell* for symbol table */
4755ea9e707SThomas Veerman buf[0] = 0;
4765ea9e707SThomas Veerman for (np = a[1]; np; np = np->nnext) {
4775ea9e707SThomas Veerman y = execute(np); /* subscript */
4785ea9e707SThomas Veerman s = getsval(y);
4795ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "array"))
4805ea9e707SThomas Veerman FATAL("out of memory for %s[%s...]", x->nval, buf);
4815ea9e707SThomas Veerman strlcat(buf, s, bufsz);
4825ea9e707SThomas Veerman if (np->nnext)
4835ea9e707SThomas Veerman strlcat(buf, *SUBSEP, bufsz);
4845ea9e707SThomas Veerman tempfree(y);
4855ea9e707SThomas Veerman }
4865ea9e707SThomas Veerman if (!isarr(x)) {
4875ea9e707SThomas Veerman dprintf( ("making %s into an array\n", NN(x->nval)) );
4885ea9e707SThomas Veerman if (freeable(x))
4895ea9e707SThomas Veerman xfree(x->sval);
4905ea9e707SThomas Veerman x->tval &= ~(STR|NUM|DONTFREE);
4915ea9e707SThomas Veerman x->tval |= ARR;
4925ea9e707SThomas Veerman x->sval = (char *) makesymtab(NSYMTAB);
4935ea9e707SThomas Veerman }
4945ea9e707SThomas Veerman z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
4955ea9e707SThomas Veerman z->ctype = OCELL;
4965ea9e707SThomas Veerman z->csub = CVAR;
4975ea9e707SThomas Veerman tempfree(x);
4985ea9e707SThomas Veerman free(buf);
4995ea9e707SThomas Veerman return(z);
5005ea9e707SThomas Veerman }
5015ea9e707SThomas Veerman
awkdelete(Node ** a,int n)5025ea9e707SThomas Veerman Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
5035ea9e707SThomas Veerman {
5045ea9e707SThomas Veerman Cell *x, *y;
5055ea9e707SThomas Veerman Node *np;
5065ea9e707SThomas Veerman uschar *s;
5075ea9e707SThomas Veerman int nsub = strlen(*SUBSEP);
5085ea9e707SThomas Veerman
5095ea9e707SThomas Veerman x = execute(a[0]); /* Cell* for symbol table */
5105ea9e707SThomas Veerman if (!isarr(x))
5115ea9e707SThomas Veerman return True;
5125ea9e707SThomas Veerman if (a[1] == 0) { /* delete the elements, not the table */
5135ea9e707SThomas Veerman freesymtab(x);
5145ea9e707SThomas Veerman x->tval &= ~STR;
5155ea9e707SThomas Veerman x->tval |= ARR;
5165ea9e707SThomas Veerman x->sval = (char *) makesymtab(NSYMTAB);
5175ea9e707SThomas Veerman } else {
5185ea9e707SThomas Veerman int bufsz = recsize;
5195ea9e707SThomas Veerman uschar *buf;
5205ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
5215ea9e707SThomas Veerman FATAL("out of memory in adelete");
5225ea9e707SThomas Veerman buf[0] = 0;
5235ea9e707SThomas Veerman for (np = a[1]; np; np = np->nnext) {
5245ea9e707SThomas Veerman y = execute(np); /* subscript */
5255ea9e707SThomas Veerman s = getsval(y);
5265ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete"))
5275ea9e707SThomas Veerman FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5285ea9e707SThomas Veerman strlcat(buf, s, bufsz);
5295ea9e707SThomas Veerman if (np->nnext)
5305ea9e707SThomas Veerman strlcat(buf, *SUBSEP, bufsz);
5315ea9e707SThomas Veerman tempfree(y);
5325ea9e707SThomas Veerman }
5335ea9e707SThomas Veerman freeelem(x, buf);
5345ea9e707SThomas Veerman free(buf);
5355ea9e707SThomas Veerman }
5365ea9e707SThomas Veerman tempfree(x);
5375ea9e707SThomas Veerman return True;
5385ea9e707SThomas Veerman }
5395ea9e707SThomas Veerman
intest(Node ** a,int n)5405ea9e707SThomas Veerman Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
5415ea9e707SThomas Veerman {
5425ea9e707SThomas Veerman Cell *x, *ap, *k;
5435ea9e707SThomas Veerman Node *p;
5445ea9e707SThomas Veerman uschar *buf;
5455ea9e707SThomas Veerman char *s;
5465ea9e707SThomas Veerman int bufsz = recsize;
5475ea9e707SThomas Veerman int nsub = strlen(*SUBSEP);
5485ea9e707SThomas Veerman
5495ea9e707SThomas Veerman ap = execute(a[1]); /* array name */
5505ea9e707SThomas Veerman if (!isarr(ap)) {
5515ea9e707SThomas Veerman dprintf( ("making %s into an array\n", ap->nval) );
5525ea9e707SThomas Veerman if (freeable(ap))
5535ea9e707SThomas Veerman xfree(ap->sval);
5545ea9e707SThomas Veerman ap->tval &= ~(STR|NUM|DONTFREE);
5555ea9e707SThomas Veerman ap->tval |= ARR;
5565ea9e707SThomas Veerman ap->sval = (char *) makesymtab(NSYMTAB);
5575ea9e707SThomas Veerman }
5585ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL) {
5595ea9e707SThomas Veerman FATAL("out of memory in intest");
5605ea9e707SThomas Veerman }
5615ea9e707SThomas Veerman buf[0] = 0;
5625ea9e707SThomas Veerman for (p = a[0]; p; p = p->nnext) {
5635ea9e707SThomas Veerman x = execute(p); /* expr */
5645ea9e707SThomas Veerman s = getsval(x);
5655ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "intest"))
5665ea9e707SThomas Veerman FATAL("out of memory deleting %s[%s...]", x->nval, buf);
5675ea9e707SThomas Veerman strcat(buf, s);
5685ea9e707SThomas Veerman tempfree(x);
5695ea9e707SThomas Veerman if (p->nnext)
5705ea9e707SThomas Veerman strcat(buf, *SUBSEP);
5715ea9e707SThomas Veerman }
5725ea9e707SThomas Veerman k = lookup(buf, (Array *) ap->sval);
5735ea9e707SThomas Veerman tempfree(ap);
5745ea9e707SThomas Veerman free(buf);
5755ea9e707SThomas Veerman if (k == NULL)
5765ea9e707SThomas Veerman return(False);
5775ea9e707SThomas Veerman else
5785ea9e707SThomas Veerman return(True);
5795ea9e707SThomas Veerman }
5805ea9e707SThomas Veerman
5815ea9e707SThomas Veerman
matchop(Node ** a,int n)5825ea9e707SThomas Veerman Cell *matchop(Node **a, int n) /* ~ and match() */
5835ea9e707SThomas Veerman {
5845ea9e707SThomas Veerman Cell *x, *y;
5855ea9e707SThomas Veerman uschar *s;
5865ea9e707SThomas Veerman char *t;
5875ea9e707SThomas Veerman int i;
5885ea9e707SThomas Veerman fa *pfa;
5895ea9e707SThomas Veerman int (*mf)(fa *, const char *) = match, mode = 0;
5905ea9e707SThomas Veerman
5915ea9e707SThomas Veerman if (n == MATCHFCN) {
5925ea9e707SThomas Veerman mf = pmatch;
5935ea9e707SThomas Veerman mode = 1;
5945ea9e707SThomas Veerman }
5955ea9e707SThomas Veerman x = execute(a[1]); /* a[1] = target text */
5965ea9e707SThomas Veerman s = getsval(x);
5975ea9e707SThomas Veerman if (a[0] == 0) /* a[1] == 0: already-compiled reg expr */
5985ea9e707SThomas Veerman i = (*mf)((fa *) a[2], s);
5995ea9e707SThomas Veerman else {
6005ea9e707SThomas Veerman y = execute(a[2]); /* a[2] = regular expr */
6015ea9e707SThomas Veerman t = getsval(y);
6025ea9e707SThomas Veerman pfa = makedfa(t, mode);
6035ea9e707SThomas Veerman i = (*mf)(pfa, s);
6045ea9e707SThomas Veerman tempfree(y);
6055ea9e707SThomas Veerman }
6065ea9e707SThomas Veerman tempfree(x);
6075ea9e707SThomas Veerman if (n == MATCHFCN) {
6085ea9e707SThomas Veerman int start = patbeg - s + 1;
6095ea9e707SThomas Veerman if (patlen < 0)
6105ea9e707SThomas Veerman start = 0;
6115ea9e707SThomas Veerman setfval(rstartloc, (Awkfloat) start);
6125ea9e707SThomas Veerman setfval(rlengthloc, (Awkfloat) patlen);
6135ea9e707SThomas Veerman x = gettemp();
6145ea9e707SThomas Veerman x->tval = NUM;
6155ea9e707SThomas Veerman x->fval = start;
6165ea9e707SThomas Veerman return x;
6175ea9e707SThomas Veerman } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
6185ea9e707SThomas Veerman return(True);
6195ea9e707SThomas Veerman else
6205ea9e707SThomas Veerman return(False);
6215ea9e707SThomas Veerman }
6225ea9e707SThomas Veerman
6235ea9e707SThomas Veerman
boolop(Node ** a,int n)6245ea9e707SThomas Veerman Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
6255ea9e707SThomas Veerman {
6265ea9e707SThomas Veerman Cell *x, *y;
6275ea9e707SThomas Veerman int i;
6285ea9e707SThomas Veerman
6295ea9e707SThomas Veerman x = execute(a[0]);
6305ea9e707SThomas Veerman i = istrue(x);
6315ea9e707SThomas Veerman tempfree(x);
6325ea9e707SThomas Veerman switch (n) {
6335ea9e707SThomas Veerman case BOR:
6345ea9e707SThomas Veerman if (i) return(True);
6355ea9e707SThomas Veerman y = execute(a[1]);
6365ea9e707SThomas Veerman i = istrue(y);
6375ea9e707SThomas Veerman tempfree(y);
6385ea9e707SThomas Veerman if (i) return(True);
6395ea9e707SThomas Veerman else return(False);
6405ea9e707SThomas Veerman case AND:
6415ea9e707SThomas Veerman if ( !i ) return(False);
6425ea9e707SThomas Veerman y = execute(a[1]);
6435ea9e707SThomas Veerman i = istrue(y);
6445ea9e707SThomas Veerman tempfree(y);
6455ea9e707SThomas Veerman if (i) return(True);
6465ea9e707SThomas Veerman else return(False);
6475ea9e707SThomas Veerman case NOT:
6485ea9e707SThomas Veerman if (i) return(False);
6495ea9e707SThomas Veerman else return(True);
6505ea9e707SThomas Veerman default: /* can't happen */
6515ea9e707SThomas Veerman FATAL("unknown boolean operator %d", n);
6525ea9e707SThomas Veerman }
6535ea9e707SThomas Veerman return 0; /*NOTREACHED*/
6545ea9e707SThomas Veerman }
6555ea9e707SThomas Veerman
relop(Node ** a,int n)6565ea9e707SThomas Veerman Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
6575ea9e707SThomas Veerman {
6585ea9e707SThomas Veerman int i;
6595ea9e707SThomas Veerman Cell *x, *y;
6605ea9e707SThomas Veerman Awkfloat j;
6615ea9e707SThomas Veerman
6625ea9e707SThomas Veerman x = execute(a[0]);
6635ea9e707SThomas Veerman y = execute(a[1]);
6645ea9e707SThomas Veerman if (x->tval&NUM && y->tval&NUM) {
6655ea9e707SThomas Veerman j = x->fval - y->fval;
6665ea9e707SThomas Veerman i = j<0? -1: (j>0? 1: 0);
6675ea9e707SThomas Veerman } else {
6685ea9e707SThomas Veerman i = strcmp(getsval(x), getsval(y));
6695ea9e707SThomas Veerman }
6705ea9e707SThomas Veerman tempfree(x);
6715ea9e707SThomas Veerman tempfree(y);
6725ea9e707SThomas Veerman switch (n) {
6735ea9e707SThomas Veerman case LT: if (i<0) return(True);
6745ea9e707SThomas Veerman else return(False);
6755ea9e707SThomas Veerman case LE: if (i<=0) return(True);
6765ea9e707SThomas Veerman else return(False);
6775ea9e707SThomas Veerman case NE: if (i!=0) return(True);
6785ea9e707SThomas Veerman else return(False);
6795ea9e707SThomas Veerman case EQ: if (i == 0) return(True);
6805ea9e707SThomas Veerman else return(False);
6815ea9e707SThomas Veerman case GE: if (i>=0) return(True);
6825ea9e707SThomas Veerman else return(False);
6835ea9e707SThomas Veerman case GT: if (i>0) return(True);
6845ea9e707SThomas Veerman else return(False);
6855ea9e707SThomas Veerman default: /* can't happen */
6865ea9e707SThomas Veerman FATAL("unknown relational operator %d", n);
6875ea9e707SThomas Veerman }
6885ea9e707SThomas Veerman return 0; /*NOTREACHED*/
6895ea9e707SThomas Veerman }
6905ea9e707SThomas Veerman
tfree(Cell * a)6915ea9e707SThomas Veerman void tfree(Cell *a) /* free a tempcell */
6925ea9e707SThomas Veerman {
6935ea9e707SThomas Veerman if (freeable(a)) {
6945ea9e707SThomas Veerman dprintf( ("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval) );
6955ea9e707SThomas Veerman xfree(a->sval);
6965ea9e707SThomas Veerman }
6975ea9e707SThomas Veerman if (a == tmps)
6985ea9e707SThomas Veerman FATAL("tempcell list is curdled");
6995ea9e707SThomas Veerman a->cnext = tmps;
7005ea9e707SThomas Veerman tmps = a;
7015ea9e707SThomas Veerman }
7025ea9e707SThomas Veerman
gettemp(void)7035ea9e707SThomas Veerman Cell *gettemp(void) /* get a tempcell */
7045ea9e707SThomas Veerman { int i;
7055ea9e707SThomas Veerman Cell *x;
7065ea9e707SThomas Veerman
7075ea9e707SThomas Veerman if (!tmps) {
7085ea9e707SThomas Veerman tmps = calloc(100, sizeof(*tmps));
7095ea9e707SThomas Veerman if (!tmps)
7105ea9e707SThomas Veerman FATAL("out of space for temporaries");
7115ea9e707SThomas Veerman for(i = 1; i < 100; i++)
7125ea9e707SThomas Veerman tmps[i-1].cnext = &tmps[i];
7135ea9e707SThomas Veerman tmps[i-1].cnext = 0;
7145ea9e707SThomas Veerman }
7155ea9e707SThomas Veerman x = tmps;
7165ea9e707SThomas Veerman tmps = x->cnext;
7175ea9e707SThomas Veerman *x = tempcell;
7185ea9e707SThomas Veerman return(x);
7195ea9e707SThomas Veerman }
7205ea9e707SThomas Veerman
indirect(Node ** a,int n)7215ea9e707SThomas Veerman Cell *indirect(Node **a, int n) /* $( a[0] ) */
7225ea9e707SThomas Veerman {
7235ea9e707SThomas Veerman Awkfloat val;
7245ea9e707SThomas Veerman Cell *x;
7255ea9e707SThomas Veerman int m;
7265ea9e707SThomas Veerman char *s;
7275ea9e707SThomas Veerman
7285ea9e707SThomas Veerman x = execute(a[0]);
7295ea9e707SThomas Veerman val = getfval(x); /* freebsd: defend against super large field numbers */
7305ea9e707SThomas Veerman if ((Awkfloat)INT_MAX < val)
7315ea9e707SThomas Veerman FATAL("trying to access out of range field %s", x->nval);
7325ea9e707SThomas Veerman m = (int) val;
7335ea9e707SThomas Veerman if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
7345ea9e707SThomas Veerman FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
7355ea9e707SThomas Veerman /* BUG: can x->nval ever be null??? */
7365ea9e707SThomas Veerman tempfree(x);
7375ea9e707SThomas Veerman x = fieldadr(m);
7385ea9e707SThomas Veerman x->ctype = OCELL; /* BUG? why are these needed? */
7395ea9e707SThomas Veerman x->csub = CFLD;
7405ea9e707SThomas Veerman return(x);
7415ea9e707SThomas Veerman }
7425ea9e707SThomas Veerman
substr(Node ** a,int nnn)7435ea9e707SThomas Veerman Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
7445ea9e707SThomas Veerman {
7455ea9e707SThomas Veerman int k, m, n;
7465ea9e707SThomas Veerman char *s;
7475ea9e707SThomas Veerman int temp;
7485ea9e707SThomas Veerman Cell *x, *y, *z = 0;
7495ea9e707SThomas Veerman
7505ea9e707SThomas Veerman x = execute(a[0]);
7515ea9e707SThomas Veerman y = execute(a[1]);
7525ea9e707SThomas Veerman if (a[2] != 0)
7535ea9e707SThomas Veerman z = execute(a[2]);
7545ea9e707SThomas Veerman s = getsval(x);
7555ea9e707SThomas Veerman k = strlen(s) + 1;
7565ea9e707SThomas Veerman if (k <= 1) {
7575ea9e707SThomas Veerman tempfree(x);
7585ea9e707SThomas Veerman tempfree(y);
7595ea9e707SThomas Veerman if (a[2] != 0) {
7605ea9e707SThomas Veerman tempfree(z);
7615ea9e707SThomas Veerman }
7625ea9e707SThomas Veerman x = gettemp();
7635ea9e707SThomas Veerman setsval(x, "");
7645ea9e707SThomas Veerman return(x);
7655ea9e707SThomas Veerman }
7665ea9e707SThomas Veerman m = (int) getfval(y);
7675ea9e707SThomas Veerman if (m <= 0)
7685ea9e707SThomas Veerman m = 1;
7695ea9e707SThomas Veerman else if (m > k)
7705ea9e707SThomas Veerman m = k;
7715ea9e707SThomas Veerman tempfree(y);
7725ea9e707SThomas Veerman if (a[2] != 0) {
7735ea9e707SThomas Veerman n = (int) getfval(z);
7745ea9e707SThomas Veerman tempfree(z);
7755ea9e707SThomas Veerman } else
7765ea9e707SThomas Veerman n = k - 1;
7775ea9e707SThomas Veerman if (n < 0)
7785ea9e707SThomas Veerman n = 0;
7795ea9e707SThomas Veerman else if (n > k - m)
7805ea9e707SThomas Veerman n = k - m;
7815ea9e707SThomas Veerman dprintf( ("substr: m=%d, n=%d, s=%s\n", m, n, s) );
7825ea9e707SThomas Veerman y = gettemp();
7835ea9e707SThomas Veerman temp = s[n+m-1]; /* with thanks to John Linderman */
7845ea9e707SThomas Veerman s[n+m-1] = '\0';
7855ea9e707SThomas Veerman setsval(y, s + m - 1);
7865ea9e707SThomas Veerman s[n+m-1] = temp;
7875ea9e707SThomas Veerman tempfree(x);
7885ea9e707SThomas Veerman return(y);
7895ea9e707SThomas Veerman }
7905ea9e707SThomas Veerman
sindex(Node ** a,int nnn)7915ea9e707SThomas Veerman Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
7925ea9e707SThomas Veerman {
7935ea9e707SThomas Veerman Cell *x, *y, *z;
7945ea9e707SThomas Veerman char *s1, *s2, *p1, *p2, *q;
7955ea9e707SThomas Veerman Awkfloat v = 0.0;
7965ea9e707SThomas Veerman
7975ea9e707SThomas Veerman x = execute(a[0]);
7985ea9e707SThomas Veerman s1 = getsval(x);
7995ea9e707SThomas Veerman y = execute(a[1]);
8005ea9e707SThomas Veerman s2 = getsval(y);
8015ea9e707SThomas Veerman
8025ea9e707SThomas Veerman z = gettemp();
8035ea9e707SThomas Veerman for (p1 = s1; *p1 != '\0'; p1++) {
8045ea9e707SThomas Veerman for (q=p1, p2=s2; *p2 != '\0' && *q == *p2; q++, p2++)
8055ea9e707SThomas Veerman ;
8065ea9e707SThomas Veerman if (*p2 == '\0') {
8075ea9e707SThomas Veerman v = (Awkfloat) (p1 - s1 + 1); /* origin 1 */
8085ea9e707SThomas Veerman break;
8095ea9e707SThomas Veerman }
8105ea9e707SThomas Veerman }
8115ea9e707SThomas Veerman tempfree(x);
8125ea9e707SThomas Veerman tempfree(y);
8135ea9e707SThomas Veerman setfval(z, v);
8145ea9e707SThomas Veerman return(z);
8155ea9e707SThomas Veerman }
8165ea9e707SThomas Veerman
8175ea9e707SThomas Veerman #define MAXNUMSIZE 50
8185ea9e707SThomas Veerman
format(char ** pbuf,int * pbufsize,const char * s,Node * a)8195ea9e707SThomas Veerman int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
8205ea9e707SThomas Veerman {
8215ea9e707SThomas Veerman uschar *fmt, *p, *t;
8225ea9e707SThomas Veerman const char *os;
8235ea9e707SThomas Veerman Cell *x;
8245ea9e707SThomas Veerman int flag = 0, n;
8255ea9e707SThomas Veerman int fmtwd; /* format width */
8265ea9e707SThomas Veerman int fmtsz = recsize;
8275ea9e707SThomas Veerman uschar *buf = *pbuf;
8285ea9e707SThomas Veerman int bufsize = *pbufsize;
8295ea9e707SThomas Veerman #define FMTSZ(a) (fmtsz - ((a) - fmt))
8305ea9e707SThomas Veerman #define BUFSZ(a) (bufsize - ((a) - buf))
8315ea9e707SThomas Veerman
8325ea9e707SThomas Veerman os = s;
8335ea9e707SThomas Veerman p = buf;
8345ea9e707SThomas Veerman if ((fmt = malloc(fmtsz)) == NULL)
8355ea9e707SThomas Veerman FATAL("out of memory in format()");
8365ea9e707SThomas Veerman while (*s) {
8375ea9e707SThomas Veerman adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
8385ea9e707SThomas Veerman if (*s != '%') {
8395ea9e707SThomas Veerman *p++ = *s++;
8405ea9e707SThomas Veerman continue;
8415ea9e707SThomas Veerman }
8425ea9e707SThomas Veerman if (*(s+1) == '%') {
8435ea9e707SThomas Veerman *p++ = '%';
8445ea9e707SThomas Veerman s += 2;
8455ea9e707SThomas Veerman continue;
8465ea9e707SThomas Veerman }
8475ea9e707SThomas Veerman /* have to be real careful in case this is a huge number, eg, %100000d */
8485ea9e707SThomas Veerman fmtwd = atoi(s+1);
8495ea9e707SThomas Veerman if (fmtwd < 0)
8505ea9e707SThomas Veerman fmtwd = -fmtwd;
8515ea9e707SThomas Veerman adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
8525ea9e707SThomas Veerman for (t = fmt; (*t++ = *s) != '\0'; s++) {
8535ea9e707SThomas Veerman if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
8545ea9e707SThomas Veerman FATAL("format item %.30s... ran format() out of memory", os);
8555ea9e707SThomas Veerman if (*s == 'l' || *s == 'h' || *s == 'L')
8565ea9e707SThomas Veerman goto weird;
8575ea9e707SThomas Veerman if (isalpha((uschar)*s))
8585ea9e707SThomas Veerman break; /* the ansi panoply */
8595ea9e707SThomas Veerman if (*s == '*') {
8605ea9e707SThomas Veerman if (a == NULL)
8615ea9e707SThomas Veerman FATAL("not enough args in printf("
8625ea9e707SThomas Veerman "\"%.30s\")", os);
8635ea9e707SThomas Veerman x = execute(a);
8645ea9e707SThomas Veerman a = a->nnext;
8655ea9e707SThomas Veerman snprintf(t - 1, FMTSZ(t - 1),
8665ea9e707SThomas Veerman "%d", fmtwd=(int) getfval(x));
8675ea9e707SThomas Veerman if (fmtwd < 0)
8685ea9e707SThomas Veerman fmtwd = -fmtwd;
8695ea9e707SThomas Veerman adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
8705ea9e707SThomas Veerman t = fmt + strlen(fmt);
8715ea9e707SThomas Veerman tempfree(x);
8725ea9e707SThomas Veerman }
8735ea9e707SThomas Veerman }
8745ea9e707SThomas Veerman *t = '\0';
8755ea9e707SThomas Veerman if (fmtwd < 0)
8765ea9e707SThomas Veerman fmtwd = -fmtwd;
8775ea9e707SThomas Veerman adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
8785ea9e707SThomas Veerman
8795ea9e707SThomas Veerman switch (*s) {
8805ea9e707SThomas Veerman case 'f': case 'e': case 'g': case 'E': case 'G':
8815ea9e707SThomas Veerman flag = 'f';
8825ea9e707SThomas Veerman break;
8835ea9e707SThomas Veerman case 'd': case 'i':
8845ea9e707SThomas Veerman flag = 'd';
8855ea9e707SThomas Veerman if(*(s-1) == 'l') break;
8865ea9e707SThomas Veerman *(t-1) = 'j';
8875ea9e707SThomas Veerman *t = 'd';
8885ea9e707SThomas Veerman *++t = '\0';
8895ea9e707SThomas Veerman break;
8905ea9e707SThomas Veerman case 'o': case 'x': case 'X': case 'u':
8915ea9e707SThomas Veerman flag = *(s-1) == 'l' ? 'd' : 'u';
8925ea9e707SThomas Veerman *(t-1) = 'j';
8935ea9e707SThomas Veerman *t = *s;
8945ea9e707SThomas Veerman *++t = '\0';
8955ea9e707SThomas Veerman break;
8965ea9e707SThomas Veerman case 's':
8975ea9e707SThomas Veerman flag = 's';
8985ea9e707SThomas Veerman break;
8995ea9e707SThomas Veerman case 'c':
9005ea9e707SThomas Veerman flag = 'c';
9015ea9e707SThomas Veerman break;
9025ea9e707SThomas Veerman default:
9035ea9e707SThomas Veerman weird:
9045ea9e707SThomas Veerman WARNING("weird printf conversion %s", fmt);
9055ea9e707SThomas Veerman flag = '?';
9065ea9e707SThomas Veerman break;
9075ea9e707SThomas Veerman }
9085ea9e707SThomas Veerman if (a == NULL)
9095ea9e707SThomas Veerman FATAL("not enough args in printf(%s)", os);
9105ea9e707SThomas Veerman x = execute(a);
9115ea9e707SThomas Veerman a = a->nnext;
9125ea9e707SThomas Veerman n = MAXNUMSIZE;
9135ea9e707SThomas Veerman if (fmtwd > n)
9145ea9e707SThomas Veerman n = fmtwd;
9155ea9e707SThomas Veerman adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
9165ea9e707SThomas Veerman switch (flag) {
9175ea9e707SThomas Veerman case '?': snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
9185ea9e707SThomas Veerman t = getsval(x);
9195ea9e707SThomas Veerman n = strlen(t);
9205ea9e707SThomas Veerman if (fmtwd > n)
9215ea9e707SThomas Veerman n = fmtwd;
9225ea9e707SThomas Veerman adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
9235ea9e707SThomas Veerman p += strlen(p);
9245ea9e707SThomas Veerman snprintf(p, BUFSZ(p), "%s", t);
9255ea9e707SThomas Veerman break;
9265ea9e707SThomas Veerman case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
9275ea9e707SThomas Veerman case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
9285ea9e707SThomas Veerman case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
9295ea9e707SThomas Veerman case 's':
9305ea9e707SThomas Veerman t = getsval(x);
9315ea9e707SThomas Veerman n = strlen(t);
9325ea9e707SThomas Veerman if (fmtwd > n)
9335ea9e707SThomas Veerman n = fmtwd;
9345ea9e707SThomas Veerman if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
9355ea9e707SThomas Veerman FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t);
9365ea9e707SThomas Veerman snprintf(p, BUFSZ(p), fmt, t);
9375ea9e707SThomas Veerman break;
9385ea9e707SThomas Veerman case 'c':
9395ea9e707SThomas Veerman if (isnum(x)) {
9405ea9e707SThomas Veerman if (getfval(x))
9415ea9e707SThomas Veerman snprintf(p, BUFSZ(p), fmt, (int) getfval(x));
9425ea9e707SThomas Veerman else {
9435ea9e707SThomas Veerman *p++ = '\0'; /* explicit null byte */
9445ea9e707SThomas Veerman *p = '\0'; /* next output will start here */
9455ea9e707SThomas Veerman }
9465ea9e707SThomas Veerman } else
9475ea9e707SThomas Veerman snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
9485ea9e707SThomas Veerman break;
9495ea9e707SThomas Veerman default:
9505ea9e707SThomas Veerman FATAL("can't happen: bad conversion %c in format()", flag);
9515ea9e707SThomas Veerman }
9525ea9e707SThomas Veerman tempfree(x);
9535ea9e707SThomas Veerman p += strlen(p);
9545ea9e707SThomas Veerman s++;
9555ea9e707SThomas Veerman }
9565ea9e707SThomas Veerman *p = '\0';
9575ea9e707SThomas Veerman free(fmt);
9585ea9e707SThomas Veerman for ( ; a; a = a->nnext) /* evaluate any remaining args */
9595ea9e707SThomas Veerman execute(a);
9605ea9e707SThomas Veerman *pbuf = buf;
9615ea9e707SThomas Veerman *pbufsize = bufsize;
9625ea9e707SThomas Veerman return p - buf;
9635ea9e707SThomas Veerman }
9645ea9e707SThomas Veerman
awksprintf(Node ** a,int n)9655ea9e707SThomas Veerman Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
9665ea9e707SThomas Veerman {
9675ea9e707SThomas Veerman Cell *x;
9685ea9e707SThomas Veerman Node *y;
9695ea9e707SThomas Veerman char *buf;
9705ea9e707SThomas Veerman int bufsz=3*recsize;
9715ea9e707SThomas Veerman
9725ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
9735ea9e707SThomas Veerman FATAL("out of memory in awksprintf");
9745ea9e707SThomas Veerman y = a[0]->nnext;
9755ea9e707SThomas Veerman x = execute(a[0]);
9765ea9e707SThomas Veerman if (format(&buf, &bufsz, getsval(x), y) == -1)
9775ea9e707SThomas Veerman FATAL("sprintf string %.30s... too long. can't happen.", buf);
9785ea9e707SThomas Veerman tempfree(x);
9795ea9e707SThomas Veerman x = gettemp();
9805ea9e707SThomas Veerman x->sval = buf;
9815ea9e707SThomas Veerman x->tval = STR;
9825ea9e707SThomas Veerman return(x);
9835ea9e707SThomas Veerman }
9845ea9e707SThomas Veerman
awkprintf(Node ** a,int n)9855ea9e707SThomas Veerman Cell *awkprintf(Node **a, int n) /* printf */
9865ea9e707SThomas Veerman { /* a[0] is list of args, starting with format string */
9875ea9e707SThomas Veerman /* a[1] is redirection operator, a[2] is redirection file */
9885ea9e707SThomas Veerman FILE *fp;
9895ea9e707SThomas Veerman Cell *x;
9905ea9e707SThomas Veerman Node *y;
9915ea9e707SThomas Veerman char *buf;
9925ea9e707SThomas Veerman int len;
9935ea9e707SThomas Veerman int bufsz=3*recsize;
9945ea9e707SThomas Veerman
9955ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
9965ea9e707SThomas Veerman FATAL("out of memory in awkprintf");
9975ea9e707SThomas Veerman y = a[0]->nnext;
9985ea9e707SThomas Veerman x = execute(a[0]);
9995ea9e707SThomas Veerman if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
10005ea9e707SThomas Veerman FATAL("printf string %.30s... too long. can't happen.", buf);
10015ea9e707SThomas Veerman tempfree(x);
10025ea9e707SThomas Veerman if (a[1] == NULL) {
10035ea9e707SThomas Veerman /* fputs(buf, stdout); */
10045ea9e707SThomas Veerman fwrite(buf, len, 1, stdout);
10055ea9e707SThomas Veerman if (ferror(stdout))
10065ea9e707SThomas Veerman FATAL("write error on stdout");
10075ea9e707SThomas Veerman } else {
10085ea9e707SThomas Veerman fp = redirect(ptoi(a[1]), a[2]);
10095ea9e707SThomas Veerman /* fputs(buf, fp); */
10105ea9e707SThomas Veerman fwrite(buf, len, 1, fp);
10115ea9e707SThomas Veerman fflush(fp);
10125ea9e707SThomas Veerman if (ferror(fp))
10135ea9e707SThomas Veerman FATAL("write error on %s", filename(fp));
10145ea9e707SThomas Veerman }
10155ea9e707SThomas Veerman free(buf);
10165ea9e707SThomas Veerman return(True);
10175ea9e707SThomas Veerman }
10185ea9e707SThomas Veerman
arith(Node ** a,int n)10195ea9e707SThomas Veerman Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
10205ea9e707SThomas Veerman {
10215ea9e707SThomas Veerman Awkfloat i, j = 0;
10225ea9e707SThomas Veerman double v;
10235ea9e707SThomas Veerman Cell *x, *y, *z;
10245ea9e707SThomas Veerman
10255ea9e707SThomas Veerman x = execute(a[0]);
10265ea9e707SThomas Veerman i = getfval(x);
10275ea9e707SThomas Veerman tempfree(x);
10285ea9e707SThomas Veerman if (n != UMINUS) {
10295ea9e707SThomas Veerman y = execute(a[1]);
10305ea9e707SThomas Veerman j = getfval(y);
10315ea9e707SThomas Veerman tempfree(y);
10325ea9e707SThomas Veerman }
10335ea9e707SThomas Veerman z = gettemp();
10345ea9e707SThomas Veerman switch (n) {
10355ea9e707SThomas Veerman case ADD:
10365ea9e707SThomas Veerman i += j;
10375ea9e707SThomas Veerman break;
10385ea9e707SThomas Veerman case MINUS:
10395ea9e707SThomas Veerman i -= j;
10405ea9e707SThomas Veerman break;
10415ea9e707SThomas Veerman case MULT:
10425ea9e707SThomas Veerman i *= j;
10435ea9e707SThomas Veerman break;
10445ea9e707SThomas Veerman case DIVIDE:
10455ea9e707SThomas Veerman if (j == 0)
10465ea9e707SThomas Veerman FATAL("division by zero");
10475ea9e707SThomas Veerman i /= j;
10485ea9e707SThomas Veerman break;
10495ea9e707SThomas Veerman case MOD:
10505ea9e707SThomas Veerman if (j == 0)
10515ea9e707SThomas Veerman FATAL("division by zero in mod");
10525ea9e707SThomas Veerman modf(i/j, &v);
10535ea9e707SThomas Veerman i = i - j * v;
10545ea9e707SThomas Veerman break;
10555ea9e707SThomas Veerman case UMINUS:
10565ea9e707SThomas Veerman i = -i;
10575ea9e707SThomas Veerman break;
10585ea9e707SThomas Veerman case POWER:
10595ea9e707SThomas Veerman if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
10605ea9e707SThomas Veerman i = ipow(i, (int) j);
10615ea9e707SThomas Veerman else
10625ea9e707SThomas Veerman i = errcheck(pow(i, j), "pow");
10635ea9e707SThomas Veerman break;
10645ea9e707SThomas Veerman default: /* can't happen */
10655ea9e707SThomas Veerman FATAL("illegal arithmetic operator %d", n);
10665ea9e707SThomas Veerman }
10675ea9e707SThomas Veerman setfval(z, i);
10685ea9e707SThomas Veerman return(z);
10695ea9e707SThomas Veerman }
10705ea9e707SThomas Veerman
ipow(double x,int n)10715ea9e707SThomas Veerman double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
10725ea9e707SThomas Veerman {
10735ea9e707SThomas Veerman double v;
10745ea9e707SThomas Veerman
10755ea9e707SThomas Veerman if (n <= 0)
10765ea9e707SThomas Veerman return 1;
10775ea9e707SThomas Veerman v = ipow(x, n/2);
10785ea9e707SThomas Veerman if (n % 2 == 0)
10795ea9e707SThomas Veerman return v * v;
10805ea9e707SThomas Veerman else
10815ea9e707SThomas Veerman return x * v * v;
10825ea9e707SThomas Veerman }
10835ea9e707SThomas Veerman
incrdecr(Node ** a,int n)10845ea9e707SThomas Veerman Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
10855ea9e707SThomas Veerman {
10865ea9e707SThomas Veerman Cell *x, *z;
10875ea9e707SThomas Veerman int k;
10885ea9e707SThomas Veerman Awkfloat xf;
10895ea9e707SThomas Veerman
10905ea9e707SThomas Veerman x = execute(a[0]);
10915ea9e707SThomas Veerman xf = getfval(x);
10925ea9e707SThomas Veerman k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
10935ea9e707SThomas Veerman if (n == PREINCR || n == PREDECR) {
10945ea9e707SThomas Veerman setfval(x, xf + k);
10955ea9e707SThomas Veerman return(x);
10965ea9e707SThomas Veerman }
10975ea9e707SThomas Veerman z = gettemp();
10985ea9e707SThomas Veerman setfval(z, xf);
10995ea9e707SThomas Veerman setfval(x, xf + k);
11005ea9e707SThomas Veerman tempfree(x);
11015ea9e707SThomas Veerman return(z);
11025ea9e707SThomas Veerman }
11035ea9e707SThomas Veerman
assign(Node ** a,int n)11045ea9e707SThomas Veerman Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
11055ea9e707SThomas Veerman { /* this is subtle; don't muck with it. */
11065ea9e707SThomas Veerman Cell *x, *y;
11075ea9e707SThomas Veerman Awkfloat xf, yf;
11085ea9e707SThomas Veerman double v;
11095ea9e707SThomas Veerman
11105ea9e707SThomas Veerman y = execute(a[1]);
11115ea9e707SThomas Veerman x = execute(a[0]);
11125ea9e707SThomas Veerman if (n == ASSIGN) { /* ordinary assignment */
11135ea9e707SThomas Veerman if (x == y && !(x->tval & (FLD|REC))) /* self-assignment: */
11145ea9e707SThomas Veerman ; /* leave alone unless it's a field */
11155ea9e707SThomas Veerman else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
11165ea9e707SThomas Veerman setsval(x, getsval(y));
11175ea9e707SThomas Veerman x->fval = getfval(y);
11185ea9e707SThomas Veerman x->tval |= NUM;
11195ea9e707SThomas Veerman }
11205ea9e707SThomas Veerman else if (isstr(y))
11215ea9e707SThomas Veerman setsval(x, getsval(y));
11225ea9e707SThomas Veerman else if (isnum(y))
11235ea9e707SThomas Veerman setfval(x, getfval(y));
11245ea9e707SThomas Veerman else
11255ea9e707SThomas Veerman funnyvar(y, "read value of");
11265ea9e707SThomas Veerman tempfree(y);
11275ea9e707SThomas Veerman return(x);
11285ea9e707SThomas Veerman }
11295ea9e707SThomas Veerman xf = getfval(x);
11305ea9e707SThomas Veerman yf = getfval(y);
11315ea9e707SThomas Veerman switch (n) {
11325ea9e707SThomas Veerman case ADDEQ:
11335ea9e707SThomas Veerman xf += yf;
11345ea9e707SThomas Veerman break;
11355ea9e707SThomas Veerman case SUBEQ:
11365ea9e707SThomas Veerman xf -= yf;
11375ea9e707SThomas Veerman break;
11385ea9e707SThomas Veerman case MULTEQ:
11395ea9e707SThomas Veerman xf *= yf;
11405ea9e707SThomas Veerman break;
11415ea9e707SThomas Veerman case DIVEQ:
11425ea9e707SThomas Veerman if (yf == 0)
11435ea9e707SThomas Veerman FATAL("division by zero in /=");
11445ea9e707SThomas Veerman xf /= yf;
11455ea9e707SThomas Veerman break;
11465ea9e707SThomas Veerman case MODEQ:
11475ea9e707SThomas Veerman if (yf == 0)
11485ea9e707SThomas Veerman FATAL("division by zero in %%=");
11495ea9e707SThomas Veerman modf(xf/yf, &v);
11505ea9e707SThomas Veerman xf = xf - yf * v;
11515ea9e707SThomas Veerman break;
11525ea9e707SThomas Veerman case POWEQ:
11535ea9e707SThomas Veerman if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
11545ea9e707SThomas Veerman xf = ipow(xf, (int) yf);
11555ea9e707SThomas Veerman else
11565ea9e707SThomas Veerman xf = errcheck(pow(xf, yf), "pow");
11575ea9e707SThomas Veerman break;
11585ea9e707SThomas Veerman default:
11595ea9e707SThomas Veerman FATAL("illegal assignment operator %d", n);
11605ea9e707SThomas Veerman break;
11615ea9e707SThomas Veerman }
11625ea9e707SThomas Veerman tempfree(y);
11635ea9e707SThomas Veerman setfval(x, xf);
11645ea9e707SThomas Veerman return(x);
11655ea9e707SThomas Veerman }
11665ea9e707SThomas Veerman
cat(Node ** a,int q)11675ea9e707SThomas Veerman Cell *cat(Node **a, int q) /* a[0] cat a[1] */
11685ea9e707SThomas Veerman {
11695ea9e707SThomas Veerman Cell *x, *y, *z;
11705ea9e707SThomas Veerman int n1, n2;
11715ea9e707SThomas Veerman char *s;
11725ea9e707SThomas Veerman
11735ea9e707SThomas Veerman x = execute(a[0]);
11745ea9e707SThomas Veerman y = execute(a[1]);
11755ea9e707SThomas Veerman getsval(x);
11765ea9e707SThomas Veerman getsval(y);
11775ea9e707SThomas Veerman n1 = strlen(x->sval);
11785ea9e707SThomas Veerman n2 = strlen(y->sval);
11795ea9e707SThomas Veerman s = malloc(n1 + n2 + 1);
11805ea9e707SThomas Veerman if (s == NULL)
11815ea9e707SThomas Veerman FATAL("out of space concatenating %.15s... and %.15s...",
11825ea9e707SThomas Veerman x->sval, y->sval);
11835ea9e707SThomas Veerman strcpy(s, x->sval);
11845ea9e707SThomas Veerman strcpy(s+n1, y->sval);
11855ea9e707SThomas Veerman tempfree(x);
11865ea9e707SThomas Veerman tempfree(y);
11875ea9e707SThomas Veerman z = gettemp();
11885ea9e707SThomas Veerman z->sval = s;
11895ea9e707SThomas Veerman z->tval = STR;
11905ea9e707SThomas Veerman return(z);
11915ea9e707SThomas Veerman }
11925ea9e707SThomas Veerman
pastat(Node ** a,int n)11935ea9e707SThomas Veerman Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
11945ea9e707SThomas Veerman {
11955ea9e707SThomas Veerman Cell *x;
11965ea9e707SThomas Veerman
11975ea9e707SThomas Veerman if (a[0] == 0)
11985ea9e707SThomas Veerman x = execute(a[1]);
11995ea9e707SThomas Veerman else {
12005ea9e707SThomas Veerman x = execute(a[0]);
12015ea9e707SThomas Veerman if (istrue(x)) {
12025ea9e707SThomas Veerman tempfree(x);
12035ea9e707SThomas Veerman x = execute(a[1]);
12045ea9e707SThomas Veerman }
12055ea9e707SThomas Veerman }
12065ea9e707SThomas Veerman return x;
12075ea9e707SThomas Veerman }
12085ea9e707SThomas Veerman
dopa2(Node ** a,int n)12095ea9e707SThomas Veerman Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
12105ea9e707SThomas Veerman {
12115ea9e707SThomas Veerman Cell *x;
12125ea9e707SThomas Veerman int pair;
12135ea9e707SThomas Veerman
12145ea9e707SThomas Veerman pair = ptoi(a[3]);
12155ea9e707SThomas Veerman if (pairstack[pair] == 0) {
12165ea9e707SThomas Veerman x = execute(a[0]);
12175ea9e707SThomas Veerman if (istrue(x))
12185ea9e707SThomas Veerman pairstack[pair] = 1;
12195ea9e707SThomas Veerman tempfree(x);
12205ea9e707SThomas Veerman }
12215ea9e707SThomas Veerman if (pairstack[pair] == 1) {
12225ea9e707SThomas Veerman x = execute(a[1]);
12235ea9e707SThomas Veerman if (istrue(x))
12245ea9e707SThomas Veerman pairstack[pair] = 0;
12255ea9e707SThomas Veerman tempfree(x);
12265ea9e707SThomas Veerman x = execute(a[2]);
12275ea9e707SThomas Veerman return(x);
12285ea9e707SThomas Veerman }
12295ea9e707SThomas Veerman return(False);
12305ea9e707SThomas Veerman }
12315ea9e707SThomas Veerman
12325ea9e707SThomas Veerman static char regexpr[] = "(regexpr)";
split(Node ** a,int nnn)12335ea9e707SThomas Veerman Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
12345ea9e707SThomas Veerman {
12355ea9e707SThomas Veerman Cell *x = 0, *y, *ap;
123684d9c625SLionel Sambuc char *s, *origs;
12375ea9e707SThomas Veerman int sep;
12385ea9e707SThomas Veerman char *t, temp, num[50], *fs = 0;
12395ea9e707SThomas Veerman int n, tempstat, arg3type;
12405ea9e707SThomas Veerman
12415ea9e707SThomas Veerman y = execute(a[0]); /* source string */
124284d9c625SLionel Sambuc origs = s = strdup(getsval(y));
12435ea9e707SThomas Veerman arg3type = ptoi(a[3]);
12445ea9e707SThomas Veerman if (a[2] == 0) /* fs string */
12455ea9e707SThomas Veerman fs = *FS;
12465ea9e707SThomas Veerman else if (arg3type == STRING) { /* split(str,arr,"string") */
12475ea9e707SThomas Veerman x = execute(a[2]);
12485ea9e707SThomas Veerman fs = getsval(x);
12495ea9e707SThomas Veerman } else if (arg3type == REGEXPR)
12505ea9e707SThomas Veerman fs = regexpr; /* split(str,arr,/regexpr/) */
12515ea9e707SThomas Veerman else
12525ea9e707SThomas Veerman FATAL("illegal type of split");
12535ea9e707SThomas Veerman sep = *fs;
12545ea9e707SThomas Veerman ap = execute(a[1]); /* array name */
12555ea9e707SThomas Veerman freesymtab(ap);
12565ea9e707SThomas Veerman dprintf( ("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs) );
12575ea9e707SThomas Veerman ap->tval &= ~STR;
12585ea9e707SThomas Veerman ap->tval |= ARR;
12595ea9e707SThomas Veerman ap->sval = (char *) makesymtab(NSYMTAB);
12605ea9e707SThomas Veerman
12615ea9e707SThomas Veerman n = 0;
126284d9c625SLionel Sambuc if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
126384d9c625SLionel Sambuc /* split(s, a, //); have to arrange that it looks like empty sep */
126484d9c625SLionel Sambuc arg3type = 0;
126584d9c625SLionel Sambuc fs = EMPTY;
126684d9c625SLionel Sambuc sep = 0;
126784d9c625SLionel Sambuc }
12685ea9e707SThomas Veerman if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
12695ea9e707SThomas Veerman fa *pfa;
12705ea9e707SThomas Veerman if (arg3type == REGEXPR) { /* it's ready already */
12715ea9e707SThomas Veerman pfa = (fa *) a[2];
12725ea9e707SThomas Veerman } else {
12735ea9e707SThomas Veerman pfa = makedfa(fs, 1);
12745ea9e707SThomas Veerman }
12755ea9e707SThomas Veerman if (nematch(pfa,s)) {
12765ea9e707SThomas Veerman tempstat = pfa->initstat;
12775ea9e707SThomas Veerman pfa->initstat = 2;
12785ea9e707SThomas Veerman do {
12795ea9e707SThomas Veerman n++;
12805ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
12815ea9e707SThomas Veerman temp = *patbeg;
12825ea9e707SThomas Veerman *patbeg = '\0';
12835ea9e707SThomas Veerman if (is_number(s))
12845ea9e707SThomas Veerman setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
12855ea9e707SThomas Veerman else
12865ea9e707SThomas Veerman setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
12875ea9e707SThomas Veerman *patbeg = temp;
12885ea9e707SThomas Veerman s = patbeg + patlen;
12895ea9e707SThomas Veerman if (*(patbeg+patlen-1) == 0 || *s == 0) {
12905ea9e707SThomas Veerman n++;
12915ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
12925ea9e707SThomas Veerman setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
12935ea9e707SThomas Veerman pfa->initstat = tempstat;
12945ea9e707SThomas Veerman goto spdone;
12955ea9e707SThomas Veerman }
12965ea9e707SThomas Veerman } while (nematch(pfa,s));
12975ea9e707SThomas Veerman pfa->initstat = tempstat; /* bwk: has to be here to reset */
12985ea9e707SThomas Veerman /* cf gsub and refldbld */
12995ea9e707SThomas Veerman }
13005ea9e707SThomas Veerman n++;
13015ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
13025ea9e707SThomas Veerman if (is_number(s))
13035ea9e707SThomas Veerman setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
13045ea9e707SThomas Veerman else
13055ea9e707SThomas Veerman setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
13065ea9e707SThomas Veerman spdone:
13075ea9e707SThomas Veerman pfa = NULL;
13085ea9e707SThomas Veerman } else if (sep == ' ') {
13095ea9e707SThomas Veerman for (n = 0; ; ) {
13105ea9e707SThomas Veerman while (*s == ' ' || *s == '\t' || *s == '\n')
13115ea9e707SThomas Veerman s++;
13125ea9e707SThomas Veerman if (*s == 0)
13135ea9e707SThomas Veerman break;
13145ea9e707SThomas Veerman n++;
13155ea9e707SThomas Veerman t = s;
13165ea9e707SThomas Veerman do
13175ea9e707SThomas Veerman s++;
13185ea9e707SThomas Veerman while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0');
13195ea9e707SThomas Veerman temp = *s;
13205ea9e707SThomas Veerman *s = '\0';
13215ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
13225ea9e707SThomas Veerman if (is_number(t))
13235ea9e707SThomas Veerman setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13245ea9e707SThomas Veerman else
13255ea9e707SThomas Veerman setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13265ea9e707SThomas Veerman *s = temp;
13275ea9e707SThomas Veerman if (*s != 0)
13285ea9e707SThomas Veerman s++;
13295ea9e707SThomas Veerman }
13305ea9e707SThomas Veerman } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
13315ea9e707SThomas Veerman for (n = 0; *s != 0; s++) {
13325ea9e707SThomas Veerman char buf[2];
13335ea9e707SThomas Veerman n++;
13345ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
13355ea9e707SThomas Veerman buf[0] = *s;
13365ea9e707SThomas Veerman buf[1] = 0;
13375ea9e707SThomas Veerman if (isdigit((uschar)buf[0]))
13385ea9e707SThomas Veerman setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
13395ea9e707SThomas Veerman else
13405ea9e707SThomas Veerman setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
13415ea9e707SThomas Veerman }
13425ea9e707SThomas Veerman } else if (*s != 0) {
13435ea9e707SThomas Veerman for (;;) {
13445ea9e707SThomas Veerman n++;
13455ea9e707SThomas Veerman t = s;
13465ea9e707SThomas Veerman while (*s != sep && *s != '\n' && *s != '\0')
13475ea9e707SThomas Veerman s++;
13485ea9e707SThomas Veerman temp = *s;
13495ea9e707SThomas Veerman *s = '\0';
13505ea9e707SThomas Veerman snprintf(num, sizeof(num), "%d", n);
13515ea9e707SThomas Veerman if (is_number(t))
13525ea9e707SThomas Veerman setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
13535ea9e707SThomas Veerman else
13545ea9e707SThomas Veerman setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
13555ea9e707SThomas Veerman *s = temp;
13565ea9e707SThomas Veerman if (*s++ == 0)
13575ea9e707SThomas Veerman break;
13585ea9e707SThomas Veerman }
13595ea9e707SThomas Veerman }
13605ea9e707SThomas Veerman tempfree(ap);
13615ea9e707SThomas Veerman tempfree(y);
136284d9c625SLionel Sambuc free(origs);
13635ea9e707SThomas Veerman if (a[2] != 0 && arg3type == STRING) {
13645ea9e707SThomas Veerman tempfree(x);
13655ea9e707SThomas Veerman }
13665ea9e707SThomas Veerman x = gettemp();
13675ea9e707SThomas Veerman x->tval = NUM;
13685ea9e707SThomas Veerman x->fval = n;
13695ea9e707SThomas Veerman return(x);
13705ea9e707SThomas Veerman }
13715ea9e707SThomas Veerman
condexpr(Node ** a,int n)13725ea9e707SThomas Veerman Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
13735ea9e707SThomas Veerman {
13745ea9e707SThomas Veerman Cell *x;
13755ea9e707SThomas Veerman
13765ea9e707SThomas Veerman x = execute(a[0]);
13775ea9e707SThomas Veerman if (istrue(x)) {
13785ea9e707SThomas Veerman tempfree(x);
13795ea9e707SThomas Veerman x = execute(a[1]);
13805ea9e707SThomas Veerman } else {
13815ea9e707SThomas Veerman tempfree(x);
13825ea9e707SThomas Veerman x = execute(a[2]);
13835ea9e707SThomas Veerman }
13845ea9e707SThomas Veerman return(x);
13855ea9e707SThomas Veerman }
13865ea9e707SThomas Veerman
ifstat(Node ** a,int n)13875ea9e707SThomas Veerman Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
13885ea9e707SThomas Veerman {
13895ea9e707SThomas Veerman Cell *x;
13905ea9e707SThomas Veerman
13915ea9e707SThomas Veerman x = execute(a[0]);
13925ea9e707SThomas Veerman if (istrue(x)) {
13935ea9e707SThomas Veerman tempfree(x);
13945ea9e707SThomas Veerman x = execute(a[1]);
13955ea9e707SThomas Veerman } else if (a[2] != 0) {
13965ea9e707SThomas Veerman tempfree(x);
13975ea9e707SThomas Veerman x = execute(a[2]);
13985ea9e707SThomas Veerman }
13995ea9e707SThomas Veerman return(x);
14005ea9e707SThomas Veerman }
14015ea9e707SThomas Veerman
whilestat(Node ** a,int n)14025ea9e707SThomas Veerman Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
14035ea9e707SThomas Veerman {
14045ea9e707SThomas Veerman Cell *x;
14055ea9e707SThomas Veerman
14065ea9e707SThomas Veerman for (;;) {
14075ea9e707SThomas Veerman x = execute(a[0]);
14085ea9e707SThomas Veerman if (!istrue(x))
14095ea9e707SThomas Veerman return(x);
14105ea9e707SThomas Veerman tempfree(x);
14115ea9e707SThomas Veerman x = execute(a[1]);
14125ea9e707SThomas Veerman if (isbreak(x)) {
14135ea9e707SThomas Veerman x = True;
14145ea9e707SThomas Veerman return(x);
14155ea9e707SThomas Veerman }
14165ea9e707SThomas Veerman if (isnext(x) || isexit(x) || isret(x))
14175ea9e707SThomas Veerman return(x);
14185ea9e707SThomas Veerman tempfree(x);
14195ea9e707SThomas Veerman }
14205ea9e707SThomas Veerman }
14215ea9e707SThomas Veerman
dostat(Node ** a,int n)14225ea9e707SThomas Veerman Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
14235ea9e707SThomas Veerman {
14245ea9e707SThomas Veerman Cell *x;
14255ea9e707SThomas Veerman
14265ea9e707SThomas Veerman for (;;) {
14275ea9e707SThomas Veerman x = execute(a[0]);
14285ea9e707SThomas Veerman if (isbreak(x))
14295ea9e707SThomas Veerman return True;
14305ea9e707SThomas Veerman if (isnext(x) || isexit(x) || isret(x))
14315ea9e707SThomas Veerman return(x);
14325ea9e707SThomas Veerman tempfree(x);
14335ea9e707SThomas Veerman x = execute(a[1]);
14345ea9e707SThomas Veerman if (!istrue(x))
14355ea9e707SThomas Veerman return(x);
14365ea9e707SThomas Veerman tempfree(x);
14375ea9e707SThomas Veerman }
14385ea9e707SThomas Veerman }
14395ea9e707SThomas Veerman
forstat(Node ** a,int n)14405ea9e707SThomas Veerman Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
14415ea9e707SThomas Veerman {
14425ea9e707SThomas Veerman Cell *x;
14435ea9e707SThomas Veerman
14445ea9e707SThomas Veerman x = execute(a[0]);
14455ea9e707SThomas Veerman tempfree(x);
14465ea9e707SThomas Veerman for (;;) {
14475ea9e707SThomas Veerman if (a[1]!=0) {
14485ea9e707SThomas Veerman x = execute(a[1]);
14495ea9e707SThomas Veerman if (!istrue(x)) return(x);
14505ea9e707SThomas Veerman else tempfree(x);
14515ea9e707SThomas Veerman }
14525ea9e707SThomas Veerman x = execute(a[3]);
14535ea9e707SThomas Veerman if (isbreak(x)) /* turn off break */
14545ea9e707SThomas Veerman return True;
14555ea9e707SThomas Veerman if (isnext(x) || isexit(x) || isret(x))
14565ea9e707SThomas Veerman return(x);
14575ea9e707SThomas Veerman tempfree(x);
14585ea9e707SThomas Veerman x = execute(a[2]);
14595ea9e707SThomas Veerman tempfree(x);
14605ea9e707SThomas Veerman }
14615ea9e707SThomas Veerman }
14625ea9e707SThomas Veerman
instat(Node ** a,int n)14635ea9e707SThomas Veerman Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
14645ea9e707SThomas Veerman {
14655ea9e707SThomas Veerman Cell *x, *vp, *arrayp, *cp, *ncp;
14665ea9e707SThomas Veerman Array *tp;
14675ea9e707SThomas Veerman int i;
14685ea9e707SThomas Veerman
14695ea9e707SThomas Veerman vp = execute(a[0]);
14705ea9e707SThomas Veerman arrayp = execute(a[1]);
14715ea9e707SThomas Veerman if (!isarr(arrayp)) {
14725ea9e707SThomas Veerman return True;
14735ea9e707SThomas Veerman }
14745ea9e707SThomas Veerman tp = (Array *) arrayp->sval;
14755ea9e707SThomas Veerman tempfree(arrayp);
14765ea9e707SThomas Veerman for (i = 0; i < tp->size; i++) { /* this routine knows too much */
14775ea9e707SThomas Veerman for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
14785ea9e707SThomas Veerman setsval(vp, cp->nval);
14795ea9e707SThomas Veerman ncp = cp->cnext;
14805ea9e707SThomas Veerman x = execute(a[2]);
14815ea9e707SThomas Veerman if (isbreak(x)) {
14825ea9e707SThomas Veerman tempfree(vp);
14835ea9e707SThomas Veerman return True;
14845ea9e707SThomas Veerman }
14855ea9e707SThomas Veerman if (isnext(x) || isexit(x) || isret(x)) {
14865ea9e707SThomas Veerman tempfree(vp);
14875ea9e707SThomas Veerman return(x);
14885ea9e707SThomas Veerman }
14895ea9e707SThomas Veerman tempfree(x);
14905ea9e707SThomas Veerman }
14915ea9e707SThomas Veerman }
14925ea9e707SThomas Veerman return True;
14935ea9e707SThomas Veerman }
14945ea9e707SThomas Veerman
14955ea9e707SThomas Veerman void flush_all(void);
14965ea9e707SThomas Veerman
nawk_toXXX(const char * s,int (* fun_c)(int),wint_t (* fun_wc)(wint_t))14975ea9e707SThomas Veerman static char *nawk_toXXX(const char *s,
14985ea9e707SThomas Veerman int (*fun_c)(int),
14995ea9e707SThomas Veerman wint_t (*fun_wc)(wint_t))
15005ea9e707SThomas Veerman {
15015ea9e707SThomas Veerman char *buf = NULL;
15025ea9e707SThomas Veerman char *pbuf = NULL;
15035ea9e707SThomas Veerman const char *ps = NULL;
15045ea9e707SThomas Veerman size_t n = 0;
15055ea9e707SThomas Veerman mbstate_t mbs, mbs2;
15065ea9e707SThomas Veerman wchar_t wc;
15075ea9e707SThomas Veerman size_t sz = MB_CUR_MAX;
15085ea9e707SThomas Veerman
15095ea9e707SThomas Veerman if (sz == 1) {
15105ea9e707SThomas Veerman buf = tostring(s);
15115ea9e707SThomas Veerman
15125ea9e707SThomas Veerman for (pbuf = buf; *pbuf; pbuf++)
15135ea9e707SThomas Veerman *pbuf = fun_c((uschar)*pbuf);
15145ea9e707SThomas Veerman
15155ea9e707SThomas Veerman return buf;
15165ea9e707SThomas Veerman } else {
15175ea9e707SThomas Veerman /* upper/lower character may be shorter/longer */
15185ea9e707SThomas Veerman buf = tostringN(s, strlen(s) * sz + 1);
15195ea9e707SThomas Veerman
15205ea9e707SThomas Veerman memset(&mbs, 0, sizeof(mbs));
15215ea9e707SThomas Veerman memset(&mbs2, 0, sizeof(mbs2));
15225ea9e707SThomas Veerman
15235ea9e707SThomas Veerman ps = s;
15245ea9e707SThomas Veerman pbuf = buf;
15255ea9e707SThomas Veerman while (n = mbrtowc(&wc, ps, sz, &mbs),
15265ea9e707SThomas Veerman n > 0 && n != (size_t)-1 && n != (size_t)-2)
15275ea9e707SThomas Veerman {
15285ea9e707SThomas Veerman ps += n;
15295ea9e707SThomas Veerman
15305ea9e707SThomas Veerman n = wcrtomb(pbuf, fun_wc(wc), &mbs2);
15315ea9e707SThomas Veerman if (n == (size_t)-1)
15325ea9e707SThomas Veerman FATAL("illegal wide character %s", s);
15335ea9e707SThomas Veerman
15345ea9e707SThomas Veerman pbuf += n;
15355ea9e707SThomas Veerman }
15365ea9e707SThomas Veerman
15375ea9e707SThomas Veerman *pbuf = 0;
15385ea9e707SThomas Veerman
15395ea9e707SThomas Veerman if (n)
15405ea9e707SThomas Veerman FATAL("illegal byte sequence %s", s);
15415ea9e707SThomas Veerman
15425ea9e707SThomas Veerman return buf;
15435ea9e707SThomas Veerman }
15445ea9e707SThomas Veerman }
15455ea9e707SThomas Veerman
nawk_toupper(const char * s)15465ea9e707SThomas Veerman static char *nawk_toupper(const char *s)
15475ea9e707SThomas Veerman {
15485ea9e707SThomas Veerman return nawk_toXXX(s, toupper, towupper);
15495ea9e707SThomas Veerman }
15505ea9e707SThomas Veerman
nawk_tolower(const char * s)15515ea9e707SThomas Veerman static char *nawk_tolower(const char *s)
15525ea9e707SThomas Veerman {
15535ea9e707SThomas Veerman return nawk_toXXX(s, tolower, towlower);
15545ea9e707SThomas Veerman }
15555ea9e707SThomas Veerman
bltin(Node ** a,int n)15565ea9e707SThomas Veerman Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
15575ea9e707SThomas Veerman {
15585ea9e707SThomas Veerman Cell *x, *y;
15595ea9e707SThomas Veerman Awkfloat u;
15605ea9e707SThomas Veerman int t, sz;
15615ea9e707SThomas Veerman unsigned int tmp;
15625ea9e707SThomas Veerman char *buf, *fmt;
15635ea9e707SThomas Veerman Node *nextarg;
15645ea9e707SThomas Veerman FILE *fp;
15655ea9e707SThomas Veerman time_t tv;
15665ea9e707SThomas Veerman struct tm *tm;
15675ea9e707SThomas Veerman
15685ea9e707SThomas Veerman t = ptoi(a[0]);
15695ea9e707SThomas Veerman x = execute(a[1]);
15705ea9e707SThomas Veerman nextarg = a[1]->nnext;
15715ea9e707SThomas Veerman switch (t) {
15725ea9e707SThomas Veerman case FLENGTH:
15735ea9e707SThomas Veerman if (isarr(x))
15745ea9e707SThomas Veerman u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
15755ea9e707SThomas Veerman else
15765ea9e707SThomas Veerman u = strlen(getsval(x));
15775ea9e707SThomas Veerman break;
15785ea9e707SThomas Veerman case FLOG:
15795ea9e707SThomas Veerman u = errcheck(log(getfval(x)), "log"); break;
15805ea9e707SThomas Veerman case FINT:
15815ea9e707SThomas Veerman modf(getfval(x), &u); break;
15825ea9e707SThomas Veerman case FEXP:
15835ea9e707SThomas Veerman u = errcheck(exp(getfval(x)), "exp"); break;
15845ea9e707SThomas Veerman case FSQRT:
15855ea9e707SThomas Veerman u = errcheck(sqrt(getfval(x)), "sqrt"); break;
15865ea9e707SThomas Veerman case FSIN:
15875ea9e707SThomas Veerman u = sin(getfval(x)); break;
15885ea9e707SThomas Veerman case FCOS:
15895ea9e707SThomas Veerman u = cos(getfval(x)); break;
15905ea9e707SThomas Veerman case FATAN:
15915ea9e707SThomas Veerman if (nextarg == 0) {
15925ea9e707SThomas Veerman WARNING("atan2 requires two arguments; returning 1.0");
15935ea9e707SThomas Veerman u = 1.0;
15945ea9e707SThomas Veerman } else {
15955ea9e707SThomas Veerman y = execute(a[1]->nnext);
15965ea9e707SThomas Veerman u = atan2(getfval(x), getfval(y));
15975ea9e707SThomas Veerman tempfree(y);
15985ea9e707SThomas Veerman nextarg = nextarg->nnext;
15995ea9e707SThomas Veerman }
16005ea9e707SThomas Veerman break;
16015ea9e707SThomas Veerman case FSYSTEM:
16025ea9e707SThomas Veerman fflush(stdout); /* in case something is buffered already */
16035ea9e707SThomas Veerman u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */
16045ea9e707SThomas Veerman break;
16055ea9e707SThomas Veerman case FRAND:
16065ea9e707SThomas Veerman /* in principle, rand() returns something in 0..RAND_MAX */
16075ea9e707SThomas Veerman u = (Awkfloat) (rand() % RAND_MAX) / RAND_MAX;
16085ea9e707SThomas Veerman break;
16095ea9e707SThomas Veerman case FSRAND:
16105ea9e707SThomas Veerman if (isrec(x)) /* no argument provided */
16115ea9e707SThomas Veerman u = time((time_t *)0);
16125ea9e707SThomas Veerman else
16135ea9e707SThomas Veerman u = getfval(x);
161484d9c625SLionel Sambuc tmp = (unsigned int) u;
161584d9c625SLionel Sambuc srand(tmp);
16165ea9e707SThomas Veerman u = srand_seed;
16175ea9e707SThomas Veerman srand_seed = tmp;
16185ea9e707SThomas Veerman break;
16195ea9e707SThomas Veerman case FTOUPPER:
16205ea9e707SThomas Veerman case FTOLOWER:
16215ea9e707SThomas Veerman if (t == FTOUPPER)
16225ea9e707SThomas Veerman buf = nawk_toupper(getsval(x));
16235ea9e707SThomas Veerman else
16245ea9e707SThomas Veerman buf = nawk_tolower(getsval(x));
16255ea9e707SThomas Veerman tempfree(x);
16265ea9e707SThomas Veerman x = gettemp();
16275ea9e707SThomas Veerman setsval(x, buf);
16285ea9e707SThomas Veerman free(buf);
16295ea9e707SThomas Veerman return x;
16305ea9e707SThomas Veerman case FFLUSH:
16315ea9e707SThomas Veerman if (isrec(x) || strlen(getsval(x)) == 0) {
16325ea9e707SThomas Veerman flush_all(); /* fflush() or fflush("") -> all */
16335ea9e707SThomas Veerman u = 0;
16345ea9e707SThomas Veerman } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
16355ea9e707SThomas Veerman u = -1;
16365ea9e707SThomas Veerman else
16375ea9e707SThomas Veerman u = fflush(fp);
16385ea9e707SThomas Veerman break;
16395ea9e707SThomas Veerman case FSYSTIME:
16405ea9e707SThomas Veerman u = time((time_t *) 0); break;
16415ea9e707SThomas Veerman case FSTRFTIME:
16425ea9e707SThomas Veerman /* strftime([format [,timestamp]]) */
16435ea9e707SThomas Veerman if (nextarg) {
16445ea9e707SThomas Veerman y = execute(nextarg), nextarg = nextarg->nnext;
16455ea9e707SThomas Veerman tv = (time_t) getfval(y);
16465ea9e707SThomas Veerman tempfree(y);
16475ea9e707SThomas Veerman } else
16485ea9e707SThomas Veerman tv = time((time_t *) 0);
16495ea9e707SThomas Veerman tm = localtime(&tv);
1650*0a6a1f1dSLionel Sambuc if (tm == NULL)
1651*0a6a1f1dSLionel Sambuc FATAL("bad time %jd", (intmax_t)tv);
16525ea9e707SThomas Veerman
16535ea9e707SThomas Veerman if (isrec(x)) {
16545ea9e707SThomas Veerman /* format argument not provided, use default */
16555ea9e707SThomas Veerman fmt = tostring("%a %b %d %H:%M:%S %Z %Y");
16565ea9e707SThomas Veerman } else
16575ea9e707SThomas Veerman fmt = tostring(getsval(x));
16585ea9e707SThomas Veerman
16595ea9e707SThomas Veerman sz = 32, buf = NULL;
16605ea9e707SThomas Veerman do {
16615ea9e707SThomas Veerman if ((buf = realloc(buf, (sz *= 2))) == NULL)
16625ea9e707SThomas Veerman FATAL("out of memory in strftime");
16635ea9e707SThomas Veerman } while(strftime(buf, sz, fmt, tm) == 0);
16645ea9e707SThomas Veerman
16655ea9e707SThomas Veerman y = gettemp();
16665ea9e707SThomas Veerman setsval(y, buf);
16675ea9e707SThomas Veerman free(fmt);
16685ea9e707SThomas Veerman free(buf);
16695ea9e707SThomas Veerman
16705ea9e707SThomas Veerman return y;
16715ea9e707SThomas Veerman default: /* can't happen */
16725ea9e707SThomas Veerman FATAL("illegal function type %d", t);
16735ea9e707SThomas Veerman break;
16745ea9e707SThomas Veerman }
16755ea9e707SThomas Veerman tempfree(x);
16765ea9e707SThomas Veerman x = gettemp();
16775ea9e707SThomas Veerman setfval(x, u);
16785ea9e707SThomas Veerman if (nextarg != 0) {
16795ea9e707SThomas Veerman WARNING("warning: function has too many arguments");
16805ea9e707SThomas Veerman for ( ; nextarg; nextarg = nextarg->nnext)
16815ea9e707SThomas Veerman execute(nextarg);
16825ea9e707SThomas Veerman }
16835ea9e707SThomas Veerman return(x);
16845ea9e707SThomas Veerman }
16855ea9e707SThomas Veerman
printstat(Node ** a,int n)16865ea9e707SThomas Veerman Cell *printstat(Node **a, int n) /* print a[0] */
16875ea9e707SThomas Veerman {
16885ea9e707SThomas Veerman Node *x;
16895ea9e707SThomas Veerman Cell *y;
16905ea9e707SThomas Veerman FILE *fp;
16915ea9e707SThomas Veerman
16925ea9e707SThomas Veerman if (a[1] == 0) /* a[1] is redirection operator, a[2] is file */
16935ea9e707SThomas Veerman fp = stdout;
16945ea9e707SThomas Veerman else
16955ea9e707SThomas Veerman fp = redirect(ptoi(a[1]), a[2]);
16965ea9e707SThomas Veerman for (x = a[0]; x != NULL; x = x->nnext) {
16975ea9e707SThomas Veerman y = execute(x);
16985ea9e707SThomas Veerman fputs(getpssval(y), fp);
16995ea9e707SThomas Veerman tempfree(y);
17005ea9e707SThomas Veerman if (x->nnext == NULL)
17015ea9e707SThomas Veerman fputs(*ORS, fp);
17025ea9e707SThomas Veerman else
17035ea9e707SThomas Veerman fputs(*OFS, fp);
17045ea9e707SThomas Veerman }
17055ea9e707SThomas Veerman if (a[1] != 0)
17065ea9e707SThomas Veerman fflush(fp);
17075ea9e707SThomas Veerman if (ferror(fp))
17085ea9e707SThomas Veerman FATAL("write error on %s", filename(fp));
17095ea9e707SThomas Veerman return(True);
17105ea9e707SThomas Veerman }
17115ea9e707SThomas Veerman
nullproc(Node ** a,int n)17125ea9e707SThomas Veerman Cell *nullproc(Node **a, int n)
17135ea9e707SThomas Veerman {
17145ea9e707SThomas Veerman n = n;
17155ea9e707SThomas Veerman a = a;
17165ea9e707SThomas Veerman return 0;
17175ea9e707SThomas Veerman }
17185ea9e707SThomas Veerman
17195ea9e707SThomas Veerman
redirect(int a,Node * b)17205ea9e707SThomas Veerman FILE *redirect(int a, Node *b) /* set up all i/o redirections */
17215ea9e707SThomas Veerman {
17225ea9e707SThomas Veerman FILE *fp;
17235ea9e707SThomas Veerman Cell *x;
17245ea9e707SThomas Veerman char *fname;
17255ea9e707SThomas Veerman
17265ea9e707SThomas Veerman x = execute(b);
17275ea9e707SThomas Veerman fname = getsval(x);
17285ea9e707SThomas Veerman fp = openfile(a, fname, NULL);
17295ea9e707SThomas Veerman if (fp == NULL)
17305ea9e707SThomas Veerman FATAL("can't open file %s", fname);
17315ea9e707SThomas Veerman tempfree(x);
17325ea9e707SThomas Veerman return fp;
17335ea9e707SThomas Veerman }
17345ea9e707SThomas Veerman
17355ea9e707SThomas Veerman struct files {
17365ea9e707SThomas Veerman FILE *fp;
17375ea9e707SThomas Veerman const char *fname;
17385ea9e707SThomas Veerman int mode; /* '|', 'a', 'w' => LE/LT, GT */
17395ea9e707SThomas Veerman } *files;
174084d9c625SLionel Sambuc
17415ea9e707SThomas Veerman size_t nfiles;
17425ea9e707SThomas Veerman
stdinit(void)17435ea9e707SThomas Veerman void stdinit(void) /* in case stdin, etc., are not constants */
17445ea9e707SThomas Veerman {
17455ea9e707SThomas Veerman nfiles = FOPEN_MAX;
17465ea9e707SThomas Veerman files = calloc(nfiles, sizeof(*files));
17475ea9e707SThomas Veerman if (files == NULL)
17485ea9e707SThomas Veerman FATAL("can't allocate file memory for %zu files", nfiles);
17495ea9e707SThomas Veerman files[0].fp = stdin;
17505ea9e707SThomas Veerman files[0].fname = "/dev/stdin";
17515ea9e707SThomas Veerman files[0].mode = LT;
17525ea9e707SThomas Veerman files[1].fp = stdout;
17535ea9e707SThomas Veerman files[1].fname = "/dev/stdout";
17545ea9e707SThomas Veerman files[1].mode = GT;
17555ea9e707SThomas Veerman files[2].fp = stderr;
17565ea9e707SThomas Veerman files[2].fname = "/dev/stderr";
17575ea9e707SThomas Veerman files[2].mode = GT;
17585ea9e707SThomas Veerman }
17595ea9e707SThomas Veerman
openfile(int a,const char * us,int * pnewflag)17605ea9e707SThomas Veerman FILE *openfile(int a, const char *us, int *pnewflag)
17615ea9e707SThomas Veerman {
17625ea9e707SThomas Veerman const char *s = us;
17635ea9e707SThomas Veerman size_t i;
17645ea9e707SThomas Veerman int m;
17655ea9e707SThomas Veerman FILE *fp = 0;
17665ea9e707SThomas Veerman
17675ea9e707SThomas Veerman if (*s == '\0')
17685ea9e707SThomas Veerman FATAL("null file name in print or getline");
17695ea9e707SThomas Veerman for (i = 0; i < nfiles; i++)
17705ea9e707SThomas Veerman if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
17715ea9e707SThomas Veerman (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
17725ea9e707SThomas Veerman a == FFLUSH)) {
17735ea9e707SThomas Veerman if (pnewflag)
17745ea9e707SThomas Veerman *pnewflag = 0;
17755ea9e707SThomas Veerman return files[i].fp;
17765ea9e707SThomas Veerman }
17775ea9e707SThomas Veerman if (a == FFLUSH) /* didn't find it, so don't create it! */
17785ea9e707SThomas Veerman return NULL;
17795ea9e707SThomas Veerman
17805ea9e707SThomas Veerman for (i = 0; i < nfiles; i++)
17815ea9e707SThomas Veerman if (files[i].fp == NULL)
17825ea9e707SThomas Veerman break;
17835ea9e707SThomas Veerman if (i >= nfiles) {
17845ea9e707SThomas Veerman struct files *nf;
17855ea9e707SThomas Veerman size_t nnf = nfiles + FOPEN_MAX;
17865ea9e707SThomas Veerman nf = realloc(files, nnf * sizeof(*nf));
17875ea9e707SThomas Veerman if (nf == NULL)
17885ea9e707SThomas Veerman FATAL("cannot grow files for %s and %zu files", s, nnf);
17895ea9e707SThomas Veerman (void)memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
17905ea9e707SThomas Veerman nfiles = nnf;
17915ea9e707SThomas Veerman files = nf;
17925ea9e707SThomas Veerman }
17935ea9e707SThomas Veerman fflush(stdout); /* force a semblance of order */
17945ea9e707SThomas Veerman m = a;
17955ea9e707SThomas Veerman if (a == GT) {
17965ea9e707SThomas Veerman fp = fopen(s, "w");
17975ea9e707SThomas Veerman } else if (a == APPEND) {
17985ea9e707SThomas Veerman fp = fopen(s, "a");
17995ea9e707SThomas Veerman m = GT; /* so can mix > and >> */
18005ea9e707SThomas Veerman } else if (a == '|') { /* output pipe */
18015ea9e707SThomas Veerman fp = popen(s, "w");
18025ea9e707SThomas Veerman } else if (a == LE) { /* input pipe */
18035ea9e707SThomas Veerman fp = popen(s, "r");
18045ea9e707SThomas Veerman } else if (a == LT) { /* getline <file */
18055ea9e707SThomas Veerman fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
18065ea9e707SThomas Veerman } else /* can't happen */
18075ea9e707SThomas Veerman FATAL("illegal redirection %d", a);
18085ea9e707SThomas Veerman if (fp != NULL) {
18095ea9e707SThomas Veerman files[i].fname = tostring(s);
18105ea9e707SThomas Veerman files[i].fp = fp;
18115ea9e707SThomas Veerman files[i].mode = m;
18125ea9e707SThomas Veerman if (pnewflag)
18135ea9e707SThomas Veerman *pnewflag = 1;
18145ea9e707SThomas Veerman }
18155ea9e707SThomas Veerman return fp;
18165ea9e707SThomas Veerman }
18175ea9e707SThomas Veerman
filename(FILE * fp)18185ea9e707SThomas Veerman const char *filename(FILE *fp)
18195ea9e707SThomas Veerman {
18205ea9e707SThomas Veerman size_t i;
18215ea9e707SThomas Veerman
18225ea9e707SThomas Veerman for (i = 0; i < nfiles; i++)
18235ea9e707SThomas Veerman if (fp == files[i].fp)
18245ea9e707SThomas Veerman return files[i].fname;
18255ea9e707SThomas Veerman return "???";
18265ea9e707SThomas Veerman }
18275ea9e707SThomas Veerman
closefile(Node ** a,int n)18285ea9e707SThomas Veerman Cell *closefile(Node **a, int n)
18295ea9e707SThomas Veerman {
18305ea9e707SThomas Veerman Cell *x;
18315ea9e707SThomas Veerman size_t i;
18325ea9e707SThomas Veerman int stat;
18335ea9e707SThomas Veerman
18345ea9e707SThomas Veerman n = n;
18355ea9e707SThomas Veerman x = execute(a[0]);
18365ea9e707SThomas Veerman getsval(x);
18375ea9e707SThomas Veerman stat = -1;
18385ea9e707SThomas Veerman for (i = 0; i < nfiles; i++) {
18395ea9e707SThomas Veerman if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) {
18405ea9e707SThomas Veerman if (ferror(files[i].fp))
18415ea9e707SThomas Veerman WARNING( "i/o error occurred on %s", files[i].fname );
18425ea9e707SThomas Veerman if (files[i].mode == '|' || files[i].mode == LE)
18435ea9e707SThomas Veerman stat = pclose(files[i].fp) == -1;
18445ea9e707SThomas Veerman else
18455ea9e707SThomas Veerman stat = fclose(files[i].fp) == EOF;
18465ea9e707SThomas Veerman if (stat) {
18475ea9e707SThomas Veerman stat = -1;
18485ea9e707SThomas Veerman WARNING( "i/o error occurred closing %s",
18495ea9e707SThomas Veerman files[i].fname );
18505ea9e707SThomas Veerman }
18515ea9e707SThomas Veerman if (i > 2) /* don't do /dev/std... */
18525ea9e707SThomas Veerman free(__UNCONST(files[i].fname));
18535ea9e707SThomas Veerman files[i].fname = NULL; /* watch out for ref thru this */
18545ea9e707SThomas Veerman files[i].fp = NULL;
18555ea9e707SThomas Veerman }
18565ea9e707SThomas Veerman }
18575ea9e707SThomas Veerman tempfree(x);
18585ea9e707SThomas Veerman x = gettemp();
18595ea9e707SThomas Veerman setfval(x, (Awkfloat) stat);
18605ea9e707SThomas Veerman return(x);
18615ea9e707SThomas Veerman }
18625ea9e707SThomas Veerman
closeall(void)18635ea9e707SThomas Veerman void closeall(void)
18645ea9e707SThomas Veerman {
18655ea9e707SThomas Veerman size_t i;
18665ea9e707SThomas Veerman int stat;
18675ea9e707SThomas Veerman
18685ea9e707SThomas Veerman for (i = 0; i < nfiles; i++) {
18695ea9e707SThomas Veerman if (files[i].fp) {
18705ea9e707SThomas Veerman if (ferror(files[i].fp))
18715ea9e707SThomas Veerman WARNING( "i/o error occurred on %s", files[i].fname );
18725ea9e707SThomas Veerman if (i == 0)
18735ea9e707SThomas Veerman stat = fpurge(files[i].fp) == EOF;
18745ea9e707SThomas Veerman else if (i <= 2)
18755ea9e707SThomas Veerman stat = fflush(files[i].fp) == EOF;
18765ea9e707SThomas Veerman else if (files[i].mode == '|' || files[i].mode == LE)
18775ea9e707SThomas Veerman stat = pclose(files[i].fp) == -1;
18785ea9e707SThomas Veerman else
18795ea9e707SThomas Veerman stat = fclose(files[i].fp) == EOF;
18805ea9e707SThomas Veerman if (stat)
18815ea9e707SThomas Veerman WARNING( "i/o error occurred while closing %s", files[i].fname );
18825ea9e707SThomas Veerman }
18835ea9e707SThomas Veerman }
18845ea9e707SThomas Veerman }
18855ea9e707SThomas Veerman
flush_all(void)18865ea9e707SThomas Veerman void flush_all(void)
18875ea9e707SThomas Veerman {
18885ea9e707SThomas Veerman size_t i;
18895ea9e707SThomas Veerman
18905ea9e707SThomas Veerman for (i = 0; i < nfiles; i++)
18915ea9e707SThomas Veerman if (files[i].fp)
18925ea9e707SThomas Veerman fflush(files[i].fp);
18935ea9e707SThomas Veerman }
18945ea9e707SThomas Veerman
18955ea9e707SThomas Veerman void backsub(uschar **pb_ptr, const uschar **sptr_ptr);
18965ea9e707SThomas Veerman
sub(Node ** a,int nnn)18975ea9e707SThomas Veerman Cell *sub(Node **a, int nnn) /* substitute command */
18985ea9e707SThomas Veerman {
18995ea9e707SThomas Veerman const uschar *sptr;
19005ea9e707SThomas Veerman uschar *q;
19015ea9e707SThomas Veerman Cell *x, *y, *result;
19025ea9e707SThomas Veerman uschar *t, *buf, *pb;
19035ea9e707SThomas Veerman fa *pfa;
19045ea9e707SThomas Veerman int bufsz = recsize;
19055ea9e707SThomas Veerman
19065ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
19075ea9e707SThomas Veerman FATAL("out of memory in sub");
19085ea9e707SThomas Veerman x = execute(a[3]); /* target string */
19095ea9e707SThomas Veerman t = getsval(x);
19105ea9e707SThomas Veerman if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
19115ea9e707SThomas Veerman pfa = (fa *) a[1]; /* regular expression */
19125ea9e707SThomas Veerman else {
19135ea9e707SThomas Veerman y = execute(a[1]);
19145ea9e707SThomas Veerman pfa = makedfa(getsval(y), 1);
19155ea9e707SThomas Veerman tempfree(y);
19165ea9e707SThomas Veerman }
19175ea9e707SThomas Veerman y = execute(a[2]); /* replacement string */
19185ea9e707SThomas Veerman result = False;
19195ea9e707SThomas Veerman if (pmatch(pfa, t)) {
19205ea9e707SThomas Veerman sptr = t;
19215ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patbeg-sptr, recsize, 0, "sub");
19225ea9e707SThomas Veerman pb = buf;
19235ea9e707SThomas Veerman while (sptr < patbeg)
19245ea9e707SThomas Veerman *pb++ = *sptr++;
19255ea9e707SThomas Veerman sptr = getsval(y);
19265ea9e707SThomas Veerman while (*sptr != 0) {
19275ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "sub");
19285ea9e707SThomas Veerman if (*sptr == '\\') {
19295ea9e707SThomas Veerman backsub(&pb, &sptr);
19305ea9e707SThomas Veerman } else if (*sptr == '&') {
19315ea9e707SThomas Veerman sptr++;
19325ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "sub");
19335ea9e707SThomas Veerman for (q = patbeg; q < patbeg+patlen; )
19345ea9e707SThomas Veerman *pb++ = *q++;
19355ea9e707SThomas Veerman } else
19365ea9e707SThomas Veerman *pb++ = *sptr++;
19375ea9e707SThomas Veerman }
19385ea9e707SThomas Veerman *pb = '\0';
19395ea9e707SThomas Veerman if (pb > buf + bufsz)
19405ea9e707SThomas Veerman FATAL("sub result1 %.30s too big; can't happen", buf);
19415ea9e707SThomas Veerman sptr = patbeg + patlen;
19425ea9e707SThomas Veerman if ((patlen == 0 && *patbeg) || (patlen && *(sptr-1))) {
19435ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "sub");
19445ea9e707SThomas Veerman while ((*pb++ = *sptr++) != 0)
19455ea9e707SThomas Veerman ;
19465ea9e707SThomas Veerman }
19475ea9e707SThomas Veerman if (pb > buf + bufsz)
19485ea9e707SThomas Veerman FATAL("sub result2 %.30s too big; can't happen", buf);
19495ea9e707SThomas Veerman setsval(x, buf); /* BUG: should be able to avoid copy */
19505ea9e707SThomas Veerman result = True;;
19515ea9e707SThomas Veerman }
19525ea9e707SThomas Veerman tempfree(x);
19535ea9e707SThomas Veerman tempfree(y);
19545ea9e707SThomas Veerman free(buf);
19555ea9e707SThomas Veerman return result;
19565ea9e707SThomas Veerman }
19575ea9e707SThomas Veerman
gsub(Node ** a,int nnn)19585ea9e707SThomas Veerman Cell *gsub(Node **a, int nnn) /* global substitute */
19595ea9e707SThomas Veerman {
19605ea9e707SThomas Veerman Cell *x, *y;
19615ea9e707SThomas Veerman const char *rptr;
19625ea9e707SThomas Veerman const uschar *sptr;
19635ea9e707SThomas Veerman uschar *t, *q;
19645ea9e707SThomas Veerman uschar *pb, *buf;
19655ea9e707SThomas Veerman fa *pfa;
19665ea9e707SThomas Veerman int mflag, tempstat, num;
19675ea9e707SThomas Veerman int bufsz = recsize;
19685ea9e707SThomas Veerman
19695ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
19705ea9e707SThomas Veerman FATAL("out of memory in gsub");
19715ea9e707SThomas Veerman mflag = 0; /* if mflag == 0, can replace empty string */
19725ea9e707SThomas Veerman num = 0;
19735ea9e707SThomas Veerman x = execute(a[3]); /* target string */
19745ea9e707SThomas Veerman t = getsval(x);
19755ea9e707SThomas Veerman if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
19765ea9e707SThomas Veerman pfa = (fa *) a[1]; /* regular expression */
19775ea9e707SThomas Veerman else {
19785ea9e707SThomas Veerman y = execute(a[1]);
19795ea9e707SThomas Veerman pfa = makedfa(getsval(y), 1);
19805ea9e707SThomas Veerman tempfree(y);
19815ea9e707SThomas Veerman }
19825ea9e707SThomas Veerman y = execute(a[2]); /* replacement string */
19835ea9e707SThomas Veerman if (pmatch(pfa, t)) {
19845ea9e707SThomas Veerman tempstat = pfa->initstat;
19855ea9e707SThomas Veerman pfa->initstat = 2;
19865ea9e707SThomas Veerman pb = buf;
19875ea9e707SThomas Veerman rptr = getsval(y);
19885ea9e707SThomas Veerman do {
19895ea9e707SThomas Veerman if (patlen == 0 && *patbeg != 0) { /* matched empty string */
19905ea9e707SThomas Veerman if (mflag == 0) { /* can replace empty */
19915ea9e707SThomas Veerman num++;
19925ea9e707SThomas Veerman sptr = rptr;
19935ea9e707SThomas Veerman while (*sptr != 0) {
19945ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
19955ea9e707SThomas Veerman if (*sptr == '\\') {
19965ea9e707SThomas Veerman backsub(&pb, &sptr);
19975ea9e707SThomas Veerman } else if (*sptr == '&') {
19985ea9e707SThomas Veerman sptr++;
19995ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
20005ea9e707SThomas Veerman for (q = patbeg; q < patbeg+patlen; )
20015ea9e707SThomas Veerman *pb++ = *q++;
20025ea9e707SThomas Veerman } else
20035ea9e707SThomas Veerman *pb++ = *sptr++;
20045ea9e707SThomas Veerman }
20055ea9e707SThomas Veerman }
20065ea9e707SThomas Veerman if (*t == 0) /* at end */
20075ea9e707SThomas Veerman goto done;
20085ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gsub");
20095ea9e707SThomas Veerman *pb++ = *t++;
20105ea9e707SThomas Veerman if (pb > buf + bufsz) /* BUG: not sure of this test */
20115ea9e707SThomas Veerman FATAL("gsub result0 %.30s too big; can't happen", buf);
20125ea9e707SThomas Veerman mflag = 0;
20135ea9e707SThomas Veerman }
20145ea9e707SThomas Veerman else { /* matched nonempty string */
20155ea9e707SThomas Veerman num++;
20165ea9e707SThomas Veerman sptr = t;
20175ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gsub");
20185ea9e707SThomas Veerman while (sptr < patbeg)
20195ea9e707SThomas Veerman *pb++ = *sptr++;
20205ea9e707SThomas Veerman sptr = rptr;
20215ea9e707SThomas Veerman while (*sptr != 0) {
20225ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gsub");
20235ea9e707SThomas Veerman if (*sptr == '\\') {
20245ea9e707SThomas Veerman backsub(&pb, &sptr);
20255ea9e707SThomas Veerman } else if (*sptr == '&') {
20265ea9e707SThomas Veerman sptr++;
20275ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gsub");
20285ea9e707SThomas Veerman for (q = patbeg; q < patbeg+patlen; )
20295ea9e707SThomas Veerman *pb++ = *q++;
20305ea9e707SThomas Veerman } else
20315ea9e707SThomas Veerman *pb++ = *sptr++;
20325ea9e707SThomas Veerman }
20335ea9e707SThomas Veerman t = patbeg + patlen;
20345ea9e707SThomas Veerman if (patlen == 0 || *t == 0 || *(t-1) == 0)
20355ea9e707SThomas Veerman goto done;
20365ea9e707SThomas Veerman if (pb > buf + bufsz)
20375ea9e707SThomas Veerman FATAL("gsub result1 %.30s too big; can't happen", buf);
20385ea9e707SThomas Veerman mflag = 1;
20395ea9e707SThomas Veerman }
20405ea9e707SThomas Veerman } while (pmatch(pfa,t));
20415ea9e707SThomas Veerman sptr = t;
20425ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub");
20435ea9e707SThomas Veerman while ((*pb++ = *sptr++) != 0)
20445ea9e707SThomas Veerman ;
20455ea9e707SThomas Veerman done: if (pb < buf + bufsz)
20465ea9e707SThomas Veerman *pb = '\0';
20475ea9e707SThomas Veerman else if (*(pb-1) != '\0')
20485ea9e707SThomas Veerman FATAL("gsub result2 %.30s truncated; can't happen", buf);
20495ea9e707SThomas Veerman setsval(x, buf); /* BUG: should be able to avoid copy + free */
20505ea9e707SThomas Veerman pfa->initstat = tempstat;
20515ea9e707SThomas Veerman }
20525ea9e707SThomas Veerman tempfree(x);
20535ea9e707SThomas Veerman tempfree(y);
20545ea9e707SThomas Veerman x = gettemp();
20555ea9e707SThomas Veerman x->tval = NUM;
20565ea9e707SThomas Veerman x->fval = num;
20575ea9e707SThomas Veerman free(buf);
20585ea9e707SThomas Veerman return(x);
20595ea9e707SThomas Veerman }
20605ea9e707SThomas Veerman
gensub(Node ** a,int nnn)20615ea9e707SThomas Veerman Cell *gensub(Node **a, int nnn) /* global selective substitute */
20625ea9e707SThomas Veerman /* XXX incomplete - doesn't support backreferences \0 ... \9 */
20635ea9e707SThomas Veerman {
20645ea9e707SThomas Veerman Cell *x, *y, *res, *h;
20655ea9e707SThomas Veerman char *rptr;
20665ea9e707SThomas Veerman const uschar *sptr;
20675ea9e707SThomas Veerman uschar *q, *pb, *t, *buf;
20685ea9e707SThomas Veerman fa *pfa;
20695ea9e707SThomas Veerman int mflag, tempstat, num, whichm;
20705ea9e707SThomas Veerman int bufsz = recsize;
20715ea9e707SThomas Veerman
20725ea9e707SThomas Veerman if ((buf = malloc(bufsz)) == NULL)
20735ea9e707SThomas Veerman FATAL("out of memory in gensub");
20745ea9e707SThomas Veerman mflag = 0; /* if mflag == 0, can replace empty string */
20755ea9e707SThomas Veerman num = 0;
20765ea9e707SThomas Veerman x = execute(a[4]); /* source string */
20775ea9e707SThomas Veerman t = getsval(x);
20785ea9e707SThomas Veerman res = copycell(x); /* target string - initially copy of source */
207984d9c625SLionel Sambuc res->csub = CTEMP; /* result values are temporary */
20805ea9e707SThomas Veerman if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */
20815ea9e707SThomas Veerman pfa = (fa *) a[1]; /* regular expression */
20825ea9e707SThomas Veerman else {
20835ea9e707SThomas Veerman y = execute(a[1]);
20845ea9e707SThomas Veerman pfa = makedfa(getsval(y), 1);
20855ea9e707SThomas Veerman tempfree(y);
20865ea9e707SThomas Veerman }
20875ea9e707SThomas Veerman y = execute(a[2]); /* replacement string */
20885ea9e707SThomas Veerman h = execute(a[3]); /* which matches should be replaced */
20895ea9e707SThomas Veerman sptr = getsval(h);
20905ea9e707SThomas Veerman if (sptr[0] == 'g' || sptr[0] == 'G')
20915ea9e707SThomas Veerman whichm = -1;
20925ea9e707SThomas Veerman else {
20935ea9e707SThomas Veerman /*
20945ea9e707SThomas Veerman * The specified number is index of replacement, starting
20955ea9e707SThomas Veerman * from 1. GNU awk treats index lower than 0 same as
20965ea9e707SThomas Veerman * 1, we do same for compatibility.
20975ea9e707SThomas Veerman */
20985ea9e707SThomas Veerman whichm = (int) getfval(h) - 1;
20995ea9e707SThomas Veerman if (whichm < 0)
21005ea9e707SThomas Veerman whichm = 0;
21015ea9e707SThomas Veerman }
21025ea9e707SThomas Veerman tempfree(h);
21035ea9e707SThomas Veerman
21045ea9e707SThomas Veerman if (pmatch(pfa, t)) {
21055ea9e707SThomas Veerman char *sl;
21065ea9e707SThomas Veerman
21075ea9e707SThomas Veerman tempstat = pfa->initstat;
21085ea9e707SThomas Veerman pfa->initstat = 2;
21095ea9e707SThomas Veerman pb = buf;
21105ea9e707SThomas Veerman rptr = getsval(y);
21115ea9e707SThomas Veerman /*
21125ea9e707SThomas Veerman * XXX if there are any backreferences in subst string,
21135ea9e707SThomas Veerman * complain now.
21145ea9e707SThomas Veerman */
21155ea9e707SThomas Veerman for(sl=rptr; (sl = strchr(sl, '\\')) && sl[1]; sl++) {
21165ea9e707SThomas Veerman if (strchr("0123456789", sl[1])) {
21175ea9e707SThomas Veerman FATAL("gensub doesn't support backreferences (subst \"%s\")", rptr);
21185ea9e707SThomas Veerman }
21195ea9e707SThomas Veerman }
21205ea9e707SThomas Veerman
21215ea9e707SThomas Veerman do {
21225ea9e707SThomas Veerman if (whichm >= 0 && whichm != num) {
21235ea9e707SThomas Veerman num++;
21245ea9e707SThomas Veerman adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - t) + patlen, recsize, &pb, "gensub");
21255ea9e707SThomas Veerman
21265ea9e707SThomas Veerman /* copy the part of string up to and including
21275ea9e707SThomas Veerman * match to output buffer */
21285ea9e707SThomas Veerman while (t < patbeg + patlen)
21295ea9e707SThomas Veerman *pb++ = *t++;
21305ea9e707SThomas Veerman continue;
21315ea9e707SThomas Veerman }
21325ea9e707SThomas Veerman
21335ea9e707SThomas Veerman if (patlen == 0 && *patbeg != 0) { /* matched empty string */
21345ea9e707SThomas Veerman if (mflag == 0) { /* can replace empty */
21355ea9e707SThomas Veerman num++;
21365ea9e707SThomas Veerman sptr = rptr;
21375ea9e707SThomas Veerman while (*sptr != 0) {
21385ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
21395ea9e707SThomas Veerman if (*sptr == '\\') {
21405ea9e707SThomas Veerman backsub(&pb, &sptr);
21415ea9e707SThomas Veerman } else if (*sptr == '&') {
21425ea9e707SThomas Veerman sptr++;
21435ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
21445ea9e707SThomas Veerman for (q = patbeg; q < patbeg+patlen; )
21455ea9e707SThomas Veerman *pb++ = *q++;
21465ea9e707SThomas Veerman } else
21475ea9e707SThomas Veerman *pb++ = *sptr++;
21485ea9e707SThomas Veerman }
21495ea9e707SThomas Veerman }
21505ea9e707SThomas Veerman if (*t == 0) /* at end */
21515ea9e707SThomas Veerman goto done;
21525ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gensub");
21535ea9e707SThomas Veerman *pb++ = *t++;
21545ea9e707SThomas Veerman if (pb > buf + bufsz) /* BUG: not sure of this test */
21555ea9e707SThomas Veerman FATAL("gensub result0 %.30s too big; can't happen", buf);
21565ea9e707SThomas Veerman mflag = 0;
21575ea9e707SThomas Veerman }
21585ea9e707SThomas Veerman else { /* matched nonempty string */
21595ea9e707SThomas Veerman num++;
21605ea9e707SThomas Veerman sptr = t;
21615ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gensub");
21625ea9e707SThomas Veerman while (sptr < patbeg)
21635ea9e707SThomas Veerman *pb++ = *sptr++;
21645ea9e707SThomas Veerman sptr = rptr;
21655ea9e707SThomas Veerman while (*sptr != 0) {
21665ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub");
21675ea9e707SThomas Veerman if (*sptr == '\\') {
21685ea9e707SThomas Veerman backsub(&pb, &sptr);
21695ea9e707SThomas Veerman } else if (*sptr == '&') {
21705ea9e707SThomas Veerman sptr++;
21715ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub");
21725ea9e707SThomas Veerman for (q = patbeg; q < patbeg+patlen; )
21735ea9e707SThomas Veerman *pb++ = *q++;
21745ea9e707SThomas Veerman } else
21755ea9e707SThomas Veerman *pb++ = *sptr++;
21765ea9e707SThomas Veerman }
21775ea9e707SThomas Veerman t = patbeg + patlen;
21785ea9e707SThomas Veerman if (patlen == 0 || *t == 0 || *(t-1) == 0)
21795ea9e707SThomas Veerman goto done;
21805ea9e707SThomas Veerman if (pb > buf + bufsz)
21815ea9e707SThomas Veerman FATAL("gensub result1 %.30s too big; can't happen", buf);
21825ea9e707SThomas Veerman mflag = 1;
21835ea9e707SThomas Veerman }
21845ea9e707SThomas Veerman } while (pmatch(pfa,t));
21855ea9e707SThomas Veerman sptr = t;
21865ea9e707SThomas Veerman adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gensub");
21875ea9e707SThomas Veerman while ((*pb++ = *sptr++) != 0)
21885ea9e707SThomas Veerman ;
21895ea9e707SThomas Veerman done: if (pb > buf + bufsz)
21905ea9e707SThomas Veerman FATAL("gensub result2 %.30s too big; can't happen", buf);
21915ea9e707SThomas Veerman *pb = '\0';
21925ea9e707SThomas Veerman setsval(res, buf);
21935ea9e707SThomas Veerman pfa->initstat = tempstat;
21945ea9e707SThomas Veerman }
21955ea9e707SThomas Veerman tempfree(x);
21965ea9e707SThomas Veerman tempfree(y);
21975ea9e707SThomas Veerman free(buf);
21985ea9e707SThomas Veerman return(res);
21995ea9e707SThomas Veerman }
22005ea9e707SThomas Veerman
backsub(uschar ** pb_ptr,const uschar ** sptr_ptr)22015ea9e707SThomas Veerman void backsub(uschar **pb_ptr, const uschar **sptr_ptr)/* handle \\& variations */
22025ea9e707SThomas Veerman { /* sptr[0] == '\\' */
22035ea9e707SThomas Veerman uschar *pb = *pb_ptr;
22045ea9e707SThomas Veerman const uschar *sptr = *sptr_ptr;
22055ea9e707SThomas Veerman
22065ea9e707SThomas Veerman if (sptr[1] == '\\') {
22075ea9e707SThomas Veerman if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
22085ea9e707SThomas Veerman *pb++ = '\\';
22095ea9e707SThomas Veerman *pb++ = '&';
22105ea9e707SThomas Veerman sptr += 4;
22115ea9e707SThomas Veerman } else if (sptr[2] == '&') { /* \\& -> \ + matched */
22125ea9e707SThomas Veerman *pb++ = '\\';
22135ea9e707SThomas Veerman sptr += 2;
22145ea9e707SThomas Veerman } else { /* \\x -> \\x */
22155ea9e707SThomas Veerman *pb++ = *sptr++;
22165ea9e707SThomas Veerman *pb++ = *sptr++;
22175ea9e707SThomas Veerman }
22185ea9e707SThomas Veerman } else if (sptr[1] == '&') { /* literal & */
22195ea9e707SThomas Veerman sptr++;
22205ea9e707SThomas Veerman *pb++ = *sptr++;
22215ea9e707SThomas Veerman } else /* literal \ */
22225ea9e707SThomas Veerman *pb++ = *sptr++;
22235ea9e707SThomas Veerman
22245ea9e707SThomas Veerman *pb_ptr = pb;
22255ea9e707SThomas Veerman *sptr_ptr = sptr;
22265ea9e707SThomas Veerman }
2227