xref: /dflybsd-src/contrib/awk/run.c (revision e2ee60a4f1757f9ded9e1041053222b631f387b6)
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