1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <errno.h> 33 #include "awk.h" 34 #include "y.tab.h" 35 36 uchar *record; 37 size_t record_size; 38 39 int donefld; /* 1 = implies rec broken into fields */ 40 int donerec; /* 1 = record is valid (no flds have changed) */ 41 42 static struct fldtab_chunk { 43 struct fldtab_chunk *next; 44 Cell fields[FLD_INCR]; 45 } *fldtab_head, *fldtab_tail; 46 47 static size_t fldtab_maxidx; 48 49 static FILE *infile = NULL; 50 static uchar *file = (uchar*) ""; 51 static uchar *fields; 52 static size_t fields_size = LINE_INCR; 53 54 static int maxfld = 0; /* last used field */ 55 static int argno = 1; /* current input argument number */ 56 57 static uchar *getargv(int); 58 static void cleanfld(int, int); 59 static int refldbld(uchar *, uchar *); 60 static void bcheck2(int, int, int); 61 static void eprint(void); 62 static void bclass(int); 63 64 static void 65 initgetrec(void) 66 { 67 int i; 68 uchar *p; 69 70 for (i = 1; i < *ARGC; i++) { 71 if (!isclvar(p = getargv(i))) /* find 1st real filename */ 72 return; 73 setclvar(p); /* a commandline assignment before filename */ 74 argno++; 75 } 76 infile = stdin; /* no filenames, so use stdin */ 77 /* *FILENAME = file = (uchar*) "-"; */ 78 } 79 80 int 81 getrec(uchar **bufp, size_t *bufsizep) 82 { 83 int c; 84 static int firsttime = 1; 85 uchar_t *buf, *nbuf; 86 size_t len; 87 88 if (firsttime) { 89 firsttime = 0; 90 initgetrec(); 91 } 92 dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n", 93 *RS, *FS, *ARGC, *FILENAME)); 94 donefld = 0; 95 donerec = 1; 96 while (argno < *ARGC || infile == stdin) { 97 dprintf(("argno=%d, file=|%s|\n", argno, file)); 98 if (infile == NULL) { /* have to open a new file */ 99 file = getargv(argno); 100 if (*file == '\0') { /* it's been zapped */ 101 argno++; 102 continue; 103 } 104 if (isclvar(file)) { /* a var=value arg */ 105 setclvar(file); 106 argno++; 107 continue; 108 } 109 *FILENAME = file; 110 dprintf(("opening file %s\n", file)); 111 if (*file == '-' && *(file+1) == '\0') 112 infile = stdin; 113 else if ((infile = fopen((char *)file, "r")) == NULL) 114 ERROR "can't open file %s", file FATAL; 115 (void) setfval(fnrloc, 0.0); 116 } 117 c = readrec(&nbuf, &len, infile); 118 expand_buf(bufp, bufsizep, len); 119 buf = *bufp; 120 (void) memcpy(buf, nbuf, len); 121 buf[len] = '\0'; 122 free(nbuf); 123 124 if (c != 0 || buf[0] != '\0') { /* normal record */ 125 if (bufp == &record) { 126 if (!(recloc->tval & DONTFREE)) 127 xfree(recloc->sval); 128 recloc->sval = record; 129 recloc->tval = REC | STR | DONTFREE; 130 if (is_number(recloc->sval)) { 131 recloc->fval = 132 atof((const char *)recloc->sval); 133 recloc->tval |= NUM; 134 } 135 } 136 (void) setfval(nrloc, nrloc->fval+1); 137 (void) setfval(fnrloc, fnrloc->fval+1); 138 return (1); 139 } 140 /* EOF arrived on this file; set up next */ 141 if (infile != stdin) 142 (void) fclose(infile); 143 infile = NULL; 144 argno++; 145 } 146 return (0); /* true end of file */ 147 } 148 149 int 150 readrec(uchar **bufp, size_t *sizep, FILE *inf) /* read one record into buf */ 151 { 152 int sep, c; 153 uchar *buf; 154 int count; 155 size_t bufsize; 156 157 init_buf(&buf, &bufsize, LINE_INCR); 158 if ((sep = **RS) == 0) { 159 sep = '\n'; 160 /* skip leading \n's */ 161 while ((c = getc(inf)) == '\n' && c != EOF) 162 ; 163 if (c != EOF) 164 (void) ungetc(c, inf); 165 } 166 count = 0; 167 for (;;) { 168 while ((c = getc(inf)) != sep && c != EOF) { 169 expand_buf(&buf, &bufsize, count); 170 buf[count++] = c; 171 } 172 if (**RS == sep || c == EOF) 173 break; 174 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ 175 break; 176 expand_buf(&buf, &bufsize, count + 1); 177 buf[count++] = '\n'; 178 buf[count++] = c; 179 } 180 buf[count] = '\0'; 181 dprintf(("readrec saw <%s>, returns %d\n", 182 buf, c == EOF && count == 0 ? 0 : 1)); 183 *bufp = buf; 184 *sizep = count; 185 return (c == EOF && count == 0 ? 0 : 1); 186 } 187 188 /* get ARGV[n] */ 189 static uchar * 190 getargv(int n) 191 { 192 Cell *x; 193 uchar *s, temp[11]; 194 extern Array *ARGVtab; 195 196 (void) sprintf((char *)temp, "%d", n); 197 x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab); 198 s = getsval(x); 199 dprintf(("getargv(%d) returns |%s|\n", n, s)); 200 return (s); 201 } 202 203 void 204 setclvar(uchar *s) /* set var=value from s */ 205 { 206 uchar *p; 207 Cell *q; 208 209 for (p = s; *p != '='; p++) 210 ; 211 *p++ = 0; 212 p = qstring(p, '\0'); 213 q = setsymtab(s, p, 0.0, STR, symtab); 214 (void) setsval(q, p); 215 if (is_number(q->sval)) { 216 q->fval = atof((const char *)q->sval); 217 q->tval |= NUM; 218 } 219 dprintf(("command line set %s to |%s|\n", s, p)); 220 free(p); 221 } 222 223 void 224 fldbld(void) 225 { 226 uchar *r, *fr, sep; 227 Cell *p; 228 int i; 229 size_t len; 230 231 if (donefld) 232 return; 233 if (!(recloc->tval & STR)) 234 (void) getsval(recloc); 235 r = recloc->sval; /* was record! */ 236 237 /* make sure fields is always allocated */ 238 adjust_buf(&fields, fields_size); 239 240 /* 241 * make sure fields has enough size. We don't expand the buffer 242 * in the middle of the loop, since p->sval has already pointed 243 * the address in the fields. 244 */ 245 len = strlen((char *)r) + 1; 246 expand_buf(&fields, &fields_size, len); 247 fr = fields; 248 249 i = 0; /* number of fields accumulated here */ 250 if (strlen((char *)*FS) > 1) { /* it's a regular expression */ 251 i = refldbld(r, *FS); 252 } else if ((sep = **FS) == ' ') { 253 for (i = 0; ; ) { 254 while (*r == ' ' || *r == '\t' || *r == '\n') 255 r++; 256 if (*r == 0) 257 break; 258 i++; 259 p = getfld(i); 260 if (!(p->tval & DONTFREE)) 261 xfree(p->sval); 262 p->sval = fr; 263 p->tval = FLD | STR | DONTFREE; 264 do 265 *fr++ = *r++; 266 while (*r != ' ' && *r != '\t' && *r != '\n' && 267 *r != '\0') 268 ; 269 *fr++ = 0; 270 } 271 *fr = 0; 272 } else if (*r != 0) { /* if 0, it's a null field */ 273 for (;;) { 274 i++; 275 p = getfld(i); 276 if (!(p->tval & DONTFREE)) 277 xfree(p->sval); 278 p->sval = fr; 279 p->tval = FLD | STR | DONTFREE; 280 /* \n always a separator */ 281 while (*r != sep && *r != '\n' && *r != '\0') 282 *fr++ = *r++; 283 *fr++ = 0; 284 if (*r++ == 0) 285 break; 286 } 287 *fr = 0; 288 } 289 /* clean out junk from previous record */ 290 cleanfld(i, maxfld); 291 maxfld = i; 292 donefld = 1; 293 for (i = 1; i <= maxfld; i++) { 294 p = getfld(i); 295 if (is_number(p->sval)) { 296 p->fval = atof((const char *)p->sval); 297 p->tval |= NUM; 298 } 299 } 300 301 (void) setfval(nfloc, (Awkfloat) maxfld); 302 if (dbg) { 303 for (i = 0; i <= maxfld; i++) { 304 p = getfld(i); 305 (void) printf("field %d: |%s|\n", i, p->sval); 306 } 307 } 308 } 309 310 static void 311 cleanfld(int n1, int n2) /* clean out fields n1..n2 inclusive */ 312 { 313 static uchar *nullstat = (uchar *) ""; 314 Cell *p; 315 int i; 316 317 for (i = n2; i > n1; i--) { 318 p = getfld(i); 319 if (!(p->tval & DONTFREE)) 320 xfree(p->sval); 321 p->tval = FLD | STR | DONTFREE; 322 p->sval = nullstat; 323 } 324 } 325 326 void 327 newfld(int n) /* add field n (after end) */ 328 { 329 if (n < 0) 330 ERROR "accessing invalid field", record FATAL; 331 (void) getfld(n); 332 cleanfld(maxfld, n); 333 maxfld = n; 334 (void) setfval(nfloc, (Awkfloat) n); 335 } 336 337 /* 338 * allocate field table. We don't reallocate the table since there 339 * might be somewhere recording the address of the table. 340 */ 341 static void 342 morefld(void) 343 { 344 int i; 345 struct fldtab_chunk *fldcp; 346 Cell *newfld; 347 348 if ((fldcp = calloc(sizeof (struct fldtab_chunk), 1)) == NULL) 349 ERROR "out of space in morefld" FATAL; 350 351 newfld = &fldcp->fields[0]; 352 for (i = 0; i < FLD_INCR; i++) { 353 newfld[i].ctype = OCELL; 354 newfld[i].csub = CFLD; 355 newfld[i].nval = NULL; 356 newfld[i].sval = (uchar *)""; 357 newfld[i].fval = 0.0; 358 newfld[i].tval = FLD|STR|DONTFREE; 359 newfld[i].cnext = NULL; 360 } 361 /* 362 * link this field chunk 363 */ 364 if (fldtab_head == NULL) 365 fldtab_head = fldcp; 366 else 367 fldtab_tail->next = fldcp; 368 fldtab_tail = fldcp; 369 fldcp->next = NULL; 370 371 fldtab_maxidx += FLD_INCR; 372 } 373 374 Cell * 375 getfld(int idx) 376 { 377 struct fldtab_chunk *fldcp; 378 int cbase; 379 380 if (idx < 0) 381 ERROR "trying to access field %d", idx FATAL; 382 while (idx >= fldtab_maxidx) 383 morefld(); 384 cbase = 0; 385 for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) { 386 if (idx < (cbase + FLD_INCR)) 387 return (&fldcp->fields[idx - cbase]); 388 cbase += FLD_INCR; 389 } 390 /* should never happen */ 391 ERROR "trying to access invalid field %d", idx FATAL; 392 return (NULL); 393 } 394 395 int 396 fldidx(Cell *vp) 397 { 398 struct fldtab_chunk *fldcp; 399 Cell *tbl; 400 int cbase; 401 402 cbase = 0; 403 for (fldcp = fldtab_head; fldcp != NULL; fldcp = fldcp->next) { 404 tbl = &fldcp->fields[0]; 405 if (vp >= tbl && vp < (tbl + FLD_INCR)) 406 return (cbase + (vp - tbl)); 407 cbase += FLD_INCR; 408 } 409 /* should never happen */ 410 ERROR "trying to access unknown field" FATAL; 411 return (0); 412 } 413 414 static int 415 refldbld(uchar *rec, uchar *fs) /* build fields from reg expr in FS */ 416 { 417 uchar *fr; 418 int i, tempstat; 419 fa *pfa; 420 Cell *p; 421 size_t len; 422 423 /* make sure fields is allocated */ 424 adjust_buf(&fields, fields_size); 425 fr = fields; 426 *fr = '\0'; 427 if (*rec == '\0') 428 return (0); 429 430 len = strlen((char *)rec) + 1; 431 expand_buf(&fields, &fields_size, len); 432 fr = fields; 433 434 pfa = makedfa(fs, 1); 435 dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)); 436 tempstat = pfa->initstat; 437 for (i = 1; ; i++) { 438 p = getfld(i); 439 if (!(p->tval & DONTFREE)) 440 xfree(p->sval); 441 p->tval = FLD | STR | DONTFREE; 442 p->sval = fr; 443 dprintf(("refldbld: i=%d\n", i)); 444 if (nematch(pfa, rec)) { 445 pfa->initstat = 2; 446 dprintf(("match %s (%d chars)\n", patbeg, patlen)); 447 (void) strncpy((char *)fr, (char *)rec, patbeg-rec); 448 fr += patbeg - rec + 1; 449 *(fr-1) = '\0'; 450 rec = patbeg + patlen; 451 } else { 452 dprintf(("no match %s\n", rec)); 453 (void) strcpy((char *)fr, (char *)rec); 454 pfa->initstat = tempstat; 455 break; 456 } 457 } 458 return (i); 459 } 460 461 void 462 recbld(void) 463 { 464 int i; 465 uchar *p; 466 size_t cnt, len, olen; 467 468 if (donerec == 1) 469 return; 470 cnt = 0; 471 olen = strlen((char *)*OFS); 472 for (i = 1; i <= *NF; i++) { 473 p = getsval(getfld(i)); 474 len = strlen((char *)p); 475 expand_buf(&record, &record_size, cnt + len + olen); 476 (void) memcpy(&record[cnt], p, len); 477 cnt += len; 478 if (i < *NF) { 479 (void) memcpy(&record[cnt], *OFS, olen); 480 cnt += olen; 481 } 482 } 483 record[cnt] = '\0'; 484 dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc)); 485 if (!(recloc->tval & DONTFREE)) 486 xfree(recloc->sval); 487 recloc->tval = REC | STR | DONTFREE; 488 recloc->sval = record; 489 dprintf(("in recbld FS=%o, recloc=%p\n", **FS, (void *)recloc)); 490 dprintf(("recbld = |%s|\n", record)); 491 donerec = 1; 492 } 493 494 Cell * 495 fieldadr(int n) 496 { 497 if (n < 0) 498 ERROR "trying to access field %d", n FATAL; 499 return (getfld(n)); 500 } 501 502 int errorflag = 0; 503 char errbuf[200]; 504 505 void 506 yyerror(char *s) 507 { 508 extern uchar *cmdname, *curfname; 509 static int been_here = 0; 510 511 if (been_here++ > 2) 512 return; 513 (void) fprintf(stderr, "%s: %s", cmdname, s); 514 (void) fprintf(stderr, gettext(" at source line %lld"), lineno); 515 if (curfname != NULL) 516 (void) fprintf(stderr, gettext(" in function %s"), curfname); 517 (void) fprintf(stderr, "\n"); 518 errorflag = 2; 519 eprint(); 520 } 521 522 /*ARGSUSED*/ 523 void 524 fpecatch(int sig) 525 { 526 ERROR "floating point exception" FATAL; 527 } 528 529 extern int bracecnt, brackcnt, parencnt; 530 531 void 532 bracecheck(void) 533 { 534 int c; 535 static int beenhere = 0; 536 537 if (beenhere++) 538 return; 539 while ((c = input()) != EOF && c != '\0') 540 bclass(c); 541 bcheck2(bracecnt, '{', '}'); 542 bcheck2(brackcnt, '[', ']'); 543 bcheck2(parencnt, '(', ')'); 544 } 545 546 /*ARGSUSED*/ 547 static void 548 bcheck2(int n, int c1, int c2) 549 { 550 if (n == 1) 551 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2); 552 else if (n > 1) 553 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2); 554 else if (n == -1) 555 (void) fprintf(stderr, gettext("\textra %c\n"), c2); 556 else if (n < -1) 557 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2); 558 } 559 560 void 561 error(int f, char *s) 562 { 563 extern Node *curnode; 564 extern uchar *cmdname; 565 566 (void) fflush(stdout); 567 (void) fprintf(stderr, "%s: ", cmdname); 568 (void) fprintf(stderr, "%s", s); 569 (void) fprintf(stderr, "\n"); 570 if (compile_time != 2 && NR && *NR > 0) { 571 (void) fprintf(stderr, 572 gettext(" input record number %g"), *FNR); 573 if (strcmp((char *)*FILENAME, "-") != 0) 574 (void) fprintf(stderr, gettext(", file %s"), *FILENAME); 575 (void) fprintf(stderr, "\n"); 576 } 577 if (compile_time != 2 && curnode) 578 (void) fprintf(stderr, gettext(" source line number %lld\n"), 579 curnode->lineno); 580 else if (compile_time != 2 && lineno) { 581 (void) fprintf(stderr, 582 gettext(" source line number %lld\n"), lineno); 583 } 584 eprint(); 585 if (f) { 586 if (dbg) 587 abort(); 588 exit(2); 589 } 590 } 591 592 static void 593 eprint(void) /* try to print context around error */ 594 { 595 uchar *p, *q; 596 int c; 597 static int been_here = 0; 598 extern uchar ebuf[300], *ep; 599 600 if (compile_time == 2 || compile_time == 0 || been_here++ > 0) 601 return; 602 p = ep - 1; 603 if (p > ebuf && *p == '\n') 604 p--; 605 for (; p > ebuf && *p != '\n' && *p != '\0'; p--) 606 ; 607 while (*p == '\n') 608 p++; 609 (void) fprintf(stderr, gettext(" context is\n\t")); 610 for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--) 611 ; 612 for (; p < q; p++) 613 if (*p) 614 (void) putc(*p, stderr); 615 (void) fprintf(stderr, " >>> "); 616 for (; p < ep; p++) 617 if (*p) 618 (void) putc(*p, stderr); 619 (void) fprintf(stderr, " <<< "); 620 if (*ep) 621 while ((c = input()) != '\n' && c != '\0' && c != EOF) { 622 (void) putc(c, stderr); 623 bclass(c); 624 } 625 (void) putc('\n', stderr); 626 ep = ebuf; 627 } 628 629 static void 630 bclass(int c) 631 { 632 switch (c) { 633 case '{': bracecnt++; break; 634 case '}': bracecnt--; break; 635 case '[': brackcnt++; break; 636 case ']': brackcnt--; break; 637 case '(': parencnt++; break; 638 case ')': parencnt--; break; 639 } 640 } 641 642 double 643 errcheck(double x, char *s) 644 { 645 extern int errno; 646 647 if (errno == EDOM) { 648 errno = 0; 649 ERROR "%s argument out of domain", s WARNING; 650 x = 1; 651 } else if (errno == ERANGE) { 652 errno = 0; 653 ERROR "%s result out of range", s WARNING; 654 x = 1; 655 } 656 return (x); 657 } 658 659 void 660 PUTS(uchar *s) 661 { 662 dprintf(("%s\n", s)); 663 } 664 665 int 666 isclvar(uchar *s) /* is s of form var=something? */ 667 { 668 if (s != NULL) { 669 670 /* Must begin with an underscore or alphabetic character */ 671 if (isalpha(*s) || (*s == '_')) { 672 673 for (s++; *s; s++) { 674 /* 675 * followed by a sequence of underscores, 676 * digits, and alphabetics 677 */ 678 if (!(isalnum(*s) || *s == '_')) { 679 break; 680 } 681 } 682 return (*s == '=' && *(s + 1) != '='); 683 } 684 } 685 686 return (0); 687 } 688 689 #define MAXEXPON 38 /* maximum exponent for fp number */ 690 691 int 692 is_number(uchar *s) 693 { 694 int d1, d2; 695 int point; 696 uchar *es; 697 extern char radixpoint; 698 699 d1 = d2 = point = 0; 700 while (*s == ' ' || *s == '\t' || *s == '\n') 701 s++; 702 if (*s == '\0') 703 return (0); /* empty stuff isn't number */ 704 if (*s == '+' || *s == '-') 705 s++; 706 if (!isdigit(*s) && *s != radixpoint) 707 return (0); 708 if (isdigit(*s)) { 709 do { 710 d1++; 711 s++; 712 } while (isdigit(*s)); 713 } 714 if (d1 >= MAXEXPON) 715 return (0); /* too many digits to convert */ 716 if (*s == radixpoint) { 717 point++; 718 s++; 719 } 720 if (isdigit(*s)) { 721 d2++; 722 do { 723 s++; 724 } while (isdigit(*s)); 725 } 726 if (!(d1 || point && d2)) 727 return (0); 728 if (*s == 'e' || *s == 'E') { 729 s++; 730 if (*s == '+' || *s == '-') 731 s++; 732 if (!isdigit(*s)) 733 return (0); 734 es = s; 735 do { 736 s++; 737 } while (isdigit(*s)); 738 if (s - es > 2) { 739 return (0); 740 } else if (s - es == 2 && 741 (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON) { 742 return (0); 743 } 744 } 745 while (*s == ' ' || *s == '\t' || *s == '\n') 746 s++; 747 if (*s == '\0') 748 return (1); 749 else 750 return (0); 751 } 752 753 void 754 init_buf(uchar **optr, size_t *sizep, size_t amt) 755 { 756 uchar *nptr = NULL; 757 758 if ((nptr = malloc(amt)) == NULL) 759 ERROR "out of space in init_buf" FATAL; 760 /* initial buffer should have NULL terminated */ 761 *nptr = '\0'; 762 if (sizep != NULL) 763 *sizep = amt; 764 *optr = nptr; 765 } 766 767 void 768 r_expand_buf(uchar **optr, size_t *sizep, size_t req) 769 { 770 uchar *nptr; 771 size_t amt, size = *sizep; 772 773 if (size != 0 && req < (size - 1)) 774 return; 775 amt = req + 1 - size; 776 amt = (amt / LINE_INCR + 1) * LINE_INCR; 777 778 if ((nptr = realloc(*optr, size + amt)) == NULL) 779 ERROR "out of space in expand_buf" FATAL; 780 /* initial buffer should have NULL terminated */ 781 if (size == 0) 782 *nptr = '\0'; 783 *sizep += amt; 784 *optr = nptr; 785 } 786 787 void 788 adjust_buf(uchar **optr, size_t size) 789 { 790 uchar *nptr; 791 792 if ((nptr = realloc(*optr, size)) == NULL) 793 ERROR "out of space in adjust_buf" FATAL; 794 *optr = nptr; 795 }