Home | History | Annotate | Download | only in awk
      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 }
    796