xref: /freebsd/contrib/one-true-awk/tran.c (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
4 
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name Lucent Technologies or any of
11 its entities not be used in advertising or publicity pertaining
12 to distribution of the software without specific, written prior
13 permission.
14 
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 THIS SOFTWARE.
23 ****************************************************************/
24 
25 #define	DEBUG
26 #include <stdio.h>
27 #include <math.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include "awk.h"
32 #include "ytab.h"
33 
34 #define	FULLTAB	2	/* rehash when table gets this x full */
35 #define	GROWTAB 4	/* grow table by this factor */
36 
37 Array	*symtab;	/* main symbol table */
38 
39 char	**FS;		/* initial field sep */
40 char	**RS;		/* initial record sep */
41 char	**OFS;		/* output field sep */
42 char	**ORS;		/* output record sep */
43 char	**OFMT;		/* output format for numbers */
44 char	**CONVFMT;	/* format for conversions in getsval */
45 Awkfloat *NF;		/* number of fields in current record */
46 Awkfloat *NR;		/* number of current record */
47 Awkfloat *FNR;		/* number of current record in current file */
48 char	**FILENAME;	/* current filename argument */
49 Awkfloat *ARGC;		/* number of arguments from command line */
50 char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
51 Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
52 Awkfloat *RLENGTH;	/* length of same */
53 
54 Cell	*fsloc;		/* FS */
55 Cell	*nrloc;		/* NR */
56 Cell	*nfloc;		/* NF */
57 Cell	*fnrloc;	/* FNR */
58 Array	*ARGVtab;	/* symbol table containing ARGV[...] */
59 Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
60 Cell	*rstartloc;	/* RSTART */
61 Cell	*rlengthloc;	/* RLENGTH */
62 Cell	*symtabloc;	/* SYMTAB */
63 
64 Cell	*nullloc;	/* a guaranteed empty cell */
65 Node	*nullnode;	/* zero&null, converted into a node for comparisons */
66 Cell	*literal0;
67 
68 extern Cell **fldtab;
69 
70 void syminit(void)	/* initialize symbol table with builtin vars */
71 {
72 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
73 	/* this is used for if(x)... tests: */
74 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
75 	nullnode = celltonode(nullloc, CCON);
76 
77 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
78 	FS = &fsloc->sval;
79 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
80 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
81 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
82 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
83 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
85 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
86 	NF = &nfloc->fval;
87 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
88 	NR = &nrloc->fval;
89 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
90 	FNR = &fnrloc->fval;
91 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
92 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
93 	RSTART = &rstartloc->fval;
94 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
95 	RLENGTH = &rlengthloc->fval;
96 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
97 	symtabloc->sval = (char *) symtab;
98 }
99 
100 void arginit(int ac, char **av)	/* set up ARGV and ARGC */
101 {
102 	Cell *cp;
103 	int i;
104 	char temp[50];
105 
106 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
107 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
108 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
109 	cp->sval = (char *) ARGVtab;
110 	for (i = 0; i < ac; i++) {
111 		sprintf(temp, "%d", i);
112 		if (is_number(*av))
113 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
114 		else
115 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
116 		av++;
117 	}
118 }
119 
120 void envinit(char **envp)	/* set up ENVIRON variable */
121 {
122 	Cell *cp;
123 	char *p;
124 
125 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
126 	ENVtab = makesymtab(NSYMTAB);
127 	cp->sval = (char *) ENVtab;
128 	for ( ; *envp; envp++) {
129 		if ((p = strchr(*envp, '=')) == NULL)
130 			continue;
131 		if( p == *envp ) /* no left hand side name in env string */
132 			continue;
133 		*p++ = 0;	/* split into two strings at = */
134 		if (is_number(p))
135 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
136 		else
137 			setsymtab(*envp, p, 0.0, STR, ENVtab);
138 		p[-1] = '=';	/* restore in case env is passed down to a shell */
139 	}
140 }
141 
142 Array *makesymtab(int n)	/* make a new symbol table */
143 {
144 	Array *ap;
145 	Cell **tp;
146 
147 	ap = (Array *) malloc(sizeof(Array));
148 	tp = (Cell **) calloc(n, sizeof(Cell *));
149 	if (ap == NULL || tp == NULL)
150 		FATAL("out of space in makesymtab");
151 	ap->nelem = 0;
152 	ap->size = n;
153 	ap->tab = tp;
154 	return(ap);
155 }
156 
157 void freesymtab(Cell *ap)	/* free a symbol table */
158 {
159 	Cell *cp, *temp;
160 	Array *tp;
161 	int i;
162 
163 	if (!isarr(ap))
164 		return;
165 	tp = (Array *) ap->sval;
166 	if (tp == NULL)
167 		return;
168 	for (i = 0; i < tp->size; i++) {
169 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
170 			xfree(cp->nval);
171 			if (freeable(cp))
172 				xfree(cp->sval);
173 			temp = cp->cnext;	/* avoids freeing then using */
174 			free(cp);
175 			tp->nelem--;
176 		}
177 		tp->tab[i] = 0;
178 	}
179 	if (tp->nelem != 0)
180 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
181 	free(tp->tab);
182 	free(tp);
183 }
184 
185 void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
186 {
187 	Array *tp;
188 	Cell *p, *prev = NULL;
189 	int h;
190 
191 	tp = (Array *) ap->sval;
192 	h = hash(s, tp->size);
193 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
194 		if (strcmp(s, p->nval) == 0) {
195 			if (prev == NULL)	/* 1st one */
196 				tp->tab[h] = p->cnext;
197 			else			/* middle somewhere */
198 				prev->cnext = p->cnext;
199 			if (freeable(p))
200 				xfree(p->sval);
201 			free(p->nval);
202 			free(p);
203 			tp->nelem--;
204 			return;
205 		}
206 }
207 
208 Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
209 {
210 	int h;
211 	Cell *p;
212 
213 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
214 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
215 			p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
216 		return(p);
217 	}
218 	p = (Cell *) malloc(sizeof(Cell));
219 	if (p == NULL)
220 		FATAL("out of space for symbol table at %s", n);
221 	p->nval = tostring(n);
222 	p->sval = s ? tostring(s) : tostring("");
223 	p->fval = f;
224 	p->tval = t;
225 	p->csub = CUNK;
226 	p->ctype = OCELL;
227 	tp->nelem++;
228 	if (tp->nelem > FULLTAB * tp->size)
229 		rehash(tp);
230 	h = hash(n, tp->size);
231 	p->cnext = tp->tab[h];
232 	tp->tab[h] = p;
233 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
234 		p, p->nval, p->sval, p->fval, p->tval) );
235 	return(p);
236 }
237 
238 int hash(const char *s, int n)	/* form hash value for string s */
239 {
240 	unsigned hashval;
241 
242 	for (hashval = 0; *s != '\0'; s++)
243 		hashval = (*s + 31 * hashval);
244 	return hashval % n;
245 }
246 
247 void rehash(Array *tp)	/* rehash items in small table into big one */
248 {
249 	int i, nh, nsz;
250 	Cell *cp, *op, **np;
251 
252 	nsz = GROWTAB * tp->size;
253 	np = (Cell **) calloc(nsz, sizeof(Cell *));
254 	if (np == NULL)		/* can't do it, but can keep running. */
255 		return;		/* someone else will run out later. */
256 	for (i = 0; i < tp->size; i++) {
257 		for (cp = tp->tab[i]; cp; cp = op) {
258 			op = cp->cnext;
259 			nh = hash(cp->nval, nsz);
260 			cp->cnext = np[nh];
261 			np[nh] = cp;
262 		}
263 	}
264 	free(tp->tab);
265 	tp->tab = np;
266 	tp->size = nsz;
267 }
268 
269 Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
270 {
271 	Cell *p;
272 	int h;
273 
274 	h = hash(s, tp->size);
275 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
276 		if (strcmp(s, p->nval) == 0)
277 			return(p);	/* found it */
278 	return(NULL);			/* not found */
279 }
280 
281 Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
282 {
283 	int fldno;
284 
285 	if ((vp->tval & (NUM | STR)) == 0)
286 		funnyvar(vp, "assign to");
287 	if (isfld(vp)) {
288 		donerec = 0;	/* mark $0 invalid */
289 		fldno = atoi(vp->nval);
290 		if (fldno > *NF)
291 			newfld(fldno);
292 		   dprintf( ("setting field %d to %g\n", fldno, f) );
293 	} else if (isrec(vp)) {
294 		donefld = 0;	/* mark $1... invalid */
295 		donerec = 1;
296 	}
297 	if (freeable(vp))
298 		xfree(vp->sval); /* free any previous string */
299 	vp->tval &= ~STR;	/* mark string invalid */
300 	vp->tval |= NUM;	/* mark number ok */
301 	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) );
302 	return vp->fval = f;
303 }
304 
305 void funnyvar(Cell *vp, const char *rw)
306 {
307 	if (isarr(vp))
308 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
309 	if (vp->tval & FCN)
310 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
311 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
312 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
313 }
314 
315 char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
316 {
317 	char *t;
318 	int fldno;
319 
320 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
321 		vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
322 	if ((vp->tval & (NUM | STR)) == 0)
323 		funnyvar(vp, "assign to");
324 	if (isfld(vp)) {
325 		donerec = 0;	/* mark $0 invalid */
326 		fldno = atoi(vp->nval);
327 		if (fldno > *NF)
328 			newfld(fldno);
329 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
330 	} else if (isrec(vp)) {
331 		donefld = 0;	/* mark $1... invalid */
332 		donerec = 1;
333 	}
334 	t = tostring(s);	/* in case it's self-assign */
335 	if (freeable(vp))
336 		xfree(vp->sval);
337 	vp->tval &= ~NUM;
338 	vp->tval |= STR;
339 	vp->tval &= ~DONTFREE;
340 	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
341 		vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
342 	return(vp->sval = t);
343 }
344 
345 Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
346 {
347 	if ((vp->tval & (NUM | STR)) == 0)
348 		funnyvar(vp, "read value of");
349 	if (isfld(vp) && donefld == 0)
350 		fldbld();
351 	else if (isrec(vp) && donerec == 0)
352 		recbld();
353 	if (!isnum(vp)) {	/* not a number */
354 		vp->fval = atof(vp->sval);	/* best guess */
355 		if (is_number(vp->sval) && !(vp->tval&CON))
356 			vp->tval |= NUM;	/* make NUM only sparingly */
357 	}
358 	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) );
359 	return(vp->fval);
360 }
361 
362 static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
363 {
364 	char s[100];	/* BUG: unchecked */
365 	double dtemp;
366 
367 	if ((vp->tval & (NUM | STR)) == 0)
368 		funnyvar(vp, "read value of");
369 	if (isfld(vp) && donefld == 0)
370 		fldbld();
371 	else if (isrec(vp) && donerec == 0)
372 		recbld();
373 	if (isstr(vp) == 0) {
374 		if (freeable(vp))
375 			xfree(vp->sval);
376 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
377 			sprintf(s, "%.30g", vp->fval);
378 		else
379 			sprintf(s, *fmt, vp->fval);
380 		vp->sval = tostring(s);
381 		vp->tval &= ~DONTFREE;
382 		vp->tval |= STR;
383 	}
384 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
385 	return(vp->sval);
386 }
387 
388 char *getsval(Cell *vp)       /* get string val of a Cell */
389 {
390       return get_str_val(vp, CONVFMT);
391 }
392 
393 char *getpssval(Cell *vp)     /* get string val of a Cell for print */
394 {
395       return get_str_val(vp, OFMT);
396 }
397 
398 
399 char *tostring(const char *s)	/* make a copy of string s */
400 {
401 	char *p;
402 
403 	p = (char *) malloc(strlen(s)+1);
404 	if (p == NULL)
405 		FATAL("out of space in tostring on %s", s);
406 	strcpy(p, s);
407 	return(p);
408 }
409 
410 char *qstring(const char *is, int delim)	/* collect string up to next delim */
411 {
412 	const char *os = is;
413 	int c, n;
414 	uschar *s = (uschar *) is;
415 	uschar *buf, *bp;
416 
417 	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
418 		FATAL( "out of space in qstring(%s)", s);
419 	for (bp = buf; (c = *s) != delim; s++) {
420 		if (c == '\n')
421 			SYNTAX( "newline in string %.20s...", os );
422 		else if (c != '\\')
423 			*bp++ = c;
424 		else {	/* \something */
425 			c = *++s;
426 			if (c == 0) {	/* \ at end */
427 				*bp++ = '\\';
428 				break;	/* for loop */
429 			}
430 			switch (c) {
431 			case '\\':	*bp++ = '\\'; break;
432 			case 'n':	*bp++ = '\n'; break;
433 			case 't':	*bp++ = '\t'; break;
434 			case 'b':	*bp++ = '\b'; break;
435 			case 'f':	*bp++ = '\f'; break;
436 			case 'r':	*bp++ = '\r'; break;
437 			default:
438 				if (!isdigit(c)) {
439 					*bp++ = c;
440 					break;
441 				}
442 				n = c - '0';
443 				if (isdigit(s[1])) {
444 					n = 8 * n + *++s - '0';
445 					if (isdigit(s[1]))
446 						n = 8 * n + *++s - '0';
447 				}
448 				*bp++ = n;
449 				break;
450 			}
451 		}
452 	}
453 	*bp++ = 0;
454 	return (char *) buf;
455 }
456