Import of awk version 20100523
[dragonfly.git] / contrib / awk20070501 / tran.c
CommitLineData
7d2a10de
PA
1/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS 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
37Array *symtab; /* main symbol table */
38
39char **FS; /* initial field sep */
40char **RS; /* initial record sep */
41char **OFS; /* output field sep */
42char **ORS; /* output record sep */
43char **OFMT; /* output format for numbers */
44char **CONVFMT; /* format for conversions in getsval */
45Awkfloat *NF; /* number of fields in current record */
46Awkfloat *NR; /* number of current record */
47Awkfloat *FNR; /* number of current record in current file */
48char **FILENAME; /* current filename argument */
49Awkfloat *ARGC; /* number of arguments from command line */
50char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
51Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
52Awkfloat *RLENGTH; /* length of same */
53
54Cell *fsloc; /* FS */
55Cell *nrloc; /* NR */
56Cell *nfloc; /* NF */
57Cell *fnrloc; /* FNR */
58Array *ARGVtab; /* symbol table containing ARGV[...] */
59Array *ENVtab; /* symbol table containing ENVIRON[...] */
60Cell *rstartloc; /* RSTART */
61Cell *rlengthloc; /* RLENGTH */
62Cell *symtabloc; /* SYMTAB */
63
64Cell *nullloc; /* a guaranteed empty cell */
65Node *nullnode; /* zero&null, converted into a node for comparisons */
66Cell *literal0;
67
68extern Cell **fldtab;
69
70void 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
100void 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
120void 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
142Array *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
157void 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
185void 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
208Cell *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
238int 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
247void 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
269Cell *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
281Awkfloat 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
305void 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
315char *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 vp->tval &= ~NUM;
336 vp->tval |= STR;
337 if (freeable(vp))
338 xfree(vp->sval);
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
345Awkfloat 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
362static 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
388char *getsval(Cell *vp) /* get string val of a Cell */
389{
390 return get_str_val(vp, CONVFMT);
391}
392
393char *getpssval(Cell *vp) /* get string val of a Cell for print */
394{
395 return get_str_val(vp, OFMT);
396}
397
398
399char *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
410char *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}