xref: /aosp_15_r20/external/one-true-awk/lib.c (revision 9a7741de182b2776d7b30d6355f2585c0780a51b)
1*9a7741deSElliott Hughes /****************************************************************
2*9a7741deSElliott Hughes Copyright (C) Lucent Technologies 1997
3*9a7741deSElliott Hughes All Rights Reserved
4*9a7741deSElliott Hughes 
5*9a7741deSElliott Hughes Permission to use, copy, modify, and distribute this software and
6*9a7741deSElliott Hughes its documentation for any purpose and without fee is hereby
7*9a7741deSElliott Hughes granted, provided that the above copyright notice appear in all
8*9a7741deSElliott Hughes copies and that both that the copyright notice and this
9*9a7741deSElliott Hughes permission notice and warranty disclaimer appear in supporting
10*9a7741deSElliott Hughes documentation, and that the name Lucent Technologies or any of
11*9a7741deSElliott Hughes its entities not be used in advertising or publicity pertaining
12*9a7741deSElliott Hughes to distribution of the software without specific, written prior
13*9a7741deSElliott Hughes permission.
14*9a7741deSElliott Hughes 
15*9a7741deSElliott Hughes LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*9a7741deSElliott Hughes INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*9a7741deSElliott Hughes IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*9a7741deSElliott Hughes SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*9a7741deSElliott Hughes WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*9a7741deSElliott Hughes IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*9a7741deSElliott Hughes ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*9a7741deSElliott Hughes THIS SOFTWARE.
23*9a7741deSElliott Hughes ****************************************************************/
24*9a7741deSElliott Hughes 
25*9a7741deSElliott Hughes #define DEBUG
26*9a7741deSElliott Hughes #include <stdio.h>
27*9a7741deSElliott Hughes #include <string.h>
28*9a7741deSElliott Hughes #include <strings.h>
29*9a7741deSElliott Hughes #include <ctype.h>
30*9a7741deSElliott Hughes #include <errno.h>
31*9a7741deSElliott Hughes #include <stdlib.h>
32*9a7741deSElliott Hughes #include <stdarg.h>
33*9a7741deSElliott Hughes #include <limits.h>
34*9a7741deSElliott Hughes #include <math.h>
35*9a7741deSElliott Hughes #include "awk.h"
36*9a7741deSElliott Hughes 
37*9a7741deSElliott Hughes extern int u8_nextlen(const char *s);
38*9a7741deSElliott Hughes 
39*9a7741deSElliott Hughes char	EMPTY[] = { '\0' };
40*9a7741deSElliott Hughes FILE	*infile	= NULL;
41*9a7741deSElliott Hughes bool	innew;		/* true = infile has not been read by readrec */
42*9a7741deSElliott Hughes char	*file	= EMPTY;
43*9a7741deSElliott Hughes char	*record;
44*9a7741deSElliott Hughes int	recsize	= RECSIZE;
45*9a7741deSElliott Hughes char	*fields;
46*9a7741deSElliott Hughes int	fieldssize = RECSIZE;
47*9a7741deSElliott Hughes 
48*9a7741deSElliott Hughes Cell	**fldtab;	/* pointers to Cells */
49*9a7741deSElliott Hughes static size_t	len_inputFS = 0;
50*9a7741deSElliott Hughes static char	*inputFS = NULL; /* FS at time of input, for field splitting */
51*9a7741deSElliott Hughes 
52*9a7741deSElliott Hughes #define	MAXFLD	2
53*9a7741deSElliott Hughes int	nfields	= MAXFLD;	/* last allocated slot for $i */
54*9a7741deSElliott Hughes 
55*9a7741deSElliott Hughes bool	donefld;	/* true = implies rec broken into fields */
56*9a7741deSElliott Hughes bool	donerec;	/* true = record is valid (no flds have changed) */
57*9a7741deSElliott Hughes 
58*9a7741deSElliott Hughes int	lastfld	= 0;	/* last used field */
59*9a7741deSElliott Hughes int	argno	= 1;	/* current input argument number */
60*9a7741deSElliott Hughes extern	Awkfloat *ARGC;
61*9a7741deSElliott Hughes 
62*9a7741deSElliott Hughes static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
63*9a7741deSElliott Hughes static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
64*9a7741deSElliott Hughes 
recinit(unsigned int n)65*9a7741deSElliott Hughes void recinit(unsigned int n)
66*9a7741deSElliott Hughes {
67*9a7741deSElliott Hughes 	if ( (record = (char *) malloc(n)) == NULL
68*9a7741deSElliott Hughes 	  || (fields = (char *) malloc(n+1)) == NULL
69*9a7741deSElliott Hughes 	  || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
70*9a7741deSElliott Hughes 	  || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
71*9a7741deSElliott Hughes 		FATAL("out of space for $0 and fields");
72*9a7741deSElliott Hughes 	*record = '\0';
73*9a7741deSElliott Hughes 	*fldtab[0] = dollar0;
74*9a7741deSElliott Hughes 	fldtab[0]->sval = record;
75*9a7741deSElliott Hughes 	fldtab[0]->nval = tostring("0");
76*9a7741deSElliott Hughes 	makefields(1, nfields);
77*9a7741deSElliott Hughes }
78*9a7741deSElliott Hughes 
makefields(int n1,int n2)79*9a7741deSElliott Hughes void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
80*9a7741deSElliott Hughes {
81*9a7741deSElliott Hughes 	char temp[50];
82*9a7741deSElliott Hughes 	int i;
83*9a7741deSElliott Hughes 
84*9a7741deSElliott Hughes 	for (i = n1; i <= n2; i++) {
85*9a7741deSElliott Hughes 		fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
86*9a7741deSElliott Hughes 		if (fldtab[i] == NULL)
87*9a7741deSElliott Hughes 			FATAL("out of space in makefields %d", i);
88*9a7741deSElliott Hughes 		*fldtab[i] = dollar1;
89*9a7741deSElliott Hughes 		snprintf(temp, sizeof(temp), "%d", i);
90*9a7741deSElliott Hughes 		fldtab[i]->nval = tostring(temp);
91*9a7741deSElliott Hughes 	}
92*9a7741deSElliott Hughes }
93*9a7741deSElliott Hughes 
initgetrec(void)94*9a7741deSElliott Hughes void initgetrec(void)
95*9a7741deSElliott Hughes {
96*9a7741deSElliott Hughes 	int i;
97*9a7741deSElliott Hughes 	char *p;
98*9a7741deSElliott Hughes 
99*9a7741deSElliott Hughes 	for (i = 1; i < *ARGC; i++) {
100*9a7741deSElliott Hughes 		p = getargv(i); /* find 1st real filename */
101*9a7741deSElliott Hughes 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
102*9a7741deSElliott Hughes 			argno++;
103*9a7741deSElliott Hughes 			continue;
104*9a7741deSElliott Hughes 		}
105*9a7741deSElliott Hughes 		if (!isclvar(p)) {
106*9a7741deSElliott Hughes 			setsval(lookup("FILENAME", symtab), p);
107*9a7741deSElliott Hughes 			return;
108*9a7741deSElliott Hughes 		}
109*9a7741deSElliott Hughes 		setclvar(p);	/* a commandline assignment before filename */
110*9a7741deSElliott Hughes 		argno++;
111*9a7741deSElliott Hughes 	}
112*9a7741deSElliott Hughes 	infile = stdin;		/* no filenames, so use stdin */
113*9a7741deSElliott Hughes 	innew = true;
114*9a7741deSElliott Hughes }
115*9a7741deSElliott Hughes 
116*9a7741deSElliott Hughes /*
117*9a7741deSElliott Hughes  * POSIX specifies that fields are supposed to be evaluated as if they were
118*9a7741deSElliott Hughes  * split using the value of FS at the time that the record's value ($0) was
119*9a7741deSElliott Hughes  * read.
120*9a7741deSElliott Hughes  *
121*9a7741deSElliott Hughes  * Since field-splitting is done lazily, we save the current value of FS
122*9a7741deSElliott Hughes  * whenever a new record is read in (implicitly or via getline), or when
123*9a7741deSElliott Hughes  * a new value is assigned to $0.
124*9a7741deSElliott Hughes  */
savefs(void)125*9a7741deSElliott Hughes void savefs(void)
126*9a7741deSElliott Hughes {
127*9a7741deSElliott Hughes 	size_t len;
128*9a7741deSElliott Hughes 	if ((len = strlen(getsval(fsloc))) < len_inputFS) {
129*9a7741deSElliott Hughes 		strcpy(inputFS, *FS);	/* for subsequent field splitting */
130*9a7741deSElliott Hughes 		return;
131*9a7741deSElliott Hughes 	}
132*9a7741deSElliott Hughes 
133*9a7741deSElliott Hughes 	len_inputFS = len + 1;
134*9a7741deSElliott Hughes 	inputFS = (char *) realloc(inputFS, len_inputFS);
135*9a7741deSElliott Hughes 	if (inputFS == NULL)
136*9a7741deSElliott Hughes 		FATAL("field separator %.10s... is too long", *FS);
137*9a7741deSElliott Hughes 	memcpy(inputFS, *FS, len_inputFS);
138*9a7741deSElliott Hughes }
139*9a7741deSElliott Hughes 
140*9a7741deSElliott Hughes static bool firsttime = true;
141*9a7741deSElliott Hughes 
getrec(char ** pbuf,int * pbufsize,bool isrecord)142*9a7741deSElliott Hughes int getrec(char **pbuf, int *pbufsize, bool isrecord)	/* get next input record */
143*9a7741deSElliott Hughes {			/* note: cares whether buf == record */
144*9a7741deSElliott Hughes 	int c;
145*9a7741deSElliott Hughes 	char *buf = *pbuf;
146*9a7741deSElliott Hughes 	uschar saveb0;
147*9a7741deSElliott Hughes 	int bufsize = *pbufsize, savebufsize = bufsize;
148*9a7741deSElliott Hughes 
149*9a7741deSElliott Hughes 	if (firsttime) {
150*9a7741deSElliott Hughes 		firsttime = false;
151*9a7741deSElliott Hughes 		initgetrec();
152*9a7741deSElliott Hughes 	}
153*9a7741deSElliott Hughes 	DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
154*9a7741deSElliott Hughes 		*RS, *FS, *ARGC, *FILENAME);
155*9a7741deSElliott Hughes 	saveb0 = buf[0];
156*9a7741deSElliott Hughes 	buf[0] = 0;
157*9a7741deSElliott Hughes 	while (argno < *ARGC || infile == stdin) {
158*9a7741deSElliott Hughes 		DPRINTF("argno=%d, file=|%s|\n", argno, file);
159*9a7741deSElliott Hughes 		if (infile == NULL) {	/* have to open a new file */
160*9a7741deSElliott Hughes 			file = getargv(argno);
161*9a7741deSElliott Hughes 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
162*9a7741deSElliott Hughes 				argno++;
163*9a7741deSElliott Hughes 				continue;
164*9a7741deSElliott Hughes 			}
165*9a7741deSElliott Hughes 			if (isclvar(file)) {	/* a var=value arg */
166*9a7741deSElliott Hughes 				setclvar(file);
167*9a7741deSElliott Hughes 				argno++;
168*9a7741deSElliott Hughes 				continue;
169*9a7741deSElliott Hughes 			}
170*9a7741deSElliott Hughes 			*FILENAME = file;
171*9a7741deSElliott Hughes 			DPRINTF("opening file %s\n", file);
172*9a7741deSElliott Hughes 			if (*file == '-' && *(file+1) == '\0')
173*9a7741deSElliott Hughes 				infile = stdin;
174*9a7741deSElliott Hughes 			else if ((infile = fopen(file, "r")) == NULL)
175*9a7741deSElliott Hughes 				FATAL("can't open file %s", file);
176*9a7741deSElliott Hughes 			innew = true;
177*9a7741deSElliott Hughes 			setfval(fnrloc, 0.0);
178*9a7741deSElliott Hughes 		}
179*9a7741deSElliott Hughes 		c = readrec(&buf, &bufsize, infile, innew);
180*9a7741deSElliott Hughes 		if (innew)
181*9a7741deSElliott Hughes 			innew = false;
182*9a7741deSElliott Hughes 		if (c != 0 || buf[0] != '\0') {	/* normal record */
183*9a7741deSElliott Hughes 			if (isrecord) {
184*9a7741deSElliott Hughes 				double result;
185*9a7741deSElliott Hughes 
186*9a7741deSElliott Hughes 				if (freeable(fldtab[0]))
187*9a7741deSElliott Hughes 					xfree(fldtab[0]->sval);
188*9a7741deSElliott Hughes 				fldtab[0]->sval = buf;	/* buf == record */
189*9a7741deSElliott Hughes 				fldtab[0]->tval = REC | STR | DONTFREE;
190*9a7741deSElliott Hughes 				if (is_number(fldtab[0]->sval, & result)) {
191*9a7741deSElliott Hughes 					fldtab[0]->fval = result;
192*9a7741deSElliott Hughes 					fldtab[0]->tval |= NUM;
193*9a7741deSElliott Hughes 				}
194*9a7741deSElliott Hughes 				donefld = false;
195*9a7741deSElliott Hughes 				donerec = true;
196*9a7741deSElliott Hughes 				savefs();
197*9a7741deSElliott Hughes 			}
198*9a7741deSElliott Hughes 			setfval(nrloc, nrloc->fval+1);
199*9a7741deSElliott Hughes 			setfval(fnrloc, fnrloc->fval+1);
200*9a7741deSElliott Hughes 			*pbuf = buf;
201*9a7741deSElliott Hughes 			*pbufsize = bufsize;
202*9a7741deSElliott Hughes 			return 1;
203*9a7741deSElliott Hughes 		}
204*9a7741deSElliott Hughes 		/* EOF arrived on this file; set up next */
205*9a7741deSElliott Hughes 		if (infile != stdin)
206*9a7741deSElliott Hughes 			fclose(infile);
207*9a7741deSElliott Hughes 		infile = NULL;
208*9a7741deSElliott Hughes 		argno++;
209*9a7741deSElliott Hughes 	}
210*9a7741deSElliott Hughes 	buf[0] = saveb0;
211*9a7741deSElliott Hughes 	*pbuf = buf;
212*9a7741deSElliott Hughes 	*pbufsize = savebufsize;
213*9a7741deSElliott Hughes 	return 0;	/* true end of file */
214*9a7741deSElliott Hughes }
215*9a7741deSElliott Hughes 
nextfile(void)216*9a7741deSElliott Hughes void nextfile(void)
217*9a7741deSElliott Hughes {
218*9a7741deSElliott Hughes 	if (infile != NULL && infile != stdin)
219*9a7741deSElliott Hughes 		fclose(infile);
220*9a7741deSElliott Hughes 	infile = NULL;
221*9a7741deSElliott Hughes 	argno++;
222*9a7741deSElliott Hughes }
223*9a7741deSElliott Hughes 
224*9a7741deSElliott Hughes extern int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag);
225*9a7741deSElliott Hughes 
readrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)226*9a7741deSElliott Hughes int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag)	/* read one record into buf */
227*9a7741deSElliott Hughes {
228*9a7741deSElliott Hughes 	int sep, c, isrec; // POTENTIAL BUG? isrec is a macro in awk.h
229*9a7741deSElliott Hughes 	char *rr = *pbuf, *buf = *pbuf;
230*9a7741deSElliott Hughes 	int bufsize = *pbufsize;
231*9a7741deSElliott Hughes 	char *rs = getsval(rsloc);
232*9a7741deSElliott Hughes 
233*9a7741deSElliott Hughes 	if (CSV) {
234*9a7741deSElliott Hughes 		c = readcsvrec(&buf, &bufsize, inf, newflag);
235*9a7741deSElliott Hughes 		isrec = (c == EOF && rr == buf) ? false : true;
236*9a7741deSElliott Hughes 	} else if (*rs && rs[1]) {
237*9a7741deSElliott Hughes 		bool found;
238*9a7741deSElliott Hughes 
239*9a7741deSElliott Hughes 		memset(buf, 0, bufsize);
240*9a7741deSElliott Hughes 		fa *pfa = makedfa(rs, 1);
241*9a7741deSElliott Hughes 		if (newflag)
242*9a7741deSElliott Hughes 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
243*9a7741deSElliott Hughes 		else {
244*9a7741deSElliott Hughes 			int tempstat = pfa->initstat;
245*9a7741deSElliott Hughes 			pfa->initstat = 2;
246*9a7741deSElliott Hughes 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
247*9a7741deSElliott Hughes 			pfa->initstat = tempstat;
248*9a7741deSElliott Hughes 		}
249*9a7741deSElliott Hughes 		if (found)
250*9a7741deSElliott Hughes 			setptr(patbeg, '\0');
251*9a7741deSElliott Hughes 		isrec = (found == 0 && *buf == '\0') ? false : true;
252*9a7741deSElliott Hughes 
253*9a7741deSElliott Hughes 	} else {
254*9a7741deSElliott Hughes 		if ((sep = *rs) == 0) {
255*9a7741deSElliott Hughes 			sep = '\n';
256*9a7741deSElliott Hughes 			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
257*9a7741deSElliott Hughes 				;
258*9a7741deSElliott Hughes 			if (c != EOF)
259*9a7741deSElliott Hughes 				ungetc(c, inf);
260*9a7741deSElliott Hughes 		}
261*9a7741deSElliott Hughes 		for (rr = buf; ; ) {
262*9a7741deSElliott Hughes 			for (; (c=getc(inf)) != sep && c != EOF; ) {
263*9a7741deSElliott Hughes 				if (rr-buf+1 > bufsize)
264*9a7741deSElliott Hughes 					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
265*9a7741deSElliott Hughes 					    recsize, &rr, "readrec 1"))
266*9a7741deSElliott Hughes 						FATAL("input record `%.30s...' too long", buf);
267*9a7741deSElliott Hughes 				*rr++ = c;
268*9a7741deSElliott Hughes 			}
269*9a7741deSElliott Hughes 			if (*rs == sep || c == EOF)
270*9a7741deSElliott Hughes 				break;
271*9a7741deSElliott Hughes 			if ((c = getc(inf)) == '\n' || c == EOF)	/* 2 in a row */
272*9a7741deSElliott Hughes 				break;
273*9a7741deSElliott Hughes 			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
274*9a7741deSElliott Hughes 			    "readrec 2"))
275*9a7741deSElliott Hughes 				FATAL("input record `%.30s...' too long", buf);
276*9a7741deSElliott Hughes 			*rr++ = '\n';
277*9a7741deSElliott Hughes 			*rr++ = c;
278*9a7741deSElliott Hughes 		}
279*9a7741deSElliott Hughes 		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
280*9a7741deSElliott Hughes 			FATAL("input record `%.30s...' too long", buf);
281*9a7741deSElliott Hughes 		*rr = 0;
282*9a7741deSElliott Hughes 		isrec = (c == EOF && rr == buf) ? false : true;
283*9a7741deSElliott Hughes 	}
284*9a7741deSElliott Hughes 	*pbuf = buf;
285*9a7741deSElliott Hughes 	*pbufsize = bufsize;
286*9a7741deSElliott Hughes 	DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
287*9a7741deSElliott Hughes 	return isrec;
288*9a7741deSElliott Hughes }
289*9a7741deSElliott Hughes 
290*9a7741deSElliott Hughes 
291*9a7741deSElliott Hughes /*******************
292*9a7741deSElliott Hughes  * loose ends here:
293*9a7741deSElliott Hughes  *   \r\n should become \n
294*9a7741deSElliott Hughes  *   what about bare \r?  Excel uses that for embedded newlines
295*9a7741deSElliott Hughes  *   can't have "" in unquoted fields, according to RFC 4180
296*9a7741deSElliott Hughes */
297*9a7741deSElliott Hughes 
298*9a7741deSElliott Hughes 
readcsvrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)299*9a7741deSElliott Hughes int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* csv can have \n's */
300*9a7741deSElliott Hughes {			/* so read a complete record that might be multiple lines */
301*9a7741deSElliott Hughes 	int sep, c;
302*9a7741deSElliott Hughes 	char *rr = *pbuf, *buf = *pbuf;
303*9a7741deSElliott Hughes 	int bufsize = *pbufsize;
304*9a7741deSElliott Hughes 	bool in_quote = false;
305*9a7741deSElliott Hughes 
306*9a7741deSElliott Hughes 	sep = '\n'; /* the only separator; have to skip over \n embedded in "..." */
307*9a7741deSElliott Hughes 	rr = buf;
308*9a7741deSElliott Hughes 	while ((c = getc(inf)) != EOF) {
309*9a7741deSElliott Hughes 		if (c == sep) {
310*9a7741deSElliott Hughes 			if (! in_quote)
311*9a7741deSElliott Hughes 				break;
312*9a7741deSElliott Hughes 			if (rr > buf && rr[-1] == '\r')	// remove \r if was \r\n
313*9a7741deSElliott Hughes 				rr--;
314*9a7741deSElliott Hughes 		}
315*9a7741deSElliott Hughes 
316*9a7741deSElliott Hughes 		if (rr-buf+1 > bufsize)
317*9a7741deSElliott Hughes 			if (!adjbuf(&buf, &bufsize, 1+rr-buf,
318*9a7741deSElliott Hughes 			    recsize, &rr, "readcsvrec 1"))
319*9a7741deSElliott Hughes 				FATAL("input record `%.30s...' too long", buf);
320*9a7741deSElliott Hughes 		*rr++ = c;
321*9a7741deSElliott Hughes 		if (c == '"')
322*9a7741deSElliott Hughes 			in_quote = ! in_quote;
323*9a7741deSElliott Hughes  	}
324*9a7741deSElliott Hughes 	if (c == '\n' && rr > buf && rr[-1] == '\r') 	// remove \r if was \r\n
325*9a7741deSElliott Hughes 		rr--;
326*9a7741deSElliott Hughes 
327*9a7741deSElliott Hughes 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readcsvrec 4"))
328*9a7741deSElliott Hughes 		FATAL("input record `%.30s...' too long", buf);
329*9a7741deSElliott Hughes 	*rr = 0;
330*9a7741deSElliott Hughes 	*pbuf = buf;
331*9a7741deSElliott Hughes 	*pbufsize = bufsize;
332*9a7741deSElliott Hughes 	DPRINTF("readcsvrec saw <%s>, returns %d\n", buf, c);
333*9a7741deSElliott Hughes 	return c;
334*9a7741deSElliott Hughes }
335*9a7741deSElliott Hughes 
getargv(int n)336*9a7741deSElliott Hughes char *getargv(int n)	/* get ARGV[n] */
337*9a7741deSElliott Hughes {
338*9a7741deSElliott Hughes 	Array *ap;
339*9a7741deSElliott Hughes 	Cell *x;
340*9a7741deSElliott Hughes 	char *s, temp[50];
341*9a7741deSElliott Hughes 	extern Cell *ARGVcell;
342*9a7741deSElliott Hughes 
343*9a7741deSElliott Hughes 	ap = (Array *)ARGVcell->sval;
344*9a7741deSElliott Hughes 	snprintf(temp, sizeof(temp), "%d", n);
345*9a7741deSElliott Hughes 	if (lookup(temp, ap) == NULL)
346*9a7741deSElliott Hughes 		return NULL;
347*9a7741deSElliott Hughes 	x = setsymtab(temp, "", 0.0, STR, ap);
348*9a7741deSElliott Hughes 	s = getsval(x);
349*9a7741deSElliott Hughes 	DPRINTF("getargv(%d) returns |%s|\n", n, s);
350*9a7741deSElliott Hughes 	return s;
351*9a7741deSElliott Hughes }
352*9a7741deSElliott Hughes 
setclvar(char * s)353*9a7741deSElliott Hughes void setclvar(char *s)	/* set var=value from s */
354*9a7741deSElliott Hughes {
355*9a7741deSElliott Hughes 	char *e, *p;
356*9a7741deSElliott Hughes 	Cell *q;
357*9a7741deSElliott Hughes 	double result;
358*9a7741deSElliott Hughes 
359*9a7741deSElliott Hughes /* commit f3d9187d4e0f02294fb1b0e31152070506314e67 broke T.argv test */
360*9a7741deSElliott Hughes /* I don't understand why it was changed. */
361*9a7741deSElliott Hughes 
362*9a7741deSElliott Hughes 	for (p=s; *p != '='; p++)
363*9a7741deSElliott Hughes 		;
364*9a7741deSElliott Hughes 	e = p;
365*9a7741deSElliott Hughes 	*p++ = 0;
366*9a7741deSElliott Hughes 	p = qstring(p, '\0');
367*9a7741deSElliott Hughes 	q = setsymtab(s, p, 0.0, STR, symtab);
368*9a7741deSElliott Hughes 	setsval(q, p);
369*9a7741deSElliott Hughes 	if (is_number(q->sval, & result)) {
370*9a7741deSElliott Hughes 		q->fval = result;
371*9a7741deSElliott Hughes 		q->tval |= NUM;
372*9a7741deSElliott Hughes 	}
373*9a7741deSElliott Hughes 	DPRINTF("command line set %s to |%s|\n", s, p);
374*9a7741deSElliott Hughes 	free(p);
375*9a7741deSElliott Hughes 	*e = '=';
376*9a7741deSElliott Hughes }
377*9a7741deSElliott Hughes 
378*9a7741deSElliott Hughes 
fldbld(void)379*9a7741deSElliott Hughes void fldbld(void)	/* create fields from current record */
380*9a7741deSElliott Hughes {
381*9a7741deSElliott Hughes 	/* this relies on having fields[] the same length as $0 */
382*9a7741deSElliott Hughes 	/* the fields are all stored in this one array with \0's */
383*9a7741deSElliott Hughes 	/* possibly with a final trailing \0 not associated with any field */
384*9a7741deSElliott Hughes 	char *r, *fr, sep;
385*9a7741deSElliott Hughes 	Cell *p;
386*9a7741deSElliott Hughes 	int i, j, n;
387*9a7741deSElliott Hughes 
388*9a7741deSElliott Hughes 	if (donefld)
389*9a7741deSElliott Hughes 		return;
390*9a7741deSElliott Hughes 	if (!isstr(fldtab[0]))
391*9a7741deSElliott Hughes 		getsval(fldtab[0]);
392*9a7741deSElliott Hughes 	r = fldtab[0]->sval;
393*9a7741deSElliott Hughes 	n = strlen(r);
394*9a7741deSElliott Hughes 	if (n > fieldssize) {
395*9a7741deSElliott Hughes 		xfree(fields);
396*9a7741deSElliott Hughes 		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
397*9a7741deSElliott Hughes 			FATAL("out of space for fields in fldbld %d", n);
398*9a7741deSElliott Hughes 		fieldssize = n;
399*9a7741deSElliott Hughes 	}
400*9a7741deSElliott Hughes 	fr = fields;
401*9a7741deSElliott Hughes 	i = 0;	/* number of fields accumulated here */
402*9a7741deSElliott Hughes 	if (inputFS == NULL)	/* make sure we have a copy of FS */
403*9a7741deSElliott Hughes 		savefs();
404*9a7741deSElliott Hughes 	if (!CSV && strlen(inputFS) > 1) {	/* it's a regular expression */
405*9a7741deSElliott Hughes 		i = refldbld(r, inputFS);
406*9a7741deSElliott Hughes 	} else if (!CSV && (sep = *inputFS) == ' ') {	/* default whitespace */
407*9a7741deSElliott Hughes 		for (i = 0; ; ) {
408*9a7741deSElliott Hughes 			while (*r == ' ' || *r == '\t' || *r == '\n')
409*9a7741deSElliott Hughes 				r++;
410*9a7741deSElliott Hughes 			if (*r == 0)
411*9a7741deSElliott Hughes 				break;
412*9a7741deSElliott Hughes 			i++;
413*9a7741deSElliott Hughes 			if (i > nfields)
414*9a7741deSElliott Hughes 				growfldtab(i);
415*9a7741deSElliott Hughes 			if (freeable(fldtab[i]))
416*9a7741deSElliott Hughes 				xfree(fldtab[i]->sval);
417*9a7741deSElliott Hughes 			fldtab[i]->sval = fr;
418*9a7741deSElliott Hughes 			fldtab[i]->tval = FLD | STR | DONTFREE;
419*9a7741deSElliott Hughes 			do
420*9a7741deSElliott Hughes 				*fr++ = *r++;
421*9a7741deSElliott Hughes 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
422*9a7741deSElliott Hughes 			*fr++ = 0;
423*9a7741deSElliott Hughes 		}
424*9a7741deSElliott Hughes 		*fr = 0;
425*9a7741deSElliott Hughes 	} else if (CSV) {	/* CSV processing.  no error handling */
426*9a7741deSElliott Hughes 		if (*r != 0) {
427*9a7741deSElliott Hughes 			for (;;) {
428*9a7741deSElliott Hughes 				i++;
429*9a7741deSElliott Hughes 				if (i > nfields)
430*9a7741deSElliott Hughes 					growfldtab(i);
431*9a7741deSElliott Hughes 				if (freeable(fldtab[i]))
432*9a7741deSElliott Hughes 					xfree(fldtab[i]->sval);
433*9a7741deSElliott Hughes 				fldtab[i]->sval = fr;
434*9a7741deSElliott Hughes 				fldtab[i]->tval = FLD | STR | DONTFREE;
435*9a7741deSElliott Hughes 				if (*r == '"' ) { /* start of "..." */
436*9a7741deSElliott Hughes 					for (r++ ; *r != '\0'; ) {
437*9a7741deSElliott Hughes 						if (*r == '"' && r[1] != '\0' && r[1] == '"') {
438*9a7741deSElliott Hughes 							r += 2; /* doubled quote */
439*9a7741deSElliott Hughes 							*fr++ = '"';
440*9a7741deSElliott Hughes 						} else if (*r == '"' && (r[1] == '\0' || r[1] == ',')) {
441*9a7741deSElliott Hughes 							r++; /* skip over closing quote */
442*9a7741deSElliott Hughes 							break;
443*9a7741deSElliott Hughes 						} else {
444*9a7741deSElliott Hughes 							*fr++ = *r++;
445*9a7741deSElliott Hughes 						}
446*9a7741deSElliott Hughes 					}
447*9a7741deSElliott Hughes 					*fr++ = 0;
448*9a7741deSElliott Hughes 				} else {	/* unquoted field */
449*9a7741deSElliott Hughes 					while (*r != ',' && *r != '\0')
450*9a7741deSElliott Hughes 						*fr++ = *r++;
451*9a7741deSElliott Hughes 					*fr++ = 0;
452*9a7741deSElliott Hughes 				}
453*9a7741deSElliott Hughes 				if (*r++ == 0)
454*9a7741deSElliott Hughes 					break;
455*9a7741deSElliott Hughes 
456*9a7741deSElliott Hughes 			}
457*9a7741deSElliott Hughes 		}
458*9a7741deSElliott Hughes 		*fr = 0;
459*9a7741deSElliott Hughes 	} else if ((sep = *inputFS) == 0) {	/* new: FS="" => 1 char/field */
460*9a7741deSElliott Hughes 		for (i = 0; *r != '\0'; ) {
461*9a7741deSElliott Hughes 			char buf[10];
462*9a7741deSElliott Hughes 			i++;
463*9a7741deSElliott Hughes 			if (i > nfields)
464*9a7741deSElliott Hughes 				growfldtab(i);
465*9a7741deSElliott Hughes 			if (freeable(fldtab[i]))
466*9a7741deSElliott Hughes 				xfree(fldtab[i]->sval);
467*9a7741deSElliott Hughes 			n = u8_nextlen(r);
468*9a7741deSElliott Hughes 			for (j = 0; j < n; j++)
469*9a7741deSElliott Hughes 				buf[j] = *r++;
470*9a7741deSElliott Hughes 			buf[j] = '\0';
471*9a7741deSElliott Hughes 			fldtab[i]->sval = tostring(buf);
472*9a7741deSElliott Hughes 			fldtab[i]->tval = FLD | STR;
473*9a7741deSElliott Hughes 		}
474*9a7741deSElliott Hughes 		*fr = 0;
475*9a7741deSElliott Hughes 	} else if (*r != 0) {	/* if 0, it's a null field */
476*9a7741deSElliott Hughes 		/* subtle case: if length(FS) == 1 && length(RS > 0)
477*9a7741deSElliott Hughes 		 * \n is NOT a field separator (cf awk book 61,84).
478*9a7741deSElliott Hughes 		 * this variable is tested in the inner while loop.
479*9a7741deSElliott Hughes 		 */
480*9a7741deSElliott Hughes 		int rtest = '\n';  /* normal case */
481*9a7741deSElliott Hughes 		if (strlen(*RS) > 0)
482*9a7741deSElliott Hughes 			rtest = '\0';
483*9a7741deSElliott Hughes 		for (;;) {
484*9a7741deSElliott Hughes 			i++;
485*9a7741deSElliott Hughes 			if (i > nfields)
486*9a7741deSElliott Hughes 				growfldtab(i);
487*9a7741deSElliott Hughes 			if (freeable(fldtab[i]))
488*9a7741deSElliott Hughes 				xfree(fldtab[i]->sval);
489*9a7741deSElliott Hughes 			fldtab[i]->sval = fr;
490*9a7741deSElliott Hughes 			fldtab[i]->tval = FLD | STR | DONTFREE;
491*9a7741deSElliott Hughes 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
492*9a7741deSElliott Hughes 				*fr++ = *r++;
493*9a7741deSElliott Hughes 			*fr++ = 0;
494*9a7741deSElliott Hughes 			if (*r++ == 0)
495*9a7741deSElliott Hughes 				break;
496*9a7741deSElliott Hughes 		}
497*9a7741deSElliott Hughes 		*fr = 0;
498*9a7741deSElliott Hughes 	}
499*9a7741deSElliott Hughes 	if (i > nfields)
500*9a7741deSElliott Hughes 		FATAL("record `%.30s...' has too many fields; can't happen", r);
501*9a7741deSElliott Hughes 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
502*9a7741deSElliott Hughes 	lastfld = i;
503*9a7741deSElliott Hughes 	donefld = true;
504*9a7741deSElliott Hughes 	for (j = 1; j <= lastfld; j++) {
505*9a7741deSElliott Hughes 		double result;
506*9a7741deSElliott Hughes 
507*9a7741deSElliott Hughes 		p = fldtab[j];
508*9a7741deSElliott Hughes 		if(is_number(p->sval, & result)) {
509*9a7741deSElliott Hughes 			p->fval = result;
510*9a7741deSElliott Hughes 			p->tval |= NUM;
511*9a7741deSElliott Hughes 		}
512*9a7741deSElliott Hughes 	}
513*9a7741deSElliott Hughes 	setfval(nfloc, (Awkfloat) lastfld);
514*9a7741deSElliott Hughes 	donerec = true; /* restore */
515*9a7741deSElliott Hughes 	if (dbg) {
516*9a7741deSElliott Hughes 		for (j = 0; j <= lastfld; j++) {
517*9a7741deSElliott Hughes 			p = fldtab[j];
518*9a7741deSElliott Hughes 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
519*9a7741deSElliott Hughes 		}
520*9a7741deSElliott Hughes 	}
521*9a7741deSElliott Hughes }
522*9a7741deSElliott Hughes 
cleanfld(int n1,int n2)523*9a7741deSElliott Hughes void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
524*9a7741deSElliott Hughes {				/* nvals remain intact */
525*9a7741deSElliott Hughes 	Cell *p;
526*9a7741deSElliott Hughes 	int i;
527*9a7741deSElliott Hughes 
528*9a7741deSElliott Hughes 	for (i = n1; i <= n2; i++) {
529*9a7741deSElliott Hughes 		p = fldtab[i];
530*9a7741deSElliott Hughes 		if (freeable(p))
531*9a7741deSElliott Hughes 			xfree(p->sval);
532*9a7741deSElliott Hughes 		p->sval = EMPTY,
533*9a7741deSElliott Hughes 		p->tval = FLD | STR | DONTFREE;
534*9a7741deSElliott Hughes 	}
535*9a7741deSElliott Hughes }
536*9a7741deSElliott Hughes 
newfld(int n)537*9a7741deSElliott Hughes void newfld(int n)	/* add field n after end of existing lastfld */
538*9a7741deSElliott Hughes {
539*9a7741deSElliott Hughes 	if (n > nfields)
540*9a7741deSElliott Hughes 		growfldtab(n);
541*9a7741deSElliott Hughes 	cleanfld(lastfld+1, n);
542*9a7741deSElliott Hughes 	lastfld = n;
543*9a7741deSElliott Hughes 	setfval(nfloc, (Awkfloat) n);
544*9a7741deSElliott Hughes }
545*9a7741deSElliott Hughes 
setlastfld(int n)546*9a7741deSElliott Hughes void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
547*9a7741deSElliott Hughes {
548*9a7741deSElliott Hughes 	if (n < 0)
549*9a7741deSElliott Hughes 		FATAL("cannot set NF to a negative value");
550*9a7741deSElliott Hughes 	if (n > nfields)
551*9a7741deSElliott Hughes 		growfldtab(n);
552*9a7741deSElliott Hughes 
553*9a7741deSElliott Hughes 	if (lastfld < n)
554*9a7741deSElliott Hughes 	    cleanfld(lastfld+1, n);
555*9a7741deSElliott Hughes 	else
556*9a7741deSElliott Hughes 	    cleanfld(n+1, lastfld);
557*9a7741deSElliott Hughes 
558*9a7741deSElliott Hughes 	lastfld = n;
559*9a7741deSElliott Hughes }
560*9a7741deSElliott Hughes 
fieldadr(int n)561*9a7741deSElliott Hughes Cell *fieldadr(int n)	/* get nth field */
562*9a7741deSElliott Hughes {
563*9a7741deSElliott Hughes 	if (n < 0)
564*9a7741deSElliott Hughes 		FATAL("trying to access out of range field %d", n);
565*9a7741deSElliott Hughes 	if (n > nfields)	/* fields after NF are empty */
566*9a7741deSElliott Hughes 		growfldtab(n);	/* but does not increase NF */
567*9a7741deSElliott Hughes 	return(fldtab[n]);
568*9a7741deSElliott Hughes }
569*9a7741deSElliott Hughes 
growfldtab(int n)570*9a7741deSElliott Hughes void growfldtab(int n)	/* make new fields up to at least $n */
571*9a7741deSElliott Hughes {
572*9a7741deSElliott Hughes 	int nf = 2 * nfields;
573*9a7741deSElliott Hughes 	size_t s;
574*9a7741deSElliott Hughes 
575*9a7741deSElliott Hughes 	if (n > nf)
576*9a7741deSElliott Hughes 		nf = n;
577*9a7741deSElliott Hughes 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
578*9a7741deSElliott Hughes 	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
579*9a7741deSElliott Hughes 		fldtab = (Cell **) realloc(fldtab, s);
580*9a7741deSElliott Hughes 	else					/* overflow sizeof int */
581*9a7741deSElliott Hughes 		xfree(fldtab);	/* make it null */
582*9a7741deSElliott Hughes 	if (fldtab == NULL)
583*9a7741deSElliott Hughes 		FATAL("out of space creating %d fields", nf);
584*9a7741deSElliott Hughes 	makefields(nfields+1, nf);
585*9a7741deSElliott Hughes 	nfields = nf;
586*9a7741deSElliott Hughes }
587*9a7741deSElliott Hughes 
refldbld(const char * rec,const char * fs)588*9a7741deSElliott Hughes int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
589*9a7741deSElliott Hughes {
590*9a7741deSElliott Hughes 	/* this relies on having fields[] the same length as $0 */
591*9a7741deSElliott Hughes 	/* the fields are all stored in this one array with \0's */
592*9a7741deSElliott Hughes 	char *fr;
593*9a7741deSElliott Hughes 	int i, tempstat, n;
594*9a7741deSElliott Hughes 	fa *pfa;
595*9a7741deSElliott Hughes 
596*9a7741deSElliott Hughes 	n = strlen(rec);
597*9a7741deSElliott Hughes 	if (n > fieldssize) {
598*9a7741deSElliott Hughes 		xfree(fields);
599*9a7741deSElliott Hughes 		if ((fields = (char *) malloc(n+1)) == NULL)
600*9a7741deSElliott Hughes 			FATAL("out of space for fields in refldbld %d", n);
601*9a7741deSElliott Hughes 		fieldssize = n;
602*9a7741deSElliott Hughes 	}
603*9a7741deSElliott Hughes 	fr = fields;
604*9a7741deSElliott Hughes 	*fr = '\0';
605*9a7741deSElliott Hughes 	if (*rec == '\0')
606*9a7741deSElliott Hughes 		return 0;
607*9a7741deSElliott Hughes 	pfa = makedfa(fs, 1);
608*9a7741deSElliott Hughes 	DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs);
609*9a7741deSElliott Hughes 	tempstat = pfa->initstat;
610*9a7741deSElliott Hughes 	for (i = 1; ; i++) {
611*9a7741deSElliott Hughes 		if (i > nfields)
612*9a7741deSElliott Hughes 			growfldtab(i);
613*9a7741deSElliott Hughes 		if (freeable(fldtab[i]))
614*9a7741deSElliott Hughes 			xfree(fldtab[i]->sval);
615*9a7741deSElliott Hughes 		fldtab[i]->tval = FLD | STR | DONTFREE;
616*9a7741deSElliott Hughes 		fldtab[i]->sval = fr;
617*9a7741deSElliott Hughes 		DPRINTF("refldbld: i=%d\n", i);
618*9a7741deSElliott Hughes 		if (nematch(pfa, rec)) {
619*9a7741deSElliott Hughes 			pfa->initstat = 2;	/* horrible coupling to b.c */
620*9a7741deSElliott Hughes 			DPRINTF("match %s (%d chars)\n", patbeg, patlen);
621*9a7741deSElliott Hughes 			strncpy(fr, rec, patbeg-rec);
622*9a7741deSElliott Hughes 			fr += patbeg - rec + 1;
623*9a7741deSElliott Hughes 			*(fr-1) = '\0';
624*9a7741deSElliott Hughes 			rec = patbeg + patlen;
625*9a7741deSElliott Hughes 		} else {
626*9a7741deSElliott Hughes 			DPRINTF("no match %s\n", rec);
627*9a7741deSElliott Hughes 			strcpy(fr, rec);
628*9a7741deSElliott Hughes 			pfa->initstat = tempstat;
629*9a7741deSElliott Hughes 			break;
630*9a7741deSElliott Hughes 		}
631*9a7741deSElliott Hughes 	}
632*9a7741deSElliott Hughes 	return i;
633*9a7741deSElliott Hughes }
634*9a7741deSElliott Hughes 
recbld(void)635*9a7741deSElliott Hughes void recbld(void)	/* create $0 from $1..$NF if necessary */
636*9a7741deSElliott Hughes {
637*9a7741deSElliott Hughes 	int i;
638*9a7741deSElliott Hughes 	char *r, *p;
639*9a7741deSElliott Hughes 	char *sep = getsval(ofsloc);
640*9a7741deSElliott Hughes 
641*9a7741deSElliott Hughes 	if (donerec)
642*9a7741deSElliott Hughes 		return;
643*9a7741deSElliott Hughes 	r = record;
644*9a7741deSElliott Hughes 	for (i = 1; i <= *NF; i++) {
645*9a7741deSElliott Hughes 		p = getsval(fldtab[i]);
646*9a7741deSElliott Hughes 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
647*9a7741deSElliott Hughes 			FATAL("created $0 `%.30s...' too long", record);
648*9a7741deSElliott Hughes 		while ((*r = *p++) != 0)
649*9a7741deSElliott Hughes 			r++;
650*9a7741deSElliott Hughes 		if (i < *NF) {
651*9a7741deSElliott Hughes 			if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
652*9a7741deSElliott Hughes 				FATAL("created $0 `%.30s...' too long", record);
653*9a7741deSElliott Hughes 			for (p = sep; (*r = *p++) != 0; )
654*9a7741deSElliott Hughes 				r++;
655*9a7741deSElliott Hughes 		}
656*9a7741deSElliott Hughes 	}
657*9a7741deSElliott Hughes 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
658*9a7741deSElliott Hughes 		FATAL("built giant record `%.30s...'", record);
659*9a7741deSElliott Hughes 	*r = '\0';
660*9a7741deSElliott Hughes 	DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
661*9a7741deSElliott Hughes 
662*9a7741deSElliott Hughes 	if (freeable(fldtab[0]))
663*9a7741deSElliott Hughes 		xfree(fldtab[0]->sval);
664*9a7741deSElliott Hughes 	fldtab[0]->tval = REC | STR | DONTFREE;
665*9a7741deSElliott Hughes 	fldtab[0]->sval = record;
666*9a7741deSElliott Hughes 
667*9a7741deSElliott Hughes 	DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
668*9a7741deSElliott Hughes 	DPRINTF("recbld = |%s|\n", record);
669*9a7741deSElliott Hughes 	donerec = true;
670*9a7741deSElliott Hughes }
671*9a7741deSElliott Hughes 
672*9a7741deSElliott Hughes int	errorflag	= 0;
673*9a7741deSElliott Hughes 
yyerror(const char * s)674*9a7741deSElliott Hughes void yyerror(const char *s)
675*9a7741deSElliott Hughes {
676*9a7741deSElliott Hughes 	SYNTAX("%s", s);
677*9a7741deSElliott Hughes }
678*9a7741deSElliott Hughes 
SYNTAX(const char * fmt,...)679*9a7741deSElliott Hughes void SYNTAX(const char *fmt, ...)
680*9a7741deSElliott Hughes {
681*9a7741deSElliott Hughes 	extern char *cmdname, *curfname;
682*9a7741deSElliott Hughes 	static int been_here = 0;
683*9a7741deSElliott Hughes 	va_list varg;
684*9a7741deSElliott Hughes 
685*9a7741deSElliott Hughes 	if (been_here++ > 2)
686*9a7741deSElliott Hughes 		return;
687*9a7741deSElliott Hughes 	fprintf(stderr, "%s: ", cmdname);
688*9a7741deSElliott Hughes 	va_start(varg, fmt);
689*9a7741deSElliott Hughes 	vfprintf(stderr, fmt, varg);
690*9a7741deSElliott Hughes 	va_end(varg);
691*9a7741deSElliott Hughes 	fprintf(stderr, " at source line %d", lineno);
692*9a7741deSElliott Hughes 	if (curfname != NULL)
693*9a7741deSElliott Hughes 		fprintf(stderr, " in function %s", curfname);
694*9a7741deSElliott Hughes 	if (compile_time == COMPILING && cursource() != NULL)
695*9a7741deSElliott Hughes 		fprintf(stderr, " source file %s", cursource());
696*9a7741deSElliott Hughes 	fprintf(stderr, "\n");
697*9a7741deSElliott Hughes 	errorflag = 2;
698*9a7741deSElliott Hughes 	eprint();
699*9a7741deSElliott Hughes }
700*9a7741deSElliott Hughes 
701*9a7741deSElliott Hughes extern int bracecnt, brackcnt, parencnt;
702*9a7741deSElliott Hughes 
bracecheck(void)703*9a7741deSElliott Hughes void bracecheck(void)
704*9a7741deSElliott Hughes {
705*9a7741deSElliott Hughes 	int c;
706*9a7741deSElliott Hughes 	static int beenhere = 0;
707*9a7741deSElliott Hughes 
708*9a7741deSElliott Hughes 	if (beenhere++)
709*9a7741deSElliott Hughes 		return;
710*9a7741deSElliott Hughes 	while ((c = input()) != EOF && c != '\0')
711*9a7741deSElliott Hughes 		bclass(c);
712*9a7741deSElliott Hughes 	bcheck2(bracecnt, '{', '}');
713*9a7741deSElliott Hughes 	bcheck2(brackcnt, '[', ']');
714*9a7741deSElliott Hughes 	bcheck2(parencnt, '(', ')');
715*9a7741deSElliott Hughes }
716*9a7741deSElliott Hughes 
bcheck2(int n,int c1,int c2)717*9a7741deSElliott Hughes void bcheck2(int n, int c1, int c2)
718*9a7741deSElliott Hughes {
719*9a7741deSElliott Hughes 	if (n == 1)
720*9a7741deSElliott Hughes 		fprintf(stderr, "\tmissing %c\n", c2);
721*9a7741deSElliott Hughes 	else if (n > 1)
722*9a7741deSElliott Hughes 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
723*9a7741deSElliott Hughes 	else if (n == -1)
724*9a7741deSElliott Hughes 		fprintf(stderr, "\textra %c\n", c2);
725*9a7741deSElliott Hughes 	else if (n < -1)
726*9a7741deSElliott Hughes 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
727*9a7741deSElliott Hughes }
728*9a7741deSElliott Hughes 
FATAL(const char * fmt,...)729*9a7741deSElliott Hughes void FATAL(const char *fmt, ...)
730*9a7741deSElliott Hughes {
731*9a7741deSElliott Hughes 	extern char *cmdname;
732*9a7741deSElliott Hughes 	va_list varg;
733*9a7741deSElliott Hughes 
734*9a7741deSElliott Hughes 	fflush(stdout);
735*9a7741deSElliott Hughes 	fprintf(stderr, "%s: ", cmdname);
736*9a7741deSElliott Hughes 	va_start(varg, fmt);
737*9a7741deSElliott Hughes 	vfprintf(stderr, fmt, varg);
738*9a7741deSElliott Hughes 	va_end(varg);
739*9a7741deSElliott Hughes 	error();
740*9a7741deSElliott Hughes 	if (dbg > 1)		/* core dump if serious debugging on */
741*9a7741deSElliott Hughes 		abort();
742*9a7741deSElliott Hughes 	exit(2);
743*9a7741deSElliott Hughes }
744*9a7741deSElliott Hughes 
WARNING(const char * fmt,...)745*9a7741deSElliott Hughes void WARNING(const char *fmt, ...)
746*9a7741deSElliott Hughes {
747*9a7741deSElliott Hughes 	extern char *cmdname;
748*9a7741deSElliott Hughes 	va_list varg;
749*9a7741deSElliott Hughes 
750*9a7741deSElliott Hughes 	fflush(stdout);
751*9a7741deSElliott Hughes 	fprintf(stderr, "%s: ", cmdname);
752*9a7741deSElliott Hughes 	va_start(varg, fmt);
753*9a7741deSElliott Hughes 	vfprintf(stderr, fmt, varg);
754*9a7741deSElliott Hughes 	va_end(varg);
755*9a7741deSElliott Hughes 	error();
756*9a7741deSElliott Hughes }
757*9a7741deSElliott Hughes 
error()758*9a7741deSElliott Hughes void error()
759*9a7741deSElliott Hughes {
760*9a7741deSElliott Hughes 	extern Node *curnode;
761*9a7741deSElliott Hughes 
762*9a7741deSElliott Hughes 	fprintf(stderr, "\n");
763*9a7741deSElliott Hughes 	if (compile_time != ERROR_PRINTING) {
764*9a7741deSElliott Hughes 		if (NR && *NR > 0) {
765*9a7741deSElliott Hughes 			fprintf(stderr, " input record number %d", (int) (*FNR));
766*9a7741deSElliott Hughes 			if (strcmp(*FILENAME, "-") != 0)
767*9a7741deSElliott Hughes 				fprintf(stderr, ", file %s", *FILENAME);
768*9a7741deSElliott Hughes 			fprintf(stderr, "\n");
769*9a7741deSElliott Hughes 		}
770*9a7741deSElliott Hughes 		if (curnode)
771*9a7741deSElliott Hughes 			fprintf(stderr, " source line number %d", curnode->lineno);
772*9a7741deSElliott Hughes 		else if (lineno)
773*9a7741deSElliott Hughes 			fprintf(stderr, " source line number %d", lineno);
774*9a7741deSElliott Hughes 		if (compile_time == COMPILING && cursource() != NULL)
775*9a7741deSElliott Hughes 			fprintf(stderr, " source file %s", cursource());
776*9a7741deSElliott Hughes 		fprintf(stderr, "\n");
777*9a7741deSElliott Hughes 		eprint();
778*9a7741deSElliott Hughes 	}
779*9a7741deSElliott Hughes }
780*9a7741deSElliott Hughes 
eprint(void)781*9a7741deSElliott Hughes void eprint(void)	/* try to print context around error */
782*9a7741deSElliott Hughes {
783*9a7741deSElliott Hughes 	char *p, *q;
784*9a7741deSElliott Hughes 	int c;
785*9a7741deSElliott Hughes 	static int been_here = 0;
786*9a7741deSElliott Hughes 	extern char ebuf[], *ep;
787*9a7741deSElliott Hughes 
788*9a7741deSElliott Hughes 	if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
789*9a7741deSElliott Hughes 		return;
790*9a7741deSElliott Hughes 	if (ebuf == ep)
791*9a7741deSElliott Hughes 		return;
792*9a7741deSElliott Hughes 	p = ep - 1;
793*9a7741deSElliott Hughes 	if (p > ebuf && *p == '\n')
794*9a7741deSElliott Hughes 		p--;
795*9a7741deSElliott Hughes 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
796*9a7741deSElliott Hughes 		;
797*9a7741deSElliott Hughes 	while (*p == '\n')
798*9a7741deSElliott Hughes 		p++;
799*9a7741deSElliott Hughes 	fprintf(stderr, " context is\n\t");
800*9a7741deSElliott Hughes 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
801*9a7741deSElliott Hughes 		;
802*9a7741deSElliott Hughes 	for ( ; p < q; p++)
803*9a7741deSElliott Hughes 		if (*p)
804*9a7741deSElliott Hughes 			putc(*p, stderr);
805*9a7741deSElliott Hughes 	fprintf(stderr, " >>> ");
806*9a7741deSElliott Hughes 	for ( ; p < ep; p++)
807*9a7741deSElliott Hughes 		if (*p)
808*9a7741deSElliott Hughes 			putc(*p, stderr);
809*9a7741deSElliott Hughes 	fprintf(stderr, " <<< ");
810*9a7741deSElliott Hughes 	if (*ep)
811*9a7741deSElliott Hughes 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
812*9a7741deSElliott Hughes 			putc(c, stderr);
813*9a7741deSElliott Hughes 			bclass(c);
814*9a7741deSElliott Hughes 		}
815*9a7741deSElliott Hughes 	putc('\n', stderr);
816*9a7741deSElliott Hughes 	ep = ebuf;
817*9a7741deSElliott Hughes }
818*9a7741deSElliott Hughes 
bclass(int c)819*9a7741deSElliott Hughes void bclass(int c)
820*9a7741deSElliott Hughes {
821*9a7741deSElliott Hughes 	switch (c) {
822*9a7741deSElliott Hughes 	case '{': bracecnt++; break;
823*9a7741deSElliott Hughes 	case '}': bracecnt--; break;
824*9a7741deSElliott Hughes 	case '[': brackcnt++; break;
825*9a7741deSElliott Hughes 	case ']': brackcnt--; break;
826*9a7741deSElliott Hughes 	case '(': parencnt++; break;
827*9a7741deSElliott Hughes 	case ')': parencnt--; break;
828*9a7741deSElliott Hughes 	}
829*9a7741deSElliott Hughes }
830*9a7741deSElliott Hughes 
errcheck(double x,const char * s)831*9a7741deSElliott Hughes double errcheck(double x, const char *s)
832*9a7741deSElliott Hughes {
833*9a7741deSElliott Hughes 
834*9a7741deSElliott Hughes 	if (errno == EDOM) {
835*9a7741deSElliott Hughes 		errno = 0;
836*9a7741deSElliott Hughes 		WARNING("%s argument out of domain", s);
837*9a7741deSElliott Hughes 		x = 1;
838*9a7741deSElliott Hughes 	} else if (errno == ERANGE) {
839*9a7741deSElliott Hughes 		errno = 0;
840*9a7741deSElliott Hughes 		WARNING("%s result out of range", s);
841*9a7741deSElliott Hughes 		x = 1;
842*9a7741deSElliott Hughes 	}
843*9a7741deSElliott Hughes 	return x;
844*9a7741deSElliott Hughes }
845*9a7741deSElliott Hughes 
isclvar(const char * s)846*9a7741deSElliott Hughes int isclvar(const char *s)	/* is s of form var=something ? */
847*9a7741deSElliott Hughes {
848*9a7741deSElliott Hughes 	const char *os = s;
849*9a7741deSElliott Hughes 
850*9a7741deSElliott Hughes 	if (!isalpha((int) *s) && *s != '_')
851*9a7741deSElliott Hughes 		return 0;
852*9a7741deSElliott Hughes 	for ( ; *s; s++)
853*9a7741deSElliott Hughes 		if (!(isalnum((int) *s) || *s == '_'))
854*9a7741deSElliott Hughes 			break;
855*9a7741deSElliott Hughes 	return *s == '=' && s > os;
856*9a7741deSElliott Hughes }
857*9a7741deSElliott Hughes 
858*9a7741deSElliott Hughes /* strtod is supposed to be a proper test of what's a valid number */
859*9a7741deSElliott Hughes /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
860*9a7741deSElliott Hughes /* wrong: violates 4.10.1.4 of ansi C standard */
861*9a7741deSElliott Hughes 
862*9a7741deSElliott Hughes /* well, not quite. As of C99, hex floating point is allowed. so this is
863*9a7741deSElliott Hughes  * a bit of a mess. We work around the mess by checking for a hexadecimal
864*9a7741deSElliott Hughes  * value and disallowing it. Similarly, we now follow gawk and allow only
865*9a7741deSElliott Hughes  * +nan, -nan, +inf, and -inf for NaN and infinity values.
866*9a7741deSElliott Hughes  */
867*9a7741deSElliott Hughes 
868*9a7741deSElliott Hughes /*
869*9a7741deSElliott Hughes  * This routine now has a more complicated interface, the main point
870*9a7741deSElliott Hughes  * being to avoid the double conversion of a string to double, and
871*9a7741deSElliott Hughes  * also to convey out, if requested, the information that the numeric
872*9a7741deSElliott Hughes  * value was a leading string or is all of the string. The latter bit
873*9a7741deSElliott Hughes  * is used in getfval().
874*9a7741deSElliott Hughes  */
875*9a7741deSElliott Hughes 
is_valid_number(const char * s,bool trailing_stuff_ok,bool * no_trailing,double * result)876*9a7741deSElliott Hughes bool is_valid_number(const char *s, bool trailing_stuff_ok,
877*9a7741deSElliott Hughes 			bool *no_trailing, double *result)
878*9a7741deSElliott Hughes {
879*9a7741deSElliott Hughes 	double r;
880*9a7741deSElliott Hughes 	char *ep;
881*9a7741deSElliott Hughes 	bool retval = false;
882*9a7741deSElliott Hughes 	bool is_nan = false;
883*9a7741deSElliott Hughes 	bool is_inf = false;
884*9a7741deSElliott Hughes 
885*9a7741deSElliott Hughes 	if (no_trailing)
886*9a7741deSElliott Hughes 		*no_trailing = false;
887*9a7741deSElliott Hughes 
888*9a7741deSElliott Hughes 	while (isspace((int) *s))
889*9a7741deSElliott Hughes 		s++;
890*9a7741deSElliott Hughes 
891*9a7741deSElliott Hughes 	/* no hex floating point, sorry */
892*9a7741deSElliott Hughes 	if (s[0] == '0' && tolower(s[1]) == 'x')
893*9a7741deSElliott Hughes 		return false;
894*9a7741deSElliott Hughes 
895*9a7741deSElliott Hughes 	/* allow +nan, -nan, +inf, -inf, any other letter, no */
896*9a7741deSElliott Hughes 	if (s[0] == '+' || s[0] == '-') {
897*9a7741deSElliott Hughes 		is_nan = (strncasecmp(s+1, "nan", 3) == 0);
898*9a7741deSElliott Hughes 		is_inf = (strncasecmp(s+1, "inf", 3) == 0);
899*9a7741deSElliott Hughes 		if ((is_nan || is_inf)
900*9a7741deSElliott Hughes 		    && (isspace((int) s[4]) || s[4] == '\0'))
901*9a7741deSElliott Hughes 			goto convert;
902*9a7741deSElliott Hughes 		else if (! isdigit(s[1]) && s[1] != '.')
903*9a7741deSElliott Hughes 			return false;
904*9a7741deSElliott Hughes 	}
905*9a7741deSElliott Hughes 	else if (! isdigit(s[0]) && s[0] != '.')
906*9a7741deSElliott Hughes 		return false;
907*9a7741deSElliott Hughes 
908*9a7741deSElliott Hughes convert:
909*9a7741deSElliott Hughes 	errno = 0;
910*9a7741deSElliott Hughes 	r = strtod(s, &ep);
911*9a7741deSElliott Hughes 	if (ep == s || errno == ERANGE)
912*9a7741deSElliott Hughes 		return false;
913*9a7741deSElliott Hughes 
914*9a7741deSElliott Hughes 	if (isnan(r) && s[0] == '-' && signbit(r) == 0)
915*9a7741deSElliott Hughes 		r = -r;
916*9a7741deSElliott Hughes 
917*9a7741deSElliott Hughes 	if (result != NULL)
918*9a7741deSElliott Hughes 		*result = r;
919*9a7741deSElliott Hughes 
920*9a7741deSElliott Hughes 	/*
921*9a7741deSElliott Hughes 	 * check for trailing stuff
922*9a7741deSElliott Hughes 	 */
923*9a7741deSElliott Hughes 	while (isspace((int) *ep))
924*9a7741deSElliott Hughes 		ep++;
925*9a7741deSElliott Hughes 
926*9a7741deSElliott Hughes 	if (no_trailing != NULL)
927*9a7741deSElliott Hughes 		*no_trailing = (*ep == '\0');
928*9a7741deSElliott Hughes 
929*9a7741deSElliott Hughes         /* return true if found the end, or trailing stuff is allowed */
930*9a7741deSElliott Hughes 	retval = *ep == '\0' || trailing_stuff_ok;
931*9a7741deSElliott Hughes 
932*9a7741deSElliott Hughes 	return retval;
933*9a7741deSElliott Hughes }
934