xref: /plan9/sys/src/cmd/awk/lib.c (revision 05bfb676bfe3b84c9fb5fa2c9ef6d09a93084a7b)
17dd7cddfSDavid du Colombier /****************************************************************
27dd7cddfSDavid du Colombier Copyright (C) Lucent Technologies 1997
33e12c5d1SDavid du Colombier All Rights Reserved
43e12c5d1SDavid du Colombier 
57dd7cddfSDavid du Colombier Permission to use, copy, modify, and distribute this software and
67dd7cddfSDavid du Colombier its documentation for any purpose and without fee is hereby
77dd7cddfSDavid du Colombier granted, provided that the above copyright notice appear in all
87dd7cddfSDavid du Colombier copies and that both that the copyright notice and this
97dd7cddfSDavid du Colombier permission notice and warranty disclaimer appear in supporting
107dd7cddfSDavid du Colombier documentation, and that the name Lucent Technologies or any of
117dd7cddfSDavid du Colombier its entities not be used in advertising or publicity pertaining
127dd7cddfSDavid du Colombier to distribution of the software without specific, written prior
137dd7cddfSDavid du Colombier permission.
143e12c5d1SDavid du Colombier 
157dd7cddfSDavid du Colombier LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
167dd7cddfSDavid du Colombier INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
177dd7cddfSDavid du Colombier IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
187dd7cddfSDavid du Colombier SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
197dd7cddfSDavid du Colombier WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
207dd7cddfSDavid du Colombier IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
217dd7cddfSDavid du Colombier ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
227dd7cddfSDavid du Colombier THIS SOFTWARE.
237dd7cddfSDavid du Colombier ****************************************************************/
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier #define DEBUG
263e12c5d1SDavid du Colombier #include <stdio.h>
273e12c5d1SDavid du Colombier #include <string.h>
283e12c5d1SDavid du Colombier #include <ctype.h>
293e12c5d1SDavid du Colombier #include <errno.h>
303e12c5d1SDavid du Colombier #include <stdlib.h>
317dd7cddfSDavid du Colombier #include <stdarg.h>
323e12c5d1SDavid du Colombier #include "awk.h"
333e12c5d1SDavid du Colombier #include "y.tab.h"
343e12c5d1SDavid du Colombier 
353e12c5d1SDavid du Colombier FILE	*infile	= NULL;
367dd7cddfSDavid du Colombier char	*file	= "";
377dd7cddfSDavid du Colombier char	*record;
38219b2ee8SDavid du Colombier int	recsize	= RECSIZE;
397dd7cddfSDavid du Colombier char	*fields;
407dd7cddfSDavid du Colombier int	fieldssize = RECSIZE;
417dd7cddfSDavid du Colombier 
427dd7cddfSDavid du Colombier Cell	**fldtab;	/* pointers to Cells */
437dd7cddfSDavid du Colombier char	inputFS[100] = " ";
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier #define	MAXFLD	200
467dd7cddfSDavid du Colombier int	nfields	= MAXFLD;	/* last allocated slot for $i */
47219b2ee8SDavid du Colombier 
483e12c5d1SDavid du Colombier int	donefld;	/* 1 = implies rec broken into fields */
493e12c5d1SDavid du Colombier int	donerec;	/* 1 = record is valid (no flds have changed) */
503e12c5d1SDavid du Colombier 
517dd7cddfSDavid du Colombier int	lastfld	= 0;	/* last used field */
523e12c5d1SDavid du Colombier int	argno	= 1;	/* current input argument number */
533e12c5d1SDavid du Colombier extern	Awkfloat *ARGC;
543e12c5d1SDavid du Colombier 
557dd7cddfSDavid du Colombier static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
567dd7cddfSDavid du Colombier static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
577dd7cddfSDavid du Colombier 
recinit(unsigned int n)58219b2ee8SDavid du Colombier void recinit(unsigned int n)
59219b2ee8SDavid du Colombier {
607dd7cddfSDavid du Colombier 	record = (char *) malloc(n);
617dd7cddfSDavid du Colombier 	fields = (char *) malloc(n);
627dd7cddfSDavid du Colombier 	fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
637dd7cddfSDavid du Colombier 	if (record == NULL || fields == NULL || fldtab == NULL)
647dd7cddfSDavid du Colombier 		FATAL("out of space for $0 and fields");
657dd7cddfSDavid du Colombier 	fldtab[0] = (Cell *) malloc(sizeof (Cell));
667dd7cddfSDavid du Colombier 	*fldtab[0] = dollar0;
677dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
687dd7cddfSDavid du Colombier 	fldtab[0]->nval = tostring("0");
697dd7cddfSDavid du Colombier 	makefields(1, nfields);
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier 
makefields(int n1,int n2)727dd7cddfSDavid du Colombier void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier 	char temp[50];
75219b2ee8SDavid du Colombier 	int i;
76219b2ee8SDavid du Colombier 
777dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
787dd7cddfSDavid du Colombier 		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
797dd7cddfSDavid du Colombier 		if (fldtab[i] == NULL)
807dd7cddfSDavid du Colombier 			FATAL("out of space in makefields %d", i);
817dd7cddfSDavid du Colombier 		*fldtab[i] = dollar1;
827dd7cddfSDavid du Colombier 		sprintf(temp, "%d", i);
837dd7cddfSDavid du Colombier 		fldtab[i]->nval = tostring(temp);
847dd7cddfSDavid du Colombier 	}
85219b2ee8SDavid du Colombier }
86219b2ee8SDavid du Colombier 
initgetrec(void)873e12c5d1SDavid du Colombier void initgetrec(void)
883e12c5d1SDavid du Colombier {
893e12c5d1SDavid du Colombier 	int i;
907dd7cddfSDavid du Colombier 	char *p;
913e12c5d1SDavid du Colombier 
923e12c5d1SDavid du Colombier 	for (i = 1; i < *ARGC; i++) {
93219b2ee8SDavid du Colombier 		if (!isclvar(p = getargv(i))) {	/* find 1st real filename */
94219b2ee8SDavid du Colombier 			setsval(lookup("FILENAME", symtab), getargv(i));
953e12c5d1SDavid du Colombier 			return;
96219b2ee8SDavid du Colombier 		}
973e12c5d1SDavid du Colombier 		setclvar(p);	/* a commandline assignment before filename */
983e12c5d1SDavid du Colombier 		argno++;
993e12c5d1SDavid du Colombier 	}
1003e12c5d1SDavid du Colombier 	infile = stdin;		/* no filenames, so use stdin */
1013e12c5d1SDavid du Colombier }
1023e12c5d1SDavid du Colombier 
getrec(char ** pbuf,int * pbufsize,int isrecord)1037dd7cddfSDavid du Colombier int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
1047dd7cddfSDavid du Colombier {			/* note: cares whether buf == record */
1053e12c5d1SDavid du Colombier 	int c;
1063e12c5d1SDavid du Colombier 	static int firsttime = 1;
1077dd7cddfSDavid du Colombier 	char *buf = *pbuf;
1087dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier 	if (firsttime) {
1113e12c5d1SDavid du Colombier 		firsttime = 0;
1123e12c5d1SDavid du Colombier 		initgetrec();
1133e12c5d1SDavid du Colombier 	}
1143e12c5d1SDavid du Colombier 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
1153e12c5d1SDavid du Colombier 		*RS, *FS, *ARGC, *FILENAME) );
1167dd7cddfSDavid du Colombier 	if (isrecord) {
1173e12c5d1SDavid du Colombier 		donefld = 0;
1183e12c5d1SDavid du Colombier 		donerec = 1;
1197dd7cddfSDavid du Colombier 	}
1203e12c5d1SDavid du Colombier 	buf[0] = 0;
1213e12c5d1SDavid du Colombier 	while (argno < *ARGC || infile == stdin) {
1223e12c5d1SDavid du Colombier 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
1233e12c5d1SDavid du Colombier 		if (infile == NULL) {	/* have to open a new file */
1243e12c5d1SDavid du Colombier 			file = getargv(argno);
1253e12c5d1SDavid du Colombier 			if (*file == '\0') {	/* it's been zapped */
1263e12c5d1SDavid du Colombier 				argno++;
1273e12c5d1SDavid du Colombier 				continue;
1283e12c5d1SDavid du Colombier 			}
1293e12c5d1SDavid du Colombier 			if (isclvar(file)) {	/* a var=value arg */
1303e12c5d1SDavid du Colombier 				setclvar(file);
1313e12c5d1SDavid du Colombier 				argno++;
1323e12c5d1SDavid du Colombier 				continue;
1333e12c5d1SDavid du Colombier 			}
1343e12c5d1SDavid du Colombier 			*FILENAME = file;
1353e12c5d1SDavid du Colombier 			   dprintf( ("opening file %s\n", file) );
1363e12c5d1SDavid du Colombier 			if (*file == '-' && *(file+1) == '\0')
1373e12c5d1SDavid du Colombier 				infile = stdin;
1387dd7cddfSDavid du Colombier 			else if ((infile = fopen(file, "r")) == NULL)
1397dd7cddfSDavid du Colombier 				FATAL("can't open file %s", file);
1403e12c5d1SDavid du Colombier 			setfval(fnrloc, 0.0);
1413e12c5d1SDavid du Colombier 		}
1427dd7cddfSDavid du Colombier 		c = readrec(&buf, &bufsize, infile);
1433e12c5d1SDavid du Colombier 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1447dd7cddfSDavid du Colombier 			if (isrecord) {
1457dd7cddfSDavid du Colombier 				if (freeable(fldtab[0]))
1467dd7cddfSDavid du Colombier 					xfree(fldtab[0]->sval);
1477dd7cddfSDavid du Colombier 				fldtab[0]->sval = buf;	/* buf == record */
1487dd7cddfSDavid du Colombier 				fldtab[0]->tval = REC | STR | DONTFREE;
1497dd7cddfSDavid du Colombier 				if (is_number(fldtab[0]->sval)) {
1507dd7cddfSDavid du Colombier 					fldtab[0]->fval = atof(fldtab[0]->sval);
1517dd7cddfSDavid du Colombier 					fldtab[0]->tval |= NUM;
1523e12c5d1SDavid du Colombier 				}
1533e12c5d1SDavid du Colombier 			}
1543e12c5d1SDavid du Colombier 			setfval(nrloc, nrloc->fval+1);
1553e12c5d1SDavid du Colombier 			setfval(fnrloc, fnrloc->fval+1);
1567dd7cddfSDavid du Colombier 			*pbuf = buf;
1577dd7cddfSDavid du Colombier 			*pbufsize = bufsize;
1583e12c5d1SDavid du Colombier 			return 1;
1593e12c5d1SDavid du Colombier 		}
1603e12c5d1SDavid du Colombier 		/* EOF arrived on this file; set up next */
1613e12c5d1SDavid du Colombier 		if (infile != stdin)
1623e12c5d1SDavid du Colombier 			fclose(infile);
1633e12c5d1SDavid du Colombier 		infile = NULL;
1643e12c5d1SDavid du Colombier 		argno++;
1653e12c5d1SDavid du Colombier 	}
1667dd7cddfSDavid du Colombier 	*pbuf = buf;
1677dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
1683e12c5d1SDavid du Colombier 	return 0;	/* true end of file */
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier 
nextfile(void)1717dd7cddfSDavid du Colombier void nextfile(void)
1723e12c5d1SDavid du Colombier {
1737dd7cddfSDavid du Colombier 	if (infile != stdin)
1747dd7cddfSDavid du Colombier 		fclose(infile);
1757dd7cddfSDavid du Colombier 	infile = NULL;
1767dd7cddfSDavid du Colombier 	argno++;
1777dd7cddfSDavid du Colombier }
1783e12c5d1SDavid du Colombier 
readrec(char ** pbuf,int * pbufsize,FILE * inf)1797dd7cddfSDavid du Colombier int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
1807dd7cddfSDavid du Colombier {
1817dd7cddfSDavid du Colombier 	int sep, c;
1827dd7cddfSDavid du Colombier 	char *rr, *buf = *pbuf;
1837dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	if (strlen(*FS) >= sizeof(inputFS))
1867dd7cddfSDavid du Colombier 		FATAL("field separator %.10s... is too long", *FS);
1877dd7cddfSDavid du Colombier 	strcpy(inputFS, *FS);	/* for subsequent field splitting */
1883e12c5d1SDavid du Colombier 	if ((sep = **RS) == 0) {
1893e12c5d1SDavid du Colombier 		sep = '\n';
1903e12c5d1SDavid du Colombier 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
1913e12c5d1SDavid du Colombier 			;
1923e12c5d1SDavid du Colombier 		if (c != EOF)
1933e12c5d1SDavid du Colombier 			ungetc(c, inf);
1943e12c5d1SDavid du Colombier 	}
1957dd7cddfSDavid du Colombier 	for (rr = buf; ; ) {
1967dd7cddfSDavid du Colombier 		for (; (c=getc(inf)) != sep && c != EOF; ) {
1977dd7cddfSDavid du Colombier 			if (rr-buf+1 > bufsize)
1987dd7cddfSDavid du Colombier 				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
1997dd7cddfSDavid du Colombier 					FATAL("input record `%.30s...' too long", buf);
2007dd7cddfSDavid du Colombier 			*rr++ = c;
2017dd7cddfSDavid du Colombier 		}
2023e12c5d1SDavid du Colombier 		if (**RS == sep || c == EOF)
2033e12c5d1SDavid du Colombier 			break;
2043e12c5d1SDavid du Colombier 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
2053e12c5d1SDavid du Colombier 			break;
2067dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
2077dd7cddfSDavid du Colombier 			FATAL("input record `%.30s...' too long", buf);
2083e12c5d1SDavid du Colombier 		*rr++ = '\n';
2093e12c5d1SDavid du Colombier 		*rr++ = c;
2103e12c5d1SDavid du Colombier 	}
2117dd7cddfSDavid du Colombier 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2127dd7cddfSDavid du Colombier 		FATAL("input record `%.30s...' too long", buf);
2133e12c5d1SDavid du Colombier 	*rr = 0;
2143e12c5d1SDavid du Colombier 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
2157dd7cddfSDavid du Colombier 	*pbuf = buf;
2167dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
2173e12c5d1SDavid du Colombier 	return c == EOF && rr == buf ? 0 : 1;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier 
getargv(int n)2207dd7cddfSDavid du Colombier char *getargv(int n)	/* get ARGV[n] */
2213e12c5d1SDavid du Colombier {
2223e12c5d1SDavid du Colombier 	Cell *x;
2237dd7cddfSDavid du Colombier 	char *s, temp[50];
2243e12c5d1SDavid du Colombier 	extern Array *ARGVtab;
2253e12c5d1SDavid du Colombier 
2267dd7cddfSDavid du Colombier 	sprintf(temp, "%d", n);
2273e12c5d1SDavid du Colombier 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
2283e12c5d1SDavid du Colombier 	s = getsval(x);
2293e12c5d1SDavid du Colombier 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
2303e12c5d1SDavid du Colombier 	return s;
2313e12c5d1SDavid du Colombier }
2323e12c5d1SDavid du Colombier 
setclvar(char * s)2337dd7cddfSDavid du Colombier void setclvar(char *s)	/* set var=value from s */
2343e12c5d1SDavid du Colombier {
2357dd7cddfSDavid du Colombier 	char *p;
2363e12c5d1SDavid du Colombier 	Cell *q;
2373e12c5d1SDavid du Colombier 
2383e12c5d1SDavid du Colombier 	for (p=s; *p != '='; p++)
2393e12c5d1SDavid du Colombier 		;
2403e12c5d1SDavid du Colombier 	*p++ = 0;
2413e12c5d1SDavid du Colombier 	p = qstring(p, '\0');
2423e12c5d1SDavid du Colombier 	q = setsymtab(s, p, 0.0, STR, symtab);
2433e12c5d1SDavid du Colombier 	setsval(q, p);
2447dd7cddfSDavid du Colombier 	if (is_number(q->sval)) {
2453e12c5d1SDavid du Colombier 		q->fval = atof(q->sval);
2463e12c5d1SDavid du Colombier 		q->tval |= NUM;
2473e12c5d1SDavid du Colombier 	}
2483e12c5d1SDavid du Colombier 	   dprintf( ("command line set %s to |%s|\n", s, p) );
2493e12c5d1SDavid du Colombier }
2503e12c5d1SDavid du Colombier 
2513e12c5d1SDavid du Colombier 
fldbld(void)252219b2ee8SDavid du Colombier void fldbld(void)	/* create fields from current record */
2533e12c5d1SDavid du Colombier {
2547dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
2557dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
2567dd7cddfSDavid du Colombier 	char *r, *fr, sep;
2573e12c5d1SDavid du Colombier 	Cell *p;
2587dd7cddfSDavid du Colombier 	int i, j, n;
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 	if (donefld)
2613e12c5d1SDavid du Colombier 		return;
2627dd7cddfSDavid du Colombier 	if (!isstr(fldtab[0]))
2637dd7cddfSDavid du Colombier 		getsval(fldtab[0]);
2647dd7cddfSDavid du Colombier 	r = fldtab[0]->sval;
2657dd7cddfSDavid du Colombier 	n = strlen(r);
2667dd7cddfSDavid du Colombier 	if (n > fieldssize) {
2677dd7cddfSDavid du Colombier 		xfree(fields);
2687dd7cddfSDavid du Colombier 		if ((fields = (char *) malloc(n+1)) == NULL)
2697dd7cddfSDavid du Colombier 			FATAL("out of space for fields in fldbld %d", n);
2707dd7cddfSDavid du Colombier 		fieldssize = n;
2717dd7cddfSDavid du Colombier 	}
2723e12c5d1SDavid du Colombier 	fr = fields;
2733e12c5d1SDavid du Colombier 	i = 0;	/* number of fields accumulated here */
2747dd7cddfSDavid du Colombier 	if (strlen(inputFS) > 1) {	/* it's a regular expression */
2757dd7cddfSDavid du Colombier 		i = refldbld(r, inputFS);
2767dd7cddfSDavid du Colombier 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
2773e12c5d1SDavid du Colombier 		for (i = 0; ; ) {
2783e12c5d1SDavid du Colombier 			while (*r == ' ' || *r == '\t' || *r == '\n')
2793e12c5d1SDavid du Colombier 				r++;
2803e12c5d1SDavid du Colombier 			if (*r == 0)
2813e12c5d1SDavid du Colombier 				break;
2823e12c5d1SDavid du Colombier 			i++;
2837dd7cddfSDavid du Colombier 			if (i > nfields)
2847dd7cddfSDavid du Colombier 				growfldtab(i);
2857dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
2867dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
2877dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
2887dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR | DONTFREE;
2893e12c5d1SDavid du Colombier 			do
2903e12c5d1SDavid du Colombier 				*fr++ = *r++;
2913e12c5d1SDavid du Colombier 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
2923e12c5d1SDavid du Colombier 			*fr++ = 0;
2933e12c5d1SDavid du Colombier 		}
2943e12c5d1SDavid du Colombier 		*fr = 0;
2957dd7cddfSDavid du Colombier 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
2967dd7cddfSDavid du Colombier 		for (i = 0; *r != 0; r++) {
2977dd7cddfSDavid du Colombier 			char buf[2];
2987dd7cddfSDavid du Colombier 			i++;
2997dd7cddfSDavid du Colombier 			if (i > nfields)
3007dd7cddfSDavid du Colombier 				growfldtab(i);
3017dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
3027dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
3037dd7cddfSDavid du Colombier 			buf[0] = *r;
3047dd7cddfSDavid du Colombier 			buf[1] = 0;
3057dd7cddfSDavid du Colombier 			fldtab[i]->sval = tostring(buf);
3067dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR;
3077dd7cddfSDavid du Colombier 		}
3087dd7cddfSDavid du Colombier 		*fr = 0;
3093e12c5d1SDavid du Colombier 	} else if (*r != 0) {	/* if 0, it's a null field */
3103e12c5d1SDavid du Colombier 		for (;;) {
3113e12c5d1SDavid du Colombier 			i++;
3127dd7cddfSDavid du Colombier 			if (i > nfields)
3137dd7cddfSDavid du Colombier 				growfldtab(i);
3147dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
3157dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
3167dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
3177dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR | DONTFREE;
318219b2ee8SDavid du Colombier 			while (*r != sep && *r != '\n' && *r != '\0')	/* \n is always a separator */
3193e12c5d1SDavid du Colombier 				*fr++ = *r++;
3203e12c5d1SDavid du Colombier 			*fr++ = 0;
3213e12c5d1SDavid du Colombier 			if (*r++ == 0)
3223e12c5d1SDavid du Colombier 				break;
3233e12c5d1SDavid du Colombier 		}
3243e12c5d1SDavid du Colombier 		*fr = 0;
3253e12c5d1SDavid du Colombier 	}
3267dd7cddfSDavid du Colombier 	if (i > nfields)
3277dd7cddfSDavid du Colombier 		FATAL("record `%.30s...' has too many fields; can't happen", r);
3287dd7cddfSDavid du Colombier 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
3297dd7cddfSDavid du Colombier 	lastfld = i;
3303e12c5d1SDavid du Colombier 	donefld = 1;
3317dd7cddfSDavid du Colombier 	for (j = 1; j <= lastfld; j++) {
3327dd7cddfSDavid du Colombier 		p = fldtab[j];
3337dd7cddfSDavid du Colombier 		if(is_number(p->sval)) {
3343e12c5d1SDavid du Colombier 			p->fval = atof(p->sval);
3353e12c5d1SDavid du Colombier 			p->tval |= NUM;
3363e12c5d1SDavid du Colombier 		}
3373e12c5d1SDavid du Colombier 	}
3387dd7cddfSDavid du Colombier 	setfval(nfloc, (Awkfloat) lastfld);
3397dd7cddfSDavid du Colombier 	if (dbg) {
3407dd7cddfSDavid du Colombier 		for (j = 0; j <= lastfld; j++) {
3417dd7cddfSDavid du Colombier 			p = fldtab[j];
3427dd7cddfSDavid du Colombier 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
3437dd7cddfSDavid du Colombier 		}
3447dd7cddfSDavid du Colombier 	}
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier 
cleanfld(int n1,int n2)3473e12c5d1SDavid du Colombier void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
3487dd7cddfSDavid du Colombier {				/* nvals remain intact */
3497dd7cddfSDavid du Colombier 	Cell *p;
3507dd7cddfSDavid du Colombier 	int i;
3513e12c5d1SDavid du Colombier 
3527dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
3537dd7cddfSDavid du Colombier 		p = fldtab[i];
3547dd7cddfSDavid du Colombier 		if (freeable(p))
3553e12c5d1SDavid du Colombier 			xfree(p->sval);
3567dd7cddfSDavid du Colombier 		p->sval = "";
3573e12c5d1SDavid du Colombier 		p->tval = FLD | STR | DONTFREE;
3583e12c5d1SDavid du Colombier 	}
3593e12c5d1SDavid du Colombier }
3603e12c5d1SDavid du Colombier 
newfld(int n)3617dd7cddfSDavid du Colombier void newfld(int n)	/* add field n after end of existing lastfld */
3623e12c5d1SDavid du Colombier {
3637dd7cddfSDavid du Colombier 	if (n > nfields)
3647dd7cddfSDavid du Colombier 		growfldtab(n);
3657dd7cddfSDavid du Colombier 	cleanfld(lastfld+1, n);
3667dd7cddfSDavid du Colombier 	lastfld = n;
3673e12c5d1SDavid du Colombier 	setfval(nfloc, (Awkfloat) n);
3683e12c5d1SDavid du Colombier }
3693e12c5d1SDavid du Colombier 
fieldadr(int n)3707dd7cddfSDavid du Colombier Cell *fieldadr(int n)	/* get nth field */
3713e12c5d1SDavid du Colombier {
3727dd7cddfSDavid du Colombier 	if (n < 0)
3737dd7cddfSDavid du Colombier 		FATAL("trying to access field %d", n);
3747dd7cddfSDavid du Colombier 	if (n > nfields)	/* fields after NF are empty */
3757dd7cddfSDavid du Colombier 		growfldtab(n);	/* but does not increase NF */
3767dd7cddfSDavid du Colombier 	return(fldtab[n]);
3777dd7cddfSDavid du Colombier }
3783e12c5d1SDavid du Colombier 
growfldtab(int n)3797dd7cddfSDavid du Colombier void growfldtab(int n)	/* make new fields up to at least $n */
3807dd7cddfSDavid du Colombier {
3817dd7cddfSDavid du Colombier 	int nf = 2 * nfields;
3827dd7cddfSDavid du Colombier 
3837dd7cddfSDavid du Colombier 	if (n > nf)
3847dd7cddfSDavid du Colombier 		nf = n;
3857dd7cddfSDavid du Colombier 	fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
3867dd7cddfSDavid du Colombier 	if (fldtab == NULL)
3877dd7cddfSDavid du Colombier 		FATAL("out of space creating %d fields", nf);
3887dd7cddfSDavid du Colombier 	makefields(nfields+1, nf);
3897dd7cddfSDavid du Colombier 	nfields = nf;
3907dd7cddfSDavid du Colombier }
3917dd7cddfSDavid du Colombier 
refldbld(char * rec,char * fs)3927dd7cddfSDavid du Colombier int refldbld(char *rec, char *fs)	/* build fields from reg expr in FS */
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
3957dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
3967dd7cddfSDavid du Colombier 	char *fr;
3977dd7cddfSDavid du Colombier 	void *p;
3987dd7cddfSDavid du Colombier 	int i, tempstat, n;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier 	n = strlen(rec);
4017dd7cddfSDavid du Colombier 	if (n > fieldssize) {
4027dd7cddfSDavid du Colombier 		xfree(fields);
4037dd7cddfSDavid du Colombier 		if ((fields = (char *) malloc(n+1)) == NULL)
4047dd7cddfSDavid du Colombier 			FATAL("out of space for fields in refldbld %d", n);
4057dd7cddfSDavid du Colombier 		fieldssize = n;
4067dd7cddfSDavid du Colombier 	}
4073e12c5d1SDavid du Colombier 	fr = fields;
4083e12c5d1SDavid du Colombier 	*fr = '\0';
4093e12c5d1SDavid du Colombier 	if (*rec == '\0')
4103e12c5d1SDavid du Colombier 		return 0;
4113e12c5d1SDavid du Colombier 	p = compre(fs);
4123e12c5d1SDavid du Colombier 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
4137dd7cddfSDavid du Colombier 	for (i = 1; ; i++) {
4147dd7cddfSDavid du Colombier 		if (i > nfields)
4157dd7cddfSDavid du Colombier 			growfldtab(i);
4167dd7cddfSDavid du Colombier 		if (freeable(fldtab[i]))
4177dd7cddfSDavid du Colombier 			xfree(fldtab[i]->sval);
4187dd7cddfSDavid du Colombier 		fldtab[i]->tval = FLD | STR | DONTFREE;
4197dd7cddfSDavid du Colombier 		fldtab[i]->sval = fr;
4203e12c5d1SDavid du Colombier 		   dprintf( ("refldbld: i=%d\n", i) );
4213e12c5d1SDavid du Colombier 		if (nematch(p, rec, rec)) {
4223e12c5d1SDavid du Colombier 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
4233e12c5d1SDavid du Colombier 			strncpy(fr, rec, patbeg-rec);
4243e12c5d1SDavid du Colombier 			fr += patbeg - rec + 1;
4253e12c5d1SDavid du Colombier 			*(fr-1) = '\0';
4263e12c5d1SDavid du Colombier 			rec = patbeg + patlen;
4273e12c5d1SDavid du Colombier 		} else {
4283e12c5d1SDavid du Colombier 			   dprintf( ("no match %s\n", rec) );
4293e12c5d1SDavid du Colombier 			strcpy(fr, rec);
4303e12c5d1SDavid du Colombier 			break;
4313e12c5d1SDavid du Colombier 		}
4323e12c5d1SDavid du Colombier 	}
4333e12c5d1SDavid du Colombier 	return i;
4343e12c5d1SDavid du Colombier }
4353e12c5d1SDavid du Colombier 
recbld(void)436219b2ee8SDavid du Colombier void recbld(void)	/* create $0 from $1..$NF if necessary */
4373e12c5d1SDavid du Colombier {
4387dd7cddfSDavid du Colombier 	int i;
4397dd7cddfSDavid du Colombier 	char *r, *p;
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	if (donerec == 1)
4423e12c5d1SDavid du Colombier 		return;
4437dd7cddfSDavid du Colombier 	r = record;
4443e12c5d1SDavid du Colombier 	for (i = 1; i <= *NF; i++) {
4457dd7cddfSDavid du Colombier 		p = getsval(fldtab[i]);
4467dd7cddfSDavid du Colombier 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
4477dd7cddfSDavid du Colombier 			FATAL("created $0 `%.30s...' too long", record);
4487dd7cddfSDavid du Colombier 		while ((*r = *p++) != 0)
4493e12c5d1SDavid du Colombier 			r++;
4507dd7cddfSDavid du Colombier 		if (i < *NF) {
4517dd7cddfSDavid du Colombier 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
4527dd7cddfSDavid du Colombier 				FATAL("created $0 `%.30s...' too long", record);
4537dd7cddfSDavid du Colombier 			for (p = *OFS; (*r = *p++) != 0; )
4543e12c5d1SDavid du Colombier 				r++;
4553e12c5d1SDavid du Colombier 		}
4567dd7cddfSDavid du Colombier 	}
4577dd7cddfSDavid du Colombier 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
4587dd7cddfSDavid du Colombier 		FATAL("built giant record `%.30s...'", record);
4593e12c5d1SDavid du Colombier 	*r = '\0';
4607dd7cddfSDavid du Colombier 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
4617dd7cddfSDavid du Colombier 
4627dd7cddfSDavid du Colombier 	if (freeable(fldtab[0]))
4637dd7cddfSDavid du Colombier 		xfree(fldtab[0]->sval);
4647dd7cddfSDavid du Colombier 	fldtab[0]->tval = REC | STR | DONTFREE;
4657dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
4667dd7cddfSDavid du Colombier 
4677dd7cddfSDavid du Colombier 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
4683e12c5d1SDavid du Colombier 	   dprintf( ("recbld = |%s|\n", record) );
4693e12c5d1SDavid du Colombier 	donerec = 1;
4703e12c5d1SDavid du Colombier }
4713e12c5d1SDavid du Colombier 
4727dd7cddfSDavid du Colombier int	errorflag	= 0;
4737dd7cddfSDavid du Colombier 
yyerror(char * s)4747dd7cddfSDavid du Colombier void yyerror(char *s)
4753e12c5d1SDavid du Colombier {
4767dd7cddfSDavid du Colombier 	SYNTAX(s);
4773e12c5d1SDavid du Colombier }
4783e12c5d1SDavid du Colombier 
SYNTAX(char * fmt,...)4797dd7cddfSDavid du Colombier void SYNTAX(char *fmt, ...)
4803e12c5d1SDavid du Colombier {
4817dd7cddfSDavid du Colombier 	extern char *cmdname, *curfname;
4823e12c5d1SDavid du Colombier 	static int been_here = 0;
4837dd7cddfSDavid du Colombier 	va_list varg;
4843e12c5d1SDavid du Colombier 
4853e12c5d1SDavid du Colombier 	if (been_here++ > 2)
4863e12c5d1SDavid du Colombier 		return;
4877dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
4887dd7cddfSDavid du Colombier 	va_start(varg, fmt);
4897dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
4907dd7cddfSDavid du Colombier 	va_end(varg);
4917dd7cddfSDavid du Colombier 	if(compile_time == 1 && cursource() != NULL)
4927dd7cddfSDavid du Colombier 		fprintf(stderr, " at %s:%d", cursource(), lineno);
4937dd7cddfSDavid du Colombier 	else
4947dd7cddfSDavid du Colombier 		fprintf(stderr, " at line %d", lineno);
4953e12c5d1SDavid du Colombier 	if (curfname != NULL)
4963e12c5d1SDavid du Colombier 		fprintf(stderr, " in function %s", curfname);
4973e12c5d1SDavid du Colombier 	fprintf(stderr, "\n");
4983e12c5d1SDavid du Colombier 	errorflag = 2;
4993e12c5d1SDavid du Colombier 	eprint();
5003e12c5d1SDavid du Colombier }
5013e12c5d1SDavid du Colombier 
fpecatch(int n)5023e12c5d1SDavid du Colombier void fpecatch(int n)
5033e12c5d1SDavid du Colombier {
5047dd7cddfSDavid du Colombier 	FATAL("floating point exception %d", n);
5053e12c5d1SDavid du Colombier }
5063e12c5d1SDavid du Colombier 
5073e12c5d1SDavid du Colombier extern int bracecnt, brackcnt, parencnt;
5083e12c5d1SDavid du Colombier 
bracecheck(void)5093e12c5d1SDavid du Colombier void bracecheck(void)
5103e12c5d1SDavid du Colombier {
5113e12c5d1SDavid du Colombier 	int c;
5123e12c5d1SDavid du Colombier 	static int beenhere = 0;
5133e12c5d1SDavid du Colombier 
5143e12c5d1SDavid du Colombier 	if (beenhere++)
5153e12c5d1SDavid du Colombier 		return;
5163e12c5d1SDavid du Colombier 	while ((c = input()) != EOF && c != '\0')
5173e12c5d1SDavid du Colombier 		bclass(c);
5183e12c5d1SDavid du Colombier 	bcheck2(bracecnt, '{', '}');
5193e12c5d1SDavid du Colombier 	bcheck2(brackcnt, '[', ']');
5203e12c5d1SDavid du Colombier 	bcheck2(parencnt, '(', ')');
5213e12c5d1SDavid du Colombier }
5223e12c5d1SDavid du Colombier 
bcheck2(int n,int c1,int c2)5233e12c5d1SDavid du Colombier void bcheck2(int n, int c1, int c2)
5243e12c5d1SDavid du Colombier {
5253e12c5d1SDavid du Colombier 	if (n == 1)
5263e12c5d1SDavid du Colombier 		fprintf(stderr, "\tmissing %c\n", c2);
5273e12c5d1SDavid du Colombier 	else if (n > 1)
5283e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
5293e12c5d1SDavid du Colombier 	else if (n == -1)
5303e12c5d1SDavid du Colombier 		fprintf(stderr, "\textra %c\n", c2);
5313e12c5d1SDavid du Colombier 	else if (n < -1)
5323e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
5333e12c5d1SDavid du Colombier }
5343e12c5d1SDavid du Colombier 
FATAL(char * fmt,...)5357dd7cddfSDavid du Colombier void FATAL(char *fmt, ...)
5363e12c5d1SDavid du Colombier {
5377dd7cddfSDavid du Colombier 	extern char *cmdname;
5387dd7cddfSDavid du Colombier 	va_list varg;
5393e12c5d1SDavid du Colombier 
5403e12c5d1SDavid du Colombier 	fflush(stdout);
5413e12c5d1SDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
5427dd7cddfSDavid du Colombier 	va_start(varg, fmt);
5437dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
5447dd7cddfSDavid du Colombier 	va_end(varg);
5457dd7cddfSDavid du Colombier 	error();
546219b2ee8SDavid du Colombier 	if (dbg > 1)		/* core dump if serious debugging on */
5473e12c5d1SDavid du Colombier 		abort();
5483e12c5d1SDavid du Colombier 	exit(2);
5493e12c5d1SDavid du Colombier }
5507dd7cddfSDavid du Colombier 
WARNING(char * fmt,...)5517dd7cddfSDavid du Colombier void WARNING(char *fmt, ...)
5527dd7cddfSDavid du Colombier {
5537dd7cddfSDavid du Colombier 	extern char *cmdname;
5547dd7cddfSDavid du Colombier 	va_list varg;
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier 	fflush(stdout);
5577dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
5587dd7cddfSDavid du Colombier 	va_start(varg, fmt);
5597dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
5607dd7cddfSDavid du Colombier 	va_end(varg);
5617dd7cddfSDavid du Colombier 	error();
5627dd7cddfSDavid du Colombier }
5637dd7cddfSDavid du Colombier 
error()5647dd7cddfSDavid du Colombier void error()
5657dd7cddfSDavid du Colombier {
5667dd7cddfSDavid du Colombier 	extern Node *curnode;
5677dd7cddfSDavid du Colombier 	int line;
5687dd7cddfSDavid du Colombier 
5697dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
5707dd7cddfSDavid du Colombier 	if (compile_time != 2 && NR && *NR > 0) {
5717dd7cddfSDavid du Colombier 		if (strcmp(*FILENAME, "-") != 0)
5727dd7cddfSDavid du Colombier 			fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
5737dd7cddfSDavid du Colombier 		else
5747dd7cddfSDavid du Colombier 			fprintf(stderr, " input record number %d", (int) (*FNR));
5757dd7cddfSDavid du Colombier 		fprintf(stderr, "\n");
5767dd7cddfSDavid du Colombier 	}
5777dd7cddfSDavid du Colombier 	if (compile_time != 2 && curnode)
5787dd7cddfSDavid du Colombier 		line = curnode->lineno;
5797dd7cddfSDavid du Colombier 	else if (compile_time != 2 && lineno)
5807dd7cddfSDavid du Colombier 		line = lineno;
5817dd7cddfSDavid du Colombier 	else
5827dd7cddfSDavid du Colombier 		line = -1;
5837dd7cddfSDavid du Colombier 	if (compile_time == 1 && cursource() != NULL){
5847dd7cddfSDavid du Colombier 		if(line >= 0)
5857dd7cddfSDavid du Colombier 			fprintf(stderr, " source %s:%d", cursource(), line);
5867dd7cddfSDavid du Colombier 		else
5877dd7cddfSDavid du Colombier 			fprintf(stderr, " source file %s", cursource());
5887dd7cddfSDavid du Colombier 	}else if(line >= 0)
5897dd7cddfSDavid du Colombier 		fprintf(stderr, " source line %d", line);
5907dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
5917dd7cddfSDavid du Colombier 	eprint();
5923e12c5d1SDavid du Colombier }
5933e12c5d1SDavid du Colombier 
eprint(void)5943e12c5d1SDavid du Colombier void eprint(void)	/* try to print context around error */
5953e12c5d1SDavid du Colombier {
5967dd7cddfSDavid du Colombier 	char *p, *q;
5973e12c5d1SDavid du Colombier 	int c;
5983e12c5d1SDavid du Colombier 	static int been_here = 0;
5997dd7cddfSDavid du Colombier 	extern char ebuf[], *ep;
6003e12c5d1SDavid du Colombier 
6013e12c5d1SDavid du Colombier 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
6023e12c5d1SDavid du Colombier 		return;
6033e12c5d1SDavid du Colombier 	p = ep - 1;
6043e12c5d1SDavid du Colombier 	if (p > ebuf && *p == '\n')
6053e12c5d1SDavid du Colombier 		p--;
6063e12c5d1SDavid du Colombier 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
6073e12c5d1SDavid du Colombier 		;
6083e12c5d1SDavid du Colombier 	while (*p == '\n')
6093e12c5d1SDavid du Colombier 		p++;
6103e12c5d1SDavid du Colombier 	fprintf(stderr, " context is\n\t");
6113e12c5d1SDavid du Colombier 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
6123e12c5d1SDavid du Colombier 		;
6133e12c5d1SDavid du Colombier 	for ( ; p < q; p++)
6143e12c5d1SDavid du Colombier 		if (*p)
6153e12c5d1SDavid du Colombier 			putc(*p, stderr);
6163e12c5d1SDavid du Colombier 	fprintf(stderr, " >>> ");
6173e12c5d1SDavid du Colombier 	for ( ; p < ep; p++)
6183e12c5d1SDavid du Colombier 		if (*p)
6193e12c5d1SDavid du Colombier 			putc(*p, stderr);
6203e12c5d1SDavid du Colombier 	fprintf(stderr, " <<< ");
6213e12c5d1SDavid du Colombier 	if (*ep)
6223e12c5d1SDavid du Colombier 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
6233e12c5d1SDavid du Colombier 			putc(c, stderr);
6243e12c5d1SDavid du Colombier 			bclass(c);
6253e12c5d1SDavid du Colombier 		}
6263e12c5d1SDavid du Colombier 	putc('\n', stderr);
6273e12c5d1SDavid du Colombier 	ep = ebuf;
6283e12c5d1SDavid du Colombier }
6293e12c5d1SDavid du Colombier 
bclass(int c)6303e12c5d1SDavid du Colombier void bclass(int c)
6313e12c5d1SDavid du Colombier {
6323e12c5d1SDavid du Colombier 	switch (c) {
6333e12c5d1SDavid du Colombier 	case '{': bracecnt++; break;
6343e12c5d1SDavid du Colombier 	case '}': bracecnt--; break;
6353e12c5d1SDavid du Colombier 	case '[': brackcnt++; break;
6363e12c5d1SDavid du Colombier 	case ']': brackcnt--; break;
6373e12c5d1SDavid du Colombier 	case '(': parencnt++; break;
6383e12c5d1SDavid du Colombier 	case ')': parencnt--; break;
6393e12c5d1SDavid du Colombier 	}
6403e12c5d1SDavid du Colombier }
6413e12c5d1SDavid du Colombier 
errcheck(double x,char * s)6427dd7cddfSDavid du Colombier double errcheck(double x, char *s)
6433e12c5d1SDavid du Colombier {
6443e12c5d1SDavid du Colombier 
6453e12c5d1SDavid du Colombier 	if (errno == EDOM) {
6463e12c5d1SDavid du Colombier 		errno = 0;
6477dd7cddfSDavid du Colombier 		WARNING("%s argument out of domain", s);
6483e12c5d1SDavid du Colombier 		x = 1;
6493e12c5d1SDavid du Colombier 	} else if (errno == ERANGE) {
6503e12c5d1SDavid du Colombier 		errno = 0;
6517dd7cddfSDavid du Colombier 		WARNING("%s result out of range", s);
6523e12c5d1SDavid du Colombier 		x = 1;
6533e12c5d1SDavid du Colombier 	}
6543e12c5d1SDavid du Colombier 	return x;
6553e12c5d1SDavid du Colombier }
6563e12c5d1SDavid du Colombier 
isclvar(char * s)6577dd7cddfSDavid du Colombier int isclvar(char *s)	/* is s of form var=something ? */
6583e12c5d1SDavid du Colombier {
6597dd7cddfSDavid du Colombier 	char *os = s;
6603e12c5d1SDavid du Colombier 
6613e12c5d1SDavid du Colombier 	if (!isalpha(*s) && *s != '_')
6623e12c5d1SDavid du Colombier 		return 0;
6633e12c5d1SDavid du Colombier 	for ( ; *s; s++)
6643e12c5d1SDavid du Colombier 		if (!(isalnum(*s) || *s == '_'))
6653e12c5d1SDavid du Colombier 			break;
6663e12c5d1SDavid du Colombier 	return *s == '=' && s > os && *(s+1) != '=';
6673e12c5d1SDavid du Colombier }
6683e12c5d1SDavid du Colombier 
6697dd7cddfSDavid du Colombier /* strtod is supposed to be a proper test of what's a valid number */
6703e12c5d1SDavid du Colombier 
6717dd7cddfSDavid du Colombier #include <math.h>
is_number(char * s)6727dd7cddfSDavid du Colombier int is_number(char *s)
6733e12c5d1SDavid du Colombier {
6747dd7cddfSDavid du Colombier 	double r;
6757dd7cddfSDavid du Colombier 	char *ep;
676*05bfb676SDavid du Colombier 
677*05bfb676SDavid du Colombier 	/*
678*05bfb676SDavid du Colombier 	 * fast could-it-be-a-number check before calling strtod,
679*05bfb676SDavid du Colombier 	 * which takes a surprisingly long time to reject non-numbers.
680*05bfb676SDavid du Colombier 	 */
681*05bfb676SDavid du Colombier 	switch (*s) {
682*05bfb676SDavid du Colombier 	case '0': case '1': case '2': case '3': case '4':
683*05bfb676SDavid du Colombier 	case '5': case '6': case '7': case '8': case '9':
684*05bfb676SDavid du Colombier 	case '\t':
685*05bfb676SDavid du Colombier 	case '\n':
686*05bfb676SDavid du Colombier 	case '\v':
687*05bfb676SDavid du Colombier 	case '\f':
688*05bfb676SDavid du Colombier 	case '\r':
689*05bfb676SDavid du Colombier 	case ' ':
690*05bfb676SDavid du Colombier 	case '-':
691*05bfb676SDavid du Colombier 	case '+':
692*05bfb676SDavid du Colombier 	case '.':
693*05bfb676SDavid du Colombier 	case 'n':		/* nans */
694*05bfb676SDavid du Colombier 	case 'N':
695*05bfb676SDavid du Colombier 	case 'i':		/* infs */
696*05bfb676SDavid du Colombier 	case 'I':
697*05bfb676SDavid du Colombier 		break;
698*05bfb676SDavid du Colombier 	default:
699*05bfb676SDavid du Colombier 		return 0;	/* can't be a number */
700*05bfb676SDavid du Colombier 	}
701*05bfb676SDavid du Colombier 
7027dd7cddfSDavid du Colombier 	errno = 0;
7037dd7cddfSDavid du Colombier 	r = strtod(s, &ep);
7047dd7cddfSDavid du Colombier 	if (ep == s || r == HUGE_VAL || errno == ERANGE)
7057dd7cddfSDavid du Colombier 		return 0;
7067dd7cddfSDavid du Colombier 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
7077dd7cddfSDavid du Colombier 		ep++;
7087dd7cddfSDavid du Colombier 	if (*ep == '\0')
7097dd7cddfSDavid du Colombier 		return 1;
7103e12c5d1SDavid du Colombier 	else
7117dd7cddfSDavid du Colombier 		return 0;
7123e12c5d1SDavid du Colombier }
713