xref: /dflybsd-src/contrib/awk/lib.c (revision 1d48fce09e070b7fb0180fe19e991a6b7edcd14c)
14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos 
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos 
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos 
254b588458SPeter Avalos #define DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <string.h>
284b588458SPeter Avalos #include <ctype.h>
294b588458SPeter Avalos #include <errno.h>
304b588458SPeter Avalos #include <stdlib.h>
314b588458SPeter Avalos #include <stdarg.h>
32*1d48fce0SDaniel Fojt #include <limits.h>
334b588458SPeter Avalos #include "awk.h"
344b588458SPeter Avalos #include "ytab.h"
354b588458SPeter Avalos 
36*1d48fce0SDaniel Fojt char	EMPTY[] = { '\0' };
374b588458SPeter Avalos FILE	*infile	= NULL;
38*1d48fce0SDaniel Fojt bool	innew;		/* true = infile has not been read by readrec */
39*1d48fce0SDaniel Fojt char	*file	= EMPTY;
404b588458SPeter Avalos char	*record;
414b588458SPeter Avalos int	recsize	= RECSIZE;
424b588458SPeter Avalos char	*fields;
434b588458SPeter Avalos int	fieldssize = RECSIZE;
444b588458SPeter Avalos 
454b588458SPeter Avalos Cell	**fldtab;	/* pointers to Cells */
46*1d48fce0SDaniel Fojt static size_t	len_inputFS = 0;
47*1d48fce0SDaniel Fojt static char	*inputFS = NULL; /* FS at time of input, for field splitting */
484b588458SPeter Avalos 
494b588458SPeter Avalos #define	MAXFLD	2
504b588458SPeter Avalos int	nfields	= MAXFLD;	/* last allocated slot for $i */
514b588458SPeter Avalos 
52*1d48fce0SDaniel Fojt bool	donefld;	/* true = implies rec broken into fields */
53*1d48fce0SDaniel Fojt bool	donerec;	/* true = record is valid (no flds have changed) */
544b588458SPeter Avalos 
554b588458SPeter Avalos int	lastfld	= 0;	/* last used field */
564b588458SPeter Avalos int	argno	= 1;	/* current input argument number */
574b588458SPeter Avalos extern	Awkfloat *ARGC;
584b588458SPeter Avalos 
59*1d48fce0SDaniel Fojt static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
60*1d48fce0SDaniel Fojt static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
614b588458SPeter Avalos 
624b588458SPeter Avalos void recinit(unsigned int n)
634b588458SPeter Avalos {
64*1d48fce0SDaniel Fojt 	if ( (record = malloc(n)) == NULL
65*1d48fce0SDaniel Fojt 	  || (fields = malloc(n+1)) == NULL
66*1d48fce0SDaniel Fojt 	  || (fldtab = calloc(nfields+2, sizeof(*fldtab))) == NULL
67*1d48fce0SDaniel Fojt 	  || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL)
684b588458SPeter Avalos 		FATAL("out of space for $0 and fields");
69*1d48fce0SDaniel Fojt 	*record = '\0';
704b588458SPeter Avalos 	*fldtab[0] = dollar0;
714b588458SPeter Avalos 	fldtab[0]->sval = record;
724b588458SPeter Avalos 	fldtab[0]->nval = tostring("0");
734b588458SPeter Avalos 	makefields(1, nfields);
744b588458SPeter Avalos }
754b588458SPeter Avalos 
764b588458SPeter Avalos void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
774b588458SPeter Avalos {
784b588458SPeter Avalos 	char temp[50];
794b588458SPeter Avalos 	int i;
804b588458SPeter Avalos 
814b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
82*1d48fce0SDaniel Fojt 		fldtab[i] = malloc(sizeof(**fldtab));
834b588458SPeter Avalos 		if (fldtab[i] == NULL)
844b588458SPeter Avalos 			FATAL("out of space in makefields %d", i);
854b588458SPeter Avalos 		*fldtab[i] = dollar1;
86*1d48fce0SDaniel Fojt 		snprintf(temp, sizeof(temp), "%d", i);
874b588458SPeter Avalos 		fldtab[i]->nval = tostring(temp);
884b588458SPeter Avalos 	}
894b588458SPeter Avalos }
904b588458SPeter Avalos 
914b588458SPeter Avalos void initgetrec(void)
924b588458SPeter Avalos {
934b588458SPeter Avalos 	int i;
944b588458SPeter Avalos 	char *p;
954b588458SPeter Avalos 
964b588458SPeter Avalos 	for (i = 1; i < *ARGC; i++) {
97b12bae18SSascha Wildner 		p = getargv(i); /* find 1st real filename */
98b12bae18SSascha Wildner 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
99b12bae18SSascha Wildner 			argno++;
100b12bae18SSascha Wildner 			continue;
101b12bae18SSascha Wildner 		}
102b12bae18SSascha Wildner 		if (!isclvar(p)) {
103b12bae18SSascha Wildner 			setsval(lookup("FILENAME", symtab), p);
1044b588458SPeter Avalos 			return;
1054b588458SPeter Avalos 		}
1064b588458SPeter Avalos 		setclvar(p);	/* a commandline assignment before filename */
1074b588458SPeter Avalos 		argno++;
1084b588458SPeter Avalos 	}
1094b588458SPeter Avalos 	infile = stdin;		/* no filenames, so use stdin */
110*1d48fce0SDaniel Fojt 	innew = true;
1114b588458SPeter Avalos }
1124b588458SPeter Avalos 
113*1d48fce0SDaniel Fojt /*
114*1d48fce0SDaniel Fojt  * POSIX specifies that fields are supposed to be evaluated as if they were
115*1d48fce0SDaniel Fojt  * split using the value of FS at the time that the record's value ($0) was
116*1d48fce0SDaniel Fojt  * read.
117*1d48fce0SDaniel Fojt  *
118*1d48fce0SDaniel Fojt  * Since field-splitting is done lazily, we save the current value of FS
119*1d48fce0SDaniel Fojt  * whenever a new record is read in (implicitly or via getline), or when
120*1d48fce0SDaniel Fojt  * a new value is assigned to $0.
121*1d48fce0SDaniel Fojt  */
122*1d48fce0SDaniel Fojt void savefs(void)
123*1d48fce0SDaniel Fojt {
124*1d48fce0SDaniel Fojt 	size_t len;
125*1d48fce0SDaniel Fojt 	if ((len = strlen(getsval(fsloc))) < len_inputFS) {
126*1d48fce0SDaniel Fojt 		strcpy(inputFS, *FS);	/* for subsequent field splitting */
127*1d48fce0SDaniel Fojt 		return;
128*1d48fce0SDaniel Fojt 	}
1294b588458SPeter Avalos 
130*1d48fce0SDaniel Fojt 	len_inputFS = len + 1;
131*1d48fce0SDaniel Fojt 	inputFS = realloc(inputFS, len_inputFS);
132*1d48fce0SDaniel Fojt 	if (inputFS == NULL)
133*1d48fce0SDaniel Fojt 		FATAL("field separator %.10s... is too long", *FS);
134*1d48fce0SDaniel Fojt 	memcpy(inputFS, *FS, len_inputFS);
135*1d48fce0SDaniel Fojt }
136*1d48fce0SDaniel Fojt 
137*1d48fce0SDaniel Fojt static bool firsttime = true;
138*1d48fce0SDaniel Fojt 
139*1d48fce0SDaniel Fojt int getrec(char **pbuf, int *pbufsize, bool isrecord)	/* get next input record */
1404b588458SPeter Avalos {			/* note: cares whether buf == record */
1414b588458SPeter Avalos 	int c;
1424b588458SPeter Avalos 	char *buf = *pbuf;
1434b588458SPeter Avalos 	uschar saveb0;
1444b588458SPeter Avalos 	int bufsize = *pbufsize, savebufsize = bufsize;
1454b588458SPeter Avalos 
1464b588458SPeter Avalos 	if (firsttime) {
147*1d48fce0SDaniel Fojt 		firsttime = false;
1484b588458SPeter Avalos 		initgetrec();
1494b588458SPeter Avalos 	}
1504b588458SPeter Avalos 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
1514b588458SPeter Avalos 		*RS, *FS, *ARGC, *FILENAME) );
1524b588458SPeter Avalos 	if (isrecord) {
153*1d48fce0SDaniel Fojt 		donefld = false;
154*1d48fce0SDaniel Fojt 		donerec = true;
155*1d48fce0SDaniel Fojt 		savefs();
1564b588458SPeter Avalos 	}
1574b588458SPeter Avalos 	saveb0 = buf[0];
1584b588458SPeter Avalos 	buf[0] = 0;
1594b588458SPeter Avalos 	while (argno < *ARGC || infile == stdin) {
1604b588458SPeter Avalos 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
1614b588458SPeter Avalos 		if (infile == NULL) {	/* have to open a new file */
1624b588458SPeter Avalos 			file = getargv(argno);
163b12bae18SSascha Wildner 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
1644b588458SPeter Avalos 				argno++;
1654b588458SPeter Avalos 				continue;
1664b588458SPeter Avalos 			}
1674b588458SPeter Avalos 			if (isclvar(file)) {	/* a var=value arg */
1684b588458SPeter Avalos 				setclvar(file);
1694b588458SPeter Avalos 				argno++;
1704b588458SPeter Avalos 				continue;
1714b588458SPeter Avalos 			}
1724b588458SPeter Avalos 			*FILENAME = file;
1734b588458SPeter Avalos 			   dprintf( ("opening file %s\n", file) );
1744b588458SPeter Avalos 			if (*file == '-' && *(file+1) == '\0')
1754b588458SPeter Avalos 				infile = stdin;
1764b588458SPeter Avalos 			else if ((infile = fopen(file, "r")) == NULL)
1774b588458SPeter Avalos 				FATAL("can't open file %s", file);
1784b588458SPeter Avalos 			setfval(fnrloc, 0.0);
1794b588458SPeter Avalos 		}
180*1d48fce0SDaniel Fojt 		c = readrec(&buf, &bufsize, infile, innew);
181*1d48fce0SDaniel Fojt 		if (innew)
182*1d48fce0SDaniel Fojt 			innew = false;
1834b588458SPeter Avalos 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1844b588458SPeter Avalos 			if (isrecord) {
1854b588458SPeter Avalos 				if (freeable(fldtab[0]))
1864b588458SPeter Avalos 					xfree(fldtab[0]->sval);
1874b588458SPeter Avalos 				fldtab[0]->sval = buf;	/* buf == record */
1884b588458SPeter Avalos 				fldtab[0]->tval = REC | STR | DONTFREE;
1894b588458SPeter Avalos 				if (is_number(fldtab[0]->sval)) {
1904b588458SPeter Avalos 					fldtab[0]->fval = atof(fldtab[0]->sval);
1914b588458SPeter Avalos 					fldtab[0]->tval |= NUM;
1924b588458SPeter Avalos 				}
1934b588458SPeter Avalos 			}
1944b588458SPeter Avalos 			setfval(nrloc, nrloc->fval+1);
1954b588458SPeter Avalos 			setfval(fnrloc, fnrloc->fval+1);
1964b588458SPeter Avalos 			*pbuf = buf;
1974b588458SPeter Avalos 			*pbufsize = bufsize;
1984b588458SPeter Avalos 			return 1;
1994b588458SPeter Avalos 		}
2004b588458SPeter Avalos 		/* EOF arrived on this file; set up next */
2014b588458SPeter Avalos 		if (infile != stdin)
2024b588458SPeter Avalos 			fclose(infile);
2034b588458SPeter Avalos 		infile = NULL;
2044b588458SPeter Avalos 		argno++;
2054b588458SPeter Avalos 	}
2064b588458SPeter Avalos 	buf[0] = saveb0;
2074b588458SPeter Avalos 	*pbuf = buf;
2084b588458SPeter Avalos 	*pbufsize = savebufsize;
2094b588458SPeter Avalos 	return 0;	/* true end of file */
2104b588458SPeter Avalos }
2114b588458SPeter Avalos 
2124b588458SPeter Avalos void nextfile(void)
2134b588458SPeter Avalos {
2144b588458SPeter Avalos 	if (infile != NULL && infile != stdin)
2154b588458SPeter Avalos 		fclose(infile);
2164b588458SPeter Avalos 	infile = NULL;
2174b588458SPeter Avalos 	argno++;
2184b588458SPeter Avalos }
2194b588458SPeter Avalos 
220*1d48fce0SDaniel Fojt int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag)	/* read one record into buf */
2214b588458SPeter Avalos {
222*1d48fce0SDaniel Fojt 	int sep, c, isrec;
2234b588458SPeter Avalos 	char *rr, *buf = *pbuf;
2244b588458SPeter Avalos 	int bufsize = *pbufsize;
225*1d48fce0SDaniel Fojt 	char *rs = getsval(rsloc);
2264b588458SPeter Avalos 
227*1d48fce0SDaniel Fojt 	if (*rs && rs[1]) {
228*1d48fce0SDaniel Fojt 		bool found;
229*1d48fce0SDaniel Fojt 
230*1d48fce0SDaniel Fojt 		fa *pfa = makedfa(rs, 1);
231*1d48fce0SDaniel Fojt 		if (newflag)
232*1d48fce0SDaniel Fojt 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
233*1d48fce0SDaniel Fojt 		else {
234*1d48fce0SDaniel Fojt 			int tempstat = pfa->initstat;
235*1d48fce0SDaniel Fojt 			pfa->initstat = 2;
236*1d48fce0SDaniel Fojt 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
237*1d48fce0SDaniel Fojt 			pfa->initstat = tempstat;
238*1d48fce0SDaniel Fojt 		}
239*1d48fce0SDaniel Fojt 		if (found)
240*1d48fce0SDaniel Fojt 			setptr(patbeg, '\0');
241*1d48fce0SDaniel Fojt 	} else {
242*1d48fce0SDaniel Fojt 		if ((sep = *rs) == 0) {
2434b588458SPeter Avalos 			sep = '\n';
2444b588458SPeter Avalos 			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
2454b588458SPeter Avalos 				;
2464b588458SPeter Avalos 			if (c != EOF)
2474b588458SPeter Avalos 				ungetc(c, inf);
2484b588458SPeter Avalos 		}
2494b588458SPeter Avalos 		for (rr = buf; ; ) {
2504b588458SPeter Avalos 			for (; (c=getc(inf)) != sep && c != EOF; ) {
2514b588458SPeter Avalos 				if (rr-buf+1 > bufsize)
252*1d48fce0SDaniel Fojt 					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
253*1d48fce0SDaniel Fojt 					    recsize, &rr, "readrec 1"))
2544b588458SPeter Avalos 						FATAL("input record `%.30s...' too long", buf);
2554b588458SPeter Avalos 				*rr++ = c;
2564b588458SPeter Avalos 			}
257*1d48fce0SDaniel Fojt 			if (*rs == sep || c == EOF)
2584b588458SPeter Avalos 				break;
2594b588458SPeter Avalos 			if ((c = getc(inf)) == '\n' || c == EOF)	/* 2 in a row */
2604b588458SPeter Avalos 				break;
261*1d48fce0SDaniel Fojt 			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
262*1d48fce0SDaniel Fojt 			    "readrec 2"))
2634b588458SPeter Avalos 				FATAL("input record `%.30s...' too long", buf);
2644b588458SPeter Avalos 			*rr++ = '\n';
2654b588458SPeter Avalos 			*rr++ = c;
2664b588458SPeter Avalos 		}
2674b588458SPeter Avalos 		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2684b588458SPeter Avalos 			FATAL("input record `%.30s...' too long", buf);
2694b588458SPeter Avalos 		*rr = 0;
270*1d48fce0SDaniel Fojt 	}
2714b588458SPeter Avalos 	*pbuf = buf;
2724b588458SPeter Avalos 	*pbufsize = bufsize;
273*1d48fce0SDaniel Fojt 	isrec = *buf || !feof(inf);
274*1d48fce0SDaniel Fojt 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
275*1d48fce0SDaniel Fojt 	return isrec;
2764b588458SPeter Avalos }
2774b588458SPeter Avalos 
2784b588458SPeter Avalos char *getargv(int n)	/* get ARGV[n] */
2794b588458SPeter Avalos {
2804b588458SPeter Avalos 	Cell *x;
2814b588458SPeter Avalos 	char *s, temp[50];
2824b588458SPeter Avalos 	extern Array *ARGVtab;
2834b588458SPeter Avalos 
284*1d48fce0SDaniel Fojt 	snprintf(temp, sizeof(temp), "%d", n);
285b12bae18SSascha Wildner 	if (lookup(temp, ARGVtab) == NULL)
286b12bae18SSascha Wildner 		return NULL;
2874b588458SPeter Avalos 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
2884b588458SPeter Avalos 	s = getsval(x);
2894b588458SPeter Avalos 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
2904b588458SPeter Avalos 	return s;
2914b588458SPeter Avalos }
2924b588458SPeter Avalos 
2934b588458SPeter Avalos void setclvar(char *s)	/* set var=value from s */
2944b588458SPeter Avalos {
2954b588458SPeter Avalos 	char *p;
2964b588458SPeter Avalos 	Cell *q;
2974b588458SPeter Avalos 
2984b588458SPeter Avalos 	for (p=s; *p != '='; p++)
2994b588458SPeter Avalos 		;
3004b588458SPeter Avalos 	*p++ = 0;
3014b588458SPeter Avalos 	p = qstring(p, '\0');
3024b588458SPeter Avalos 	q = setsymtab(s, p, 0.0, STR, symtab);
3034b588458SPeter Avalos 	setsval(q, p);
3044b588458SPeter Avalos 	if (is_number(q->sval)) {
3054b588458SPeter Avalos 		q->fval = atof(q->sval);
3064b588458SPeter Avalos 		q->tval |= NUM;
3074b588458SPeter Avalos 	}
3084b588458SPeter Avalos 	   dprintf( ("command line set %s to |%s|\n", s, p) );
3094b588458SPeter Avalos }
3104b588458SPeter Avalos 
3114b588458SPeter Avalos 
3124b588458SPeter Avalos void fldbld(void)	/* create fields from current record */
3134b588458SPeter Avalos {
3144b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
3154b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
3160020174dSPeter Avalos 	/* possibly with a final trailing \0 not associated with any field */
3174b588458SPeter Avalos 	char *r, *fr, sep;
3184b588458SPeter Avalos 	Cell *p;
3194b588458SPeter Avalos 	int i, j, n;
3204b588458SPeter Avalos 
3214b588458SPeter Avalos 	if (donefld)
3224b588458SPeter Avalos 		return;
3234b588458SPeter Avalos 	if (!isstr(fldtab[0]))
3244b588458SPeter Avalos 		getsval(fldtab[0]);
3254b588458SPeter Avalos 	r = fldtab[0]->sval;
3264b588458SPeter Avalos 	n = strlen(r);
3274b588458SPeter Avalos 	if (n > fieldssize) {
3284b588458SPeter Avalos 		xfree(fields);
329*1d48fce0SDaniel Fojt 		if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */
3304b588458SPeter Avalos 			FATAL("out of space for fields in fldbld %d", n);
3314b588458SPeter Avalos 		fieldssize = n;
3324b588458SPeter Avalos 	}
3334b588458SPeter Avalos 	fr = fields;
3344b588458SPeter Avalos 	i = 0;	/* number of fields accumulated here */
335*1d48fce0SDaniel Fojt 	if (inputFS == NULL)	/* make sure we have a copy of FS */
336*1d48fce0SDaniel Fojt 		savefs();
3374b588458SPeter Avalos 	if (strlen(inputFS) > 1) {	/* it's a regular expression */
3384b588458SPeter Avalos 		i = refldbld(r, inputFS);
3394b588458SPeter Avalos 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
3404b588458SPeter Avalos 		for (i = 0; ; ) {
3414b588458SPeter Avalos 			while (*r == ' ' || *r == '\t' || *r == '\n')
3424b588458SPeter Avalos 				r++;
3434b588458SPeter Avalos 			if (*r == 0)
3444b588458SPeter Avalos 				break;
3454b588458SPeter Avalos 			i++;
3464b588458SPeter Avalos 			if (i > nfields)
3474b588458SPeter Avalos 				growfldtab(i);
3484b588458SPeter Avalos 			if (freeable(fldtab[i]))
3494b588458SPeter Avalos 				xfree(fldtab[i]->sval);
3504b588458SPeter Avalos 			fldtab[i]->sval = fr;
3514b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
3524b588458SPeter Avalos 			do
3534b588458SPeter Avalos 				*fr++ = *r++;
3544b588458SPeter Avalos 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
3554b588458SPeter Avalos 			*fr++ = 0;
3564b588458SPeter Avalos 		}
3574b588458SPeter Avalos 		*fr = 0;
3584b588458SPeter Avalos 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
359*1d48fce0SDaniel Fojt 		for (i = 0; *r != '\0'; r += n) {
360*1d48fce0SDaniel Fojt 			char buf[MB_LEN_MAX + 1];
361*1d48fce0SDaniel Fojt 
3624b588458SPeter Avalos 			i++;
3634b588458SPeter Avalos 			if (i > nfields)
3644b588458SPeter Avalos 				growfldtab(i);
3654b588458SPeter Avalos 			if (freeable(fldtab[i]))
3664b588458SPeter Avalos 				xfree(fldtab[i]->sval);
367*1d48fce0SDaniel Fojt 			n = mblen(r, MB_LEN_MAX);
368*1d48fce0SDaniel Fojt 			if (n < 0)
369*1d48fce0SDaniel Fojt 				n = 1;
370*1d48fce0SDaniel Fojt 			memcpy(buf, r, n);
371*1d48fce0SDaniel Fojt 			buf[n] = '\0';
3724b588458SPeter Avalos 			fldtab[i]->sval = tostring(buf);
3734b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR;
3744b588458SPeter Avalos 		}
3754b588458SPeter Avalos 		*fr = 0;
3764b588458SPeter Avalos 	} else if (*r != 0) {	/* if 0, it's a null field */
3774b588458SPeter Avalos 		/* subtlecase : if length(FS) == 1 && length(RS > 0)
3784b588458SPeter Avalos 		 * \n is NOT a field separator (cf awk book 61,84).
3794b588458SPeter Avalos 		 * this variable is tested in the inner while loop.
3804b588458SPeter Avalos 		 */
3814b588458SPeter Avalos 		int rtest = '\n';  /* normal case */
3824b588458SPeter Avalos 		if (strlen(*RS) > 0)
3834b588458SPeter Avalos 			rtest = '\0';
3844b588458SPeter Avalos 		for (;;) {
3854b588458SPeter Avalos 			i++;
3864b588458SPeter Avalos 			if (i > nfields)
3874b588458SPeter Avalos 				growfldtab(i);
3884b588458SPeter Avalos 			if (freeable(fldtab[i]))
3894b588458SPeter Avalos 				xfree(fldtab[i]->sval);
3904b588458SPeter Avalos 			fldtab[i]->sval = fr;
3914b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
3924b588458SPeter Avalos 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
3934b588458SPeter Avalos 				*fr++ = *r++;
3944b588458SPeter Avalos 			*fr++ = 0;
3954b588458SPeter Avalos 			if (*r++ == 0)
3964b588458SPeter Avalos 				break;
3974b588458SPeter Avalos 		}
3984b588458SPeter Avalos 		*fr = 0;
3994b588458SPeter Avalos 	}
4004b588458SPeter Avalos 	if (i > nfields)
4014b588458SPeter Avalos 		FATAL("record `%.30s...' has too many fields; can't happen", r);
4024b588458SPeter Avalos 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
4034b588458SPeter Avalos 	lastfld = i;
404*1d48fce0SDaniel Fojt 	donefld = true;
4054b588458SPeter Avalos 	for (j = 1; j <= lastfld; j++) {
4064b588458SPeter Avalos 		p = fldtab[j];
4074b588458SPeter Avalos 		if(is_number(p->sval)) {
4084b588458SPeter Avalos 			p->fval = atof(p->sval);
4094b588458SPeter Avalos 			p->tval |= NUM;
4104b588458SPeter Avalos 		}
4114b588458SPeter Avalos 	}
4124b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) lastfld);
413*1d48fce0SDaniel Fojt 	donerec = true; /* restore */
4144b588458SPeter Avalos 	if (dbg) {
4154b588458SPeter Avalos 		for (j = 0; j <= lastfld; j++) {
4164b588458SPeter Avalos 			p = fldtab[j];
4174b588458SPeter Avalos 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
4184b588458SPeter Avalos 		}
4194b588458SPeter Avalos 	}
4204b588458SPeter Avalos }
4214b588458SPeter Avalos 
4224b588458SPeter Avalos void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
4234b588458SPeter Avalos {				/* nvals remain intact */
4244b588458SPeter Avalos 	Cell *p;
4254b588458SPeter Avalos 	int i;
4264b588458SPeter Avalos 
4274b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
4284b588458SPeter Avalos 		p = fldtab[i];
4294b588458SPeter Avalos 		if (freeable(p))
4304b588458SPeter Avalos 			xfree(p->sval);
431*1d48fce0SDaniel Fojt 		p->sval = EMPTY,
4324b588458SPeter Avalos 		p->tval = FLD | STR | DONTFREE;
4334b588458SPeter Avalos 	}
4344b588458SPeter Avalos }
4354b588458SPeter Avalos 
4364b588458SPeter Avalos void newfld(int n)	/* add field n after end of existing lastfld */
4374b588458SPeter Avalos {
4384b588458SPeter Avalos 	if (n > nfields)
4394b588458SPeter Avalos 		growfldtab(n);
4404b588458SPeter Avalos 	cleanfld(lastfld+1, n);
4414b588458SPeter Avalos 	lastfld = n;
4424b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) n);
4434b588458SPeter Avalos }
4444b588458SPeter Avalos 
445*1d48fce0SDaniel Fojt void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
446*1d48fce0SDaniel Fojt {
447*1d48fce0SDaniel Fojt 	if (n < 0)
448*1d48fce0SDaniel Fojt 		FATAL("cannot set NF to a negative value");
449*1d48fce0SDaniel Fojt 	if (n > nfields)
450*1d48fce0SDaniel Fojt 		growfldtab(n);
451*1d48fce0SDaniel Fojt 
452*1d48fce0SDaniel Fojt 	if (lastfld < n)
453*1d48fce0SDaniel Fojt 	    cleanfld(lastfld+1, n);
454*1d48fce0SDaniel Fojt 	else
455*1d48fce0SDaniel Fojt 	    cleanfld(n+1, lastfld);
456*1d48fce0SDaniel Fojt 
457*1d48fce0SDaniel Fojt 	lastfld = n;
458*1d48fce0SDaniel Fojt }
459*1d48fce0SDaniel Fojt 
4604b588458SPeter Avalos Cell *fieldadr(int n)	/* get nth field */
4614b588458SPeter Avalos {
4624b588458SPeter Avalos 	if (n < 0)
4634b588458SPeter Avalos 		FATAL("trying to access out of range field %d", n);
4644b588458SPeter Avalos 	if (n > nfields)	/* fields after NF are empty */
4654b588458SPeter Avalos 		growfldtab(n);	/* but does not increase NF */
4664b588458SPeter Avalos 	return(fldtab[n]);
4674b588458SPeter Avalos }
4684b588458SPeter Avalos 
4694b588458SPeter Avalos void growfldtab(int n)	/* make new fields up to at least $n */
4704b588458SPeter Avalos {
4714b588458SPeter Avalos 	int nf = 2 * nfields;
4724b588458SPeter Avalos 	size_t s;
4734b588458SPeter Avalos 
4744b588458SPeter Avalos 	if (n > nf)
4754b588458SPeter Avalos 		nf = n;
4764b588458SPeter Avalos 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
477*1d48fce0SDaniel Fojt 	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
478*1d48fce0SDaniel Fojt 		fldtab = realloc(fldtab, s);
4794b588458SPeter Avalos 	else					/* overflow sizeof int */
4804b588458SPeter Avalos 		xfree(fldtab);	/* make it null */
4814b588458SPeter Avalos 	if (fldtab == NULL)
4824b588458SPeter Avalos 		FATAL("out of space creating %d fields", nf);
4834b588458SPeter Avalos 	makefields(nfields+1, nf);
4844b588458SPeter Avalos 	nfields = nf;
4854b588458SPeter Avalos }
4864b588458SPeter Avalos 
4874b588458SPeter Avalos int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
4884b588458SPeter Avalos {
4894b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
4904b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
4914b588458SPeter Avalos 	char *fr;
4924b588458SPeter Avalos 	int i, tempstat, n;
4934b588458SPeter Avalos 	fa *pfa;
4944b588458SPeter Avalos 
4954b588458SPeter Avalos 	n = strlen(rec);
4964b588458SPeter Avalos 	if (n > fieldssize) {
4974b588458SPeter Avalos 		xfree(fields);
498*1d48fce0SDaniel Fojt 		if ((fields = malloc(n+1)) == NULL)
4994b588458SPeter Avalos 			FATAL("out of space for fields in refldbld %d", n);
5004b588458SPeter Avalos 		fieldssize = n;
5014b588458SPeter Avalos 	}
5024b588458SPeter Avalos 	fr = fields;
5034b588458SPeter Avalos 	*fr = '\0';
5044b588458SPeter Avalos 	if (*rec == '\0')
5054b588458SPeter Avalos 		return 0;
5064b588458SPeter Avalos 	pfa = makedfa(fs, 1);
5074b588458SPeter Avalos 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
5084b588458SPeter Avalos 	tempstat = pfa->initstat;
5094b588458SPeter Avalos 	for (i = 1; ; i++) {
5104b588458SPeter Avalos 		if (i > nfields)
5114b588458SPeter Avalos 			growfldtab(i);
5124b588458SPeter Avalos 		if (freeable(fldtab[i]))
5134b588458SPeter Avalos 			xfree(fldtab[i]->sval);
5144b588458SPeter Avalos 		fldtab[i]->tval = FLD | STR | DONTFREE;
5154b588458SPeter Avalos 		fldtab[i]->sval = fr;
5164b588458SPeter Avalos 		   dprintf( ("refldbld: i=%d\n", i) );
5174b588458SPeter Avalos 		if (nematch(pfa, rec)) {
5184b588458SPeter Avalos 			pfa->initstat = 2;	/* horrible coupling to b.c */
5194b588458SPeter Avalos 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
5204b588458SPeter Avalos 			strncpy(fr, rec, patbeg-rec);
5214b588458SPeter Avalos 			fr += patbeg - rec + 1;
5224b588458SPeter Avalos 			*(fr-1) = '\0';
5234b588458SPeter Avalos 			rec = patbeg + patlen;
5244b588458SPeter Avalos 		} else {
5254b588458SPeter Avalos 			   dprintf( ("no match %s\n", rec) );
5264b588458SPeter Avalos 			strcpy(fr, rec);
5274b588458SPeter Avalos 			pfa->initstat = tempstat;
5284b588458SPeter Avalos 			break;
5294b588458SPeter Avalos 		}
5304b588458SPeter Avalos 	}
5314b588458SPeter Avalos 	return i;
5324b588458SPeter Avalos }
5334b588458SPeter Avalos 
5344b588458SPeter Avalos void recbld(void)	/* create $0 from $1..$NF if necessary */
5354b588458SPeter Avalos {
5364b588458SPeter Avalos 	int i;
5374b588458SPeter Avalos 	char *r, *p;
538*1d48fce0SDaniel Fojt 	char *sep = getsval(ofsloc);
5394b588458SPeter Avalos 
540*1d48fce0SDaniel Fojt 	if (donerec)
5414b588458SPeter Avalos 		return;
5424b588458SPeter Avalos 	r = record;
5434b588458SPeter Avalos 	for (i = 1; i <= *NF; i++) {
5444b588458SPeter Avalos 		p = getsval(fldtab[i]);
5454b588458SPeter Avalos 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
5464b588458SPeter Avalos 			FATAL("created $0 `%.30s...' too long", record);
5474b588458SPeter Avalos 		while ((*r = *p++) != 0)
5484b588458SPeter Avalos 			r++;
5494b588458SPeter Avalos 		if (i < *NF) {
550*1d48fce0SDaniel Fojt 			if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
5514b588458SPeter Avalos 				FATAL("created $0 `%.30s...' too long", record);
552*1d48fce0SDaniel Fojt 			for (p = sep; (*r = *p++) != 0; )
5534b588458SPeter Avalos 				r++;
5544b588458SPeter Avalos 		}
5554b588458SPeter Avalos 	}
5564b588458SPeter Avalos 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
5574b588458SPeter Avalos 		FATAL("built giant record `%.30s...'", record);
5584b588458SPeter Avalos 	*r = '\0';
559b12bae18SSascha Wildner 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
5604b588458SPeter Avalos 
5614b588458SPeter Avalos 	if (freeable(fldtab[0]))
5624b588458SPeter Avalos 		xfree(fldtab[0]->sval);
5634b588458SPeter Avalos 	fldtab[0]->tval = REC | STR | DONTFREE;
5644b588458SPeter Avalos 	fldtab[0]->sval = record;
5654b588458SPeter Avalos 
566b12bae18SSascha Wildner 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
5674b588458SPeter Avalos 	   dprintf( ("recbld = |%s|\n", record) );
568*1d48fce0SDaniel Fojt 	donerec = true;
5694b588458SPeter Avalos }
5704b588458SPeter Avalos 
5714b588458SPeter Avalos int	errorflag	= 0;
5724b588458SPeter Avalos 
5734b588458SPeter Avalos void yyerror(const char *s)
5744b588458SPeter Avalos {
5754b588458SPeter Avalos 	SYNTAX("%s", s);
5764b588458SPeter Avalos }
5774b588458SPeter Avalos 
5784b588458SPeter Avalos void SYNTAX(const char *fmt, ...)
5794b588458SPeter Avalos {
5804b588458SPeter Avalos 	extern char *cmdname, *curfname;
5814b588458SPeter Avalos 	static int been_here = 0;
5824b588458SPeter Avalos 	va_list varg;
5834b588458SPeter Avalos 
5844b588458SPeter Avalos 	if (been_here++ > 2)
5854b588458SPeter Avalos 		return;
5864b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
5874b588458SPeter Avalos 	va_start(varg, fmt);
5884b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
5894b588458SPeter Avalos 	va_end(varg);
5904b588458SPeter Avalos 	fprintf(stderr, " at source line %d", lineno);
5914b588458SPeter Avalos 	if (curfname != NULL)
5924b588458SPeter Avalos 		fprintf(stderr, " in function %s", curfname);
593*1d48fce0SDaniel Fojt 	if (compile_time == COMPILING && cursource() != NULL)
5944b588458SPeter Avalos 		fprintf(stderr, " source file %s", cursource());
5954b588458SPeter Avalos 	fprintf(stderr, "\n");
5964b588458SPeter Avalos 	errorflag = 2;
5974b588458SPeter Avalos 	eprint();
5984b588458SPeter Avalos }
5994b588458SPeter Avalos 
6004b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt;
6014b588458SPeter Avalos 
6024b588458SPeter Avalos void bracecheck(void)
6034b588458SPeter Avalos {
6044b588458SPeter Avalos 	int c;
6054b588458SPeter Avalos 	static int beenhere = 0;
6064b588458SPeter Avalos 
6074b588458SPeter Avalos 	if (beenhere++)
6084b588458SPeter Avalos 		return;
6094b588458SPeter Avalos 	while ((c = input()) != EOF && c != '\0')
6104b588458SPeter Avalos 		bclass(c);
6114b588458SPeter Avalos 	bcheck2(bracecnt, '{', '}');
6124b588458SPeter Avalos 	bcheck2(brackcnt, '[', ']');
6134b588458SPeter Avalos 	bcheck2(parencnt, '(', ')');
6144b588458SPeter Avalos }
6154b588458SPeter Avalos 
6164b588458SPeter Avalos void bcheck2(int n, int c1, int c2)
6174b588458SPeter Avalos {
6184b588458SPeter Avalos 	if (n == 1)
6194b588458SPeter Avalos 		fprintf(stderr, "\tmissing %c\n", c2);
6204b588458SPeter Avalos 	else if (n > 1)
6214b588458SPeter Avalos 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
6224b588458SPeter Avalos 	else if (n == -1)
6234b588458SPeter Avalos 		fprintf(stderr, "\textra %c\n", c2);
6244b588458SPeter Avalos 	else if (n < -1)
6254b588458SPeter Avalos 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
6264b588458SPeter Avalos }
6274b588458SPeter Avalos 
6284b588458SPeter Avalos void FATAL(const char *fmt, ...)
6294b588458SPeter Avalos {
6304b588458SPeter Avalos 	extern char *cmdname;
6314b588458SPeter Avalos 	va_list varg;
6324b588458SPeter Avalos 
6334b588458SPeter Avalos 	fflush(stdout);
6344b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
6354b588458SPeter Avalos 	va_start(varg, fmt);
6364b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
6374b588458SPeter Avalos 	va_end(varg);
6384b588458SPeter Avalos 	error();
6394b588458SPeter Avalos 	if (dbg > 1)		/* core dump if serious debugging on */
6404b588458SPeter Avalos 		abort();
6414b588458SPeter Avalos 	exit(2);
6424b588458SPeter Avalos }
6434b588458SPeter Avalos 
6444b588458SPeter Avalos void WARNING(const char *fmt, ...)
6454b588458SPeter Avalos {
6464b588458SPeter Avalos 	extern char *cmdname;
6474b588458SPeter Avalos 	va_list varg;
6484b588458SPeter Avalos 
6494b588458SPeter Avalos 	fflush(stdout);
6504b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
6514b588458SPeter Avalos 	va_start(varg, fmt);
6524b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
6534b588458SPeter Avalos 	va_end(varg);
6544b588458SPeter Avalos 	error();
6554b588458SPeter Avalos }
6564b588458SPeter Avalos 
6574b588458SPeter Avalos void error()
6584b588458SPeter Avalos {
6594b588458SPeter Avalos 	extern Node *curnode;
6604b588458SPeter Avalos 
6614b588458SPeter Avalos 	fprintf(stderr, "\n");
662*1d48fce0SDaniel Fojt 	if (compile_time != ERROR_PRINTING) {
663*1d48fce0SDaniel Fojt 		if (NR && *NR > 0) {
6644b588458SPeter Avalos 			fprintf(stderr, " input record number %d", (int) (*FNR));
6654b588458SPeter Avalos 			if (strcmp(*FILENAME, "-") != 0)
6664b588458SPeter Avalos 				fprintf(stderr, ", file %s", *FILENAME);
6674b588458SPeter Avalos 			fprintf(stderr, "\n");
6684b588458SPeter Avalos 		}
669*1d48fce0SDaniel Fojt 		if (curnode)
6704b588458SPeter Avalos 			fprintf(stderr, " source line number %d", curnode->lineno);
671*1d48fce0SDaniel Fojt 		else if (lineno)
6724b588458SPeter Avalos 			fprintf(stderr, " source line number %d", lineno);
673*1d48fce0SDaniel Fojt 	}
674*1d48fce0SDaniel Fojt 
675*1d48fce0SDaniel Fojt 	if (compile_time == COMPILING && cursource() != NULL)
6764b588458SPeter Avalos 		fprintf(stderr, " source file %s", cursource());
6774b588458SPeter Avalos 	fprintf(stderr, "\n");
6784b588458SPeter Avalos 	eprint();
6794b588458SPeter Avalos }
6804b588458SPeter Avalos 
6814b588458SPeter Avalos void eprint(void)	/* try to print context around error */
6824b588458SPeter Avalos {
6834b588458SPeter Avalos 	char *p, *q;
6844b588458SPeter Avalos 	int c;
6854b588458SPeter Avalos 	static int been_here = 0;
6864b588458SPeter Avalos 	extern char ebuf[], *ep;
6874b588458SPeter Avalos 
688*1d48fce0SDaniel Fojt 	if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
689*1d48fce0SDaniel Fojt 		return;
690*1d48fce0SDaniel Fojt 	if (ebuf == ep)
6914b588458SPeter Avalos 		return;
6924b588458SPeter Avalos 	p = ep - 1;
6934b588458SPeter Avalos 	if (p > ebuf && *p == '\n')
6944b588458SPeter Avalos 		p--;
6954b588458SPeter Avalos 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
6964b588458SPeter Avalos 		;
6974b588458SPeter Avalos 	while (*p == '\n')
6984b588458SPeter Avalos 		p++;
6994b588458SPeter Avalos 	fprintf(stderr, " context is\n\t");
7004b588458SPeter Avalos 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
7014b588458SPeter Avalos 		;
7024b588458SPeter Avalos 	for ( ; p < q; p++)
7034b588458SPeter Avalos 		if (*p)
7044b588458SPeter Avalos 			putc(*p, stderr);
7054b588458SPeter Avalos 	fprintf(stderr, " >>> ");
7064b588458SPeter Avalos 	for ( ; p < ep; p++)
7074b588458SPeter Avalos 		if (*p)
7084b588458SPeter Avalos 			putc(*p, stderr);
7094b588458SPeter Avalos 	fprintf(stderr, " <<< ");
7104b588458SPeter Avalos 	if (*ep)
7114b588458SPeter Avalos 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
7124b588458SPeter Avalos 			putc(c, stderr);
7134b588458SPeter Avalos 			bclass(c);
7144b588458SPeter Avalos 		}
7154b588458SPeter Avalos 	putc('\n', stderr);
7164b588458SPeter Avalos 	ep = ebuf;
7174b588458SPeter Avalos }
7184b588458SPeter Avalos 
7194b588458SPeter Avalos void bclass(int c)
7204b588458SPeter Avalos {
7214b588458SPeter Avalos 	switch (c) {
7224b588458SPeter Avalos 	case '{': bracecnt++; break;
7234b588458SPeter Avalos 	case '}': bracecnt--; break;
7244b588458SPeter Avalos 	case '[': brackcnt++; break;
7254b588458SPeter Avalos 	case ']': brackcnt--; break;
7264b588458SPeter Avalos 	case '(': parencnt++; break;
7274b588458SPeter Avalos 	case ')': parencnt--; break;
7284b588458SPeter Avalos 	}
7294b588458SPeter Avalos }
7304b588458SPeter Avalos 
7314b588458SPeter Avalos double errcheck(double x, const char *s)
7324b588458SPeter Avalos {
7334b588458SPeter Avalos 
7344b588458SPeter Avalos 	if (errno == EDOM) {
7354b588458SPeter Avalos 		errno = 0;
7364b588458SPeter Avalos 		WARNING("%s argument out of domain", s);
7374b588458SPeter Avalos 		x = 1;
7384b588458SPeter Avalos 	} else if (errno == ERANGE) {
7394b588458SPeter Avalos 		errno = 0;
7404b588458SPeter Avalos 		WARNING("%s result out of range", s);
7414b588458SPeter Avalos 		x = 1;
7424b588458SPeter Avalos 	}
7434b588458SPeter Avalos 	return x;
7444b588458SPeter Avalos }
7454b588458SPeter Avalos 
7464b588458SPeter Avalos int isclvar(const char *s)	/* is s of form var=something ? */
7474b588458SPeter Avalos {
7484b588458SPeter Avalos 	const char *os = s;
7494b588458SPeter Avalos 
7504b588458SPeter Avalos 	if (!isalpha((uschar) *s) && *s != '_')
7514b588458SPeter Avalos 		return 0;
7524b588458SPeter Avalos 	for ( ; *s; s++)
7534b588458SPeter Avalos 		if (!(isalnum((uschar) *s) || *s == '_'))
7544b588458SPeter Avalos 			break;
755*1d48fce0SDaniel Fojt 	return *s == '=' && s > os;
7564b588458SPeter Avalos }
7574b588458SPeter Avalos 
7584b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */
7594b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
7604b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */
761*1d48fce0SDaniel Fojt /* well, not quite. As of C99, hex floating point is allowed. so this is
762*1d48fce0SDaniel Fojt  * a bit of a mess.
763*1d48fce0SDaniel Fojt  */
7644b588458SPeter Avalos 
7654b588458SPeter Avalos #include <math.h>
7664b588458SPeter Avalos int is_number(const char *s)
7674b588458SPeter Avalos {
7684b588458SPeter Avalos 	double r;
7694b588458SPeter Avalos 	char *ep;
7704b588458SPeter Avalos 	errno = 0;
7714b588458SPeter Avalos 	r = strtod(s, &ep);
7724b588458SPeter Avalos 	if (ep == s || r == HUGE_VAL || errno == ERANGE)
7734b588458SPeter Avalos 		return 0;
774*1d48fce0SDaniel Fojt 	/* allow \r as well. windows files aren't going to go away. */
775*1d48fce0SDaniel Fojt 	while (*ep == ' ' || *ep == '\t' || *ep == '\n' || *ep == '\r')
7764b588458SPeter Avalos 		ep++;
7774b588458SPeter Avalos 	if (*ep == '\0')
7784b588458SPeter Avalos 		return 1;
7794b588458SPeter Avalos 	else
7804b588458SPeter Avalos 		return 0;
7814b588458SPeter Avalos }
782