xref: /plan9-contrib/sys/src/cmd/awk/lib.c (revision a2c41696452f8a895ad2951a6355034fbc3034ed)
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 
45*a2c41696SDavid du Colombier #define	MAXFLD	2
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 {
60*a2c41696SDavid du Colombier 	if ( (record = (char *) malloc(n)) == NULL
61*a2c41696SDavid du Colombier 	  || (fields = (char *) malloc(n+1)) == NULL
62*a2c41696SDavid du Colombier 	  || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
63*a2c41696SDavid du Colombier 	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
647dd7cddfSDavid du Colombier 		FATAL("out of space for $0 and fields");
657dd7cddfSDavid du Colombier 	*fldtab[0] = dollar0;
667dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
677dd7cddfSDavid du Colombier 	fldtab[0]->nval = tostring("0");
687dd7cddfSDavid du Colombier 	makefields(1, nfields);
697dd7cddfSDavid du Colombier }
707dd7cddfSDavid du Colombier 
makefields(int n1,int n2)717dd7cddfSDavid du Colombier void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier 	char temp[50];
74219b2ee8SDavid du Colombier 	int i;
75219b2ee8SDavid du Colombier 
767dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
777dd7cddfSDavid du Colombier 		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
787dd7cddfSDavid du Colombier 		if (fldtab[i] == NULL)
797dd7cddfSDavid du Colombier 			FATAL("out of space in makefields %d", i);
807dd7cddfSDavid du Colombier 		*fldtab[i] = dollar1;
817dd7cddfSDavid du Colombier 		sprintf(temp, "%d", i);
827dd7cddfSDavid du Colombier 		fldtab[i]->nval = tostring(temp);
837dd7cddfSDavid du Colombier 	}
84219b2ee8SDavid du Colombier }
85219b2ee8SDavid du Colombier 
initgetrec(void)863e12c5d1SDavid du Colombier void initgetrec(void)
873e12c5d1SDavid du Colombier {
883e12c5d1SDavid du Colombier 	int i;
897dd7cddfSDavid du Colombier 	char *p;
903e12c5d1SDavid du Colombier 
913e12c5d1SDavid du Colombier 	for (i = 1; i < *ARGC; i++) {
92*a2c41696SDavid du Colombier 		p = getargv(i); /* find 1st real filename */
93*a2c41696SDavid du Colombier 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
94*a2c41696SDavid du Colombier 			argno++;
95*a2c41696SDavid du Colombier 			continue;
96*a2c41696SDavid du Colombier 		}
97*a2c41696SDavid du Colombier 		if (!isclvar(p)) {
98*a2c41696SDavid du Colombier 			setsval(lookup("FILENAME", symtab), p);
993e12c5d1SDavid du Colombier 			return;
100219b2ee8SDavid du Colombier 		}
1013e12c5d1SDavid du Colombier 		setclvar(p);	/* a commandline assignment before filename */
1023e12c5d1SDavid du Colombier 		argno++;
1033e12c5d1SDavid du Colombier 	}
1043e12c5d1SDavid du Colombier 	infile = stdin;		/* no filenames, so use stdin */
1053e12c5d1SDavid du Colombier }
1063e12c5d1SDavid du Colombier 
107*a2c41696SDavid du Colombier static int firsttime = 1;
108*a2c41696SDavid du Colombier 
getrec(char ** pbuf,int * pbufsize,int isrecord)1097dd7cddfSDavid du Colombier int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
1107dd7cddfSDavid du Colombier {			/* note: cares whether buf == record */
1113e12c5d1SDavid du Colombier 	int c;
1127dd7cddfSDavid du Colombier 	char *buf = *pbuf;
113*a2c41696SDavid du Colombier 	uschar saveb0;
114*a2c41696SDavid du Colombier 	int bufsize = *pbufsize, savebufsize = bufsize;
1153e12c5d1SDavid du Colombier 
1163e12c5d1SDavid du Colombier 	if (firsttime) {
1173e12c5d1SDavid du Colombier 		firsttime = 0;
1183e12c5d1SDavid du Colombier 		initgetrec();
1193e12c5d1SDavid du Colombier 	}
1203e12c5d1SDavid du Colombier 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
1213e12c5d1SDavid du Colombier 		*RS, *FS, *ARGC, *FILENAME) );
1227dd7cddfSDavid du Colombier 	if (isrecord) {
1233e12c5d1SDavid du Colombier 		donefld = 0;
1243e12c5d1SDavid du Colombier 		donerec = 1;
1257dd7cddfSDavid du Colombier 	}
126*a2c41696SDavid du Colombier 	saveb0 = buf[0];
1273e12c5d1SDavid du Colombier 	buf[0] = 0;
1283e12c5d1SDavid du Colombier 	while (argno < *ARGC || infile == stdin) {
1293e12c5d1SDavid du Colombier 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
1303e12c5d1SDavid du Colombier 		if (infile == NULL) {	/* have to open a new file */
1313e12c5d1SDavid du Colombier 			file = getargv(argno);
132*a2c41696SDavid du Colombier 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
1333e12c5d1SDavid du Colombier 				argno++;
1343e12c5d1SDavid du Colombier 				continue;
1353e12c5d1SDavid du Colombier 			}
1363e12c5d1SDavid du Colombier 			if (isclvar(file)) {	/* a var=value arg */
1373e12c5d1SDavid du Colombier 				setclvar(file);
1383e12c5d1SDavid du Colombier 				argno++;
1393e12c5d1SDavid du Colombier 				continue;
1403e12c5d1SDavid du Colombier 			}
1413e12c5d1SDavid du Colombier 			*FILENAME = file;
1423e12c5d1SDavid du Colombier 			   dprintf( ("opening file %s\n", file) );
1433e12c5d1SDavid du Colombier 			if (*file == '-' && *(file+1) == '\0')
1443e12c5d1SDavid du Colombier 				infile = stdin;
1457dd7cddfSDavid du Colombier 			else if ((infile = fopen(file, "r")) == NULL)
1467dd7cddfSDavid du Colombier 				FATAL("can't open file %s", file);
1473e12c5d1SDavid du Colombier 			setfval(fnrloc, 0.0);
1483e12c5d1SDavid du Colombier 		}
1497dd7cddfSDavid du Colombier 		c = readrec(&buf, &bufsize, infile);
1503e12c5d1SDavid du Colombier 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1517dd7cddfSDavid du Colombier 			if (isrecord) {
1527dd7cddfSDavid du Colombier 				if (freeable(fldtab[0]))
1537dd7cddfSDavid du Colombier 					xfree(fldtab[0]->sval);
1547dd7cddfSDavid du Colombier 				fldtab[0]->sval = buf;	/* buf == record */
1557dd7cddfSDavid du Colombier 				fldtab[0]->tval = REC | STR | DONTFREE;
1567dd7cddfSDavid du Colombier 				if (is_number(fldtab[0]->sval)) {
1577dd7cddfSDavid du Colombier 					fldtab[0]->fval = atof(fldtab[0]->sval);
1587dd7cddfSDavid du Colombier 					fldtab[0]->tval |= NUM;
1593e12c5d1SDavid du Colombier 				}
1603e12c5d1SDavid du Colombier 			}
1613e12c5d1SDavid du Colombier 			setfval(nrloc, nrloc->fval+1);
1623e12c5d1SDavid du Colombier 			setfval(fnrloc, fnrloc->fval+1);
1637dd7cddfSDavid du Colombier 			*pbuf = buf;
1647dd7cddfSDavid du Colombier 			*pbufsize = bufsize;
1653e12c5d1SDavid du Colombier 			return 1;
1663e12c5d1SDavid du Colombier 		}
1673e12c5d1SDavid du Colombier 		/* EOF arrived on this file; set up next */
1683e12c5d1SDavid du Colombier 		if (infile != stdin)
1693e12c5d1SDavid du Colombier 			fclose(infile);
1703e12c5d1SDavid du Colombier 		infile = NULL;
1713e12c5d1SDavid du Colombier 		argno++;
1723e12c5d1SDavid du Colombier 	}
173*a2c41696SDavid du Colombier 	buf[0] = saveb0;
1747dd7cddfSDavid du Colombier 	*pbuf = buf;
175*a2c41696SDavid du Colombier 	*pbufsize = savebufsize;
1763e12c5d1SDavid du Colombier 	return 0;	/* true end of file */
1773e12c5d1SDavid du Colombier }
1783e12c5d1SDavid du Colombier 
nextfile(void)1797dd7cddfSDavid du Colombier void nextfile(void)
1803e12c5d1SDavid du Colombier {
181*a2c41696SDavid du Colombier 	if (infile != NULL && infile != stdin)
1827dd7cddfSDavid du Colombier 		fclose(infile);
1837dd7cddfSDavid du Colombier 	infile = NULL;
1847dd7cddfSDavid du Colombier 	argno++;
1857dd7cddfSDavid du Colombier }
1863e12c5d1SDavid du Colombier 
readrec(char ** pbuf,int * pbufsize,FILE * inf)1877dd7cddfSDavid du Colombier int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
1887dd7cddfSDavid du Colombier {
1897dd7cddfSDavid du Colombier 	int sep, c;
1907dd7cddfSDavid du Colombier 	char *rr, *buf = *pbuf;
1917dd7cddfSDavid du Colombier 	int bufsize = *pbufsize;
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 	if (strlen(*FS) >= sizeof(inputFS))
1947dd7cddfSDavid du Colombier 		FATAL("field separator %.10s... is too long", *FS);
195*a2c41696SDavid du Colombier 	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
1967dd7cddfSDavid du Colombier 	strcpy(inputFS, *FS);	/* for subsequent field splitting */
1973e12c5d1SDavid du Colombier 	if ((sep = **RS) == 0) {
1983e12c5d1SDavid du Colombier 		sep = '\n';
1993e12c5d1SDavid du Colombier 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
2003e12c5d1SDavid du Colombier 			;
2013e12c5d1SDavid du Colombier 		if (c != EOF)
2023e12c5d1SDavid du Colombier 			ungetc(c, inf);
2033e12c5d1SDavid du Colombier 	}
2047dd7cddfSDavid du Colombier 	for (rr = buf; ; ) {
2057dd7cddfSDavid du Colombier 		for (; (c=getc(inf)) != sep && c != EOF; ) {
2067dd7cddfSDavid du Colombier 			if (rr-buf+1 > bufsize)
2077dd7cddfSDavid du Colombier 				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
2087dd7cddfSDavid du Colombier 					FATAL("input record `%.30s...' too long", buf);
2097dd7cddfSDavid du Colombier 			*rr++ = c;
2107dd7cddfSDavid du Colombier 		}
2113e12c5d1SDavid du Colombier 		if (**RS == sep || c == EOF)
2123e12c5d1SDavid du Colombier 			break;
2133e12c5d1SDavid du Colombier 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
2143e12c5d1SDavid du Colombier 			break;
2157dd7cddfSDavid du Colombier 		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
2167dd7cddfSDavid du Colombier 			FATAL("input record `%.30s...' too long", buf);
2173e12c5d1SDavid du Colombier 		*rr++ = '\n';
2183e12c5d1SDavid du Colombier 		*rr++ = c;
2193e12c5d1SDavid du Colombier 	}
2207dd7cddfSDavid du Colombier 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2217dd7cddfSDavid du Colombier 		FATAL("input record `%.30s...' too long", buf);
2223e12c5d1SDavid du Colombier 	*rr = 0;
2233e12c5d1SDavid du Colombier 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
2247dd7cddfSDavid du Colombier 	*pbuf = buf;
2257dd7cddfSDavid du Colombier 	*pbufsize = bufsize;
2263e12c5d1SDavid du Colombier 	return c == EOF && rr == buf ? 0 : 1;
2273e12c5d1SDavid du Colombier }
2283e12c5d1SDavid du Colombier 
getargv(int n)2297dd7cddfSDavid du Colombier char *getargv(int n)	/* get ARGV[n] */
2303e12c5d1SDavid du Colombier {
2313e12c5d1SDavid du Colombier 	Cell *x;
2327dd7cddfSDavid du Colombier 	char *s, temp[50];
2333e12c5d1SDavid du Colombier 	extern Array *ARGVtab;
2343e12c5d1SDavid du Colombier 
2357dd7cddfSDavid du Colombier 	sprintf(temp, "%d", n);
236*a2c41696SDavid du Colombier 	if (lookup(temp, ARGVtab) == NULL)
237*a2c41696SDavid du Colombier 		return NULL;
2383e12c5d1SDavid du Colombier 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
2393e12c5d1SDavid du Colombier 	s = getsval(x);
2403e12c5d1SDavid du Colombier 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
2413e12c5d1SDavid du Colombier 	return s;
2423e12c5d1SDavid du Colombier }
2433e12c5d1SDavid du Colombier 
setclvar(char * s)2447dd7cddfSDavid du Colombier void setclvar(char *s)	/* set var=value from s */
2453e12c5d1SDavid du Colombier {
2467dd7cddfSDavid du Colombier 	char *p;
2473e12c5d1SDavid du Colombier 	Cell *q;
2483e12c5d1SDavid du Colombier 
2493e12c5d1SDavid du Colombier 	for (p=s; *p != '='; p++)
2503e12c5d1SDavid du Colombier 		;
2513e12c5d1SDavid du Colombier 	*p++ = 0;
2523e12c5d1SDavid du Colombier 	p = qstring(p, '\0');
2533e12c5d1SDavid du Colombier 	q = setsymtab(s, p, 0.0, STR, symtab);
2543e12c5d1SDavid du Colombier 	setsval(q, p);
2557dd7cddfSDavid du Colombier 	if (is_number(q->sval)) {
2563e12c5d1SDavid du Colombier 		q->fval = atof(q->sval);
2573e12c5d1SDavid du Colombier 		q->tval |= NUM;
2583e12c5d1SDavid du Colombier 	}
2593e12c5d1SDavid du Colombier 	   dprintf( ("command line set %s to |%s|\n", s, p) );
2603e12c5d1SDavid du Colombier }
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier 
fldbld(void)263219b2ee8SDavid du Colombier void fldbld(void)	/* create fields from current record */
2643e12c5d1SDavid du Colombier {
2657dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
2667dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
267*a2c41696SDavid du Colombier 	/* possibly with a final trailing \0 not associated with any field */
2687dd7cddfSDavid du Colombier 	char *r, *fr, sep;
2693e12c5d1SDavid du Colombier 	Cell *p;
2707dd7cddfSDavid du Colombier 	int i, j, n;
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	if (donefld)
2733e12c5d1SDavid du Colombier 		return;
2747dd7cddfSDavid du Colombier 	if (!isstr(fldtab[0]))
2757dd7cddfSDavid du Colombier 		getsval(fldtab[0]);
2767dd7cddfSDavid du Colombier 	r = fldtab[0]->sval;
2777dd7cddfSDavid du Colombier 	n = strlen(r);
2787dd7cddfSDavid du Colombier 	if (n > fieldssize) {
2797dd7cddfSDavid du Colombier 		xfree(fields);
280*a2c41696SDavid du Colombier 		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
2817dd7cddfSDavid du Colombier 			FATAL("out of space for fields in fldbld %d", n);
2827dd7cddfSDavid du Colombier 		fieldssize = n;
2837dd7cddfSDavid du Colombier 	}
2843e12c5d1SDavid du Colombier 	fr = fields;
2853e12c5d1SDavid du Colombier 	i = 0;	/* number of fields accumulated here */
286*a2c41696SDavid du Colombier 	strcpy(inputFS, *FS);
2877dd7cddfSDavid du Colombier 	if (strlen(inputFS) > 1) {	/* it's a regular expression */
2887dd7cddfSDavid du Colombier 		i = refldbld(r, inputFS);
2897dd7cddfSDavid du Colombier 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
2903e12c5d1SDavid du Colombier 		for (i = 0; ; ) {
2913e12c5d1SDavid du Colombier 			while (*r == ' ' || *r == '\t' || *r == '\n')
2923e12c5d1SDavid du Colombier 				r++;
2933e12c5d1SDavid du Colombier 			if (*r == 0)
2943e12c5d1SDavid du Colombier 				break;
2953e12c5d1SDavid du Colombier 			i++;
2967dd7cddfSDavid du Colombier 			if (i > nfields)
2977dd7cddfSDavid du Colombier 				growfldtab(i);
2987dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
2997dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
3007dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
3017dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR | DONTFREE;
3023e12c5d1SDavid du Colombier 			do
3033e12c5d1SDavid du Colombier 				*fr++ = *r++;
3043e12c5d1SDavid du Colombier 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
3053e12c5d1SDavid du Colombier 			*fr++ = 0;
3063e12c5d1SDavid du Colombier 		}
3073e12c5d1SDavid du Colombier 		*fr = 0;
3087dd7cddfSDavid du Colombier 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
3097dd7cddfSDavid du Colombier 		for (i = 0; *r != 0; r++) {
3107dd7cddfSDavid du Colombier 			char buf[2];
3117dd7cddfSDavid 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 			buf[0] = *r;
3177dd7cddfSDavid du Colombier 			buf[1] = 0;
3187dd7cddfSDavid du Colombier 			fldtab[i]->sval = tostring(buf);
3197dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR;
3207dd7cddfSDavid du Colombier 		}
3217dd7cddfSDavid du Colombier 		*fr = 0;
3223e12c5d1SDavid du Colombier 	} else if (*r != 0) {	/* if 0, it's a null field */
323*a2c41696SDavid du Colombier 		/* subtlecase : if length(FS) == 1 && length(RS > 0)
324*a2c41696SDavid du Colombier 		 * \n is NOT a field separator (cf awk book 61,84).
325*a2c41696SDavid du Colombier 		 * this variable is tested in the inner while loop.
326*a2c41696SDavid du Colombier 		 */
327*a2c41696SDavid du Colombier 		int rtest = '\n';  /* normal case */
328*a2c41696SDavid du Colombier 		if (strlen(*RS) > 0)
329*a2c41696SDavid du Colombier 			rtest = '\0';
3303e12c5d1SDavid du Colombier 		for (;;) {
3313e12c5d1SDavid du Colombier 			i++;
3327dd7cddfSDavid du Colombier 			if (i > nfields)
3337dd7cddfSDavid du Colombier 				growfldtab(i);
3347dd7cddfSDavid du Colombier 			if (freeable(fldtab[i]))
3357dd7cddfSDavid du Colombier 				xfree(fldtab[i]->sval);
3367dd7cddfSDavid du Colombier 			fldtab[i]->sval = fr;
3377dd7cddfSDavid du Colombier 			fldtab[i]->tval = FLD | STR | DONTFREE;
338*a2c41696SDavid du Colombier 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
3393e12c5d1SDavid du Colombier 				*fr++ = *r++;
3403e12c5d1SDavid du Colombier 			*fr++ = 0;
3413e12c5d1SDavid du Colombier 			if (*r++ == 0)
3423e12c5d1SDavid du Colombier 				break;
3433e12c5d1SDavid du Colombier 		}
3443e12c5d1SDavid du Colombier 		*fr = 0;
3453e12c5d1SDavid du Colombier 	}
3467dd7cddfSDavid du Colombier 	if (i > nfields)
3477dd7cddfSDavid du Colombier 		FATAL("record `%.30s...' has too many fields; can't happen", r);
3487dd7cddfSDavid du Colombier 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
3497dd7cddfSDavid du Colombier 	lastfld = i;
3503e12c5d1SDavid du Colombier 	donefld = 1;
3517dd7cddfSDavid du Colombier 	for (j = 1; j <= lastfld; j++) {
3527dd7cddfSDavid du Colombier 		p = fldtab[j];
3537dd7cddfSDavid du Colombier 		if(is_number(p->sval)) {
3543e12c5d1SDavid du Colombier 			p->fval = atof(p->sval);
3553e12c5d1SDavid du Colombier 			p->tval |= NUM;
3563e12c5d1SDavid du Colombier 		}
3573e12c5d1SDavid du Colombier 	}
3587dd7cddfSDavid du Colombier 	setfval(nfloc, (Awkfloat) lastfld);
3597dd7cddfSDavid du Colombier 	if (dbg) {
3607dd7cddfSDavid du Colombier 		for (j = 0; j <= lastfld; j++) {
3617dd7cddfSDavid du Colombier 			p = fldtab[j];
3627dd7cddfSDavid du Colombier 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
3637dd7cddfSDavid du Colombier 		}
3647dd7cddfSDavid du Colombier 	}
3653e12c5d1SDavid du Colombier }
3663e12c5d1SDavid du Colombier 
cleanfld(int n1,int n2)3673e12c5d1SDavid du Colombier void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
3687dd7cddfSDavid du Colombier {				/* nvals remain intact */
3697dd7cddfSDavid du Colombier 	Cell *p;
3707dd7cddfSDavid du Colombier 	int i;
3713e12c5d1SDavid du Colombier 
3727dd7cddfSDavid du Colombier 	for (i = n1; i <= n2; i++) {
3737dd7cddfSDavid du Colombier 		p = fldtab[i];
3747dd7cddfSDavid du Colombier 		if (freeable(p))
3753e12c5d1SDavid du Colombier 			xfree(p->sval);
3767dd7cddfSDavid du Colombier 		p->sval = "";
3773e12c5d1SDavid du Colombier 		p->tval = FLD | STR | DONTFREE;
3783e12c5d1SDavid du Colombier 	}
3793e12c5d1SDavid du Colombier }
3803e12c5d1SDavid du Colombier 
newfld(int n)3817dd7cddfSDavid du Colombier void newfld(int n)	/* add field n after end of existing lastfld */
3823e12c5d1SDavid du Colombier {
3837dd7cddfSDavid du Colombier 	if (n > nfields)
3847dd7cddfSDavid du Colombier 		growfldtab(n);
3857dd7cddfSDavid du Colombier 	cleanfld(lastfld+1, n);
3867dd7cddfSDavid du Colombier 	lastfld = n;
3873e12c5d1SDavid du Colombier 	setfval(nfloc, (Awkfloat) n);
3883e12c5d1SDavid du Colombier }
3893e12c5d1SDavid du Colombier 
fieldadr(int n)3907dd7cddfSDavid du Colombier Cell *fieldadr(int n)	/* get nth field */
3913e12c5d1SDavid du Colombier {
3927dd7cddfSDavid du Colombier 	if (n < 0)
393*a2c41696SDavid du Colombier 		FATAL("trying to access out of range field %d", n);
3947dd7cddfSDavid du Colombier 	if (n > nfields)	/* fields after NF are empty */
3957dd7cddfSDavid du Colombier 		growfldtab(n);	/* but does not increase NF */
3967dd7cddfSDavid du Colombier 	return(fldtab[n]);
3977dd7cddfSDavid du Colombier }
3983e12c5d1SDavid du Colombier 
growfldtab(int n)3997dd7cddfSDavid du Colombier void growfldtab(int n)	/* make new fields up to at least $n */
4007dd7cddfSDavid du Colombier {
4017dd7cddfSDavid du Colombier 	int nf = 2 * nfields;
402*a2c41696SDavid du Colombier 	size_t s;
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 	if (n > nf)
4057dd7cddfSDavid du Colombier 		nf = n;
406*a2c41696SDavid du Colombier 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
407*a2c41696SDavid du Colombier 	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
408*a2c41696SDavid du Colombier 		fldtab = (Cell **) realloc(fldtab, s);
409*a2c41696SDavid du Colombier 	else					/* overflow sizeof int */
410*a2c41696SDavid du Colombier 		xfree(fldtab);	/* make it null */
4117dd7cddfSDavid du Colombier 	if (fldtab == NULL)
4127dd7cddfSDavid du Colombier 		FATAL("out of space creating %d fields", nf);
4137dd7cddfSDavid du Colombier 	makefields(nfields+1, nf);
4147dd7cddfSDavid du Colombier 	nfields = nf;
4157dd7cddfSDavid du Colombier }
4167dd7cddfSDavid du Colombier 
refldbld(const char * rec,const char * fs)417*a2c41696SDavid du Colombier int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
4187dd7cddfSDavid du Colombier {
4197dd7cddfSDavid du Colombier 	/* this relies on having fields[] the same length as $0 */
4207dd7cddfSDavid du Colombier 	/* the fields are all stored in this one array with \0's */
4217dd7cddfSDavid du Colombier 	char *fr;
4227dd7cddfSDavid du Colombier 	void *p;
4237dd7cddfSDavid du Colombier 	int i, tempstat, n;
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier 	n = strlen(rec);
4267dd7cddfSDavid du Colombier 	if (n > fieldssize) {
4277dd7cddfSDavid du Colombier 		xfree(fields);
4287dd7cddfSDavid du Colombier 		if ((fields = (char *) malloc(n+1)) == NULL)
4297dd7cddfSDavid du Colombier 			FATAL("out of space for fields in refldbld %d", n);
4307dd7cddfSDavid du Colombier 		fieldssize = n;
4317dd7cddfSDavid du Colombier 	}
4323e12c5d1SDavid du Colombier 	fr = fields;
4333e12c5d1SDavid du Colombier 	*fr = '\0';
4343e12c5d1SDavid du Colombier 	if (*rec == '\0')
4353e12c5d1SDavid du Colombier 		return 0;
4363e12c5d1SDavid du Colombier 	p = compre(fs);
4373e12c5d1SDavid du Colombier 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
4387dd7cddfSDavid du Colombier 	for (i = 1; ; i++) {
4397dd7cddfSDavid du Colombier 		if (i > nfields)
4407dd7cddfSDavid du Colombier 			growfldtab(i);
4417dd7cddfSDavid du Colombier 		if (freeable(fldtab[i]))
4427dd7cddfSDavid du Colombier 			xfree(fldtab[i]->sval);
4437dd7cddfSDavid du Colombier 		fldtab[i]->tval = FLD | STR | DONTFREE;
4447dd7cddfSDavid du Colombier 		fldtab[i]->sval = fr;
4453e12c5d1SDavid du Colombier 		   dprintf( ("refldbld: i=%d\n", i) );
4463e12c5d1SDavid du Colombier 		if (nematch(p, rec, rec)) {
4473e12c5d1SDavid du Colombier 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
4483e12c5d1SDavid du Colombier 			strncpy(fr, rec, patbeg-rec);
4493e12c5d1SDavid du Colombier 			fr += patbeg - rec + 1;
4503e12c5d1SDavid du Colombier 			*(fr-1) = '\0';
4513e12c5d1SDavid du Colombier 			rec = patbeg + patlen;
4523e12c5d1SDavid du Colombier 		} else {
4533e12c5d1SDavid du Colombier 			   dprintf( ("no match %s\n", rec) );
4543e12c5d1SDavid du Colombier 			strcpy(fr, rec);
4553e12c5d1SDavid du Colombier 			break;
4563e12c5d1SDavid du Colombier 		}
4573e12c5d1SDavid du Colombier 	}
4583e12c5d1SDavid du Colombier 	return i;
4593e12c5d1SDavid du Colombier }
4603e12c5d1SDavid du Colombier 
recbld(void)461219b2ee8SDavid du Colombier void recbld(void)	/* create $0 from $1..$NF if necessary */
4623e12c5d1SDavid du Colombier {
4637dd7cddfSDavid du Colombier 	int i;
4647dd7cddfSDavid du Colombier 	char *r, *p;
4653e12c5d1SDavid du Colombier 
4663e12c5d1SDavid du Colombier 	if (donerec == 1)
4673e12c5d1SDavid du Colombier 		return;
4687dd7cddfSDavid du Colombier 	r = record;
4693e12c5d1SDavid du Colombier 	for (i = 1; i <= *NF; i++) {
4707dd7cddfSDavid du Colombier 		p = getsval(fldtab[i]);
4717dd7cddfSDavid du Colombier 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
4727dd7cddfSDavid du Colombier 			FATAL("created $0 `%.30s...' too long", record);
4737dd7cddfSDavid du Colombier 		while ((*r = *p++) != 0)
4743e12c5d1SDavid du Colombier 			r++;
4757dd7cddfSDavid du Colombier 		if (i < *NF) {
4767dd7cddfSDavid du Colombier 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
4777dd7cddfSDavid du Colombier 				FATAL("created $0 `%.30s...' too long", record);
4787dd7cddfSDavid du Colombier 			for (p = *OFS; (*r = *p++) != 0; )
4793e12c5d1SDavid du Colombier 				r++;
4803e12c5d1SDavid du Colombier 		}
4817dd7cddfSDavid du Colombier 	}
4827dd7cddfSDavid du Colombier 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
4837dd7cddfSDavid du Colombier 		FATAL("built giant record `%.30s...'", record);
4843e12c5d1SDavid du Colombier 	*r = '\0';
485*a2c41696SDavid du Colombier 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
4867dd7cddfSDavid du Colombier 
4877dd7cddfSDavid du Colombier 	if (freeable(fldtab[0]))
4887dd7cddfSDavid du Colombier 		xfree(fldtab[0]->sval);
4897dd7cddfSDavid du Colombier 	fldtab[0]->tval = REC | STR | DONTFREE;
4907dd7cddfSDavid du Colombier 	fldtab[0]->sval = record;
4917dd7cddfSDavid du Colombier 
492*a2c41696SDavid du Colombier 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
4933e12c5d1SDavid du Colombier 	   dprintf( ("recbld = |%s|\n", record) );
4943e12c5d1SDavid du Colombier 	donerec = 1;
4953e12c5d1SDavid du Colombier }
4963e12c5d1SDavid du Colombier 
4977dd7cddfSDavid du Colombier int	errorflag	= 0;
4987dd7cddfSDavid du Colombier 
yyerror(const char * s)499*a2c41696SDavid du Colombier void yyerror(const char *s)
5003e12c5d1SDavid du Colombier {
501*a2c41696SDavid du Colombier 	SYNTAX("%s", s);
5023e12c5d1SDavid du Colombier }
5033e12c5d1SDavid du Colombier 
SYNTAX(const char * fmt,...)504*a2c41696SDavid du Colombier void SYNTAX(const char *fmt, ...)
5053e12c5d1SDavid du Colombier {
5067dd7cddfSDavid du Colombier 	extern char *cmdname, *curfname;
5073e12c5d1SDavid du Colombier 	static int been_here = 0;
5087dd7cddfSDavid du Colombier 	va_list varg;
5093e12c5d1SDavid du Colombier 
5103e12c5d1SDavid du Colombier 	if (been_here++ > 2)
5113e12c5d1SDavid du Colombier 		return;
5127dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
5137dd7cddfSDavid du Colombier 	va_start(varg, fmt);
5147dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
5157dd7cddfSDavid du Colombier 	va_end(varg);
516*a2c41696SDavid du Colombier 	fprintf(stderr, " at source line %d", lineno);
5173e12c5d1SDavid du Colombier 	if (curfname != NULL)
5183e12c5d1SDavid du Colombier 		fprintf(stderr, " in function %s", curfname);
519*a2c41696SDavid du Colombier 	if (compile_time == 1 && cursource() != NULL)
520*a2c41696SDavid du Colombier 		fprintf(stderr, " source file %s", cursource());
5213e12c5d1SDavid du Colombier 	fprintf(stderr, "\n");
5223e12c5d1SDavid du Colombier 	errorflag = 2;
5233e12c5d1SDavid du Colombier 	eprint();
5243e12c5d1SDavid du Colombier }
5253e12c5d1SDavid du Colombier 
fpecatch(int n)5263e12c5d1SDavid du Colombier void fpecatch(int n)
5273e12c5d1SDavid du Colombier {
5287dd7cddfSDavid du Colombier 	FATAL("floating point exception %d", n);
5293e12c5d1SDavid du Colombier }
5303e12c5d1SDavid du Colombier 
5313e12c5d1SDavid du Colombier extern int bracecnt, brackcnt, parencnt;
5323e12c5d1SDavid du Colombier 
bracecheck(void)5333e12c5d1SDavid du Colombier void bracecheck(void)
5343e12c5d1SDavid du Colombier {
5353e12c5d1SDavid du Colombier 	int c;
5363e12c5d1SDavid du Colombier 	static int beenhere = 0;
5373e12c5d1SDavid du Colombier 
5383e12c5d1SDavid du Colombier 	if (beenhere++)
5393e12c5d1SDavid du Colombier 		return;
5403e12c5d1SDavid du Colombier 	while ((c = input()) != EOF && c != '\0')
5413e12c5d1SDavid du Colombier 		bclass(c);
5423e12c5d1SDavid du Colombier 	bcheck2(bracecnt, '{', '}');
5433e12c5d1SDavid du Colombier 	bcheck2(brackcnt, '[', ']');
5443e12c5d1SDavid du Colombier 	bcheck2(parencnt, '(', ')');
5453e12c5d1SDavid du Colombier }
5463e12c5d1SDavid du Colombier 
bcheck2(int n,int c1,int c2)5473e12c5d1SDavid du Colombier void bcheck2(int n, int c1, int c2)
5483e12c5d1SDavid du Colombier {
5493e12c5d1SDavid du Colombier 	if (n == 1)
5503e12c5d1SDavid du Colombier 		fprintf(stderr, "\tmissing %c\n", c2);
5513e12c5d1SDavid du Colombier 	else if (n > 1)
5523e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
5533e12c5d1SDavid du Colombier 	else if (n == -1)
5543e12c5d1SDavid du Colombier 		fprintf(stderr, "\textra %c\n", c2);
5553e12c5d1SDavid du Colombier 	else if (n < -1)
5563e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
5573e12c5d1SDavid du Colombier }
5583e12c5d1SDavid du Colombier 
FATAL(const char * fmt,...)559*a2c41696SDavid du Colombier void FATAL(const char *fmt, ...)
5603e12c5d1SDavid du Colombier {
5617dd7cddfSDavid du Colombier 	extern char *cmdname;
5627dd7cddfSDavid du Colombier 	va_list varg;
5633e12c5d1SDavid du Colombier 
5643e12c5d1SDavid du Colombier 	fflush(stdout);
5653e12c5d1SDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
5667dd7cddfSDavid du Colombier 	va_start(varg, fmt);
5677dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
5687dd7cddfSDavid du Colombier 	va_end(varg);
5697dd7cddfSDavid du Colombier 	error();
570219b2ee8SDavid du Colombier 	if (dbg > 1)		/* core dump if serious debugging on */
5713e12c5d1SDavid du Colombier 		abort();
5723e12c5d1SDavid du Colombier 	exit(2);
5733e12c5d1SDavid du Colombier }
5747dd7cddfSDavid du Colombier 
WARNING(const char * fmt,...)575*a2c41696SDavid du Colombier void WARNING(const char *fmt, ...)
5767dd7cddfSDavid du Colombier {
5777dd7cddfSDavid du Colombier 	extern char *cmdname;
5787dd7cddfSDavid du Colombier 	va_list varg;
5797dd7cddfSDavid du Colombier 
5807dd7cddfSDavid du Colombier 	fflush(stdout);
5817dd7cddfSDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
5827dd7cddfSDavid du Colombier 	va_start(varg, fmt);
5837dd7cddfSDavid du Colombier 	vfprintf(stderr, fmt, varg);
5847dd7cddfSDavid du Colombier 	va_end(varg);
5857dd7cddfSDavid du Colombier 	error();
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier 
error()5887dd7cddfSDavid du Colombier void error()
5897dd7cddfSDavid du Colombier {
5907dd7cddfSDavid du Colombier 	extern Node *curnode;
5917dd7cddfSDavid du Colombier 
5927dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
5937dd7cddfSDavid du Colombier 	if (compile_time != 2 && NR && *NR > 0) {
5947dd7cddfSDavid du Colombier 		fprintf(stderr, " input record number %d", (int) (*FNR));
595*a2c41696SDavid du Colombier 		if (strcmp(*FILENAME, "-") != 0)
596*a2c41696SDavid du Colombier 			fprintf(stderr, ", file %s", *FILENAME);
5977dd7cddfSDavid du Colombier 		fprintf(stderr, "\n");
5987dd7cddfSDavid du Colombier 	}
5997dd7cddfSDavid du Colombier 	if (compile_time != 2 && curnode)
600*a2c41696SDavid du Colombier 		fprintf(stderr, " source line number %d", curnode->lineno);
6017dd7cddfSDavid du Colombier 	else if (compile_time != 2 && lineno)
602*a2c41696SDavid du Colombier 		fprintf(stderr, " source line number %d", lineno);
603*a2c41696SDavid du Colombier 	if (compile_time == 1 && cursource() != NULL)
6047dd7cddfSDavid du Colombier 		fprintf(stderr, " source file %s", cursource());
6057dd7cddfSDavid du Colombier 	fprintf(stderr, "\n");
6067dd7cddfSDavid du Colombier 	eprint();
6073e12c5d1SDavid du Colombier }
6083e12c5d1SDavid du Colombier 
eprint(void)6093e12c5d1SDavid du Colombier void eprint(void)	/* try to print context around error */
6103e12c5d1SDavid du Colombier {
6117dd7cddfSDavid du Colombier 	char *p, *q;
6123e12c5d1SDavid du Colombier 	int c;
6133e12c5d1SDavid du Colombier 	static int been_here = 0;
6147dd7cddfSDavid du Colombier 	extern char ebuf[], *ep;
6153e12c5d1SDavid du Colombier 
6163e12c5d1SDavid du Colombier 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
6173e12c5d1SDavid du Colombier 		return;
6183e12c5d1SDavid du Colombier 	p = ep - 1;
6193e12c5d1SDavid du Colombier 	if (p > ebuf && *p == '\n')
6203e12c5d1SDavid du Colombier 		p--;
6213e12c5d1SDavid du Colombier 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
6223e12c5d1SDavid du Colombier 		;
6233e12c5d1SDavid du Colombier 	while (*p == '\n')
6243e12c5d1SDavid du Colombier 		p++;
6253e12c5d1SDavid du Colombier 	fprintf(stderr, " context is\n\t");
6263e12c5d1SDavid du Colombier 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
6273e12c5d1SDavid du Colombier 		;
6283e12c5d1SDavid du Colombier 	for ( ; p < q; p++)
6293e12c5d1SDavid du Colombier 		if (*p)
6303e12c5d1SDavid du Colombier 			putc(*p, stderr);
6313e12c5d1SDavid du Colombier 	fprintf(stderr, " >>> ");
6323e12c5d1SDavid du Colombier 	for ( ; p < ep; p++)
6333e12c5d1SDavid du Colombier 		if (*p)
6343e12c5d1SDavid du Colombier 			putc(*p, stderr);
6353e12c5d1SDavid du Colombier 	fprintf(stderr, " <<< ");
6363e12c5d1SDavid du Colombier 	if (*ep)
6373e12c5d1SDavid du Colombier 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
6383e12c5d1SDavid du Colombier 			putc(c, stderr);
6393e12c5d1SDavid du Colombier 			bclass(c);
6403e12c5d1SDavid du Colombier 		}
6413e12c5d1SDavid du Colombier 	putc('\n', stderr);
6423e12c5d1SDavid du Colombier 	ep = ebuf;
6433e12c5d1SDavid du Colombier }
6443e12c5d1SDavid du Colombier 
bclass(int c)6453e12c5d1SDavid du Colombier void bclass(int c)
6463e12c5d1SDavid du Colombier {
6473e12c5d1SDavid du Colombier 	switch (c) {
6483e12c5d1SDavid du Colombier 	case '{': bracecnt++; break;
6493e12c5d1SDavid du Colombier 	case '}': bracecnt--; break;
6503e12c5d1SDavid du Colombier 	case '[': brackcnt++; break;
6513e12c5d1SDavid du Colombier 	case ']': brackcnt--; break;
6523e12c5d1SDavid du Colombier 	case '(': parencnt++; break;
6533e12c5d1SDavid du Colombier 	case ')': parencnt--; break;
6543e12c5d1SDavid du Colombier 	}
6553e12c5d1SDavid du Colombier }
6563e12c5d1SDavid du Colombier 
errcheck(double x,const char * s)657*a2c41696SDavid du Colombier double errcheck(double x, const char *s)
6583e12c5d1SDavid du Colombier {
6593e12c5d1SDavid du Colombier 
6603e12c5d1SDavid du Colombier 	if (errno == EDOM) {
6613e12c5d1SDavid du Colombier 		errno = 0;
6627dd7cddfSDavid du Colombier 		WARNING("%s argument out of domain", s);
6633e12c5d1SDavid du Colombier 		x = 1;
6643e12c5d1SDavid du Colombier 	} else if (errno == ERANGE) {
6653e12c5d1SDavid du Colombier 		errno = 0;
6667dd7cddfSDavid du Colombier 		WARNING("%s result out of range", s);
6673e12c5d1SDavid du Colombier 		x = 1;
6683e12c5d1SDavid du Colombier 	}
6693e12c5d1SDavid du Colombier 	return x;
6703e12c5d1SDavid du Colombier }
6713e12c5d1SDavid du Colombier 
isclvar(const char * s)672*a2c41696SDavid du Colombier int isclvar(const char *s)	/* is s of form var=something ? */
6733e12c5d1SDavid du Colombier {
674*a2c41696SDavid du Colombier 	const char *os = s;
6753e12c5d1SDavid du Colombier 
676*a2c41696SDavid du Colombier 	if (!isalpha((uschar) *s) && *s != '_')
6773e12c5d1SDavid du Colombier 		return 0;
6783e12c5d1SDavid du Colombier 	for ( ; *s; s++)
679*a2c41696SDavid du Colombier 		if (!(isalnum((uschar) *s) || *s == '_'))
6803e12c5d1SDavid du Colombier 			break;
6813e12c5d1SDavid du Colombier 	return *s == '=' && s > os && *(s+1) != '=';
6823e12c5d1SDavid du Colombier }
6833e12c5d1SDavid du Colombier 
6847dd7cddfSDavid du Colombier /* strtod is supposed to be a proper test of what's a valid number */
685*a2c41696SDavid du Colombier /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
686*a2c41696SDavid du Colombier /* wrong: violates 4.10.1.4 of ansi C standard */
6873e12c5d1SDavid du Colombier 
6887dd7cddfSDavid du Colombier #include <math.h>
is_number(const char * s)689*a2c41696SDavid du Colombier int is_number(const char *s)
6903e12c5d1SDavid du Colombier {
6917dd7cddfSDavid du Colombier 	double r;
6927dd7cddfSDavid du Colombier 	char *ep;
69305bfb676SDavid du Colombier 
69405bfb676SDavid du Colombier 	/*
69505bfb676SDavid du Colombier 	 * fast could-it-be-a-number check before calling strtod,
69605bfb676SDavid du Colombier 	 * which takes a surprisingly long time to reject non-numbers.
69705bfb676SDavid du Colombier 	 */
69805bfb676SDavid du Colombier 	switch (*s) {
69905bfb676SDavid du Colombier 	case '0': case '1': case '2': case '3': case '4':
70005bfb676SDavid du Colombier 	case '5': case '6': case '7': case '8': case '9':
70105bfb676SDavid du Colombier 	case '\t':
70205bfb676SDavid du Colombier 	case '\n':
70305bfb676SDavid du Colombier 	case '\v':
70405bfb676SDavid du Colombier 	case '\f':
70505bfb676SDavid du Colombier 	case '\r':
70605bfb676SDavid du Colombier 	case ' ':
70705bfb676SDavid du Colombier 	case '-':
70805bfb676SDavid du Colombier 	case '+':
70905bfb676SDavid du Colombier 	case '.':
71005bfb676SDavid du Colombier 	case 'n':		/* nans */
71105bfb676SDavid du Colombier 	case 'N':
71205bfb676SDavid du Colombier 	case 'i':		/* infs */
71305bfb676SDavid du Colombier 	case 'I':
71405bfb676SDavid du Colombier 		break;
71505bfb676SDavid du Colombier 	default:
71605bfb676SDavid du Colombier 		return 0;	/* can't be a number */
71705bfb676SDavid du Colombier 	}
71805bfb676SDavid du Colombier 
7197dd7cddfSDavid du Colombier 	errno = 0;
7207dd7cddfSDavid du Colombier 	r = strtod(s, &ep);
7217dd7cddfSDavid du Colombier 	if (ep == s || r == HUGE_VAL || errno == ERANGE)
7227dd7cddfSDavid du Colombier 		return 0;
7237dd7cddfSDavid du Colombier 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
7247dd7cddfSDavid du Colombier 		ep++;
7257dd7cddfSDavid du Colombier 	if (*ep == '\0')
7267dd7cddfSDavid du Colombier 		return 1;
7273e12c5d1SDavid du Colombier 	else
7287dd7cddfSDavid du Colombier 		return 0;
7293e12c5d1SDavid du Colombier }
730