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 }