xref: /dflybsd-src/contrib/awk/tran.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 <math.h>
284b588458SPeter Avalos #include <ctype.h>
294b588458SPeter Avalos #include <string.h>
304b588458SPeter Avalos #include <stdlib.h>
314b588458SPeter Avalos #include "awk.h"
324b588458SPeter Avalos 
334b588458SPeter Avalos #define	FULLTAB	2	/* rehash when table gets this x full */
344b588458SPeter Avalos #define	GROWTAB 4	/* grow table by this factor */
354b588458SPeter Avalos 
364b588458SPeter Avalos Array	*symtab;	/* main symbol table */
374b588458SPeter Avalos 
384b588458SPeter Avalos char	**FS;		/* initial field sep */
394b588458SPeter Avalos char	**RS;		/* initial record sep */
404b588458SPeter Avalos char	**OFS;		/* output field sep */
414b588458SPeter Avalos char	**ORS;		/* output record sep */
424b588458SPeter Avalos char	**OFMT;		/* output format for numbers */
434b588458SPeter Avalos char	**CONVFMT;	/* format for conversions in getsval */
444b588458SPeter Avalos Awkfloat *NF;		/* number of fields in current record */
454b588458SPeter Avalos Awkfloat *NR;		/* number of current record */
464b588458SPeter Avalos Awkfloat *FNR;		/* number of current record in current file */
474b588458SPeter Avalos char	**FILENAME;	/* current filename argument */
484b588458SPeter Avalos Awkfloat *ARGC;		/* number of arguments from command line */
494b588458SPeter Avalos char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
504b588458SPeter Avalos Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
514b588458SPeter Avalos Awkfloat *RLENGTH;	/* length of same */
524b588458SPeter Avalos 
534b588458SPeter Avalos Cell	*fsloc;		/* FS */
544b588458SPeter Avalos Cell	*nrloc;		/* NR */
554b588458SPeter Avalos Cell	*nfloc;		/* NF */
564b588458SPeter Avalos Cell	*fnrloc;	/* FNR */
571d48fce0SDaniel Fojt Cell	*ofsloc;	/* OFS */
581d48fce0SDaniel Fojt Cell	*orsloc;	/* ORS */
591d48fce0SDaniel Fojt Cell	*rsloc;		/* RS */
604b588458SPeter Avalos Array	*ARGVtab;	/* symbol table containing ARGV[...] */
614b588458SPeter Avalos Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
624b588458SPeter Avalos Cell	*rstartloc;	/* RSTART */
634b588458SPeter Avalos Cell	*rlengthloc;	/* RLENGTH */
641d48fce0SDaniel Fojt Cell	*subseploc;	/* SUBSEP */
654b588458SPeter Avalos Cell	*symtabloc;	/* SYMTAB */
664b588458SPeter Avalos 
674b588458SPeter Avalos Cell	*nullloc;	/* a guaranteed empty cell */
684b588458SPeter Avalos Node	*nullnode;	/* zero&null, converted into a node for comparisons */
694b588458SPeter Avalos Cell	*literal0;
704b588458SPeter Avalos 
714b588458SPeter Avalos extern Cell **fldtab;
724b588458SPeter Avalos 
syminit(void)734b588458SPeter Avalos void syminit(void)	/* initialize symbol table with builtin vars */
744b588458SPeter Avalos {
754b588458SPeter Avalos 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
764b588458SPeter Avalos 	/* this is used for if(x)... tests: */
774b588458SPeter Avalos 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
784b588458SPeter Avalos 	nullnode = celltonode(nullloc, CCON);
794b588458SPeter Avalos 
804b588458SPeter Avalos 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
814b588458SPeter Avalos 	FS = &fsloc->sval;
821d48fce0SDaniel Fojt 	rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
831d48fce0SDaniel Fojt 	RS = &rsloc->sval;
841d48fce0SDaniel Fojt 	ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
851d48fce0SDaniel Fojt 	OFS = &ofsloc->sval;
861d48fce0SDaniel Fojt 	orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
871d48fce0SDaniel Fojt 	ORS = &orsloc->sval;
884b588458SPeter Avalos 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
894b588458SPeter Avalos 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
904b588458SPeter Avalos 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
914b588458SPeter Avalos 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
924b588458SPeter Avalos 	NF = &nfloc->fval;
934b588458SPeter Avalos 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
944b588458SPeter Avalos 	NR = &nrloc->fval;
954b588458SPeter Avalos 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
964b588458SPeter Avalos 	FNR = &fnrloc->fval;
971d48fce0SDaniel Fojt 	subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
981d48fce0SDaniel Fojt 	SUBSEP = &subseploc->sval;
994b588458SPeter Avalos 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
1004b588458SPeter Avalos 	RSTART = &rstartloc->fval;
1014b588458SPeter Avalos 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
1024b588458SPeter Avalos 	RLENGTH = &rlengthloc->fval;
1034b588458SPeter Avalos 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
1041d48fce0SDaniel Fojt 	free(symtabloc->sval);
1054b588458SPeter Avalos 	symtabloc->sval = (char *) symtab;
1064b588458SPeter Avalos }
1074b588458SPeter Avalos 
arginit(int ac,char ** av)1084b588458SPeter Avalos void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1094b588458SPeter Avalos {
1104b588458SPeter Avalos 	Cell *cp;
1114b588458SPeter Avalos 	int i;
1124b588458SPeter Avalos 	char temp[50];
1134b588458SPeter Avalos 
1144b588458SPeter Avalos 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1154b588458SPeter Avalos 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1164b588458SPeter Avalos 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1171d48fce0SDaniel Fojt 	free(cp->sval);
1184b588458SPeter Avalos 	cp->sval = (char *) ARGVtab;
1194b588458SPeter Avalos 	for (i = 0; i < ac; i++) {
12048f09a05SAntonio Huete Jimenez 		double result;
12148f09a05SAntonio Huete Jimenez 
1224b588458SPeter Avalos 		sprintf(temp, "%d", i);
12348f09a05SAntonio Huete Jimenez 		if (is_number(*av, & result))
12448f09a05SAntonio Huete Jimenez 			setsymtab(temp, *av, result, STR|NUM, ARGVtab);
1254b588458SPeter Avalos 		else
1264b588458SPeter Avalos 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1274b588458SPeter Avalos 		av++;
1284b588458SPeter Avalos 	}
1294b588458SPeter Avalos }
1304b588458SPeter Avalos 
envinit(char ** envp)1314b588458SPeter Avalos void envinit(char **envp)	/* set up ENVIRON variable */
1324b588458SPeter Avalos {
1334b588458SPeter Avalos 	Cell *cp;
1344b588458SPeter Avalos 	char *p;
1354b588458SPeter Avalos 
1364b588458SPeter Avalos 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1374b588458SPeter Avalos 	ENVtab = makesymtab(NSYMTAB);
1381d48fce0SDaniel Fojt 	free(cp->sval);
1394b588458SPeter Avalos 	cp->sval = (char *) ENVtab;
1404b588458SPeter Avalos 	for ( ; *envp; envp++) {
14148f09a05SAntonio Huete Jimenez 		double result;
14248f09a05SAntonio Huete Jimenez 
1434b588458SPeter Avalos 		if ((p = strchr(*envp, '=')) == NULL)
1444b588458SPeter Avalos 			continue;
1454b588458SPeter Avalos 		if( p == *envp ) /* no left hand side name in env string */
1464b588458SPeter Avalos 			continue;
1474b588458SPeter Avalos 		*p++ = 0;	/* split into two strings at = */
14848f09a05SAntonio Huete Jimenez 		if (is_number(p, & result))
14948f09a05SAntonio Huete Jimenez 			setsymtab(*envp, p, result, STR|NUM, ENVtab);
1504b588458SPeter Avalos 		else
1514b588458SPeter Avalos 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1524b588458SPeter Avalos 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1534b588458SPeter Avalos 	}
1544b588458SPeter Avalos }
1554b588458SPeter Avalos 
makesymtab(int n)1564b588458SPeter Avalos Array *makesymtab(int n)	/* make a new symbol table */
1574b588458SPeter Avalos {
1584b588458SPeter Avalos 	Array *ap;
1594b588458SPeter Avalos 	Cell **tp;
1604b588458SPeter Avalos 
16148f09a05SAntonio Huete Jimenez 	ap = (Array *) malloc(sizeof(*ap));
16248f09a05SAntonio Huete Jimenez 	tp = (Cell **) calloc(n, sizeof(*tp));
1634b588458SPeter Avalos 	if (ap == NULL || tp == NULL)
1644b588458SPeter Avalos 		FATAL("out of space in makesymtab");
1654b588458SPeter Avalos 	ap->nelem = 0;
1664b588458SPeter Avalos 	ap->size = n;
1674b588458SPeter Avalos 	ap->tab = tp;
1684b588458SPeter Avalos 	return(ap);
1694b588458SPeter Avalos }
1704b588458SPeter Avalos 
freesymtab(Cell * ap)1714b588458SPeter Avalos void freesymtab(Cell *ap)	/* free a symbol table */
1724b588458SPeter Avalos {
1734b588458SPeter Avalos 	Cell *cp, *temp;
1744b588458SPeter Avalos 	Array *tp;
1754b588458SPeter Avalos 	int i;
1764b588458SPeter Avalos 
1774b588458SPeter Avalos 	if (!isarr(ap))
1784b588458SPeter Avalos 		return;
1794b588458SPeter Avalos 	tp = (Array *) ap->sval;
1804b588458SPeter Avalos 	if (tp == NULL)
1814b588458SPeter Avalos 		return;
1824b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
1834b588458SPeter Avalos 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1844b588458SPeter Avalos 			xfree(cp->nval);
1854b588458SPeter Avalos 			if (freeable(cp))
1864b588458SPeter Avalos 				xfree(cp->sval);
1874b588458SPeter Avalos 			temp = cp->cnext;	/* avoids freeing then using */
1884b588458SPeter Avalos 			free(cp);
1894b588458SPeter Avalos 			tp->nelem--;
1904b588458SPeter Avalos 		}
1911d48fce0SDaniel Fojt 		tp->tab[i] = NULL;
1924b588458SPeter Avalos 	}
1934b588458SPeter Avalos 	if (tp->nelem != 0)
1944b588458SPeter Avalos 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1954b588458SPeter Avalos 	free(tp->tab);
1964b588458SPeter Avalos 	free(tp);
1974b588458SPeter Avalos }
1984b588458SPeter Avalos 
freeelem(Cell * ap,const char * s)1994b588458SPeter Avalos void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
2004b588458SPeter Avalos {
2014b588458SPeter Avalos 	Array *tp;
2024b588458SPeter Avalos 	Cell *p, *prev = NULL;
2034b588458SPeter Avalos 	int h;
2044b588458SPeter Avalos 
2054b588458SPeter Avalos 	tp = (Array *) ap->sval;
2064b588458SPeter Avalos 	h = hash(s, tp->size);
2074b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
2084b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0) {
2094b588458SPeter Avalos 			if (prev == NULL)	/* 1st one */
2104b588458SPeter Avalos 				tp->tab[h] = p->cnext;
2114b588458SPeter Avalos 			else			/* middle somewhere */
2124b588458SPeter Avalos 				prev->cnext = p->cnext;
2134b588458SPeter Avalos 			if (freeable(p))
2144b588458SPeter Avalos 				xfree(p->sval);
2154b588458SPeter Avalos 			free(p->nval);
2164b588458SPeter Avalos 			free(p);
2174b588458SPeter Avalos 			tp->nelem--;
2184b588458SPeter Avalos 			return;
2194b588458SPeter Avalos 		}
2204b588458SPeter Avalos }
2214b588458SPeter Avalos 
setsymtab(const char * n,const char * s,Awkfloat f,unsigned t,Array * tp)2224b588458SPeter Avalos Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2234b588458SPeter Avalos {
2244b588458SPeter Avalos 	int h;
2254b588458SPeter Avalos 	Cell *p;
2264b588458SPeter Avalos 
2274b588458SPeter Avalos 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
228e5e686a0SDaniel Fojt 		DPRINTF("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
229e5e686a0SDaniel Fojt 			(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval);
2304b588458SPeter Avalos 		return(p);
2314b588458SPeter Avalos 	}
23248f09a05SAntonio Huete Jimenez 	p = (Cell *) malloc(sizeof(*p));
2334b588458SPeter Avalos 	if (p == NULL)
2344b588458SPeter Avalos 		FATAL("out of space for symbol table at %s", n);
2354b588458SPeter Avalos 	p->nval = tostring(n);
2364b588458SPeter Avalos 	p->sval = s ? tostring(s) : tostring("");
2374b588458SPeter Avalos 	p->fval = f;
2384b588458SPeter Avalos 	p->tval = t;
2394b588458SPeter Avalos 	p->csub = CUNK;
2404b588458SPeter Avalos 	p->ctype = OCELL;
2414b588458SPeter Avalos 	tp->nelem++;
2424b588458SPeter Avalos 	if (tp->nelem > FULLTAB * tp->size)
2434b588458SPeter Avalos 		rehash(tp);
2444b588458SPeter Avalos 	h = hash(n, tp->size);
2454b588458SPeter Avalos 	p->cnext = tp->tab[h];
2464b588458SPeter Avalos 	tp->tab[h] = p;
247e5e686a0SDaniel Fojt 	DPRINTF("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
248e5e686a0SDaniel Fojt 		(void*)p, p->nval, p->sval, p->fval, p->tval);
2494b588458SPeter Avalos 	return(p);
2504b588458SPeter Avalos }
2514b588458SPeter Avalos 
hash(const char * s,int n)2524b588458SPeter Avalos int hash(const char *s, int n)	/* form hash value for string s */
2534b588458SPeter Avalos {
2544b588458SPeter Avalos 	unsigned hashval;
2554b588458SPeter Avalos 
2564b588458SPeter Avalos 	for (hashval = 0; *s != '\0'; s++)
2574b588458SPeter Avalos 		hashval = (*s + 31 * hashval);
2584b588458SPeter Avalos 	return hashval % n;
2594b588458SPeter Avalos }
2604b588458SPeter Avalos 
rehash(Array * tp)2614b588458SPeter Avalos void rehash(Array *tp)	/* rehash items in small table into big one */
2624b588458SPeter Avalos {
2634b588458SPeter Avalos 	int i, nh, nsz;
2644b588458SPeter Avalos 	Cell *cp, *op, **np;
2654b588458SPeter Avalos 
2664b588458SPeter Avalos 	nsz = GROWTAB * tp->size;
26748f09a05SAntonio Huete Jimenez 	np = (Cell **) calloc(nsz, sizeof(*np));
2684b588458SPeter Avalos 	if (np == NULL)		/* can't do it, but can keep running. */
2694b588458SPeter Avalos 		return;		/* someone else will run out later. */
2704b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
2714b588458SPeter Avalos 		for (cp = tp->tab[i]; cp; cp = op) {
2724b588458SPeter Avalos 			op = cp->cnext;
2734b588458SPeter Avalos 			nh = hash(cp->nval, nsz);
2744b588458SPeter Avalos 			cp->cnext = np[nh];
2754b588458SPeter Avalos 			np[nh] = cp;
2764b588458SPeter Avalos 		}
2774b588458SPeter Avalos 	}
2784b588458SPeter Avalos 	free(tp->tab);
2794b588458SPeter Avalos 	tp->tab = np;
2804b588458SPeter Avalos 	tp->size = nsz;
2814b588458SPeter Avalos }
2824b588458SPeter Avalos 
lookup(const char * s,Array * tp)2834b588458SPeter Avalos Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
2844b588458SPeter Avalos {
2854b588458SPeter Avalos 	Cell *p;
2864b588458SPeter Avalos 	int h;
2874b588458SPeter Avalos 
2884b588458SPeter Avalos 	h = hash(s, tp->size);
2894b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
2904b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0)
2914b588458SPeter Avalos 			return(p);	/* found it */
2924b588458SPeter Avalos 	return(NULL);			/* not found */
2934b588458SPeter Avalos }
2944b588458SPeter Avalos 
setfval(Cell * vp,Awkfloat f)2954b588458SPeter Avalos Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
2964b588458SPeter Avalos {
2974b588458SPeter Avalos 	int fldno;
2984b588458SPeter Avalos 
2991d48fce0SDaniel Fojt 	f += 0.0;		/* normalise negative zero to positive zero */
3004b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3014b588458SPeter Avalos 		funnyvar(vp, "assign to");
3024b588458SPeter Avalos 	if (isfld(vp)) {
3031d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3044b588458SPeter Avalos 		fldno = atoi(vp->nval);
3054b588458SPeter Avalos 		if (fldno > *NF)
3064b588458SPeter Avalos 			newfld(fldno);
307e5e686a0SDaniel Fojt 		DPRINTF("setting field %d to %g\n", fldno, f);
3081d48fce0SDaniel Fojt 	} else if (&vp->fval == NF) {
3091d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3101d48fce0SDaniel Fojt 		setlastfld(f);
311*ed569bc2SAaron LI 		DPRINTF("setfval: setting NF to %g\n", f);
3124b588458SPeter Avalos 	} else if (isrec(vp)) {
3131d48fce0SDaniel Fojt 		donefld = false;	/* mark $1... invalid */
3141d48fce0SDaniel Fojt 		donerec = true;
3151d48fce0SDaniel Fojt 		savefs();
3161d48fce0SDaniel Fojt 	} else if (vp == ofsloc) {
3171d48fce0SDaniel Fojt 		if (!donerec)
3181d48fce0SDaniel Fojt 			recbld();
3194b588458SPeter Avalos 	}
3204b588458SPeter Avalos 	if (freeable(vp))
3214b588458SPeter Avalos 		xfree(vp->sval); /* free any previous string */
3221d48fce0SDaniel Fojt 	vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
3231d48fce0SDaniel Fojt 	vp->fmt = NULL;
3244b588458SPeter Avalos 	vp->tval |= NUM;	/* mark number ok */
3252078c1f0SJohn Marino 	if (f == -0)  /* who would have thought this possible? */
3262078c1f0SJohn Marino 		f = 0;
327e5e686a0SDaniel Fojt 	DPRINTF("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval);
3284b588458SPeter Avalos 	return vp->fval = f;
3294b588458SPeter Avalos }
3304b588458SPeter Avalos 
funnyvar(Cell * vp,const char * rw)3314b588458SPeter Avalos void funnyvar(Cell *vp, const char *rw)
3324b588458SPeter Avalos {
3334b588458SPeter Avalos 	if (isarr(vp))
3344b588458SPeter Avalos 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3354b588458SPeter Avalos 	if (vp->tval & FCN)
3364b588458SPeter Avalos 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
3374b588458SPeter Avalos 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3381d48fce0SDaniel Fojt 		(void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
3394b588458SPeter Avalos }
3404b588458SPeter Avalos 
setsval(Cell * vp,const char * s)3414b588458SPeter Avalos char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
3424b588458SPeter Avalos {
3434b588458SPeter Avalos 	char *t;
3444b588458SPeter Avalos 	int fldno;
3451d48fce0SDaniel Fojt 	Awkfloat f;
3464b588458SPeter Avalos 
347e5e686a0SDaniel Fojt 	DPRINTF("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
348e5e686a0SDaniel Fojt 		(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld);
3494b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3504b588458SPeter Avalos 		funnyvar(vp, "assign to");
351*ed569bc2SAaron LI 	if (CSV && (vp == rsloc))
352*ed569bc2SAaron LI 		WARNING("danger: don't set RS when --csv is in effect");
353*ed569bc2SAaron LI 	if (CSV && (vp == fsloc))
354*ed569bc2SAaron LI 		WARNING("danger: don't set FS when --csv is in effect");
3554b588458SPeter Avalos 	if (isfld(vp)) {
3561d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3574b588458SPeter Avalos 		fldno = atoi(vp->nval);
3584b588458SPeter Avalos 		if (fldno > *NF)
3594b588458SPeter Avalos 			newfld(fldno);
36048f09a05SAntonio Huete Jimenez 		DPRINTF("setting field %d to %s (%p)\n", fldno, s, (const void*)s);
3614b588458SPeter Avalos 	} else if (isrec(vp)) {
3621d48fce0SDaniel Fojt 		donefld = false;	/* mark $1... invalid */
3631d48fce0SDaniel Fojt 		donerec = true;
3641d48fce0SDaniel Fojt 		savefs();
3651d48fce0SDaniel Fojt 	} else if (vp == ofsloc) {
3661d48fce0SDaniel Fojt 		if (!donerec)
3671d48fce0SDaniel Fojt 			recbld();
3684b588458SPeter Avalos 	}
3691d48fce0SDaniel Fojt 	t = s ? tostring(s) : tostring("");	/* in case it's self-assign */
3704b588458SPeter Avalos 	if (freeable(vp))
3714b588458SPeter Avalos 		xfree(vp->sval);
37248f09a05SAntonio Huete Jimenez 	vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
3734b588458SPeter Avalos 	vp->tval |= STR;
3741d48fce0SDaniel Fojt 	vp->fmt = NULL;
375e5e686a0SDaniel Fojt 	DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
37648f09a05SAntonio Huete Jimenez 		(void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
3771d48fce0SDaniel Fojt 	vp->sval = t;
3781d48fce0SDaniel Fojt 	if (&vp->fval == NF) {
3791d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3801d48fce0SDaniel Fojt 		f = getfval(vp);
3811d48fce0SDaniel Fojt 		setlastfld(f);
382*ed569bc2SAaron LI 		DPRINTF("setsval: setting NF to %g\n", f);
3831d48fce0SDaniel Fojt 	}
3841d48fce0SDaniel Fojt 
3851d48fce0SDaniel Fojt 	return(vp->sval);
3864b588458SPeter Avalos }
3874b588458SPeter Avalos 
getfval(Cell * vp)3884b588458SPeter Avalos Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3894b588458SPeter Avalos {
3904b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3914b588458SPeter Avalos 		funnyvar(vp, "read value of");
3921d48fce0SDaniel Fojt 	if (isfld(vp) && !donefld)
3934b588458SPeter Avalos 		fldbld();
3941d48fce0SDaniel Fojt 	else if (isrec(vp) && !donerec)
3954b588458SPeter Avalos 		recbld();
3964b588458SPeter Avalos 	if (!isnum(vp)) {	/* not a number */
39748f09a05SAntonio Huete Jimenez 		double fval;
39848f09a05SAntonio Huete Jimenez 		bool no_trailing;
39948f09a05SAntonio Huete Jimenez 
40048f09a05SAntonio Huete Jimenez 		if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
40148f09a05SAntonio Huete Jimenez 			vp->fval = fval;
40248f09a05SAntonio Huete Jimenez 			if (no_trailing && !(vp->tval&CON))
4034b588458SPeter Avalos 				vp->tval |= NUM;	/* make NUM only sparingly */
40448f09a05SAntonio Huete Jimenez 		} else
40548f09a05SAntonio Huete Jimenez 			vp->fval = 0.0;
4064b588458SPeter Avalos 	}
407e5e686a0SDaniel Fojt 	DPRINTF("getfval %p: %s = %g, t=%o\n",
408e5e686a0SDaniel Fojt 		(void*)vp, NN(vp->nval), vp->fval, vp->tval);
4094b588458SPeter Avalos 	return(vp->fval);
4104b588458SPeter Avalos }
4114b588458SPeter Avalos 
get_inf_nan(double d)41248f09a05SAntonio Huete Jimenez static const char *get_inf_nan(double d)
41348f09a05SAntonio Huete Jimenez {
41448f09a05SAntonio Huete Jimenez 	if (isinf(d)) {
41548f09a05SAntonio Huete Jimenez 		return (d < 0 ? "-inf" : "+inf");
41648f09a05SAntonio Huete Jimenez 	} else if (isnan(d)) {
41748f09a05SAntonio Huete Jimenez 		return (signbit(d) != 0 ? "-nan" : "+nan");
41848f09a05SAntonio Huete Jimenez 	} else
41948f09a05SAntonio Huete Jimenez 		return NULL;
42048f09a05SAntonio Huete Jimenez }
42148f09a05SAntonio Huete Jimenez 
get_str_val(Cell * vp,char ** fmt)4224b588458SPeter Avalos static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
4234b588458SPeter Avalos {
4241d48fce0SDaniel Fojt 	char s[256];
4254b588458SPeter Avalos 	double dtemp;
42648f09a05SAntonio Huete Jimenez 	const char *p;
4274b588458SPeter Avalos 
4284b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
4294b588458SPeter Avalos 		funnyvar(vp, "read value of");
4301d48fce0SDaniel Fojt 	if (isfld(vp) && ! donefld)
4314b588458SPeter Avalos 		fldbld();
4321d48fce0SDaniel Fojt 	else if (isrec(vp) && ! donerec)
4334b588458SPeter Avalos 		recbld();
4341d48fce0SDaniel Fojt 
4351d48fce0SDaniel Fojt 	/*
4361d48fce0SDaniel Fojt 	 * ADR: This is complicated and more fragile than is desirable.
4371d48fce0SDaniel Fojt 	 * Retrieving a string value for a number associates the string
4381d48fce0SDaniel Fojt 	 * value with the scalar.  Previously, the string value was
4391d48fce0SDaniel Fojt 	 * sticky, meaning if converted via OFMT that became the value
4401d48fce0SDaniel Fojt 	 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
4411d48fce0SDaniel Fojt 	 * changed after a string value was retrieved, the original value
4421d48fce0SDaniel Fojt 	 * was maintained and used.  Also not per POSIX.
4431d48fce0SDaniel Fojt 	 *
4441d48fce0SDaniel Fojt 	 * We work around this design by adding two additional flags,
4451d48fce0SDaniel Fojt 	 * CONVC and CONVO, indicating how the string value was
4461d48fce0SDaniel Fojt 	 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
4471d48fce0SDaniel Fojt 	 * of the pointer to the xFMT format string used for the
4481d48fce0SDaniel Fojt 	 * conversion.  This pointer is only read, **never** dereferenced.
4491d48fce0SDaniel Fojt 	 * The next time we do a conversion, if it's coming from the same
4501d48fce0SDaniel Fojt 	 * xFMT as last time, and the pointer value is different, we
4511d48fce0SDaniel Fojt 	 * know that the xFMT format string changed, and we need to
4521d48fce0SDaniel Fojt 	 * redo the conversion. If it's the same, we don't have to.
4531d48fce0SDaniel Fojt 	 *
4541d48fce0SDaniel Fojt 	 * There are also several cases where we don't do a conversion,
4551d48fce0SDaniel Fojt 	 * such as for a field (see the checks below).
4561d48fce0SDaniel Fojt 	 */
4571d48fce0SDaniel Fojt 
4581d48fce0SDaniel Fojt 	/* Don't duplicate the code for actually updating the value */
4591d48fce0SDaniel Fojt #define update_str_val(vp) \
4601d48fce0SDaniel Fojt 	{ \
4611d48fce0SDaniel Fojt 		if (freeable(vp)) \
4621d48fce0SDaniel Fojt 			xfree(vp->sval); \
46348f09a05SAntonio Huete Jimenez 		if ((p = get_inf_nan(vp->fval)) != NULL) \
46448f09a05SAntonio Huete Jimenez 			strcpy(s, p); \
46548f09a05SAntonio Huete Jimenez 		else if (modf(vp->fval, &dtemp) == 0)	/* it's integral */ \
4661d48fce0SDaniel Fojt 			snprintf(s, sizeof (s), "%.30g", vp->fval); \
4671d48fce0SDaniel Fojt 		else \
4681d48fce0SDaniel Fojt 			snprintf(s, sizeof (s), *fmt, vp->fval); \
4691d48fce0SDaniel Fojt 		vp->sval = tostring(s); \
4701d48fce0SDaniel Fojt 		vp->tval &= ~DONTFREE; \
4711d48fce0SDaniel Fojt 		vp->tval |= STR; \
4724b588458SPeter Avalos 	}
4731d48fce0SDaniel Fojt 
4741d48fce0SDaniel Fojt 	if (isstr(vp) == 0) {
4751d48fce0SDaniel Fojt 		update_str_val(vp);
4761d48fce0SDaniel Fojt 		if (fmt == OFMT) {
4771d48fce0SDaniel Fojt 			vp->tval &= ~CONVC;
4781d48fce0SDaniel Fojt 			vp->tval |= CONVO;
4791d48fce0SDaniel Fojt 		} else {
4801d48fce0SDaniel Fojt 			/* CONVFMT */
4811d48fce0SDaniel Fojt 			vp->tval &= ~CONVO;
4821d48fce0SDaniel Fojt 			vp->tval |= CONVC;
4831d48fce0SDaniel Fojt 		}
4841d48fce0SDaniel Fojt 		vp->fmt = *fmt;
4851d48fce0SDaniel Fojt 	} else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
4861d48fce0SDaniel Fojt 		goto done;
4871d48fce0SDaniel Fojt 	} else if (isstr(vp)) {
4881d48fce0SDaniel Fojt 		if (fmt == OFMT) {
4891d48fce0SDaniel Fojt 			if ((vp->tval & CONVC) != 0
4901d48fce0SDaniel Fojt 			    || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
4911d48fce0SDaniel Fojt 				update_str_val(vp);
4921d48fce0SDaniel Fojt 				vp->tval &= ~CONVC;
4931d48fce0SDaniel Fojt 				vp->tval |= CONVO;
4941d48fce0SDaniel Fojt 				vp->fmt = *fmt;
4951d48fce0SDaniel Fojt 			}
4961d48fce0SDaniel Fojt 		} else {
4971d48fce0SDaniel Fojt 			/* CONVFMT */
4981d48fce0SDaniel Fojt 			if ((vp->tval & CONVO) != 0
4991d48fce0SDaniel Fojt 			    || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
5001d48fce0SDaniel Fojt 				update_str_val(vp);
5011d48fce0SDaniel Fojt 				vp->tval &= ~CONVO;
5021d48fce0SDaniel Fojt 				vp->tval |= CONVC;
5031d48fce0SDaniel Fojt 				vp->fmt = *fmt;
5041d48fce0SDaniel Fojt 			}
5051d48fce0SDaniel Fojt 		}
5061d48fce0SDaniel Fojt 	}
5071d48fce0SDaniel Fojt done:
508e5e686a0SDaniel Fojt 	DPRINTF("getsval %p: %s = \"%s (%p)\", t=%o\n",
50948f09a05SAntonio Huete Jimenez 		(void*)vp, NN(vp->nval), vp->sval, (void*)vp->sval, vp->tval);
5104b588458SPeter Avalos 	return(vp->sval);
5114b588458SPeter Avalos }
5124b588458SPeter Avalos 
getsval(Cell * vp)5134b588458SPeter Avalos char *getsval(Cell *vp)       /* get string val of a Cell */
5144b588458SPeter Avalos {
5154b588458SPeter Avalos       return get_str_val(vp, CONVFMT);
5164b588458SPeter Avalos }
5174b588458SPeter Avalos 
getpssval(Cell * vp)5184b588458SPeter Avalos char *getpssval(Cell *vp)     /* get string val of a Cell for print */
5194b588458SPeter Avalos {
5204b588458SPeter Avalos       return get_str_val(vp, OFMT);
5214b588458SPeter Avalos }
5224b588458SPeter Avalos 
5234b588458SPeter Avalos 
tostring(const char * s)5244b588458SPeter Avalos char *tostring(const char *s)	/* make a copy of string s */
5254b588458SPeter Avalos {
5261d48fce0SDaniel Fojt 	char *p = strdup(s);
5271d48fce0SDaniel Fojt 	if (p == NULL)
5281d48fce0SDaniel Fojt 		FATAL("out of space in tostring on %s", s);
5291d48fce0SDaniel Fojt 	return(p);
5301d48fce0SDaniel Fojt }
5311d48fce0SDaniel Fojt 
tostringN(const char * s,size_t n)5321d48fce0SDaniel Fojt char *tostringN(const char *s, size_t n)	/* make a copy of string s */
5331d48fce0SDaniel Fojt {
5344b588458SPeter Avalos 	char *p;
5354b588458SPeter Avalos 
53648f09a05SAntonio Huete Jimenez 	p = (char *) malloc(n);
5374b588458SPeter Avalos 	if (p == NULL)
5384b588458SPeter Avalos 		FATAL("out of space in tostring on %s", s);
5394b588458SPeter Avalos 	strcpy(p, s);
5404b588458SPeter Avalos 	return(p);
5414b588458SPeter Avalos }
5424b588458SPeter Avalos 
catstr(Cell * a,Cell * b)5431d48fce0SDaniel Fojt Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
5441d48fce0SDaniel Fojt {
5451d48fce0SDaniel Fojt 	Cell *c;
5461d48fce0SDaniel Fojt 	char *p;
5471d48fce0SDaniel Fojt 	char *sa = getsval(a);
5481d48fce0SDaniel Fojt 	char *sb = getsval(b);
5491d48fce0SDaniel Fojt 	size_t l = strlen(sa) + strlen(sb) + 1;
55048f09a05SAntonio Huete Jimenez 	p = (char *) malloc(l);
5511d48fce0SDaniel Fojt 	if (p == NULL)
5521d48fce0SDaniel Fojt 		FATAL("out of space concatenating %s and %s", sa, sb);
5531d48fce0SDaniel Fojt 	snprintf(p, l, "%s%s", sa, sb);
5541d48fce0SDaniel Fojt 
5551d48fce0SDaniel Fojt 	l++;	// add room for ' '
55648f09a05SAntonio Huete Jimenez 	char *newbuf = (char *) malloc(l);
5571d48fce0SDaniel Fojt 	if (newbuf == NULL)
5581d48fce0SDaniel Fojt 		FATAL("out of space concatenating %s and %s", sa, sb);
5591d48fce0SDaniel Fojt 	// See string() in lex.c; a string "xx" is stored in the symbol
5601d48fce0SDaniel Fojt 	// table as "xx ".
5611d48fce0SDaniel Fojt 	snprintf(newbuf, l, "%s ", p);
5621d48fce0SDaniel Fojt 	c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
5631d48fce0SDaniel Fojt 	free(p);
5641d48fce0SDaniel Fojt 	free(newbuf);
5651d48fce0SDaniel Fojt 	return c;
5661d48fce0SDaniel Fojt }
5671d48fce0SDaniel Fojt 
qstring(const char * is,int delim)5684b588458SPeter Avalos char *qstring(const char *is, int delim)	/* collect string up to next delim */
5694b588458SPeter Avalos {
5704b588458SPeter Avalos 	int c, n;
5711d48fce0SDaniel Fojt 	const uschar *s = (const uschar *) is;
5724b588458SPeter Avalos 	uschar *buf, *bp;
5734b588458SPeter Avalos 
57448f09a05SAntonio Huete Jimenez 	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
5754b588458SPeter Avalos 		FATAL( "out of space in qstring(%s)", s);
5764b588458SPeter Avalos 	for (bp = buf; (c = *s) != delim; s++) {
5774b588458SPeter Avalos 		if (c == '\n')
57848f09a05SAntonio Huete Jimenez 			SYNTAX( "newline in string %.20s...", is );
5794b588458SPeter Avalos 		else if (c != '\\')
5804b588458SPeter Avalos 			*bp++ = c;
5814b588458SPeter Avalos 		else {	/* \something */
5824b588458SPeter Avalos 			c = *++s;
5834b588458SPeter Avalos 			if (c == 0) {	/* \ at end */
5844b588458SPeter Avalos 				*bp++ = '\\';
5854b588458SPeter Avalos 				break;	/* for loop */
5864b588458SPeter Avalos 			}
5874b588458SPeter Avalos 			switch (c) {
5884b588458SPeter Avalos 			case '\\':	*bp++ = '\\'; break;
5894b588458SPeter Avalos 			case 'n':	*bp++ = '\n'; break;
5904b588458SPeter Avalos 			case 't':	*bp++ = '\t'; break;
5914b588458SPeter Avalos 			case 'b':	*bp++ = '\b'; break;
5924b588458SPeter Avalos 			case 'f':	*bp++ = '\f'; break;
5934b588458SPeter Avalos 			case 'r':	*bp++ = '\r'; break;
5941d48fce0SDaniel Fojt 			case 'v':	*bp++ = '\v'; break;
5951d48fce0SDaniel Fojt 			case 'a':	*bp++ = '\a'; break;
5964b588458SPeter Avalos 			default:
5974b588458SPeter Avalos 				if (!isdigit(c)) {
5984b588458SPeter Avalos 					*bp++ = c;
5994b588458SPeter Avalos 					break;
6004b588458SPeter Avalos 				}
6014b588458SPeter Avalos 				n = c - '0';
6024b588458SPeter Avalos 				if (isdigit(s[1])) {
6034b588458SPeter Avalos 					n = 8 * n + *++s - '0';
6044b588458SPeter Avalos 					if (isdigit(s[1]))
6054b588458SPeter Avalos 						n = 8 * n + *++s - '0';
6064b588458SPeter Avalos 				}
6074b588458SPeter Avalos 				*bp++ = n;
6084b588458SPeter Avalos 				break;
6094b588458SPeter Avalos 			}
6104b588458SPeter Avalos 		}
6114b588458SPeter Avalos 	}
6124b588458SPeter Avalos 	*bp++ = 0;
6134b588458SPeter Avalos 	return (char *) buf;
6144b588458SPeter Avalos }
6151d48fce0SDaniel Fojt 
flags2str(int flags)6161d48fce0SDaniel Fojt const char *flags2str(int flags)
6171d48fce0SDaniel Fojt {
6181d48fce0SDaniel Fojt 	static const struct ftab {
6191d48fce0SDaniel Fojt 		const char *name;
6201d48fce0SDaniel Fojt 		int value;
6211d48fce0SDaniel Fojt 	} flagtab[] = {
6221d48fce0SDaniel Fojt 		{ "NUM", NUM },
6231d48fce0SDaniel Fojt 		{ "STR", STR },
6241d48fce0SDaniel Fojt 		{ "DONTFREE", DONTFREE },
6251d48fce0SDaniel Fojt 		{ "CON", CON },
6261d48fce0SDaniel Fojt 		{ "ARR", ARR },
6271d48fce0SDaniel Fojt 		{ "FCN", FCN },
6281d48fce0SDaniel Fojt 		{ "FLD", FLD },
6291d48fce0SDaniel Fojt 		{ "REC", REC },
6301d48fce0SDaniel Fojt 		{ "CONVC", CONVC },
6311d48fce0SDaniel Fojt 		{ "CONVO", CONVO },
6321d48fce0SDaniel Fojt 		{ NULL, 0 }
6331d48fce0SDaniel Fojt 	};
6341d48fce0SDaniel Fojt 	static char buf[100];
6351d48fce0SDaniel Fojt 	int i;
6361d48fce0SDaniel Fojt 	char *cp = buf;
6371d48fce0SDaniel Fojt 
6381d48fce0SDaniel Fojt 	for (i = 0; flagtab[i].name != NULL; i++) {
6391d48fce0SDaniel Fojt 		if ((flags & flagtab[i].value) != 0) {
6401d48fce0SDaniel Fojt 			if (cp > buf)
6411d48fce0SDaniel Fojt 				*cp++ = '|';
6421d48fce0SDaniel Fojt 			strcpy(cp, flagtab[i].name);
6431d48fce0SDaniel Fojt 			cp += strlen(cp);
6441d48fce0SDaniel Fojt 		}
6451d48fce0SDaniel Fojt 	}
6461d48fce0SDaniel Fojt 
6471d48fce0SDaniel Fojt 	return buf;
6481d48fce0SDaniel Fojt }
649