1 /**************************************************************** 2 Copyright (C) Lucent Technologies 1997 3 All Rights Reserved 4 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. 14 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 ****************************************************************/ 24 25 #define DEBUG 26 #include <stdio.h> 27 #include <math.h> 28 #include <ctype.h> 29 #include <string.h> 30 #include <stdlib.h> 31 #include "awk.h" 32 #include "ytab.h" 33 34 #define FULLTAB 2 /* rehash when table gets this x full */ 35 #define GROWTAB 4 /* grow table by this factor */ 36 37 Array *symtab; /* main symbol table */ 38 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 */ 53 54 Cell *nrloc; /* NR */ 55 Cell *nfloc; /* NF */ 56 Cell *fnrloc; /* FNR */ 57 Array *ARGVtab; /* symbol table containing ARGV[...] */ 58 Array *ENVtab; /* symbol table containing ENVIRON[...] */ 59 Cell *rstartloc; /* RSTART */ 60 Cell *rlengthloc; /* RLENGTH */ 61 Cell *symtabloc; /* SYMTAB */ 62 63 Cell *nullloc; /* a guaranteed empty cell */ 64 Node *nullnode; /* zero&null, converted into a node for comparisons */ 65 Cell *literal0; 66 67 extern Cell **fldtab; 68 69 void syminit(void) /* initialize symbol table with builtin vars */ 70 { 71 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 72 /* this is used for if(x)... tests: */ 73 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 74 nullnode = celltonode(nullloc, CCON); 75 76 FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; 77 RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 78 OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 79 ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 80 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 81 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 82 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 83 nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 84 NF = &nfloc->fval; 85 nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 86 NR = &nrloc->fval; 87 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 88 FNR = &fnrloc->fval; 89 SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 90 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 91 RSTART = &rstartloc->fval; 92 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 93 RLENGTH = &rlengthloc->fval; 94 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 95 symtabloc->sval = (char *) symtab; 96 } 97 98 void arginit(int ac, char **av) /* set up ARGV and ARGC */ 99 { 100 Cell *cp; 101 int i; 102 char temp[50]; 103 104 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 105 cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 106 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 107 cp->sval = (char *) ARGVtab; 108 for (i = 0; i < ac; i++) { 109 sprintf(temp, "%d", i); 110 if (is_number(*av)) 111 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 112 else 113 setsymtab(temp, *av, 0.0, STR, ARGVtab); 114 av++; 115 } 116 } 117 118 void envinit(char **envp) /* set up ENVIRON variable */ 119 { 120 Cell *cp; 121 char *p; 122 123 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 124 ENVtab = makesymtab(NSYMTAB); 125 cp->sval = (char *) ENVtab; 126 for ( ; *envp; envp++) { 127 if ((p = strchr(*envp, '=')) == NULL) 128 continue; 129 if( p == *envp ) /* no left hand side name in env string */ 130 continue; 131 *p++ = 0; /* split into two strings at = */ 132 if (is_number(p)) 133 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 134 else 135 setsymtab(*envp, p, 0.0, STR, ENVtab); 136 p[-1] = '='; /* restore in case env is passed down to a shell */ 137 } 138 } 139 140 Array *makesymtab(int n) /* make a new symbol table */ 141 { 142 Array *ap; 143 Cell **tp; 144 145 ap = (Array *) malloc(sizeof(Array)); 146 tp = (Cell **) calloc(n, sizeof(Cell *)); 147 if (ap == NULL || tp == NULL) 148 FATAL("out of space in makesymtab"); 149 ap->nelem = 0; 150 ap->size = n; 151 ap->tab = tp; 152 return(ap); 153 } 154 155 void freesymtab(Cell *ap) /* free a symbol table */ 156 { 157 Cell *cp, *temp; 158 Array *tp; 159 int i; 160 161 if (!isarr(ap)) 162 return; 163 tp = (Array *) ap->sval; 164 if (tp == NULL) 165 return; 166 for (i = 0; i < tp->size; i++) { 167 for (cp = tp->tab[i]; cp != NULL; cp = temp) { 168 xfree(cp->nval); 169 if (freeable(cp)) 170 xfree(cp->sval); 171 temp = cp->cnext; /* avoids freeing then using */ 172 free(cp); 173 tp->nelem--; 174 } 175 tp->tab[i] = 0; 176 } 177 if (tp->nelem != 0) 178 WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 179 free(tp->tab); 180 free(tp); 181 } 182 183 void freeelem(Cell *ap, char *s) /* free elem s from ap (i.e., ap["s"] */ 184 { 185 Array *tp; 186 Cell *p, *prev = NULL; 187 int h; 188 189 tp = (Array *) ap->sval; 190 h = hash(s, tp->size); 191 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 192 if (strcmp(s, p->nval) == 0) { 193 if (prev == NULL) /* 1st one */ 194 tp->tab[h] = p->cnext; 195 else /* middle somewhere */ 196 prev->cnext = p->cnext; 197 if (freeable(p)) 198 xfree(p->sval); 199 free(p->nval); 200 free(p); 201 tp->nelem--; 202 return; 203 } 204 } 205 206 Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp) 207 { 208 int h; 209 Cell *p; 210 211 if (n != NULL && (p = lookup(n, tp)) != NULL) { 212 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 213 p, p->nval, p->sval, p->fval, p->tval) ); 214 return(p); 215 } 216 p = (Cell *) malloc(sizeof(Cell)); 217 if (p == NULL) 218 FATAL("out of space for symbol table at %s", n); 219 p->nval = tostring(n); 220 p->sval = s ? tostring(s) : tostring(""); 221 p->fval = f; 222 p->tval = t; 223 p->csub = CUNK; 224 p->ctype = OCELL; 225 tp->nelem++; 226 if (tp->nelem > FULLTAB * tp->size) 227 rehash(tp); 228 h = hash(n, tp->size); 229 p->cnext = tp->tab[h]; 230 tp->tab[h] = p; 231 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 232 p, p->nval, p->sval, p->fval, p->tval) ); 233 return(p); 234 } 235 236 int hash(char *s, int n) /* form hash value for string s */ 237 { 238 unsigned hashval; 239 240 for (hashval = 0; *s != '\0'; s++) 241 hashval = (*s + 31 * hashval); 242 return hashval % n; 243 } 244 245 void rehash(Array *tp) /* rehash items in small table into big one */ 246 { 247 int i, nh, nsz; 248 Cell *cp, *op, **np; 249 250 nsz = GROWTAB * tp->size; 251 np = (Cell **) calloc(nsz, sizeof(Cell *)); 252 if (np == NULL) /* can't do it, but can keep running. */ 253 return; /* someone else will run out later. */ 254 for (i = 0; i < tp->size; i++) { 255 for (cp = tp->tab[i]; cp; cp = op) { 256 op = cp->cnext; 257 nh = hash(cp->nval, nsz); 258 cp->cnext = np[nh]; 259 np[nh] = cp; 260 } 261 } 262 free(tp->tab); 263 tp->tab = np; 264 tp->size = nsz; 265 } 266 267 Cell *lookup(char *s, Array *tp) /* look for s in tp */ 268 { 269 Cell *p; 270 int h; 271 272 h = hash(s, tp->size); 273 for (p = tp->tab[h]; p != NULL; p = p->cnext) 274 if (strcmp(s, p->nval) == 0) 275 return(p); /* found it */ 276 return(NULL); /* not found */ 277 } 278 279 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 280 { 281 int fldno; 282 283 if ((vp->tval & (NUM | STR)) == 0) 284 funnyvar(vp, "assign to"); 285 if (isfld(vp)) { 286 donerec = 0; /* mark $0 invalid */ 287 fldno = atoi(vp->nval); 288 if (fldno > *NF) 289 newfld(fldno); 290 dprintf( ("setting field %d to %g\n", fldno, f) ); 291 } else if (isrec(vp)) { 292 donefld = 0; /* mark $1... invalid */ 293 donerec = 1; 294 } 295 if (freeable(vp)) 296 xfree(vp->sval); /* free any previous string */ 297 vp->tval &= ~STR; /* mark string invalid */ 298 vp->tval |= NUM; /* mark number ok */ 299 dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); 300 return vp->fval = f; 301 } 302 303 void funnyvar(Cell *vp, char *rw) 304 { 305 if (isarr(vp)) 306 FATAL("can't %s %s; it's an array name.", rw, vp->nval); 307 if (vp->tval & FCN) 308 FATAL("can't %s %s; it's a function.", rw, vp->nval); 309 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 310 vp, vp->nval, vp->sval, vp->fval, vp->tval); 311 } 312 313 char *setsval(Cell *vp, char *s) /* set string val of a Cell */ 314 { 315 char *t; 316 int fldno; 317 318 dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) ); 319 if ((vp->tval & (NUM | STR)) == 0) 320 funnyvar(vp, "assign to"); 321 if (isfld(vp)) { 322 donerec = 0; /* mark $0 invalid */ 323 fldno = atoi(vp->nval); 324 if (fldno > *NF) 325 newfld(fldno); 326 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 327 } else if (isrec(vp)) { 328 donefld = 0; /* mark $1... invalid */ 329 donerec = 1; 330 } 331 t = tostring(s); /* in case it's self-assign */ 332 vp->tval &= ~NUM; 333 vp->tval |= STR; 334 if (freeable(vp)) 335 xfree(vp->sval); 336 vp->tval &= ~DONTFREE; 337 dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); 338 return(vp->sval = t); 339 } 340 341 Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 342 { 343 if ((vp->tval & (NUM | STR)) == 0) 344 funnyvar(vp, "read value of"); 345 if (isfld(vp) && donefld == 0) 346 fldbld(); 347 else if (isrec(vp) && donerec == 0) 348 recbld(); 349 if (!isnum(vp)) { /* not a number */ 350 vp->fval = atof(vp->sval); /* best guess */ 351 if (is_number(vp->sval) && !(vp->tval&CON)) 352 vp->tval |= NUM; /* make NUM only sparingly */ 353 } 354 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); 355 return(vp->fval); 356 } 357 358 char *getsval(Cell *vp) /* get string val of a Cell */ 359 { 360 char s[100]; /* BUG: unchecked */ 361 double dtemp; 362 363 if ((vp->tval & (NUM | STR)) == 0) 364 funnyvar(vp, "read value of"); 365 if (isfld(vp) && donefld == 0) 366 fldbld(); 367 else if (isrec(vp) && donerec == 0) 368 recbld(); 369 if (isstr(vp) == 0) { 370 if (freeable(vp)) 371 xfree(vp->sval); 372 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 373 sprintf(s, "%.30g", vp->fval); 374 else 375 sprintf(s, *CONVFMT, vp->fval); 376 vp->sval = tostring(s); 377 vp->tval &= ~DONTFREE; 378 vp->tval |= STR; 379 } 380 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); 381 return(vp->sval); 382 } 383 384 char *tostring(char *s) /* make a copy of string s */ 385 { 386 char *p; 387 388 p = (char *) malloc(strlen(s)+1); 389 if (p == NULL) 390 FATAL("out of space in tostring on %s", s); 391 strcpy(p, s); 392 return(p); 393 } 394 395 char *qstring(char *is, int delim) /* collect string up to next delim */ 396 { 397 char *os = is; 398 int c, n; 399 uschar *s = (uschar *) is; 400 uschar *buf, *bp; 401 402 if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 403 FATAL( "out of space in qstring(%s)", s); 404 for (bp = buf; (c = *s) != delim; s++) { 405 if (c == '\n') 406 SYNTAX( "newline in string %.20s...", os ); 407 else if (c != '\\') 408 *bp++ = c; 409 else { /* \something */ 410 c = *++s; 411 if (c == 0) { /* \ at end */ 412 *bp++ = '\\'; 413 break; /* for loop */ 414 } 415 switch (c) { 416 case '\\': *bp++ = '\\'; break; 417 case 'n': *bp++ = '\n'; break; 418 case 't': *bp++ = '\t'; break; 419 case 'b': *bp++ = '\b'; break; 420 case 'f': *bp++ = '\f'; break; 421 case 'r': *bp++ = '\r'; break; 422 default: 423 if (!isdigit(c)) { 424 *bp++ = c; 425 break; 426 } 427 n = c - '0'; 428 if (isdigit(s[1])) { 429 n = 8 * n + *++s - '0'; 430 if (isdigit(s[1])) 431 n = 8 * n + *++s - '0'; 432 } 433 *bp++ = n; 434 break; 435 } 436 } 437 } 438 *bp++ = 0; 439 return (char *) buf; 440 } 441