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 *fsloc; /* FS */ 55 Cell *nrloc; /* NR */ 56 Cell *nfloc; /* NF */ 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 */ 63 64 Cell *nullloc; /* a guaranteed empty cell */ 65 Node *nullnode; /* zero&null, converted into a node for comparisons */ 66 Cell *literal0; 67 68 extern Cell **fldtab; 69 70 void syminit(void) /* initialize symbol table with builtin vars */ 71 { 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); 76 77 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 78 FS = &fsloc->sval; 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); 86 NF = &nfloc->fval; 87 nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 88 NR = &nrloc->fval; 89 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 90 FNR = &fnrloc->fval; 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; 98 } 99 100 void arginit(int ac, char **av) /* set up ARGV and ARGC */ 101 { 102 Cell *cp; 103 int i; 104 char temp[50]; 105 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); 112 if (is_number(*av)) 113 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 114 else 115 setsymtab(temp, *av, 0.0, STR, ARGVtab); 116 av++; 117 } 118 } 119 120 void envinit(char **envp) /* set up ENVIRON variable */ 121 { 122 Cell *cp; 123 char *p; 124 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) 130 continue; 131 if( p == *envp ) /* no left hand side name in env string */ 132 continue; 133 *p++ = 0; /* split into two strings at = */ 134 if (is_number(p)) 135 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 136 else 137 setsymtab(*envp, p, 0.0, STR, ENVtab); 138 p[-1] = '='; /* restore in case env is passed down to a shell */ 139 } 140 } 141 142 Array *makesymtab(int n) /* make a new symbol table */ 143 { 144 Array *ap; 145 Cell **tp; 146 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"); 151 ap->nelem = 0; 152 ap->size = n; 153 ap->tab = tp; 154 return(ap); 155 } 156 157 void freesymtab(Cell *ap) /* free a symbol table */ 158 { 159 Cell *cp, *temp; 160 Array *tp; 161 int i; 162 163 if (!isarr(ap)) 164 return; 165 tp = (Array *) ap->sval; 166 if (tp == NULL) 167 return; 168 for (i = 0; i < tp->size; i++) { 169 for (cp = tp->tab[i]; cp != NULL; cp = temp) { 170 xfree(cp->nval); 171 if (freeable(cp)) 172 xfree(cp->sval); 173 temp = cp->cnext; /* avoids freeing then using */ 174 free(cp); 175 tp->nelem--; 176 } 177 tp->tab[i] = 0; 178 } 179 if (tp->nelem != 0) 180 WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 181 free(tp->tab); 182 free(tp); 183 } 184 185 void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 186 { 187 Array *tp; 188 Cell *p, *prev = NULL; 189 int h; 190 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; 199 if (freeable(p)) 200 xfree(p->sval); 201 free(p->nval); 202 free(p); 203 tp->nelem--; 204 return; 205 } 206 } 207 208 Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 209 { 210 int h; 211 Cell *p; 212 213 if (n != NULL && (p = lookup(n, tp)) != NULL) { 214 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 215 p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 216 return(p); 217 } 218 p = (Cell *) malloc(sizeof(Cell)); 219 if (p == NULL) 220 FATAL("out of space for symbol table at %s", n); 221 p->nval = tostring(n); 222 p->sval = s ? tostring(s) : tostring(""); 223 p->fval = f; 224 p->tval = t; 225 p->csub = CUNK; 226 p->ctype = OCELL; 227 tp->nelem++; 228 if (tp->nelem > FULLTAB * tp->size) 229 rehash(tp); 230 h = hash(n, tp->size); 231 p->cnext = tp->tab[h]; 232 tp->tab[h] = p; 233 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 234 p, p->nval, p->sval, p->fval, p->tval) ); 235 return(p); 236 } 237 238 int hash(const char *s, int n) /* form hash value for string s */ 239 { 240 unsigned hashval; 241 242 for (hashval = 0; *s != '\0'; s++) 243 hashval = (*s + 31 * hashval); 244 return hashval % n; 245 } 246 247 void rehash(Array *tp) /* rehash items in small table into big one */ 248 { 249 int i, nh, nsz; 250 Cell *cp, *op, **np; 251 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) { 258 op = cp->cnext; 259 nh = hash(cp->nval, nsz); 260 cp->cnext = np[nh]; 261 np[nh] = cp; 262 } 263 } 264 free(tp->tab); 265 tp->tab = np; 266 tp->size = nsz; 267 } 268 269 Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 270 { 271 Cell *p; 272 int h; 273 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 */ 279 } 280 281 Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 282 { 283 int fldno; 284 285 if ((vp->tval & (NUM | STR)) == 0) 286 funnyvar(vp, "assign to"); 287 if (isfld(vp)) { 288 donerec = 0; /* mark $0 invalid */ 289 fldno = atoi(vp->nval); 290 if (fldno > *NF) 291 newfld(fldno); 292 dprintf( ("setting field %d to %g\n", fldno, f) ); 293 } else if (isrec(vp)) { 294 donefld = 0; /* mark $1... invalid */ 295 donerec = 1; 296 } 297 if (freeable(vp)) 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", vp, NN(vp->nval), f, vp->tval) ); 302 return vp->fval = f; 303 } 304 305 void funnyvar(Cell *vp, const char *rw) 306 { 307 if (isarr(vp)) 308 FATAL("can't %s %s; it's an array name.", rw, vp->nval); 309 if (vp->tval & FCN) 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); 313 } 314 315 char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 316 { 317 char *t; 318 int fldno; 319 320 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 321 vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 322 if ((vp->tval & (NUM | STR)) == 0) 323 funnyvar(vp, "assign to"); 324 if (isfld(vp)) { 325 donerec = 0; /* mark $0 invalid */ 326 fldno = atoi(vp->nval); 327 if (fldno > *NF) 328 newfld(fldno); 329 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 330 } else if (isrec(vp)) { 331 donefld = 0; /* mark $1... invalid */ 332 donerec = 1; 333 } 334 t = tostring(s); /* in case it's self-assign */ 335 if (freeable(vp)) 336 xfree(vp->sval); 337 vp->tval &= ~NUM; 338 vp->tval |= STR; 339 vp->tval &= ~DONTFREE; 340 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 341 vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); 342 return(vp->sval = t); 343 } 344 345 Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 346 { 347 if ((vp->tval & (NUM | STR)) == 0) 348 funnyvar(vp, "read value of"); 349 if (isfld(vp) && donefld == 0) 350 fldbld(); 351 else if (isrec(vp) && donerec == 0) 352 recbld(); 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 */ 357 } 358 dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) ); 359 return(vp->fval); 360 } 361 362 static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 363 { 364 char s[100]; /* BUG: unchecked */ 365 double dtemp; 366 367 if ((vp->tval & (NUM | STR)) == 0) 368 funnyvar(vp, "read value of"); 369 if (isfld(vp) && donefld == 0) 370 fldbld(); 371 else if (isrec(vp) && donerec == 0) 372 recbld(); 373 if (isstr(vp) == 0) { 374 if (freeable(vp)) 375 xfree(vp->sval); 376 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 377 sprintf(s, "%.30g", vp->fval); 378 else 379 sprintf(s, *fmt, vp->fval); 380 vp->sval = tostring(s); 381 vp->tval &= ~DONTFREE; 382 vp->tval |= STR; 383 } 384 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 385 return(vp->sval); 386 } 387 388 char *getsval(Cell *vp) /* get string val of a Cell */ 389 { 390 return get_str_val(vp, CONVFMT); 391 } 392 393 char *getpssval(Cell *vp) /* get string val of a Cell for print */ 394 { 395 return get_str_val(vp, OFMT); 396 } 397 398 399 char *tostring(const char *s) /* make a copy of string s */ 400 { 401 char *p; 402 403 p = (char *) malloc(strlen(s)+1); 404 if (p == NULL) 405 FATAL("out of space in tostring on %s", s); 406 strcpy(p, s); 407 return(p); 408 } 409 410 char *qstring(const char *is, int delim) /* collect string up to next delim */ 411 { 412 const char *os = is; 413 int c, n; 414 uschar *s = (uschar *) is; 415 uschar *buf, *bp; 416 417 if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 418 FATAL( "out of space in qstring(%s)", s); 419 for (bp = buf; (c = *s) != delim; s++) { 420 if (c == '\n') 421 SYNTAX( "newline in string %.20s...", os ); 422 else if (c != '\\') 423 *bp++ = c; 424 else { /* \something */ 425 c = *++s; 426 if (c == 0) { /* \ at end */ 427 *bp++ = '\\'; 428 break; /* for loop */ 429 } 430 switch (c) { 431 case '\\': *bp++ = '\\'; break; 432 case 'n': *bp++ = '\n'; break; 433 case 't': *bp++ = '\t'; break; 434 case 'b': *bp++ = '\b'; break; 435 case 'f': *bp++ = '\f'; break; 436 case 'r': *bp++ = '\r'; break; 437 default: 438 if (!isdigit(c)) { 439 *bp++ = c; 440 break; 441 } 442 n = c - '0'; 443 if (isdigit(s[1])) { 444 n = 8 * n + *++s - '0'; 445 if (isdigit(s[1])) 446 n = 8 * n + *++s - '0'; 447 } 448 *bp++ = n; 449 break; 450 } 451 } 452 } 453 *bp++ = 0; 454 return (char *) buf; 455 } 456