Print this page
3731 Update nawk to version 20121220


   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);


 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 }


   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 /*
  28  * Copyright (C) Lucent Technologies 1997
  29  * All Rights Reserved
  30  *
  31  * Permission to use, copy, modify, and distribute this software and
  32  * its documentation for any purpose and without fee is hereby
  33  * granted, provided that the above copyright notice appear in all
  34  * copies and that both that the copyright notice and this
  35  * permission notice and warranty disclaimer appear in supporting
  36  * documentation, and that the name Lucent Technologies or any of
  37  * its entities not be used in advertising or publicity pertaining
  38  * to distribution of the software without specific, written prior
  39  * permission.
  40  *
  41  * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  42  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  43  * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
  44  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  45  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  46  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  47  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  48  * THIS SOFTWARE.
  49  */
  50 
  51 #include <errno.h>
  52 #include <stdarg.h>
  53 #include <math.h>
  54 #include "awk.h"
  55 #include "y.tab.h"
  56 
  57 uchar   *record;
  58 size_t  record_size = RECSIZE;
  59 
  60 Cell    **fldtab;       /* pointers to Cells */
  61 char    inputFS[100] = " ";
  62 
  63 #define MAXFLD  2
  64 int     nfields = MAXFLD;       /* last allocated slot for $i */
  65 
  66 int     donefld;        /* 1 = implies rec broken into fields */
  67 int     donerec;        /* 1 = record is valid (no flds have changed) */
  68 
  69 int     lastfld = 0;    /* last used field */





  70 
  71 static FILE     *infile = NULL;
  72 static uchar    *file   = (uchar*) "";
  73 static uchar    *fields;
  74 static size_t   fields_size = RECSIZE;
  75 

  76 static int      argno   = 1;    /* current input argument number */
  77 
  78 static  uchar   *getargv(int);
  79 static  void    cleanfld(int, int);
  80 static  int     refldbld(uchar *, uchar *);
  81 static  void    bcheck2(int, int, int);
  82 static  void    eprint(void);
  83 static  void    bclass(int);
  84 static  void    makefields(int, int);
  85 
  86 
  87 static Cell dollar0 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, REC|STR|DONTFREE };
  88 static Cell dollar1 = { OCELL, CFLD, NULL, (uchar *)"", 0.0, FLD|STR|DONTFREE };
  89 
  90 void
  91 recinit(unsigned int n)
  92 {
  93         if ((record = (uchar *)malloc(n)) == NULL ||
  94             (fields = (uchar *)malloc(n+1)) == NULL ||
  95             (fldtab = (Cell **)malloc((nfields + 1) *
  96             sizeof (Cell *))) == NULL ||
  97             (fldtab[0] = (Cell *)malloc(sizeof (Cell))) == NULL)
  98                 FATAL("out of space for $0 and fields");
  99         *fldtab[0] = dollar0;
 100         fldtab[0]->sval = record;
 101         fldtab[0]->nval = tostring((uchar *)"0");
 102         makefields(1, nfields);
 103 }
 104 
 105 static void
 106 makefields(int n1, int n2)      /* create $n1..$n2 inclusive */
 107 {
 108         char temp[50];
 109         int i;
 110 
 111         for (i = n1; i <= n2; i++) {
 112                 fldtab[i] = (Cell *)malloc(sizeof (struct Cell));
 113                 if (fldtab[i] == NULL)
 114                         FATAL("out of space in makefields %d", i);
 115                 *fldtab[i] = dollar1;
 116                 (void) sprintf(temp, "%d", i);
 117                 fldtab[i]->nval = tostring((uchar *)temp);
 118         }
 119 }
 120 
 121 static void
 122 initgetrec(void)
 123 {
 124         int i;
 125         uchar *p;
 126 
 127         for (i = 1; i < *ARGC; i++) {
 128                 p = getargv(i); /* find 1st real filename */
 129                 if (p == NULL || *p == '\0') {  /* deleted or zapped */
 130                         argno++;
 131                         continue;
 132                 }
 133                 if (!isclvar(p)) {
 134                         (void) setsval(lookup((uchar *)"FILENAME", symtab), p);
 135                         return;
 136                 }
 137                 setclvar(p);    /* a commandline assignment before filename */
 138                 argno++;
 139         }
 140         infile = stdin;         /* no filenames, so use stdin */

 141 }
 142 
 143 static int firsttime = 1;
 144 
 145 int
 146 getrec(uchar **pbuf, size_t *pbufsize, int isrecord)
 147 {                               /* get next input record */
 148                                 /* note: cares whether buf == record */
 149         int c;
 150         uchar_t *buf = *pbuf;
 151         uchar saveb0;
 152         size_t bufsize = *pbufsize, savebufsize = bufsize;
 153 
 154         if (firsttime) {
 155                 firsttime = 0;
 156                 initgetrec();
 157         }
 158         dprintf(("RS=<%s>, FS=<%s>, ARGC=%f, FILENAME=%s\n",
 159             *RS, *FS, *ARGC, *FILENAME));
 160         if (isrecord) {
 161                 donefld = 0;
 162                 donerec = 1;
 163         }
 164         saveb0 = buf[0];
 165         buf[0] = 0;
 166         while (argno < *ARGC || infile == stdin) {
 167                 dprintf(("argno=%d, file=|%s|\n", argno, file));
 168                 if (infile == NULL) {   /* have to open a new file */
 169                         file = getargv(argno);
 170                         /* deleted or zapped */
 171                         if (file == NULL || *file == '\0') {
 172                                 argno++;
 173                                 continue;
 174                         }
 175                         if (isclvar(file)) {    /* a var=value arg */
 176                                 setclvar(file);
 177                                 argno++;
 178                                 continue;
 179                         }
 180                         *FILENAME = file;
 181                         dprintf(("opening file %s\n", file));
 182                         if (*file == '-' && *(file+1) == '\0')
 183                                 infile = stdin;
 184                         else if ((infile = fopen((char *)file, "r")) == NULL)
 185                                 FATAL("can't open file %s", file);
 186                         (void) setfval(fnrloc, 0.0);
 187                 }
 188                 c = readrec(&buf, &bufsize, infile);






 189                 if (c != 0 || buf[0] != '\0') { /* normal record */
 190                         if (isrecord) {
 191                                 if (freeable(fldtab[0]))
 192                                         xfree(fldtab[0]->sval);
 193                                 fldtab[0]->sval = buf;       /* buf == record */
 194                                 fldtab[0]->tval = REC | STR | DONTFREE;
 195                                 if (is_number(fldtab[0]->sval)) {
 196                                         fldtab[0]->fval =
 197                                             atof((const char *)fldtab[0]->sval);
 198                                         fldtab[0]->tval |= NUM;
 199                                 }
 200                         }
 201                         (void) setfval(nrloc, nrloc->fval+1);
 202                         (void) setfval(fnrloc, fnrloc->fval+1);
 203                         *pbuf = buf;
 204                         *pbufsize = bufsize;
 205                         return (1);
 206                 }
 207                 /* EOF arrived on this file; set up next */
 208                 if (infile != stdin)
 209                         (void) fclose(infile);
 210                 infile = NULL;
 211                 argno++;
 212         }
 213         buf[0] = saveb0;
 214         *pbuf = buf;
 215         *pbufsize = savebufsize;
 216         return (0);     /* true end of file */
 217 }
 218 
 219 void
 220 nextfile(void)
 221 {
 222         if (infile != NULL && infile != stdin)
 223                 (void) fclose(infile);
 224         infile = NULL;
 225         argno++;
 226 }
 227 
 228 /*
 229  * read one record into buf
 230  */
 231 int
 232 readrec(uchar **pbuf, size_t *pbufsize, FILE *inf)
 233 {
 234         int sep, c;
 235         uchar *rr, *buf = *pbuf;
 236         size_t bufsize = *pbufsize;
 237 
 238         if (strlen((char *)*FS) >= sizeof (inputFS))
 239                 FATAL("field separator %.10s... is too long", *FS);
 240         /*
 241          * fflush(stdout); avoids some buffering problem
 242          * but makes it 25% slower
 243          */
 244 
 245         /* for subsequent field splitting */
 246         (void) strcpy(inputFS, (char *)*FS);
 247         if ((sep = **RS) == 0) {
 248                 sep = '\n';
 249                 /* skip leading \n's */
 250                 while ((c = getc(inf)) == '\n' && c != EOF)
 251                         ;
 252                 if (c != EOF)
 253                         (void) ungetc(c, inf);
 254         }
 255         for (rr = buf; ; ) {
 256                 for (; (c = getc(inf)) != sep && c != EOF; ) {
 257                         if (rr-buf+1 > bufsize)
 258                                 if (!adjbuf(&buf, &bufsize, 1+rr-buf,
 259                                     record_size, &rr, "readrec 1"))
 260                                         FATAL(
 261                                 "input record `%.30s...' too long", buf);
 262                         *rr++ = c;
 263                 }
 264                 if (**RS == sep || c == EOF)
 265                         break;
 266                 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
 267                         break;
 268                 if (!adjbuf(&buf, &bufsize, 2+rr-buf, record_size, &rr,
 269                     "readrec 2"))
 270                         FATAL("input record `%.30s...' too long", buf);
 271                 *rr++ = '\n';
 272                 *rr++ = c;
 273         }
 274         if (!adjbuf(&buf, &bufsize, 1+rr-buf, record_size, &rr, "readrec 3"))
 275                 FATAL("input record `%.30s...' too long", buf);
 276         *rr = 0;
 277         dprintf(("readrec saw <%s>, returns %d\n",
 278             buf, c == EOF && rr == buf ? 0 : 1));
 279         *pbuf = buf;
 280         *pbufsize = bufsize;
 281         return (c == EOF && rr == buf ? 0 : 1);
 282 }
 283 

 284 static uchar *
 285 getargv(int n)          /* get ARGV[n] */
 286 {
 287         Cell *x;
 288         uchar *s, temp[50];
 289         extern Array *ARGVtab;
 290 
 291         (void) sprintf((char *)temp, "%d", n);
 292         if (lookup(temp, ARGVtab) == NULL)
 293                 return (NULL);
 294         x = setsymtab(temp, (uchar *)"", 0.0, STR, ARGVtab);
 295         s = getsval(x);
 296         dprintf(("getargv(%d) returns |%s|\n", n, s));
 297         return (s);
 298 }
 299 
 300 void
 301 setclvar(uchar *s)      /* set var=value from s */
 302 {
 303         uchar *p;
 304         Cell *q;
 305 
 306         for (p = s; *p != '='; p++)
 307                 ;
 308         *p++ = 0;
 309         p = qstring(p, '\0');
 310         q = setsymtab(s, p, 0.0, STR, symtab);
 311         (void) setsval(q, p);
 312         if (is_number(q->sval)) {
 313                 q->fval = atof((const char *)q->sval);
 314                 q->tval |= NUM;
 315         }
 316         dprintf(("command line set %s to |%s|\n", s, p));

 317 }
 318 
 319 void
 320 fldbld(void)    /* create fields from current record */
 321 {
 322         /* this relies on having fields[] the same length as $0 */
 323         /* the fields are all stored in this one array with \0's */
 324         /* possibly with a final trailing \0 not associated with any field */
 325         uchar *r, *fr, sep;
 326         Cell *p;
 327         int i, j;
 328         size_t n;
 329 
 330         if (donefld)
 331                 return;
 332         if (!isstr(fldtab[0]))
 333                 (void) getsval(fldtab[0]);
 334         r = fldtab[0]->sval;
 335         n = strlen((char *)r);
 336         if (n > fields_size) {
 337                 xfree(fields);
 338                 /* possibly 2 final \0s */
 339                 if ((fields = (uchar *)malloc(n + 2)) == NULL)
 340                         FATAL("out of space for fields in fldbld %d", n);
 341                 fields_size = n;
 342         }



 343         fr = fields;

 344         i = 0;  /* number of fields accumulated here */
 345         (void) strcpy(inputFS, (char *)*FS);
 346         if (strlen(inputFS) > 1) {   /* it's a regular expression */
 347                 i = refldbld(r, (uchar *)inputFS);
 348         } else if ((sep = *inputFS) == ' ') {   /* default whitespace */
 349                 for (i = 0; ; ) {
 350                         while (*r == ' ' || *r == '\t' || *r == '\n')
 351                                 r++;
 352                         if (*r == 0)
 353                                 break;
 354                         i++;
 355                         if (i > nfields)
 356                                 growfldtab(i);
 357                         if (freeable(fldtab[i]))
 358                                 xfree(fldtab[i]->sval);
 359                         fldtab[i]->sval = fr;
 360                         fldtab[i]->tval = FLD | STR | DONTFREE;
 361                         do
 362                                 *fr++ = *r++;
 363                         while (*r != ' ' && *r != '\t' && *r != '\n' &&
 364                             *r != '\0')
 365                                 ;
 366                         *fr++ = 0;
 367                 }
 368                 *fr = 0;
 369         } else if ((sep = *inputFS) == 0) {     /* new: FS="" => 1 char/field */
 370                 for (i = 0; *r != 0; r++) {
 371                         uchar buf[2];
 372                         i++;
 373                         if (i > nfields)
 374                                 growfldtab(i);
 375                         if (freeable(fldtab[i]))
 376                                 xfree(fldtab[i]->sval);
 377                         buf[0] = *r;
 378                         buf[1] = 0;
 379                         fldtab[i]->sval = tostring(buf);
 380                         fldtab[i]->tval = FLD | STR;
 381                 }
 382                 *fr = 0;
 383         } else if (*r != 0) {   /* if 0, it's a null field */
 384                 /*
 385                  * subtlecase : if length(FS) == 1 && length(RS > 0)
 386                  * \n is NOT a field separator (cf awk book 61,84).
 387                  * this variable is tested in the inner while loop.
 388                  */
 389                 int rtest = '\n';  /* normal case */
 390                 if (strlen((char *)*RS) > 0)
 391                         rtest = '\0';
 392                 for (;;) {
 393                         i++;
 394                         if (i > nfields)
 395                                 growfldtab(i);
 396                         if (freeable(fldtab[i]))
 397                                 xfree(fldtab[i]->sval);
 398                         fldtab[i]->sval = fr;
 399                         fldtab[i]->tval = FLD | STR | DONTFREE;
 400                         /* \n is always a separator */
 401                         while (*r != sep && *r != rtest && *r != '\0')
 402                                 *fr++ = *r++;
 403                         *fr++ = 0;
 404                         if (*r++ == 0)
 405                                 break;
 406                 }
 407                 *fr = 0;
 408         }
 409         if (i > nfields)
 410                 FATAL("record `%.30s...' has too many fields; can't happen", r);
 411         /* clean out junk from previous record */
 412         cleanfld(i + 1, lastfld);
 413         lastfld = i;
 414         donefld = 1;
 415         for (j = 1; j <= lastfld; j++) {
 416                 p = fldtab[j];
 417                 if (is_number(p->sval)) {
 418                         p->fval = atof((const char *)p->sval);
 419                         p->tval |= NUM;
 420                 }
 421         }
 422         (void) setfval(nfloc, (Awkfloat)lastfld);

 423         if (dbg) {
 424                 for (j = 0; j <= lastfld; j++) {
 425                         p = fldtab[j];
 426                         (void) printf("field %d (%s): |%s|\n", j, p->nval,
 427                             p->sval);
 428                 }
 429         }
 430 }
 431 
 432 static void
 433 cleanfld(int n1, int n2)        /* clean out fields n1..n2 inclusive */
 434 {                               /* nvals remain intact */
 435         static uchar *nullstat = (uchar *)"";
 436         Cell *p;
 437         int i;
 438 
 439         for (i = n1; i <= n2; i++) {
 440                 p = fldtab[i];
 441                 if (freeable(p))
 442                         xfree(p->sval);

 443                 p->sval = nullstat;
 444                 p->tval = FLD | STR | DONTFREE;
 445         }
 446 }
 447 
 448 void
 449 newfld(int n)   /* add field n after end of existing lastfld */















 450 {
 451         if (n > nfields)
 452                 growfldtab(n);
 453         cleanfld(lastfld + 1, n);
 454         lastfld = n;
 455         (void) setfval(nfloc, (Awkfloat)n);























 456 }
 457 
 458 Cell *
 459 fieldadr(int n)         /* get nth field */
 460 {
 461         if (n < 0)
 462                 FATAL("trying to access out of range field %d", n);
 463         if (n > nfields)     /* fields after NF are empty */
 464                 growfldtab(n);  /* but does not increase NF */
 465         return (fldtab[n]);











 466 }
 467 
 468 void
 469 growfldtab(int n)       /* make new fields up to at least $n */
 470 {
 471         int nf = 2 * nfields;
 472         size_t s;
 473 
 474         if (n > nf)
 475                 nf = n;
 476         /* freebsd: how much do we need? */
 477         s = (nf + 1) * (sizeof (struct Cell *));
 478         if (s / sizeof (struct Cell *) - 1 == nf)       /* didn't overflow */
 479                 fldtab = (Cell **) realloc(fldtab, s);
 480         else    /* overflow sizeof int */
 481                 xfree(fldtab);  /* make it null */
 482         if (fldtab == NULL)
 483                 FATAL("out of space creating %d fields", nf);
 484         makefields(nfields + 1, nf);
 485         nfields = nf;
 486 }
 487 
 488 static int
 489 refldbld(uchar *rec, uchar *fs) /* build fields from reg expr in FS */
 490 {
 491         /* this relies on having fields[] the same length as $0 */
 492         /* the fields are all stored in this one array with \0's */
 493         uchar *fr;
 494         int i, tempstat;
 495         fa *pfa;
 496         size_t n;

 497 
 498         n = strlen((char *)rec);
 499         if (n > fields_size) {
 500                 xfree(fields);
 501                 if ((fields = (uchar *)malloc(n + 1)) == NULL)
 502                         FATAL("out of space for fields in refldbld %d", n);
 503                 fields_size = n;
 504         }
 505         fr = fields;
 506         *fr = '\0';
 507         if (*rec == '\0')
 508                 return (0);





 509         pfa = makedfa(fs, 1);
 510         dprintf(("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs));
 511         tempstat = pfa->initstat;
 512         for (i = 1; ; i++) {
 513                 if (i > nfields)
 514                         growfldtab(i);
 515                 if (freeable(fldtab[i]))
 516                         xfree(fldtab[i]->sval);
 517                 fldtab[i]->tval = FLD | STR | DONTFREE;
 518                 fldtab[i]->sval = fr;
 519                 dprintf(("refldbld: i=%d\n", i));
 520                 if (nematch(pfa, rec)) {
 521                         pfa->initstat = 2;   /* horrible coupling to b.c */
 522                         dprintf(("match %s (%d chars)\n", patbeg, patlen));
 523                         (void) strncpy((char *)fr, (char *)rec, patbeg-rec);
 524                         fr += patbeg - rec + 1;
 525                         *(fr-1) = '\0';
 526                         rec = patbeg + patlen;
 527                 } else {
 528                         dprintf(("no match %s\n", rec));
 529                         (void) strcpy((char *)fr, (char *)rec);
 530                         pfa->initstat = tempstat;
 531                         break;
 532                 }
 533         }
 534         return (i);
 535 }
 536 
 537 void
 538 recbld(void)            /* create $0 from $1..$NF if necessary */
 539 {
 540         int i;
 541         uchar *r, *p;

 542 
 543         if (donerec == 1)
 544                 return;
 545         r = record;

 546         for (i = 1; i <= *NF; i++) {
 547                 p = getsval(fldtab[i]);
 548                 if (!adjbuf(&record, &record_size, 1 + strlen((char *)p) + r -
 549                     record, record_size, &r, "recbld 1"))
 550                         FATAL("created $0 `%.30s...' too long", record);
 551                 while ((*r = *p++) != 0)
 552                         r++;
 553                 if (i < *NF) {
 554                         if (!adjbuf(&record, &record_size, 2 +
 555                             strlen((char *)*OFS) + r - record, record_size,
 556                             &r, "recbld 2"))
 557                                 FATAL("created $0 `%.30s...' too long", record);
 558                         for (p = *OFS; (*r = *p++) != 0; )
 559                                 r++;
 560                 }
 561         }
 562         if (!adjbuf(&record, &record_size, 2 + r - record, record_size, &r,
 563             "recbld 3"))
 564                 FATAL("built giant record `%.30s...'", record);
 565         *r = '\0';
 566         dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS,
 567             (void *)fldtab[0]));
 568 
 569         if (freeable(fldtab[0]))
 570                 xfree(fldtab[0]->sval);
 571         fldtab[0]->tval = REC | STR | DONTFREE;
 572         fldtab[0]->sval = record;
 573 
 574         dprintf(("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS,
 575             (void *)fldtab[0]));
 576         dprintf(("recbld = |%s|\n", record));
 577         donerec = 1;
 578 }
 579 








 580 int     errorflag       = 0;

 581 
 582 void
 583 yyerror(char *s)
 584 {
 585         SYNTAX("%s", s);
 586 }
 587 
 588 void
 589 SYNTAX(const char *fmt, ...)
 590 {
 591         extern uchar *cmdname, *curfname;
 592         static int been_here = 0;
 593         va_list varg;
 594 
 595         if (been_here++ > 2)
 596                 return;
 597         (void) fprintf(stderr, "%s: ", cmdname);
 598         va_start(varg, fmt);
 599         (void) vfprintf(stderr, fmt, varg);
 600         va_end(varg);
 601         (void) fprintf(stderr, gettext(" at source line %lld"), lineno);
 602         if (curfname != NULL)
 603                 (void) fprintf(stderr, gettext(" in function %s"), curfname);
 604         if (compile_time == 1 && cursource() != NULL)
 605                 (void) fprintf(stderr, gettext(" source file %s"), cursource());
 606         (void) fprintf(stderr, "\n");
 607         errorflag = 2;
 608         eprint();
 609 }
 610 

 611 void
 612 fpecatch(int n)
 613 {
 614         FATAL("floating point exception %d", n);
 615 }
 616 
 617 extern int bracecnt, brackcnt, parencnt;
 618 
 619 void
 620 bracecheck(void)
 621 {
 622         int c;
 623         static int beenhere = 0;
 624 
 625         if (beenhere++)
 626                 return;
 627         while ((c = input()) != EOF && c != '\0')
 628                 bclass(c);
 629         bcheck2(bracecnt, '{', '}');
 630         bcheck2(brackcnt, '[', ']');
 631         bcheck2(parencnt, '(', ')');
 632 }
 633 
 634 /*ARGSUSED*/
 635 static void
 636 bcheck2(int n, int c1, int c2)
 637 {
 638         if (n == 1)
 639                 (void) fprintf(stderr, gettext("\tmissing %c\n"), c2);
 640         else if (n > 1)
 641                 (void) fprintf(stderr, gettext("\t%d missing %c's\n"), n, c2);
 642         else if (n == -1)
 643                 (void) fprintf(stderr, gettext("\textra %c\n"), c2);
 644         else if (n < -1)
 645                 (void) fprintf(stderr, gettext("\t%d extra %c's\n"), -n, c2);
 646 }
 647 
 648 void
 649 FATAL(const char *fmt, ...)
 650 {

 651         extern uchar *cmdname;
 652         va_list varg;
 653 
 654         (void) fflush(stdout);
 655         (void) fprintf(stderr, "%s: ", cmdname);
 656         va_start(varg, fmt);
 657         (void) vfprintf(stderr, fmt, varg);
 658         va_end(varg);
 659         error();
 660         if (dbg > 1) /* core dump if serious debugging on */
 661                 abort();
 662         exit(2);
 663 }
 664 
 665 void
 666 WARNING(const char *fmt, ...)
 667 {
 668         extern uchar *cmdname;
 669         va_list varg;
 670 
 671         (void) fflush(stdout);
 672         (void) fprintf(stderr, "%s: ", cmdname);
 673         va_start(varg, fmt);
 674         (void) vfprintf(stderr, fmt, varg);
 675         va_end(varg);
 676         error();
 677 }
 678 
 679 void
 680 error(void)
 681 {
 682         extern Node *curnode;
 683 
 684         (void) fprintf(stderr, "\n");
 685         if (compile_time != 2 && NR && *NR > 0) {
 686                 (void) fprintf(stderr,
 687                     gettext(" input record number %g"), (int) (*FNR));
 688                 if (strcmp((char *)*FILENAME, "-") != 0)
 689                         (void) fprintf(stderr, gettext(", file %s"), *FILENAME);
 690                 (void) fprintf(stderr, "\n");
 691         }
 692         if (compile_time != 2 && curnode)
 693                 (void) fprintf(stderr, gettext(" source line number %d"),
 694                     curnode->lineno);
 695         else if (compile_time != 2 && lineno) {
 696                 (void) fprintf(stderr,
 697                     gettext(" source line number %d"), lineno);
 698         }
 699         if (compile_time == 1 && cursource() != NULL)
 700                 (void) fprintf(stderr,
 701                     gettext(" source file %s"), cursource());
 702         (void) fprintf(stderr, "\n");
 703         eprint();





 704 }
 705 
 706 static void
 707 eprint(void)    /* try to print context around error */
 708 {
 709         uchar *p, *q;
 710         int c;
 711         static int been_here = 0;
 712         extern uchar ebuf[], *ep;
 713 
 714         if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
 715                 return;
 716         p = ep - 1;
 717         if (p > ebuf && *p == '\n')
 718                 p--;
 719         for (; p > ebuf && *p != '\n' && *p != '\0'; p--)
 720                 ;
 721         while (*p == '\n')
 722                 p++;
 723         (void) fprintf(stderr, gettext(" context is\n\t"));
 724         for (q = ep-1; q >= p && *q != ' ' && *q != '\t' && *q != '\n'; q--)
 725                 ;
 726         for (; p < q; p++)
 727                 if (*p)
 728                         (void) putc(*p, stderr);
 729         (void) fprintf(stderr, " >>> ");
 730         for (; p < ep; p++)
 731                 if (*p)
 732                         (void) putc(*p, stderr);


 737                         bclass(c);
 738                 }
 739         (void) putc('\n', stderr);
 740         ep = ebuf;
 741 }
 742 
 743 static void
 744 bclass(int c)
 745 {
 746         switch (c) {
 747         case '{': bracecnt++; break;
 748         case '}': bracecnt--; break;
 749         case '[': brackcnt++; break;
 750         case ']': brackcnt--; break;
 751         case '(': parencnt++; break;
 752         case ')': parencnt--; break;
 753         }
 754 }
 755 
 756 double
 757 errcheck(double x, const char *s)
 758 {


 759         if (errno == EDOM) {
 760                 errno = 0;
 761                 WARNING("%s argument out of domain", s);
 762                 x = 1;
 763         } else if (errno == ERANGE) {
 764                 errno = 0;
 765                 WARNING("%s result out of range", s);
 766                 x = 1;
 767         }
 768         return (x);
 769 }
 770 






 771 int
 772 isclvar(const uchar *s) /* is s of form var=something? */
 773 {
 774         const uchar *os = s;
 775 
 776         if (!isalpha(*s) && *s != '_')
 777                 return (0);
 778         for (; *s; s++) {
 779                 if (!(isalnum(*s) || *s == '_'))





 780                         break;
 781         }




 782 
 783         return (*s == '=' && s > os && *(s+1) != '=');
 784 }
 785 
 786 /* strtod is supposed to be a proper test of what's a valid number */
 787 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
 788 /* wrong: violates 4.10.1.4 of ansi C standard */
 789 
 790 int
 791 is_number(const uchar *s)
 792 {
 793         double r;
 794         char *ep;
 795         errno = 0;
 796         r = strtod((const char *)s, &ep);
 797         if (ep == (char *)s || r == HUGE_VAL || errno == ERANGE)











































 798                 return (0);
 799         while (*ep == ' ' || *ep == '\t' || *ep == '\n')
 800                 ep++;
 801         if (*ep == '\0')


 802                 return (1);
 803         else
 804                 return (0);
 805 }