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(const 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(const Cell
*ap
, const char *s
)
186 /* free elem s from ap (i.e., ap["s"] */
189 Cell
*p
, *prev
= NULL
;
192 tp
= (Array
*) ap
->sval
;
193 h
= hash(s
, tp
->size
);
194 for (p
= tp
->tab
[h
]; p
!= NULL
; prev
= p
, p
= p
->cnext
)
195 if (strcmp(s
, p
->nval
) == 0) {
196 if (prev
== NULL
) /* 1st one */
197 tp
->tab
[h
] = p
->cnext
;
198 else /* middle somewhere */
199 prev
->cnext
= p
->cnext
;
209 Cell
*setsymtab(const char *n
, const char *s
, Awkfloat f
, unsigned t
, Array
*tp
)
214 if (n
!= NULL
&& (p
= lookup(n
, tp
)) != NULL
) {
215 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
216 p
, NN(p
->nval
), NN(p
->sval
), p
->fval
, p
->tval
) );
219 p
= (Cell
*) malloc(sizeof(Cell
));
221 FATAL("out of space for symbol table at %s", n
);
222 p
->nval
= tostring(n
);
223 p
->sval
= s
? tostring(s
) : tostring("");
229 if (tp
->nelem
> FULLTAB
* tp
->size
)
231 h
= hash(n
, tp
->size
);
232 p
->cnext
= tp
->tab
[h
];
234 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
235 p
, p
->nval
, p
->sval
, p
->fval
, p
->tval
) );
239 int hash(const char *s
, int n
) /* form hash value for string s */
243 for (hashval
= 0; *s
!= '\0'; s
++)
244 hashval
= (*s
+ 31 * hashval
);
248 void rehash(Array
*tp
) /* rehash items in small table into big one */
253 nsz
= GROWTAB
* tp
->size
;
254 np
= (Cell
**) calloc(nsz
, sizeof(Cell
*));
255 if (np
== NULL
) /* can't do it, but can keep running. */
256 return; /* someone else will run out later. */
257 for (i
= 0; i
< tp
->size
; i
++) {
258 for (cp
= tp
->tab
[i
]; cp
; cp
= op
) {
260 nh
= hash(cp
->nval
, nsz
);
270 Cell
*lookup(const char *s
, const Array
*tp
) /* look for s in tp */
275 h
= hash(s
, tp
->size
);
276 for (p
= tp
->tab
[h
]; p
!= NULL
; p
= p
->cnext
)
277 if (strcmp(s
, p
->nval
) == 0)
278 return(p
); /* found it */
279 return(NULL
); /* not found */
282 Awkfloat
setfval(Cell
*vp
, Awkfloat f
) /* set float val of a Cell */
286 if ((vp
->tval
& (NUM
| STR
)) == 0)
287 funnyvar(vp
, "assign to");
289 donerec
= 0; /* mark $0 invalid */
290 fldno
= atoi(vp
->nval
);
293 dprintf( ("setting field %d to %g\n", fldno
, f
) );
294 } else if (isrec(vp
)) {
295 donefld
= 0; /* mark $1... invalid */
299 xfree(vp
->sval
); /* free any previous string */
300 vp
->tval
&= ~STR
; /* mark string invalid */
301 vp
->tval
|= NUM
; /* mark number ok */
302 dprintf( ("setfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), f
, vp
->tval
) );
306 void funnyvar(Cell
*vp
, const char *rw
)
309 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
311 FATAL("can't %s %s; it's a function.", rw
, vp
->nval
);
312 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
313 vp
, vp
->nval
, vp
->sval
, vp
->fval
, vp
->tval
);
316 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
321 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
322 vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
323 if ((vp
->tval
& (NUM
| STR
)) == 0)
324 funnyvar(vp
, "assign to");
326 donerec
= 0; /* mark $0 invalid */
327 fldno
= atoi(vp
->nval
);
330 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
331 } else if (isrec(vp
)) {
332 donefld
= 0; /* mark $1... invalid */
335 t
= tostring(s
); /* in case it's self-assign */
340 vp
->tval
&= ~DONTFREE
;
341 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
342 vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
343 return(vp
->sval
= t
);
346 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
348 if ((vp
->tval
& (NUM
| STR
)) == 0)
349 funnyvar(vp
, "read value of");
350 if (isfld(vp
) && donefld
== 0)
352 else if (isrec(vp
) && donerec
== 0)
354 if (!isnum(vp
)) { /* not a number */
355 vp
->fval
= atof(vp
->sval
); /* best guess */
356 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
357 vp
->tval
|= NUM
; /* make NUM only sparingly */
359 dprintf( ("getfval %p: %s = %g, t=%o\n", vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
363 static char *get_str_val(Cell
*vp
, char **fmt
)
364 /* get string val of a Cell */
366 char s
[100]; /* BUG: unchecked */
369 if ((vp
->tval
& (NUM
| STR
)) == 0)
370 funnyvar(vp
, "read value of");
371 if (isfld(vp
) && donefld
== 0)
373 else if (isrec(vp
) && donerec
== 0)
375 if (isstr(vp
) == 0) {
378 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
379 sprintf(s
, "%.30g", vp
->fval
);
381 sprintf(s
, *fmt
, vp
->fval
);
382 vp
->sval
= tostring(s
);
383 vp
->tval
&= ~DONTFREE
;
386 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp
, NN(vp
->nval
), vp
->sval
, vp
->sval
, vp
->tval
) );
390 char *getsval(Cell
*vp
) /* get string val of a Cell */
392 return get_str_val(vp
, CONVFMT
);
395 char *getpssval(Cell
*vp
) /* get string val of a Cell for print */
397 return get_str_val(vp
, OFMT
);
401 char *tostring(const char *s
) /* make a copy of string s */
405 p
= (char *) malloc(strlen(s
)+1);
407 FATAL("out of space in tostring on %s", s
);
412 char *qstring(const char *is
, int delim
) /* collect string up to next delim */
416 uschar
*s
= (uschar
*) is
;
419 if ((buf
= (uschar
*) malloc(strlen(is
)+3)) == NULL
)
420 FATAL( "out of space in qstring(%s)", s
);
421 for (bp
= buf
; (c
= *s
) != delim
; s
++) {
423 SYNTAX( "newline in string %.20s...", os
);
426 else { /* \something */
428 if (c
== 0) { /* \ at end */
430 break; /* for loop */
433 case '\\': *bp
++ = '\\'; break;
434 case 'n': *bp
++ = '\n'; break;
435 case 't': *bp
++ = '\t'; break;
436 case 'b': *bp
++ = '\b'; break;
437 case 'f': *bp
++ = '\f'; break;
438 case 'r': *bp
++ = '\r'; break;
446 n
= 8 * n
+ *++s
- '0';
448 n
= 8 * n
+ *++s
- '0';