1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
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
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
23 ****************************************************************/
34 #define FULLTAB 2 /* rehash when table gets this x full */
35 #define GROWTAB 4 /* grow table by this factor */
37 Array
*symtab
; /* main symbol table */
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 */
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 */
64 Cell
*nullloc
; /* a guaranteed empty cell */
65 Node
*nullnode
; /* zero&null, converted into a node for comparisons */
70 void syminit(void) /* initialize symbol table with builtin vars */
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
);
77 fsloc
= setsymtab("FS", " ", 0.0, STR
|DONTFREE
, symtab
);
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
);
87 nrloc
= setsymtab("NR", "", 0.0, NUM
, symtab
);
89 fnrloc
= setsymtab("FNR", "", 0.0, NUM
, symtab
);
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
;
100 void arginit(int ac
, char **av
) /* set up ARGV and ARGC */
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
);
113 setsymtab(temp
, *av
, atof(*av
), STR
|NUM
, ARGVtab
);
115 setsymtab(temp
, *av
, 0.0, STR
, ARGVtab
);
120 void envinit(char **envp
) /* set up ENVIRON variable */
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
)
131 if( p
== *envp
) /* no left hand side name in env string */
133 *p
++ = 0; /* split into two strings at = */
135 setsymtab(*envp
, p
, atof(p
), STR
|NUM
, ENVtab
);
137 setsymtab(*envp
, p
, 0.0, STR
, ENVtab
);
138 p
[-1] = '='; /* restore in case env is passed down to a shell */
142 Array
*makesymtab(int n
) /* make a new symbol table */
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");
157 void freesymtab(Cell
*ap
) /* free a symbol table */
165 tp
= (Array
*) ap
->sval
;
168 for (i
= 0; i
< tp
->size
; i
++) {
169 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= temp
) {
173 temp
= cp
->cnext
; /* avoids freeing then using */
180 WARNING("can't happen: inconsistent element count freeing %s", ap
->nval
);
185 void freeelem(Cell
*ap
, const char *s
) /* free elem s from ap (i.e., ap["s"] */
188 Cell
*p
, *prev
= NULL
;
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
;
208 Cell
*setsymtab(const char *n
, const char *s
, Awkfloat f
, unsigned t
, Array
*tp
)
213 if (n
!= NULL
&& (p
= lookup(n
, tp
)) != NULL
) {
214 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
215 (void*)p
, NN(p
->nval
), NN(p
->sval
), p
->fval
, p
->tval
) );
218 p
= (Cell
*) malloc(sizeof(Cell
));
220 FATAL("out of space for symbol table at %s", n
);
221 p
->nval
= tostring(n
);
222 p
->sval
= s
? tostring(s
) : tostring("");
228 if (tp
->nelem
> FULLTAB
* tp
->size
)
230 h
= hash(n
, tp
->size
);
231 p
->cnext
= tp
->tab
[h
];
233 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
234 (void*)p
, p
->nval
, p
->sval
, p
->fval
, p
->tval
) );
238 int hash(const char *s
, int n
) /* form hash value for string s */
242 for (hashval
= 0; *s
!= '\0'; s
++)
243 hashval
= (*s
+ 31 * hashval
);
247 void rehash(Array
*tp
) /* rehash items in small table into big one */
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
) {
259 nh
= hash(cp
->nval
, nsz
);
269 Cell
*lookup(const char *s
, Array
*tp
) /* look for s in tp */
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 */
281 Awkfloat
setfval(Cell
*vp
, Awkfloat f
) /* set float val of a Cell */
285 if ((vp
->tval
& (NUM
| STR
)) == 0)
286 funnyvar(vp
, "assign to");
288 donerec
= 0; /* mark $0 invalid */
289 fldno
= atoi(vp
->nval
);
292 dprintf( ("setting field %d to %g\n", fldno
, f
) );
293 } else if (isrec(vp
)) {
294 donefld
= 0; /* mark $1... invalid */
298 xfree(vp
->sval
); /* free any previous string */
299 vp
->tval
&= ~STR
; /* mark string invalid */
300 vp
->tval
|= NUM
; /* mark number ok */
301 if (f
== -0) /* who would have thought this possible? */
303 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp
, NN(vp
->nval
), f
, vp
->tval
) );
307 void funnyvar(Cell
*vp
, const char *rw
)
310 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
312 FATAL("can't %s %s; it's a function.", rw
, vp
->nval
);
313 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
314 vp
, vp
->nval
, vp
->sval
, vp
->fval
, vp
->tval
);
317 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
322 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
323 (void*)vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
324 if ((vp
->tval
& (NUM
| STR
)) == 0)
325 funnyvar(vp
, "assign to");
327 donerec
= 0; /* mark $0 invalid */
328 fldno
= atoi(vp
->nval
);
331 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
332 } else if (isrec(vp
)) {
333 donefld
= 0; /* mark $1... invalid */
336 t
= tostring(s
); /* in case it's self-assign */
341 vp
->tval
&= ~DONTFREE
;
342 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
343 (void*)vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
344 return(vp
->sval
= t
);
347 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
349 if ((vp
->tval
& (NUM
| STR
)) == 0)
350 funnyvar(vp
, "read value of");
351 if (isfld(vp
) && donefld
== 0)
353 else if (isrec(vp
) && donerec
== 0)
355 if (!isnum(vp
)) { /* not a number */
356 vp
->fval
= atof(vp
->sval
); /* best guess */
357 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
358 vp
->tval
|= NUM
; /* make NUM only sparingly */
360 dprintf( ("getfval %p: %s = %g, t=%o\n",
361 (void*)vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
365 static char *get_str_val(Cell
*vp
, char **fmt
) /* get string val of a Cell */
367 char s
[100]; /* BUG: unchecked */
370 if ((vp
->tval
& (NUM
| STR
)) == 0)
371 funnyvar(vp
, "read value of");
372 if (isfld(vp
) && donefld
== 0)
374 else if (isrec(vp
) && donerec
== 0)
376 if (isstr(vp
) == 0) {
379 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
380 sprintf(s
, "%.30g", vp
->fval
);
382 sprintf(s
, *fmt
, vp
->fval
);
383 vp
->sval
= tostring(s
);
384 vp
->tval
&= ~DONTFREE
;
387 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
388 (void*)vp
, NN(vp
->nval
), vp
->sval
, vp
->sval
, vp
->tval
) );
392 char *getsval(Cell
*vp
) /* get string val of a Cell */
394 return get_str_val(vp
, CONVFMT
);
397 char *getpssval(Cell
*vp
) /* get string val of a Cell for print */
399 return get_str_val(vp
, OFMT
);
403 char *tostring(const char *s
) /* make a copy of string s */
407 p
= (char *) malloc(strlen(s
)+1);
409 FATAL("out of space in tostring on %s", s
);
414 char *qstring(const char *is
, int delim
) /* collect string up to next delim */
418 uschar
*s
= (uschar
*) is
;
421 if ((buf
= (uschar
*) malloc(strlen(is
)+3)) == NULL
)
422 FATAL( "out of space in qstring(%s)", s
);
423 for (bp
= buf
; (c
= *s
) != delim
; s
++) {
425 SYNTAX( "newline in string %.20s...", os
);
428 else { /* \something */
430 if (c
== 0) { /* \ at end */
432 break; /* for loop */
435 case '\\': *bp
++ = '\\'; break;
436 case 'n': *bp
++ = '\n'; break;
437 case 't': *bp
++ = '\t'; break;
438 case 'b': *bp
++ = '\b'; break;
439 case 'f': *bp
++ = '\f'; break;
440 case 'r': *bp
++ = '\r'; break;
448 n
= 8 * n
+ *++s
- '0';
450 n
= 8 * n
+ *++s
- '0';