1 /**************************************************************** 2 Copyright (C) AT&T and Lucent Technologies 1996 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 names of AT&T or Lucent Technologies 11 or any of their entities not be used in advertising or publicity 12 pertaining to distribution of the software without specific, 13 written prior permission. 14 15 AT&T AND LUCENT DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 16 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 17 FITNESS. IN NO EVENT SHALL AT&T OR LUCENT OR ANY OF THEIR 18 ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 19 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 21 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 22 USE OR PERFORMANCE OF THIS SOFTWARE. 23 ****************************************************************/ 24 25 #define DEBUG 26 #include <stdio.h> 27 #include <string.h> 28 #include <ctype.h> 29 #include <errno.h> 30 #include <stdlib.h> 31 #include "awk.h" 32 #include "awkgram.h" 33 34 FILE *infile = NULL; 35 char *file = ""; 36 int recsize = RECSIZE; 37 char *recdata; 38 char *record; 39 char *fields; 40 Cell *fldtab; 41 42 #define MAXFLD 200 43 int nfields = MAXFLD; /* can be set from commandline in main */ 44 45 int donefld; /* 1 = implies rec broken into fields */ 46 int donerec; /* 1 = record is valid (no flds have changed) */ 47 48 int maxfld = 0; /* last used field */ 49 int argno = 1; /* current input argument number */ 50 extern Awkfloat *ARGC; 51 52 void recinit(unsigned int n) 53 { 54 static Cell dollar0 = { 55 OCELL, CFLD, "$0", /*recdata*/0, 0.0, REC|STR|DONTFREE }; 56 static Cell dollar1 = { 57 OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; 58 int i; 59 60 record = recdata = (char *) malloc(n); 61 fields = (char *) malloc(n); 62 fldtab = (Cell *) malloc(nfields * sizeof(Cell)); 63 if (recdata == NULL || fields == NULL || fldtab == NULL) 64 ERROR "out of space for $0 and fields" FATAL; 65 fldtab[0] = dollar0; 66 fldtab[0].sval = recdata; 67 for (i = 1; i < nfields; i++) 68 fldtab[i] = dollar1; 69 } 70 71 void initgetrec(void) 72 { 73 int i; 74 char *p; 75 76 for (i = 1; i < *ARGC; i++) { 77 if (!isclvar(p = getargv(i))) { /* find 1st real filename */ 78 setsval(lookup("FILENAME", symtab), getargv(i)); 79 return; 80 } 81 setclvar(p); /* a commandline assignment before filename */ 82 argno++; 83 } 84 infile = stdin; /* no filenames, so use stdin */ 85 } 86 87 int getrec(char *buf) /* get next input record from whatever source */ 88 { /* note: tests whether buf == record */ 89 int c; 90 static int firsttime = 1; 91 92 if (firsttime) { 93 firsttime = 0; 94 initgetrec(); 95 } 96 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n", 97 *RS, *FS, *ARGC, *FILENAME) ); 98 donefld = 0; 99 donerec = 1; 100 buf[0] = 0; 101 while (argno < *ARGC || infile == stdin) { 102 dprintf( ("argno=%d, file=|%s|\n", argno, file) ); 103 if (infile == NULL) { /* have to open a new file */ 104 file = getargv(argno); 105 if (*file == '\0') { /* it's been zapped */ 106 argno++; 107 continue; 108 } 109 if (isclvar(file)) { /* a var=value arg */ 110 setclvar(file); 111 argno++; 112 continue; 113 } 114 *FILENAME = file; 115 dprintf( ("opening file %s\n", file) ); 116 if (*file == '-' && *(file+1) == '\0') 117 infile = stdin; 118 else if ((infile = fopen((char *)file, "r")) == NULL) 119 ERROR "can't open file %s", file FATAL; 120 setfval(fnrloc, 0.0); 121 } 122 c = readrec(buf, recsize, infile); 123 if (c != 0 || buf[0] != '\0') { /* normal record */ 124 if (buf == record) { 125 if (!(recloc->tval & DONTFREE)) 126 xfree(recloc->sval); 127 recloc->sval = record; 128 recloc->tval = REC | STR | DONTFREE; 129 if (isnumber(recloc->sval)) { 130 recloc->fval = atof(recloc->sval); 131 recloc->tval |= NUM; 132 } 133 } 134 setfval(nrloc, nrloc->fval+1); 135 setfval(fnrloc, fnrloc->fval+1); 136 return 1; 137 } 138 /* EOF arrived on this file; set up next */ 139 if (infile != stdin) 140 fclose(infile); 141 infile = NULL; 142 argno++; 143 } 144 return 0; /* true end of file */ 145 } 146 147 void nextfile(void) 148 { 149 if (infile != stdin) 150 fclose(infile); 151 infile = NULL; 152 argno++; 153 } 154 155 int readrec(char *buf, int bufsize, FILE *inf) /* read one record into buf */ 156 { 157 int sep, c; 158 char *rr; 159 int nrr; 160 161 if ((sep = **RS) == 0) { 162 sep = '\n'; 163 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ 164 ; 165 if (c != EOF) 166 ungetc(c, inf); 167 } 168 for (rr = buf, nrr = bufsize; ; ) { 169 for (; (c=getc(inf)) != sep && c != EOF; *rr++ = c) 170 if (--nrr < 0) 171 ERROR "input record `%.30s...' too long; try -mr n", buf FATAL; 172 if (**RS == sep || c == EOF) 173 break; 174 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 175 break; 176 *rr++ = '\n'; 177 *rr++ = c; 178 } 179 if (rr > buf + bufsize) 180 ERROR "input record `%.30s...' too long; try -mr n", buf FATAL; 181 *rr = 0; 182 dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); 183 return c == EOF && rr == buf ? 0 : 1; 184 } 185 186 char *getargv(int n) /* get ARGV[n] */ 187 { 188 Cell *x; 189 char *s, temp[10]; 190 extern Array *ARGVtab; 191 192 sprintf(temp, "%d", n); 193 x = setsymtab(temp, "", 0.0, STR, ARGVtab); 194 s = getsval(x); 195 dprintf( ("getargv(%d) returns |%s|\n", n, s) ); 196 return s; 197 } 198 199 void setclvar(char *s) /* set var=value from s */ 200 { 201 char *p; 202 Cell *q; 203 204 for (p=s; *p != '='; p++) 205 ; 206 *p++ = 0; 207 p = qstring(p, '\0'); 208 q = setsymtab(s, p, 0.0, STR, symtab); 209 setsval(q, p); 210 if (isnumber(q->sval)) { 211 q->fval = atof(q->sval); 212 q->tval |= NUM; 213 } 214 dprintf( ("command line set %s to |%s|\n", s, p) ); 215 } 216 217 218 void fldbld(void) /* create fields from current record */ 219 { 220 char *r, *fr, sep; 221 Cell *p; 222 int i; 223 224 if (donefld) 225 return; 226 if (!(recloc->tval & STR)) 227 getsval(recloc); 228 r = recloc->sval; 229 fr = fields; 230 i = 0; /* number of fields accumulated here */ 231 if (strlen(*FS) > 1) { /* it's a regular expression */ 232 i = refldbld(r, *FS); 233 } else if ((sep = **FS) == ' ') { /* default whitespace */ 234 for (i = 0; ; ) { 235 while (*r == ' ' || *r == '\t' || *r == '\n') 236 r++; 237 if (*r == 0) 238 break; 239 i++; 240 if (i >= nfields) 241 break; 242 if (!(fldtab[i].tval & DONTFREE)) 243 xfree(fldtab[i].sval); 244 fldtab[i].sval = fr; 245 fldtab[i].tval = FLD | STR | DONTFREE; 246 do 247 *fr++ = *r++; 248 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0'); 249 *fr++ = 0; 250 } 251 *fr = 0; 252 } else if ((sep = **FS) == 0) { /* new: FS="" => 1 char/field */ 253 for (i = 0; *r != 0; r++) { 254 char buf[2]; 255 i++; 256 if (i >= nfields) 257 break; 258 if (!(fldtab[i].tval & DONTFREE)) 259 xfree(fldtab[i].sval); 260 buf[0] = *r; 261 buf[1] = 0; 262 fldtab[i].sval = tostring(buf); 263 fldtab[i].tval = FLD | STR; 264 } 265 *fr = 0; 266 } else if (*r != 0) { /* if 0, it's a null field */ 267 for (;;) { 268 i++; 269 if (i >= nfields) 270 break; 271 if (!(fldtab[i].tval & DONTFREE)) 272 xfree(fldtab[i].sval); 273 fldtab[i].sval = fr; 274 fldtab[i].tval = FLD | STR | DONTFREE; 275 while (*r != sep && *r != '\n' && *r != '\0') /* \n is always a separator */ 276 *fr++ = *r++; 277 *fr++ = 0; 278 if (*r++ == 0) 279 break; 280 } 281 *fr = 0; 282 } 283 if (i >= nfields) 284 ERROR "record `%.30s...' has too many fields; try -mf n", record FATAL; 285 /* clean out junk from previous record */ 286 cleanfld(i, maxfld); 287 maxfld = i; 288 donefld = 1; 289 for (p = fldtab+1; p <= fldtab+maxfld; p++) { 290 if(isnumber(p->sval)) { 291 p->fval = atof(p->sval); 292 p->tval |= NUM; 293 } 294 } 295 setfval(nfloc, (Awkfloat) maxfld); 296 if (dbg) 297 for (p = fldtab; p <= fldtab+maxfld; p++) 298 printf("field %d: |%s|\n", p-fldtab, p->sval); 299 } 300 301 void cleanfld(int n1, int n2) /* clean out fields n1..n2 inclusive */ 302 { 303 static char *nullstat = ""; 304 Cell *p, *q; 305 306 for (p = &fldtab[n2], q = &fldtab[n1]; p > q; p--) { 307 if (!(p->tval & DONTFREE)) 308 xfree(p->sval); 309 p->tval = FLD | STR | DONTFREE; 310 p->sval = nullstat; 311 } 312 } 313 314 void newfld(int n) /* add field n (after end) */ 315 { 316 if (n >= nfields) 317 ERROR "creating too many fields (%d); try -mf n", n FATAL; 318 cleanfld(maxfld, n); 319 maxfld = n; 320 setfval(nfloc, (Awkfloat) n); 321 } 322 323 int refldbld(char *rec, char *fs) /* build fields from reg expr in FS */ 324 { 325 char *fr; 326 int i, tempstat; 327 fa *pfa; 328 329 fr = fields; 330 *fr = '\0'; 331 if (*rec == '\0') 332 return 0; 333 pfa = makedfa(fs, 1); 334 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) ); 335 tempstat = pfa->initstat; 336 for (i = 1; i < nfields; i++) { 337 if (!(fldtab[i].tval & DONTFREE)) 338 xfree(fldtab[i].sval); 339 fldtab[i].tval = FLD | STR | DONTFREE; 340 fldtab[i].sval = fr; 341 dprintf( ("refldbld: i=%d\n", i) ); 342 if (nematch(pfa, rec)) { 343 pfa->initstat = 2; /* horrible coupling */ 344 dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); 345 strncpy(fr, rec, patbeg-rec); 346 fr += patbeg - rec + 1; 347 *(fr-1) = '\0'; 348 rec = patbeg + patlen; 349 } else { 350 dprintf( ("no match %s\n", rec) ); 351 strcpy(fr, rec); 352 pfa->initstat = tempstat; 353 break; 354 } 355 } 356 return i; 357 } 358 359 void recbld(void) /* create $0 from $1..$NF if necessary */ 360 { 361 int i; 362 char *r, *p; 363 static char *rec = 0; 364 365 if (donerec == 1) 366 return; 367 if (rec == 0) { 368 rec = (char *) malloc(recsize); 369 if (rec == 0) 370 ERROR "out of space building $0, record size %d", recsize FATAL; 371 } 372 r = rec; 373 for (i = 1; i <= *NF; i++) { 374 p = getsval(&fldtab[i]); 375 while (r < rec+recsize-1 && (*r = *p++)) 376 r++; 377 if (i < *NF) 378 for (p = *OFS; r < rec+recsize-1 && (*r = *p++); ) 379 r++; 380 } 381 if (r > rec + recsize - 1) 382 ERROR "built giant record `%.30s...'; try -mr n", record FATAL; 383 *r = '\0'; 384 dprintf( ("in recbld FS=%o, recloc=%p\n", **FS, recloc) ); 385 recloc->tval = REC | STR | DONTFREE; 386 recloc->sval = record = rec; 387 dprintf( ("in recbld FS=%o, recloc=%p\n", **FS, recloc) ); 388 dprintf( ("recbld = |%s|\n", record) ); 389 donerec = 1; 390 } 391 392 Cell *fieldadr(int n) 393 { 394 if (n < 0 || n >= nfields) 395 ERROR "trying to access field %d; try -mf n", n FATAL; 396 return(&fldtab[n]); 397 } 398 399 int errorflag = 0; 400 char errbuf[200]; 401 402 void yyerror(char *s) 403 { 404 extern char *cmdname, *curfname; 405 static int been_here = 0; 406 407 if (been_here++ > 2) 408 return; 409 fprintf(stderr, "%s: %s", cmdname, s); 410 fprintf(stderr, " at source line %d", lineno); 411 if (curfname != NULL) 412 fprintf(stderr, " in function %s", curfname); 413 fprintf(stderr, "\n"); 414 errorflag = 2; 415 eprint(); 416 } 417 418 void fpecatch(int n) 419 { 420 ERROR "floating point exception %d", n FATAL; 421 } 422 423 extern int bracecnt, brackcnt, parencnt; 424 425 void bracecheck(void) 426 { 427 int c; 428 static int beenhere = 0; 429 430 if (beenhere++) 431 return; 432 while ((c = lex_input()) != EOF && c != '\0') 433 bclass(c); 434 bcheck2(bracecnt, '{', '}'); 435 bcheck2(brackcnt, '[', ']'); 436 bcheck2(parencnt, '(', ')'); 437 } 438 439 void bcheck2(int n, int c1, int c2) 440 { 441 if (n == 1) 442 fprintf(stderr, "\tmissing %c\n", c2); 443 else if (n > 1) 444 fprintf(stderr, "\t%d missing %c's\n", n, c2); 445 else if (n == -1) 446 fprintf(stderr, "\textra %c\n", c2); 447 else if (n < -1) 448 fprintf(stderr, "\t%d extra %c's\n", -n, c2); 449 } 450 451 void error(int f, char *s) 452 { 453 extern Node *curnode; 454 extern char *cmdname; 455 456 fflush(stdout); 457 fprintf(stderr, "%s: ", cmdname); 458 fprintf(stderr, "%s", s); 459 fprintf(stderr, "\n"); 460 if (compile_time != 2 && NR && *NR > 0) { 461 fprintf(stderr, " input record number %d", (int) (*FNR)); 462 if (strcmp(*FILENAME, "-") != 0) 463 fprintf(stderr, ", file %s", *FILENAME); 464 fprintf(stderr, "\n"); 465 } 466 if (compile_time != 2 && curnode) 467 fprintf(stderr, " source line number %d\n", curnode->lineno); 468 else if (compile_time != 2 && lineno) 469 fprintf(stderr, " source line number %d\n", lineno); 470 eprint(); 471 if (f) { 472 if (dbg > 1) /* core dump if serious debugging on */ 473 abort(); 474 exit(2); 475 } 476 } 477 478 void eprint(void) /* try to print context around error */ 479 { 480 #if 0 481 char *p, *q; 482 int c; 483 static int been_here = 0; 484 extern char ebuf[], *ep; 485 486 if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 487 return; 488 p = ep - 1; 489 if (p > ebuf && *p == '\n') 490 p--; 491 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--) 492 ; 493 while (*p == '\n') 494 p++; 495 fprintf(stderr, " context is\n\t"); 496 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--) 497 ; 498 for ( ; p < q; p++) 499 if (*p) 500 putc(*p, stderr); 501 fprintf(stderr, " >>> "); 502 for ( ; p < ep; p++) 503 if (*p) 504 putc(*p, stderr); 505 fprintf(stderr, " <<< "); 506 if (*ep) 507 while ((c = input()) != '\n' && c != '\0' && c != EOF) { 508 putc(c, stderr); 509 bclass(c); 510 } 511 putc('\n', stderr); 512 ep = ebuf; 513 #endif 514 } 515 516 void bclass(int c) 517 { 518 switch (c) { 519 case '{': bracecnt++; break; 520 case '}': bracecnt--; break; 521 case '[': brackcnt++; break; 522 case ']': brackcnt--; break; 523 case '(': parencnt++; break; 524 case ')': parencnt--; break; 525 } 526 } 527 528 double errcheck(double x, char *s) 529 { 530 extern int errno; 531 532 if (errno == EDOM) { 533 errno = 0; 534 ERROR "%s argument out of domain", s WARNING; 535 x = 1; 536 } else if (errno == ERANGE) { 537 errno = 0; 538 ERROR "%s result out of range", s WARNING; 539 x = 1; 540 } 541 return x; 542 } 543 544 int isclvar(char *s) /* is s of form var=something ? */ 545 { 546 char *os = s; 547 548 if (!isalpha(*s) && *s != '_') 549 return 0; 550 for ( ; *s; s++) 551 if (!(isalnum(*s) || *s == '_')) 552 break; 553 return *s == '=' && s > os && *(s+1) != '='; 554 } 555 556 #define MAXEXPON 38 /* maximum exponent for fp number. should be IEEE */ 557 558 int isnumber(char *s) /* should be done by a library function */ 559 { 560 int d1, d2; 561 int point; 562 char *es; 563 564 d1 = d2 = point = 0; 565 while (*s == ' ' || *s == '\t' || *s == '\n') 566 s++; 567 if (*s == '\0') 568 return(0); /* empty stuff isn't a number */ 569 if (*s == '+' || *s == '-') 570 s++; 571 if (!isdigit(*s) && *s != '.') 572 return(0); 573 if (isdigit(*s)) { 574 do { 575 d1++; 576 s++; 577 } while (isdigit(*s)); 578 } 579 if (*s == '.') { 580 point++; 581 s++; 582 } 583 if (isdigit(*s)) { 584 d2++; 585 do { 586 s++; 587 } while (isdigit(*s)); 588 } 589 if (!(d1 || (point && d2))) 590 return(0); 591 if (*s == 'e' || *s == 'E') { 592 s++; 593 if (*s == '+' || *s == '-') 594 s++; 595 if (!isdigit(*s)) 596 return(0); 597 es = s; 598 do { 599 s++; 600 } while (isdigit(*s)); 601 if (s - es > 2) 602 return(0); 603 else if (s - es == 2 && (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON) 604 return(0); 605 } 606 while (*s == ' ' || *s == '\t' || *s == '\n') 607 s++; 608 if (*s == '\0') 609 return(1); 610 else 611 return(0); 612 } 613 614 #if 0 615 /* THIS IS AN EXPERIMENT THAT'S NOT DONE. */ 616 /* strtod ought to provide a better test of what's */ 617 /* a valid number, but it doesn't work according to */ 618 /* the standard on any machine near me! */ 619 620 #include <math.h> 621 isnumber(char *s) 622 { 623 double r; 624 char *ep; 625 errno = 0; 626 r = strtod(s, &ep); 627 if (r == HUGE_VAL || errno == ERANGE) 628 return 0; 629 while (*ep == ' ' || *ep == '\t' || *ep == '\n') 630 ep++; 631 if (*ep == '\0') 632 return 1; 633 else 634 return 0; 635 } 636 #endif 637