xref: /dflybsd-src/contrib/awk/lib.c (revision e2ee60a4f1757f9ded9e1041053222b631f387b6)
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>
2848f09a05SAntonio Huete Jimenez #include <strings.h>
294b588458SPeter Avalos #include <ctype.h>
304b588458SPeter Avalos #include <errno.h>
314b588458SPeter Avalos #include <stdlib.h>
324b588458SPeter Avalos #include <stdarg.h>
331d48fce0SDaniel Fojt #include <limits.h>
3448f09a05SAntonio Huete Jimenez #include <math.h>
354b588458SPeter Avalos #include "awk.h"
364b588458SPeter Avalos 
37*ed569bc2SAaron LI extern int u8_nextlen(const char *s);
38*ed569bc2SAaron LI 
391d48fce0SDaniel Fojt char	EMPTY[] = { '\0' };
404b588458SPeter Avalos FILE	*infile	= NULL;
411d48fce0SDaniel Fojt bool	innew;		/* true = infile has not been read by readrec */
421d48fce0SDaniel Fojt char	*file	= EMPTY;
434b588458SPeter Avalos char	*record;
444b588458SPeter Avalos int	recsize	= RECSIZE;
454b588458SPeter Avalos char	*fields;
464b588458SPeter Avalos int	fieldssize = RECSIZE;
474b588458SPeter Avalos 
484b588458SPeter Avalos Cell	**fldtab;	/* pointers to Cells */
491d48fce0SDaniel Fojt static size_t	len_inputFS = 0;
501d48fce0SDaniel Fojt static char	*inputFS = NULL; /* FS at time of input, for field splitting */
514b588458SPeter Avalos 
524b588458SPeter Avalos #define	MAXFLD	2
534b588458SPeter Avalos int	nfields	= MAXFLD;	/* last allocated slot for $i */
544b588458SPeter Avalos 
551d48fce0SDaniel Fojt bool	donefld;	/* true = implies rec broken into fields */
561d48fce0SDaniel Fojt bool	donerec;	/* true = record is valid (no flds have changed) */
574b588458SPeter Avalos 
584b588458SPeter Avalos int	lastfld	= 0;	/* last used field */
594b588458SPeter Avalos int	argno	= 1;	/* current input argument number */
604b588458SPeter Avalos extern	Awkfloat *ARGC;
614b588458SPeter Avalos 
621d48fce0SDaniel Fojt static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
631d48fce0SDaniel Fojt static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
644b588458SPeter Avalos 
recinit(unsigned int n)654b588458SPeter Avalos void recinit(unsigned int n)
664b588458SPeter Avalos {
6748f09a05SAntonio Huete Jimenez 	if ( (record = (char *) malloc(n)) == NULL
6848f09a05SAntonio Huete Jimenez 	  || (fields = (char *) malloc(n+1)) == NULL
6948f09a05SAntonio Huete Jimenez 	  || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
7048f09a05SAntonio Huete Jimenez 	  || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
714b588458SPeter Avalos 		FATAL("out of space for $0 and fields");
721d48fce0SDaniel Fojt 	*record = '\0';
734b588458SPeter Avalos 	*fldtab[0] = dollar0;
744b588458SPeter Avalos 	fldtab[0]->sval = record;
754b588458SPeter Avalos 	fldtab[0]->nval = tostring("0");
764b588458SPeter Avalos 	makefields(1, nfields);
774b588458SPeter Avalos }
784b588458SPeter Avalos 
makefields(int n1,int n2)794b588458SPeter Avalos void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
804b588458SPeter Avalos {
814b588458SPeter Avalos 	char temp[50];
824b588458SPeter Avalos 	int i;
834b588458SPeter Avalos 
844b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
8548f09a05SAntonio Huete Jimenez 		fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
864b588458SPeter Avalos 		if (fldtab[i] == NULL)
874b588458SPeter Avalos 			FATAL("out of space in makefields %d", i);
884b588458SPeter Avalos 		*fldtab[i] = dollar1;
891d48fce0SDaniel Fojt 		snprintf(temp, sizeof(temp), "%d", i);
904b588458SPeter Avalos 		fldtab[i]->nval = tostring(temp);
914b588458SPeter Avalos 	}
924b588458SPeter Avalos }
934b588458SPeter Avalos 
initgetrec(void)944b588458SPeter Avalos void initgetrec(void)
954b588458SPeter Avalos {
964b588458SPeter Avalos 	int i;
974b588458SPeter Avalos 	char *p;
984b588458SPeter Avalos 
994b588458SPeter Avalos 	for (i = 1; i < *ARGC; i++) {
100b12bae18SSascha Wildner 		p = getargv(i); /* find 1st real filename */
101b12bae18SSascha Wildner 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
102b12bae18SSascha Wildner 			argno++;
103b12bae18SSascha Wildner 			continue;
104b12bae18SSascha Wildner 		}
105b12bae18SSascha Wildner 		if (!isclvar(p)) {
106b12bae18SSascha Wildner 			setsval(lookup("FILENAME", symtab), p);
1074b588458SPeter Avalos 			return;
1084b588458SPeter Avalos 		}
1094b588458SPeter Avalos 		setclvar(p);	/* a commandline assignment before filename */
1104b588458SPeter Avalos 		argno++;
1114b588458SPeter Avalos 	}
1124b588458SPeter Avalos 	infile = stdin;		/* no filenames, so use stdin */
1131d48fce0SDaniel Fojt 	innew = true;
1144b588458SPeter Avalos }
1154b588458SPeter Avalos 
1161d48fce0SDaniel Fojt /*
1171d48fce0SDaniel Fojt  * POSIX specifies that fields are supposed to be evaluated as if they were
1181d48fce0SDaniel Fojt  * split using the value of FS at the time that the record's value ($0) was
1191d48fce0SDaniel Fojt  * read.
1201d48fce0SDaniel Fojt  *
1211d48fce0SDaniel Fojt  * Since field-splitting is done lazily, we save the current value of FS
1221d48fce0SDaniel Fojt  * whenever a new record is read in (implicitly or via getline), or when
1231d48fce0SDaniel Fojt  * a new value is assigned to $0.
1241d48fce0SDaniel Fojt  */
savefs(void)1251d48fce0SDaniel Fojt void savefs(void)
1261d48fce0SDaniel Fojt {
1271d48fce0SDaniel Fojt 	size_t len;
1281d48fce0SDaniel Fojt 	if ((len = strlen(getsval(fsloc))) < len_inputFS) {
1291d48fce0SDaniel Fojt 		strcpy(inputFS, *FS);	/* for subsequent field splitting */
1301d48fce0SDaniel Fojt 		return;
1311d48fce0SDaniel Fojt 	}
1324b588458SPeter Avalos 
1331d48fce0SDaniel Fojt 	len_inputFS = len + 1;
13448f09a05SAntonio Huete Jimenez 	inputFS = (char *) realloc(inputFS, len_inputFS);
1351d48fce0SDaniel Fojt 	if (inputFS == NULL)
1361d48fce0SDaniel Fojt 		FATAL("field separator %.10s... is too long", *FS);
1371d48fce0SDaniel Fojt 	memcpy(inputFS, *FS, len_inputFS);
1381d48fce0SDaniel Fojt }
1391d48fce0SDaniel Fojt 
1401d48fce0SDaniel Fojt static bool firsttime = true;
1411d48fce0SDaniel Fojt 
getrec(char ** pbuf,int * pbufsize,bool isrecord)1421d48fce0SDaniel Fojt int getrec(char **pbuf, int *pbufsize, bool isrecord)	/* get next input record */
1434b588458SPeter Avalos {			/* note: cares whether buf == record */
1444b588458SPeter Avalos 	int c;
1454b588458SPeter Avalos 	char *buf = *pbuf;
1464b588458SPeter Avalos 	uschar saveb0;
1474b588458SPeter Avalos 	int bufsize = *pbufsize, savebufsize = bufsize;
1484b588458SPeter Avalos 
1494b588458SPeter Avalos 	if (firsttime) {
1501d48fce0SDaniel Fojt 		firsttime = false;
1514b588458SPeter Avalos 		initgetrec();
1524b588458SPeter Avalos 	}
153e5e686a0SDaniel Fojt 	DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
154e5e686a0SDaniel Fojt 		*RS, *FS, *ARGC, *FILENAME);
1554b588458SPeter Avalos 	saveb0 = buf[0];
1564b588458SPeter Avalos 	buf[0] = 0;
1574b588458SPeter Avalos 	while (argno < *ARGC || infile == stdin) {
158e5e686a0SDaniel Fojt 		DPRINTF("argno=%d, file=|%s|\n", argno, file);
1594b588458SPeter Avalos 		if (infile == NULL) {	/* have to open a new file */
1604b588458SPeter Avalos 			file = getargv(argno);
161b12bae18SSascha Wildner 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
1624b588458SPeter Avalos 				argno++;
1634b588458SPeter Avalos 				continue;
1644b588458SPeter Avalos 			}
1654b588458SPeter Avalos 			if (isclvar(file)) {	/* a var=value arg */
1664b588458SPeter Avalos 				setclvar(file);
1674b588458SPeter Avalos 				argno++;
1684b588458SPeter Avalos 				continue;
1694b588458SPeter Avalos 			}
1704b588458SPeter Avalos 			*FILENAME = file;
171e5e686a0SDaniel Fojt 			DPRINTF("opening file %s\n", file);
1724b588458SPeter Avalos 			if (*file == '-' && *(file+1) == '\0')
1734b588458SPeter Avalos 				infile = stdin;
1744b588458SPeter Avalos 			else if ((infile = fopen(file, "r")) == NULL)
1754b588458SPeter Avalos 				FATAL("can't open file %s", file);
17648f09a05SAntonio Huete Jimenez 			innew = true;
1774b588458SPeter Avalos 			setfval(fnrloc, 0.0);
1784b588458SPeter Avalos 		}
1791d48fce0SDaniel Fojt 		c = readrec(&buf, &bufsize, infile, innew);
1801d48fce0SDaniel Fojt 		if (innew)
1811d48fce0SDaniel Fojt 			innew = false;
1824b588458SPeter Avalos 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1834b588458SPeter Avalos 			if (isrecord) {
18448f09a05SAntonio Huete Jimenez 				double result;
18548f09a05SAntonio Huete Jimenez 
1864b588458SPeter Avalos 				if (freeable(fldtab[0]))
1874b588458SPeter Avalos 					xfree(fldtab[0]->sval);
1884b588458SPeter Avalos 				fldtab[0]->sval = buf;	/* buf == record */
1894b588458SPeter Avalos 				fldtab[0]->tval = REC | STR | DONTFREE;
19048f09a05SAntonio Huete Jimenez 				if (is_number(fldtab[0]->sval, & result)) {
19148f09a05SAntonio Huete Jimenez 					fldtab[0]->fval = result;
1924b588458SPeter Avalos 					fldtab[0]->tval |= NUM;
1934b588458SPeter Avalos 				}
194*ed569bc2SAaron LI 				donefld = false;
195*ed569bc2SAaron LI 				donerec = true;
196*ed569bc2SAaron LI 				savefs();
1974b588458SPeter Avalos 			}
1984b588458SPeter Avalos 			setfval(nrloc, nrloc->fval+1);
1994b588458SPeter Avalos 			setfval(fnrloc, fnrloc->fval+1);
2004b588458SPeter Avalos 			*pbuf = buf;
2014b588458SPeter Avalos 			*pbufsize = bufsize;
2024b588458SPeter Avalos 			return 1;
2034b588458SPeter Avalos 		}
2044b588458SPeter Avalos 		/* EOF arrived on this file; set up next */
2054b588458SPeter Avalos 		if (infile != stdin)
2064b588458SPeter Avalos 			fclose(infile);
2074b588458SPeter Avalos 		infile = NULL;
2084b588458SPeter Avalos 		argno++;
2094b588458SPeter Avalos 	}
2104b588458SPeter Avalos 	buf[0] = saveb0;
2114b588458SPeter Avalos 	*pbuf = buf;
2124b588458SPeter Avalos 	*pbufsize = savebufsize;
2134b588458SPeter Avalos 	return 0;	/* true end of file */
2144b588458SPeter Avalos }
2154b588458SPeter Avalos 
nextfile(void)2164b588458SPeter Avalos void nextfile(void)
2174b588458SPeter Avalos {
2184b588458SPeter Avalos 	if (infile != NULL && infile != stdin)
2194b588458SPeter Avalos 		fclose(infile);
2204b588458SPeter Avalos 	infile = NULL;
2214b588458SPeter Avalos 	argno++;
2224b588458SPeter Avalos }
2234b588458SPeter Avalos 
224*ed569bc2SAaron LI extern int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag);
225*ed569bc2SAaron LI 
readrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)2261d48fce0SDaniel Fojt int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag)	/* read one record into buf */
2274b588458SPeter Avalos {
228*ed569bc2SAaron LI 	int sep, c, isrec; // POTENTIAL BUG? isrec is a macro in awk.h
229*ed569bc2SAaron LI 	char *rr = *pbuf, *buf = *pbuf;
2304b588458SPeter Avalos 	int bufsize = *pbufsize;
2311d48fce0SDaniel Fojt 	char *rs = getsval(rsloc);
2324b588458SPeter Avalos 
233*ed569bc2SAaron LI 	if (CSV) {
234*ed569bc2SAaron LI 		c = readcsvrec(pbuf, pbufsize, inf, newflag);
235*ed569bc2SAaron LI 		isrec = (c == EOF && rr == buf) ? false : true;
236*ed569bc2SAaron LI 	} else if (*rs && rs[1]) {
2371d48fce0SDaniel Fojt 		bool found;
2381d48fce0SDaniel Fojt 
239*ed569bc2SAaron LI 		memset(buf, 0, bufsize);
2401d48fce0SDaniel Fojt 		fa *pfa = makedfa(rs, 1);
2411d48fce0SDaniel Fojt 		if (newflag)
2421d48fce0SDaniel Fojt 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2431d48fce0SDaniel Fojt 		else {
2441d48fce0SDaniel Fojt 			int tempstat = pfa->initstat;
2451d48fce0SDaniel Fojt 			pfa->initstat = 2;
2461d48fce0SDaniel Fojt 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
2471d48fce0SDaniel Fojt 			pfa->initstat = tempstat;
2481d48fce0SDaniel Fojt 		}
2491d48fce0SDaniel Fojt 		if (found)
2501d48fce0SDaniel Fojt 			setptr(patbeg, '\0');
25148f09a05SAntonio Huete Jimenez 		isrec = (found == 0 && *buf == '\0') ? false : true;
252*ed569bc2SAaron LI 
2531d48fce0SDaniel Fojt 	} else {
2541d48fce0SDaniel Fojt 		if ((sep = *rs) == 0) {
2554b588458SPeter Avalos 			sep = '\n';
2564b588458SPeter Avalos 			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
2574b588458SPeter Avalos 				;
2584b588458SPeter Avalos 			if (c != EOF)
2594b588458SPeter Avalos 				ungetc(c, inf);
2604b588458SPeter Avalos 		}
2614b588458SPeter Avalos 		for (rr = buf; ; ) {
2624b588458SPeter Avalos 			for (; (c=getc(inf)) != sep && c != EOF; ) {
2634b588458SPeter Avalos 				if (rr-buf+1 > bufsize)
2641d48fce0SDaniel Fojt 					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
2651d48fce0SDaniel Fojt 					    recsize, &rr, "readrec 1"))
2664b588458SPeter Avalos 						FATAL("input record `%.30s...' too long", buf);
2674b588458SPeter Avalos 				*rr++ = c;
2684b588458SPeter Avalos 			}
2691d48fce0SDaniel Fojt 			if (*rs == sep || c == EOF)
2704b588458SPeter Avalos 				break;
2714b588458SPeter Avalos 			if ((c = getc(inf)) == '\n' || c == EOF)	/* 2 in a row */
2724b588458SPeter Avalos 				break;
2731d48fce0SDaniel Fojt 			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
2741d48fce0SDaniel Fojt 			    "readrec 2"))
2754b588458SPeter Avalos 				FATAL("input record `%.30s...' too long", buf);
2764b588458SPeter Avalos 			*rr++ = '\n';
2774b588458SPeter Avalos 			*rr++ = c;
2784b588458SPeter Avalos 		}
2794b588458SPeter Avalos 		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2804b588458SPeter Avalos 			FATAL("input record `%.30s...' too long", buf);
2814b588458SPeter Avalos 		*rr = 0;
28248f09a05SAntonio Huete Jimenez 		isrec = (c == EOF && rr == buf) ? false : true;
2831d48fce0SDaniel Fojt 	}
2844b588458SPeter Avalos 	*pbuf = buf;
2854b588458SPeter Avalos 	*pbufsize = bufsize;
286e5e686a0SDaniel Fojt 	DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
2871d48fce0SDaniel Fojt 	return isrec;
2884b588458SPeter Avalos }
2894b588458SPeter Avalos 
290*ed569bc2SAaron LI 
291*ed569bc2SAaron LI /*******************
292*ed569bc2SAaron LI  * loose ends here:
293*ed569bc2SAaron LI  *   \r\n should become \n
294*ed569bc2SAaron LI  *   what about bare \r?  Excel uses that for embedded newlines
295*ed569bc2SAaron LI  *   can't have "" in unquoted fields, according to RFC 4180
296*ed569bc2SAaron LI */
297*ed569bc2SAaron LI 
298*ed569bc2SAaron LI 
readcsvrec(char ** pbuf,int * pbufsize,FILE * inf,bool newflag)299*ed569bc2SAaron LI int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* csv can have \n's */
300*ed569bc2SAaron LI {			/* so read a complete record that might be multiple lines */
301*ed569bc2SAaron LI 	int sep, c;
302*ed569bc2SAaron LI 	char *rr = *pbuf, *buf = *pbuf;
303*ed569bc2SAaron LI 	int bufsize = *pbufsize;
304*ed569bc2SAaron LI 	bool in_quote = false;
305*ed569bc2SAaron LI 
306*ed569bc2SAaron LI 	sep = '\n'; /* the only separator; have to skip over \n embedded in "..." */
307*ed569bc2SAaron LI 	rr = buf;
308*ed569bc2SAaron LI 	while ((c = getc(inf)) != EOF) {
309*ed569bc2SAaron LI 		if (c == sep) {
310*ed569bc2SAaron LI 			if (! in_quote)
311*ed569bc2SAaron LI 				break;
312*ed569bc2SAaron LI 			if (rr > buf && rr[-1] == '\r')	// remove \r if was \r\n
313*ed569bc2SAaron LI 				rr--;
314*ed569bc2SAaron LI 		}
315*ed569bc2SAaron LI 
316*ed569bc2SAaron LI 		if (rr-buf+1 > bufsize)
317*ed569bc2SAaron LI 			if (!adjbuf(&buf, &bufsize, 1+rr-buf,
318*ed569bc2SAaron LI 			    recsize, &rr, "readcsvrec 1"))
319*ed569bc2SAaron LI 				FATAL("input record `%.30s...' too long", buf);
320*ed569bc2SAaron LI 		*rr++ = c;
321*ed569bc2SAaron LI 		if (c == '"')
322*ed569bc2SAaron LI 			in_quote = ! in_quote;
323*ed569bc2SAaron LI  	}
324*ed569bc2SAaron LI 	if (c == '\n' && rr > buf && rr[-1] == '\r') 	// remove \r if was \r\n
325*ed569bc2SAaron LI 		rr--;
326*ed569bc2SAaron LI 
327*ed569bc2SAaron LI 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readcsvrec 4"))
328*ed569bc2SAaron LI 		FATAL("input record `%.30s...' too long", buf);
329*ed569bc2SAaron LI 	*rr = 0;
330*ed569bc2SAaron LI 	*pbuf = buf;
331*ed569bc2SAaron LI 	*pbufsize = bufsize;
332*ed569bc2SAaron LI 	DPRINTF("readcsvrec saw <%s>, returns %d\n", buf, c);
333*ed569bc2SAaron LI 	return c;
334*ed569bc2SAaron LI }
335*ed569bc2SAaron LI 
getargv(int n)3364b588458SPeter Avalos char *getargv(int n)	/* get ARGV[n] */
3374b588458SPeter Avalos {
3384b588458SPeter Avalos 	Cell *x;
3394b588458SPeter Avalos 	char *s, temp[50];
3404b588458SPeter Avalos 	extern Array *ARGVtab;
3414b588458SPeter Avalos 
3421d48fce0SDaniel Fojt 	snprintf(temp, sizeof(temp), "%d", n);
343b12bae18SSascha Wildner 	if (lookup(temp, ARGVtab) == NULL)
344b12bae18SSascha Wildner 		return NULL;
3454b588458SPeter Avalos 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
3464b588458SPeter Avalos 	s = getsval(x);
347e5e686a0SDaniel Fojt 	DPRINTF("getargv(%d) returns |%s|\n", n, s);
3484b588458SPeter Avalos 	return s;
3494b588458SPeter Avalos }
3504b588458SPeter Avalos 
setclvar(char * s)3514b588458SPeter Avalos void setclvar(char *s)	/* set var=value from s */
3524b588458SPeter Avalos {
35348f09a05SAntonio Huete Jimenez 	char *e, *p;
3544b588458SPeter Avalos 	Cell *q;
35548f09a05SAntonio Huete Jimenez 	double result;
3564b588458SPeter Avalos 
357*ed569bc2SAaron LI /* commit f3d9187d4e0f02294fb1b0e31152070506314e67 broke T.argv test */
358*ed569bc2SAaron LI /* I don't understand why it was changed. */
359*ed569bc2SAaron LI 
3604b588458SPeter Avalos 	for (p=s; *p != '='; p++)
3614b588458SPeter Avalos 		;
36248f09a05SAntonio Huete Jimenez 	e = p;
3634b588458SPeter Avalos 	*p++ = 0;
3644b588458SPeter Avalos 	p = qstring(p, '\0');
3654b588458SPeter Avalos 	q = setsymtab(s, p, 0.0, STR, symtab);
3664b588458SPeter Avalos 	setsval(q, p);
36748f09a05SAntonio Huete Jimenez 	if (is_number(q->sval, & result)) {
36848f09a05SAntonio Huete Jimenez 		q->fval = result;
3694b588458SPeter Avalos 		q->tval |= NUM;
3704b588458SPeter Avalos 	}
371e5e686a0SDaniel Fojt 	DPRINTF("command line set %s to |%s|\n", s, p);
37248f09a05SAntonio Huete Jimenez 	free(p);
37348f09a05SAntonio Huete Jimenez 	*e = '=';
3744b588458SPeter Avalos }
3754b588458SPeter Avalos 
3764b588458SPeter Avalos 
fldbld(void)3774b588458SPeter Avalos void fldbld(void)	/* create fields from current record */
3784b588458SPeter Avalos {
3794b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
3804b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
3810020174dSPeter Avalos 	/* possibly with a final trailing \0 not associated with any field */
3824b588458SPeter Avalos 	char *r, *fr, sep;
3834b588458SPeter Avalos 	Cell *p;
3844b588458SPeter Avalos 	int i, j, n;
3854b588458SPeter Avalos 
3864b588458SPeter Avalos 	if (donefld)
3874b588458SPeter Avalos 		return;
3884b588458SPeter Avalos 	if (!isstr(fldtab[0]))
3894b588458SPeter Avalos 		getsval(fldtab[0]);
3904b588458SPeter Avalos 	r = fldtab[0]->sval;
3914b588458SPeter Avalos 	n = strlen(r);
3924b588458SPeter Avalos 	if (n > fieldssize) {
3934b588458SPeter Avalos 		xfree(fields);
39448f09a05SAntonio Huete Jimenez 		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
3954b588458SPeter Avalos 			FATAL("out of space for fields in fldbld %d", n);
3964b588458SPeter Avalos 		fieldssize = n;
3974b588458SPeter Avalos 	}
3984b588458SPeter Avalos 	fr = fields;
3994b588458SPeter Avalos 	i = 0;	/* number of fields accumulated here */
4001d48fce0SDaniel Fojt 	if (inputFS == NULL)	/* make sure we have a copy of FS */
4011d48fce0SDaniel Fojt 		savefs();
402*ed569bc2SAaron LI 	if (!CSV && strlen(inputFS) > 1) {	/* it's a regular expression */
4034b588458SPeter Avalos 		i = refldbld(r, inputFS);
404*ed569bc2SAaron LI 	} else if (!CSV && (sep = *inputFS) == ' ') {	/* default whitespace */
4054b588458SPeter Avalos 		for (i = 0; ; ) {
4064b588458SPeter Avalos 			while (*r == ' ' || *r == '\t' || *r == '\n')
4074b588458SPeter Avalos 				r++;
4084b588458SPeter Avalos 			if (*r == 0)
4094b588458SPeter Avalos 				break;
4104b588458SPeter Avalos 			i++;
4114b588458SPeter Avalos 			if (i > nfields)
4124b588458SPeter Avalos 				growfldtab(i);
4134b588458SPeter Avalos 			if (freeable(fldtab[i]))
4144b588458SPeter Avalos 				xfree(fldtab[i]->sval);
4154b588458SPeter Avalos 			fldtab[i]->sval = fr;
4164b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
4174b588458SPeter Avalos 			do
4184b588458SPeter Avalos 				*fr++ = *r++;
4194b588458SPeter Avalos 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
4204b588458SPeter Avalos 			*fr++ = 0;
4214b588458SPeter Avalos 		}
4224b588458SPeter Avalos 		*fr = 0;
423*ed569bc2SAaron LI 	} else if (CSV) {	/* CSV processing.  no error handling */
424*ed569bc2SAaron LI 		if (*r != 0) {
425*ed569bc2SAaron LI 			for (;;) {
4264b588458SPeter Avalos 				i++;
4274b588458SPeter Avalos 				if (i > nfields)
4284b588458SPeter Avalos 					growfldtab(i);
4294b588458SPeter Avalos 				if (freeable(fldtab[i]))
4304b588458SPeter Avalos 					xfree(fldtab[i]->sval);
431*ed569bc2SAaron LI 				fldtab[i]->sval = fr;
432*ed569bc2SAaron LI 				fldtab[i]->tval = FLD | STR | DONTFREE;
433*ed569bc2SAaron LI 				if (*r == '"' ) { /* start of "..." */
434*ed569bc2SAaron LI 					for (r++ ; *r != '\0'; ) {
435*ed569bc2SAaron LI 						if (*r == '"' && r[1] != '\0' && r[1] == '"') {
436*ed569bc2SAaron LI 							r += 2; /* doubled quote */
437*ed569bc2SAaron LI 							*fr++ = '"';
438*ed569bc2SAaron LI 						} else if (*r == '"' && (r[1] == '\0' || r[1] == ',')) {
439*ed569bc2SAaron LI 							r++; /* skip over closing quote */
440*ed569bc2SAaron LI 							break;
441*ed569bc2SAaron LI 						} else {
442*ed569bc2SAaron LI 							*fr++ = *r++;
443*ed569bc2SAaron LI 						}
444*ed569bc2SAaron LI 					}
445*ed569bc2SAaron LI 					*fr++ = 0;
446*ed569bc2SAaron LI 				} else {	/* unquoted field */
447*ed569bc2SAaron LI 					while (*r != ',' && *r != '\0')
448*ed569bc2SAaron LI 						*fr++ = *r++;
449*ed569bc2SAaron LI 					*fr++ = 0;
450*ed569bc2SAaron LI 				}
451*ed569bc2SAaron LI 				if (*r++ == 0)
452*ed569bc2SAaron LI 					break;
453*ed569bc2SAaron LI 
454*ed569bc2SAaron LI 			}
455*ed569bc2SAaron LI 		}
456*ed569bc2SAaron LI 		*fr = 0;
457*ed569bc2SAaron LI 	} else if ((sep = *inputFS) == 0) {	/* new: FS="" => 1 char/field */
458*ed569bc2SAaron LI 		for (i = 0; *r != '\0'; ) {
459*ed569bc2SAaron LI 			char buf[10];
460*ed569bc2SAaron LI 			i++;
461*ed569bc2SAaron LI 			if (i > nfields)
462*ed569bc2SAaron LI 				growfldtab(i);
463*ed569bc2SAaron LI 			if (freeable(fldtab[i]))
464*ed569bc2SAaron LI 				xfree(fldtab[i]->sval);
465*ed569bc2SAaron LI 			n = u8_nextlen(r);
466*ed569bc2SAaron LI 			for (j = 0; j < n; j++)
467*ed569bc2SAaron LI 				buf[j] = *r++;
468*ed569bc2SAaron LI 			buf[j] = '\0';
4694b588458SPeter Avalos 			fldtab[i]->sval = tostring(buf);
4704b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR;
4714b588458SPeter Avalos 		}
4724b588458SPeter Avalos 		*fr = 0;
4734b588458SPeter Avalos 	} else if (*r != 0) {	/* if 0, it's a null field */
4744b588458SPeter Avalos 		/* subtle case: if length(FS) == 1 && length(RS > 0)
4754b588458SPeter Avalos 		 * \n is NOT a field separator (cf awk book 61,84).
4764b588458SPeter Avalos 		 * this variable is tested in the inner while loop.
4774b588458SPeter Avalos 		 */
4784b588458SPeter Avalos 		int rtest = '\n';  /* normal case */
4794b588458SPeter Avalos 		if (strlen(*RS) > 0)
4804b588458SPeter Avalos 			rtest = '\0';
4814b588458SPeter Avalos 		for (;;) {
4824b588458SPeter Avalos 			i++;
4834b588458SPeter Avalos 			if (i > nfields)
4844b588458SPeter Avalos 				growfldtab(i);
4854b588458SPeter Avalos 			if (freeable(fldtab[i]))
4864b588458SPeter Avalos 				xfree(fldtab[i]->sval);
4874b588458SPeter Avalos 			fldtab[i]->sval = fr;
4884b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
4894b588458SPeter Avalos 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
4904b588458SPeter Avalos 				*fr++ = *r++;
4914b588458SPeter Avalos 			*fr++ = 0;
4924b588458SPeter Avalos 			if (*r++ == 0)
4934b588458SPeter Avalos 				break;
4944b588458SPeter Avalos 		}
4954b588458SPeter Avalos 		*fr = 0;
4964b588458SPeter Avalos 	}
4974b588458SPeter Avalos 	if (i > nfields)
4984b588458SPeter Avalos 		FATAL("record `%.30s...' has too many fields; can't happen", r);
4994b588458SPeter Avalos 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
5004b588458SPeter Avalos 	lastfld = i;
5011d48fce0SDaniel Fojt 	donefld = true;
5024b588458SPeter Avalos 	for (j = 1; j <= lastfld; j++) {
50348f09a05SAntonio Huete Jimenez 		double result;
50448f09a05SAntonio Huete Jimenez 
5054b588458SPeter Avalos 		p = fldtab[j];
50648f09a05SAntonio Huete Jimenez 		if(is_number(p->sval, & result)) {
50748f09a05SAntonio Huete Jimenez 			p->fval = result;
5084b588458SPeter Avalos 			p->tval |= NUM;
5094b588458SPeter Avalos 		}
5104b588458SPeter Avalos 	}
5114b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) lastfld);
5121d48fce0SDaniel Fojt 	donerec = true; /* restore */
5134b588458SPeter Avalos 	if (dbg) {
5144b588458SPeter Avalos 		for (j = 0; j <= lastfld; j++) {
5154b588458SPeter Avalos 			p = fldtab[j];
5164b588458SPeter Avalos 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
5174b588458SPeter Avalos 		}
5184b588458SPeter Avalos 	}
5194b588458SPeter Avalos }
5204b588458SPeter Avalos 
cleanfld(int n1,int n2)5214b588458SPeter Avalos void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
5224b588458SPeter Avalos {				/* nvals remain intact */
5234b588458SPeter Avalos 	Cell *p;
5244b588458SPeter Avalos 	int i;
5254b588458SPeter Avalos 
5264b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
5274b588458SPeter Avalos 		p = fldtab[i];
5284b588458SPeter Avalos 		if (freeable(p))
5294b588458SPeter Avalos 			xfree(p->sval);
5301d48fce0SDaniel Fojt 		p->sval = EMPTY,
5314b588458SPeter Avalos 		p->tval = FLD | STR | DONTFREE;
5324b588458SPeter Avalos 	}
5334b588458SPeter Avalos }
5344b588458SPeter Avalos 
newfld(int n)5354b588458SPeter Avalos void newfld(int n)	/* add field n after end of existing lastfld */
5364b588458SPeter Avalos {
5374b588458SPeter Avalos 	if (n > nfields)
5384b588458SPeter Avalos 		growfldtab(n);
5394b588458SPeter Avalos 	cleanfld(lastfld+1, n);
5404b588458SPeter Avalos 	lastfld = n;
5414b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) n);
5424b588458SPeter Avalos }
5434b588458SPeter Avalos 
setlastfld(int n)5441d48fce0SDaniel Fojt void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
5451d48fce0SDaniel Fojt {
5461d48fce0SDaniel Fojt 	if (n < 0)
5471d48fce0SDaniel Fojt 		FATAL("cannot set NF to a negative value");
5481d48fce0SDaniel Fojt 	if (n > nfields)
5491d48fce0SDaniel Fojt 		growfldtab(n);
5501d48fce0SDaniel Fojt 
5511d48fce0SDaniel Fojt 	if (lastfld < n)
5521d48fce0SDaniel Fojt 	    cleanfld(lastfld+1, n);
5531d48fce0SDaniel Fojt 	else
5541d48fce0SDaniel Fojt 	    cleanfld(n+1, lastfld);
5551d48fce0SDaniel Fojt 
5561d48fce0SDaniel Fojt 	lastfld = n;
5571d48fce0SDaniel Fojt }
5581d48fce0SDaniel Fojt 
fieldadr(int n)5594b588458SPeter Avalos Cell *fieldadr(int n)	/* get nth field */
5604b588458SPeter Avalos {
5614b588458SPeter Avalos 	if (n < 0)
5624b588458SPeter Avalos 		FATAL("trying to access out of range field %d", n);
5634b588458SPeter Avalos 	if (n > nfields)	/* fields after NF are empty */
5644b588458SPeter Avalos 		growfldtab(n);	/* but does not increase NF */
5654b588458SPeter Avalos 	return(fldtab[n]);
5664b588458SPeter Avalos }
5674b588458SPeter Avalos 
growfldtab(int n)5684b588458SPeter Avalos void growfldtab(int n)	/* make new fields up to at least $n */
5694b588458SPeter Avalos {
5704b588458SPeter Avalos 	int nf = 2 * nfields;
5714b588458SPeter Avalos 	size_t s;
5724b588458SPeter Avalos 
5734b588458SPeter Avalos 	if (n > nf)
5744b588458SPeter Avalos 		nf = n;
5754b588458SPeter Avalos 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
5761d48fce0SDaniel Fojt 	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
57748f09a05SAntonio Huete Jimenez 		fldtab = (Cell **) realloc(fldtab, s);
5784b588458SPeter Avalos 	else					/* overflow sizeof int */
5794b588458SPeter Avalos 		xfree(fldtab);	/* make it null */
5804b588458SPeter Avalos 	if (fldtab == NULL)
5814b588458SPeter Avalos 		FATAL("out of space creating %d fields", nf);
5824b588458SPeter Avalos 	makefields(nfields+1, nf);
5834b588458SPeter Avalos 	nfields = nf;
5844b588458SPeter Avalos }
5854b588458SPeter Avalos 
refldbld(const char * rec,const char * fs)5864b588458SPeter Avalos int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
5874b588458SPeter Avalos {
5884b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
5894b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
5904b588458SPeter Avalos 	char *fr;
5914b588458SPeter Avalos 	int i, tempstat, n;
5924b588458SPeter Avalos 	fa *pfa;
5934b588458SPeter Avalos 
5944b588458SPeter Avalos 	n = strlen(rec);
5954b588458SPeter Avalos 	if (n > fieldssize) {
5964b588458SPeter Avalos 		xfree(fields);
59748f09a05SAntonio Huete Jimenez 		if ((fields = (char *) malloc(n+1)) == NULL)
5984b588458SPeter Avalos 			FATAL("out of space for fields in refldbld %d", n);
5994b588458SPeter Avalos 		fieldssize = n;
6004b588458SPeter Avalos 	}
6014b588458SPeter Avalos 	fr = fields;
6024b588458SPeter Avalos 	*fr = '\0';
6034b588458SPeter Avalos 	if (*rec == '\0')
6044b588458SPeter Avalos 		return 0;
6054b588458SPeter Avalos 	pfa = makedfa(fs, 1);
606e5e686a0SDaniel Fojt 	DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs);
6074b588458SPeter Avalos 	tempstat = pfa->initstat;
6084b588458SPeter Avalos 	for (i = 1; ; i++) {
6094b588458SPeter Avalos 		if (i > nfields)
6104b588458SPeter Avalos 			growfldtab(i);
6114b588458SPeter Avalos 		if (freeable(fldtab[i]))
6124b588458SPeter Avalos 			xfree(fldtab[i]->sval);
6134b588458SPeter Avalos 		fldtab[i]->tval = FLD | STR | DONTFREE;
6144b588458SPeter Avalos 		fldtab[i]->sval = fr;
615e5e686a0SDaniel Fojt 		DPRINTF("refldbld: i=%d\n", i);
6164b588458SPeter Avalos 		if (nematch(pfa, rec)) {
6174b588458SPeter Avalos 			pfa->initstat = 2;	/* horrible coupling to b.c */
618e5e686a0SDaniel Fojt 			DPRINTF("match %s (%d chars)\n", patbeg, patlen);
6194b588458SPeter Avalos 			strncpy(fr, rec, patbeg-rec);
6204b588458SPeter Avalos 			fr += patbeg - rec + 1;
6214b588458SPeter Avalos 			*(fr-1) = '\0';
6224b588458SPeter Avalos 			rec = patbeg + patlen;
6234b588458SPeter Avalos 		} else {
624e5e686a0SDaniel Fojt 			DPRINTF("no match %s\n", rec);
6254b588458SPeter Avalos 			strcpy(fr, rec);
6264b588458SPeter Avalos 			pfa->initstat = tempstat;
6274b588458SPeter Avalos 			break;
6284b588458SPeter Avalos 		}
6294b588458SPeter Avalos 	}
6304b588458SPeter Avalos 	return i;
6314b588458SPeter Avalos }
6324b588458SPeter Avalos 
recbld(void)6334b588458SPeter Avalos void recbld(void)	/* create $0 from $1..$NF if necessary */
6344b588458SPeter Avalos {
6354b588458SPeter Avalos 	int i;
6364b588458SPeter Avalos 	char *r, *p;
6371d48fce0SDaniel Fojt 	char *sep = getsval(ofsloc);
6384b588458SPeter Avalos 
6391d48fce0SDaniel Fojt 	if (donerec)
6404b588458SPeter Avalos 		return;
6414b588458SPeter Avalos 	r = record;
6424b588458SPeter Avalos 	for (i = 1; i <= *NF; i++) {
6434b588458SPeter Avalos 		p = getsval(fldtab[i]);
6444b588458SPeter Avalos 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
6454b588458SPeter Avalos 			FATAL("created $0 `%.30s...' too long", record);
6464b588458SPeter Avalos 		while ((*r = *p++) != 0)
6474b588458SPeter Avalos 			r++;
6484b588458SPeter Avalos 		if (i < *NF) {
6491d48fce0SDaniel Fojt 			if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
6504b588458SPeter Avalos 				FATAL("created $0 `%.30s...' too long", record);
6511d48fce0SDaniel Fojt 			for (p = sep; (*r = *p++) != 0; )
6524b588458SPeter Avalos 				r++;
6534b588458SPeter Avalos 		}
6544b588458SPeter Avalos 	}
6554b588458SPeter Avalos 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
6564b588458SPeter Avalos 		FATAL("built giant record `%.30s...'", record);
6574b588458SPeter Avalos 	*r = '\0';
658e5e686a0SDaniel Fojt 	DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
6594b588458SPeter Avalos 
6604b588458SPeter Avalos 	if (freeable(fldtab[0]))
6614b588458SPeter Avalos 		xfree(fldtab[0]->sval);
6624b588458SPeter Avalos 	fldtab[0]->tval = REC | STR | DONTFREE;
6634b588458SPeter Avalos 	fldtab[0]->sval = record;
6644b588458SPeter Avalos 
665e5e686a0SDaniel Fojt 	DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
666e5e686a0SDaniel Fojt 	DPRINTF("recbld = |%s|\n", record);
6671d48fce0SDaniel Fojt 	donerec = true;
6684b588458SPeter Avalos }
6694b588458SPeter Avalos 
6704b588458SPeter Avalos int	errorflag	= 0;
6714b588458SPeter Avalos 
yyerror(const char * s)6724b588458SPeter Avalos void yyerror(const char *s)
6734b588458SPeter Avalos {
6744b588458SPeter Avalos 	SYNTAX("%s", s);
6754b588458SPeter Avalos }
6764b588458SPeter Avalos 
SYNTAX(const char * fmt,...)6774b588458SPeter Avalos void SYNTAX(const char *fmt, ...)
6784b588458SPeter Avalos {
6794b588458SPeter Avalos 	extern char *cmdname, *curfname;
6804b588458SPeter Avalos 	static int been_here = 0;
6814b588458SPeter Avalos 	va_list varg;
6824b588458SPeter Avalos 
6834b588458SPeter Avalos 	if (been_here++ > 2)
6844b588458SPeter Avalos 		return;
6854b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
6864b588458SPeter Avalos 	va_start(varg, fmt);
6874b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
6884b588458SPeter Avalos 	va_end(varg);
6894b588458SPeter Avalos 	fprintf(stderr, " at source line %d", lineno);
6904b588458SPeter Avalos 	if (curfname != NULL)
6914b588458SPeter Avalos 		fprintf(stderr, " in function %s", curfname);
6921d48fce0SDaniel Fojt 	if (compile_time == COMPILING && cursource() != NULL)
6934b588458SPeter Avalos 		fprintf(stderr, " source file %s", cursource());
6944b588458SPeter Avalos 	fprintf(stderr, "\n");
6954b588458SPeter Avalos 	errorflag = 2;
6964b588458SPeter Avalos 	eprint();
6974b588458SPeter Avalos }
6984b588458SPeter Avalos 
6994b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt;
7004b588458SPeter Avalos 
bracecheck(void)7014b588458SPeter Avalos void bracecheck(void)
7024b588458SPeter Avalos {
7034b588458SPeter Avalos 	int c;
7044b588458SPeter Avalos 	static int beenhere = 0;
7054b588458SPeter Avalos 
7064b588458SPeter Avalos 	if (beenhere++)
7074b588458SPeter Avalos 		return;
7084b588458SPeter Avalos 	while ((c = input()) != EOF && c != '\0')
7094b588458SPeter Avalos 		bclass(c);
7104b588458SPeter Avalos 	bcheck2(bracecnt, '{', '}');
7114b588458SPeter Avalos 	bcheck2(brackcnt, '[', ']');
7124b588458SPeter Avalos 	bcheck2(parencnt, '(', ')');
7134b588458SPeter Avalos }
7144b588458SPeter Avalos 
bcheck2(int n,int c1,int c2)7154b588458SPeter Avalos void bcheck2(int n, int c1, int c2)
7164b588458SPeter Avalos {
7174b588458SPeter Avalos 	if (n == 1)
7184b588458SPeter Avalos 		fprintf(stderr, "\tmissing %c\n", c2);
7194b588458SPeter Avalos 	else if (n > 1)
7204b588458SPeter Avalos 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
7214b588458SPeter Avalos 	else if (n == -1)
7224b588458SPeter Avalos 		fprintf(stderr, "\textra %c\n", c2);
7234b588458SPeter Avalos 	else if (n < -1)
7244b588458SPeter Avalos 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
7254b588458SPeter Avalos }
7264b588458SPeter Avalos 
FATAL(const char * fmt,...)7274b588458SPeter Avalos void FATAL(const char *fmt, ...)
7284b588458SPeter Avalos {
7294b588458SPeter Avalos 	extern char *cmdname;
7304b588458SPeter Avalos 	va_list varg;
7314b588458SPeter Avalos 
7324b588458SPeter Avalos 	fflush(stdout);
7334b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
7344b588458SPeter Avalos 	va_start(varg, fmt);
7354b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
7364b588458SPeter Avalos 	va_end(varg);
7374b588458SPeter Avalos 	error();
7384b588458SPeter Avalos 	if (dbg > 1)		/* core dump if serious debugging on */
7394b588458SPeter Avalos 		abort();
7404b588458SPeter Avalos 	exit(2);
7414b588458SPeter Avalos }
7424b588458SPeter Avalos 
WARNING(const char * fmt,...)7434b588458SPeter Avalos void WARNING(const char *fmt, ...)
7444b588458SPeter Avalos {
7454b588458SPeter Avalos 	extern char *cmdname;
7464b588458SPeter Avalos 	va_list varg;
7474b588458SPeter Avalos 
7484b588458SPeter Avalos 	fflush(stdout);
7494b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
7504b588458SPeter Avalos 	va_start(varg, fmt);
7514b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
7524b588458SPeter Avalos 	va_end(varg);
7534b588458SPeter Avalos 	error();
7544b588458SPeter Avalos }
7554b588458SPeter Avalos 
error()7564b588458SPeter Avalos void error()
7574b588458SPeter Avalos {
7584b588458SPeter Avalos 	extern Node *curnode;
7594b588458SPeter Avalos 
7604b588458SPeter Avalos 	fprintf(stderr, "\n");
7611d48fce0SDaniel Fojt 	if (compile_time != ERROR_PRINTING) {
7621d48fce0SDaniel Fojt 		if (NR && *NR > 0) {
7634b588458SPeter Avalos 			fprintf(stderr, " input record number %d", (int) (*FNR));
7644b588458SPeter Avalos 			if (strcmp(*FILENAME, "-") != 0)
7654b588458SPeter Avalos 				fprintf(stderr, ", file %s", *FILENAME);
7664b588458SPeter Avalos 			fprintf(stderr, "\n");
7674b588458SPeter Avalos 		}
7681d48fce0SDaniel Fojt 		if (curnode)
7694b588458SPeter Avalos 			fprintf(stderr, " source line number %d", curnode->lineno);
7701d48fce0SDaniel Fojt 		else if (lineno)
7714b588458SPeter Avalos 			fprintf(stderr, " source line number %d", lineno);
7721d48fce0SDaniel Fojt 		if (compile_time == COMPILING && cursource() != NULL)
7734b588458SPeter Avalos 			fprintf(stderr, " source file %s", cursource());
7744b588458SPeter Avalos 		fprintf(stderr, "\n");
7754b588458SPeter Avalos 		eprint();
7764b588458SPeter Avalos 	}
77748f09a05SAntonio Huete Jimenez }
7784b588458SPeter Avalos 
eprint(void)7794b588458SPeter Avalos void eprint(void)	/* try to print context around error */
7804b588458SPeter Avalos {
7814b588458SPeter Avalos 	char *p, *q;
7824b588458SPeter Avalos 	int c;
7834b588458SPeter Avalos 	static int been_here = 0;
7844b588458SPeter Avalos 	extern char ebuf[], *ep;
7854b588458SPeter Avalos 
7861d48fce0SDaniel Fojt 	if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
7871d48fce0SDaniel Fojt 		return;
7881d48fce0SDaniel Fojt 	if (ebuf == ep)
7894b588458SPeter Avalos 		return;
7904b588458SPeter Avalos 	p = ep - 1;
7914b588458SPeter Avalos 	if (p > ebuf && *p == '\n')
7924b588458SPeter Avalos 		p--;
7934b588458SPeter Avalos 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
7944b588458SPeter Avalos 		;
7954b588458SPeter Avalos 	while (*p == '\n')
7964b588458SPeter Avalos 		p++;
7974b588458SPeter Avalos 	fprintf(stderr, " context is\n\t");
7984b588458SPeter Avalos 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
7994b588458SPeter Avalos 		;
8004b588458SPeter Avalos 	for ( ; p < q; p++)
8014b588458SPeter Avalos 		if (*p)
8024b588458SPeter Avalos 			putc(*p, stderr);
8034b588458SPeter Avalos 	fprintf(stderr, " >>> ");
8044b588458SPeter Avalos 	for ( ; p < ep; p++)
8054b588458SPeter Avalos 		if (*p)
8064b588458SPeter Avalos 			putc(*p, stderr);
8074b588458SPeter Avalos 	fprintf(stderr, " <<< ");
8084b588458SPeter Avalos 	if (*ep)
8094b588458SPeter Avalos 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
8104b588458SPeter Avalos 			putc(c, stderr);
8114b588458SPeter Avalos 			bclass(c);
8124b588458SPeter Avalos 		}
8134b588458SPeter Avalos 	putc('\n', stderr);
8144b588458SPeter Avalos 	ep = ebuf;
8154b588458SPeter Avalos }
8164b588458SPeter Avalos 
bclass(int c)8174b588458SPeter Avalos void bclass(int c)
8184b588458SPeter Avalos {
8194b588458SPeter Avalos 	switch (c) {
8204b588458SPeter Avalos 	case '{': bracecnt++; break;
8214b588458SPeter Avalos 	case '}': bracecnt--; break;
8224b588458SPeter Avalos 	case '[': brackcnt++; break;
8234b588458SPeter Avalos 	case ']': brackcnt--; break;
8244b588458SPeter Avalos 	case '(': parencnt++; break;
8254b588458SPeter Avalos 	case ')': parencnt--; break;
8264b588458SPeter Avalos 	}
8274b588458SPeter Avalos }
8284b588458SPeter Avalos 
errcheck(double x,const char * s)8294b588458SPeter Avalos double errcheck(double x, const char *s)
8304b588458SPeter Avalos {
8314b588458SPeter Avalos 
8324b588458SPeter Avalos 	if (errno == EDOM) {
8334b588458SPeter Avalos 		errno = 0;
8344b588458SPeter Avalos 		WARNING("%s argument out of domain", s);
8354b588458SPeter Avalos 		x = 1;
8364b588458SPeter Avalos 	} else if (errno == ERANGE) {
8374b588458SPeter Avalos 		errno = 0;
8384b588458SPeter Avalos 		WARNING("%s result out of range", s);
8394b588458SPeter Avalos 		x = 1;
8404b588458SPeter Avalos 	}
8414b588458SPeter Avalos 	return x;
8424b588458SPeter Avalos }
8434b588458SPeter Avalos 
isclvar(const char * s)8444b588458SPeter Avalos int isclvar(const char *s)	/* is s of form var=something ? */
8454b588458SPeter Avalos {
8464b588458SPeter Avalos 	const char *os = s;
8474b588458SPeter Avalos 
848*ed569bc2SAaron LI 	if (!isalpha((int) *s) && *s != '_')
8494b588458SPeter Avalos 		return 0;
8504b588458SPeter Avalos 	for ( ; *s; s++)
851*ed569bc2SAaron LI 		if (!(isalnum((int) *s) || *s == '_'))
8524b588458SPeter Avalos 			break;
8531d48fce0SDaniel Fojt 	return *s == '=' && s > os;
8544b588458SPeter Avalos }
8554b588458SPeter Avalos 
8564b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */
8574b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
8584b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */
85948f09a05SAntonio Huete Jimenez 
8601d48fce0SDaniel Fojt /* well, not quite. As of C99, hex floating point is allowed. so this is
86148f09a05SAntonio Huete Jimenez  * a bit of a mess. We work around the mess by checking for a hexadecimal
86248f09a05SAntonio Huete Jimenez  * value and disallowing it. Similarly, we now follow gawk and allow only
86348f09a05SAntonio Huete Jimenez  * +nan, -nan, +inf, and -inf for NaN and infinity values.
8641d48fce0SDaniel Fojt  */
8654b588458SPeter Avalos 
86648f09a05SAntonio Huete Jimenez /*
86748f09a05SAntonio Huete Jimenez  * This routine now has a more complicated interface, the main point
86848f09a05SAntonio Huete Jimenez  * being to avoid the double conversion of a string to double, and
86948f09a05SAntonio Huete Jimenez  * also to convey out, if requested, the information that the numeric
87048f09a05SAntonio Huete Jimenez  * value was a leading string or is all of the string. The latter bit
87148f09a05SAntonio Huete Jimenez  * is used in getfval().
87248f09a05SAntonio Huete Jimenez  */
87348f09a05SAntonio Huete Jimenez 
is_valid_number(const char * s,bool trailing_stuff_ok,bool * no_trailing,double * result)87448f09a05SAntonio Huete Jimenez bool is_valid_number(const char *s, bool trailing_stuff_ok,
87548f09a05SAntonio Huete Jimenez 			bool *no_trailing, double *result)
8764b588458SPeter Avalos {
8774b588458SPeter Avalos 	double r;
8784b588458SPeter Avalos 	char *ep;
87948f09a05SAntonio Huete Jimenez 	bool retval = false;
88048f09a05SAntonio Huete Jimenez 	bool is_nan = false;
88148f09a05SAntonio Huete Jimenez 	bool is_inf = false;
88248f09a05SAntonio Huete Jimenez 
88348f09a05SAntonio Huete Jimenez 	if (no_trailing)
88448f09a05SAntonio Huete Jimenez 		*no_trailing = false;
88548f09a05SAntonio Huete Jimenez 
886*ed569bc2SAaron LI 	while (isspace((int) *s))
88748f09a05SAntonio Huete Jimenez 		s++;
88848f09a05SAntonio Huete Jimenez 
889*ed569bc2SAaron LI 	/* no hex floating point, sorry */
89048f09a05SAntonio Huete Jimenez 	if (s[0] == '0' && tolower(s[1]) == 'x')
89148f09a05SAntonio Huete Jimenez 		return false;
89248f09a05SAntonio Huete Jimenez 
893*ed569bc2SAaron LI 	/* allow +nan, -nan, +inf, -inf, any other letter, no */
89448f09a05SAntonio Huete Jimenez 	if (s[0] == '+' || s[0] == '-') {
89548f09a05SAntonio Huete Jimenez 		is_nan = (strncasecmp(s+1, "nan", 3) == 0);
89648f09a05SAntonio Huete Jimenez 		is_inf = (strncasecmp(s+1, "inf", 3) == 0);
89748f09a05SAntonio Huete Jimenez 		if ((is_nan || is_inf)
898*ed569bc2SAaron LI 		    && (isspace((int) s[4]) || s[4] == '\0'))
89948f09a05SAntonio Huete Jimenez 			goto convert;
90048f09a05SAntonio Huete Jimenez 		else if (! isdigit(s[1]) && s[1] != '.')
90148f09a05SAntonio Huete Jimenez 			return false;
90248f09a05SAntonio Huete Jimenez 	}
90348f09a05SAntonio Huete Jimenez 	else if (! isdigit(s[0]) && s[0] != '.')
90448f09a05SAntonio Huete Jimenez 		return false;
90548f09a05SAntonio Huete Jimenez 
90648f09a05SAntonio Huete Jimenez convert:
9074b588458SPeter Avalos 	errno = 0;
9084b588458SPeter Avalos 	r = strtod(s, &ep);
90948f09a05SAntonio Huete Jimenez 	if (ep == s || errno == ERANGE)
91048f09a05SAntonio Huete Jimenez 		return false;
91148f09a05SAntonio Huete Jimenez 
91248f09a05SAntonio Huete Jimenez 	if (isnan(r) && s[0] == '-' && signbit(r) == 0)
91348f09a05SAntonio Huete Jimenez 		r = -r;
91448f09a05SAntonio Huete Jimenez 
91548f09a05SAntonio Huete Jimenez 	if (result != NULL)
91648f09a05SAntonio Huete Jimenez 		*result = r;
91748f09a05SAntonio Huete Jimenez 
91848f09a05SAntonio Huete Jimenez 	/*
91948f09a05SAntonio Huete Jimenez 	 * check for trailing stuff
92048f09a05SAntonio Huete Jimenez 	 */
921*ed569bc2SAaron LI 	while (isspace((int) *ep))
9224b588458SPeter Avalos 		ep++;
92348f09a05SAntonio Huete Jimenez 
92448f09a05SAntonio Huete Jimenez 	if (no_trailing != NULL)
92548f09a05SAntonio Huete Jimenez 		*no_trailing = (*ep == '\0');
92648f09a05SAntonio Huete Jimenez 
927*ed569bc2SAaron LI         /* return true if found the end, or trailing stuff is allowed */
92848f09a05SAntonio Huete Jimenez 	retval = *ep == '\0' || trailing_stuff_ok;
92948f09a05SAntonio Huete Jimenez 
93048f09a05SAntonio Huete Jimenez 	return retval;
9314b588458SPeter Avalos }
932