Sync usage with man page.
[netbsd-mini2440.git] / dist / nawk / tran.c
blob9d6523ab26919205a2069617e9e98f4ddcb667a4
1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
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.
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 ****************************************************************/
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
27 #endif
29 #define DEBUG
30 #include <stdio.h>
31 #include <math.h>
32 #include <ctype.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include "awk.h"
36 #include "awkgram.h"
38 #define FULLTAB 2 /* rehash when table gets this x full */
39 #define GROWTAB 4 /* grow table by this factor */
41 Array *symtab; /* main symbol table */
43 char **FS; /* initial field sep */
44 char **RS; /* initial record sep */
45 char **OFS; /* output field sep */
46 char **ORS; /* output record sep */
47 char **OFMT; /* output format for numbers */
48 char **CONVFMT; /* format for conversions in getsval */
49 Awkfloat *NF; /* number of fields in current record */
50 Awkfloat *NR; /* number of current record */
51 Awkfloat *FNR; /* number of current record in current file */
52 char **FILENAME; /* current filename argument */
53 Awkfloat *ARGC; /* number of arguments from command line */
54 char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
55 Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
56 Awkfloat *RLENGTH; /* length of same */
58 Cell *fsloc; /* FS */
59 Cell *nrloc; /* NR */
60 Cell *nfloc; /* NF */
61 Cell *fnrloc; /* FNR */
62 Array *ARGVtab; /* symbol table containing ARGV[...] */
63 Array *ENVtab; /* symbol table containing ENVIRON[...] */
64 Cell *rstartloc; /* RSTART */
65 Cell *rlengthloc; /* RLENGTH */
66 Cell *symtabloc; /* SYMTAB */
68 Cell *nullloc; /* a guaranteed empty cell */
69 Node *nullnode; /* zero&null, converted into a node for comparisons */
70 Cell *literal0;
72 extern Cell **fldtab;
74 void syminit(void) /* initialize symbol table with builtin vars */
76 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
77 /* this is used for if(x)... tests: */
78 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
79 nullnode = celltonode(nullloc, CCON);
81 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
82 FS = &fsloc->sval;
83 RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
84 OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
85 ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
86 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
87 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
88 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
89 nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
90 NF = &nfloc->fval;
91 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
92 NR = &nrloc->fval;
93 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
94 FNR = &fnrloc->fval;
95 SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
96 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
97 RSTART = &rstartloc->fval;
98 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
99 RLENGTH = &rlengthloc->fval;
100 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
101 symtabloc->sval = (char *) symtab;
104 void arginit(int ac, char **av) /* set up ARGV and ARGC */
106 Cell *cp;
107 int i;
108 char temp[50];
110 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
111 cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
112 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
113 cp->sval = (char *) ARGVtab;
114 for (i = 0; i < ac; i++) {
115 snprintf(temp, sizeof(temp), "%d", i);
116 if (is_number(*av))
117 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
118 else
119 setsymtab(temp, *av, 0.0, STR, ARGVtab);
120 av++;
124 void envinit(char **envp) /* set up ENVIRON variable */
126 Cell *cp;
127 char *p;
129 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
130 ENVtab = makesymtab(NSYMTAB);
131 cp->sval = (char *) ENVtab;
132 for ( ; *envp; envp++) {
133 if ((p = strchr(*envp, '=')) == NULL)
134 continue;
135 if( p == *envp ) /* no left hand side name in env string */
136 continue;
137 *p++ = 0; /* split into two strings at = */
138 if (is_number(p))
139 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
140 else
141 setsymtab(*envp, p, 0.0, STR, ENVtab);
142 p[-1] = '='; /* restore in case env is passed down to a shell */
146 Array *makesymtab(int n) /* make a new symbol table */
148 Array *ap;
149 Cell **tp;
151 ap = (Array *) malloc(sizeof(Array));
152 tp = (Cell **) calloc(n, sizeof(Cell *));
153 if (ap == NULL || tp == NULL)
154 FATAL("out of space in makesymtab");
155 ap->nelem = 0;
156 ap->size = n;
157 ap->tab = tp;
158 return(ap);
161 void freesymtab(Cell *ap) /* free a symbol table */
163 Cell *cp, *temp;
164 Array *tp;
165 int i;
167 if (!isarr(ap))
168 return;
169 tp = (Array *) ap->sval;
170 if (tp == NULL)
171 return;
172 for (i = 0; i < tp->size; i++) {
173 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
174 xfree(cp->nval);
175 if (freeable(cp))
176 xfree(cp->sval);
177 temp = cp->cnext; /* avoids freeing then using */
178 free(cp);
179 tp->nelem--;
181 tp->tab[i] = 0;
183 if (tp->nelem != 0)
184 WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
185 free(tp->tab);
186 free(tp);
189 void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
191 Array *tp;
192 Cell *p, *prev = NULL;
193 int h;
195 tp = (Array *) ap->sval;
196 h = hash(s, tp->size);
197 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
198 if (strcmp(s, p->nval) == 0) {
199 if (prev == NULL) /* 1st one */
200 tp->tab[h] = p->cnext;
201 else /* middle somewhere */
202 prev->cnext = p->cnext;
203 if (freeable(p))
204 xfree(p->sval);
205 free(p->nval);
206 free(p);
207 tp->nelem--;
208 return;
212 Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
214 int h;
215 Cell *p;
217 if (n == NULL)
218 n = "";
220 if ((p = lookup(n, tp)) != NULL) {
221 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
222 p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
223 return(p);
225 p = (Cell *) malloc(sizeof(Cell));
226 if (p == NULL)
227 FATAL("out of space for symbol table at %s", n);
228 p->nval = tostring(n);
229 p->sval = s ? tostring(s) : tostring("");
230 p->fval = f;
231 p->tval = t;
232 p->csub = CUNK;
233 p->ctype = OCELL;
234 tp->nelem++;
235 if (tp->nelem > FULLTAB * tp->size)
236 rehash(tp);
237 h = hash(n, tp->size);
238 p->cnext = tp->tab[h];
239 tp->tab[h] = p;
240 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
241 p, p->nval, p->sval, p->fval, p->tval) );
242 return(p);
245 int hash(const char *s, int n) /* form hash value for string s */
247 unsigned hashval;
249 for (hashval = 0; *s != '\0'; s++)
250 hashval = (*s + 31 * hashval);
251 return hashval % n;
254 void rehash(Array *tp) /* rehash items in small table into big one */
256 int i, nh, nsz;
257 Cell *cp, *op, **np;
259 nsz = GROWTAB * tp->size;
260 np = (Cell **) calloc(nsz, sizeof(Cell *));
261 if (np == NULL) /* can't do it, but can keep running. */
262 return; /* someone else will run out later. */
263 for (i = 0; i < tp->size; i++) {
264 for (cp = tp->tab[i]; cp; cp = op) {
265 op = cp->cnext;
266 nh = hash(cp->nval, nsz);
267 cp->cnext = np[nh];
268 np[nh] = cp;
271 free(tp->tab);
272 tp->tab = np;
273 tp->size = nsz;
276 Cell *lookup(const char *s, Array *tp) /* look for s in tp */
278 Cell *p;
279 int h;
281 h = hash(s, tp->size);
282 for (p = tp->tab[h]; p != NULL; p = p->cnext)
283 if (strcmp(s, p->nval) == 0)
284 return(p); /* found it */
285 return(NULL); /* not found */
288 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
290 int fldno;
292 f += 0.0; /* normalise negative zero to positive zero */
293 if ((vp->tval & (NUM | STR)) == 0)
294 funnyvar(vp, "assign to");
295 if (isfld(vp)) {
296 donerec = 0; /* mark $0 invalid */
297 fldno = atoi(vp->nval);
298 if (fldno > *NF)
299 newfld(fldno);
300 dprintf( ("setting field %d to %g\n", fldno, f) );
301 } else if (isrec(vp)) {
302 donefld = 0; /* mark $1... invalid */
303 donerec = 1;
305 if (freeable(vp))
306 xfree(vp->sval); /* free any previous string */
307 vp->tval &= ~STR; /* mark string invalid */
308 vp->tval |= NUM; /* mark number ok */
309 dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) );
310 return vp->fval = f;
313 void funnyvar(Cell *vp, const char *rw)
315 if (isarr(vp))
316 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
317 if (vp->tval & FCN)
318 FATAL("can't %s %s; it's a function.", rw, vp->nval);
319 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
320 vp, vp->nval, vp->sval, vp->fval, vp->tval);
323 char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
325 char *t;
326 int fldno;
328 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
329 vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
330 if ((vp->tval & (NUM | STR)) == 0)
331 funnyvar(vp, "assign to");
332 if (isfld(vp)) {
333 donerec = 0; /* mark $0 invalid */
334 fldno = atoi(vp->nval);
335 if (fldno > *NF)
336 newfld(fldno);
337 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
338 } else if (isrec(vp)) {
339 donefld = 0; /* mark $1... invalid */
340 donerec = 1;
342 t = tostring(s); /* in case it's self-assign */
343 vp->tval &= ~NUM;
344 vp->tval |= STR;
345 if (freeable(vp))
346 xfree(vp->sval);
347 vp->tval &= ~DONTFREE;
348 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
349 vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
350 return(vp->sval = t);
353 Awkfloat getfval(Cell *vp) /* get float val of a Cell */
355 if ((vp->tval & (NUM | STR)) == 0)
356 funnyvar(vp, "read value of");
357 if (isfld(vp) && donefld == 0)
358 fldbld();
359 else if (isrec(vp) && donerec == 0)
360 recbld();
361 if (!isnum(vp)) { /* not a number */
362 vp->fval = atof(vp->sval); /* best guess */
363 if (is_number(vp->sval) && !(vp->tval&CON))
364 vp->tval |= NUM; /* make NUM only sparingly */
366 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) );
367 return(vp->fval);
370 static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
372 char s[100];
373 double dtemp;
375 if ((vp->tval & (NUM | STR)) == 0)
376 funnyvar(vp, "read value of");
377 if (isfld(vp) && donefld == 0)
378 fldbld();
379 else if (isrec(vp) && donerec == 0)
380 recbld();
381 if (isstr(vp) == 0) {
382 if (freeable(vp))
383 xfree(vp->sval);
384 if (modf(vp->fval, &dtemp) == 0) /* it's integral */
385 snprintf(s, sizeof(s), "%.30g", vp->fval);
386 else
387 snprintf(s, sizeof(s), *fmt, vp->fval);
388 vp->sval = tostring(s);
389 vp->tval &= ~DONTFREE;
390 vp->tval |= STR;
392 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
393 return(vp->sval);
396 char *getsval(Cell *vp) /* get string val of a Cell */
398 return get_str_val(vp, CONVFMT);
401 char *getpssval(Cell *vp) /* get string val of a Cell for print */
403 return get_str_val(vp, OFMT);
407 char *tostring(const char *s) /* make a copy of string s */
409 char *p;
411 p = strdup(s);
412 if (p == NULL)
413 FATAL("out of space in tostring on %s", s);
414 return(p);
417 char *tostringN(const char *s, size_t n) /* make a copy of string s */
419 char *p;
421 p = malloc(n);
422 if (p == NULL)
423 FATAL("out of space in tostring on %s", s);
424 strcpy(p, s);
425 return(p);
428 char *qstring(const char *is, int delim) /* collect string up to next delim */
430 const char *os = is;
431 int c, n;
432 uschar *s = (uschar *) is;
433 uschar *buf, *bp;
435 if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
436 FATAL( "out of space in qstring(%s)", s);
437 for (bp = buf; (c = *s) != delim; s++) {
438 if (c == '\n')
439 SYNTAX( "newline in string %.20s...", os );
440 else if (c != '\\')
441 *bp++ = c;
442 else { /* \something */
443 c = *++s;
444 if (c == 0) { /* \ at end */
445 *bp++ = '\\';
446 break; /* for loop */
448 switch (c) {
449 case '\\': *bp++ = '\\'; break;
450 case 'n': *bp++ = '\n'; break;
451 case 't': *bp++ = '\t'; break;
452 case 'b': *bp++ = '\b'; break;
453 case 'f': *bp++ = '\f'; break;
454 case 'r': *bp++ = '\r'; break;
455 default:
456 if (!isdigit(c)) {
457 *bp++ = c;
458 break;
460 n = c - '0';
461 if (isdigit(s[1])) {
462 n = 8 * n + *++s - '0';
463 if (isdigit(s[1]))
464 n = 8 * n + *++s - '0';
466 *bp++ = n;
467 break;
471 *bp++ = 0;
472 return (char *) buf;