xref: /titanic_51/usr/src/cmd/awk/tran.c (revision 1ee2e5fa222f6d33d1ff1c48f155973a5e146434)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate 
237c478bd9Sstevel@tonic-gate /*
24*1ee2e5faSnakanon  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
28*1ee2e5faSnakanon /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29*1ee2e5faSnakanon /*	  All Rights Reserved  	*/
307c478bd9Sstevel@tonic-gate 
31*1ee2e5faSnakanon #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #define	DEBUG
347c478bd9Sstevel@tonic-gate #include <stdio.h>
35*1ee2e5faSnakanon #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include "awk.h"
397c478bd9Sstevel@tonic-gate #include "y.tab.h"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #define	FULLTAB	2	/* rehash when table gets this x full */
427c478bd9Sstevel@tonic-gate #define	GROWTAB 4	/* grow table by this factor */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate Array	*symtab;	/* main symbol table */
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate uchar	**FS;		/* initial field sep */
477c478bd9Sstevel@tonic-gate uchar	**RS;		/* initial record sep */
487c478bd9Sstevel@tonic-gate uchar	**OFS;		/* output field sep */
497c478bd9Sstevel@tonic-gate uchar	**ORS;		/* output record sep */
507c478bd9Sstevel@tonic-gate uchar	**OFMT;		/* output format for numbers */
517c478bd9Sstevel@tonic-gate Awkfloat *NF;		/* number of fields in current record */
527c478bd9Sstevel@tonic-gate Awkfloat *NR;		/* number of current record */
537c478bd9Sstevel@tonic-gate Awkfloat *FNR;		/* number of current record in current file */
547c478bd9Sstevel@tonic-gate uchar	**FILENAME;	/* current filename argument */
557c478bd9Sstevel@tonic-gate Awkfloat *ARGC;		/* number of arguments from command line */
567c478bd9Sstevel@tonic-gate uchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
577c478bd9Sstevel@tonic-gate Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
587c478bd9Sstevel@tonic-gate Awkfloat *RLENGTH;	/* length of same */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate Cell	*recloc;	/* location of record */
617c478bd9Sstevel@tonic-gate Cell	*nrloc;		/* NR */
627c478bd9Sstevel@tonic-gate Cell	*nfloc;		/* NF */
637c478bd9Sstevel@tonic-gate Cell	*fnrloc;	/* FNR */
647c478bd9Sstevel@tonic-gate Array	*ARGVtab;	/* symbol table containing ARGV[...] */
657c478bd9Sstevel@tonic-gate Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
667c478bd9Sstevel@tonic-gate Cell	*rstartloc;	/* RSTART */
677c478bd9Sstevel@tonic-gate Cell	*rlengthloc;	/* RLENGTH */
687c478bd9Sstevel@tonic-gate Cell	*symtabloc;	/* SYMTAB */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate Cell	*nullloc;
717c478bd9Sstevel@tonic-gate Node	*nullnode;	/* zero&null, converted into a node for comparisons */
727c478bd9Sstevel@tonic-gate 
73*1ee2e5faSnakanon static	void	rehash(Array *);
747c478bd9Sstevel@tonic-gate 
75*1ee2e5faSnakanon void
76*1ee2e5faSnakanon syminit(void)
777c478bd9Sstevel@tonic-gate {
78*1ee2e5faSnakanon 	Cell	*p;
797c478bd9Sstevel@tonic-gate 
80*1ee2e5faSnakanon 	init_buf(&recdata, &record_size, LINE_INCR);
81*1ee2e5faSnakanon 	record = recdata;
827c478bd9Sstevel@tonic-gate 
83*1ee2e5faSnakanon 	p = getfld(0);
84*1ee2e5faSnakanon 	/* initialize $0 */
85*1ee2e5faSnakanon 	p->nval = (uchar*) "$0";
86*1ee2e5faSnakanon 	p->sval = recdata;
87*1ee2e5faSnakanon 	p->tval = REC|STR|DONTFREE;
88*1ee2e5faSnakanon 
897c478bd9Sstevel@tonic-gate 	symtab = makesymtab(NSYMTAB);
90*1ee2e5faSnakanon 	(void) setsymtab((uchar *)"0", (uchar *)"0", 0.0,
91*1ee2e5faSnakanon 	    NUM|STR|CON|DONTFREE, symtab);
927c478bd9Sstevel@tonic-gate 	/* this is used for if(x)... tests: */
93*1ee2e5faSnakanon 	nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0,
94*1ee2e5faSnakanon 	    NUM|STR|CON|DONTFREE, symtab);
957c478bd9Sstevel@tonic-gate 	nullnode = valtonode(nullloc, CCON);
96*1ee2e5faSnakanon 	recloc = getfld(0);
97*1ee2e5faSnakanon 	FS = &setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
98*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
99*1ee2e5faSnakanon 	RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0,
100*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
101*1ee2e5faSnakanon 	OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0,
102*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
103*1ee2e5faSnakanon 	ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0,
104*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
105*1ee2e5faSnakanon 	OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0,
106*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
107*1ee2e5faSnakanon 	FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0,
108*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
109*1ee2e5faSnakanon 	nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab);
1107c478bd9Sstevel@tonic-gate 	NF = &nfloc->fval;
111*1ee2e5faSnakanon 	nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);
1127c478bd9Sstevel@tonic-gate 	NR = &nrloc->fval;
113*1ee2e5faSnakanon 	fnrloc = setsymtab((uchar *)"FNR", (uchar *)"", 0.0, NUM, symtab);
1147c478bd9Sstevel@tonic-gate 	FNR = &fnrloc->fval;
115*1ee2e5faSnakanon 	SUBSEP = &setsymtab((uchar *)"SUBSEP", (uchar *)"\034", 0.0,
116*1ee2e5faSnakanon 	    STR|DONTFREE, symtab)->sval;
117*1ee2e5faSnakanon 	rstartloc = setsymtab((uchar *)"RSTART", (uchar *)"", 0.0,
118*1ee2e5faSnakanon 	    NUM, symtab);
1197c478bd9Sstevel@tonic-gate 	RSTART = &rstartloc->fval;
120*1ee2e5faSnakanon 	rlengthloc = setsymtab((uchar *)"RLENGTH", (uchar *)"", 0.0,
121*1ee2e5faSnakanon 	    NUM, symtab);
1227c478bd9Sstevel@tonic-gate 	RLENGTH = &rlengthloc->fval;
123*1ee2e5faSnakanon 	symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab);
1247c478bd9Sstevel@tonic-gate 	symtabloc->sval = (uchar *)symtab;
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
127*1ee2e5faSnakanon void
128*1ee2e5faSnakanon arginit(int ac, uchar *av[])
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate 	Cell *cp;
1317c478bd9Sstevel@tonic-gate 	int i;
132*1ee2e5faSnakanon 	uchar temp[11];
1337c478bd9Sstevel@tonic-gate 
134*1ee2e5faSnakanon 	/* first make FILENAME first real argument */
135*1ee2e5faSnakanon 	for (i = 1; i < ac; i++) {
1367c478bd9Sstevel@tonic-gate 		if (!isclvar(av[i])) {
137*1ee2e5faSnakanon 			(void) setsval(lookup((uchar *)"FILENAME", symtab),
138*1ee2e5faSnakanon 			    av[i]);
1397c478bd9Sstevel@tonic-gate 			break;
1407c478bd9Sstevel@tonic-gate 		}
141*1ee2e5faSnakanon 	}
142*1ee2e5faSnakanon 	ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac,
143*1ee2e5faSnakanon 	    NUM, symtab)->fval;
144*1ee2e5faSnakanon 	cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab);
1457c478bd9Sstevel@tonic-gate 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1467c478bd9Sstevel@tonic-gate 	cp->sval = (uchar *) ARGVtab;
1477c478bd9Sstevel@tonic-gate 	for (i = 0; i < ac; i++) {
148*1ee2e5faSnakanon 		(void) sprintf((char *)temp, "%d", i);
149*1ee2e5faSnakanon 		if (is_number(*av)) {
150*1ee2e5faSnakanon 			(void) setsymtab(temp, *av, atof((const char *)*av),
151*1ee2e5faSnakanon 			    STR|NUM, ARGVtab);
152*1ee2e5faSnakanon 		} else {
153*1ee2e5faSnakanon 			(void) setsymtab(temp, *av, 0.0, STR, ARGVtab);
154*1ee2e5faSnakanon 		}
1557c478bd9Sstevel@tonic-gate 		av++;
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
159*1ee2e5faSnakanon void
160*1ee2e5faSnakanon envinit(uchar *envp[])
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	Cell *cp;
1637c478bd9Sstevel@tonic-gate 	uchar *p;
1647c478bd9Sstevel@tonic-gate 
165*1ee2e5faSnakanon 	cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab);
1667c478bd9Sstevel@tonic-gate 	ENVtab = makesymtab(NSYMTAB);
1677c478bd9Sstevel@tonic-gate 	cp->sval = (uchar *) ENVtab;
1687c478bd9Sstevel@tonic-gate 	for (; *envp; envp++) {
169*1ee2e5faSnakanon 		if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL)
1707c478bd9Sstevel@tonic-gate 			continue;
1717c478bd9Sstevel@tonic-gate 		*p++ = 0;	/* split into two strings at = */
172*1ee2e5faSnakanon 		if (is_number(p)) {
173*1ee2e5faSnakanon 			(void) setsymtab(*envp, p, atof((const char *)p),
174*1ee2e5faSnakanon 			    STR|NUM, ENVtab);
175*1ee2e5faSnakanon 		} else {
176*1ee2e5faSnakanon 			(void) setsymtab(*envp, p, 0.0, STR, ENVtab);
177*1ee2e5faSnakanon 		}
178*1ee2e5faSnakanon 		/* restore in case env is passed down to a shell */
179*1ee2e5faSnakanon 		p[-1] = '=';
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
183*1ee2e5faSnakanon Array *
184*1ee2e5faSnakanon makesymtab(int n)
1857c478bd9Sstevel@tonic-gate {
1867c478bd9Sstevel@tonic-gate 	Array *ap;
1877c478bd9Sstevel@tonic-gate 	Cell **tp;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	ap = (Array *)malloc(sizeof (Array));
1907c478bd9Sstevel@tonic-gate 	tp = (Cell **)calloc(n, sizeof (Cell *));
1917c478bd9Sstevel@tonic-gate 	if (ap == NULL || tp == NULL)
1927c478bd9Sstevel@tonic-gate 		ERROR "out of space in makesymtab" FATAL;
1937c478bd9Sstevel@tonic-gate 	ap->nelem = 0;
1947c478bd9Sstevel@tonic-gate 	ap->size = n;
1957c478bd9Sstevel@tonic-gate 	ap->tab = tp;
1967c478bd9Sstevel@tonic-gate 	return (ap);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
199*1ee2e5faSnakanon void
200*1ee2e5faSnakanon freesymtab(Cell *ap)	/* free symbol table */
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	Cell *cp, *next;
2037c478bd9Sstevel@tonic-gate 	Array *tp;
2047c478bd9Sstevel@tonic-gate 	int i;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	if (!isarr(ap))
2077c478bd9Sstevel@tonic-gate 		return;
208*1ee2e5faSnakanon 	/*LINTED align*/
2097c478bd9Sstevel@tonic-gate 	tp = (Array *)ap->sval;
2107c478bd9Sstevel@tonic-gate 	if (tp == NULL)
2117c478bd9Sstevel@tonic-gate 		return;
2127c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->size; i++) {
2137c478bd9Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp != NULL; cp = next) {
2147c478bd9Sstevel@tonic-gate 			next = cp->cnext;
2157c478bd9Sstevel@tonic-gate 			xfree(cp->nval);
2167c478bd9Sstevel@tonic-gate 			if (freeable(cp))
2177c478bd9Sstevel@tonic-gate 				xfree(cp->sval);
2187c478bd9Sstevel@tonic-gate 			free(cp);
2197c478bd9Sstevel@tonic-gate 		}
2207c478bd9Sstevel@tonic-gate 	}
2217c478bd9Sstevel@tonic-gate 	free(tp->tab);
2227c478bd9Sstevel@tonic-gate 	free(tp);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
225*1ee2e5faSnakanon void
226*1ee2e5faSnakanon freeelem(Cell *ap, uchar *s)		/* free elem s from ap (i.e., ap["s"] */
2277c478bd9Sstevel@tonic-gate {
2287c478bd9Sstevel@tonic-gate 	Array *tp;
2297c478bd9Sstevel@tonic-gate 	Cell *p, *prev = NULL;
2307c478bd9Sstevel@tonic-gate 	int h;
2317c478bd9Sstevel@tonic-gate 
232*1ee2e5faSnakanon 	/*LINTED align*/
2337c478bd9Sstevel@tonic-gate 	tp = (Array *)ap->sval;
2347c478bd9Sstevel@tonic-gate 	h = hash(s, tp->size);
2357c478bd9Sstevel@tonic-gate 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
2367c478bd9Sstevel@tonic-gate 		if (strcmp((char *)s, (char *)p->nval) == 0) {
2377c478bd9Sstevel@tonic-gate 			if (prev == NULL)	/* 1st one */
2387c478bd9Sstevel@tonic-gate 				tp->tab[h] = p->cnext;
2397c478bd9Sstevel@tonic-gate 			else			/* middle somewhere */
2407c478bd9Sstevel@tonic-gate 				prev->cnext = p->cnext;
2417c478bd9Sstevel@tonic-gate 			if (freeable(p))
2427c478bd9Sstevel@tonic-gate 				xfree(p->sval);
2437c478bd9Sstevel@tonic-gate 			free(p->nval);
2447c478bd9Sstevel@tonic-gate 			free(p);
2457c478bd9Sstevel@tonic-gate 			tp->nelem--;
2467c478bd9Sstevel@tonic-gate 			return;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate 
250*1ee2e5faSnakanon Cell *
251*1ee2e5faSnakanon setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned int t, Array *tp)
2527c478bd9Sstevel@tonic-gate {
2537c478bd9Sstevel@tonic-gate 	register int h;
2547c478bd9Sstevel@tonic-gate 	register Cell *p;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
257*1ee2e5faSnakanon 		dprintf(("setsymtab found %p: n=%s", (void *)p, p->nval));
258*1ee2e5faSnakanon 		dprintf((" s=\"%s\" f=%g t=%p\n",
259*1ee2e5faSnakanon 		    p->sval, p->fval, (void *)p->tval));
2607c478bd9Sstevel@tonic-gate 		return (p);
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 	p = (Cell *)malloc(sizeof (Cell));
2637c478bd9Sstevel@tonic-gate 	if (p == NULL)
2647c478bd9Sstevel@tonic-gate 		ERROR "symbol table overflow at %s", n FATAL;
2657c478bd9Sstevel@tonic-gate 	p->nval = tostring(n);
266*1ee2e5faSnakanon 	p->sval = s ? tostring(s) : tostring((uchar *)"");
2677c478bd9Sstevel@tonic-gate 	p->fval = f;
2687c478bd9Sstevel@tonic-gate 	p->tval = t;
2697c478bd9Sstevel@tonic-gate 	p->csub = 0;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	tp->nelem++;
2727c478bd9Sstevel@tonic-gate 	if (tp->nelem > FULLTAB * tp->size)
2737c478bd9Sstevel@tonic-gate 		rehash(tp);
2747c478bd9Sstevel@tonic-gate 	h = hash(n, tp->size);
2757c478bd9Sstevel@tonic-gate 	p->cnext = tp->tab[h];
2767c478bd9Sstevel@tonic-gate 	tp->tab[h] = p;
277*1ee2e5faSnakanon 	dprintf(("setsymtab set %p: n=%s", (void *)p, p->nval));
278*1ee2e5faSnakanon 	dprintf((" s=\"%s\" f=%g t=%p\n", p->sval, p->fval, (void *)p->tval));
2797c478bd9Sstevel@tonic-gate 	return (p);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
282*1ee2e5faSnakanon int
283*1ee2e5faSnakanon hash(uchar *s, int n)	/* form hash value for string s */
2847c478bd9Sstevel@tonic-gate {
2857c478bd9Sstevel@tonic-gate 	register unsigned hashval;
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	for (hashval = 0; *s != '\0'; s++)
2887c478bd9Sstevel@tonic-gate 		hashval = (*s + 31 * hashval);
289*1ee2e5faSnakanon 	return (hashval % n);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
292*1ee2e5faSnakanon static void
293*1ee2e5faSnakanon rehash(Array *tp)	/* rehash items in small table into big one */
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	int i, nh, nsz;
2967c478bd9Sstevel@tonic-gate 	Cell *cp, *op, **np;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	nsz = GROWTAB * tp->size;
2997c478bd9Sstevel@tonic-gate 	np = (Cell **)calloc(nsz, sizeof (Cell *));
3007c478bd9Sstevel@tonic-gate 	if (np == NULL)
3017c478bd9Sstevel@tonic-gate 		ERROR "out of space in rehash" FATAL;
3027c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->size; i++) {
3037c478bd9Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp; cp = op) {
3047c478bd9Sstevel@tonic-gate 			op = cp->cnext;
3057c478bd9Sstevel@tonic-gate 			nh = hash(cp->nval, nsz);
3067c478bd9Sstevel@tonic-gate 			cp->cnext = np[nh];
3077c478bd9Sstevel@tonic-gate 			np[nh] = cp;
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	free(tp->tab);
3117c478bd9Sstevel@tonic-gate 	tp->tab = np;
3127c478bd9Sstevel@tonic-gate 	tp->size = nsz;
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
315*1ee2e5faSnakanon Cell *
316*1ee2e5faSnakanon lookup(uchar *s, Array *tp)	/* look for s in tp */
3177c478bd9Sstevel@tonic-gate {
318*1ee2e5faSnakanon 	register Cell *p;
3197c478bd9Sstevel@tonic-gate 	int h;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	h = hash(s, tp->size);
322*1ee2e5faSnakanon 	for (p = tp->tab[h]; p != NULL; p = p->cnext) {
3237c478bd9Sstevel@tonic-gate 		if (strcmp((char *)s, (char *)p->nval) == 0)
3247c478bd9Sstevel@tonic-gate 			return (p);	/* found it */
325*1ee2e5faSnakanon 	}
3267c478bd9Sstevel@tonic-gate 	return (NULL);			/* not found */
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
329*1ee2e5faSnakanon Awkfloat
330*1ee2e5faSnakanon setfval(Cell *vp, Awkfloat f)
3317c478bd9Sstevel@tonic-gate {
332*1ee2e5faSnakanon 	int	i;
333*1ee2e5faSnakanon 
3347c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
3357c478bd9Sstevel@tonic-gate 		funnyvar(vp, "assign to");
3367c478bd9Sstevel@tonic-gate 	if (vp->tval & FLD) {
3377c478bd9Sstevel@tonic-gate 		donerec = 0;	/* mark $0 invalid */
338*1ee2e5faSnakanon 		i = fldidx(vp);
339*1ee2e5faSnakanon 		if (i > *NF)
340*1ee2e5faSnakanon 			newfld(i);
341*1ee2e5faSnakanon 		dprintf(("setting field %d to %g\n", i, f));
3427c478bd9Sstevel@tonic-gate 	} else if (vp->tval & REC) {
3437c478bd9Sstevel@tonic-gate 		donefld = 0;	/* mark $1... invalid */
3447c478bd9Sstevel@tonic-gate 		donerec = 1;
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 	vp->tval &= ~STR;	/* mark string invalid */
3477c478bd9Sstevel@tonic-gate 	vp->tval |= NUM;	/* mark number ok */
348*1ee2e5faSnakanon 	dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp,
3497c478bd9Sstevel@tonic-gate 	    vp->nval ? vp->nval : (unsigned char *)"NULL",
350*1ee2e5faSnakanon 	    f, (void *)vp->tval));
351*1ee2e5faSnakanon 	return (vp->fval = f);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate 
354*1ee2e5faSnakanon void
355*1ee2e5faSnakanon funnyvar(Cell *vp, char *rw)
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	if (vp->tval & ARR)
3587c478bd9Sstevel@tonic-gate 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
3597c478bd9Sstevel@tonic-gate 	if (vp->tval & FCN)
3607c478bd9Sstevel@tonic-gate 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
3617c478bd9Sstevel@tonic-gate 	ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
362*1ee2e5faSnakanon 	    vp, vp->nval, vp->sval, vp->fval, vp->tval CONT;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
365*1ee2e5faSnakanon uchar *
366*1ee2e5faSnakanon setsval(Cell *vp, uchar *s)
3677c478bd9Sstevel@tonic-gate {
368*1ee2e5faSnakanon 	int	i;
369*1ee2e5faSnakanon 
3707c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
3717c478bd9Sstevel@tonic-gate 		funnyvar(vp, "assign to");
3727c478bd9Sstevel@tonic-gate 	if (vp->tval & FLD) {
3737c478bd9Sstevel@tonic-gate 		donerec = 0;	/* mark $0 invalid */
374*1ee2e5faSnakanon 		i = fldidx(vp);
375*1ee2e5faSnakanon 		if (i > *NF)
376*1ee2e5faSnakanon 			newfld(i);
377*1ee2e5faSnakanon 		dprintf(("setting field %d to %s\n", i, s));
3787c478bd9Sstevel@tonic-gate 	} else if (vp->tval & REC) {
3797c478bd9Sstevel@tonic-gate 		donefld = 0;	/* mark $1... invalid */
3807c478bd9Sstevel@tonic-gate 		donerec = 1;
3817c478bd9Sstevel@tonic-gate 	}
3827c478bd9Sstevel@tonic-gate 	vp->tval &= ~NUM;
3837c478bd9Sstevel@tonic-gate 	vp->tval |= STR;
3847c478bd9Sstevel@tonic-gate 	if (freeable(vp))
3857c478bd9Sstevel@tonic-gate 		xfree(vp->sval);
3867c478bd9Sstevel@tonic-gate 	vp->tval &= ~DONTFREE;
387*1ee2e5faSnakanon 	dprintf(("setsval %p: %s = \"%s\", t=%p\n",
388*1ee2e5faSnakanon 	    (void *)vp,
389*1ee2e5faSnakanon 	    vp->nval ? (char *)vp->nval : "",
390*1ee2e5faSnakanon 	    s,
391*1ee2e5faSnakanon 	    (void *)(vp->tval ? (char *)vp->tval : "")));
3927c478bd9Sstevel@tonic-gate 	return (vp->sval = tostring(s));
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
395*1ee2e5faSnakanon Awkfloat
396*1ee2e5faSnakanon r_getfval(Cell *vp)
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
3997c478bd9Sstevel@tonic-gate 		funnyvar(vp, "read value of");
4007c478bd9Sstevel@tonic-gate 	if ((vp->tval & FLD) && donefld == 0)
4017c478bd9Sstevel@tonic-gate 		fldbld();
4027c478bd9Sstevel@tonic-gate 	else if ((vp->tval & REC) && donerec == 0)
4037c478bd9Sstevel@tonic-gate 		recbld();
4047c478bd9Sstevel@tonic-gate 	if (!isnum(vp)) {	/* not a number */
405*1ee2e5faSnakanon 		vp->fval = atof((const char *)vp->sval);	/* best guess */
406*1ee2e5faSnakanon 		if (is_number(vp->sval) && !(vp->tval&CON))
4077c478bd9Sstevel@tonic-gate 			vp->tval |= NUM;	/* make NUM only sparingly */
4087c478bd9Sstevel@tonic-gate 	}
409*1ee2e5faSnakanon 	dprintf(("getfval %p: %s = %g, t=%p\n",
410*1ee2e5faSnakanon 	    (void *)vp, vp->nval, vp->fval, (void *)vp->tval));
4117c478bd9Sstevel@tonic-gate 	return (vp->fval);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
414*1ee2e5faSnakanon uchar *
415*1ee2e5faSnakanon r_getsval(Cell *vp)
4167c478bd9Sstevel@tonic-gate {
417*1ee2e5faSnakanon 	uchar s[256];
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
4207c478bd9Sstevel@tonic-gate 		funnyvar(vp, "read value of");
4217c478bd9Sstevel@tonic-gate 	if ((vp->tval & FLD) && donefld == 0)
4227c478bd9Sstevel@tonic-gate 		fldbld();
4237c478bd9Sstevel@tonic-gate 	else if ((vp->tval & REC) && donerec == 0)
4247c478bd9Sstevel@tonic-gate 		recbld();
4257c478bd9Sstevel@tonic-gate 	if ((vp->tval & STR) == 0) {
4267c478bd9Sstevel@tonic-gate 		if (!(vp->tval&DONTFREE))
4277c478bd9Sstevel@tonic-gate 			xfree(vp->sval);
428*1ee2e5faSnakanon 		if ((long long)vp->fval == vp->fval) {
429*1ee2e5faSnakanon 			(void) snprintf((char *)s, sizeof (s),
430*1ee2e5faSnakanon 			    "%.20g", vp->fval);
431*1ee2e5faSnakanon 		} else {
432*1ee2e5faSnakanon 			/*LINTED*/
433*1ee2e5faSnakanon 			(void) snprintf((char *)s, sizeof (s),
434*1ee2e5faSnakanon 			    (char *)*OFMT, vp->fval);
435*1ee2e5faSnakanon 		}
4367c478bd9Sstevel@tonic-gate 		vp->sval = tostring(s);
4377c478bd9Sstevel@tonic-gate 		vp->tval &= ~DONTFREE;
4387c478bd9Sstevel@tonic-gate 		vp->tval |= STR;
4397c478bd9Sstevel@tonic-gate 	}
440*1ee2e5faSnakanon 	dprintf(("getsval %p: %s = \"%s\", t=%p\n",
441*1ee2e5faSnakanon 	    (void *)vp,
442*1ee2e5faSnakanon 	    vp->nval ? (char *)vp->nval : "",
443*1ee2e5faSnakanon 	    vp->sval ? (char *)vp->sval : "",
444*1ee2e5faSnakanon 	    (void *)vp->tval));
4457c478bd9Sstevel@tonic-gate 	return (vp->sval);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
448*1ee2e5faSnakanon uchar *
449*1ee2e5faSnakanon tostring(uchar *s)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	register uchar *p;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	p = (uchar *)malloc(strlen((char *)s)+1);
4547c478bd9Sstevel@tonic-gate 	if (p == NULL)
4557c478bd9Sstevel@tonic-gate 		ERROR "out of space in tostring on %s", s FATAL;
456*1ee2e5faSnakanon 	(void) strcpy((char *)p, (char *)s);
4577c478bd9Sstevel@tonic-gate 	return (p);
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate 
460*1ee2e5faSnakanon uchar *
461*1ee2e5faSnakanon qstring(uchar *s, int delim)	/* collect string up to delim */
4627c478bd9Sstevel@tonic-gate {
463*1ee2e5faSnakanon 	uchar *cbuf, *ret;
4647c478bd9Sstevel@tonic-gate 	int c, n;
465*1ee2e5faSnakanon 	size_t	cbufsz, cnt;
4667c478bd9Sstevel@tonic-gate 
467*1ee2e5faSnakanon 	init_buf(&cbuf, &cbufsz, LINE_INCR);
468*1ee2e5faSnakanon 
469*1ee2e5faSnakanon 	for (cnt = 0; (c = *s) != delim; s++) {
470*1ee2e5faSnakanon 		if (c == '\n') {
4717c478bd9Sstevel@tonic-gate 			ERROR "newline in string %.10s...", cbuf SYNTAX;
472*1ee2e5faSnakanon 		} else if (c != '\\') {
473*1ee2e5faSnakanon 			expand_buf(&cbuf, &cbufsz, cnt);
474*1ee2e5faSnakanon 			cbuf[cnt++] = c;
475*1ee2e5faSnakanon 		} else {	/* \something */
476*1ee2e5faSnakanon 			expand_buf(&cbuf, &cbufsz, cnt);
4777c478bd9Sstevel@tonic-gate 			switch (c = *++s) {
478*1ee2e5faSnakanon 			case '\\':	cbuf[cnt++] = '\\'; break;
479*1ee2e5faSnakanon 			case 'n':	cbuf[cnt++] = '\n'; break;
480*1ee2e5faSnakanon 			case 't':	cbuf[cnt++] = '\t'; break;
481*1ee2e5faSnakanon 			case 'b':	cbuf[cnt++] = '\b'; break;
482*1ee2e5faSnakanon 			case 'f':	cbuf[cnt++] = '\f'; break;
483*1ee2e5faSnakanon 			case 'r':	cbuf[cnt++] = '\r'; break;
4847c478bd9Sstevel@tonic-gate 			default:
4857c478bd9Sstevel@tonic-gate 				if (!isdigit(c)) {
486*1ee2e5faSnakanon 					cbuf[cnt++] = c;
4877c478bd9Sstevel@tonic-gate 					break;
4887c478bd9Sstevel@tonic-gate 				}
4897c478bd9Sstevel@tonic-gate 				n = c - '0';
4907c478bd9Sstevel@tonic-gate 				if (isdigit(s[1])) {
4917c478bd9Sstevel@tonic-gate 					n = 8 * n + *++s - '0';
4927c478bd9Sstevel@tonic-gate 					if (isdigit(s[1]))
4937c478bd9Sstevel@tonic-gate 						n = 8 * n + *++s - '0';
4947c478bd9Sstevel@tonic-gate 				}
495*1ee2e5faSnakanon 				cbuf[cnt++] = n;
4967c478bd9Sstevel@tonic-gate 				break;
4977c478bd9Sstevel@tonic-gate 			}
4987c478bd9Sstevel@tonic-gate 		}
499*1ee2e5faSnakanon 	}
500*1ee2e5faSnakanon 	cbuf[cnt] = '\0';
501*1ee2e5faSnakanon 	ret = tostring(cbuf);
502*1ee2e5faSnakanon 	free(cbuf);
503*1ee2e5faSnakanon 	return (ret);
5047c478bd9Sstevel@tonic-gate }
505