xref: /dflybsd-src/contrib/awk/tran.c (revision 1d48fce09e070b7fb0180fe19e991a6b7edcd14c)
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 #include "ytab.h"
334b588458SPeter Avalos 
344b588458SPeter Avalos #define	FULLTAB	2	/* rehash when table gets this x full */
354b588458SPeter Avalos #define	GROWTAB 4	/* grow table by this factor */
364b588458SPeter Avalos 
374b588458SPeter Avalos Array	*symtab;	/* main symbol table */
384b588458SPeter Avalos 
394b588458SPeter Avalos char	**FS;		/* initial field sep */
404b588458SPeter Avalos char	**RS;		/* initial record sep */
414b588458SPeter Avalos char	**OFS;		/* output field sep */
424b588458SPeter Avalos char	**ORS;		/* output record sep */
434b588458SPeter Avalos char	**OFMT;		/* output format for numbers */
444b588458SPeter Avalos char	**CONVFMT;	/* format for conversions in getsval */
454b588458SPeter Avalos Awkfloat *NF;		/* number of fields in current record */
464b588458SPeter Avalos Awkfloat *NR;		/* number of current record */
474b588458SPeter Avalos Awkfloat *FNR;		/* number of current record in current file */
484b588458SPeter Avalos char	**FILENAME;	/* current filename argument */
494b588458SPeter Avalos Awkfloat *ARGC;		/* number of arguments from command line */
504b588458SPeter Avalos char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
514b588458SPeter Avalos Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
524b588458SPeter Avalos Awkfloat *RLENGTH;	/* length of same */
534b588458SPeter Avalos 
544b588458SPeter Avalos Cell	*fsloc;		/* FS */
554b588458SPeter Avalos Cell	*nrloc;		/* NR */
564b588458SPeter Avalos Cell	*nfloc;		/* NF */
574b588458SPeter Avalos Cell	*fnrloc;	/* FNR */
58*1d48fce0SDaniel Fojt Cell	*ofsloc;	/* OFS */
59*1d48fce0SDaniel Fojt Cell	*orsloc;	/* ORS */
60*1d48fce0SDaniel Fojt Cell	*rsloc;		/* RS */
614b588458SPeter Avalos Array	*ARGVtab;	/* symbol table containing ARGV[...] */
624b588458SPeter Avalos Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
634b588458SPeter Avalos Cell	*rstartloc;	/* RSTART */
644b588458SPeter Avalos Cell	*rlengthloc;	/* RLENGTH */
65*1d48fce0SDaniel Fojt Cell	*subseploc;	/* SUBSEP */
664b588458SPeter Avalos Cell	*symtabloc;	/* SYMTAB */
674b588458SPeter Avalos 
684b588458SPeter Avalos Cell	*nullloc;	/* a guaranteed empty cell */
694b588458SPeter Avalos Node	*nullnode;	/* zero&null, converted into a node for comparisons */
704b588458SPeter Avalos Cell	*literal0;
714b588458SPeter Avalos 
724b588458SPeter Avalos extern Cell **fldtab;
734b588458SPeter Avalos 
74*1d48fce0SDaniel Fojt static void
75*1d48fce0SDaniel Fojt setfree(Cell *vp)
76*1d48fce0SDaniel Fojt {
77*1d48fce0SDaniel Fojt 	if (&vp->sval == FS || &vp->sval == RS ||
78*1d48fce0SDaniel Fojt 	    &vp->sval == OFS || &vp->sval == ORS ||
79*1d48fce0SDaniel Fojt 	    &vp->sval == OFMT || &vp->sval == CONVFMT ||
80*1d48fce0SDaniel Fojt 	    &vp->sval == FILENAME || &vp->sval == SUBSEP)
81*1d48fce0SDaniel Fojt 		vp->tval |= DONTFREE;
82*1d48fce0SDaniel Fojt 	else
83*1d48fce0SDaniel Fojt 		vp->tval &= ~DONTFREE;
84*1d48fce0SDaniel Fojt }
85*1d48fce0SDaniel Fojt 
864b588458SPeter Avalos void syminit(void)	/* initialize symbol table with builtin vars */
874b588458SPeter Avalos {
884b588458SPeter Avalos 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
894b588458SPeter Avalos 	/* this is used for if(x)... tests: */
904b588458SPeter Avalos 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
914b588458SPeter Avalos 	nullnode = celltonode(nullloc, CCON);
924b588458SPeter Avalos 
934b588458SPeter Avalos 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
944b588458SPeter Avalos 	FS = &fsloc->sval;
95*1d48fce0SDaniel Fojt 	rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
96*1d48fce0SDaniel Fojt 	RS = &rsloc->sval;
97*1d48fce0SDaniel Fojt 	ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
98*1d48fce0SDaniel Fojt 	OFS = &ofsloc->sval;
99*1d48fce0SDaniel Fojt 	orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
100*1d48fce0SDaniel Fojt 	ORS = &orsloc->sval;
1014b588458SPeter Avalos 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
1024b588458SPeter Avalos 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
1034b588458SPeter Avalos 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
1044b588458SPeter Avalos 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
1054b588458SPeter Avalos 	NF = &nfloc->fval;
1064b588458SPeter Avalos 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
1074b588458SPeter Avalos 	NR = &nrloc->fval;
1084b588458SPeter Avalos 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
1094b588458SPeter Avalos 	FNR = &fnrloc->fval;
110*1d48fce0SDaniel Fojt 	subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
111*1d48fce0SDaniel Fojt 	SUBSEP = &subseploc->sval;
1124b588458SPeter Avalos 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
1134b588458SPeter Avalos 	RSTART = &rstartloc->fval;
1144b588458SPeter Avalos 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
1154b588458SPeter Avalos 	RLENGTH = &rlengthloc->fval;
1164b588458SPeter Avalos 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
117*1d48fce0SDaniel Fojt 	free(symtabloc->sval);
1184b588458SPeter Avalos 	symtabloc->sval = (char *) symtab;
1194b588458SPeter Avalos }
1204b588458SPeter Avalos 
1214b588458SPeter Avalos void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1224b588458SPeter Avalos {
1234b588458SPeter Avalos 	Cell *cp;
1244b588458SPeter Avalos 	int i;
1254b588458SPeter Avalos 	char temp[50];
1264b588458SPeter Avalos 
1274b588458SPeter Avalos 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1284b588458SPeter Avalos 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1294b588458SPeter Avalos 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
130*1d48fce0SDaniel Fojt 	free(cp->sval);
1314b588458SPeter Avalos 	cp->sval = (char *) ARGVtab;
1324b588458SPeter Avalos 	for (i = 0; i < ac; i++) {
1334b588458SPeter Avalos 		sprintf(temp, "%d", i);
1344b588458SPeter Avalos 		if (is_number(*av))
1354b588458SPeter Avalos 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
1364b588458SPeter Avalos 		else
1374b588458SPeter Avalos 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1384b588458SPeter Avalos 		av++;
1394b588458SPeter Avalos 	}
1404b588458SPeter Avalos }
1414b588458SPeter Avalos 
1424b588458SPeter Avalos void envinit(char **envp)	/* set up ENVIRON variable */
1434b588458SPeter Avalos {
1444b588458SPeter Avalos 	Cell *cp;
1454b588458SPeter Avalos 	char *p;
1464b588458SPeter Avalos 
1474b588458SPeter Avalos 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1484b588458SPeter Avalos 	ENVtab = makesymtab(NSYMTAB);
149*1d48fce0SDaniel Fojt 	free(cp->sval);
1504b588458SPeter Avalos 	cp->sval = (char *) ENVtab;
1514b588458SPeter Avalos 	for ( ; *envp; envp++) {
1524b588458SPeter Avalos 		if ((p = strchr(*envp, '=')) == NULL)
1534b588458SPeter Avalos 			continue;
1544b588458SPeter Avalos 		if( p == *envp ) /* no left hand side name in env string */
1554b588458SPeter Avalos 			continue;
1564b588458SPeter Avalos 		*p++ = 0;	/* split into two strings at = */
1574b588458SPeter Avalos 		if (is_number(p))
1584b588458SPeter Avalos 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
1594b588458SPeter Avalos 		else
1604b588458SPeter Avalos 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1614b588458SPeter Avalos 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1624b588458SPeter Avalos 	}
1634b588458SPeter Avalos }
1644b588458SPeter Avalos 
1654b588458SPeter Avalos Array *makesymtab(int n)	/* make a new symbol table */
1664b588458SPeter Avalos {
1674b588458SPeter Avalos 	Array *ap;
1684b588458SPeter Avalos 	Cell **tp;
1694b588458SPeter Avalos 
170*1d48fce0SDaniel Fojt 	ap = malloc(sizeof(*ap));
171*1d48fce0SDaniel Fojt 	tp = calloc(n, sizeof(*tp));
1724b588458SPeter Avalos 	if (ap == NULL || tp == NULL)
1734b588458SPeter Avalos 		FATAL("out of space in makesymtab");
1744b588458SPeter Avalos 	ap->nelem = 0;
1754b588458SPeter Avalos 	ap->size = n;
1764b588458SPeter Avalos 	ap->tab = tp;
1774b588458SPeter Avalos 	return(ap);
1784b588458SPeter Avalos }
1794b588458SPeter Avalos 
1804b588458SPeter Avalos void freesymtab(Cell *ap)	/* free a symbol table */
1814b588458SPeter Avalos {
1824b588458SPeter Avalos 	Cell *cp, *temp;
1834b588458SPeter Avalos 	Array *tp;
1844b588458SPeter Avalos 	int i;
1854b588458SPeter Avalos 
1864b588458SPeter Avalos 	if (!isarr(ap))
1874b588458SPeter Avalos 		return;
1884b588458SPeter Avalos 	tp = (Array *) ap->sval;
1894b588458SPeter Avalos 	if (tp == NULL)
1904b588458SPeter Avalos 		return;
1914b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
1924b588458SPeter Avalos 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1934b588458SPeter Avalos 			xfree(cp->nval);
1944b588458SPeter Avalos 			if (freeable(cp))
1954b588458SPeter Avalos 				xfree(cp->sval);
1964b588458SPeter Avalos 			temp = cp->cnext;	/* avoids freeing then using */
1974b588458SPeter Avalos 			free(cp);
1984b588458SPeter Avalos 			tp->nelem--;
1994b588458SPeter Avalos 		}
200*1d48fce0SDaniel Fojt 		tp->tab[i] = NULL;
2014b588458SPeter Avalos 	}
2024b588458SPeter Avalos 	if (tp->nelem != 0)
2034b588458SPeter Avalos 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
2044b588458SPeter Avalos 	free(tp->tab);
2054b588458SPeter Avalos 	free(tp);
2064b588458SPeter Avalos }
2074b588458SPeter Avalos 
2084b588458SPeter Avalos void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
2094b588458SPeter Avalos {
2104b588458SPeter Avalos 	Array *tp;
2114b588458SPeter Avalos 	Cell *p, *prev = NULL;
2124b588458SPeter Avalos 	int h;
2134b588458SPeter Avalos 
2144b588458SPeter Avalos 	tp = (Array *) ap->sval;
2154b588458SPeter Avalos 	h = hash(s, tp->size);
2164b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
2174b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0) {
2184b588458SPeter Avalos 			if (prev == NULL)	/* 1st one */
2194b588458SPeter Avalos 				tp->tab[h] = p->cnext;
2204b588458SPeter Avalos 			else			/* middle somewhere */
2214b588458SPeter Avalos 				prev->cnext = p->cnext;
2224b588458SPeter Avalos 			if (freeable(p))
2234b588458SPeter Avalos 				xfree(p->sval);
2244b588458SPeter Avalos 			free(p->nval);
2254b588458SPeter Avalos 			free(p);
2264b588458SPeter Avalos 			tp->nelem--;
2274b588458SPeter Avalos 			return;
2284b588458SPeter Avalos 		}
2294b588458SPeter Avalos }
2304b588458SPeter Avalos 
2314b588458SPeter Avalos Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2324b588458SPeter Avalos {
2334b588458SPeter Avalos 	int h;
2344b588458SPeter Avalos 	Cell *p;
2354b588458SPeter Avalos 
2364b588458SPeter Avalos 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
2374b588458SPeter Avalos 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
238b12bae18SSascha Wildner 			(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
2394b588458SPeter Avalos 		return(p);
2404b588458SPeter Avalos 	}
241*1d48fce0SDaniel Fojt 	p = malloc(sizeof(*p));
2424b588458SPeter Avalos 	if (p == NULL)
2434b588458SPeter Avalos 		FATAL("out of space for symbol table at %s", n);
2444b588458SPeter Avalos 	p->nval = tostring(n);
2454b588458SPeter Avalos 	p->sval = s ? tostring(s) : tostring("");
2464b588458SPeter Avalos 	p->fval = f;
2474b588458SPeter Avalos 	p->tval = t;
2484b588458SPeter Avalos 	p->csub = CUNK;
2494b588458SPeter Avalos 	p->ctype = OCELL;
2504b588458SPeter Avalos 	tp->nelem++;
2514b588458SPeter Avalos 	if (tp->nelem > FULLTAB * tp->size)
2524b588458SPeter Avalos 		rehash(tp);
2534b588458SPeter Avalos 	h = hash(n, tp->size);
2544b588458SPeter Avalos 	p->cnext = tp->tab[h];
2554b588458SPeter Avalos 	tp->tab[h] = p;
2564b588458SPeter Avalos 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
257b12bae18SSascha Wildner 		(void*)p, p->nval, p->sval, p->fval, p->tval) );
2584b588458SPeter Avalos 	return(p);
2594b588458SPeter Avalos }
2604b588458SPeter Avalos 
2614b588458SPeter Avalos int hash(const char *s, int n)	/* form hash value for string s */
2624b588458SPeter Avalos {
2634b588458SPeter Avalos 	unsigned hashval;
2644b588458SPeter Avalos 
2654b588458SPeter Avalos 	for (hashval = 0; *s != '\0'; s++)
2664b588458SPeter Avalos 		hashval = (*s + 31 * hashval);
2674b588458SPeter Avalos 	return hashval % n;
2684b588458SPeter Avalos }
2694b588458SPeter Avalos 
2704b588458SPeter Avalos void rehash(Array *tp)	/* rehash items in small table into big one */
2714b588458SPeter Avalos {
2724b588458SPeter Avalos 	int i, nh, nsz;
2734b588458SPeter Avalos 	Cell *cp, *op, **np;
2744b588458SPeter Avalos 
2754b588458SPeter Avalos 	nsz = GROWTAB * tp->size;
276*1d48fce0SDaniel Fojt 	np = calloc(nsz, sizeof(*np));
2774b588458SPeter Avalos 	if (np == NULL)		/* can't do it, but can keep running. */
2784b588458SPeter Avalos 		return;		/* someone else will run out later. */
2794b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
2804b588458SPeter Avalos 		for (cp = tp->tab[i]; cp; cp = op) {
2814b588458SPeter Avalos 			op = cp->cnext;
2824b588458SPeter Avalos 			nh = hash(cp->nval, nsz);
2834b588458SPeter Avalos 			cp->cnext = np[nh];
2844b588458SPeter Avalos 			np[nh] = cp;
2854b588458SPeter Avalos 		}
2864b588458SPeter Avalos 	}
2874b588458SPeter Avalos 	free(tp->tab);
2884b588458SPeter Avalos 	tp->tab = np;
2894b588458SPeter Avalos 	tp->size = nsz;
2904b588458SPeter Avalos }
2914b588458SPeter Avalos 
2924b588458SPeter Avalos Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
2934b588458SPeter Avalos {
2944b588458SPeter Avalos 	Cell *p;
2954b588458SPeter Avalos 	int h;
2964b588458SPeter Avalos 
2974b588458SPeter Avalos 	h = hash(s, tp->size);
2984b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
2994b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0)
3004b588458SPeter Avalos 			return(p);	/* found it */
3014b588458SPeter Avalos 	return(NULL);			/* not found */
3024b588458SPeter Avalos }
3034b588458SPeter Avalos 
3044b588458SPeter Avalos Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
3054b588458SPeter Avalos {
3064b588458SPeter Avalos 	int fldno;
3074b588458SPeter Avalos 
308*1d48fce0SDaniel Fojt 	f += 0.0;		/* normalise negative zero to positive zero */
3094b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3104b588458SPeter Avalos 		funnyvar(vp, "assign to");
3114b588458SPeter Avalos 	if (isfld(vp)) {
312*1d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3134b588458SPeter Avalos 		fldno = atoi(vp->nval);
3144b588458SPeter Avalos 		if (fldno > *NF)
3154b588458SPeter Avalos 			newfld(fldno);
3164b588458SPeter Avalos 		   dprintf( ("setting field %d to %g\n", fldno, f) );
317*1d48fce0SDaniel Fojt 	} else if (&vp->fval == NF) {
318*1d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
319*1d48fce0SDaniel Fojt 		setlastfld(f);
320*1d48fce0SDaniel Fojt 		dprintf( ("setting NF to %g\n", f) );
3214b588458SPeter Avalos 	} else if (isrec(vp)) {
322*1d48fce0SDaniel Fojt 		donefld = false;	/* mark $1... invalid */
323*1d48fce0SDaniel Fojt 		donerec = true;
324*1d48fce0SDaniel Fojt 		savefs();
325*1d48fce0SDaniel Fojt 	} else if (vp == ofsloc) {
326*1d48fce0SDaniel Fojt 		if (!donerec)
327*1d48fce0SDaniel Fojt 			recbld();
3284b588458SPeter Avalos 	}
3294b588458SPeter Avalos 	if (freeable(vp))
3304b588458SPeter Avalos 		xfree(vp->sval); /* free any previous string */
331*1d48fce0SDaniel Fojt 	vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
332*1d48fce0SDaniel Fojt 	vp->fmt = NULL;
3334b588458SPeter Avalos 	vp->tval |= NUM;	/* mark number ok */
3342078c1f0SJohn Marino 	if (f == -0)  /* who would have thought this possible? */
3352078c1f0SJohn Marino 		f = 0;
336b12bae18SSascha Wildner 	   dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
3374b588458SPeter Avalos 	return vp->fval = f;
3384b588458SPeter Avalos }
3394b588458SPeter Avalos 
3404b588458SPeter Avalos void funnyvar(Cell *vp, const char *rw)
3414b588458SPeter Avalos {
3424b588458SPeter Avalos 	if (isarr(vp))
3434b588458SPeter Avalos 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3444b588458SPeter Avalos 	if (vp->tval & FCN)
3454b588458SPeter Avalos 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
3464b588458SPeter Avalos 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
347*1d48fce0SDaniel Fojt 		(void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
3484b588458SPeter Avalos }
3494b588458SPeter Avalos 
3504b588458SPeter Avalos char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
3514b588458SPeter Avalos {
3524b588458SPeter Avalos 	char *t;
3534b588458SPeter Avalos 	int fldno;
354*1d48fce0SDaniel Fojt 	Awkfloat f;
3554b588458SPeter Avalos 
3564b588458SPeter Avalos 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
357b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
3584b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3594b588458SPeter Avalos 		funnyvar(vp, "assign to");
3604b588458SPeter Avalos 	if (isfld(vp)) {
361*1d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
3624b588458SPeter Avalos 		fldno = atoi(vp->nval);
3634b588458SPeter Avalos 		if (fldno > *NF)
3644b588458SPeter Avalos 			newfld(fldno);
3654b588458SPeter Avalos 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
3664b588458SPeter Avalos 	} else if (isrec(vp)) {
367*1d48fce0SDaniel Fojt 		donefld = false;	/* mark $1... invalid */
368*1d48fce0SDaniel Fojt 		donerec = true;
369*1d48fce0SDaniel Fojt 		savefs();
370*1d48fce0SDaniel Fojt 	} else if (vp == ofsloc) {
371*1d48fce0SDaniel Fojt 		if (!donerec)
372*1d48fce0SDaniel Fojt 			recbld();
3734b588458SPeter Avalos 	}
374*1d48fce0SDaniel Fojt 	t = s ? tostring(s) : tostring("");	/* in case it's self-assign */
3754b588458SPeter Avalos 	if (freeable(vp))
3764b588458SPeter Avalos 		xfree(vp->sval);
377*1d48fce0SDaniel Fojt 	vp->tval &= ~(NUM|CONVC|CONVO);
3784b588458SPeter Avalos 	vp->tval |= STR;
379*1d48fce0SDaniel Fojt 	vp->fmt = NULL;
380*1d48fce0SDaniel Fojt 	setfree(vp);
3814b588458SPeter Avalos 	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
382b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) );
383*1d48fce0SDaniel Fojt 	vp->sval = t;
384*1d48fce0SDaniel Fojt 	if (&vp->fval == NF) {
385*1d48fce0SDaniel Fojt 		donerec = false;	/* mark $0 invalid */
386*1d48fce0SDaniel Fojt 		f = getfval(vp);
387*1d48fce0SDaniel Fojt 		setlastfld(f);
388*1d48fce0SDaniel Fojt 		dprintf( ("setting NF to %g\n", f) );
389*1d48fce0SDaniel Fojt 	}
390*1d48fce0SDaniel Fojt 
391*1d48fce0SDaniel Fojt 	return(vp->sval);
3924b588458SPeter Avalos }
3934b588458SPeter Avalos 
3944b588458SPeter Avalos Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3954b588458SPeter Avalos {
3964b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3974b588458SPeter Avalos 		funnyvar(vp, "read value of");
398*1d48fce0SDaniel Fojt 	if (isfld(vp) && !donefld)
3994b588458SPeter Avalos 		fldbld();
400*1d48fce0SDaniel Fojt 	else if (isrec(vp) && !donerec)
4014b588458SPeter Avalos 		recbld();
4024b588458SPeter Avalos 	if (!isnum(vp)) {	/* not a number */
4034b588458SPeter Avalos 		vp->fval = atof(vp->sval);	/* best guess */
4044b588458SPeter Avalos 		if (is_number(vp->sval) && !(vp->tval&CON))
4054b588458SPeter Avalos 			vp->tval |= NUM;	/* make NUM only sparingly */
4064b588458SPeter Avalos 	}
407b12bae18SSascha Wildner 	   dprintf( ("getfval %p: %s = %g, t=%o\n",
408b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
4094b588458SPeter Avalos 	return(vp->fval);
4104b588458SPeter Avalos }
4114b588458SPeter Avalos 
4124b588458SPeter Avalos static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
4134b588458SPeter Avalos {
414*1d48fce0SDaniel Fojt 	char s[256];
4154b588458SPeter Avalos 	double dtemp;
4164b588458SPeter Avalos 
4174b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
4184b588458SPeter Avalos 		funnyvar(vp, "read value of");
419*1d48fce0SDaniel Fojt 	if (isfld(vp) && ! donefld)
4204b588458SPeter Avalos 		fldbld();
421*1d48fce0SDaniel Fojt 	else if (isrec(vp) && ! donerec)
4224b588458SPeter Avalos 		recbld();
423*1d48fce0SDaniel Fojt 
424*1d48fce0SDaniel Fojt 	/*
425*1d48fce0SDaniel Fojt 	 * ADR: This is complicated and more fragile than is desirable.
426*1d48fce0SDaniel Fojt 	 * Retrieving a string value for a number associates the string
427*1d48fce0SDaniel Fojt 	 * value with the scalar.  Previously, the string value was
428*1d48fce0SDaniel Fojt 	 * sticky, meaning if converted via OFMT that became the value
429*1d48fce0SDaniel Fojt 	 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
430*1d48fce0SDaniel Fojt 	 * changed after a string value was retrieved, the original value
431*1d48fce0SDaniel Fojt 	 * was maintained and used.  Also not per POSIX.
432*1d48fce0SDaniel Fojt 	 *
433*1d48fce0SDaniel Fojt 	 * We work around this design by adding two additional flags,
434*1d48fce0SDaniel Fojt 	 * CONVC and CONVO, indicating how the string value was
435*1d48fce0SDaniel Fojt 	 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
436*1d48fce0SDaniel Fojt 	 * of the pointer to the xFMT format string used for the
437*1d48fce0SDaniel Fojt 	 * conversion.  This pointer is only read, **never** dereferenced.
438*1d48fce0SDaniel Fojt 	 * The next time we do a conversion, if it's coming from the same
439*1d48fce0SDaniel Fojt 	 * xFMT as last time, and the pointer value is different, we
440*1d48fce0SDaniel Fojt 	 * know that the xFMT format string changed, and we need to
441*1d48fce0SDaniel Fojt 	 * redo the conversion. If it's the same, we don't have to.
442*1d48fce0SDaniel Fojt 	 *
443*1d48fce0SDaniel Fojt 	 * There are also several cases where we don't do a conversion,
444*1d48fce0SDaniel Fojt 	 * such as for a field (see the checks below).
445*1d48fce0SDaniel Fojt 	 */
446*1d48fce0SDaniel Fojt 
447*1d48fce0SDaniel Fojt 	/* Don't duplicate the code for actually updating the value */
448*1d48fce0SDaniel Fojt #define update_str_val(vp) \
449*1d48fce0SDaniel Fojt 	{ \
450*1d48fce0SDaniel Fojt 		if (freeable(vp)) \
451*1d48fce0SDaniel Fojt 			xfree(vp->sval); \
452*1d48fce0SDaniel Fojt 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */ \
453*1d48fce0SDaniel Fojt 			snprintf(s, sizeof (s), "%.30g", vp->fval); \
454*1d48fce0SDaniel Fojt 		else \
455*1d48fce0SDaniel Fojt 			snprintf(s, sizeof (s), *fmt, vp->fval); \
456*1d48fce0SDaniel Fojt 		vp->sval = tostring(s); \
457*1d48fce0SDaniel Fojt 		vp->tval &= ~DONTFREE; \
458*1d48fce0SDaniel Fojt 		vp->tval |= STR; \
4594b588458SPeter Avalos 	}
460*1d48fce0SDaniel Fojt 
461*1d48fce0SDaniel Fojt 	if (isstr(vp) == 0) {
462*1d48fce0SDaniel Fojt 		update_str_val(vp);
463*1d48fce0SDaniel Fojt 		if (fmt == OFMT) {
464*1d48fce0SDaniel Fojt 			vp->tval &= ~CONVC;
465*1d48fce0SDaniel Fojt 			vp->tval |= CONVO;
466*1d48fce0SDaniel Fojt 		} else {
467*1d48fce0SDaniel Fojt 			/* CONVFMT */
468*1d48fce0SDaniel Fojt 			vp->tval &= ~CONVO;
469*1d48fce0SDaniel Fojt 			vp->tval |= CONVC;
470*1d48fce0SDaniel Fojt 		}
471*1d48fce0SDaniel Fojt 		vp->fmt = *fmt;
472*1d48fce0SDaniel Fojt 	} else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
473*1d48fce0SDaniel Fojt 		goto done;
474*1d48fce0SDaniel Fojt 	} else if (isstr(vp)) {
475*1d48fce0SDaniel Fojt 		if (fmt == OFMT) {
476*1d48fce0SDaniel Fojt 			if ((vp->tval & CONVC) != 0
477*1d48fce0SDaniel Fojt 			    || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
478*1d48fce0SDaniel Fojt 				update_str_val(vp);
479*1d48fce0SDaniel Fojt 				vp->tval &= ~CONVC;
480*1d48fce0SDaniel Fojt 				vp->tval |= CONVO;
481*1d48fce0SDaniel Fojt 				vp->fmt = *fmt;
482*1d48fce0SDaniel Fojt 			}
483*1d48fce0SDaniel Fojt 		} else {
484*1d48fce0SDaniel Fojt 			/* CONVFMT */
485*1d48fce0SDaniel Fojt 			if ((vp->tval & CONVO) != 0
486*1d48fce0SDaniel Fojt 			    || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
487*1d48fce0SDaniel Fojt 				update_str_val(vp);
488*1d48fce0SDaniel Fojt 				vp->tval &= ~CONVO;
489*1d48fce0SDaniel Fojt 				vp->tval |= CONVC;
490*1d48fce0SDaniel Fojt 				vp->fmt = *fmt;
491*1d48fce0SDaniel Fojt 			}
492*1d48fce0SDaniel Fojt 		}
493*1d48fce0SDaniel Fojt 	}
494*1d48fce0SDaniel Fojt done:
495b12bae18SSascha Wildner 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
496b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
4974b588458SPeter Avalos 	return(vp->sval);
4984b588458SPeter Avalos }
4994b588458SPeter Avalos 
5004b588458SPeter Avalos char *getsval(Cell *vp)       /* get string val of a Cell */
5014b588458SPeter Avalos {
5024b588458SPeter Avalos       return get_str_val(vp, CONVFMT);
5034b588458SPeter Avalos }
5044b588458SPeter Avalos 
5054b588458SPeter Avalos char *getpssval(Cell *vp)     /* get string val of a Cell for print */
5064b588458SPeter Avalos {
5074b588458SPeter Avalos       return get_str_val(vp, OFMT);
5084b588458SPeter Avalos }
5094b588458SPeter Avalos 
5104b588458SPeter Avalos 
5114b588458SPeter Avalos char *tostring(const char *s)	/* make a copy of string s */
5124b588458SPeter Avalos {
513*1d48fce0SDaniel Fojt 	char *p = strdup(s);
514*1d48fce0SDaniel Fojt 	if (p == NULL)
515*1d48fce0SDaniel Fojt 		FATAL("out of space in tostring on %s", s);
516*1d48fce0SDaniel Fojt 	return(p);
517*1d48fce0SDaniel Fojt }
518*1d48fce0SDaniel Fojt 
519*1d48fce0SDaniel Fojt char *tostringN(const char *s, size_t n)	/* make a copy of string s */
520*1d48fce0SDaniel Fojt {
5214b588458SPeter Avalos 	char *p;
5224b588458SPeter Avalos 
523*1d48fce0SDaniel Fojt 	p = malloc(n);
5244b588458SPeter Avalos 	if (p == NULL)
5254b588458SPeter Avalos 		FATAL("out of space in tostring on %s", s);
5264b588458SPeter Avalos 	strcpy(p, s);
5274b588458SPeter Avalos 	return(p);
5284b588458SPeter Avalos }
5294b588458SPeter Avalos 
530*1d48fce0SDaniel Fojt Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
531*1d48fce0SDaniel Fojt {
532*1d48fce0SDaniel Fojt 	Cell *c;
533*1d48fce0SDaniel Fojt 	char *p;
534*1d48fce0SDaniel Fojt 	char *sa = getsval(a);
535*1d48fce0SDaniel Fojt 	char *sb = getsval(b);
536*1d48fce0SDaniel Fojt 	size_t l = strlen(sa) + strlen(sb) + 1;
537*1d48fce0SDaniel Fojt 	p = malloc(l);
538*1d48fce0SDaniel Fojt 	if (p == NULL)
539*1d48fce0SDaniel Fojt 		FATAL("out of space concatenating %s and %s", sa, sb);
540*1d48fce0SDaniel Fojt 	snprintf(p, l, "%s%s", sa, sb);
541*1d48fce0SDaniel Fojt 
542*1d48fce0SDaniel Fojt 	l++;	// add room for ' '
543*1d48fce0SDaniel Fojt 	char *newbuf = malloc(l);
544*1d48fce0SDaniel Fojt 	if (newbuf == NULL)
545*1d48fce0SDaniel Fojt 		FATAL("out of space concatenating %s and %s", sa, sb);
546*1d48fce0SDaniel Fojt 	// See string() in lex.c; a string "xx" is stored in the symbol
547*1d48fce0SDaniel Fojt 	// table as "xx ".
548*1d48fce0SDaniel Fojt 	snprintf(newbuf, l, "%s ", p);
549*1d48fce0SDaniel Fojt 	c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
550*1d48fce0SDaniel Fojt 	free(p);
551*1d48fce0SDaniel Fojt 	free(newbuf);
552*1d48fce0SDaniel Fojt 	return c;
553*1d48fce0SDaniel Fojt }
554*1d48fce0SDaniel Fojt 
5554b588458SPeter Avalos char *qstring(const char *is, int delim)	/* collect string up to next delim */
5564b588458SPeter Avalos {
5574b588458SPeter Avalos 	const char *os = is;
5584b588458SPeter Avalos 	int c, n;
559*1d48fce0SDaniel Fojt 	const uschar *s = (const uschar *) is;
5604b588458SPeter Avalos 	uschar *buf, *bp;
5614b588458SPeter Avalos 
562*1d48fce0SDaniel Fojt 	if ((buf = malloc(strlen(is)+3)) == NULL)
5634b588458SPeter Avalos 		FATAL( "out of space in qstring(%s)", s);
5644b588458SPeter Avalos 	for (bp = buf; (c = *s) != delim; s++) {
5654b588458SPeter Avalos 		if (c == '\n')
5664b588458SPeter Avalos 			SYNTAX( "newline in string %.20s...", os );
5674b588458SPeter Avalos 		else if (c != '\\')
5684b588458SPeter Avalos 			*bp++ = c;
5694b588458SPeter Avalos 		else {	/* \something */
5704b588458SPeter Avalos 			c = *++s;
5714b588458SPeter Avalos 			if (c == 0) {	/* \ at end */
5724b588458SPeter Avalos 				*bp++ = '\\';
5734b588458SPeter Avalos 				break;	/* for loop */
5744b588458SPeter Avalos 			}
5754b588458SPeter Avalos 			switch (c) {
5764b588458SPeter Avalos 			case '\\':	*bp++ = '\\'; break;
5774b588458SPeter Avalos 			case 'n':	*bp++ = '\n'; break;
5784b588458SPeter Avalos 			case 't':	*bp++ = '\t'; break;
5794b588458SPeter Avalos 			case 'b':	*bp++ = '\b'; break;
5804b588458SPeter Avalos 			case 'f':	*bp++ = '\f'; break;
5814b588458SPeter Avalos 			case 'r':	*bp++ = '\r'; break;
582*1d48fce0SDaniel Fojt 			case 'v':	*bp++ = '\v'; break;
583*1d48fce0SDaniel Fojt 			case 'a':	*bp++ = '\a'; break;
5844b588458SPeter Avalos 			default:
5854b588458SPeter Avalos 				if (!isdigit(c)) {
5864b588458SPeter Avalos 					*bp++ = c;
5874b588458SPeter Avalos 					break;
5884b588458SPeter Avalos 				}
5894b588458SPeter Avalos 				n = c - '0';
5904b588458SPeter Avalos 				if (isdigit(s[1])) {
5914b588458SPeter Avalos 					n = 8 * n + *++s - '0';
5924b588458SPeter Avalos 					if (isdigit(s[1]))
5934b588458SPeter Avalos 						n = 8 * n + *++s - '0';
5944b588458SPeter Avalos 				}
5954b588458SPeter Avalos 				*bp++ = n;
5964b588458SPeter Avalos 				break;
5974b588458SPeter Avalos 			}
5984b588458SPeter Avalos 		}
5994b588458SPeter Avalos 	}
6004b588458SPeter Avalos 	*bp++ = 0;
6014b588458SPeter Avalos 	return (char *) buf;
6024b588458SPeter Avalos }
603*1d48fce0SDaniel Fojt 
604*1d48fce0SDaniel Fojt const char *flags2str(int flags)
605*1d48fce0SDaniel Fojt {
606*1d48fce0SDaniel Fojt 	static const struct ftab {
607*1d48fce0SDaniel Fojt 		const char *name;
608*1d48fce0SDaniel Fojt 		int value;
609*1d48fce0SDaniel Fojt 	} flagtab[] = {
610*1d48fce0SDaniel Fojt 		{ "NUM", NUM },
611*1d48fce0SDaniel Fojt 		{ "STR", STR },
612*1d48fce0SDaniel Fojt 		{ "DONTFREE", DONTFREE },
613*1d48fce0SDaniel Fojt 		{ "CON", CON },
614*1d48fce0SDaniel Fojt 		{ "ARR", ARR },
615*1d48fce0SDaniel Fojt 		{ "FCN", FCN },
616*1d48fce0SDaniel Fojt 		{ "FLD", FLD },
617*1d48fce0SDaniel Fojt 		{ "REC", REC },
618*1d48fce0SDaniel Fojt 		{ "CONVC", CONVC },
619*1d48fce0SDaniel Fojt 		{ "CONVO", CONVO },
620*1d48fce0SDaniel Fojt 		{ NULL, 0 }
621*1d48fce0SDaniel Fojt 	};
622*1d48fce0SDaniel Fojt 	static char buf[100];
623*1d48fce0SDaniel Fojt 	int i;
624*1d48fce0SDaniel Fojt 	char *cp = buf;
625*1d48fce0SDaniel Fojt 
626*1d48fce0SDaniel Fojt 	for (i = 0; flagtab[i].name != NULL; i++) {
627*1d48fce0SDaniel Fojt 		if ((flags & flagtab[i].value) != 0) {
628*1d48fce0SDaniel Fojt 			if (cp > buf)
629*1d48fce0SDaniel Fojt 				*cp++ = '|';
630*1d48fce0SDaniel Fojt 			strcpy(cp, flagtab[i].name);
631*1d48fce0SDaniel Fojt 			cp += strlen(cp);
632*1d48fce0SDaniel Fojt 		}
633*1d48fce0SDaniel Fojt 	}
634*1d48fce0SDaniel Fojt 
635*1d48fce0SDaniel Fojt 	return buf;
636*1d48fce0SDaniel Fojt }
637