4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 #pragma ident "%Z%%M% %I% %E% SMI"
40 #define FULLTAB 2 /* rehash when table gets this x full */
41 #define GROWTAB 4 /* grow table by this factor */
43 Array
*symtab
; /* main symbol table */
45 uchar
**FS
; /* initial field sep */
46 uchar
**RS
; /* initial record sep */
47 uchar
**OFS
; /* output field sep */
48 uchar
**ORS
; /* output record sep */
49 uchar
**OFMT
; /* output format for numbers */
50 Awkfloat
*NF
; /* number of fields in current record */
51 Awkfloat
*NR
; /* number of current record */
52 Awkfloat
*FNR
; /* number of current record in current file */
53 uchar
**FILENAME
; /* current filename argument */
54 Awkfloat
*ARGC
; /* number of arguments from command line */
55 uchar
**SUBSEP
; /* subscript separator for a[i,j,k]; default \034 */
56 Awkfloat
*RSTART
; /* start of re matched with ~; origin 1 (!) */
57 Awkfloat
*RLENGTH
; /* length of same */
59 Cell
*recloc
; /* location of record */
62 Cell
*fnrloc
; /* FNR */
63 Array
*ARGVtab
; /* symbol table containing ARGV[...] */
64 Array
*ENVtab
; /* symbol table containing ENVIRON[...] */
65 Cell
*rstartloc
; /* RSTART */
66 Cell
*rlengthloc
; /* RLENGTH */
67 Cell
*symtabloc
; /* SYMTAB */
70 Node
*nullnode
; /* zero&null, converted into a node for comparisons */
72 static void rehash(Array
*);
77 init_buf(&record
, &record_size
, LINE_INCR
);
81 recloc
->nval
= (uchar
*)"$0";
82 recloc
->sval
= record
;
83 recloc
->tval
= REC
|STR
|DONTFREE
;
85 symtab
= makesymtab(NSYMTAB
);
86 (void) setsymtab((uchar
*)"0", (uchar
*)"0", 0.0,
87 NUM
|STR
|CON
|DONTFREE
, symtab
);
88 /* this is used for if(x)... tests: */
89 nullloc
= setsymtab((uchar
*)"$zero&null", (uchar
*)"", 0.0,
90 NUM
|STR
|CON
|DONTFREE
, symtab
);
91 nullnode
= valtonode(nullloc
, CCON
);
92 FS
= &setsymtab((uchar
*)"FS", (uchar
*)" ", 0.0,
93 STR
|DONTFREE
, symtab
)->sval
;
94 RS
= &setsymtab((uchar
*)"RS", (uchar
*)"\n", 0.0,
95 STR
|DONTFREE
, symtab
)->sval
;
96 OFS
= &setsymtab((uchar
*)"OFS", (uchar
*)" ", 0.0,
97 STR
|DONTFREE
, symtab
)->sval
;
98 ORS
= &setsymtab((uchar
*)"ORS", (uchar
*)"\n", 0.0,
99 STR
|DONTFREE
, symtab
)->sval
;
100 OFMT
= &setsymtab((uchar
*)"OFMT", (uchar
*)"%.6g", 0.0,
101 STR
|DONTFREE
, symtab
)->sval
;
102 FILENAME
= &setsymtab((uchar
*)"FILENAME", (uchar
*)"-", 0.0,
103 STR
|DONTFREE
, symtab
)->sval
;
104 nfloc
= setsymtab((uchar
*)"NF", (uchar
*)"", 0.0, NUM
, symtab
);
106 nrloc
= setsymtab((uchar
*)"NR", (uchar
*)"", 0.0, NUM
, symtab
);
108 fnrloc
= setsymtab((uchar
*)"FNR", (uchar
*)"", 0.0, NUM
, symtab
);
110 SUBSEP
= &setsymtab((uchar
*)"SUBSEP", (uchar
*)"\034", 0.0,
111 STR
|DONTFREE
, symtab
)->sval
;
112 rstartloc
= setsymtab((uchar
*)"RSTART", (uchar
*)"", 0.0,
114 RSTART
= &rstartloc
->fval
;
115 rlengthloc
= setsymtab((uchar
*)"RLENGTH", (uchar
*)"", 0.0,
117 RLENGTH
= &rlengthloc
->fval
;
118 symtabloc
= setsymtab((uchar
*)"SYMTAB", (uchar
*)"", 0.0, ARR
, symtab
);
119 symtabloc
->sval
= (uchar
*)symtab
;
123 arginit(int ac
, uchar
*av
[])
129 /* first make FILENAME first real argument */
130 for (i
= 1; i
< ac
; i
++) {
131 if (!isclvar(av
[i
])) {
132 (void) setsval(lookup((uchar
*)"FILENAME", symtab
),
137 ARGC
= &setsymtab((uchar
*)"ARGC", (uchar
*)"", (Awkfloat
)ac
,
139 cp
= setsymtab((uchar
*)"ARGV", (uchar
*)"", 0.0, ARR
, symtab
);
140 ARGVtab
= makesymtab(NSYMTAB
); /* could be (int) ARGC as well */
141 cp
->sval
= (uchar
*) ARGVtab
;
142 for (i
= 0; i
< ac
; i
++) {
143 (void) sprintf((char *)temp
, "%d", i
);
144 if (is_number(*av
)) {
145 (void) setsymtab(temp
, *av
, atof((const char *)*av
),
148 (void) setsymtab(temp
, *av
, 0.0, STR
, ARGVtab
);
155 envinit(uchar
*envp
[])
160 cp
= setsymtab((uchar
*)"ENVIRON", (uchar
*)"", 0.0, ARR
, symtab
);
161 ENVtab
= makesymtab(NSYMTAB
);
162 cp
->sval
= (uchar
*) ENVtab
;
163 for (; *envp
; envp
++) {
164 if ((p
= (uchar
*)strchr((char *)*envp
, '=')) == NULL
)
166 *p
++ = 0; /* split into two strings at = */
168 (void) setsymtab(*envp
, p
, atof((const char *)p
),
171 (void) setsymtab(*envp
, p
, 0.0, STR
, ENVtab
);
173 /* restore in case env is passed down to a shell */
184 ap
= (Array
*)malloc(sizeof (Array
));
185 tp
= (Cell
**)calloc(n
, sizeof (Cell
*));
186 if (ap
== NULL
|| tp
== NULL
)
187 ERROR
"out of space in makesymtab" FATAL
;
195 freesymtab(Cell
*ap
) /* free symbol table */
204 tp
= (Array
*)ap
->sval
;
207 for (i
= 0; i
< tp
->size
; i
++) {
208 for (cp
= tp
->tab
[i
]; cp
!= NULL
; cp
= next
) {
221 freeelem(Cell
*ap
, uchar
*s
) /* free elem s from ap (i.e., ap["s"] */
224 Cell
*p
, *prev
= NULL
;
228 tp
= (Array
*)ap
->sval
;
229 h
= hash(s
, tp
->size
);
230 for (p
= tp
->tab
[h
]; p
!= NULL
; prev
= p
, p
= p
->cnext
)
231 if (strcmp((char *)s
, (char *)p
->nval
) == 0) {
232 if (prev
== NULL
) /* 1st one */
233 tp
->tab
[h
] = p
->cnext
;
234 else /* middle somewhere */
235 prev
->cnext
= p
->cnext
;
246 setsymtab(uchar
*n
, uchar
*s
, Awkfloat f
, unsigned int t
, Array
*tp
)
251 if (n
!= NULL
&& (p
= lookup(n
, tp
)) != NULL
) {
252 dprintf(("setsymtab found %p: n=%s", (void *)p
, p
->nval
));
253 dprintf((" s=\"%s\" f=%g t=%p\n",
254 p
->sval
, p
->fval
, (void *)p
->tval
));
257 p
= (Cell
*)malloc(sizeof (Cell
));
259 ERROR
"symbol table overflow at %s", n FATAL
;
260 p
->nval
= tostring(n
);
261 p
->sval
= s
? tostring(s
) : tostring((uchar
*)"");
267 if (tp
->nelem
> FULLTAB
* tp
->size
)
269 h
= hash(n
, tp
->size
);
270 p
->cnext
= tp
->tab
[h
];
272 dprintf(("setsymtab set %p: n=%s", (void *)p
, p
->nval
));
273 dprintf((" s=\"%s\" f=%g t=%p\n", p
->sval
, p
->fval
, (void *)p
->tval
));
278 hash(uchar
*s
, int n
) /* form hash value for string s */
280 register unsigned hashval
;
282 for (hashval
= 0; *s
!= '\0'; s
++)
283 hashval
= (*s
+ 31 * hashval
);
284 return (hashval
% n
);
288 rehash(Array
*tp
) /* rehash items in small table into big one */
293 nsz
= GROWTAB
* tp
->size
;
294 np
= (Cell
**)calloc(nsz
, sizeof (Cell
*));
296 ERROR
"out of space in rehash" FATAL
;
297 for (i
= 0; i
< tp
->size
; i
++) {
298 for (cp
= tp
->tab
[i
]; cp
; cp
= op
) {
300 nh
= hash(cp
->nval
, nsz
);
311 lookup(uchar
*s
, Array
*tp
) /* look for s in tp */
316 h
= hash(s
, tp
->size
);
317 for (p
= tp
->tab
[h
]; p
!= NULL
; p
= p
->cnext
) {
318 if (strcmp((char *)s
, (char *)p
->nval
) == 0)
319 return (p
); /* found it */
321 return (NULL
); /* not found */
325 setfval(Cell
*vp
, Awkfloat f
)
329 if ((vp
->tval
& (NUM
| STR
)) == 0)
330 funnyvar(vp
, "assign to");
331 if (vp
->tval
& FLD
) {
332 donerec
= 0; /* mark $0 invalid */
336 dprintf(("setting field %d to %g\n", i
, f
));
337 } else if (vp
->tval
& REC
) {
338 donefld
= 0; /* mark $1... invalid */
341 vp
->tval
&= ~STR
; /* mark string invalid */
342 vp
->tval
|= NUM
; /* mark number ok */
343 dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp
,
344 vp
->nval
? vp
->nval
: (unsigned char *)"NULL",
345 f
, (void *)vp
->tval
));
346 return (vp
->fval
= f
);
350 funnyvar(Cell
*vp
, char *rw
)
353 ERROR
"can't %s %s; it's an array name.", rw
, vp
->nval FATAL
;
355 ERROR
"can't %s %s; it's a function.", rw
, vp
->nval FATAL
;
356 ERROR
"funny variable %o: n=%s s=\"%s\" f=%g t=%o",
357 vp
, vp
->nval
, vp
->sval
, vp
->fval
, vp
->tval CONT
;
361 setsval(Cell
*vp
, uchar
*s
)
365 if ((vp
->tval
& (NUM
| STR
)) == 0)
366 funnyvar(vp
, "assign to");
367 if (vp
->tval
& FLD
) {
368 donerec
= 0; /* mark $0 invalid */
372 dprintf(("setting field %d to %s\n", i
, s
));
373 } else if (vp
->tval
& REC
) {
374 donefld
= 0; /* mark $1... invalid */
381 vp
->tval
&= ~DONTFREE
;
382 dprintf(("setsval %p: %s = \"%s\", t=%p\n",
384 vp
->nval
? (char *)vp
->nval
: "",
386 (void *)(vp
->tval
? (char *)vp
->tval
: "")));
387 return (vp
->sval
= tostring(s
));
393 if ((vp
->tval
& (NUM
| STR
)) == 0)
394 funnyvar(vp
, "read value of");
395 if ((vp
->tval
& FLD
) && donefld
== 0)
397 else if ((vp
->tval
& REC
) && donerec
== 0)
399 if (!isnum(vp
)) { /* not a number */
400 vp
->fval
= atof((const char *)vp
->sval
); /* best guess */
401 if (is_number(vp
->sval
) && !(vp
->tval
&CON
))
402 vp
->tval
|= NUM
; /* make NUM only sparingly */
404 dprintf(("getfval %p: %s = %g, t=%p\n",
405 (void *)vp
, vp
->nval
, vp
->fval
, (void *)vp
->tval
));
414 if ((vp
->tval
& (NUM
| STR
)) == 0)
415 funnyvar(vp
, "read value of");
416 if ((vp
->tval
& FLD
) && donefld
== 0)
418 else if ((vp
->tval
& REC
) && donerec
== 0)
420 if ((vp
->tval
& STR
) == 0) {
421 if (!(vp
->tval
&DONTFREE
))
423 if ((long long)vp
->fval
== vp
->fval
) {
424 (void) snprintf((char *)s
, sizeof (s
),
428 (void) snprintf((char *)s
, sizeof (s
),
429 (char *)*OFMT
, vp
->fval
);
431 vp
->sval
= tostring(s
);
432 vp
->tval
&= ~DONTFREE
;
435 dprintf(("getsval %p: %s = \"%s\", t=%p\n",
437 vp
->nval
? (char *)vp
->nval
: "",
438 vp
->sval
? (char *)vp
->sval
: "",
448 p
= (uchar
*)malloc(strlen((char *)s
)+1);
450 ERROR
"out of space in tostring on %s", s FATAL
;
451 (void) strcpy((char *)p
, (char *)s
);
456 qstring(uchar
*s
, int delim
) /* collect string up to delim */
462 init_buf(&cbuf
, &cbufsz
, LINE_INCR
);
464 for (cnt
= 0; (c
= *s
) != delim
; s
++) {
466 ERROR
"newline in string %.10s...", cbuf SYNTAX
;
467 } else if (c
!= '\\') {
468 expand_buf(&cbuf
, &cbufsz
, cnt
);
470 } else { /* \something */
471 expand_buf(&cbuf
, &cbufsz
, cnt
);
473 case '\\': cbuf
[cnt
++] = '\\'; break;
474 case 'n': cbuf
[cnt
++] = '\n'; break;
475 case 't': cbuf
[cnt
++] = '\t'; break;
476 case 'b': cbuf
[cnt
++] = '\b'; break;
477 case 'f': cbuf
[cnt
++] = '\f'; break;
478 case 'r': cbuf
[cnt
++] = '\r'; break;
486 n
= 8 * n
+ *++s
- '0';
488 n
= 8 * n
+ *++s
- '0';
496 ret
= tostring(cbuf
);