xref: /plan9/sys/src/cmd/awk/lib.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier /****************************************************************
2*7dd7cddfSDavid du Colombier Copyright (C) Lucent Technologies 1997
33e12c5d1SDavid du Colombier All Rights Reserved
43e12c5d1SDavid du Colombier 
5*7dd7cddfSDavid du Colombier Permission to use, copy, modify, and distribute this software and
6*7dd7cddfSDavid du Colombier its documentation for any purpose and without fee is hereby
7*7dd7cddfSDavid du Colombier granted, provided that the above copyright notice appear in all
8*7dd7cddfSDavid du Colombier copies and that both that the copyright notice and this
9*7dd7cddfSDavid du Colombier permission notice and warranty disclaimer appear in supporting
10*7dd7cddfSDavid du Colombier documentation, and that the name Lucent Technologies or any of
11*7dd7cddfSDavid du Colombier its entities not be used in advertising or publicity pertaining
12*7dd7cddfSDavid du Colombier to distribution of the software without specific, written prior
13*7dd7cddfSDavid du Colombier permission.
143e12c5d1SDavid du Colombier 
15*7dd7cddfSDavid du Colombier LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*7dd7cddfSDavid du Colombier INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*7dd7cddfSDavid du Colombier IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*7dd7cddfSDavid du Colombier SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*7dd7cddfSDavid du Colombier WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*7dd7cddfSDavid du Colombier IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*7dd7cddfSDavid du Colombier ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*7dd7cddfSDavid du Colombier THIS SOFTWARE.
23*7dd7cddfSDavid 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>
31*7dd7cddfSDavid 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;
36*7dd7cddfSDavid du Colombier char	*file	= "";
37*7dd7cddfSDavid du Colombier char	*record;
38219b2ee8SDavid du Colombier int	recsize	= RECSIZE;
39*7dd7cddfSDavid du Colombier char	*fields;
40*7dd7cddfSDavid du Colombier int	fieldssize = RECSIZE;
41*7dd7cddfSDavid du Colombier 
42*7dd7cddfSDavid du Colombier Cell	**fldtab;	/* pointers to Cells */
43*7dd7cddfSDavid du Colombier char	inputFS[100] = " ";
443e12c5d1SDavid du Colombier 
453e12c5d1SDavid du Colombier #define	MAXFLD	200
46*7dd7cddfSDavid 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 
51*7dd7cddfSDavid 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 
55*7dd7cddfSDavid du Colombier static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
56*7dd7cddfSDavid du Colombier static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
57*7dd7cddfSDavid du Colombier 
58219b2ee8SDavid du Colombier void recinit(unsigned int n)
59219b2ee8SDavid du Colombier {
60*7dd7cddfSDavid du Colombier 	record = (char *) malloc(n);
61*7dd7cddfSDavid du Colombier 	fields = (char *) malloc(n);
62*7dd7cddfSDavid du Colombier 	fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *));
63*7dd7cddfSDavid du Colombier 	if (record == NULL || fields == NULL || fldtab == NULL)
64*7dd7cddfSDavid du Colombier 		FATAL("out of space for $0 and fields");
65*7dd7cddfSDavid du Colombier 	fldtab[0] = (Cell *) malloc(sizeof (Cell));
66*7dd7cddfSDavid du Colombier 	*fldtab[0] = dollar0;
67*7dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
68*7dd7cddfSDavid du Colombier 	fldtab[0]->nval = tostring("0");
69*7dd7cddfSDavid du Colombier 	makefields(1, nfields);
70*7dd7cddfSDavid du Colombier }
71*7dd7cddfSDavid du Colombier 
72*7dd7cddfSDavid du Colombier void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
73*7dd7cddfSDavid du Colombier {
74*7dd7cddfSDavid du Colombier 	char temp[50];
75219b2ee8SDavid du Colombier 	int i;
76219b2ee8SDavid du Colombier 
77*7dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
78*7dd7cddfSDavid du Colombier 		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
79*7dd7cddfSDavid du Colombier 		if (fldtab[i] == NULL)
80*7dd7cddfSDavid du Colombier 			FATAL("out of space in makefields %d", i);
81*7dd7cddfSDavid du Colombier 		*fldtab[i] = dollar1;
82*7dd7cddfSDavid du Colombier 		sprintf(temp, "%d", i);
83*7dd7cddfSDavid du Colombier 		fldtab[i]->nval = tostring(temp);
84*7dd7cddfSDavid du Colombier 	}
85219b2ee8SDavid du Colombier }
86219b2ee8SDavid du Colombier 
873e12c5d1SDavid du Colombier void initgetrec(void)
883e12c5d1SDavid du Colombier {
893e12c5d1SDavid du Colombier 	int i;
90*7dd7cddfSDavid 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 
103*7dd7cddfSDavid du Colombier int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
104*7dd7cddfSDavid du Colombier {			/* note: cares whether buf == record */
1053e12c5d1SDavid du Colombier 	int c;
1063e12c5d1SDavid du Colombier 	static int firsttime = 1;
107*7dd7cddfSDavid du Colombier 	char *buf = *pbuf;
108*7dd7cddfSDavid 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) );
116*7dd7cddfSDavid du Colombier 	if (isrecord) {
1173e12c5d1SDavid du Colombier 		donefld = 0;
1183e12c5d1SDavid du Colombier 		donerec = 1;
119*7dd7cddfSDavid 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;
138*7dd7cddfSDavid du Colombier 			else if ((infile = fopen(file, "r")) == NULL)
139*7dd7cddfSDavid du Colombier 				FATAL("can't open file %s", file);
1403e12c5d1SDavid du Colombier 			setfval(fnrloc, 0.0);
1413e12c5d1SDavid du Colombier 		}
142*7dd7cddfSDavid du Colombier 		c = readrec(&buf, &bufsize, infile);
1433e12c5d1SDavid du Colombier 		if (c != 0 || buf[0] != '\0') {	/* normal record */
144*7dd7cddfSDavid du Colombier 			if (isrecord) {
145*7dd7cddfSDavid du Colombier 				if (freeable(fldtab[0]))
146*7dd7cddfSDavid du Colombier 					xfree(fldtab[0]->sval);
147*7dd7cddfSDavid du Colombier 				fldtab[0]->sval = buf;	/* buf == record */
148*7dd7cddfSDavid du Colombier 				fldtab[0]->tval = REC | STR | DONTFREE;
149*7dd7cddfSDavid du Colombier 				if (is_number(fldtab[0]->sval)) {
150*7dd7cddfSDavid du Colombier 					fldtab[0]->fval = atof(fldtab[0]->sval);
151*7dd7cddfSDavid 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);
156*7dd7cddfSDavid du Colombier 			*pbuf = buf;
157*7dd7cddfSDavid 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 	}
166*7dd7cddfSDavid du Colombier 	*pbuf = buf;
167*7dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
1683e12c5d1SDavid du Colombier 	return 0;	/* true end of file */
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier 
171*7dd7cddfSDavid du Colombier void nextfile(void)
1723e12c5d1SDavid du Colombier {
173*7dd7cddfSDavid du Colombier 	if (infile != stdin)
174*7dd7cddfSDavid du Colombier 		fclose(infile);
175*7dd7cddfSDavid du Colombier 	infile = NULL;
176*7dd7cddfSDavid du Colombier 	argno++;
177*7dd7cddfSDavid du Colombier }
1783e12c5d1SDavid du Colombier 
179*7dd7cddfSDavid du Colombier int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
180*7dd7cddfSDavid du Colombier {
181*7dd7cddfSDavid du Colombier 	int sep, c;
182*7dd7cddfSDavid du Colombier 	char *rr, *buf = *pbuf;
183*7dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
184*7dd7cddfSDavid du Colombier 
185*7dd7cddfSDavid du Colombier 	if (strlen(*FS) >= sizeof(inputFS))
186*7dd7cddfSDavid du Colombier 		FATAL("field separator %.10s... is too long", *FS);
187*7dd7cddfSDavid 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 	}
195*7dd7cddfSDavid du Colombier 	for (rr = buf; ; ) {
196*7dd7cddfSDavid du Colombier 		for (; (c=getc(inf)) != sep && c != EOF; ) {
197*7dd7cddfSDavid du Colombier 			if (rr-buf+1 > bufsize)
198*7dd7cddfSDavid du Colombier 				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
199*7dd7cddfSDavid du Colombier 					FATAL("input record `%.30s...' too long", buf);
200*7dd7cddfSDavid du Colombier 			*rr++ = c;
201*7dd7cddfSDavid 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;
206*7dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
207*7dd7cddfSDavid du Colombier 			FATAL("input record `%.30s...' too long", buf);
2083e12c5d1SDavid du Colombier 		*rr++ = '\n';
2093e12c5d1SDavid du Colombier 		*rr++ = c;
2103e12c5d1SDavid du Colombier 	}
211*7dd7cddfSDavid du Colombier 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
212*7dd7cddfSDavid 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) );
215*7dd7cddfSDavid du Colombier 	*pbuf = buf;
216*7dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
2173e12c5d1SDavid du Colombier 	return c == EOF && rr == buf ? 0 : 1;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier 
220*7dd7cddfSDavid du Colombier char *getargv(int n)	/* get ARGV[n] */
2213e12c5d1SDavid du Colombier {
2223e12c5d1SDavid du Colombier 	Cell *x;
223*7dd7cddfSDavid du Colombier 	char *s, temp[50];
2243e12c5d1SDavid du Colombier 	extern Array *ARGVtab;
2253e12c5d1SDavid du Colombier 
226*7dd7cddfSDavid 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 
233*7dd7cddfSDavid du Colombier void setclvar(char *s)	/* set var=value from s */
2343e12c5d1SDavid du Colombier {
235*7dd7cddfSDavid 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);
244*7dd7cddfSDavid 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 
252219b2ee8SDavid du Colombier void fldbld(void)	/* create fields from current record */
2533e12c5d1SDavid du Colombier {
254*7dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
255*7dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
256*7dd7cddfSDavid du Colombier 	char *r, *fr, sep;
2573e12c5d1SDavid du Colombier 	Cell *p;
258*7dd7cddfSDavid du Colombier 	int i, j, n;
2593e12c5d1SDavid du Colombier 
2603e12c5d1SDavid du Colombier 	if (donefld)
2613e12c5d1SDavid du Colombier 		return;
262*7dd7cddfSDavid du Colombier 	if (!isstr(fldtab[0]))
263*7dd7cddfSDavid du Colombier 		getsval(fldtab[0]);
264*7dd7cddfSDavid du Colombier 	r = fldtab[0]->sval;
265*7dd7cddfSDavid du Colombier 	n = strlen(r);
266*7dd7cddfSDavid du Colombier 	if (n > fieldssize) {
267*7dd7cddfSDavid du Colombier 		xfree(fields);
268*7dd7cddfSDavid du Colombier 		if ((fields = (char *) malloc(n+1)) == NULL)
269*7dd7cddfSDavid du Colombier 			FATAL("out of space for fields in fldbld %d", n);
270*7dd7cddfSDavid du Colombier 		fieldssize = n;
271*7dd7cddfSDavid du Colombier 	}
2723e12c5d1SDavid du Colombier 	fr = fields;
2733e12c5d1SDavid du Colombier 	i = 0;	/* number of fields accumulated here */
274*7dd7cddfSDavid du Colombier 	if (strlen(inputFS) > 1) {	/* it's a regular expression */
275*7dd7cddfSDavid du Colombier 		i = refldbld(r, inputFS);
276*7dd7cddfSDavid 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++;
283*7dd7cddfSDavid du Colombier 			if (i > nfields)
284*7dd7cddfSDavid du Colombier 				growfldtab(i);
285*7dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
286*7dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
287*7dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
288*7dd7cddfSDavid 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;
295*7dd7cddfSDavid du Colombier 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
296*7dd7cddfSDavid du Colombier 		for (i = 0; *r != 0; r++) {
297*7dd7cddfSDavid du Colombier 			char buf[2];
298*7dd7cddfSDavid du Colombier 			i++;
299*7dd7cddfSDavid du Colombier 			if (i > nfields)
300*7dd7cddfSDavid du Colombier 				growfldtab(i);
301*7dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
302*7dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
303*7dd7cddfSDavid du Colombier 			buf[0] = *r;
304*7dd7cddfSDavid du Colombier 			buf[1] = 0;
305*7dd7cddfSDavid du Colombier 			fldtab[i]->sval = tostring(buf);
306*7dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR;
307*7dd7cddfSDavid du Colombier 		}
308*7dd7cddfSDavid 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++;
312*7dd7cddfSDavid du Colombier 			if (i > nfields)
313*7dd7cddfSDavid du Colombier 				growfldtab(i);
314*7dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
315*7dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
316*7dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
317*7dd7cddfSDavid 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 	}
326*7dd7cddfSDavid du Colombier 	if (i > nfields)
327*7dd7cddfSDavid du Colombier 		FATAL("record `%.30s...' has too many fields; can't happen", r);
328*7dd7cddfSDavid du Colombier 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
329*7dd7cddfSDavid du Colombier 	lastfld = i;
3303e12c5d1SDavid du Colombier 	donefld = 1;
331*7dd7cddfSDavid du Colombier 	for (j = 1; j <= lastfld; j++) {
332*7dd7cddfSDavid du Colombier 		p = fldtab[j];
333*7dd7cddfSDavid 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 	}
338*7dd7cddfSDavid du Colombier 	setfval(nfloc, (Awkfloat) lastfld);
339*7dd7cddfSDavid du Colombier 	if (dbg) {
340*7dd7cddfSDavid du Colombier 		for (j = 0; j <= lastfld; j++) {
341*7dd7cddfSDavid du Colombier 			p = fldtab[j];
342*7dd7cddfSDavid du Colombier 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
343*7dd7cddfSDavid du Colombier 		}
344*7dd7cddfSDavid du Colombier 	}
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier 
3473e12c5d1SDavid du Colombier void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
348*7dd7cddfSDavid du Colombier {				/* nvals remain intact */
349*7dd7cddfSDavid du Colombier 	Cell *p;
350*7dd7cddfSDavid du Colombier 	int i;
3513e12c5d1SDavid du Colombier 
352*7dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
353*7dd7cddfSDavid du Colombier 		p = fldtab[i];
354*7dd7cddfSDavid du Colombier 		if (freeable(p))
3553e12c5d1SDavid du Colombier 			xfree(p->sval);
356*7dd7cddfSDavid du Colombier 		p->sval = "";
3573e12c5d1SDavid du Colombier 		p->tval = FLD | STR | DONTFREE;
3583e12c5d1SDavid du Colombier 	}
3593e12c5d1SDavid du Colombier }
3603e12c5d1SDavid du Colombier 
361*7dd7cddfSDavid du Colombier void newfld(int n)	/* add field n after end of existing lastfld */
3623e12c5d1SDavid du Colombier {
363*7dd7cddfSDavid du Colombier 	if (n > nfields)
364*7dd7cddfSDavid du Colombier 		growfldtab(n);
365*7dd7cddfSDavid du Colombier 	cleanfld(lastfld+1, n);
366*7dd7cddfSDavid du Colombier 	lastfld = n;
3673e12c5d1SDavid du Colombier 	setfval(nfloc, (Awkfloat) n);
3683e12c5d1SDavid du Colombier }
3693e12c5d1SDavid du Colombier 
370*7dd7cddfSDavid du Colombier Cell *fieldadr(int n)	/* get nth field */
3713e12c5d1SDavid du Colombier {
372*7dd7cddfSDavid du Colombier 	if (n < 0)
373*7dd7cddfSDavid du Colombier 		FATAL("trying to access field %d", n);
374*7dd7cddfSDavid du Colombier 	if (n > nfields)	/* fields after NF are empty */
375*7dd7cddfSDavid du Colombier 		growfldtab(n);	/* but does not increase NF */
376*7dd7cddfSDavid du Colombier 	return(fldtab[n]);
377*7dd7cddfSDavid du Colombier }
3783e12c5d1SDavid du Colombier 
379*7dd7cddfSDavid du Colombier void growfldtab(int n)	/* make new fields up to at least $n */
380*7dd7cddfSDavid du Colombier {
381*7dd7cddfSDavid du Colombier 	int nf = 2 * nfields;
382*7dd7cddfSDavid du Colombier 
383*7dd7cddfSDavid du Colombier 	if (n > nf)
384*7dd7cddfSDavid du Colombier 		nf = n;
385*7dd7cddfSDavid du Colombier 	fldtab = (Cell **) realloc(fldtab, (nf+1) * (sizeof (struct Cell *)));
386*7dd7cddfSDavid du Colombier 	if (fldtab == NULL)
387*7dd7cddfSDavid du Colombier 		FATAL("out of space creating %d fields", nf);
388*7dd7cddfSDavid du Colombier 	makefields(nfields+1, nf);
389*7dd7cddfSDavid du Colombier 	nfields = nf;
390*7dd7cddfSDavid du Colombier }
391*7dd7cddfSDavid du Colombier 
392*7dd7cddfSDavid du Colombier int refldbld(char *rec, char *fs)	/* build fields from reg expr in FS */
393*7dd7cddfSDavid du Colombier {
394*7dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
395*7dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
396*7dd7cddfSDavid du Colombier 	char *fr;
397*7dd7cddfSDavid du Colombier 	void *p;
398*7dd7cddfSDavid du Colombier 	int i, tempstat, n;
399*7dd7cddfSDavid du Colombier 
400*7dd7cddfSDavid du Colombier 	n = strlen(rec);
401*7dd7cddfSDavid du Colombier 	if (n > fieldssize) {
402*7dd7cddfSDavid du Colombier 		xfree(fields);
403*7dd7cddfSDavid du Colombier 		if ((fields = (char *) malloc(n+1)) == NULL)
404*7dd7cddfSDavid du Colombier 			FATAL("out of space for fields in refldbld %d", n);
405*7dd7cddfSDavid du Colombier 		fieldssize = n;
406*7dd7cddfSDavid 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) );
413*7dd7cddfSDavid du Colombier 	for (i = 1; ; i++) {
414*7dd7cddfSDavid du Colombier 		if (i > nfields)
415*7dd7cddfSDavid du Colombier 			growfldtab(i);
416*7dd7cddfSDavid du Colombier 		if (freeable(fldtab[i]))
417*7dd7cddfSDavid du Colombier 			xfree(fldtab[i]->sval);
418*7dd7cddfSDavid du Colombier 		fldtab[i]->tval = FLD | STR | DONTFREE;
419*7dd7cddfSDavid 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 
436219b2ee8SDavid du Colombier void recbld(void)	/* create $0 from $1..$NF if necessary */
4373e12c5d1SDavid du Colombier {
438*7dd7cddfSDavid du Colombier 	int i;
439*7dd7cddfSDavid du Colombier 	char *r, *p;
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	if (donerec == 1)
4423e12c5d1SDavid du Colombier 		return;
443*7dd7cddfSDavid du Colombier 	r = record;
4443e12c5d1SDavid du Colombier 	for (i = 1; i <= *NF; i++) {
445*7dd7cddfSDavid du Colombier 		p = getsval(fldtab[i]);
446*7dd7cddfSDavid du Colombier 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
447*7dd7cddfSDavid du Colombier 			FATAL("created $0 `%.30s...' too long", record);
448*7dd7cddfSDavid du Colombier 		while ((*r = *p++) != 0)
4493e12c5d1SDavid du Colombier 			r++;
450*7dd7cddfSDavid du Colombier 		if (i < *NF) {
451*7dd7cddfSDavid du Colombier 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
452*7dd7cddfSDavid du Colombier 				FATAL("created $0 `%.30s...' too long", record);
453*7dd7cddfSDavid du Colombier 			for (p = *OFS; (*r = *p++) != 0; )
4543e12c5d1SDavid du Colombier 				r++;
4553e12c5d1SDavid du Colombier 		}
456*7dd7cddfSDavid du Colombier 	}
457*7dd7cddfSDavid du Colombier 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
458*7dd7cddfSDavid du Colombier 		FATAL("built giant record `%.30s...'", record);
4593e12c5d1SDavid du Colombier 	*r = '\0';
460*7dd7cddfSDavid du Colombier 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
461*7dd7cddfSDavid du Colombier 
462*7dd7cddfSDavid du Colombier 	if (freeable(fldtab[0]))
463*7dd7cddfSDavid du Colombier 		xfree(fldtab[0]->sval);
464*7dd7cddfSDavid du Colombier 	fldtab[0]->tval = REC | STR | DONTFREE;
465*7dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
466*7dd7cddfSDavid du Colombier 
467*7dd7cddfSDavid 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 
472*7dd7cddfSDavid du Colombier int	errorflag	= 0;
473*7dd7cddfSDavid du Colombier 
474*7dd7cddfSDavid du Colombier void yyerror(char *s)
4753e12c5d1SDavid du Colombier {
476*7dd7cddfSDavid du Colombier 	SYNTAX(s);
4773e12c5d1SDavid du Colombier }
4783e12c5d1SDavid du Colombier 
479*7dd7cddfSDavid du Colombier void SYNTAX(char *fmt, ...)
4803e12c5d1SDavid du Colombier {
481*7dd7cddfSDavid du Colombier 	extern char *cmdname, *curfname;
4823e12c5d1SDavid du Colombier 	static int been_here = 0;
483*7dd7cddfSDavid du Colombier 	va_list varg;
4843e12c5d1SDavid du Colombier 
4853e12c5d1SDavid du Colombier 	if (been_here++ > 2)
4863e12c5d1SDavid du Colombier 		return;
487*7dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
488*7dd7cddfSDavid du Colombier 	va_start(varg, fmt);
489*7dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
490*7dd7cddfSDavid du Colombier 	va_end(varg);
491*7dd7cddfSDavid du Colombier 	if(compile_time == 1 && cursource() != NULL)
492*7dd7cddfSDavid du Colombier 		fprintf(stderr, " at %s:%d", cursource(), lineno);
493*7dd7cddfSDavid du Colombier 	else
494*7dd7cddfSDavid 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 
5023e12c5d1SDavid du Colombier void fpecatch(int n)
5033e12c5d1SDavid du Colombier {
504*7dd7cddfSDavid 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 
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 
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 
535*7dd7cddfSDavid du Colombier void FATAL(char *fmt, ...)
5363e12c5d1SDavid du Colombier {
537*7dd7cddfSDavid du Colombier 	extern char *cmdname;
538*7dd7cddfSDavid du Colombier 	va_list varg;
5393e12c5d1SDavid du Colombier 
5403e12c5d1SDavid du Colombier 	fflush(stdout);
5413e12c5d1SDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
542*7dd7cddfSDavid du Colombier 	va_start(varg, fmt);
543*7dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
544*7dd7cddfSDavid du Colombier 	va_end(varg);
545*7dd7cddfSDavid 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 }
550*7dd7cddfSDavid du Colombier 
551*7dd7cddfSDavid du Colombier void WARNING(char *fmt, ...)
552*7dd7cddfSDavid du Colombier {
553*7dd7cddfSDavid du Colombier 	extern char *cmdname;
554*7dd7cddfSDavid du Colombier 	va_list varg;
555*7dd7cddfSDavid du Colombier 
556*7dd7cddfSDavid du Colombier 	fflush(stdout);
557*7dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
558*7dd7cddfSDavid du Colombier 	va_start(varg, fmt);
559*7dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
560*7dd7cddfSDavid du Colombier 	va_end(varg);
561*7dd7cddfSDavid du Colombier 	error();
562*7dd7cddfSDavid du Colombier }
563*7dd7cddfSDavid du Colombier 
564*7dd7cddfSDavid du Colombier void error()
565*7dd7cddfSDavid du Colombier {
566*7dd7cddfSDavid du Colombier 	extern Node *curnode;
567*7dd7cddfSDavid du Colombier 	int line;
568*7dd7cddfSDavid du Colombier 
569*7dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
570*7dd7cddfSDavid du Colombier 	if (compile_time != 2 && NR && *NR > 0) {
571*7dd7cddfSDavid du Colombier 		if (strcmp(*FILENAME, "-") != 0)
572*7dd7cddfSDavid du Colombier 			fprintf(stderr, " input record %s:%d", *FILENAME, (int) (*FNR));
573*7dd7cddfSDavid du Colombier 		else
574*7dd7cddfSDavid du Colombier 			fprintf(stderr, " input record number %d", (int) (*FNR));
575*7dd7cddfSDavid du Colombier 		fprintf(stderr, "\n");
576*7dd7cddfSDavid du Colombier 	}
577*7dd7cddfSDavid du Colombier 	if (compile_time != 2 && curnode)
578*7dd7cddfSDavid du Colombier 		line = curnode->lineno;
579*7dd7cddfSDavid du Colombier 	else if (compile_time != 2 && lineno)
580*7dd7cddfSDavid du Colombier 		line = lineno;
581*7dd7cddfSDavid du Colombier 	else
582*7dd7cddfSDavid du Colombier 		line = -1;
583*7dd7cddfSDavid du Colombier 	if (compile_time == 1 && cursource() != NULL){
584*7dd7cddfSDavid du Colombier 		if(line >= 0)
585*7dd7cddfSDavid du Colombier 			fprintf(stderr, " source %s:%d", cursource(), line);
586*7dd7cddfSDavid du Colombier 		else
587*7dd7cddfSDavid du Colombier 			fprintf(stderr, " source file %s", cursource());
588*7dd7cddfSDavid du Colombier 	}else if(line >= 0)
589*7dd7cddfSDavid du Colombier 		fprintf(stderr, " source line %d", line);
590*7dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
591*7dd7cddfSDavid du Colombier 	eprint();
5923e12c5d1SDavid du Colombier }
5933e12c5d1SDavid du Colombier 
5943e12c5d1SDavid du Colombier void eprint(void)	/* try to print context around error */
5953e12c5d1SDavid du Colombier {
596*7dd7cddfSDavid du Colombier 	char *p, *q;
5973e12c5d1SDavid du Colombier 	int c;
5983e12c5d1SDavid du Colombier 	static int been_here = 0;
599*7dd7cddfSDavid 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 
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 
642*7dd7cddfSDavid 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;
647*7dd7cddfSDavid 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;
651*7dd7cddfSDavid 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 
657*7dd7cddfSDavid du Colombier int isclvar(char *s)	/* is s of form var=something ? */
6583e12c5d1SDavid du Colombier {
659*7dd7cddfSDavid 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 
669*7dd7cddfSDavid du Colombier /* strtod is supposed to be a proper test of what's a valid number */
6703e12c5d1SDavid du Colombier 
671*7dd7cddfSDavid du Colombier #include <math.h>
672*7dd7cddfSDavid du Colombier int is_number(char *s)
6733e12c5d1SDavid du Colombier {
674*7dd7cddfSDavid du Colombier 	double r;
675*7dd7cddfSDavid du Colombier 	char *ep;
676*7dd7cddfSDavid du Colombier 	errno = 0;
677*7dd7cddfSDavid du Colombier 	r = strtod(s, &ep);
678*7dd7cddfSDavid du Colombier 	if (ep == s || r == HUGE_VAL || errno == ERANGE)
679*7dd7cddfSDavid du Colombier 		return 0;
680*7dd7cddfSDavid du Colombier 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
681*7dd7cddfSDavid du Colombier 		ep++;
682*7dd7cddfSDavid du Colombier 	if (*ep == '\0')
683*7dd7cddfSDavid du Colombier 		return 1;
6843e12c5d1SDavid du Colombier 	else
685*7dd7cddfSDavid du Colombier 		return 0;
6863e12c5d1SDavid du Colombier }
687