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", DEFAULT_FS
, 0.0, STR
|DONTFREE
, symtab
);
79 RS
= &setsymtab("RS", "\n", 0.0, STR
|DONTFREE
, symtab
)->sval
;
80 OFS
= &setsymtab("OFS", DEFAULT_FS
, 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 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp
, NN(vp
->nval
), f
, vp
->tval
) );
305 void funnyvar(Cell
*vp
, const char *rw
)
308 FATAL("can't %s %s; it's an array name.", rw
, vp
->nval
);
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
);
315 char *setsval(Cell
*vp
, const char *s
) /* set string val of a Cell */
320 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
321 (void*)vp
, NN(vp
->nval
), s
, vp
->tval
, donerec
, donefld
) );
322 if ((vp
->tval
& (NUM
| STR
)) == 0)
323 funnyvar(vp
, "assign to");
325 donerec
= 0; /* mark $0 invalid */
326 fldno
= atoi(vp
->nval
);
329 dprintf( ("setting field %d to %s (%p)\n", fldno
, s
, s
) );
330 } else if (isrec(vp
)) {
331 donefld
= 0; /* mark $1... invalid */
334 t
= tostring(s
); /* in case it's self-assign */
339 vp
->tval
&= ~DONTFREE
;
340 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
341 (void*)vp
, NN(vp
->nval
), t
,t
, vp
->tval
, donerec
, donefld
) );
342 return(vp
->sval
= t
);
345 Awkfloat
getfval(Cell
*vp
) /* get float val of a Cell */
347 if ((vp
->tval
& (NUM
| STR
)) == 0)
348 funnyvar(vp
, "read value of");
349 if (isfld(vp
) && donefld
== 0)
351 else if (isrec(vp
) && donerec
== 0)
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 */
358 dprintf( ("getfval %p: %s = %g, t=%o\n",
359 (void*)vp
, NN(vp
->nval
), vp
->fval
, vp
->tval
) );
363 static char *get_str_val(Cell
*vp
, char **fmt
) /* get string val of a Cell */
365 char s
[100]; /* BUG: unchecked */
368 if ((vp
->tval
& (NUM
| STR
)) == 0)
369 funnyvar(vp
, "read value of");
370 if (isfld(vp
) && donefld
== 0)
372 else if (isrec(vp
) && donerec
== 0)
374 if (isstr(vp
) == 0) {
377 if (modf(vp
->fval
, &dtemp
) == 0) /* it's integral */
378 sprintf(s
, "%.30g", vp
->fval
);
380 sprintf(s
, *fmt
, vp
->fval
);
381 vp
->sval
= tostring(s
);
382 vp
->tval
&= ~DONTFREE
;
385 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
386 (void*)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';