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