14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos
254b588458SPeter Avalos #define DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <ctype.h>
281d48fce0SDaniel Fojt #include <errno.h>
291d48fce0SDaniel Fojt #include <wctype.h>
301d48fce0SDaniel Fojt #include <fcntl.h>
314b588458SPeter Avalos #include <setjmp.h>
324b588458SPeter Avalos #include <limits.h>
334b588458SPeter Avalos #include <math.h>
344b588458SPeter Avalos #include <string.h>
354b588458SPeter Avalos #include <stdlib.h>
364b588458SPeter Avalos #include <time.h>
371d48fce0SDaniel Fojt #include <sys/types.h>
381d48fce0SDaniel Fojt #include <sys/wait.h>
394b588458SPeter Avalos #include "awk.h"
4048f09a05SAntonio Huete Jimenez #include "awkgram.tab.h"
414b588458SPeter Avalos
42*ed569bc2SAaron LI
431d48fce0SDaniel Fojt static void stdinit(void);
441d48fce0SDaniel Fojt static void flush_all(void);
45*ed569bc2SAaron LI static char *wide_char_to_byte_str(int rune, size_t *outlen);
464b588458SPeter Avalos
471d48fce0SDaniel Fojt #if 1
481d48fce0SDaniel Fojt #define tempfree(x) do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0)
491d48fce0SDaniel Fojt #else
tempfree(Cell * p)504b588458SPeter Avalos void tempfree(Cell *p) {
514b588458SPeter Avalos if (p->ctype == OCELL && (p->csub < CUNK || p->csub > CFREE)) {
524b588458SPeter Avalos WARNING("bad csub %d in Cell %d %s",
534b588458SPeter Avalos p->csub, p->ctype, p->sval);
544b588458SPeter Avalos }
554b588458SPeter Avalos if (istemp(p))
564b588458SPeter Avalos tfree(p);
574b588458SPeter Avalos }
581d48fce0SDaniel Fojt #endif
594b588458SPeter Avalos
604b588458SPeter Avalos /* do we really need these? */
614b588458SPeter Avalos /* #ifdef _NFILE */
624b588458SPeter Avalos /* #ifndef FOPEN_MAX */
634b588458SPeter Avalos /* #define FOPEN_MAX _NFILE */
644b588458SPeter Avalos /* #endif */
654b588458SPeter Avalos /* #endif */
664b588458SPeter Avalos /* */
674b588458SPeter Avalos /* #ifndef FOPEN_MAX */
684b588458SPeter Avalos /* #define FOPEN_MAX 40 */ /* max number of open files */
694b588458SPeter Avalos /* #endif */
704b588458SPeter Avalos /* */
714b588458SPeter Avalos /* #ifndef RAND_MAX */
724b588458SPeter Avalos /* #define RAND_MAX 32767 */ /* all that ansi guarantees */
734b588458SPeter Avalos /* #endif */
744b588458SPeter Avalos
754b588458SPeter Avalos jmp_buf env;
764b588458SPeter Avalos extern int pairstack[];
770020174dSPeter Avalos extern Awkfloat srand_seed;
784b588458SPeter Avalos
794b588458SPeter Avalos Node *winner = NULL; /* root of parse tree */
804b588458SPeter Avalos Cell *tmps; /* free temporary cells for execution */
814b588458SPeter Avalos
821d48fce0SDaniel Fojt static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL, NULL };
834b588458SPeter Avalos Cell *True = &truecell;
841d48fce0SDaniel Fojt static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL, NULL };
854b588458SPeter Avalos Cell *False = &falsecell;
861d48fce0SDaniel Fojt static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL, NULL };
874b588458SPeter Avalos Cell *jbreak = &breakcell;
881d48fce0SDaniel Fojt static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL, NULL };
894b588458SPeter Avalos Cell *jcont = &contcell;
901d48fce0SDaniel Fojt static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL, NULL };
914b588458SPeter Avalos Cell *jnext = &nextcell;
921d48fce0SDaniel Fojt static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL, NULL };
934b588458SPeter Avalos Cell *jnextfile = &nextfilecell;
941d48fce0SDaniel Fojt static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL, NULL };
954b588458SPeter Avalos Cell *jexit = &exitcell;
961d48fce0SDaniel Fojt static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL, NULL };
974b588458SPeter Avalos Cell *jret = &retcell;
981d48fce0SDaniel Fojt static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
994b588458SPeter Avalos
1004b588458SPeter Avalos Node *curnode = NULL; /* the node being executed, for debugging */
1014b588458SPeter Avalos
1024b588458SPeter Avalos /* buffer memory management */
adjbuf(char ** pbuf,int * psiz,int minlen,int quantum,char ** pbptr,const char * whatrtn)1034b588458SPeter Avalos int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
1044b588458SPeter Avalos const char *whatrtn)
1054b588458SPeter Avalos /* pbuf: address of pointer to buffer being managed
1064b588458SPeter Avalos * psiz: address of buffer size variable
1074b588458SPeter Avalos * minlen: minimum length of buffer needed
1084b588458SPeter Avalos * quantum: buffer size quantum
1094b588458SPeter Avalos * pbptr: address of movable pointer into buffer, or 0 if none
1104b588458SPeter Avalos * whatrtn: name of the calling routine if failure should cause fatal error
1114b588458SPeter Avalos *
1124b588458SPeter Avalos * return 0 for realloc failure, !=0 for success
1134b588458SPeter Avalos */
1144b588458SPeter Avalos {
1154b588458SPeter Avalos if (minlen > *psiz) {
1164b588458SPeter Avalos char *tbuf;
1174b588458SPeter Avalos int rminlen = quantum ? minlen % quantum : 0;
1184b588458SPeter Avalos int boff = pbptr ? *pbptr - *pbuf : 0;
1194b588458SPeter Avalos /* round up to next multiple of quantum */
1204b588458SPeter Avalos if (rminlen)
1214b588458SPeter Avalos minlen += quantum - rminlen;
12248f09a05SAntonio Huete Jimenez tbuf = (char *) realloc(*pbuf, minlen);
12348f09a05SAntonio Huete Jimenez DPRINTF("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, (void*)*pbuf, (void*)tbuf);
1244b588458SPeter Avalos if (tbuf == NULL) {
1254b588458SPeter Avalos if (whatrtn)
1264b588458SPeter Avalos FATAL("out of memory in %s", whatrtn);
1274b588458SPeter Avalos return 0;
1284b588458SPeter Avalos }
1294b588458SPeter Avalos *pbuf = tbuf;
1304b588458SPeter Avalos *psiz = minlen;
1314b588458SPeter Avalos if (pbptr)
1324b588458SPeter Avalos *pbptr = tbuf + boff;
1334b588458SPeter Avalos }
1344b588458SPeter Avalos return 1;
1354b588458SPeter Avalos }
1364b588458SPeter Avalos
run(Node * a)1374b588458SPeter Avalos void run(Node *a) /* execution of parse tree starts here */
1384b588458SPeter Avalos {
1394b588458SPeter Avalos
1404b588458SPeter Avalos stdinit();
1414b588458SPeter Avalos execute(a);
1424b588458SPeter Avalos closeall();
1434b588458SPeter Avalos }
1444b588458SPeter Avalos
execute(Node * u)1454b588458SPeter Avalos Cell *execute(Node *u) /* execute a node of the parse tree */
1464b588458SPeter Avalos {
1474b588458SPeter Avalos Cell *(*proc)(Node **, int);
1484b588458SPeter Avalos Cell *x;
1494b588458SPeter Avalos Node *a;
1504b588458SPeter Avalos
1514b588458SPeter Avalos if (u == NULL)
1524b588458SPeter Avalos return(True);
1534b588458SPeter Avalos for (a = u; ; a = a->nnext) {
1544b588458SPeter Avalos curnode = a;
1554b588458SPeter Avalos if (isvalue(a)) {
1564b588458SPeter Avalos x = (Cell *) (a->narg[0]);
1574b588458SPeter Avalos if (isfld(x) && !donefld)
1584b588458SPeter Avalos fldbld();
1594b588458SPeter Avalos else if (isrec(x) && !donerec)
1604b588458SPeter Avalos recbld();
1614b588458SPeter Avalos return(x);
1624b588458SPeter Avalos }
1634b588458SPeter Avalos if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
1644b588458SPeter Avalos FATAL("illegal statement");
1654b588458SPeter Avalos proc = proctab[a->nobj-FIRSTTOKEN];
1664b588458SPeter Avalos x = (*proc)(a->narg, a->nobj);
1674b588458SPeter Avalos if (isfld(x) && !donefld)
1684b588458SPeter Avalos fldbld();
1694b588458SPeter Avalos else if (isrec(x) && !donerec)
1704b588458SPeter Avalos recbld();
1714b588458SPeter Avalos if (isexpr(a))
1724b588458SPeter Avalos return(x);
1734b588458SPeter Avalos if (isjump(x))
1744b588458SPeter Avalos return(x);
1754b588458SPeter Avalos if (a->nnext == NULL)
1764b588458SPeter Avalos return(x);
1774b588458SPeter Avalos tempfree(x);
1784b588458SPeter Avalos }
1794b588458SPeter Avalos }
1804b588458SPeter Avalos
1814b588458SPeter Avalos
program(Node ** a,int n)1824b588458SPeter Avalos Cell *program(Node **a, int n) /* execute an awk program */
1834b588458SPeter Avalos { /* a[0] = BEGIN, a[1] = body, a[2] = END */
1844b588458SPeter Avalos Cell *x;
1854b588458SPeter Avalos
1864b588458SPeter Avalos if (setjmp(env) != 0)
1874b588458SPeter Avalos goto ex;
1884b588458SPeter Avalos if (a[0]) { /* BEGIN */
1894b588458SPeter Avalos x = execute(a[0]);
1904b588458SPeter Avalos if (isexit(x))
1914b588458SPeter Avalos return(True);
1924b588458SPeter Avalos if (isjump(x))
1934b588458SPeter Avalos FATAL("illegal break, continue, next or nextfile from BEGIN");
1944b588458SPeter Avalos tempfree(x);
1954b588458SPeter Avalos }
1964b588458SPeter Avalos if (a[1] || a[2])
1971d48fce0SDaniel Fojt while (getrec(&record, &recsize, true) > 0) {
1984b588458SPeter Avalos x = execute(a[1]);
1994b588458SPeter Avalos if (isexit(x))
2004b588458SPeter Avalos break;
2014b588458SPeter Avalos tempfree(x);
2024b588458SPeter Avalos }
2034b588458SPeter Avalos ex:
2044b588458SPeter Avalos if (setjmp(env) != 0) /* handles exit within END */
2054b588458SPeter Avalos goto ex1;
2064b588458SPeter Avalos if (a[2]) { /* END */
2074b588458SPeter Avalos x = execute(a[2]);
2084b588458SPeter Avalos if (isbreak(x) || isnext(x) || iscont(x))
2094b588458SPeter Avalos FATAL("illegal break, continue, next or nextfile from END");
2104b588458SPeter Avalos tempfree(x);
2114b588458SPeter Avalos }
2124b588458SPeter Avalos ex1:
2134b588458SPeter Avalos return(True);
2144b588458SPeter Avalos }
2154b588458SPeter Avalos
2164b588458SPeter Avalos struct Frame { /* stack frame for awk function calls */
2174b588458SPeter Avalos int nargs; /* number of arguments in this call */
2184b588458SPeter Avalos Cell *fcncell; /* pointer to Cell for function */
2194b588458SPeter Avalos Cell **args; /* pointer to array of arguments after execute */
2204b588458SPeter Avalos Cell *retval; /* return value */
2214b588458SPeter Avalos };
2224b588458SPeter Avalos
2234b588458SPeter Avalos #define NARGS 50 /* max args in a call */
2244b588458SPeter Avalos
2254b588458SPeter Avalos struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */
2264b588458SPeter Avalos int nframe = 0; /* number of frames allocated */
2271d48fce0SDaniel Fojt struct Frame *frp = NULL; /* frame pointer. bottom level unused */
2284b588458SPeter Avalos
call(Node ** a,int n)2294b588458SPeter Avalos Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
2304b588458SPeter Avalos {
2311d48fce0SDaniel Fojt static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL, NULL };
2324b588458SPeter Avalos int i, ncall, ndef;
2334b588458SPeter Avalos int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */
2344b588458SPeter Avalos Node *x;
2354b588458SPeter Avalos Cell *args[NARGS], *oargs[NARGS]; /* BUG: fixed size arrays */
2364b588458SPeter Avalos Cell *y, *z, *fcn;
2374b588458SPeter Avalos char *s;
2384b588458SPeter Avalos
2394b588458SPeter Avalos fcn = execute(a[0]); /* the function itself */
2404b588458SPeter Avalos s = fcn->nval;
2414b588458SPeter Avalos if (!isfcn(fcn))
2424b588458SPeter Avalos FATAL("calling undefined function %s", s);
2434b588458SPeter Avalos if (frame == NULL) {
24448f09a05SAntonio Huete Jimenez frp = frame = (struct Frame *) calloc(nframe += 100, sizeof(*frame));
2454b588458SPeter Avalos if (frame == NULL)
2464b588458SPeter Avalos FATAL("out of space for stack frames calling %s", s);
2474b588458SPeter Avalos }
2484b588458SPeter Avalos for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */
2494b588458SPeter Avalos ncall++;
2504b588458SPeter Avalos ndef = (int) fcn->fval; /* args in defn */
251e5e686a0SDaniel Fojt DPRINTF("calling %s, %d args (%d in defn), frp=%d\n", s, ncall, ndef, (int) (frp-frame));
2524b588458SPeter Avalos if (ncall > ndef)
2534b588458SPeter Avalos WARNING("function %s called with %d args, uses only %d",
2544b588458SPeter Avalos s, ncall, ndef);
2554b588458SPeter Avalos if (ncall + ndef > NARGS)
2564b588458SPeter Avalos FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS);
2574b588458SPeter Avalos for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */
258e5e686a0SDaniel Fojt DPRINTF("evaluate args[%d], frp=%d:\n", i, (int) (frp-frame));
2594b588458SPeter Avalos y = execute(x);
2604b588458SPeter Avalos oargs[i] = y;
261e5e686a0SDaniel Fojt DPRINTF("args[%d]: %s %f <%s>, t=%o\n",
262e5e686a0SDaniel Fojt i, NN(y->nval), y->fval, isarr(y) ? "(array)" : NN(y->sval), y->tval);
2634b588458SPeter Avalos if (isfcn(y))
2644b588458SPeter Avalos FATAL("can't use function %s as argument in %s", y->nval, s);
2654b588458SPeter Avalos if (isarr(y))
2664b588458SPeter Avalos args[i] = y; /* arrays by ref */
2674b588458SPeter Avalos else
2684b588458SPeter Avalos args[i] = copycell(y);
2694b588458SPeter Avalos tempfree(y);
2704b588458SPeter Avalos }
2714b588458SPeter Avalos for ( ; i < ndef; i++) { /* add null args for ones not provided */
2724b588458SPeter Avalos args[i] = gettemp();
2734b588458SPeter Avalos *args[i] = newcopycell;
2744b588458SPeter Avalos }
2751d48fce0SDaniel Fojt frp++; /* now ok to up frame */
2761d48fce0SDaniel Fojt if (frp >= frame + nframe) {
2771d48fce0SDaniel Fojt int dfp = frp - frame; /* old index */
27848f09a05SAntonio Huete Jimenez frame = (struct Frame *) realloc(frame, (nframe += 100) * sizeof(*frame));
2794b588458SPeter Avalos if (frame == NULL)
2804b588458SPeter Avalos FATAL("out of space for stack frames in %s", s);
2811d48fce0SDaniel Fojt frp = frame + dfp;
2824b588458SPeter Avalos }
2831d48fce0SDaniel Fojt frp->fcncell = fcn;
2841d48fce0SDaniel Fojt frp->args = args;
2851d48fce0SDaniel Fojt frp->nargs = ndef; /* number defined with (excess are locals) */
2861d48fce0SDaniel Fojt frp->retval = gettemp();
2874b588458SPeter Avalos
288e5e686a0SDaniel Fojt DPRINTF("start exec of %s, frp=%d\n", s, (int) (frp-frame));
2894b588458SPeter Avalos y = execute((Node *)(fcn->sval)); /* execute body */
290e5e686a0SDaniel Fojt DPRINTF("finished exec of %s, frp=%d\n", s, (int) (frp-frame));
2914b588458SPeter Avalos
2924b588458SPeter Avalos for (i = 0; i < ndef; i++) {
2931d48fce0SDaniel Fojt Cell *t = frp->args[i];
2944b588458SPeter Avalos if (isarr(t)) {
2954b588458SPeter Avalos if (t->csub == CCOPY) {
2964b588458SPeter Avalos if (i >= ncall) {
2974b588458SPeter Avalos freesymtab(t);
2984b588458SPeter Avalos t->csub = CTEMP;
2994b588458SPeter Avalos tempfree(t);
3004b588458SPeter Avalos } else {
3014b588458SPeter Avalos oargs[i]->tval = t->tval;
3024b588458SPeter Avalos oargs[i]->tval &= ~(STR|NUM|DONTFREE);
3034b588458SPeter Avalos oargs[i]->sval = t->sval;
3044b588458SPeter Avalos tempfree(t);
3054b588458SPeter Avalos }
3064b588458SPeter Avalos }
3074b588458SPeter Avalos } else if (t != y) { /* kludge to prevent freeing twice */
3084b588458SPeter Avalos t->csub = CTEMP;
3094b588458SPeter Avalos tempfree(t);
3104b588458SPeter Avalos } else if (t == y && t->csub == CCOPY) {
3114b588458SPeter Avalos t->csub = CTEMP;
3124b588458SPeter Avalos tempfree(t);
3134b588458SPeter Avalos freed = 1;
3144b588458SPeter Avalos }
3154b588458SPeter Avalos }
3164b588458SPeter Avalos tempfree(fcn);
3174b588458SPeter Avalos if (isexit(y) || isnext(y))
3184b588458SPeter Avalos return y;
3194b588458SPeter Avalos if (freed == 0) {
3204b588458SPeter Avalos tempfree(y); /* don't free twice! */
3214b588458SPeter Avalos }
3221d48fce0SDaniel Fojt z = frp->retval; /* return value */
323e5e686a0SDaniel Fojt DPRINTF("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval);
3241d48fce0SDaniel Fojt frp--;
3254b588458SPeter Avalos return(z);
3264b588458SPeter Avalos }
3274b588458SPeter Avalos
copycell(Cell * x)3284b588458SPeter Avalos Cell *copycell(Cell *x) /* make a copy of a cell in a temp */
3294b588458SPeter Avalos {
3304b588458SPeter Avalos Cell *y;
3314b588458SPeter Avalos
3321d48fce0SDaniel Fojt /* copy is not constant or field */
3331d48fce0SDaniel Fojt
3344b588458SPeter Avalos y = gettemp();
3351d48fce0SDaniel Fojt y->tval = x->tval & ~(CON|FLD|REC);
3364b588458SPeter Avalos y->csub = CCOPY; /* prevents freeing until call is over */
3374b588458SPeter Avalos y->nval = x->nval; /* BUG? */
3381d48fce0SDaniel Fojt if (isstr(x) /* || x->ctype == OCELL */) {
3394b588458SPeter Avalos y->sval = tostring(x->sval);
3401d48fce0SDaniel Fojt y->tval &= ~DONTFREE;
3411d48fce0SDaniel Fojt } else
3421d48fce0SDaniel Fojt y->tval |= DONTFREE;
3434b588458SPeter Avalos y->fval = x->fval;
3444b588458SPeter Avalos return y;
3454b588458SPeter Avalos }
3464b588458SPeter Avalos
arg(Node ** a,int n)3474b588458SPeter Avalos Cell *arg(Node **a, int n) /* nth argument of a function */
3484b588458SPeter Avalos {
3494b588458SPeter Avalos
3504b588458SPeter Avalos n = ptoi(a[0]); /* argument number, counting from 0 */
351e5e686a0SDaniel Fojt DPRINTF("arg(%d), frp->nargs=%d\n", n, frp->nargs);
3521d48fce0SDaniel Fojt if (n+1 > frp->nargs)
3534b588458SPeter Avalos FATAL("argument #%d of function %s was not supplied",
3541d48fce0SDaniel Fojt n+1, frp->fcncell->nval);
3551d48fce0SDaniel Fojt return frp->args[n];
3564b588458SPeter Avalos }
3574b588458SPeter Avalos
jump(Node ** a,int n)3584b588458SPeter Avalos Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */
3594b588458SPeter Avalos {
3604b588458SPeter Avalos Cell *y;
3614b588458SPeter Avalos
3624b588458SPeter Avalos switch (n) {
3634b588458SPeter Avalos case EXIT:
3644b588458SPeter Avalos if (a[0] != NULL) {
3654b588458SPeter Avalos y = execute(a[0]);
3664b588458SPeter Avalos errorflag = (int) getfval(y);
3674b588458SPeter Avalos tempfree(y);
3684b588458SPeter Avalos }
3694b588458SPeter Avalos longjmp(env, 1);
3704b588458SPeter Avalos case RETURN:
3714b588458SPeter Avalos if (a[0] != NULL) {
3724b588458SPeter Avalos y = execute(a[0]);
3734b588458SPeter Avalos if ((y->tval & (STR|NUM)) == (STR|NUM)) {
3741d48fce0SDaniel Fojt setsval(frp->retval, getsval(y));
3751d48fce0SDaniel Fojt frp->retval->fval = getfval(y);
3761d48fce0SDaniel Fojt frp->retval->tval |= NUM;
3774b588458SPeter Avalos }
3784b588458SPeter Avalos else if (y->tval & STR)
3791d48fce0SDaniel Fojt setsval(frp->retval, getsval(y));
3804b588458SPeter Avalos else if (y->tval & NUM)
3811d48fce0SDaniel Fojt setfval(frp->retval, getfval(y));
3824b588458SPeter Avalos else /* can't happen */
3834b588458SPeter Avalos FATAL("bad type variable %d", y->tval);
3844b588458SPeter Avalos tempfree(y);
3854b588458SPeter Avalos }
3864b588458SPeter Avalos return(jret);
3874b588458SPeter Avalos case NEXT:
3884b588458SPeter Avalos return(jnext);
3894b588458SPeter Avalos case NEXTFILE:
3904b588458SPeter Avalos nextfile();
3914b588458SPeter Avalos return(jnextfile);
3924b588458SPeter Avalos case BREAK:
3934b588458SPeter Avalos return(jbreak);
3944b588458SPeter Avalos case CONTINUE:
3954b588458SPeter Avalos return(jcont);
3964b588458SPeter Avalos default: /* can't happen */
3974b588458SPeter Avalos FATAL("illegal jump type %d", n);
3984b588458SPeter Avalos }
3994b588458SPeter Avalos return 0; /* not reached */
4004b588458SPeter Avalos }
4014b588458SPeter Avalos
awkgetline(Node ** a,int n)4024b588458SPeter Avalos Cell *awkgetline(Node **a, int n) /* get next line from specific input */
4034b588458SPeter Avalos { /* a[0] is variable, a[1] is operator, a[2] is filename */
4044b588458SPeter Avalos Cell *r, *x;
4054b588458SPeter Avalos extern Cell **fldtab;
4064b588458SPeter Avalos FILE *fp;
4074b588458SPeter Avalos char *buf;
4084b588458SPeter Avalos int bufsize = recsize;
4094b588458SPeter Avalos int mode;
4101d48fce0SDaniel Fojt bool newflag;
41148f09a05SAntonio Huete Jimenez double result;
4124b588458SPeter Avalos
41348f09a05SAntonio Huete Jimenez if ((buf = (char *) malloc(bufsize)) == NULL)
4144b588458SPeter Avalos FATAL("out of memory in getline");
4154b588458SPeter Avalos
4164b588458SPeter Avalos fflush(stdout); /* in case someone is waiting for a prompt */
4174b588458SPeter Avalos r = gettemp();
4184b588458SPeter Avalos if (a[1] != NULL) { /* getline < file */
4194b588458SPeter Avalos x = execute(a[2]); /* filename */
4204b588458SPeter Avalos mode = ptoi(a[1]);
4214b588458SPeter Avalos if (mode == '|') /* input pipe */
4224b588458SPeter Avalos mode = LE; /* arbitrary flag */
4231d48fce0SDaniel Fojt fp = openfile(mode, getsval(x), &newflag);
4244b588458SPeter Avalos tempfree(x);
4254b588458SPeter Avalos if (fp == NULL)
4264b588458SPeter Avalos n = -1;
4274b588458SPeter Avalos else
4281d48fce0SDaniel Fojt n = readrec(&buf, &bufsize, fp, newflag);
4294b588458SPeter Avalos if (n <= 0) {
4304b588458SPeter Avalos ;
4314b588458SPeter Avalos } else if (a[0] != NULL) { /* getline var <file */
4324b588458SPeter Avalos x = execute(a[0]);
4334b588458SPeter Avalos setsval(x, buf);
43448f09a05SAntonio Huete Jimenez if (is_number(x->sval, & result)) {
43548f09a05SAntonio Huete Jimenez x->fval = result;
4361d48fce0SDaniel Fojt x->tval |= NUM;
4371d48fce0SDaniel Fojt }
4384b588458SPeter Avalos tempfree(x);
4394b588458SPeter Avalos } else { /* getline <file */
4404b588458SPeter Avalos setsval(fldtab[0], buf);
44148f09a05SAntonio Huete Jimenez if (is_number(fldtab[0]->sval, & result)) {
44248f09a05SAntonio Huete Jimenez fldtab[0]->fval = result;
4434b588458SPeter Avalos fldtab[0]->tval |= NUM;
4444b588458SPeter Avalos }
4454b588458SPeter Avalos }
4464b588458SPeter Avalos } else { /* bare getline; use current input */
4474b588458SPeter Avalos if (a[0] == NULL) /* getline */
4481d48fce0SDaniel Fojt n = getrec(&record, &recsize, true);
4494b588458SPeter Avalos else { /* getline var */
4501d48fce0SDaniel Fojt n = getrec(&buf, &bufsize, false);
45148f09a05SAntonio Huete Jimenez if (n > 0) {
4524b588458SPeter Avalos x = execute(a[0]);
4534b588458SPeter Avalos setsval(x, buf);
45448f09a05SAntonio Huete Jimenez if (is_number(x->sval, & result)) {
45548f09a05SAntonio Huete Jimenez x->fval = result;
4561d48fce0SDaniel Fojt x->tval |= NUM;
4571d48fce0SDaniel Fojt }
4584b588458SPeter Avalos tempfree(x);
4594b588458SPeter Avalos }
4604b588458SPeter Avalos }
46148f09a05SAntonio Huete Jimenez }
4624b588458SPeter Avalos setfval(r, (Awkfloat) n);
4634b588458SPeter Avalos free(buf);
4644b588458SPeter Avalos return r;
4654b588458SPeter Avalos }
4664b588458SPeter Avalos
getnf(Node ** a,int n)4674b588458SPeter Avalos Cell *getnf(Node **a, int n) /* get NF */
4684b588458SPeter Avalos {
4691d48fce0SDaniel Fojt if (!donefld)
4704b588458SPeter Avalos fldbld();
4714b588458SPeter Avalos return (Cell *) a[0];
4724b588458SPeter Avalos }
4734b588458SPeter Avalos
4741d48fce0SDaniel Fojt static char *
makearraystring(Node * p,const char * func)4751d48fce0SDaniel Fojt makearraystring(Node *p, const char *func)
4764b588458SPeter Avalos {
4774b588458SPeter Avalos char *buf;
4784b588458SPeter Avalos int bufsz = recsize;
479e5e686a0SDaniel Fojt size_t blen;
4804b588458SPeter Avalos
48148f09a05SAntonio Huete Jimenez if ((buf = (char *) malloc(bufsz)) == NULL) {
4821d48fce0SDaniel Fojt FATAL("%s: out of memory", func);
4831d48fce0SDaniel Fojt }
4841d48fce0SDaniel Fojt
4851d48fce0SDaniel Fojt blen = 0;
4861d48fce0SDaniel Fojt buf[blen] = '\0';
4871d48fce0SDaniel Fojt
4881d48fce0SDaniel Fojt for (; p; p = p->nnext) {
4891d48fce0SDaniel Fojt Cell *x = execute(p); /* expr */
4901d48fce0SDaniel Fojt char *s = getsval(x);
491e5e686a0SDaniel Fojt size_t seplen = strlen(getsval(subseploc));
4921d48fce0SDaniel Fojt size_t nsub = p->nnext ? seplen : 0;
4931d48fce0SDaniel Fojt size_t slen = strlen(s);
4941d48fce0SDaniel Fojt size_t tlen = blen + slen + nsub;
4951d48fce0SDaniel Fojt
4961d48fce0SDaniel Fojt if (!adjbuf(&buf, &bufsz, tlen + 1, recsize, 0, func)) {
4971d48fce0SDaniel Fojt FATAL("%s: out of memory %s[%s...]",
4981d48fce0SDaniel Fojt func, x->nval, buf);
4991d48fce0SDaniel Fojt }
5001d48fce0SDaniel Fojt memcpy(buf + blen, s, slen);
5011d48fce0SDaniel Fojt if (nsub) {
5021d48fce0SDaniel Fojt memcpy(buf + blen + slen, *SUBSEP, nsub);
5031d48fce0SDaniel Fojt }
5041d48fce0SDaniel Fojt buf[tlen] = '\0';
5051d48fce0SDaniel Fojt blen = tlen;
5061d48fce0SDaniel Fojt tempfree(x);
5071d48fce0SDaniel Fojt }
5081d48fce0SDaniel Fojt return buf;
5091d48fce0SDaniel Fojt }
5101d48fce0SDaniel Fojt
array(Node ** a,int n)5111d48fce0SDaniel Fojt Cell *array(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
5121d48fce0SDaniel Fojt {
5131d48fce0SDaniel Fojt Cell *x, *z;
5141d48fce0SDaniel Fojt char *buf;
5154b588458SPeter Avalos
5164b588458SPeter Avalos x = execute(a[0]); /* Cell* for symbol table */
5171d48fce0SDaniel Fojt buf = makearraystring(a[1], __func__);
5184b588458SPeter Avalos if (!isarr(x)) {
519e5e686a0SDaniel Fojt DPRINTF("making %s into an array\n", NN(x->nval));
5204b588458SPeter Avalos if (freeable(x))
5214b588458SPeter Avalos xfree(x->sval);
5224b588458SPeter Avalos x->tval &= ~(STR|NUM|DONTFREE);
5234b588458SPeter Avalos x->tval |= ARR;
5244b588458SPeter Avalos x->sval = (char *) makesymtab(NSYMTAB);
5254b588458SPeter Avalos }
5264b588458SPeter Avalos z = setsymtab(buf, "", 0.0, STR|NUM, (Array *) x->sval);
5274b588458SPeter Avalos z->ctype = OCELL;
5284b588458SPeter Avalos z->csub = CVAR;
5294b588458SPeter Avalos tempfree(x);
5304b588458SPeter Avalos free(buf);
5314b588458SPeter Avalos return(z);
5324b588458SPeter Avalos }
5334b588458SPeter Avalos
awkdelete(Node ** a,int n)5344b588458SPeter Avalos Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts */
5354b588458SPeter Avalos {
5361d48fce0SDaniel Fojt Cell *x;
5374b588458SPeter Avalos
5384b588458SPeter Avalos x = execute(a[0]); /* Cell* for symbol table */
5391d48fce0SDaniel Fojt if (x == symtabloc) {
5401d48fce0SDaniel Fojt FATAL("cannot delete SYMTAB or its elements");
5411d48fce0SDaniel Fojt }
5424b588458SPeter Avalos if (!isarr(x))
5434b588458SPeter Avalos return True;
5441d48fce0SDaniel Fojt if (a[1] == NULL) { /* delete the elements, not the table */
5454b588458SPeter Avalos freesymtab(x);
5464b588458SPeter Avalos x->tval &= ~STR;
5474b588458SPeter Avalos x->tval |= ARR;
5484b588458SPeter Avalos x->sval = (char *) makesymtab(NSYMTAB);
5494b588458SPeter Avalos } else {
5501d48fce0SDaniel Fojt char *buf = makearraystring(a[1], __func__);
5514b588458SPeter Avalos freeelem(x, buf);
5524b588458SPeter Avalos free(buf);
5534b588458SPeter Avalos }
5544b588458SPeter Avalos tempfree(x);
5554b588458SPeter Avalos return True;
5564b588458SPeter Avalos }
5574b588458SPeter Avalos
intest(Node ** a,int n)5584b588458SPeter Avalos Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */
5594b588458SPeter Avalos {
5601d48fce0SDaniel Fojt Cell *ap, *k;
5614b588458SPeter Avalos char *buf;
5624b588458SPeter Avalos
5634b588458SPeter Avalos ap = execute(a[1]); /* array name */
5644b588458SPeter Avalos if (!isarr(ap)) {
565e5e686a0SDaniel Fojt DPRINTF("making %s into an array\n", ap->nval);
5664b588458SPeter Avalos if (freeable(ap))
5674b588458SPeter Avalos xfree(ap->sval);
5684b588458SPeter Avalos ap->tval &= ~(STR|NUM|DONTFREE);
5694b588458SPeter Avalos ap->tval |= ARR;
5704b588458SPeter Avalos ap->sval = (char *) makesymtab(NSYMTAB);
5714b588458SPeter Avalos }
5721d48fce0SDaniel Fojt buf = makearraystring(a[0], __func__);
5734b588458SPeter Avalos k = lookup(buf, (Array *) ap->sval);
5744b588458SPeter Avalos tempfree(ap);
5754b588458SPeter Avalos free(buf);
5764b588458SPeter Avalos if (k == NULL)
5774b588458SPeter Avalos return(False);
5784b588458SPeter Avalos else
5794b588458SPeter Avalos return(True);
5804b588458SPeter Avalos }
5814b588458SPeter Avalos
5824b588458SPeter Avalos
583*ed569bc2SAaron LI /* ======== utf-8 code ========== */
584*ed569bc2SAaron LI
585*ed569bc2SAaron LI /*
586*ed569bc2SAaron LI * Awk strings can contain ascii, random 8-bit items (eg Latin-1),
587*ed569bc2SAaron LI * or utf-8. u8_isutf tests whether a string starts with a valid
588*ed569bc2SAaron LI * utf-8 sequence, and returns 0 if not (e.g., high bit set).
589*ed569bc2SAaron LI * u8_nextlen returns length of next valid sequence, which is
590*ed569bc2SAaron LI * 1 for ascii, 2..4 for utf-8, or 1 for high bit non-utf.
591*ed569bc2SAaron LI * u8_strlen returns length of string in valid utf-8 sequences
592*ed569bc2SAaron LI * and/or high-bit bytes. Conversion functions go between byte
593*ed569bc2SAaron LI * number and character number.
594*ed569bc2SAaron LI *
595*ed569bc2SAaron LI * In theory, this behaves the same as before for non-utf8 bytes.
596*ed569bc2SAaron LI *
597*ed569bc2SAaron LI * Limited checking! This is a potential security hole.
598*ed569bc2SAaron LI */
599*ed569bc2SAaron LI
600*ed569bc2SAaron LI /* is s the beginning of a valid utf-8 string? */
601*ed569bc2SAaron LI /* return length 1..4 if yes, 0 if no */
u8_isutf(const char * s)602*ed569bc2SAaron LI int u8_isutf(const char *s)
603*ed569bc2SAaron LI {
604*ed569bc2SAaron LI int n, ret;
605*ed569bc2SAaron LI unsigned char c;
606*ed569bc2SAaron LI
607*ed569bc2SAaron LI c = s[0];
608*ed569bc2SAaron LI if (c < 128 || awk_mb_cur_max == 1)
609*ed569bc2SAaron LI return 1; /* what if it's 0? */
610*ed569bc2SAaron LI
611*ed569bc2SAaron LI n = strlen(s);
612*ed569bc2SAaron LI if (n >= 2 && ((c>>5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
613*ed569bc2SAaron LI ret = 2; /* 110xxxxx 10xxxxxx */
614*ed569bc2SAaron LI } else if (n >= 3 && ((c>>4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80
615*ed569bc2SAaron LI && (s[2] & 0xC0) == 0x80) {
616*ed569bc2SAaron LI ret = 3; /* 1110xxxx 10xxxxxx 10xxxxxx */
617*ed569bc2SAaron LI } else if (n >= 4 && ((c>>3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80
618*ed569bc2SAaron LI && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
619*ed569bc2SAaron LI ret = 4; /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
620*ed569bc2SAaron LI } else {
621*ed569bc2SAaron LI ret = 0;
622*ed569bc2SAaron LI }
623*ed569bc2SAaron LI return ret;
624*ed569bc2SAaron LI }
625*ed569bc2SAaron LI
626*ed569bc2SAaron LI /* Convert (prefix of) utf8 string to utf-32 rune. */
627*ed569bc2SAaron LI /* Sets *rune to the value, returns the length. */
628*ed569bc2SAaron LI /* No error checking: watch out. */
u8_rune(int * rune,const char * s)629*ed569bc2SAaron LI int u8_rune(int *rune, const char *s)
630*ed569bc2SAaron LI {
631*ed569bc2SAaron LI int n, ret;
632*ed569bc2SAaron LI unsigned char c;
633*ed569bc2SAaron LI
634*ed569bc2SAaron LI c = s[0];
635*ed569bc2SAaron LI if (c < 128 || awk_mb_cur_max == 1) {
636*ed569bc2SAaron LI *rune = c;
637*ed569bc2SAaron LI return 1;
638*ed569bc2SAaron LI }
639*ed569bc2SAaron LI
640*ed569bc2SAaron LI n = strlen(s);
641*ed569bc2SAaron LI if (n >= 2 && ((c>>5) & 0x7) == 0x6 && (s[1] & 0xC0) == 0x80) {
642*ed569bc2SAaron LI *rune = ((c & 0x1F) << 6) | (s[1] & 0x3F); /* 110xxxxx 10xxxxxx */
643*ed569bc2SAaron LI ret = 2;
644*ed569bc2SAaron LI } else if (n >= 3 && ((c>>4) & 0xF) == 0xE && (s[1] & 0xC0) == 0x80
645*ed569bc2SAaron LI && (s[2] & 0xC0) == 0x80) {
646*ed569bc2SAaron LI *rune = ((c & 0xF) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F);
647*ed569bc2SAaron LI /* 1110xxxx 10xxxxxx 10xxxxxx */
648*ed569bc2SAaron LI ret = 3;
649*ed569bc2SAaron LI } else if (n >= 4 && ((c>>3) & 0x1F) == 0x1E && (s[1] & 0xC0) == 0x80
650*ed569bc2SAaron LI && (s[2] & 0xC0) == 0x80 && (s[3] & 0xC0) == 0x80) {
651*ed569bc2SAaron LI *rune = ((c & 0x7) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F);
652*ed569bc2SAaron LI /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
653*ed569bc2SAaron LI ret = 4;
654*ed569bc2SAaron LI } else {
655*ed569bc2SAaron LI *rune = c;
656*ed569bc2SAaron LI ret = 1;
657*ed569bc2SAaron LI }
658*ed569bc2SAaron LI return ret; /* returns one byte if sequence doesn't look like utf */
659*ed569bc2SAaron LI }
660*ed569bc2SAaron LI
661*ed569bc2SAaron LI /* return length of next sequence: 1 for ascii or random, 2..4 for valid utf8 */
u8_nextlen(const char * s)662*ed569bc2SAaron LI int u8_nextlen(const char *s)
663*ed569bc2SAaron LI {
664*ed569bc2SAaron LI int len;
665*ed569bc2SAaron LI
666*ed569bc2SAaron LI len = u8_isutf(s);
667*ed569bc2SAaron LI if (len == 0)
668*ed569bc2SAaron LI len = 1;
669*ed569bc2SAaron LI return len;
670*ed569bc2SAaron LI }
671*ed569bc2SAaron LI
672*ed569bc2SAaron LI /* return number of utf characters or single non-utf bytes */
u8_strlen(const char * s)673*ed569bc2SAaron LI int u8_strlen(const char *s)
674*ed569bc2SAaron LI {
675*ed569bc2SAaron LI int i, len, n, totlen;
676*ed569bc2SAaron LI unsigned char c;
677*ed569bc2SAaron LI
678*ed569bc2SAaron LI n = strlen(s);
679*ed569bc2SAaron LI totlen = 0;
680*ed569bc2SAaron LI for (i = 0; i < n; i += len) {
681*ed569bc2SAaron LI c = s[i];
682*ed569bc2SAaron LI if (c < 128 || awk_mb_cur_max == 1) {
683*ed569bc2SAaron LI len = 1;
684*ed569bc2SAaron LI } else {
685*ed569bc2SAaron LI len = u8_nextlen(&s[i]);
686*ed569bc2SAaron LI }
687*ed569bc2SAaron LI totlen++;
688*ed569bc2SAaron LI if (i > n)
689*ed569bc2SAaron LI FATAL("bad utf count [%s] n=%d i=%d\n", s, n, i);
690*ed569bc2SAaron LI }
691*ed569bc2SAaron LI return totlen;
692*ed569bc2SAaron LI }
693*ed569bc2SAaron LI
694*ed569bc2SAaron LI /* convert utf-8 char number in a string to its byte offset */
u8_char2byte(const char * s,int charnum)695*ed569bc2SAaron LI int u8_char2byte(const char *s, int charnum)
696*ed569bc2SAaron LI {
697*ed569bc2SAaron LI int n;
698*ed569bc2SAaron LI int bytenum = 0;
699*ed569bc2SAaron LI
700*ed569bc2SAaron LI while (charnum > 0) {
701*ed569bc2SAaron LI n = u8_nextlen(s);
702*ed569bc2SAaron LI s += n;
703*ed569bc2SAaron LI bytenum += n;
704*ed569bc2SAaron LI charnum--;
705*ed569bc2SAaron LI }
706*ed569bc2SAaron LI return bytenum;
707*ed569bc2SAaron LI }
708*ed569bc2SAaron LI
709*ed569bc2SAaron LI /* convert byte offset in s to utf-8 char number that starts there */
u8_byte2char(const char * s,int bytenum)710*ed569bc2SAaron LI int u8_byte2char(const char *s, int bytenum)
711*ed569bc2SAaron LI {
712*ed569bc2SAaron LI int i, len, b;
713*ed569bc2SAaron LI int charnum = 0; /* BUG: what origin? */
714*ed569bc2SAaron LI /* should be 0 to match start==0 which means no match */
715*ed569bc2SAaron LI
716*ed569bc2SAaron LI b = strlen(s);
717*ed569bc2SAaron LI if (bytenum > b) {
718*ed569bc2SAaron LI return -1; /* ??? */
719*ed569bc2SAaron LI }
720*ed569bc2SAaron LI for (i = 0; i <= bytenum; i += len) {
721*ed569bc2SAaron LI len = u8_nextlen(s+i);
722*ed569bc2SAaron LI charnum++;
723*ed569bc2SAaron LI }
724*ed569bc2SAaron LI return charnum;
725*ed569bc2SAaron LI }
726*ed569bc2SAaron LI
727*ed569bc2SAaron LI /* runetochar() adapted from rune.c in the Plan 9 distributione */
728*ed569bc2SAaron LI
729*ed569bc2SAaron LI enum
730*ed569bc2SAaron LI {
731*ed569bc2SAaron LI Runeerror = 128, /* from somewhere else */
732*ed569bc2SAaron LI Runemax = 0x10FFFF,
733*ed569bc2SAaron LI
734*ed569bc2SAaron LI Bit1 = 7,
735*ed569bc2SAaron LI Bitx = 6,
736*ed569bc2SAaron LI Bit2 = 5,
737*ed569bc2SAaron LI Bit3 = 4,
738*ed569bc2SAaron LI Bit4 = 3,
739*ed569bc2SAaron LI Bit5 = 2,
740*ed569bc2SAaron LI
741*ed569bc2SAaron LI T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
742*ed569bc2SAaron LI Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
743*ed569bc2SAaron LI T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
744*ed569bc2SAaron LI T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
745*ed569bc2SAaron LI T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
746*ed569bc2SAaron LI T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
747*ed569bc2SAaron LI
748*ed569bc2SAaron LI Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0000 0000 0111 1111 */
749*ed569bc2SAaron LI Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0000 0000 0111 1111 1111 */
750*ed569bc2SAaron LI Rune3 = (1<<(Bit3+2*Bitx))-1, /* 0000 0000 1111 1111 1111 1111 */
751*ed569bc2SAaron LI Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0011 1111 1111 1111 1111 1111 */
752*ed569bc2SAaron LI
753*ed569bc2SAaron LI Maskx = (1<<Bitx)-1, /* 0011 1111 */
754*ed569bc2SAaron LI Testx = Maskx ^ 0xFF, /* 1100 0000 */
755*ed569bc2SAaron LI
756*ed569bc2SAaron LI };
757*ed569bc2SAaron LI
runetochar(char * str,int c)758*ed569bc2SAaron LI int runetochar(char *str, int c)
759*ed569bc2SAaron LI {
760*ed569bc2SAaron LI /* one character sequence 00000-0007F => 00-7F */
761*ed569bc2SAaron LI if (c <= Rune1) {
762*ed569bc2SAaron LI str[0] = c;
763*ed569bc2SAaron LI return 1;
764*ed569bc2SAaron LI }
765*ed569bc2SAaron LI
766*ed569bc2SAaron LI /* two character sequence 00080-007FF => T2 Tx */
767*ed569bc2SAaron LI if (c <= Rune2) {
768*ed569bc2SAaron LI str[0] = T2 | (c >> 1*Bitx);
769*ed569bc2SAaron LI str[1] = Tx | (c & Maskx);
770*ed569bc2SAaron LI return 2;
771*ed569bc2SAaron LI }
772*ed569bc2SAaron LI
773*ed569bc2SAaron LI /* three character sequence 00800-0FFFF => T3 Tx Tx */
774*ed569bc2SAaron LI if (c > Runemax)
775*ed569bc2SAaron LI c = Runeerror;
776*ed569bc2SAaron LI if (c <= Rune3) {
777*ed569bc2SAaron LI str[0] = T3 | (c >> 2*Bitx);
778*ed569bc2SAaron LI str[1] = Tx | ((c >> 1*Bitx) & Maskx);
779*ed569bc2SAaron LI str[2] = Tx | (c & Maskx);
780*ed569bc2SAaron LI return 3;
781*ed569bc2SAaron LI }
782*ed569bc2SAaron LI
783*ed569bc2SAaron LI /* four character sequence 010000-1FFFFF => T4 Tx Tx Tx */
784*ed569bc2SAaron LI str[0] = T4 | (c >> 3*Bitx);
785*ed569bc2SAaron LI str[1] = Tx | ((c >> 2*Bitx) & Maskx);
786*ed569bc2SAaron LI str[2] = Tx | ((c >> 1*Bitx) & Maskx);
787*ed569bc2SAaron LI str[3] = Tx | (c & Maskx);
788*ed569bc2SAaron LI return 4;
789*ed569bc2SAaron LI }
790*ed569bc2SAaron LI
791*ed569bc2SAaron LI
792*ed569bc2SAaron LI /* ========== end of utf8 code =========== */
793*ed569bc2SAaron LI
794*ed569bc2SAaron LI
795*ed569bc2SAaron LI
matchop(Node ** a,int n)7964b588458SPeter Avalos Cell *matchop(Node **a, int n) /* ~ and match() */
7974b588458SPeter Avalos {
798*ed569bc2SAaron LI Cell *x, *y, *z;
7994b588458SPeter Avalos char *s, *t;
8004b588458SPeter Avalos int i;
801*ed569bc2SAaron LI int cstart, cpatlen, len;
8024b588458SPeter Avalos fa *pfa;
8034b588458SPeter Avalos int (*mf)(fa *, const char *) = match, mode = 0;
8044b588458SPeter Avalos
8054b588458SPeter Avalos if (n == MATCHFCN) {
8064b588458SPeter Avalos mf = pmatch;
8074b588458SPeter Avalos mode = 1;
8084b588458SPeter Avalos }
8094b588458SPeter Avalos x = execute(a[1]); /* a[1] = target text */
8104b588458SPeter Avalos s = getsval(x);
8111d48fce0SDaniel Fojt if (a[0] == NULL) /* a[1] == 0: already-compiled reg expr */
8124b588458SPeter Avalos i = (*mf)((fa *) a[2], s);
8134b588458SPeter Avalos else {
8144b588458SPeter Avalos y = execute(a[2]); /* a[2] = regular expr */
8154b588458SPeter Avalos t = getsval(y);
8164b588458SPeter Avalos pfa = makedfa(t, mode);
8174b588458SPeter Avalos i = (*mf)(pfa, s);
8184b588458SPeter Avalos tempfree(y);
8194b588458SPeter Avalos }
820*ed569bc2SAaron LI z = x;
8214b588458SPeter Avalos if (n == MATCHFCN) {
822*ed569bc2SAaron LI int start = patbeg - s + 1; /* origin 1 */
823*ed569bc2SAaron LI if (patlen < 0) {
824*ed569bc2SAaron LI start = 0; /* not found */
825*ed569bc2SAaron LI } else {
826*ed569bc2SAaron LI cstart = u8_byte2char(s, start-1);
827*ed569bc2SAaron LI cpatlen = 0;
828*ed569bc2SAaron LI for (i = 0; i < patlen; i += len) {
829*ed569bc2SAaron LI len = u8_nextlen(patbeg+i);
830*ed569bc2SAaron LI cpatlen++;
831*ed569bc2SAaron LI }
832*ed569bc2SAaron LI
833*ed569bc2SAaron LI start = cstart;
834*ed569bc2SAaron LI patlen = cpatlen;
835*ed569bc2SAaron LI }
836*ed569bc2SAaron LI
8374b588458SPeter Avalos setfval(rstartloc, (Awkfloat) start);
8384b588458SPeter Avalos setfval(rlengthloc, (Awkfloat) patlen);
8394b588458SPeter Avalos x = gettemp();
8404b588458SPeter Avalos x->tval = NUM;
8414b588458SPeter Avalos x->fval = start;
8424b588458SPeter Avalos } else if ((n == MATCH && i == 1) || (n == NOTMATCH && i == 0))
843*ed569bc2SAaron LI x = True;
8444b588458SPeter Avalos else
845*ed569bc2SAaron LI x = False;
846*ed569bc2SAaron LI
847*ed569bc2SAaron LI tempfree(z);
848*ed569bc2SAaron LI return x;
8494b588458SPeter Avalos }
8504b588458SPeter Avalos
8514b588458SPeter Avalos
boolop(Node ** a,int n)8524b588458SPeter Avalos Cell *boolop(Node **a, int n) /* a[0] || a[1], a[0] && a[1], !a[0] */
8534b588458SPeter Avalos {
8544b588458SPeter Avalos Cell *x, *y;
8554b588458SPeter Avalos int i;
8564b588458SPeter Avalos
8574b588458SPeter Avalos x = execute(a[0]);
8584b588458SPeter Avalos i = istrue(x);
8594b588458SPeter Avalos tempfree(x);
8604b588458SPeter Avalos switch (n) {
8614b588458SPeter Avalos case BOR:
8624b588458SPeter Avalos if (i) return(True);
8634b588458SPeter Avalos y = execute(a[1]);
8644b588458SPeter Avalos i = istrue(y);
8654b588458SPeter Avalos tempfree(y);
8664b588458SPeter Avalos if (i) return(True);
8674b588458SPeter Avalos else return(False);
8684b588458SPeter Avalos case AND:
8694b588458SPeter Avalos if ( !i ) return(False);
8704b588458SPeter Avalos y = execute(a[1]);
8714b588458SPeter Avalos i = istrue(y);
8724b588458SPeter Avalos tempfree(y);
8734b588458SPeter Avalos if (i) return(True);
8744b588458SPeter Avalos else return(False);
8754b588458SPeter Avalos case NOT:
8764b588458SPeter Avalos if (i) return(False);
8774b588458SPeter Avalos else return(True);
8784b588458SPeter Avalos default: /* can't happen */
8794b588458SPeter Avalos FATAL("unknown boolean operator %d", n);
8804b588458SPeter Avalos }
8814b588458SPeter Avalos return 0; /*NOTREACHED*/
8824b588458SPeter Avalos }
8834b588458SPeter Avalos
relop(Node ** a,int n)8844b588458SPeter Avalos Cell *relop(Node **a, int n) /* a[0 < a[1], etc. */
8854b588458SPeter Avalos {
8864b588458SPeter Avalos int i;
8874b588458SPeter Avalos Cell *x, *y;
8884b588458SPeter Avalos Awkfloat j;
889*ed569bc2SAaron LI bool x_is_nan, y_is_nan;
8904b588458SPeter Avalos
8914b588458SPeter Avalos x = execute(a[0]);
8924b588458SPeter Avalos y = execute(a[1]);
893*ed569bc2SAaron LI x_is_nan = isnan(x->fval);
894*ed569bc2SAaron LI y_is_nan = isnan(y->fval);
8954b588458SPeter Avalos if (x->tval&NUM && y->tval&NUM) {
896*ed569bc2SAaron LI if ((x_is_nan || y_is_nan) && n != NE)
897*ed569bc2SAaron LI return(False);
8984b588458SPeter Avalos j = x->fval - y->fval;
8994b588458SPeter Avalos i = j<0? -1: (j>0? 1: 0);
9004b588458SPeter Avalos } else {
9014b588458SPeter Avalos i = strcmp(getsval(x), getsval(y));
9024b588458SPeter Avalos }
9034b588458SPeter Avalos tempfree(x);
9044b588458SPeter Avalos tempfree(y);
9054b588458SPeter Avalos switch (n) {
9064b588458SPeter Avalos case LT: if (i<0) return(True);
9074b588458SPeter Avalos else return(False);
9084b588458SPeter Avalos case LE: if (i<=0) return(True);
9094b588458SPeter Avalos else return(False);
910*ed569bc2SAaron LI case NE: if (x_is_nan && y_is_nan) return(True);
911*ed569bc2SAaron LI else if (i!=0) return(True);
9124b588458SPeter Avalos else return(False);
9134b588458SPeter Avalos case EQ: if (i == 0) return(True);
9144b588458SPeter Avalos else return(False);
9154b588458SPeter Avalos case GE: if (i>=0) return(True);
9164b588458SPeter Avalos else return(False);
9174b588458SPeter Avalos case GT: if (i>0) return(True);
9184b588458SPeter Avalos else return(False);
9194b588458SPeter Avalos default: /* can't happen */
9204b588458SPeter Avalos FATAL("unknown relational operator %d", n);
9214b588458SPeter Avalos }
9224b588458SPeter Avalos return 0; /*NOTREACHED*/
9234b588458SPeter Avalos }
9244b588458SPeter Avalos
tfree(Cell * a)9254b588458SPeter Avalos void tfree(Cell *a) /* free a tempcell */
9264b588458SPeter Avalos {
9274b588458SPeter Avalos if (freeable(a)) {
928e5e686a0SDaniel Fojt DPRINTF("freeing %s %s %o\n", NN(a->nval), NN(a->sval), a->tval);
9294b588458SPeter Avalos xfree(a->sval);
9304b588458SPeter Avalos }
9314b588458SPeter Avalos if (a == tmps)
9324b588458SPeter Avalos FATAL("tempcell list is curdled");
9334b588458SPeter Avalos a->cnext = tmps;
9344b588458SPeter Avalos tmps = a;
9354b588458SPeter Avalos }
9364b588458SPeter Avalos
gettemp(void)9374b588458SPeter Avalos Cell *gettemp(void) /* get a tempcell */
9384b588458SPeter Avalos { int i;
9394b588458SPeter Avalos Cell *x;
9404b588458SPeter Avalos
9414b588458SPeter Avalos if (!tmps) {
94248f09a05SAntonio Huete Jimenez tmps = (Cell *) calloc(100, sizeof(*tmps));
9434b588458SPeter Avalos if (!tmps)
9444b588458SPeter Avalos FATAL("out of space for temporaries");
9454b588458SPeter Avalos for (i = 1; i < 100; i++)
9464b588458SPeter Avalos tmps[i-1].cnext = &tmps[i];
9471d48fce0SDaniel Fojt tmps[i-1].cnext = NULL;
9484b588458SPeter Avalos }
9494b588458SPeter Avalos x = tmps;
9504b588458SPeter Avalos tmps = x->cnext;
9514b588458SPeter Avalos *x = tempcell;
9524b588458SPeter Avalos return(x);
9534b588458SPeter Avalos }
9544b588458SPeter Avalos
indirect(Node ** a,int n)9554b588458SPeter Avalos Cell *indirect(Node **a, int n) /* $( a[0] ) */
9564b588458SPeter Avalos {
9574b588458SPeter Avalos Awkfloat val;
9584b588458SPeter Avalos Cell *x;
9594b588458SPeter Avalos int m;
9604b588458SPeter Avalos char *s;
9614b588458SPeter Avalos
9624b588458SPeter Avalos x = execute(a[0]);
9634b588458SPeter Avalos val = getfval(x); /* freebsd: defend against super large field numbers */
9644b588458SPeter Avalos if ((Awkfloat)INT_MAX < val)
9654b588458SPeter Avalos FATAL("trying to access out of range field %s", x->nval);
9664b588458SPeter Avalos m = (int) val;
96748f09a05SAntonio Huete Jimenez if (m == 0 && !is_number(s = getsval(x), NULL)) /* suspicion! */
9684b588458SPeter Avalos FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
9694b588458SPeter Avalos /* BUG: can x->nval ever be null??? */
9704b588458SPeter Avalos tempfree(x);
9714b588458SPeter Avalos x = fieldadr(m);
9724b588458SPeter Avalos x->ctype = OCELL; /* BUG? why are these needed? */
9734b588458SPeter Avalos x->csub = CFLD;
9744b588458SPeter Avalos return(x);
9754b588458SPeter Avalos }
9764b588458SPeter Avalos
substr(Node ** a,int nnn)9774b588458SPeter Avalos Cell *substr(Node **a, int nnn) /* substr(a[0], a[1], a[2]) */
9784b588458SPeter Avalos {
9794b588458SPeter Avalos int k, m, n;
980*ed569bc2SAaron LI int mb, nb;
9814b588458SPeter Avalos char *s;
9824b588458SPeter Avalos int temp;
9831d48fce0SDaniel Fojt Cell *x, *y, *z = NULL;
9844b588458SPeter Avalos
9854b588458SPeter Avalos x = execute(a[0]);
9864b588458SPeter Avalos y = execute(a[1]);
9871d48fce0SDaniel Fojt if (a[2] != NULL)
9884b588458SPeter Avalos z = execute(a[2]);
9894b588458SPeter Avalos s = getsval(x);
990*ed569bc2SAaron LI k = u8_strlen(s) + 1;
9914b588458SPeter Avalos if (k <= 1) {
9924b588458SPeter Avalos tempfree(x);
9934b588458SPeter Avalos tempfree(y);
9941d48fce0SDaniel Fojt if (a[2] != NULL) {
9954b588458SPeter Avalos tempfree(z);
9964b588458SPeter Avalos }
9974b588458SPeter Avalos x = gettemp();
9984b588458SPeter Avalos setsval(x, "");
9994b588458SPeter Avalos return(x);
10004b588458SPeter Avalos }
10014b588458SPeter Avalos m = (int) getfval(y);
10024b588458SPeter Avalos if (m <= 0)
10034b588458SPeter Avalos m = 1;
10044b588458SPeter Avalos else if (m > k)
10054b588458SPeter Avalos m = k;
10064b588458SPeter Avalos tempfree(y);
10071d48fce0SDaniel Fojt if (a[2] != NULL) {
10084b588458SPeter Avalos n = (int) getfval(z);
10094b588458SPeter Avalos tempfree(z);
10104b588458SPeter Avalos } else
10114b588458SPeter Avalos n = k - 1;
10124b588458SPeter Avalos if (n < 0)
10134b588458SPeter Avalos n = 0;
10144b588458SPeter Avalos else if (n > k - m)
10154b588458SPeter Avalos n = k - m;
1016*ed569bc2SAaron LI /* m is start, n is length from there */
1017e5e686a0SDaniel Fojt DPRINTF("substr: m=%d, n=%d, s=%s\n", m, n, s);
10184b588458SPeter Avalos y = gettemp();
1019*ed569bc2SAaron LI mb = u8_char2byte(s, m-1); /* byte offset of start char in s */
1020*ed569bc2SAaron LI nb = u8_char2byte(s, m-1+n); /* byte offset of end+1 char in s */
1021*ed569bc2SAaron LI
1022*ed569bc2SAaron LI temp = s[nb]; /* with thanks to John Linderman */
1023*ed569bc2SAaron LI s[nb] = '\0';
1024*ed569bc2SAaron LI setsval(y, s + mb);
1025*ed569bc2SAaron LI s[nb] = temp;
10264b588458SPeter Avalos tempfree(x);
10274b588458SPeter Avalos return(y);
10284b588458SPeter Avalos }
10294b588458SPeter Avalos
sindex(Node ** a,int nnn)10304b588458SPeter Avalos Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */
10314b588458SPeter Avalos {
10324b588458SPeter Avalos Cell *x, *y, *z;
10334b588458SPeter Avalos char *s1, *s2, *p1, *p2, *q;
10344b588458SPeter Avalos Awkfloat v = 0.0;
10354b588458SPeter Avalos
10364b588458SPeter Avalos x = execute(a[0]);
10374b588458SPeter Avalos s1 = getsval(x);
10384b588458SPeter Avalos y = execute(a[1]);
10394b588458SPeter Avalos s2 = getsval(y);
10404b588458SPeter Avalos
10414b588458SPeter Avalos z = gettemp();
10424b588458SPeter Avalos for (p1 = s1; *p1 != '\0'; p1++) {
10434b588458SPeter Avalos for (q = p1, p2 = s2; *p2 != '\0' && *q == *p2; q++, p2++)
10441d48fce0SDaniel Fojt continue;
10454b588458SPeter Avalos if (*p2 == '\0') {
1046*ed569bc2SAaron LI /* v = (Awkfloat) (p1 - s1 + 1); origin 1 */
1047*ed569bc2SAaron LI
1048*ed569bc2SAaron LI /* should be a function: used in match() as well */
1049*ed569bc2SAaron LI int i, len;
1050*ed569bc2SAaron LI v = 0;
1051*ed569bc2SAaron LI for (i = 0; i < p1-s1+1; i += len) {
1052*ed569bc2SAaron LI len = u8_nextlen(s1+i);
1053*ed569bc2SAaron LI v++;
1054*ed569bc2SAaron LI }
10554b588458SPeter Avalos break;
10564b588458SPeter Avalos }
10574b588458SPeter Avalos }
10584b588458SPeter Avalos tempfree(x);
10594b588458SPeter Avalos tempfree(y);
10604b588458SPeter Avalos setfval(z, v);
10614b588458SPeter Avalos return(z);
10624b588458SPeter Avalos }
10634b588458SPeter Avalos
has_utf8(char * s)1064*ed569bc2SAaron LI int has_utf8(char *s) /* return 1 if s contains any utf-8 (2 bytes or more) character */
1065*ed569bc2SAaron LI {
1066*ed569bc2SAaron LI int n;
1067*ed569bc2SAaron LI
1068*ed569bc2SAaron LI for (n = 0; *s != 0; s += n) {
1069*ed569bc2SAaron LI n = u8_nextlen(s);
1070*ed569bc2SAaron LI if (n > 1)
1071*ed569bc2SAaron LI return 1;
1072*ed569bc2SAaron LI }
1073*ed569bc2SAaron LI return 0;
1074*ed569bc2SAaron LI }
1075*ed569bc2SAaron LI
10764b588458SPeter Avalos #define MAXNUMSIZE 50
10774b588458SPeter Avalos
format(char ** pbuf,int * pbufsize,const char * s,Node * a)10784b588458SPeter Avalos int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */
10794b588458SPeter Avalos {
10804b588458SPeter Avalos char *fmt;
10814b588458SPeter Avalos char *p, *t;
10824b588458SPeter Avalos const char *os;
10834b588458SPeter Avalos Cell *x;
10844b588458SPeter Avalos int flag = 0, n;
10854b588458SPeter Avalos int fmtwd; /* format width */
10864b588458SPeter Avalos int fmtsz = recsize;
10874b588458SPeter Avalos char *buf = *pbuf;
10884b588458SPeter Avalos int bufsize = *pbufsize;
10891d48fce0SDaniel Fojt #define FMTSZ(a) (fmtsz - ((a) - fmt))
10901d48fce0SDaniel Fojt #define BUFSZ(a) (bufsize - ((a) - buf))
10911d48fce0SDaniel Fojt
10921d48fce0SDaniel Fojt static bool first = true;
10931d48fce0SDaniel Fojt static bool have_a_format = false;
10941d48fce0SDaniel Fojt
10951d48fce0SDaniel Fojt if (first) {
10961d48fce0SDaniel Fojt char xbuf[100];
10971d48fce0SDaniel Fojt
10981d48fce0SDaniel Fojt snprintf(xbuf, sizeof(xbuf), "%a", 42.0);
10991d48fce0SDaniel Fojt have_a_format = (strcmp(xbuf, "0x1.5p+5") == 0);
11001d48fce0SDaniel Fojt first = false;
11011d48fce0SDaniel Fojt }
11024b588458SPeter Avalos
11034b588458SPeter Avalos os = s;
11044b588458SPeter Avalos p = buf;
110548f09a05SAntonio Huete Jimenez if ((fmt = (char *) malloc(fmtsz)) == NULL)
11064b588458SPeter Avalos FATAL("out of memory in format()");
11074b588458SPeter Avalos while (*s) {
11084b588458SPeter Avalos adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
11094b588458SPeter Avalos if (*s != '%') {
11104b588458SPeter Avalos *p++ = *s++;
11114b588458SPeter Avalos continue;
11124b588458SPeter Avalos }
11134b588458SPeter Avalos if (*(s+1) == '%') {
11144b588458SPeter Avalos *p++ = '%';
11154b588458SPeter Avalos s += 2;
11164b588458SPeter Avalos continue;
11174b588458SPeter Avalos }
11184b588458SPeter Avalos fmtwd = atoi(s+1);
11194b588458SPeter Avalos if (fmtwd < 0)
11204b588458SPeter Avalos fmtwd = -fmtwd;
11214b588458SPeter Avalos adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format2");
11224b588458SPeter Avalos for (t = fmt; (*t++ = *s) != '\0'; s++) {
11234b588458SPeter Avalos if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3"))
11244b588458SPeter Avalos FATAL("format item %.30s... ran format() out of memory", os);
11251d48fce0SDaniel Fojt /* Ignore size specifiers */
11261d48fce0SDaniel Fojt if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */
11271d48fce0SDaniel Fojt t--;
11281d48fce0SDaniel Fojt continue;
11291d48fce0SDaniel Fojt }
11301d48fce0SDaniel Fojt if (isalpha((uschar)*s))
11311d48fce0SDaniel Fojt break;
11321d48fce0SDaniel Fojt if (*s == '$') {
11331d48fce0SDaniel Fojt FATAL("'$' not permitted in awk formats");
11341d48fce0SDaniel Fojt }
11354b588458SPeter Avalos if (*s == '*') {
11361d48fce0SDaniel Fojt if (a == NULL) {
11371d48fce0SDaniel Fojt FATAL("not enough args in printf(%s)", os);
11381d48fce0SDaniel Fojt }
11394b588458SPeter Avalos x = execute(a);
11404b588458SPeter Avalos a = a->nnext;
11411d48fce0SDaniel Fojt snprintf(t - 1, FMTSZ(t - 1),
11421d48fce0SDaniel Fojt "%d", fmtwd=(int) getfval(x));
11434b588458SPeter Avalos if (fmtwd < 0)
11444b588458SPeter Avalos fmtwd = -fmtwd;
11454b588458SPeter Avalos adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format");
11464b588458SPeter Avalos t = fmt + strlen(fmt);
11474b588458SPeter Avalos tempfree(x);
11484b588458SPeter Avalos }
11494b588458SPeter Avalos }
11504b588458SPeter Avalos *t = '\0';
11514b588458SPeter Avalos if (fmtwd < 0)
11524b588458SPeter Avalos fmtwd = -fmtwd;
11534b588458SPeter Avalos adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4");
11544b588458SPeter Avalos switch (*s) {
11551d48fce0SDaniel Fojt case 'a': case 'A':
11561d48fce0SDaniel Fojt if (have_a_format)
11571d48fce0SDaniel Fojt flag = *s;
11581d48fce0SDaniel Fojt else
11591d48fce0SDaniel Fojt flag = 'f';
11601d48fce0SDaniel Fojt break;
11614b588458SPeter Avalos case 'f': case 'e': case 'g': case 'E': case 'G':
11624b588458SPeter Avalos flag = 'f';
11634b588458SPeter Avalos break;
11641d48fce0SDaniel Fojt case 'd': case 'i': case 'o': case 'x': case 'X': case 'u':
11651d48fce0SDaniel Fojt flag = (*s == 'd' || *s == 'i') ? 'd' : 'u';
11661d48fce0SDaniel Fojt *(t-1) = 'j';
11671d48fce0SDaniel Fojt *t = *s;
11684b588458SPeter Avalos *++t = '\0';
11694b588458SPeter Avalos break;
11704b588458SPeter Avalos case 's':
11714b588458SPeter Avalos flag = 's';
11724b588458SPeter Avalos break;
11734b588458SPeter Avalos case 'c':
11744b588458SPeter Avalos flag = 'c';
11754b588458SPeter Avalos break;
11764b588458SPeter Avalos default:
11774b588458SPeter Avalos WARNING("weird printf conversion %s", fmt);
11784b588458SPeter Avalos flag = '?';
11794b588458SPeter Avalos break;
11804b588458SPeter Avalos }
11814b588458SPeter Avalos if (a == NULL)
11824b588458SPeter Avalos FATAL("not enough args in printf(%s)", os);
11834b588458SPeter Avalos x = execute(a);
11844b588458SPeter Avalos a = a->nnext;
11854b588458SPeter Avalos n = MAXNUMSIZE;
11864b588458SPeter Avalos if (fmtwd > n)
11874b588458SPeter Avalos n = fmtwd;
11884b588458SPeter Avalos adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5");
11894b588458SPeter Avalos switch (flag) {
1190*ed569bc2SAaron LI case '?':
1191*ed569bc2SAaron LI snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */
11924b588458SPeter Avalos t = getsval(x);
11934b588458SPeter Avalos n = strlen(t);
11944b588458SPeter Avalos if (fmtwd > n)
11954b588458SPeter Avalos n = fmtwd;
11964b588458SPeter Avalos adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6");
11974b588458SPeter Avalos p += strlen(p);
11981d48fce0SDaniel Fojt snprintf(p, BUFSZ(p), "%s", t);
11994b588458SPeter Avalos break;
12001d48fce0SDaniel Fojt case 'a':
12011d48fce0SDaniel Fojt case 'A':
12021d48fce0SDaniel Fojt case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break;
12031d48fce0SDaniel Fojt case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break;
12041d48fce0SDaniel Fojt case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break;
1205*ed569bc2SAaron LI
1206*ed569bc2SAaron LI case 's': {
12074b588458SPeter Avalos t = getsval(x);
12084b588458SPeter Avalos n = strlen(t);
1209*ed569bc2SAaron LI /* if simple format or no utf-8 in the string, sprintf works */
1210*ed569bc2SAaron LI if (!has_utf8(t) || strcmp(fmt,"%s") == 0) {
12114b588458SPeter Avalos if (fmtwd > n)
12124b588458SPeter Avalos n = fmtwd;
12134b588458SPeter Avalos if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7"))
1214*ed569bc2SAaron LI FATAL("huge string/format (%d chars) in printf %.30s..." \
1215*ed569bc2SAaron LI " ran format() out of memory", n, t);
12161d48fce0SDaniel Fojt snprintf(p, BUFSZ(p), fmt, t);
12174b588458SPeter Avalos break;
1218*ed569bc2SAaron LI }
1219*ed569bc2SAaron LI
1220*ed569bc2SAaron LI /* get here if string has utf-8 chars and fmt is not plain %s */
1221*ed569bc2SAaron LI /* "%-w.ps", where -, w and .p are all optional */
1222*ed569bc2SAaron LI /* '0' before the w is a flag character */
1223*ed569bc2SAaron LI /* fmt points at % */
1224*ed569bc2SAaron LI int ljust = 0, wid = 0, prec = n, pad = 0;
1225*ed569bc2SAaron LI char *f = fmt+1;
1226*ed569bc2SAaron LI if (f[0] == '-') {
1227*ed569bc2SAaron LI ljust = 1;
1228*ed569bc2SAaron LI f++;
1229*ed569bc2SAaron LI }
1230*ed569bc2SAaron LI // flags '0' and '+' are recognized but skipped
1231*ed569bc2SAaron LI if (f[0] == '0') {
1232*ed569bc2SAaron LI f++;
1233*ed569bc2SAaron LI if (f[0] == '+')
1234*ed569bc2SAaron LI f++;
1235*ed569bc2SAaron LI }
1236*ed569bc2SAaron LI if (f[0] == '+') {
1237*ed569bc2SAaron LI f++;
1238*ed569bc2SAaron LI if (f[0] == '0')
1239*ed569bc2SAaron LI f++;
1240*ed569bc2SAaron LI }
1241*ed569bc2SAaron LI if (isdigit(f[0])) { /* there is a wid */
1242*ed569bc2SAaron LI wid = strtol(f, &f, 10);
1243*ed569bc2SAaron LI }
1244*ed569bc2SAaron LI if (f[0] == '.') { /* there is a .prec */
1245*ed569bc2SAaron LI prec = strtol(++f, &f, 10);
1246*ed569bc2SAaron LI }
1247*ed569bc2SAaron LI if (prec > u8_strlen(t))
1248*ed569bc2SAaron LI prec = u8_strlen(t);
1249*ed569bc2SAaron LI pad = wid>prec ? wid - prec : 0; // has to be >= 0
1250*ed569bc2SAaron LI int i, k, n;
1251*ed569bc2SAaron LI
1252*ed569bc2SAaron LI if (ljust) { // print prec chars from t, then pad blanks
1253*ed569bc2SAaron LI n = u8_char2byte(t, prec);
1254*ed569bc2SAaron LI for (k = 0; k < n; k++) {
1255*ed569bc2SAaron LI //putchar(t[k]);
1256*ed569bc2SAaron LI *p++ = t[k];
1257*ed569bc2SAaron LI }
1258*ed569bc2SAaron LI for (i = 0; i < pad; i++) {
1259*ed569bc2SAaron LI //printf(" ");
1260*ed569bc2SAaron LI *p++ = ' ';
1261*ed569bc2SAaron LI }
1262*ed569bc2SAaron LI } else { // print pad blanks, then prec chars from t
1263*ed569bc2SAaron LI for (i = 0; i < pad; i++) {
1264*ed569bc2SAaron LI //printf(" ");
1265*ed569bc2SAaron LI *p++ = ' ';
1266*ed569bc2SAaron LI }
1267*ed569bc2SAaron LI n = u8_char2byte(t, prec);
1268*ed569bc2SAaron LI for (k = 0; k < n; k++) {
1269*ed569bc2SAaron LI //putchar(t[k]);
1270*ed569bc2SAaron LI *p++ = t[k];
1271*ed569bc2SAaron LI }
1272*ed569bc2SAaron LI }
1273*ed569bc2SAaron LI *p = 0;
1274*ed569bc2SAaron LI break;
1275*ed569bc2SAaron LI }
1276*ed569bc2SAaron LI
1277*ed569bc2SAaron LI case 'c': {
1278*ed569bc2SAaron LI /*
1279*ed569bc2SAaron LI * If a numeric value is given, awk should just turn
1280*ed569bc2SAaron LI * it into a character and print it:
1281*ed569bc2SAaron LI * BEGIN { printf("%c\n", 65) }
1282*ed569bc2SAaron LI * prints "A".
1283*ed569bc2SAaron LI *
1284*ed569bc2SAaron LI * But what if the numeric value is > 128 and
1285*ed569bc2SAaron LI * represents a valid Unicode code point?!? We do
1286*ed569bc2SAaron LI * our best to convert it back into UTF-8. If we
1287*ed569bc2SAaron LI * can't, we output the encoding of the Unicode
1288*ed569bc2SAaron LI * "invalid character", 0xFFFD.
1289*ed569bc2SAaron LI */
12904b588458SPeter Avalos if (isnum(x)) {
1291*ed569bc2SAaron LI int charval = (int) getfval(x);
1292*ed569bc2SAaron LI
1293*ed569bc2SAaron LI if (charval != 0) {
1294*ed569bc2SAaron LI if (charval < 128 || awk_mb_cur_max == 1)
1295*ed569bc2SAaron LI snprintf(p, BUFSZ(p), fmt, charval);
12964b588458SPeter Avalos else {
1297*ed569bc2SAaron LI // possible unicode character
1298*ed569bc2SAaron LI size_t count;
1299*ed569bc2SAaron LI char *bs = wide_char_to_byte_str(charval, &count);
1300*ed569bc2SAaron LI
1301*ed569bc2SAaron LI if (bs == NULL) { // invalid character
1302*ed569bc2SAaron LI // use unicode invalid character, 0xFFFD
1303*ed569bc2SAaron LI static char invalid_char[] = "\357\277\275";
1304*ed569bc2SAaron LI bs = invalid_char;
1305*ed569bc2SAaron LI count = 3;
1306*ed569bc2SAaron LI }
1307*ed569bc2SAaron LI t = bs;
1308*ed569bc2SAaron LI n = count;
1309*ed569bc2SAaron LI goto format_percent_c;
1310*ed569bc2SAaron LI }
1311*ed569bc2SAaron LI } else {
13124b588458SPeter Avalos *p++ = '\0'; /* explicit null byte */
13134b588458SPeter Avalos *p = '\0'; /* next output will start here */
13144b588458SPeter Avalos }
1315*ed569bc2SAaron LI break;
1316*ed569bc2SAaron LI }
1317*ed569bc2SAaron LI t = getsval(x);
1318*ed569bc2SAaron LI n = u8_nextlen(t);
1319*ed569bc2SAaron LI format_percent_c:
1320*ed569bc2SAaron LI if (n < 2) { /* not utf8 */
13211d48fce0SDaniel Fojt snprintf(p, BUFSZ(p), fmt, getsval(x)[0]);
13224b588458SPeter Avalos break;
1323*ed569bc2SAaron LI }
1324*ed569bc2SAaron LI
1325*ed569bc2SAaron LI // utf8 character, almost same song and dance as for %s
1326*ed569bc2SAaron LI int ljust = 0, wid = 0, prec = n, pad = 0;
1327*ed569bc2SAaron LI char *f = fmt+1;
1328*ed569bc2SAaron LI if (f[0] == '-') {
1329*ed569bc2SAaron LI ljust = 1;
1330*ed569bc2SAaron LI f++;
1331*ed569bc2SAaron LI }
1332*ed569bc2SAaron LI // flags '0' and '+' are recognized but skipped
1333*ed569bc2SAaron LI if (f[0] == '0') {
1334*ed569bc2SAaron LI f++;
1335*ed569bc2SAaron LI if (f[0] == '+')
1336*ed569bc2SAaron LI f++;
1337*ed569bc2SAaron LI }
1338*ed569bc2SAaron LI if (f[0] == '+') {
1339*ed569bc2SAaron LI f++;
1340*ed569bc2SAaron LI if (f[0] == '0')
1341*ed569bc2SAaron LI f++;
1342*ed569bc2SAaron LI }
1343*ed569bc2SAaron LI if (isdigit(f[0])) { /* there is a wid */
1344*ed569bc2SAaron LI wid = strtol(f, &f, 10);
1345*ed569bc2SAaron LI }
1346*ed569bc2SAaron LI if (f[0] == '.') { /* there is a .prec */
1347*ed569bc2SAaron LI prec = strtol(++f, &f, 10);
1348*ed569bc2SAaron LI }
1349*ed569bc2SAaron LI if (prec > 1) // %c --> only one character
1350*ed569bc2SAaron LI prec = 1;
1351*ed569bc2SAaron LI pad = wid>prec ? wid - prec : 0; // has to be >= 0
1352*ed569bc2SAaron LI int i;
1353*ed569bc2SAaron LI
1354*ed569bc2SAaron LI if (ljust) { // print one char from t, then pad blanks
1355*ed569bc2SAaron LI for (i = 0; i < n; i++)
1356*ed569bc2SAaron LI *p++ = t[i];
1357*ed569bc2SAaron LI for (i = 0; i < pad; i++) {
1358*ed569bc2SAaron LI //printf(" ");
1359*ed569bc2SAaron LI *p++ = ' ';
1360*ed569bc2SAaron LI }
1361*ed569bc2SAaron LI } else { // print pad blanks, then prec chars from t
1362*ed569bc2SAaron LI for (i = 0; i < pad; i++) {
1363*ed569bc2SAaron LI //printf(" ");
1364*ed569bc2SAaron LI *p++ = ' ';
1365*ed569bc2SAaron LI }
1366*ed569bc2SAaron LI for (i = 0; i < n; i++)
1367*ed569bc2SAaron LI *p++ = t[i];
1368*ed569bc2SAaron LI }
1369*ed569bc2SAaron LI *p = 0;
1370*ed569bc2SAaron LI break;
1371*ed569bc2SAaron LI }
13724b588458SPeter Avalos default:
13734b588458SPeter Avalos FATAL("can't happen: bad conversion %c in format()", flag);
13744b588458SPeter Avalos }
1375*ed569bc2SAaron LI
13764b588458SPeter Avalos tempfree(x);
13774b588458SPeter Avalos p += strlen(p);
13784b588458SPeter Avalos s++;
13794b588458SPeter Avalos }
13804b588458SPeter Avalos *p = '\0';
13814b588458SPeter Avalos free(fmt);
138248f09a05SAntonio Huete Jimenez for ( ; a; a = a->nnext) { /* evaluate any remaining args */
138348f09a05SAntonio Huete Jimenez x = execute(a);
138448f09a05SAntonio Huete Jimenez tempfree(x);
138548f09a05SAntonio Huete Jimenez }
13864b588458SPeter Avalos *pbuf = buf;
13874b588458SPeter Avalos *pbufsize = bufsize;
13884b588458SPeter Avalos return p - buf;
13894b588458SPeter Avalos }
13904b588458SPeter Avalos
awksprintf(Node ** a,int n)13914b588458SPeter Avalos Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
13924b588458SPeter Avalos {
13934b588458SPeter Avalos Cell *x;
13944b588458SPeter Avalos Node *y;
13954b588458SPeter Avalos char *buf;
13964b588458SPeter Avalos int bufsz=3*recsize;
13974b588458SPeter Avalos
139848f09a05SAntonio Huete Jimenez if ((buf = (char *) malloc(bufsz)) == NULL)
13994b588458SPeter Avalos FATAL("out of memory in awksprintf");
14004b588458SPeter Avalos y = a[0]->nnext;
14014b588458SPeter Avalos x = execute(a[0]);
14024b588458SPeter Avalos if (format(&buf, &bufsz, getsval(x), y) == -1)
14034b588458SPeter Avalos FATAL("sprintf string %.30s... too long. can't happen.", buf);
14044b588458SPeter Avalos tempfree(x);
14054b588458SPeter Avalos x = gettemp();
14064b588458SPeter Avalos x->sval = buf;
14074b588458SPeter Avalos x->tval = STR;
14084b588458SPeter Avalos return(x);
14094b588458SPeter Avalos }
14104b588458SPeter Avalos
awkprintf(Node ** a,int n)14114b588458SPeter Avalos Cell *awkprintf(Node **a, int n) /* printf */
14124b588458SPeter Avalos { /* a[0] is list of args, starting with format string */
14134b588458SPeter Avalos /* a[1] is redirection operator, a[2] is redirection file */
14144b588458SPeter Avalos FILE *fp;
14154b588458SPeter Avalos Cell *x;
14164b588458SPeter Avalos Node *y;
14174b588458SPeter Avalos char *buf;
14184b588458SPeter Avalos int len;
14194b588458SPeter Avalos int bufsz=3*recsize;
14204b588458SPeter Avalos
142148f09a05SAntonio Huete Jimenez if ((buf = (char *) malloc(bufsz)) == NULL)
14224b588458SPeter Avalos FATAL("out of memory in awkprintf");
14234b588458SPeter Avalos y = a[0]->nnext;
14244b588458SPeter Avalos x = execute(a[0]);
14254b588458SPeter Avalos if ((len = format(&buf, &bufsz, getsval(x), y)) == -1)
14264b588458SPeter Avalos FATAL("printf string %.30s... too long. can't happen.", buf);
14274b588458SPeter Avalos tempfree(x);
14284b588458SPeter Avalos if (a[1] == NULL) {
14294b588458SPeter Avalos /* fputs(buf, stdout); */
14304b588458SPeter Avalos fwrite(buf, len, 1, stdout);
14314b588458SPeter Avalos if (ferror(stdout))
14324b588458SPeter Avalos FATAL("write error on stdout");
14334b588458SPeter Avalos } else {
14344b588458SPeter Avalos fp = redirect(ptoi(a[1]), a[2]);
14354b588458SPeter Avalos /* fputs(buf, fp); */
14364b588458SPeter Avalos fwrite(buf, len, 1, fp);
14374b588458SPeter Avalos fflush(fp);
14384b588458SPeter Avalos if (ferror(fp))
14394b588458SPeter Avalos FATAL("write error on %s", filename(fp));
14404b588458SPeter Avalos }
14414b588458SPeter Avalos free(buf);
14424b588458SPeter Avalos return(True);
14434b588458SPeter Avalos }
14444b588458SPeter Avalos
arith(Node ** a,int n)14454b588458SPeter Avalos Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */
14464b588458SPeter Avalos {
14474b588458SPeter Avalos Awkfloat i, j = 0;
14484b588458SPeter Avalos double v;
14494b588458SPeter Avalos Cell *x, *y, *z;
14504b588458SPeter Avalos
14514b588458SPeter Avalos x = execute(a[0]);
14524b588458SPeter Avalos i = getfval(x);
14534b588458SPeter Avalos tempfree(x);
14541d48fce0SDaniel Fojt if (n != UMINUS && n != UPLUS) {
14554b588458SPeter Avalos y = execute(a[1]);
14564b588458SPeter Avalos j = getfval(y);
14574b588458SPeter Avalos tempfree(y);
14584b588458SPeter Avalos }
14594b588458SPeter Avalos z = gettemp();
14604b588458SPeter Avalos switch (n) {
14614b588458SPeter Avalos case ADD:
14624b588458SPeter Avalos i += j;
14634b588458SPeter Avalos break;
14644b588458SPeter Avalos case MINUS:
14654b588458SPeter Avalos i -= j;
14664b588458SPeter Avalos break;
14674b588458SPeter Avalos case MULT:
14684b588458SPeter Avalos i *= j;
14694b588458SPeter Avalos break;
14704b588458SPeter Avalos case DIVIDE:
14714b588458SPeter Avalos if (j == 0)
14724b588458SPeter Avalos FATAL("division by zero");
14734b588458SPeter Avalos i /= j;
14744b588458SPeter Avalos break;
14754b588458SPeter Avalos case MOD:
14764b588458SPeter Avalos if (j == 0)
14774b588458SPeter Avalos FATAL("division by zero in mod");
14784b588458SPeter Avalos modf(i/j, &v);
14794b588458SPeter Avalos i = i - j * v;
14804b588458SPeter Avalos break;
14814b588458SPeter Avalos case UMINUS:
14824b588458SPeter Avalos i = -i;
14834b588458SPeter Avalos break;
14841d48fce0SDaniel Fojt case UPLUS: /* handled by getfval(), above */
14851d48fce0SDaniel Fojt break;
14864b588458SPeter Avalos case POWER:
14874b588458SPeter Avalos if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */
14884b588458SPeter Avalos i = ipow(i, (int) j);
14891d48fce0SDaniel Fojt else {
14901d48fce0SDaniel Fojt errno = 0;
14914b588458SPeter Avalos i = errcheck(pow(i, j), "pow");
14921d48fce0SDaniel Fojt }
14934b588458SPeter Avalos break;
14944b588458SPeter Avalos default: /* can't happen */
14954b588458SPeter Avalos FATAL("illegal arithmetic operator %d", n);
14964b588458SPeter Avalos }
14974b588458SPeter Avalos setfval(z, i);
14984b588458SPeter Avalos return(z);
14994b588458SPeter Avalos }
15004b588458SPeter Avalos
ipow(double x,int n)15014b588458SPeter Avalos double ipow(double x, int n) /* x**n. ought to be done by pow, but isn't always */
15024b588458SPeter Avalos {
15034b588458SPeter Avalos double v;
15044b588458SPeter Avalos
15054b588458SPeter Avalos if (n <= 0)
15064b588458SPeter Avalos return 1;
15074b588458SPeter Avalos v = ipow(x, n/2);
15084b588458SPeter Avalos if (n % 2 == 0)
15094b588458SPeter Avalos return v * v;
15104b588458SPeter Avalos else
15114b588458SPeter Avalos return x * v * v;
15124b588458SPeter Avalos }
15134b588458SPeter Avalos
incrdecr(Node ** a,int n)15144b588458SPeter Avalos Cell *incrdecr(Node **a, int n) /* a[0]++, etc. */
15154b588458SPeter Avalos {
15164b588458SPeter Avalos Cell *x, *z;
15174b588458SPeter Avalos int k;
15184b588458SPeter Avalos Awkfloat xf;
15194b588458SPeter Avalos
15204b588458SPeter Avalos x = execute(a[0]);
15214b588458SPeter Avalos xf = getfval(x);
15224b588458SPeter Avalos k = (n == PREINCR || n == POSTINCR) ? 1 : -1;
15234b588458SPeter Avalos if (n == PREINCR || n == PREDECR) {
15244b588458SPeter Avalos setfval(x, xf + k);
15254b588458SPeter Avalos return(x);
15264b588458SPeter Avalos }
15274b588458SPeter Avalos z = gettemp();
15284b588458SPeter Avalos setfval(z, xf);
15294b588458SPeter Avalos setfval(x, xf + k);
15304b588458SPeter Avalos tempfree(x);
15314b588458SPeter Avalos return(z);
15324b588458SPeter Avalos }
15334b588458SPeter Avalos
assign(Node ** a,int n)15344b588458SPeter Avalos Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */
15354b588458SPeter Avalos { /* this is subtle; don't muck with it. */
15364b588458SPeter Avalos Cell *x, *y;
15374b588458SPeter Avalos Awkfloat xf, yf;
15384b588458SPeter Avalos double v;
15394b588458SPeter Avalos
15404b588458SPeter Avalos y = execute(a[1]);
15414b588458SPeter Avalos x = execute(a[0]);
15424b588458SPeter Avalos if (n == ASSIGN) { /* ordinary assignment */
15431d48fce0SDaniel Fojt if (x == y && !(x->tval & (FLD|REC)) && x != nfloc)
15441d48fce0SDaniel Fojt ; /* self-assignment: leave alone unless it's a field or NF */
15454b588458SPeter Avalos else if ((y->tval & (STR|NUM)) == (STR|NUM)) {
1546*ed569bc2SAaron LI yf = getfval(y);
15474b588458SPeter Avalos setsval(x, getsval(y));
1548*ed569bc2SAaron LI x->fval = yf;
15494b588458SPeter Avalos x->tval |= NUM;
15504b588458SPeter Avalos }
15514b588458SPeter Avalos else if (isstr(y))
15524b588458SPeter Avalos setsval(x, getsval(y));
15534b588458SPeter Avalos else if (isnum(y))
15544b588458SPeter Avalos setfval(x, getfval(y));
15554b588458SPeter Avalos else
15564b588458SPeter Avalos funnyvar(y, "read value of");
15574b588458SPeter Avalos tempfree(y);
15584b588458SPeter Avalos return(x);
15594b588458SPeter Avalos }
15604b588458SPeter Avalos xf = getfval(x);
15614b588458SPeter Avalos yf = getfval(y);
15624b588458SPeter Avalos switch (n) {
15634b588458SPeter Avalos case ADDEQ:
15644b588458SPeter Avalos xf += yf;
15654b588458SPeter Avalos break;
15664b588458SPeter Avalos case SUBEQ:
15674b588458SPeter Avalos xf -= yf;
15684b588458SPeter Avalos break;
15694b588458SPeter Avalos case MULTEQ:
15704b588458SPeter Avalos xf *= yf;
15714b588458SPeter Avalos break;
15724b588458SPeter Avalos case DIVEQ:
15734b588458SPeter Avalos if (yf == 0)
15744b588458SPeter Avalos FATAL("division by zero in /=");
15754b588458SPeter Avalos xf /= yf;
15764b588458SPeter Avalos break;
15774b588458SPeter Avalos case MODEQ:
15784b588458SPeter Avalos if (yf == 0)
15794b588458SPeter Avalos FATAL("division by zero in %%=");
15804b588458SPeter Avalos modf(xf/yf, &v);
15814b588458SPeter Avalos xf = xf - yf * v;
15824b588458SPeter Avalos break;
15834b588458SPeter Avalos case POWEQ:
15844b588458SPeter Avalos if (yf >= 0 && modf(yf, &v) == 0.0) /* pos integer exponent */
15854b588458SPeter Avalos xf = ipow(xf, (int) yf);
15861d48fce0SDaniel Fojt else {
15871d48fce0SDaniel Fojt errno = 0;
15884b588458SPeter Avalos xf = errcheck(pow(xf, yf), "pow");
15891d48fce0SDaniel Fojt }
15904b588458SPeter Avalos break;
15914b588458SPeter Avalos default:
15924b588458SPeter Avalos FATAL("illegal assignment operator %d", n);
15934b588458SPeter Avalos break;
15944b588458SPeter Avalos }
15954b588458SPeter Avalos tempfree(y);
15964b588458SPeter Avalos setfval(x, xf);
15974b588458SPeter Avalos return(x);
15984b588458SPeter Avalos }
15994b588458SPeter Avalos
cat(Node ** a,int q)16004b588458SPeter Avalos Cell *cat(Node **a, int q) /* a[0] cat a[1] */
16014b588458SPeter Avalos {
16024b588458SPeter Avalos Cell *x, *y, *z;
16034b588458SPeter Avalos int n1, n2;
16041d48fce0SDaniel Fojt char *s = NULL;
16051d48fce0SDaniel Fojt int ssz = 0;
16064b588458SPeter Avalos
16074b588458SPeter Avalos x = execute(a[0]);
16081d48fce0SDaniel Fojt n1 = strlen(getsval(x));
160948f09a05SAntonio Huete Jimenez adjbuf(&s, &ssz, n1 + 1, recsize, 0, "cat1");
1610e5e686a0SDaniel Fojt memcpy(s, x->sval, n1);
16111d48fce0SDaniel Fojt
161248f09a05SAntonio Huete Jimenez tempfree(x);
161348f09a05SAntonio Huete Jimenez
16144b588458SPeter Avalos y = execute(a[1]);
16151d48fce0SDaniel Fojt n2 = strlen(getsval(y));
1616e5e686a0SDaniel Fojt adjbuf(&s, &ssz, n1 + n2 + 1, recsize, 0, "cat2");
16171d48fce0SDaniel Fojt memcpy(s + n1, y->sval, n2);
16181d48fce0SDaniel Fojt s[n1 + n2] = '\0';
16191d48fce0SDaniel Fojt
16204b588458SPeter Avalos tempfree(y);
16211d48fce0SDaniel Fojt
16224b588458SPeter Avalos z = gettemp();
16234b588458SPeter Avalos z->sval = s;
16244b588458SPeter Avalos z->tval = STR;
16251d48fce0SDaniel Fojt
16264b588458SPeter Avalos return(z);
16274b588458SPeter Avalos }
16284b588458SPeter Avalos
pastat(Node ** a,int n)16294b588458SPeter Avalos Cell *pastat(Node **a, int n) /* a[0] { a[1] } */
16304b588458SPeter Avalos {
16314b588458SPeter Avalos Cell *x;
16324b588458SPeter Avalos
16331d48fce0SDaniel Fojt if (a[0] == NULL)
16344b588458SPeter Avalos x = execute(a[1]);
16354b588458SPeter Avalos else {
16364b588458SPeter Avalos x = execute(a[0]);
16374b588458SPeter Avalos if (istrue(x)) {
16384b588458SPeter Avalos tempfree(x);
16394b588458SPeter Avalos x = execute(a[1]);
16404b588458SPeter Avalos }
16414b588458SPeter Avalos }
16424b588458SPeter Avalos return x;
16434b588458SPeter Avalos }
16444b588458SPeter Avalos
dopa2(Node ** a,int n)16454b588458SPeter Avalos Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */
16464b588458SPeter Avalos {
16474b588458SPeter Avalos Cell *x;
16484b588458SPeter Avalos int pair;
16494b588458SPeter Avalos
16504b588458SPeter Avalos pair = ptoi(a[3]);
16514b588458SPeter Avalos if (pairstack[pair] == 0) {
16524b588458SPeter Avalos x = execute(a[0]);
16534b588458SPeter Avalos if (istrue(x))
16544b588458SPeter Avalos pairstack[pair] = 1;
16554b588458SPeter Avalos tempfree(x);
16564b588458SPeter Avalos }
16574b588458SPeter Avalos if (pairstack[pair] == 1) {
16584b588458SPeter Avalos x = execute(a[1]);
16594b588458SPeter Avalos if (istrue(x))
16604b588458SPeter Avalos pairstack[pair] = 0;
16614b588458SPeter Avalos tempfree(x);
16624b588458SPeter Avalos x = execute(a[2]);
16634b588458SPeter Avalos return(x);
16644b588458SPeter Avalos }
16654b588458SPeter Avalos return(False);
16664b588458SPeter Avalos }
16674b588458SPeter Avalos
split(Node ** a,int nnn)16684b588458SPeter Avalos Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
16694b588458SPeter Avalos {
16701d48fce0SDaniel Fojt Cell *x = NULL, *y, *ap;
16711d48fce0SDaniel Fojt const char *s, *origs, *t;
16721d48fce0SDaniel Fojt const char *fs = NULL;
16731d48fce0SDaniel Fojt char *origfs = NULL;
16744b588458SPeter Avalos int sep;
16751d48fce0SDaniel Fojt char temp, num[50];
16764b588458SPeter Avalos int n, tempstat, arg3type;
1677*ed569bc2SAaron LI int j;
167848f09a05SAntonio Huete Jimenez double result;
16794b588458SPeter Avalos
16804b588458SPeter Avalos y = execute(a[0]); /* source string */
16812078c1f0SJohn Marino origs = s = strdup(getsval(y));
168248f09a05SAntonio Huete Jimenez tempfree(y);
16834b588458SPeter Avalos arg3type = ptoi(a[3]);
1684*ed569bc2SAaron LI if (a[2] == NULL) { /* BUG: CSV should override implicit fs but not explicit */
16851d48fce0SDaniel Fojt fs = getsval(fsloc);
1686*ed569bc2SAaron LI } else if (arg3type == STRING) { /* split(str,arr,"string") */
16874b588458SPeter Avalos x = execute(a[2]);
16881d48fce0SDaniel Fojt fs = origfs = strdup(getsval(x));
16891d48fce0SDaniel Fojt tempfree(x);
1690*ed569bc2SAaron LI } else if (arg3type == REGEXPR) {
16914b588458SPeter Avalos fs = "(regexpr)"; /* split(str,arr,/regexpr/) */
1692*ed569bc2SAaron LI } else {
16934b588458SPeter Avalos FATAL("illegal type of split");
1694*ed569bc2SAaron LI }
16954b588458SPeter Avalos sep = *fs;
16964b588458SPeter Avalos ap = execute(a[1]); /* array name */
1697*ed569bc2SAaron LI /* BUG 7/26/22: this appears not to reset array: see C1/asplit */
16984b588458SPeter Avalos freesymtab(ap);
1699e5e686a0SDaniel Fojt DPRINTF("split: s=|%s|, a=%s, sep=|%s|\n", s, NN(ap->nval), fs);
17004b588458SPeter Avalos ap->tval &= ~STR;
17014b588458SPeter Avalos ap->tval |= ARR;
17024b588458SPeter Avalos ap->sval = (char *) makesymtab(NSYMTAB);
17034b588458SPeter Avalos
17044b588458SPeter Avalos n = 0;
1705b12bae18SSascha Wildner if (arg3type == REGEXPR && strlen((char*)((fa*)a[2])->restr) == 0) {
1706b12bae18SSascha Wildner /* split(s, a, //); have to arrange that it looks like empty sep */
1707b12bae18SSascha Wildner arg3type = 0;
1708b12bae18SSascha Wildner fs = "";
1709b12bae18SSascha Wildner sep = 0;
1710b12bae18SSascha Wildner }
17114b588458SPeter Avalos if (*s != '\0' && (strlen(fs) > 1 || arg3type == REGEXPR)) { /* reg expr */
17124b588458SPeter Avalos fa *pfa;
17134b588458SPeter Avalos if (arg3type == REGEXPR) { /* it's ready already */
17144b588458SPeter Avalos pfa = (fa *) a[2];
17154b588458SPeter Avalos } else {
17164b588458SPeter Avalos pfa = makedfa(fs, 1);
17174b588458SPeter Avalos }
17184b588458SPeter Avalos if (nematch(pfa,s)) {
17194b588458SPeter Avalos tempstat = pfa->initstat;
17204b588458SPeter Avalos pfa->initstat = 2;
17214b588458SPeter Avalos do {
17224b588458SPeter Avalos n++;
17231d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
17244b588458SPeter Avalos temp = *patbeg;
17251d48fce0SDaniel Fojt setptr(patbeg, '\0');
172648f09a05SAntonio Huete Jimenez if (is_number(s, & result))
172748f09a05SAntonio Huete Jimenez setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
17284b588458SPeter Avalos else
17294b588458SPeter Avalos setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
17301d48fce0SDaniel Fojt setptr(patbeg, temp);
17314b588458SPeter Avalos s = patbeg + patlen;
17321d48fce0SDaniel Fojt if (*(patbeg+patlen-1) == '\0' || *s == '\0') {
17334b588458SPeter Avalos n++;
17341d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
17354b588458SPeter Avalos setsymtab(num, "", 0.0, STR, (Array *) ap->sval);
17364b588458SPeter Avalos pfa->initstat = tempstat;
17374b588458SPeter Avalos goto spdone;
17384b588458SPeter Avalos }
17394b588458SPeter Avalos } while (nematch(pfa,s));
17404b588458SPeter Avalos pfa->initstat = tempstat; /* bwk: has to be here to reset */
17414b588458SPeter Avalos /* cf gsub and refldbld */
17424b588458SPeter Avalos }
17434b588458SPeter Avalos n++;
17441d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
174548f09a05SAntonio Huete Jimenez if (is_number(s, & result))
174648f09a05SAntonio Huete Jimenez setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
17474b588458SPeter Avalos else
17484b588458SPeter Avalos setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
17494b588458SPeter Avalos spdone:
17504b588458SPeter Avalos pfa = NULL;
1751*ed569bc2SAaron LI
1752*ed569bc2SAaron LI } else if (a[2] == NULL && CSV) { /* CSV only if no explicit separator */
1753*ed569bc2SAaron LI char *newt = (char *) malloc(strlen(s)); /* for building new string; reuse for each field */
1754*ed569bc2SAaron LI for (;;) {
1755*ed569bc2SAaron LI char *fr = newt;
1756*ed569bc2SAaron LI n++;
1757*ed569bc2SAaron LI if (*s == '"' ) { /* start of "..." */
1758*ed569bc2SAaron LI for (s++ ; *s != '\0'; ) {
1759*ed569bc2SAaron LI if (*s == '"' && s[1] != '\0' && s[1] == '"') {
1760*ed569bc2SAaron LI s += 2; /* doubled quote */
1761*ed569bc2SAaron LI *fr++ = '"';
1762*ed569bc2SAaron LI } else if (*s == '"' && (s[1] == '\0' || s[1] == ',')) {
1763*ed569bc2SAaron LI s++; /* skip over closing quote */
1764*ed569bc2SAaron LI break;
1765*ed569bc2SAaron LI } else {
1766*ed569bc2SAaron LI *fr++ = *s++;
1767*ed569bc2SAaron LI }
1768*ed569bc2SAaron LI }
1769*ed569bc2SAaron LI *fr++ = 0;
1770*ed569bc2SAaron LI } else { /* unquoted field */
1771*ed569bc2SAaron LI while (*s != ',' && *s != '\0')
1772*ed569bc2SAaron LI *fr++ = *s++;
1773*ed569bc2SAaron LI *fr++ = 0;
1774*ed569bc2SAaron LI }
1775*ed569bc2SAaron LI snprintf(num, sizeof(num), "%d", n);
1776*ed569bc2SAaron LI if (is_number(newt, &result))
1777*ed569bc2SAaron LI setsymtab(num, newt, result, STR|NUM, (Array *) ap->sval);
1778*ed569bc2SAaron LI else
1779*ed569bc2SAaron LI setsymtab(num, newt, 0.0, STR, (Array *) ap->sval);
1780*ed569bc2SAaron LI if (*s++ == '\0')
1781*ed569bc2SAaron LI break;
1782*ed569bc2SAaron LI }
1783*ed569bc2SAaron LI free(newt);
1784*ed569bc2SAaron LI
1785*ed569bc2SAaron LI } else if (!CSV && sep == ' ') { /* usual case: split on white space */
17864b588458SPeter Avalos for (n = 0; ; ) {
17871d48fce0SDaniel Fojt #define ISWS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
17881d48fce0SDaniel Fojt while (ISWS(*s))
17894b588458SPeter Avalos s++;
17901d48fce0SDaniel Fojt if (*s == '\0')
17914b588458SPeter Avalos break;
17924b588458SPeter Avalos n++;
17934b588458SPeter Avalos t = s;
17944b588458SPeter Avalos do
17954b588458SPeter Avalos s++;
17961d48fce0SDaniel Fojt while (*s != '\0' && !ISWS(*s));
17974b588458SPeter Avalos temp = *s;
17981d48fce0SDaniel Fojt setptr(s, '\0');
17991d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
180048f09a05SAntonio Huete Jimenez if (is_number(t, & result))
180148f09a05SAntonio Huete Jimenez setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
18024b588458SPeter Avalos else
18034b588458SPeter Avalos setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
18041d48fce0SDaniel Fojt setptr(s, temp);
18051d48fce0SDaniel Fojt if (*s != '\0')
18064b588458SPeter Avalos s++;
18074b588458SPeter Avalos }
1808*ed569bc2SAaron LI
18094b588458SPeter Avalos } else if (sep == 0) { /* new: split(s, a, "") => 1 char/elem */
1810*ed569bc2SAaron LI for (n = 0; *s != '\0'; s += u8_nextlen(s)) {
1811*ed569bc2SAaron LI char buf[10];
18124b588458SPeter Avalos n++;
18131d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
1814*ed569bc2SAaron LI
1815*ed569bc2SAaron LI for (j = 0; j < u8_nextlen(s); j++) {
1816*ed569bc2SAaron LI buf[j] = s[j];
1817*ed569bc2SAaron LI }
1818*ed569bc2SAaron LI buf[j] = '\0';
1819*ed569bc2SAaron LI
18204b588458SPeter Avalos if (isdigit((uschar)buf[0]))
18214b588458SPeter Avalos setsymtab(num, buf, atof(buf), STR|NUM, (Array *) ap->sval);
18224b588458SPeter Avalos else
18234b588458SPeter Avalos setsymtab(num, buf, 0.0, STR, (Array *) ap->sval);
18244b588458SPeter Avalos }
1825*ed569bc2SAaron LI
1826*ed569bc2SAaron LI } else if (*s != '\0') { /* some random single character */
18274b588458SPeter Avalos for (;;) {
18284b588458SPeter Avalos n++;
18294b588458SPeter Avalos t = s;
18304b588458SPeter Avalos while (*s != sep && *s != '\n' && *s != '\0')
18314b588458SPeter Avalos s++;
18324b588458SPeter Avalos temp = *s;
18331d48fce0SDaniel Fojt setptr(s, '\0');
18341d48fce0SDaniel Fojt snprintf(num, sizeof(num), "%d", n);
183548f09a05SAntonio Huete Jimenez if (is_number(t, & result))
183648f09a05SAntonio Huete Jimenez setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
18374b588458SPeter Avalos else
18384b588458SPeter Avalos setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
18391d48fce0SDaniel Fojt setptr(s, temp);
18401d48fce0SDaniel Fojt if (*s++ == '\0')
18414b588458SPeter Avalos break;
18424b588458SPeter Avalos }
18434b588458SPeter Avalos }
18444b588458SPeter Avalos tempfree(ap);
18451d48fce0SDaniel Fojt xfree(origs);
18461d48fce0SDaniel Fojt xfree(origfs);
18474b588458SPeter Avalos x = gettemp();
18484b588458SPeter Avalos x->tval = NUM;
18494b588458SPeter Avalos x->fval = n;
18504b588458SPeter Avalos return(x);
18514b588458SPeter Avalos }
18524b588458SPeter Avalos
condexpr(Node ** a,int n)18534b588458SPeter Avalos Cell *condexpr(Node **a, int n) /* a[0] ? a[1] : a[2] */
18544b588458SPeter Avalos {
18554b588458SPeter Avalos Cell *x;
18564b588458SPeter Avalos
18574b588458SPeter Avalos x = execute(a[0]);
18584b588458SPeter Avalos if (istrue(x)) {
18594b588458SPeter Avalos tempfree(x);
18604b588458SPeter Avalos x = execute(a[1]);
18614b588458SPeter Avalos } else {
18624b588458SPeter Avalos tempfree(x);
18634b588458SPeter Avalos x = execute(a[2]);
18644b588458SPeter Avalos }
18654b588458SPeter Avalos return(x);
18664b588458SPeter Avalos }
18674b588458SPeter Avalos
ifstat(Node ** a,int n)18684b588458SPeter Avalos Cell *ifstat(Node **a, int n) /* if (a[0]) a[1]; else a[2] */
18694b588458SPeter Avalos {
18704b588458SPeter Avalos Cell *x;
18714b588458SPeter Avalos
18724b588458SPeter Avalos x = execute(a[0]);
18734b588458SPeter Avalos if (istrue(x)) {
18744b588458SPeter Avalos tempfree(x);
18754b588458SPeter Avalos x = execute(a[1]);
18761d48fce0SDaniel Fojt } else if (a[2] != NULL) {
18774b588458SPeter Avalos tempfree(x);
18784b588458SPeter Avalos x = execute(a[2]);
18794b588458SPeter Avalos }
18804b588458SPeter Avalos return(x);
18814b588458SPeter Avalos }
18824b588458SPeter Avalos
whilestat(Node ** a,int n)18834b588458SPeter Avalos Cell *whilestat(Node **a, int n) /* while (a[0]) a[1] */
18844b588458SPeter Avalos {
18854b588458SPeter Avalos Cell *x;
18864b588458SPeter Avalos
18874b588458SPeter Avalos for (;;) {
18884b588458SPeter Avalos x = execute(a[0]);
18894b588458SPeter Avalos if (!istrue(x))
18904b588458SPeter Avalos return(x);
18914b588458SPeter Avalos tempfree(x);
18924b588458SPeter Avalos x = execute(a[1]);
18934b588458SPeter Avalos if (isbreak(x)) {
18944b588458SPeter Avalos x = True;
18954b588458SPeter Avalos return(x);
18964b588458SPeter Avalos }
18974b588458SPeter Avalos if (isnext(x) || isexit(x) || isret(x))
18984b588458SPeter Avalos return(x);
18994b588458SPeter Avalos tempfree(x);
19004b588458SPeter Avalos }
19014b588458SPeter Avalos }
19024b588458SPeter Avalos
dostat(Node ** a,int n)19034b588458SPeter Avalos Cell *dostat(Node **a, int n) /* do a[0]; while(a[1]) */
19044b588458SPeter Avalos {
19054b588458SPeter Avalos Cell *x;
19064b588458SPeter Avalos
19074b588458SPeter Avalos for (;;) {
19084b588458SPeter Avalos x = execute(a[0]);
19094b588458SPeter Avalos if (isbreak(x))
19104b588458SPeter Avalos return True;
19114b588458SPeter Avalos if (isnext(x) || isexit(x) || isret(x))
19124b588458SPeter Avalos return(x);
19134b588458SPeter Avalos tempfree(x);
19144b588458SPeter Avalos x = execute(a[1]);
19154b588458SPeter Avalos if (!istrue(x))
19164b588458SPeter Avalos return(x);
19174b588458SPeter Avalos tempfree(x);
19184b588458SPeter Avalos }
19194b588458SPeter Avalos }
19204b588458SPeter Avalos
forstat(Node ** a,int n)19214b588458SPeter Avalos Cell *forstat(Node **a, int n) /* for (a[0]; a[1]; a[2]) a[3] */
19224b588458SPeter Avalos {
19234b588458SPeter Avalos Cell *x;
19244b588458SPeter Avalos
19254b588458SPeter Avalos x = execute(a[0]);
19264b588458SPeter Avalos tempfree(x);
19274b588458SPeter Avalos for (;;) {
19281d48fce0SDaniel Fojt if (a[1]!=NULL) {
19294b588458SPeter Avalos x = execute(a[1]);
19304b588458SPeter Avalos if (!istrue(x)) return(x);
19314b588458SPeter Avalos else tempfree(x);
19324b588458SPeter Avalos }
19334b588458SPeter Avalos x = execute(a[3]);
19344b588458SPeter Avalos if (isbreak(x)) /* turn off break */
19354b588458SPeter Avalos return True;
19364b588458SPeter Avalos if (isnext(x) || isexit(x) || isret(x))
19374b588458SPeter Avalos return(x);
19384b588458SPeter Avalos tempfree(x);
19394b588458SPeter Avalos x = execute(a[2]);
19404b588458SPeter Avalos tempfree(x);
19414b588458SPeter Avalos }
19424b588458SPeter Avalos }
19434b588458SPeter Avalos
instat(Node ** a,int n)19444b588458SPeter Avalos Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */
19454b588458SPeter Avalos {
19464b588458SPeter Avalos Cell *x, *vp, *arrayp, *cp, *ncp;
19474b588458SPeter Avalos Array *tp;
19484b588458SPeter Avalos int i;
19494b588458SPeter Avalos
19504b588458SPeter Avalos vp = execute(a[0]);
19514b588458SPeter Avalos arrayp = execute(a[1]);
19524b588458SPeter Avalos if (!isarr(arrayp)) {
19534b588458SPeter Avalos return True;
19544b588458SPeter Avalos }
19554b588458SPeter Avalos tp = (Array *) arrayp->sval;
19564b588458SPeter Avalos tempfree(arrayp);
19574b588458SPeter Avalos for (i = 0; i < tp->size; i++) { /* this routine knows too much */
19584b588458SPeter Avalos for (cp = tp->tab[i]; cp != NULL; cp = ncp) {
19594b588458SPeter Avalos setsval(vp, cp->nval);
19604b588458SPeter Avalos ncp = cp->cnext;
19614b588458SPeter Avalos x = execute(a[2]);
19624b588458SPeter Avalos if (isbreak(x)) {
19634b588458SPeter Avalos tempfree(vp);
19644b588458SPeter Avalos return True;
19654b588458SPeter Avalos }
19664b588458SPeter Avalos if (isnext(x) || isexit(x) || isret(x)) {
19674b588458SPeter Avalos tempfree(vp);
19684b588458SPeter Avalos return(x);
19694b588458SPeter Avalos }
19704b588458SPeter Avalos tempfree(x);
19714b588458SPeter Avalos }
19724b588458SPeter Avalos }
19734b588458SPeter Avalos return True;
19744b588458SPeter Avalos }
19754b588458SPeter Avalos
nawk_convert(const char * s,int (* fun_c)(int),wint_t (* fun_wc)(wint_t))19761d48fce0SDaniel Fojt static char *nawk_convert(const char *s, int (*fun_c)(int),
19771d48fce0SDaniel Fojt wint_t (*fun_wc)(wint_t))
19781d48fce0SDaniel Fojt {
19791d48fce0SDaniel Fojt char *buf = NULL;
19801d48fce0SDaniel Fojt char *pbuf = NULL;
19811d48fce0SDaniel Fojt const char *ps = NULL;
19821d48fce0SDaniel Fojt size_t n = 0;
19831d48fce0SDaniel Fojt wchar_t wc;
1984*ed569bc2SAaron LI const size_t sz = awk_mb_cur_max;
1985*ed569bc2SAaron LI int unused;
19861d48fce0SDaniel Fojt
19871d48fce0SDaniel Fojt if (sz == 1) {
19881d48fce0SDaniel Fojt buf = tostring(s);
19891d48fce0SDaniel Fojt
19901d48fce0SDaniel Fojt for (pbuf = buf; *pbuf; pbuf++)
19911d48fce0SDaniel Fojt *pbuf = fun_c((uschar)*pbuf);
19921d48fce0SDaniel Fojt
19931d48fce0SDaniel Fojt return buf;
19941d48fce0SDaniel Fojt } else {
19951d48fce0SDaniel Fojt /* upper/lower character may be shorter/longer */
19961d48fce0SDaniel Fojt buf = tostringN(s, strlen(s) * sz + 1);
19971d48fce0SDaniel Fojt
199848f09a05SAntonio Huete Jimenez (void) mbtowc(NULL, NULL, 0); /* reset internal state */
199948f09a05SAntonio Huete Jimenez /*
200048f09a05SAntonio Huete Jimenez * Reset internal state here too.
200148f09a05SAntonio Huete Jimenez * Assign result to avoid a compiler warning. (Casting to void
200248f09a05SAntonio Huete Jimenez * doesn't work.)
200348f09a05SAntonio Huete Jimenez * Increment said variable to avoid a different warning.
200448f09a05SAntonio Huete Jimenez */
2005*ed569bc2SAaron LI unused = wctomb(NULL, L'\0');
200648f09a05SAntonio Huete Jimenez unused++;
20071d48fce0SDaniel Fojt
20081d48fce0SDaniel Fojt ps = s;
20091d48fce0SDaniel Fojt pbuf = buf;
201048f09a05SAntonio Huete Jimenez while (n = mbtowc(&wc, ps, sz),
20111d48fce0SDaniel Fojt n > 0 && n != (size_t)-1 && n != (size_t)-2)
20121d48fce0SDaniel Fojt {
20131d48fce0SDaniel Fojt ps += n;
20141d48fce0SDaniel Fojt
201548f09a05SAntonio Huete Jimenez n = wctomb(pbuf, fun_wc(wc));
20161d48fce0SDaniel Fojt if (n == (size_t)-1)
20171d48fce0SDaniel Fojt FATAL("illegal wide character %s", s);
20181d48fce0SDaniel Fojt
20191d48fce0SDaniel Fojt pbuf += n;
20201d48fce0SDaniel Fojt }
20211d48fce0SDaniel Fojt
20221d48fce0SDaniel Fojt *pbuf = '\0';
20231d48fce0SDaniel Fojt
20241d48fce0SDaniel Fojt if (n)
20251d48fce0SDaniel Fojt FATAL("illegal byte sequence %s", s);
20261d48fce0SDaniel Fojt
20271d48fce0SDaniel Fojt return buf;
20281d48fce0SDaniel Fojt }
20291d48fce0SDaniel Fojt }
20301d48fce0SDaniel Fojt
203148f09a05SAntonio Huete Jimenez #ifdef __DJGPP__
towupper(wint_t wc)203248f09a05SAntonio Huete Jimenez static wint_t towupper(wint_t wc)
203348f09a05SAntonio Huete Jimenez {
203448f09a05SAntonio Huete Jimenez if (wc >= 0 && wc < 256)
203548f09a05SAntonio Huete Jimenez return toupper(wc & 0xFF);
203648f09a05SAntonio Huete Jimenez
203748f09a05SAntonio Huete Jimenez return wc;
203848f09a05SAntonio Huete Jimenez }
203948f09a05SAntonio Huete Jimenez
towlower(wint_t wc)204048f09a05SAntonio Huete Jimenez static wint_t towlower(wint_t wc)
204148f09a05SAntonio Huete Jimenez {
204248f09a05SAntonio Huete Jimenez if (wc >= 0 && wc < 256)
204348f09a05SAntonio Huete Jimenez return tolower(wc & 0xFF);
204448f09a05SAntonio Huete Jimenez
204548f09a05SAntonio Huete Jimenez return wc;
204648f09a05SAntonio Huete Jimenez }
204748f09a05SAntonio Huete Jimenez #endif
204848f09a05SAntonio Huete Jimenez
nawk_toupper(const char * s)20491d48fce0SDaniel Fojt static char *nawk_toupper(const char *s)
20501d48fce0SDaniel Fojt {
20511d48fce0SDaniel Fojt return nawk_convert(s, toupper, towupper);
20521d48fce0SDaniel Fojt }
20531d48fce0SDaniel Fojt
nawk_tolower(const char * s)20541d48fce0SDaniel Fojt static char *nawk_tolower(const char *s)
20551d48fce0SDaniel Fojt {
20561d48fce0SDaniel Fojt return nawk_convert(s, tolower, towlower);
20571d48fce0SDaniel Fojt }
20581d48fce0SDaniel Fojt
2059*ed569bc2SAaron LI
2060*ed569bc2SAaron LI
bltin(Node ** a,int n)20614b588458SPeter Avalos Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */
20624b588458SPeter Avalos {
20634b588458SPeter Avalos Cell *x, *y;
20644b588458SPeter Avalos Awkfloat u;
20654b588458SPeter Avalos int t;
20660020174dSPeter Avalos Awkfloat tmp;
20671d48fce0SDaniel Fojt char *buf;
20684b588458SPeter Avalos Node *nextarg;
20694b588458SPeter Avalos FILE *fp;
20701d48fce0SDaniel Fojt int status = 0;
2071*ed569bc2SAaron LI int estatus = 0;
20724b588458SPeter Avalos
20734b588458SPeter Avalos t = ptoi(a[0]);
20744b588458SPeter Avalos x = execute(a[1]);
20754b588458SPeter Avalos nextarg = a[1]->nnext;
20764b588458SPeter Avalos switch (t) {
20774b588458SPeter Avalos case FLENGTH:
20784b588458SPeter Avalos if (isarr(x))
20794b588458SPeter Avalos u = ((Array *) x->sval)->nelem; /* GROT. should be function*/
20804b588458SPeter Avalos else
2081*ed569bc2SAaron LI u = u8_strlen(getsval(x));
20824b588458SPeter Avalos break;
20834b588458SPeter Avalos case FLOG:
20841d48fce0SDaniel Fojt errno = 0;
20851d48fce0SDaniel Fojt u = errcheck(log(getfval(x)), "log");
20861d48fce0SDaniel Fojt break;
20874b588458SPeter Avalos case FINT:
20884b588458SPeter Avalos modf(getfval(x), &u); break;
20894b588458SPeter Avalos case FEXP:
20901d48fce0SDaniel Fojt errno = 0;
20911d48fce0SDaniel Fojt u = errcheck(exp(getfval(x)), "exp");
20921d48fce0SDaniel Fojt break;
20934b588458SPeter Avalos case FSQRT:
20941d48fce0SDaniel Fojt errno = 0;
20951d48fce0SDaniel Fojt u = errcheck(sqrt(getfval(x)), "sqrt");
20961d48fce0SDaniel Fojt break;
20974b588458SPeter Avalos case FSIN:
20984b588458SPeter Avalos u = sin(getfval(x)); break;
20994b588458SPeter Avalos case FCOS:
21004b588458SPeter Avalos u = cos(getfval(x)); break;
21014b588458SPeter Avalos case FATAN:
21021d48fce0SDaniel Fojt if (nextarg == NULL) {
21034b588458SPeter Avalos WARNING("atan2 requires two arguments; returning 1.0");
21044b588458SPeter Avalos u = 1.0;
21054b588458SPeter Avalos } else {
21064b588458SPeter Avalos y = execute(a[1]->nnext);
21074b588458SPeter Avalos u = atan2(getfval(x), getfval(y));
21084b588458SPeter Avalos tempfree(y);
21094b588458SPeter Avalos nextarg = nextarg->nnext;
21104b588458SPeter Avalos }
21114b588458SPeter Avalos break;
21124b588458SPeter Avalos case FSYSTEM:
21134b588458SPeter Avalos fflush(stdout); /* in case something is buffered already */
2114*ed569bc2SAaron LI estatus = status = system(getsval(x));
21151d48fce0SDaniel Fojt if (status != -1) {
21161d48fce0SDaniel Fojt if (WIFEXITED(status)) {
2117*ed569bc2SAaron LI estatus = WEXITSTATUS(status);
21181d48fce0SDaniel Fojt } else if (WIFSIGNALED(status)) {
2119*ed569bc2SAaron LI estatus = WTERMSIG(status) + 256;
21201d48fce0SDaniel Fojt #ifdef WCOREDUMP
21211d48fce0SDaniel Fojt if (WCOREDUMP(status))
2122*ed569bc2SAaron LI estatus += 256;
21231d48fce0SDaniel Fojt #endif
21241d48fce0SDaniel Fojt } else /* something else?!? */
2125*ed569bc2SAaron LI estatus = 0;
21261d48fce0SDaniel Fojt }
2127*ed569bc2SAaron LI /* else estatus was set to -1 */
2128*ed569bc2SAaron LI u = estatus;
21294b588458SPeter Avalos break;
21304b588458SPeter Avalos case FRAND:
21311d48fce0SDaniel Fojt /* random() returns numbers in [0..2^31-1]
21321d48fce0SDaniel Fojt * in order to get a number in [0, 1), divide it by 2^31
21331d48fce0SDaniel Fojt */
21341d48fce0SDaniel Fojt u = (Awkfloat) random() / (0x7fffffffL + 0x1UL);
21354b588458SPeter Avalos break;
21364b588458SPeter Avalos case FSRAND:
21374b588458SPeter Avalos if (isrec(x)) /* no argument provided */
21384b588458SPeter Avalos u = time((time_t *)0);
21394b588458SPeter Avalos else
21404b588458SPeter Avalos u = getfval(x);
21410020174dSPeter Avalos tmp = u;
21421d48fce0SDaniel Fojt srandom((unsigned long) u);
21430020174dSPeter Avalos u = srand_seed;
21440020174dSPeter Avalos srand_seed = tmp;
21454b588458SPeter Avalos break;
21464b588458SPeter Avalos case FTOUPPER:
21474b588458SPeter Avalos case FTOLOWER:
21481d48fce0SDaniel Fojt if (t == FTOUPPER)
21491d48fce0SDaniel Fojt buf = nawk_toupper(getsval(x));
21501d48fce0SDaniel Fojt else
21511d48fce0SDaniel Fojt buf = nawk_tolower(getsval(x));
21524b588458SPeter Avalos tempfree(x);
21534b588458SPeter Avalos x = gettemp();
21544b588458SPeter Avalos setsval(x, buf);
21554b588458SPeter Avalos free(buf);
21564b588458SPeter Avalos return x;
21574b588458SPeter Avalos case FFLUSH:
21584b588458SPeter Avalos if (isrec(x) || strlen(getsval(x)) == 0) {
21594b588458SPeter Avalos flush_all(); /* fflush() or fflush("") -> all */
21604b588458SPeter Avalos u = 0;
21611d48fce0SDaniel Fojt } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL)
21624b588458SPeter Avalos u = EOF;
21634b588458SPeter Avalos else
21644b588458SPeter Avalos u = fflush(fp);
21654b588458SPeter Avalos break;
21664b588458SPeter Avalos default: /* can't happen */
21674b588458SPeter Avalos FATAL("illegal function type %d", t);
21684b588458SPeter Avalos break;
21694b588458SPeter Avalos }
21704b588458SPeter Avalos tempfree(x);
21714b588458SPeter Avalos x = gettemp();
21724b588458SPeter Avalos setfval(x, u);
21731d48fce0SDaniel Fojt if (nextarg != NULL) {
21744b588458SPeter Avalos WARNING("warning: function has too many arguments");
217548f09a05SAntonio Huete Jimenez for ( ; nextarg; nextarg = nextarg->nnext) {
217648f09a05SAntonio Huete Jimenez y = execute(nextarg);
217748f09a05SAntonio Huete Jimenez tempfree(y);
217848f09a05SAntonio Huete Jimenez }
21794b588458SPeter Avalos }
21804b588458SPeter Avalos return(x);
21814b588458SPeter Avalos }
21824b588458SPeter Avalos
printstat(Node ** a,int n)21834b588458SPeter Avalos Cell *printstat(Node **a, int n) /* print a[0] */
21844b588458SPeter Avalos {
21854b588458SPeter Avalos Node *x;
21864b588458SPeter Avalos Cell *y;
21874b588458SPeter Avalos FILE *fp;
21884b588458SPeter Avalos
21891d48fce0SDaniel Fojt if (a[1] == NULL) /* a[1] is redirection operator, a[2] is file */
21904b588458SPeter Avalos fp = stdout;
21914b588458SPeter Avalos else
21924b588458SPeter Avalos fp = redirect(ptoi(a[1]), a[2]);
21934b588458SPeter Avalos for (x = a[0]; x != NULL; x = x->nnext) {
21944b588458SPeter Avalos y = execute(x);
21954b588458SPeter Avalos fputs(getpssval(y), fp);
21964b588458SPeter Avalos tempfree(y);
21974b588458SPeter Avalos if (x->nnext == NULL)
21981d48fce0SDaniel Fojt fputs(getsval(orsloc), fp);
21994b588458SPeter Avalos else
22001d48fce0SDaniel Fojt fputs(getsval(ofsloc), fp);
22014b588458SPeter Avalos }
22021d48fce0SDaniel Fojt if (a[1] != NULL)
22034b588458SPeter Avalos fflush(fp);
22044b588458SPeter Avalos if (ferror(fp))
22054b588458SPeter Avalos FATAL("write error on %s", filename(fp));
22064b588458SPeter Avalos return(True);
22074b588458SPeter Avalos }
22084b588458SPeter Avalos
nullproc(Node ** a,int n)22094b588458SPeter Avalos Cell *nullproc(Node **a, int n)
22104b588458SPeter Avalos {
22114b588458SPeter Avalos return 0;
22124b588458SPeter Avalos }
22134b588458SPeter Avalos
22144b588458SPeter Avalos
redirect(int a,Node * b)22154b588458SPeter Avalos FILE *redirect(int a, Node *b) /* set up all i/o redirections */
22164b588458SPeter Avalos {
22174b588458SPeter Avalos FILE *fp;
22184b588458SPeter Avalos Cell *x;
22194b588458SPeter Avalos char *fname;
22204b588458SPeter Avalos
22214b588458SPeter Avalos x = execute(b);
22224b588458SPeter Avalos fname = getsval(x);
22231d48fce0SDaniel Fojt fp = openfile(a, fname, NULL);
22244b588458SPeter Avalos if (fp == NULL)
22254b588458SPeter Avalos FATAL("can't open file %s", fname);
22264b588458SPeter Avalos tempfree(x);
22274b588458SPeter Avalos return fp;
22284b588458SPeter Avalos }
22294b588458SPeter Avalos
22304b588458SPeter Avalos struct files {
22314b588458SPeter Avalos FILE *fp;
22324b588458SPeter Avalos const char *fname;
22334b588458SPeter Avalos int mode; /* '|', 'a', 'w' => LE/LT, GT */
2234b12bae18SSascha Wildner } *files;
2235b12bae18SSascha Wildner
22361d48fce0SDaniel Fojt size_t nfiles;
22374b588458SPeter Avalos
stdinit(void)22381d48fce0SDaniel Fojt static void stdinit(void) /* in case stdin, etc., are not constants */
22394b588458SPeter Avalos {
2240b12bae18SSascha Wildner nfiles = FOPEN_MAX;
224148f09a05SAntonio Huete Jimenez files = (struct files *) calloc(nfiles, sizeof(*files));
2242b12bae18SSascha Wildner if (files == NULL)
22431d48fce0SDaniel Fojt FATAL("can't allocate file memory for %zu files", nfiles);
22444b588458SPeter Avalos files[0].fp = stdin;
224548f09a05SAntonio Huete Jimenez files[0].fname = tostring("/dev/stdin");
2246b12bae18SSascha Wildner files[0].mode = LT;
22474b588458SPeter Avalos files[1].fp = stdout;
224848f09a05SAntonio Huete Jimenez files[1].fname = tostring("/dev/stdout");
2249b12bae18SSascha Wildner files[1].mode = GT;
22504b588458SPeter Avalos files[2].fp = stderr;
225148f09a05SAntonio Huete Jimenez files[2].fname = tostring("/dev/stderr");
2252b12bae18SSascha Wildner files[2].mode = GT;
22534b588458SPeter Avalos }
22544b588458SPeter Avalos
openfile(int a,const char * us,bool * pnewflag)22551d48fce0SDaniel Fojt FILE *openfile(int a, const char *us, bool *pnewflag)
22564b588458SPeter Avalos {
22574b588458SPeter Avalos const char *s = us;
22581d48fce0SDaniel Fojt size_t i;
22591d48fce0SDaniel Fojt int m;
22601d48fce0SDaniel Fojt FILE *fp = NULL;
22614b588458SPeter Avalos
22624b588458SPeter Avalos if (*s == '\0')
22634b588458SPeter Avalos FATAL("null file name in print or getline");
2264b12bae18SSascha Wildner for (i = 0; i < nfiles; i++)
22651d48fce0SDaniel Fojt if (files[i].fname && strcmp(s, files[i].fname) == 0 &&
22661d48fce0SDaniel Fojt (a == files[i].mode || (a==APPEND && files[i].mode==GT) ||
22671d48fce0SDaniel Fojt a == FFLUSH)) {
22681d48fce0SDaniel Fojt if (pnewflag)
22691d48fce0SDaniel Fojt *pnewflag = false;
22704b588458SPeter Avalos return files[i].fp;
22714b588458SPeter Avalos }
22724b588458SPeter Avalos if (a == FFLUSH) /* didn't find it, so don't create it! */
22734b588458SPeter Avalos return NULL;
22744b588458SPeter Avalos
2275b12bae18SSascha Wildner for (i = 0; i < nfiles; i++)
22761d48fce0SDaniel Fojt if (files[i].fp == NULL)
22774b588458SPeter Avalos break;
2278b12bae18SSascha Wildner if (i >= nfiles) {
2279b12bae18SSascha Wildner struct files *nf;
22801d48fce0SDaniel Fojt size_t nnf = nfiles + FOPEN_MAX;
228148f09a05SAntonio Huete Jimenez nf = (struct files *) realloc(files, nnf * sizeof(*nf));
2282b12bae18SSascha Wildner if (nf == NULL)
22831d48fce0SDaniel Fojt FATAL("cannot grow files for %s and %zu files", s, nnf);
2284b12bae18SSascha Wildner memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
2285b12bae18SSascha Wildner nfiles = nnf;
2286b12bae18SSascha Wildner files = nf;
2287b12bae18SSascha Wildner }
22884b588458SPeter Avalos fflush(stdout); /* force a semblance of order */
22894b588458SPeter Avalos m = a;
22904b588458SPeter Avalos if (a == GT) {
22914b588458SPeter Avalos fp = fopen(s, "w");
22924b588458SPeter Avalos } else if (a == APPEND) {
22934b588458SPeter Avalos fp = fopen(s, "a");
22944b588458SPeter Avalos m = GT; /* so can mix > and >> */
22954b588458SPeter Avalos } else if (a == '|') { /* output pipe */
22964b588458SPeter Avalos fp = popen(s, "w");
22974b588458SPeter Avalos } else if (a == LE) { /* input pipe */
22984b588458SPeter Avalos fp = popen(s, "r");
22994b588458SPeter Avalos } else if (a == LT) { /* getline <file */
23004b588458SPeter Avalos fp = strcmp(s, "-") == 0 ? stdin : fopen(s, "r"); /* "-" is stdin */
23014b588458SPeter Avalos } else /* can't happen */
23024b588458SPeter Avalos FATAL("illegal redirection %d", a);
23034b588458SPeter Avalos if (fp != NULL) {
23044b588458SPeter Avalos files[i].fname = tostring(s);
23054b588458SPeter Avalos files[i].fp = fp;
23064b588458SPeter Avalos files[i].mode = m;
23071d48fce0SDaniel Fojt if (pnewflag)
23081d48fce0SDaniel Fojt *pnewflag = true;
23091d48fce0SDaniel Fojt if (fp != stdin && fp != stdout && fp != stderr)
23101d48fce0SDaniel Fojt (void) fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
23114b588458SPeter Avalos }
23124b588458SPeter Avalos return fp;
23134b588458SPeter Avalos }
23144b588458SPeter Avalos
filename(FILE * fp)23154b588458SPeter Avalos const char *filename(FILE *fp)
23164b588458SPeter Avalos {
23171d48fce0SDaniel Fojt size_t i;
23184b588458SPeter Avalos
2319b12bae18SSascha Wildner for (i = 0; i < nfiles; i++)
23204b588458SPeter Avalos if (fp == files[i].fp)
23214b588458SPeter Avalos return files[i].fname;
23224b588458SPeter Avalos return "???";
23234b588458SPeter Avalos }
23244b588458SPeter Avalos
closefile(Node ** a,int n)23254b588458SPeter Avalos Cell *closefile(Node **a, int n)
23264b588458SPeter Avalos {
23274b588458SPeter Avalos Cell *x;
23281d48fce0SDaniel Fojt size_t i;
23291d48fce0SDaniel Fojt bool stat;
23304b588458SPeter Avalos
23314b588458SPeter Avalos x = execute(a[0]);
23324b588458SPeter Avalos getsval(x);
23331d48fce0SDaniel Fojt stat = true;
2334b12bae18SSascha Wildner for (i = 0; i < nfiles; i++) {
23351d48fce0SDaniel Fojt if (!files[i].fname || strcmp(x->sval, files[i].fname) != 0)
23361d48fce0SDaniel Fojt continue;
233748f09a05SAntonio Huete Jimenez if (files[i].mode == GT || files[i].mode == '|')
233848f09a05SAntonio Huete Jimenez fflush(files[i].fp);
233948f09a05SAntonio Huete Jimenez if (ferror(files[i].fp)) {
234048f09a05SAntonio Huete Jimenez if ((files[i].mode == GT && files[i].fp != stderr)
234148f09a05SAntonio Huete Jimenez || files[i].mode == '|')
234248f09a05SAntonio Huete Jimenez FATAL("write error on %s", files[i].fname);
234348f09a05SAntonio Huete Jimenez else
234448f09a05SAntonio Huete Jimenez WARNING("i/o error occurred on %s", files[i].fname);
234548f09a05SAntonio Huete Jimenez }
234648f09a05SAntonio Huete Jimenez if (files[i].fp == stdin || files[i].fp == stdout ||
234748f09a05SAntonio Huete Jimenez files[i].fp == stderr)
234848f09a05SAntonio Huete Jimenez stat = freopen("/dev/null", "r+", files[i].fp) == NULL;
234948f09a05SAntonio Huete Jimenez else if (files[i].mode == '|' || files[i].mode == LE)
23501d48fce0SDaniel Fojt stat = pclose(files[i].fp) == -1;
23514b588458SPeter Avalos else
23521d48fce0SDaniel Fojt stat = fclose(files[i].fp) == EOF;
23531d48fce0SDaniel Fojt if (stat)
235448f09a05SAntonio Huete Jimenez WARNING("i/o error occurred closing %s", files[i].fname);
23554b588458SPeter Avalos xfree(files[i].fname);
23564b588458SPeter Avalos files[i].fname = NULL; /* watch out for ref thru this */
23574b588458SPeter Avalos files[i].fp = NULL;
235848f09a05SAntonio Huete Jimenez break;
23594b588458SPeter Avalos }
23604b588458SPeter Avalos tempfree(x);
23614b588458SPeter Avalos x = gettemp();
23621d48fce0SDaniel Fojt setfval(x, (Awkfloat) (stat ? -1 : 0));
23634b588458SPeter Avalos return(x);
23644b588458SPeter Avalos }
23654b588458SPeter Avalos
closeall(void)23664b588458SPeter Avalos void closeall(void)
23674b588458SPeter Avalos {
23681d48fce0SDaniel Fojt size_t i;
23691d48fce0SDaniel Fojt bool stat = false;
23704b588458SPeter Avalos
23711d48fce0SDaniel Fojt for (i = 0; i < nfiles; i++) {
23721d48fce0SDaniel Fojt if (! files[i].fp)
23731d48fce0SDaniel Fojt continue;
237448f09a05SAntonio Huete Jimenez if (files[i].mode == GT || files[i].mode == '|')
237548f09a05SAntonio Huete Jimenez fflush(files[i].fp);
237648f09a05SAntonio Huete Jimenez if (ferror(files[i].fp)) {
237748f09a05SAntonio Huete Jimenez if ((files[i].mode == GT && files[i].fp != stderr)
237848f09a05SAntonio Huete Jimenez || files[i].mode == '|')
237948f09a05SAntonio Huete Jimenez FATAL("write error on %s", files[i].fname);
238048f09a05SAntonio Huete Jimenez else
238148f09a05SAntonio Huete Jimenez WARNING("i/o error occurred on %s", files[i].fname);
238248f09a05SAntonio Huete Jimenez }
238348f09a05SAntonio Huete Jimenez if (files[i].fp == stdin || files[i].fp == stdout ||
238448f09a05SAntonio Huete Jimenez files[i].fp == stderr)
238548f09a05SAntonio Huete Jimenez continue;
23864b588458SPeter Avalos if (files[i].mode == '|' || files[i].mode == LE)
23871d48fce0SDaniel Fojt stat = pclose(files[i].fp) == -1;
23884b588458SPeter Avalos else
23891d48fce0SDaniel Fojt stat = fclose(files[i].fp) == EOF;
23901d48fce0SDaniel Fojt if (stat)
239148f09a05SAntonio Huete Jimenez WARNING("i/o error occurred while closing %s", files[i].fname);
23924b588458SPeter Avalos }
23934b588458SPeter Avalos }
23944b588458SPeter Avalos
flush_all(void)23951d48fce0SDaniel Fojt static void flush_all(void)
23964b588458SPeter Avalos {
23971d48fce0SDaniel Fojt size_t i;
23984b588458SPeter Avalos
2399b12bae18SSascha Wildner for (i = 0; i < nfiles; i++)
24004b588458SPeter Avalos if (files[i].fp)
24014b588458SPeter Avalos fflush(files[i].fp);
24024b588458SPeter Avalos }
24034b588458SPeter Avalos
24041d48fce0SDaniel Fojt void backsub(char **pb_ptr, const char **sptr_ptr);
24054b588458SPeter Avalos
dosub(Node ** a,int subop)2406*ed569bc2SAaron LI Cell *dosub(Node **a, int subop) /* sub and gsub */
24074b588458SPeter Avalos {
24084b588458SPeter Avalos fa *pfa;
2409*ed569bc2SAaron LI int tempstat;
2410*ed569bc2SAaron LI char *repl;
2411*ed569bc2SAaron LI Cell *x;
2412*ed569bc2SAaron LI
2413*ed569bc2SAaron LI char *buf = NULL;
2414*ed569bc2SAaron LI char *pb = NULL;
24154b588458SPeter Avalos int bufsz = recsize;
24164b588458SPeter Avalos
2417*ed569bc2SAaron LI const char *r, *s;
2418*ed569bc2SAaron LI const char *start;
2419*ed569bc2SAaron LI const char *noempty = NULL; /* empty match disallowed here */
2420*ed569bc2SAaron LI size_t m = 0; /* match count */
2421*ed569bc2SAaron LI size_t whichm; /* which match to select, 0 = global */
2422*ed569bc2SAaron LI int mtype; /* match type */
2423*ed569bc2SAaron LI
2424*ed569bc2SAaron LI if (a[0] == NULL) { /* 0 => a[1] is already-compiled regexpr */
2425*ed569bc2SAaron LI pfa = (fa *) a[1];
2426*ed569bc2SAaron LI } else {
2427*ed569bc2SAaron LI x = execute(a[1]);
2428*ed569bc2SAaron LI pfa = makedfa(getsval(x), 1);
24294b588458SPeter Avalos tempfree(x);
24304b588458SPeter Avalos }
24314b588458SPeter Avalos
2432*ed569bc2SAaron LI x = execute(a[2]); /* replacement string */
2433*ed569bc2SAaron LI repl = tostring(getsval(x));
2434*ed569bc2SAaron LI tempfree(x);
24354b588458SPeter Avalos
2436*ed569bc2SAaron LI switch (subop) {
2437*ed569bc2SAaron LI case SUB:
2438*ed569bc2SAaron LI whichm = 1;
2439*ed569bc2SAaron LI x = execute(a[3]); /* source string */
2440*ed569bc2SAaron LI break;
2441*ed569bc2SAaron LI case GSUB:
2442*ed569bc2SAaron LI whichm = 0;
2443*ed569bc2SAaron LI x = execute(a[3]); /* source string */
2444*ed569bc2SAaron LI break;
2445*ed569bc2SAaron LI default:
2446*ed569bc2SAaron LI FATAL("dosub: unrecognized subop: %d", subop);
24474b588458SPeter Avalos }
2448*ed569bc2SAaron LI
2449*ed569bc2SAaron LI start = getsval(x);
2450*ed569bc2SAaron LI while (pmatch(pfa, start)) {
2451*ed569bc2SAaron LI if (buf == NULL) {
2452*ed569bc2SAaron LI if ((pb = buf = (char *) malloc(bufsz)) == NULL)
2453*ed569bc2SAaron LI FATAL("out of memory in dosub");
24544b588458SPeter Avalos tempstat = pfa->initstat;
24554b588458SPeter Avalos pfa->initstat = 2;
2456*ed569bc2SAaron LI }
2457*ed569bc2SAaron LI
2458*ed569bc2SAaron LI /* match types */
2459*ed569bc2SAaron LI #define MT_IGNORE 0 /* unselected or invalid */
2460*ed569bc2SAaron LI #define MT_INSERT 1 /* selected, empty */
2461*ed569bc2SAaron LI #define MT_REPLACE 2 /* selected, not empty */
2462*ed569bc2SAaron LI
2463*ed569bc2SAaron LI /* an empty match just after replacement is invalid */
2464*ed569bc2SAaron LI
2465*ed569bc2SAaron LI if (patbeg == noempty && patlen == 0) {
2466*ed569bc2SAaron LI mtype = MT_IGNORE; /* invalid, not counted */
2467*ed569bc2SAaron LI } else if (whichm == ++m || whichm == 0) {
2468*ed569bc2SAaron LI mtype = patlen ? MT_REPLACE : MT_INSERT;
2469*ed569bc2SAaron LI } else {
2470*ed569bc2SAaron LI mtype = MT_IGNORE; /* unselected, but counted */
2471*ed569bc2SAaron LI }
2472*ed569bc2SAaron LI
2473*ed569bc2SAaron LI /* leading text: */
2474*ed569bc2SAaron LI if (patbeg > start) {
2475*ed569bc2SAaron LI adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - start),
2476*ed569bc2SAaron LI recsize, &pb, "dosub");
2477*ed569bc2SAaron LI s = start;
2478*ed569bc2SAaron LI while (s < patbeg)
2479*ed569bc2SAaron LI *pb++ = *s++;
2480*ed569bc2SAaron LI }
2481*ed569bc2SAaron LI
2482*ed569bc2SAaron LI if (mtype == MT_IGNORE)
2483*ed569bc2SAaron LI goto matching_text; /* skip replacement text */
2484*ed569bc2SAaron LI
2485*ed569bc2SAaron LI r = repl;
2486*ed569bc2SAaron LI while (*r != 0) {
2487*ed569bc2SAaron LI adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "dosub");
2488*ed569bc2SAaron LI if (*r == '\\') {
2489*ed569bc2SAaron LI backsub(&pb, &r);
2490*ed569bc2SAaron LI } else if (*r == '&') {
2491*ed569bc2SAaron LI r++;
2492*ed569bc2SAaron LI adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize,
2493*ed569bc2SAaron LI &pb, "dosub");
2494*ed569bc2SAaron LI for (s = patbeg; s < patbeg+patlen; )
2495*ed569bc2SAaron LI *pb++ = *s++;
2496*ed569bc2SAaron LI } else {
2497*ed569bc2SAaron LI *pb++ = *r++;
24984b588458SPeter Avalos }
24994b588458SPeter Avalos }
2500*ed569bc2SAaron LI
2501*ed569bc2SAaron LI matching_text:
2502*ed569bc2SAaron LI if (mtype == MT_REPLACE || *patbeg == '\0')
2503*ed569bc2SAaron LI goto next_search; /* skip matching text */
2504*ed569bc2SAaron LI
2505*ed569bc2SAaron LI if (patlen == 0)
2506*ed569bc2SAaron LI patlen = u8_nextlen(patbeg);
2507*ed569bc2SAaron LI adjbuf(&buf, &bufsz, (pb-buf) + patlen, recsize, &pb, "dosub");
2508*ed569bc2SAaron LI s = patbeg;
2509*ed569bc2SAaron LI while (s < patbeg + patlen)
2510*ed569bc2SAaron LI *pb++ = *s++;
2511*ed569bc2SAaron LI
2512*ed569bc2SAaron LI next_search:
2513*ed569bc2SAaron LI start = patbeg + patlen;
2514*ed569bc2SAaron LI if (m == whichm || *patbeg == '\0')
2515*ed569bc2SAaron LI break;
2516*ed569bc2SAaron LI if (mtype == MT_REPLACE)
2517*ed569bc2SAaron LI noempty = start;
2518*ed569bc2SAaron LI
2519*ed569bc2SAaron LI #undef MT_IGNORE
2520*ed569bc2SAaron LI #undef MT_INSERT
2521*ed569bc2SAaron LI #undef MT_REPLACE
25224b588458SPeter Avalos }
2523*ed569bc2SAaron LI
2524*ed569bc2SAaron LI xfree(repl);
2525*ed569bc2SAaron LI
2526*ed569bc2SAaron LI if (buf != NULL) {
25274b588458SPeter Avalos pfa->initstat = tempstat;
2528*ed569bc2SAaron LI
2529*ed569bc2SAaron LI /* trailing text */
2530*ed569bc2SAaron LI adjbuf(&buf, &bufsz, 1+strlen(start)+pb-buf, 0, &pb, "dosub");
2531*ed569bc2SAaron LI while ((*pb++ = *start++) != '\0')
2532*ed569bc2SAaron LI ;
2533*ed569bc2SAaron LI
2534*ed569bc2SAaron LI setsval(x, buf);
2535*ed569bc2SAaron LI free(buf);
25364b588458SPeter Avalos }
2537*ed569bc2SAaron LI
25384b588458SPeter Avalos tempfree(x);
25394b588458SPeter Avalos x = gettemp();
25404b588458SPeter Avalos x->tval = NUM;
2541*ed569bc2SAaron LI x->fval = m;
2542*ed569bc2SAaron LI return x;
25434b588458SPeter Avalos }
25444b588458SPeter Avalos
backsub(char ** pb_ptr,const char ** sptr_ptr)25451d48fce0SDaniel Fojt void backsub(char **pb_ptr, const char **sptr_ptr) /* handle \\& variations */
25464b588458SPeter Avalos { /* sptr[0] == '\\' */
25471d48fce0SDaniel Fojt char *pb = *pb_ptr;
25481d48fce0SDaniel Fojt const char *sptr = *sptr_ptr;
25491d48fce0SDaniel Fojt static bool first = true;
25501d48fce0SDaniel Fojt static bool do_posix = false;
25511d48fce0SDaniel Fojt
25521d48fce0SDaniel Fojt if (first) {
25531d48fce0SDaniel Fojt first = false;
25541d48fce0SDaniel Fojt do_posix = (getenv("POSIXLY_CORRECT") != NULL);
25551d48fce0SDaniel Fojt }
25564b588458SPeter Avalos
25574b588458SPeter Avalos if (sptr[1] == '\\') {
25584b588458SPeter Avalos if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */
25594b588458SPeter Avalos *pb++ = '\\';
25604b588458SPeter Avalos *pb++ = '&';
25614b588458SPeter Avalos sptr += 4;
25624b588458SPeter Avalos } else if (sptr[2] == '&') { /* \\& -> \ + matched */
25634b588458SPeter Avalos *pb++ = '\\';
25644b588458SPeter Avalos sptr += 2;
25651d48fce0SDaniel Fojt } else if (do_posix) { /* \\x -> \x */
25661d48fce0SDaniel Fojt sptr++;
25671d48fce0SDaniel Fojt *pb++ = *sptr++;
25684b588458SPeter Avalos } else { /* \\x -> \\x */
25694b588458SPeter Avalos *pb++ = *sptr++;
25704b588458SPeter Avalos *pb++ = *sptr++;
25714b588458SPeter Avalos }
25724b588458SPeter Avalos } else if (sptr[1] == '&') { /* literal & */
25734b588458SPeter Avalos sptr++;
25744b588458SPeter Avalos *pb++ = *sptr++;
25754b588458SPeter Avalos } else /* literal \ */
25764b588458SPeter Avalos *pb++ = *sptr++;
25774b588458SPeter Avalos
25784b588458SPeter Avalos *pb_ptr = pb;
25794b588458SPeter Avalos *sptr_ptr = sptr;
25804b588458SPeter Avalos }
2581*ed569bc2SAaron LI
wide_char_to_byte_str(int rune,size_t * outlen)2582*ed569bc2SAaron LI static char *wide_char_to_byte_str(int rune, size_t *outlen)
2583*ed569bc2SAaron LI {
2584*ed569bc2SAaron LI static char buf[5];
2585*ed569bc2SAaron LI int len;
2586*ed569bc2SAaron LI
2587*ed569bc2SAaron LI if (rune < 0 || rune > 0x10FFFF)
2588*ed569bc2SAaron LI return NULL;
2589*ed569bc2SAaron LI
2590*ed569bc2SAaron LI memset(buf, 0, sizeof(buf));
2591*ed569bc2SAaron LI
2592*ed569bc2SAaron LI len = 0;
2593*ed569bc2SAaron LI if (rune <= 0x0000007F) {
2594*ed569bc2SAaron LI buf[len++] = rune;
2595*ed569bc2SAaron LI } else if (rune <= 0x000007FF) {
2596*ed569bc2SAaron LI // 110xxxxx 10xxxxxx
2597*ed569bc2SAaron LI buf[len++] = 0xC0 | (rune >> 6);
2598*ed569bc2SAaron LI buf[len++] = 0x80 | (rune & 0x3F);
2599*ed569bc2SAaron LI } else if (rune <= 0x0000FFFF) {
2600*ed569bc2SAaron LI // 1110xxxx 10xxxxxx 10xxxxxx
2601*ed569bc2SAaron LI buf[len++] = 0xE0 | (rune >> 12);
2602*ed569bc2SAaron LI buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2603*ed569bc2SAaron LI buf[len++] = 0x80 | (rune & 0x3F);
2604*ed569bc2SAaron LI
2605*ed569bc2SAaron LI } else {
2606*ed569bc2SAaron LI // 0x00010000 - 0x10FFFF
2607*ed569bc2SAaron LI // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
2608*ed569bc2SAaron LI buf[len++] = 0xF0 | (rune >> 18);
2609*ed569bc2SAaron LI buf[len++] = 0x80 | ((rune >> 12) & 0x3F);
2610*ed569bc2SAaron LI buf[len++] = 0x80 | ((rune >> 6) & 0x3F);
2611*ed569bc2SAaron LI buf[len++] = 0x80 | (rune & 0x3F);
2612*ed569bc2SAaron LI }
2613*ed569bc2SAaron LI
2614*ed569bc2SAaron LI *outlen = len;
2615*ed569bc2SAaron LI buf[len++] = '\0';
2616*ed569bc2SAaron LI
2617*ed569bc2SAaron LI return buf;
2618*ed569bc2SAaron LI }
2619