xref: /dflybsd-src/contrib/awk/lib.c (revision b12bae1807abcf1f0dca9dd069ba090c7167812d)
14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos 
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos 
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos 
254b588458SPeter Avalos #define DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <string.h>
284b588458SPeter Avalos #include <ctype.h>
294b588458SPeter Avalos #include <errno.h>
304b588458SPeter Avalos #include <stdlib.h>
314b588458SPeter Avalos #include <stdarg.h>
324b588458SPeter Avalos #include "awk.h"
334b588458SPeter Avalos #include "ytab.h"
344b588458SPeter Avalos 
354b588458SPeter Avalos FILE	*infile	= NULL;
364b588458SPeter Avalos char	*file	= "";
374b588458SPeter Avalos char	*record;
384b588458SPeter Avalos int	recsize	= RECSIZE;
394b588458SPeter Avalos char	*fields;
404b588458SPeter Avalos int	fieldssize = RECSIZE;
414b588458SPeter Avalos 
424b588458SPeter Avalos Cell	**fldtab;	/* pointers to Cells */
434b588458SPeter Avalos char	inputFS[100] = " ";
444b588458SPeter Avalos 
454b588458SPeter Avalos #define	MAXFLD	2
464b588458SPeter Avalos int	nfields	= MAXFLD;	/* last allocated slot for $i */
474b588458SPeter Avalos 
484b588458SPeter Avalos int	donefld;	/* 1 = implies rec broken into fields */
494b588458SPeter Avalos int	donerec;	/* 1 = record is valid (no flds have changed) */
504b588458SPeter Avalos 
514b588458SPeter Avalos int	lastfld	= 0;	/* last used field */
524b588458SPeter Avalos int	argno	= 1;	/* current input argument number */
534b588458SPeter Avalos extern	Awkfloat *ARGC;
544b588458SPeter Avalos 
554b588458SPeter Avalos static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
564b588458SPeter Avalos static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
574b588458SPeter Avalos 
584b588458SPeter Avalos void recinit(unsigned int n)
594b588458SPeter Avalos {
604b588458SPeter Avalos 	if ( (record = (char *) malloc(n)) == NULL
614b588458SPeter Avalos 	  || (fields = (char *) malloc(n+1)) == NULL
624b588458SPeter Avalos 	  || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
634b588458SPeter Avalos 	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
644b588458SPeter Avalos 		FATAL("out of space for $0 and fields");
654b588458SPeter Avalos 	*fldtab[0] = dollar0;
664b588458SPeter Avalos 	fldtab[0]->sval = record;
674b588458SPeter Avalos 	fldtab[0]->nval = tostring("0");
684b588458SPeter Avalos 	makefields(1, nfields);
694b588458SPeter Avalos }
704b588458SPeter Avalos 
714b588458SPeter Avalos void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
724b588458SPeter Avalos {
734b588458SPeter Avalos 	char temp[50];
744b588458SPeter Avalos 	int i;
754b588458SPeter Avalos 
764b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
774b588458SPeter Avalos 		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
784b588458SPeter Avalos 		if (fldtab[i] == NULL)
794b588458SPeter Avalos 			FATAL("out of space in makefields %d", i);
804b588458SPeter Avalos 		*fldtab[i] = dollar1;
814b588458SPeter Avalos 		sprintf(temp, "%d", i);
824b588458SPeter Avalos 		fldtab[i]->nval = tostring(temp);
834b588458SPeter Avalos 	}
844b588458SPeter Avalos }
854b588458SPeter Avalos 
864b588458SPeter Avalos void initgetrec(void)
874b588458SPeter Avalos {
884b588458SPeter Avalos 	int i;
894b588458SPeter Avalos 	char *p;
904b588458SPeter Avalos 
914b588458SPeter Avalos 	for (i = 1; i < *ARGC; i++) {
92*b12bae18SSascha Wildner 		p = getargv(i); /* find 1st real filename */
93*b12bae18SSascha Wildner 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
94*b12bae18SSascha Wildner 			argno++;
95*b12bae18SSascha Wildner 			continue;
96*b12bae18SSascha Wildner 		}
97*b12bae18SSascha Wildner 		if (!isclvar(p)) {
98*b12bae18SSascha Wildner 			setsval(lookup("FILENAME", symtab), p);
994b588458SPeter Avalos 			return;
1004b588458SPeter Avalos 		}
1014b588458SPeter Avalos 		setclvar(p);	/* a commandline assignment before filename */
1024b588458SPeter Avalos 		argno++;
1034b588458SPeter Avalos 	}
1044b588458SPeter Avalos 	infile = stdin;		/* no filenames, so use stdin */
1054b588458SPeter Avalos }
1064b588458SPeter Avalos 
1074b588458SPeter Avalos static int firsttime = 1;
1084b588458SPeter Avalos 
1094b588458SPeter Avalos int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
1104b588458SPeter Avalos {			/* note: cares whether buf == record */
1114b588458SPeter Avalos 	int c;
1124b588458SPeter Avalos 	char *buf = *pbuf;
1134b588458SPeter Avalos 	uschar saveb0;
1144b588458SPeter Avalos 	int bufsize = *pbufsize, savebufsize = bufsize;
1154b588458SPeter Avalos 
1164b588458SPeter Avalos 	if (firsttime) {
1174b588458SPeter Avalos 		firsttime = 0;
1184b588458SPeter Avalos 		initgetrec();
1194b588458SPeter Avalos 	}
1204b588458SPeter Avalos 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
1214b588458SPeter Avalos 		*RS, *FS, *ARGC, *FILENAME) );
1224b588458SPeter Avalos 	if (isrecord) {
1234b588458SPeter Avalos 		donefld = 0;
1244b588458SPeter Avalos 		donerec = 1;
1254b588458SPeter Avalos 	}
1264b588458SPeter Avalos 	saveb0 = buf[0];
1274b588458SPeter Avalos 	buf[0] = 0;
1284b588458SPeter Avalos 	while (argno < *ARGC || infile == stdin) {
1294b588458SPeter Avalos 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
1304b588458SPeter Avalos 		if (infile == NULL) {	/* have to open a new file */
1314b588458SPeter Avalos 			file = getargv(argno);
132*b12bae18SSascha Wildner 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
1334b588458SPeter Avalos 				argno++;
1344b588458SPeter Avalos 				continue;
1354b588458SPeter Avalos 			}
1364b588458SPeter Avalos 			if (isclvar(file)) {	/* a var=value arg */
1374b588458SPeter Avalos 				setclvar(file);
1384b588458SPeter Avalos 				argno++;
1394b588458SPeter Avalos 				continue;
1404b588458SPeter Avalos 			}
1414b588458SPeter Avalos 			*FILENAME = file;
1424b588458SPeter Avalos 			   dprintf( ("opening file %s\n", file) );
1434b588458SPeter Avalos 			if (*file == '-' && *(file+1) == '\0')
1444b588458SPeter Avalos 				infile = stdin;
1454b588458SPeter Avalos 			else if ((infile = fopen(file, "r")) == NULL)
1464b588458SPeter Avalos 				FATAL("can't open file %s", file);
1474b588458SPeter Avalos 			setfval(fnrloc, 0.0);
1484b588458SPeter Avalos 		}
1494b588458SPeter Avalos 		c = readrec(&buf, &bufsize, infile);
1504b588458SPeter Avalos 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1514b588458SPeter Avalos 			if (isrecord) {
1524b588458SPeter Avalos 				if (freeable(fldtab[0]))
1534b588458SPeter Avalos 					xfree(fldtab[0]->sval);
1544b588458SPeter Avalos 				fldtab[0]->sval = buf;	/* buf == record */
1554b588458SPeter Avalos 				fldtab[0]->tval = REC | STR | DONTFREE;
1564b588458SPeter Avalos 				if (is_number(fldtab[0]->sval)) {
1574b588458SPeter Avalos 					fldtab[0]->fval = atof(fldtab[0]->sval);
1584b588458SPeter Avalos 					fldtab[0]->tval |= NUM;
1594b588458SPeter Avalos 				}
1604b588458SPeter Avalos 			}
1614b588458SPeter Avalos 			setfval(nrloc, nrloc->fval+1);
1624b588458SPeter Avalos 			setfval(fnrloc, fnrloc->fval+1);
1634b588458SPeter Avalos 			*pbuf = buf;
1644b588458SPeter Avalos 			*pbufsize = bufsize;
1654b588458SPeter Avalos 			return 1;
1664b588458SPeter Avalos 		}
1674b588458SPeter Avalos 		/* EOF arrived on this file; set up next */
1684b588458SPeter Avalos 		if (infile != stdin)
1694b588458SPeter Avalos 			fclose(infile);
1704b588458SPeter Avalos 		infile = NULL;
1714b588458SPeter Avalos 		argno++;
1724b588458SPeter Avalos 	}
1734b588458SPeter Avalos 	buf[0] = saveb0;
1744b588458SPeter Avalos 	*pbuf = buf;
1754b588458SPeter Avalos 	*pbufsize = savebufsize;
1764b588458SPeter Avalos 	return 0;	/* true end of file */
1774b588458SPeter Avalos }
1784b588458SPeter Avalos 
1794b588458SPeter Avalos void nextfile(void)
1804b588458SPeter Avalos {
1814b588458SPeter Avalos 	if (infile != NULL && infile != stdin)
1824b588458SPeter Avalos 		fclose(infile);
1834b588458SPeter Avalos 	infile = NULL;
1844b588458SPeter Avalos 	argno++;
1854b588458SPeter Avalos }
1864b588458SPeter Avalos 
1874b588458SPeter Avalos int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
1884b588458SPeter Avalos {
1894b588458SPeter Avalos 	int sep, c;
1904b588458SPeter Avalos 	char *rr, *buf = *pbuf;
1914b588458SPeter Avalos 	int bufsize = *pbufsize;
1924b588458SPeter Avalos 
1934b588458SPeter Avalos 	if (strlen(*FS) >= sizeof(inputFS))
1944b588458SPeter Avalos 		FATAL("field separator %.10s... is too long", *FS);
195*b12bae18SSascha Wildner 	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
1964b588458SPeter Avalos 	strcpy(inputFS, *FS);	/* for subsequent field splitting */
1974b588458SPeter Avalos 	if ((sep = **RS) == 0) {
1984b588458SPeter Avalos 		sep = '\n';
1994b588458SPeter Avalos 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
2004b588458SPeter Avalos 			;
2014b588458SPeter Avalos 		if (c != EOF)
2024b588458SPeter Avalos 			ungetc(c, inf);
2034b588458SPeter Avalos 	}
2044b588458SPeter Avalos 	for (rr = buf; ; ) {
2054b588458SPeter Avalos 		for (; (c=getc(inf)) != sep && c != EOF; ) {
2064b588458SPeter Avalos 			if (rr-buf+1 > bufsize)
2074b588458SPeter Avalos 				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
2084b588458SPeter Avalos 					FATAL("input record `%.30s...' too long", buf);
2094b588458SPeter Avalos 			*rr++ = c;
2104b588458SPeter Avalos 		}
2114b588458SPeter Avalos 		if (**RS == sep || c == EOF)
2124b588458SPeter Avalos 			break;
2134b588458SPeter Avalos 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
2144b588458SPeter Avalos 			break;
2154b588458SPeter Avalos 		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
2164b588458SPeter Avalos 			FATAL("input record `%.30s...' too long", buf);
2174b588458SPeter Avalos 		*rr++ = '\n';
2184b588458SPeter Avalos 		*rr++ = c;
2194b588458SPeter Avalos 	}
2204b588458SPeter Avalos 	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
2214b588458SPeter Avalos 		FATAL("input record `%.30s...' too long", buf);
2224b588458SPeter Avalos 	*rr = 0;
2234b588458SPeter Avalos 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
2244b588458SPeter Avalos 	*pbuf = buf;
2254b588458SPeter Avalos 	*pbufsize = bufsize;
2264b588458SPeter Avalos 	return c == EOF && rr == buf ? 0 : 1;
2274b588458SPeter Avalos }
2284b588458SPeter Avalos 
2294b588458SPeter Avalos char *getargv(int n)	/* get ARGV[n] */
2304b588458SPeter Avalos {
2314b588458SPeter Avalos 	Cell *x;
2324b588458SPeter Avalos 	char *s, temp[50];
2334b588458SPeter Avalos 	extern Array *ARGVtab;
2344b588458SPeter Avalos 
2354b588458SPeter Avalos 	sprintf(temp, "%d", n);
236*b12bae18SSascha Wildner 	if (lookup(temp, ARGVtab) == NULL)
237*b12bae18SSascha Wildner 		return NULL;
2384b588458SPeter Avalos 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
2394b588458SPeter Avalos 	s = getsval(x);
2404b588458SPeter Avalos 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
2414b588458SPeter Avalos 	return s;
2424b588458SPeter Avalos }
2434b588458SPeter Avalos 
2444b588458SPeter Avalos void setclvar(char *s)	/* set var=value from s */
2454b588458SPeter Avalos {
2464b588458SPeter Avalos 	char *p;
2474b588458SPeter Avalos 	Cell *q;
2484b588458SPeter Avalos 
2494b588458SPeter Avalos 	for (p=s; *p != '='; p++)
2504b588458SPeter Avalos 		;
2514b588458SPeter Avalos 	*p++ = 0;
2524b588458SPeter Avalos 	p = qstring(p, '\0');
2534b588458SPeter Avalos 	q = setsymtab(s, p, 0.0, STR, symtab);
2544b588458SPeter Avalos 	setsval(q, p);
2554b588458SPeter Avalos 	if (is_number(q->sval)) {
2564b588458SPeter Avalos 		q->fval = atof(q->sval);
2574b588458SPeter Avalos 		q->tval |= NUM;
2584b588458SPeter Avalos 	}
2594b588458SPeter Avalos 	   dprintf( ("command line set %s to |%s|\n", s, p) );
2604b588458SPeter Avalos }
2614b588458SPeter Avalos 
2624b588458SPeter Avalos 
2634b588458SPeter Avalos void fldbld(void)	/* create fields from current record */
2644b588458SPeter Avalos {
2654b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
2664b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
2670020174dSPeter Avalos 	/* possibly with a final trailing \0 not associated with any field */
2684b588458SPeter Avalos 	char *r, *fr, sep;
2694b588458SPeter Avalos 	Cell *p;
2704b588458SPeter Avalos 	int i, j, n;
2714b588458SPeter Avalos 
2724b588458SPeter Avalos 	if (donefld)
2734b588458SPeter Avalos 		return;
2744b588458SPeter Avalos 	if (!isstr(fldtab[0]))
2754b588458SPeter Avalos 		getsval(fldtab[0]);
2764b588458SPeter Avalos 	r = fldtab[0]->sval;
2774b588458SPeter Avalos 	n = strlen(r);
2784b588458SPeter Avalos 	if (n > fieldssize) {
2794b588458SPeter Avalos 		xfree(fields);
2800020174dSPeter Avalos 		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
2814b588458SPeter Avalos 			FATAL("out of space for fields in fldbld %d", n);
2824b588458SPeter Avalos 		fieldssize = n;
2834b588458SPeter Avalos 	}
2844b588458SPeter Avalos 	fr = fields;
2854b588458SPeter Avalos 	i = 0;	/* number of fields accumulated here */
2864b588458SPeter Avalos 	strcpy(inputFS, *FS);
2874b588458SPeter Avalos 	if (strlen(inputFS) > 1) {	/* it's a regular expression */
2884b588458SPeter Avalos 		i = refldbld(r, inputFS);
2894b588458SPeter Avalos 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
2904b588458SPeter Avalos 		for (i = 0; ; ) {
2914b588458SPeter Avalos 			while (*r == ' ' || *r == '\t' || *r == '\n')
2924b588458SPeter Avalos 				r++;
2934b588458SPeter Avalos 			if (*r == 0)
2944b588458SPeter Avalos 				break;
2954b588458SPeter Avalos 			i++;
2964b588458SPeter Avalos 			if (i > nfields)
2974b588458SPeter Avalos 				growfldtab(i);
2984b588458SPeter Avalos 			if (freeable(fldtab[i]))
2994b588458SPeter Avalos 				xfree(fldtab[i]->sval);
3004b588458SPeter Avalos 			fldtab[i]->sval = fr;
3014b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
3024b588458SPeter Avalos 			do
3034b588458SPeter Avalos 				*fr++ = *r++;
3044b588458SPeter Avalos 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
3054b588458SPeter Avalos 			*fr++ = 0;
3064b588458SPeter Avalos 		}
3074b588458SPeter Avalos 		*fr = 0;
3084b588458SPeter Avalos 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
3094b588458SPeter Avalos 		for (i = 0; *r != 0; r++) {
3104b588458SPeter Avalos 			char buf[2];
3114b588458SPeter Avalos 			i++;
3124b588458SPeter Avalos 			if (i > nfields)
3134b588458SPeter Avalos 				growfldtab(i);
3144b588458SPeter Avalos 			if (freeable(fldtab[i]))
3154b588458SPeter Avalos 				xfree(fldtab[i]->sval);
3164b588458SPeter Avalos 			buf[0] = *r;
3174b588458SPeter Avalos 			buf[1] = 0;
3184b588458SPeter Avalos 			fldtab[i]->sval = tostring(buf);
3194b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR;
3204b588458SPeter Avalos 		}
3214b588458SPeter Avalos 		*fr = 0;
3224b588458SPeter Avalos 	} else if (*r != 0) {	/* if 0, it's a null field */
3234b588458SPeter Avalos 		/* subtlecase : if length(FS) == 1 && length(RS > 0)
3244b588458SPeter Avalos 		 * \n is NOT a field separator (cf awk book 61,84).
3254b588458SPeter Avalos 		 * this variable is tested in the inner while loop.
3264b588458SPeter Avalos 		 */
3274b588458SPeter Avalos 		int rtest = '\n';  /* normal case */
3284b588458SPeter Avalos 		if (strlen(*RS) > 0)
3294b588458SPeter Avalos 			rtest = '\0';
3304b588458SPeter Avalos 		for (;;) {
3314b588458SPeter Avalos 			i++;
3324b588458SPeter Avalos 			if (i > nfields)
3334b588458SPeter Avalos 				growfldtab(i);
3344b588458SPeter Avalos 			if (freeable(fldtab[i]))
3354b588458SPeter Avalos 				xfree(fldtab[i]->sval);
3364b588458SPeter Avalos 			fldtab[i]->sval = fr;
3374b588458SPeter Avalos 			fldtab[i]->tval = FLD | STR | DONTFREE;
3384b588458SPeter Avalos 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
3394b588458SPeter Avalos 				*fr++ = *r++;
3404b588458SPeter Avalos 			*fr++ = 0;
3414b588458SPeter Avalos 			if (*r++ == 0)
3424b588458SPeter Avalos 				break;
3434b588458SPeter Avalos 		}
3444b588458SPeter Avalos 		*fr = 0;
3454b588458SPeter Avalos 	}
3464b588458SPeter Avalos 	if (i > nfields)
3474b588458SPeter Avalos 		FATAL("record `%.30s...' has too many fields; can't happen", r);
3484b588458SPeter Avalos 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
3494b588458SPeter Avalos 	lastfld = i;
3504b588458SPeter Avalos 	donefld = 1;
3514b588458SPeter Avalos 	for (j = 1; j <= lastfld; j++) {
3524b588458SPeter Avalos 		p = fldtab[j];
3534b588458SPeter Avalos 		if(is_number(p->sval)) {
3544b588458SPeter Avalos 			p->fval = atof(p->sval);
3554b588458SPeter Avalos 			p->tval |= NUM;
3564b588458SPeter Avalos 		}
3574b588458SPeter Avalos 	}
3584b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) lastfld);
3594b588458SPeter Avalos 	if (dbg) {
3604b588458SPeter Avalos 		for (j = 0; j <= lastfld; j++) {
3614b588458SPeter Avalos 			p = fldtab[j];
3624b588458SPeter Avalos 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
3634b588458SPeter Avalos 		}
3644b588458SPeter Avalos 	}
3654b588458SPeter Avalos }
3664b588458SPeter Avalos 
3674b588458SPeter Avalos void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
3684b588458SPeter Avalos {				/* nvals remain intact */
3694b588458SPeter Avalos 	Cell *p;
3704b588458SPeter Avalos 	int i;
3714b588458SPeter Avalos 
3724b588458SPeter Avalos 	for (i = n1; i <= n2; i++) {
3734b588458SPeter Avalos 		p = fldtab[i];
3744b588458SPeter Avalos 		if (freeable(p))
3754b588458SPeter Avalos 			xfree(p->sval);
3764b588458SPeter Avalos 		p->sval = "";
3774b588458SPeter Avalos 		p->tval = FLD | STR | DONTFREE;
3784b588458SPeter Avalos 	}
3794b588458SPeter Avalos }
3804b588458SPeter Avalos 
3814b588458SPeter Avalos void newfld(int n)	/* add field n after end of existing lastfld */
3824b588458SPeter Avalos {
3834b588458SPeter Avalos 	if (n > nfields)
3844b588458SPeter Avalos 		growfldtab(n);
3854b588458SPeter Avalos 	cleanfld(lastfld+1, n);
3864b588458SPeter Avalos 	lastfld = n;
3874b588458SPeter Avalos 	setfval(nfloc, (Awkfloat) n);
3884b588458SPeter Avalos }
3894b588458SPeter Avalos 
3904b588458SPeter Avalos Cell *fieldadr(int n)	/* get nth field */
3914b588458SPeter Avalos {
3924b588458SPeter Avalos 	if (n < 0)
3934b588458SPeter Avalos 		FATAL("trying to access out of range field %d", n);
3944b588458SPeter Avalos 	if (n > nfields)	/* fields after NF are empty */
3954b588458SPeter Avalos 		growfldtab(n);	/* but does not increase NF */
3964b588458SPeter Avalos 	return(fldtab[n]);
3974b588458SPeter Avalos }
3984b588458SPeter Avalos 
3994b588458SPeter Avalos void growfldtab(int n)	/* make new fields up to at least $n */
4004b588458SPeter Avalos {
4014b588458SPeter Avalos 	int nf = 2 * nfields;
4024b588458SPeter Avalos 	size_t s;
4034b588458SPeter Avalos 
4044b588458SPeter Avalos 	if (n > nf)
4054b588458SPeter Avalos 		nf = n;
4064b588458SPeter Avalos 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
4074b588458SPeter Avalos 	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
4084b588458SPeter Avalos 		fldtab = (Cell **) realloc(fldtab, s);
4094b588458SPeter Avalos 	else					/* overflow sizeof int */
4104b588458SPeter Avalos 		xfree(fldtab);	/* make it null */
4114b588458SPeter Avalos 	if (fldtab == NULL)
4124b588458SPeter Avalos 		FATAL("out of space creating %d fields", nf);
4134b588458SPeter Avalos 	makefields(nfields+1, nf);
4144b588458SPeter Avalos 	nfields = nf;
4154b588458SPeter Avalos }
4164b588458SPeter Avalos 
4174b588458SPeter Avalos int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
4184b588458SPeter Avalos {
4194b588458SPeter Avalos 	/* this relies on having fields[] the same length as $0 */
4204b588458SPeter Avalos 	/* the fields are all stored in this one array with \0's */
4214b588458SPeter Avalos 	char *fr;
4224b588458SPeter Avalos 	int i, tempstat, n;
4234b588458SPeter Avalos 	fa *pfa;
4244b588458SPeter Avalos 
4254b588458SPeter Avalos 	n = strlen(rec);
4264b588458SPeter Avalos 	if (n > fieldssize) {
4274b588458SPeter Avalos 		xfree(fields);
4284b588458SPeter Avalos 		if ((fields = (char *) malloc(n+1)) == NULL)
4294b588458SPeter Avalos 			FATAL("out of space for fields in refldbld %d", n);
4304b588458SPeter Avalos 		fieldssize = n;
4314b588458SPeter Avalos 	}
4324b588458SPeter Avalos 	fr = fields;
4334b588458SPeter Avalos 	*fr = '\0';
4344b588458SPeter Avalos 	if (*rec == '\0')
4354b588458SPeter Avalos 		return 0;
4364b588458SPeter Avalos 	pfa = makedfa(fs, 1);
4374b588458SPeter Avalos 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
4384b588458SPeter Avalos 	tempstat = pfa->initstat;
4394b588458SPeter Avalos 	for (i = 1; ; i++) {
4404b588458SPeter Avalos 		if (i > nfields)
4414b588458SPeter Avalos 			growfldtab(i);
4424b588458SPeter Avalos 		if (freeable(fldtab[i]))
4434b588458SPeter Avalos 			xfree(fldtab[i]->sval);
4444b588458SPeter Avalos 		fldtab[i]->tval = FLD | STR | DONTFREE;
4454b588458SPeter Avalos 		fldtab[i]->sval = fr;
4464b588458SPeter Avalos 		   dprintf( ("refldbld: i=%d\n", i) );
4474b588458SPeter Avalos 		if (nematch(pfa, rec)) {
4484b588458SPeter Avalos 			pfa->initstat = 2;	/* horrible coupling to b.c */
4494b588458SPeter Avalos 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
4504b588458SPeter Avalos 			strncpy(fr, rec, patbeg-rec);
4514b588458SPeter Avalos 			fr += patbeg - rec + 1;
4524b588458SPeter Avalos 			*(fr-1) = '\0';
4534b588458SPeter Avalos 			rec = patbeg + patlen;
4544b588458SPeter Avalos 		} else {
4554b588458SPeter Avalos 			   dprintf( ("no match %s\n", rec) );
4564b588458SPeter Avalos 			strcpy(fr, rec);
4574b588458SPeter Avalos 			pfa->initstat = tempstat;
4584b588458SPeter Avalos 			break;
4594b588458SPeter Avalos 		}
4604b588458SPeter Avalos 	}
4614b588458SPeter Avalos 	return i;
4624b588458SPeter Avalos }
4634b588458SPeter Avalos 
4644b588458SPeter Avalos void recbld(void)	/* create $0 from $1..$NF if necessary */
4654b588458SPeter Avalos {
4664b588458SPeter Avalos 	int i;
4674b588458SPeter Avalos 	char *r, *p;
4684b588458SPeter Avalos 
4694b588458SPeter Avalos 	if (donerec == 1)
4704b588458SPeter Avalos 		return;
4714b588458SPeter Avalos 	r = record;
4724b588458SPeter Avalos 	for (i = 1; i <= *NF; i++) {
4734b588458SPeter Avalos 		p = getsval(fldtab[i]);
4744b588458SPeter Avalos 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
4754b588458SPeter Avalos 			FATAL("created $0 `%.30s...' too long", record);
4764b588458SPeter Avalos 		while ((*r = *p++) != 0)
4774b588458SPeter Avalos 			r++;
4784b588458SPeter Avalos 		if (i < *NF) {
4794b588458SPeter Avalos 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
4804b588458SPeter Avalos 				FATAL("created $0 `%.30s...' too long", record);
4814b588458SPeter Avalos 			for (p = *OFS; (*r = *p++) != 0; )
4824b588458SPeter Avalos 				r++;
4834b588458SPeter Avalos 		}
4844b588458SPeter Avalos 	}
4854b588458SPeter Avalos 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
4864b588458SPeter Avalos 		FATAL("built giant record `%.30s...'", record);
4874b588458SPeter Avalos 	*r = '\0';
488*b12bae18SSascha Wildner 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
4894b588458SPeter Avalos 
4904b588458SPeter Avalos 	if (freeable(fldtab[0]))
4914b588458SPeter Avalos 		xfree(fldtab[0]->sval);
4924b588458SPeter Avalos 	fldtab[0]->tval = REC | STR | DONTFREE;
4934b588458SPeter Avalos 	fldtab[0]->sval = record;
4944b588458SPeter Avalos 
495*b12bae18SSascha Wildner 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
4964b588458SPeter Avalos 	   dprintf( ("recbld = |%s|\n", record) );
4974b588458SPeter Avalos 	donerec = 1;
4984b588458SPeter Avalos }
4994b588458SPeter Avalos 
5004b588458SPeter Avalos int	errorflag	= 0;
5014b588458SPeter Avalos 
5024b588458SPeter Avalos void yyerror(const char *s)
5034b588458SPeter Avalos {
5044b588458SPeter Avalos 	SYNTAX("%s", s);
5054b588458SPeter Avalos }
5064b588458SPeter Avalos 
5074b588458SPeter Avalos void SYNTAX(const char *fmt, ...)
5084b588458SPeter Avalos {
5094b588458SPeter Avalos 	extern char *cmdname, *curfname;
5104b588458SPeter Avalos 	static int been_here = 0;
5114b588458SPeter Avalos 	va_list varg;
5124b588458SPeter Avalos 
5134b588458SPeter Avalos 	if (been_here++ > 2)
5144b588458SPeter Avalos 		return;
5154b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
5164b588458SPeter Avalos 	va_start(varg, fmt);
5174b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
5184b588458SPeter Avalos 	va_end(varg);
5194b588458SPeter Avalos 	fprintf(stderr, " at source line %d", lineno);
5204b588458SPeter Avalos 	if (curfname != NULL)
5214b588458SPeter Avalos 		fprintf(stderr, " in function %s", curfname);
5224b588458SPeter Avalos 	if (compile_time == 1 && cursource() != NULL)
5234b588458SPeter Avalos 		fprintf(stderr, " source file %s", cursource());
5244b588458SPeter Avalos 	fprintf(stderr, "\n");
5254b588458SPeter Avalos 	errorflag = 2;
5264b588458SPeter Avalos 	eprint();
5274b588458SPeter Avalos }
5284b588458SPeter Avalos 
5294b588458SPeter Avalos void fpecatch(int n)
5304b588458SPeter Avalos {
5314b588458SPeter Avalos 	FATAL("floating point exception %d", n);
5324b588458SPeter Avalos }
5334b588458SPeter Avalos 
5344b588458SPeter Avalos extern int bracecnt, brackcnt, parencnt;
5354b588458SPeter Avalos 
5364b588458SPeter Avalos void bracecheck(void)
5374b588458SPeter Avalos {
5384b588458SPeter Avalos 	int c;
5394b588458SPeter Avalos 	static int beenhere = 0;
5404b588458SPeter Avalos 
5414b588458SPeter Avalos 	if (beenhere++)
5424b588458SPeter Avalos 		return;
5434b588458SPeter Avalos 	while ((c = input()) != EOF && c != '\0')
5444b588458SPeter Avalos 		bclass(c);
5454b588458SPeter Avalos 	bcheck2(bracecnt, '{', '}');
5464b588458SPeter Avalos 	bcheck2(brackcnt, '[', ']');
5474b588458SPeter Avalos 	bcheck2(parencnt, '(', ')');
5484b588458SPeter Avalos }
5494b588458SPeter Avalos 
5504b588458SPeter Avalos void bcheck2(int n, int c1, int c2)
5514b588458SPeter Avalos {
5524b588458SPeter Avalos 	if (n == 1)
5534b588458SPeter Avalos 		fprintf(stderr, "\tmissing %c\n", c2);
5544b588458SPeter Avalos 	else if (n > 1)
5554b588458SPeter Avalos 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
5564b588458SPeter Avalos 	else if (n == -1)
5574b588458SPeter Avalos 		fprintf(stderr, "\textra %c\n", c2);
5584b588458SPeter Avalos 	else if (n < -1)
5594b588458SPeter Avalos 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
5604b588458SPeter Avalos }
5614b588458SPeter Avalos 
5624b588458SPeter Avalos void FATAL(const char *fmt, ...)
5634b588458SPeter Avalos {
5644b588458SPeter Avalos 	extern char *cmdname;
5654b588458SPeter Avalos 	va_list varg;
5664b588458SPeter Avalos 
5674b588458SPeter Avalos 	fflush(stdout);
5684b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
5694b588458SPeter Avalos 	va_start(varg, fmt);
5704b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
5714b588458SPeter Avalos 	va_end(varg);
5724b588458SPeter Avalos 	error();
5734b588458SPeter Avalos 	if (dbg > 1)		/* core dump if serious debugging on */
5744b588458SPeter Avalos 		abort();
5754b588458SPeter Avalos 	exit(2);
5764b588458SPeter Avalos }
5774b588458SPeter Avalos 
5784b588458SPeter Avalos void WARNING(const char *fmt, ...)
5794b588458SPeter Avalos {
5804b588458SPeter Avalos 	extern char *cmdname;
5814b588458SPeter Avalos 	va_list varg;
5824b588458SPeter Avalos 
5834b588458SPeter Avalos 	fflush(stdout);
5844b588458SPeter Avalos 	fprintf(stderr, "%s: ", cmdname);
5854b588458SPeter Avalos 	va_start(varg, fmt);
5864b588458SPeter Avalos 	vfprintf(stderr, fmt, varg);
5874b588458SPeter Avalos 	va_end(varg);
5884b588458SPeter Avalos 	error();
5894b588458SPeter Avalos }
5904b588458SPeter Avalos 
5914b588458SPeter Avalos void error()
5924b588458SPeter Avalos {
5934b588458SPeter Avalos 	extern Node *curnode;
5944b588458SPeter Avalos 
5954b588458SPeter Avalos 	fprintf(stderr, "\n");
5964b588458SPeter Avalos 	if (compile_time != 2 && NR && *NR > 0) {
5974b588458SPeter Avalos 		fprintf(stderr, " input record number %d", (int) (*FNR));
5984b588458SPeter Avalos 		if (strcmp(*FILENAME, "-") != 0)
5994b588458SPeter Avalos 			fprintf(stderr, ", file %s", *FILENAME);
6004b588458SPeter Avalos 		fprintf(stderr, "\n");
6014b588458SPeter Avalos 	}
6024b588458SPeter Avalos 	if (compile_time != 2 && curnode)
6034b588458SPeter Avalos 		fprintf(stderr, " source line number %d", curnode->lineno);
6044b588458SPeter Avalos 	else if (compile_time != 2 && lineno)
6054b588458SPeter Avalos 		fprintf(stderr, " source line number %d", lineno);
6064b588458SPeter Avalos 	if (compile_time == 1 && cursource() != NULL)
6074b588458SPeter Avalos 		fprintf(stderr, " source file %s", cursource());
6084b588458SPeter Avalos 	fprintf(stderr, "\n");
6094b588458SPeter Avalos 	eprint();
6104b588458SPeter Avalos }
6114b588458SPeter Avalos 
6124b588458SPeter Avalos void eprint(void)	/* try to print context around error */
6134b588458SPeter Avalos {
6144b588458SPeter Avalos 	char *p, *q;
6154b588458SPeter Avalos 	int c;
6164b588458SPeter Avalos 	static int been_here = 0;
6174b588458SPeter Avalos 	extern char ebuf[], *ep;
6184b588458SPeter Avalos 
6194b588458SPeter Avalos 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
6204b588458SPeter Avalos 		return;
6214b588458SPeter Avalos 	p = ep - 1;
6224b588458SPeter Avalos 	if (p > ebuf && *p == '\n')
6234b588458SPeter Avalos 		p--;
6244b588458SPeter Avalos 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
6254b588458SPeter Avalos 		;
6264b588458SPeter Avalos 	while (*p == '\n')
6274b588458SPeter Avalos 		p++;
6284b588458SPeter Avalos 	fprintf(stderr, " context is\n\t");
6294b588458SPeter Avalos 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
6304b588458SPeter Avalos 		;
6314b588458SPeter Avalos 	for ( ; p < q; p++)
6324b588458SPeter Avalos 		if (*p)
6334b588458SPeter Avalos 			putc(*p, stderr);
6344b588458SPeter Avalos 	fprintf(stderr, " >>> ");
6354b588458SPeter Avalos 	for ( ; p < ep; p++)
6364b588458SPeter Avalos 		if (*p)
6374b588458SPeter Avalos 			putc(*p, stderr);
6384b588458SPeter Avalos 	fprintf(stderr, " <<< ");
6394b588458SPeter Avalos 	if (*ep)
6404b588458SPeter Avalos 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
6414b588458SPeter Avalos 			putc(c, stderr);
6424b588458SPeter Avalos 			bclass(c);
6434b588458SPeter Avalos 		}
6444b588458SPeter Avalos 	putc('\n', stderr);
6454b588458SPeter Avalos 	ep = ebuf;
6464b588458SPeter Avalos }
6474b588458SPeter Avalos 
6484b588458SPeter Avalos void bclass(int c)
6494b588458SPeter Avalos {
6504b588458SPeter Avalos 	switch (c) {
6514b588458SPeter Avalos 	case '{': bracecnt++; break;
6524b588458SPeter Avalos 	case '}': bracecnt--; break;
6534b588458SPeter Avalos 	case '[': brackcnt++; break;
6544b588458SPeter Avalos 	case ']': brackcnt--; break;
6554b588458SPeter Avalos 	case '(': parencnt++; break;
6564b588458SPeter Avalos 	case ')': parencnt--; break;
6574b588458SPeter Avalos 	}
6584b588458SPeter Avalos }
6594b588458SPeter Avalos 
6604b588458SPeter Avalos double errcheck(double x, const char *s)
6614b588458SPeter Avalos {
6624b588458SPeter Avalos 
6634b588458SPeter Avalos 	if (errno == EDOM) {
6644b588458SPeter Avalos 		errno = 0;
6654b588458SPeter Avalos 		WARNING("%s argument out of domain", s);
6664b588458SPeter Avalos 		x = 1;
6674b588458SPeter Avalos 	} else if (errno == ERANGE) {
6684b588458SPeter Avalos 		errno = 0;
6694b588458SPeter Avalos 		WARNING("%s result out of range", s);
6704b588458SPeter Avalos 		x = 1;
6714b588458SPeter Avalos 	}
6724b588458SPeter Avalos 	return x;
6734b588458SPeter Avalos }
6744b588458SPeter Avalos 
6754b588458SPeter Avalos int isclvar(const char *s)	/* is s of form var=something ? */
6764b588458SPeter Avalos {
6774b588458SPeter Avalos 	const char *os = s;
6784b588458SPeter Avalos 
6794b588458SPeter Avalos 	if (!isalpha((uschar) *s) && *s != '_')
6804b588458SPeter Avalos 		return 0;
6814b588458SPeter Avalos 	for ( ; *s; s++)
6824b588458SPeter Avalos 		if (!(isalnum((uschar) *s) || *s == '_'))
6834b588458SPeter Avalos 			break;
6844b588458SPeter Avalos 	return *s == '=' && s > os && *(s+1) != '=';
6854b588458SPeter Avalos }
6864b588458SPeter Avalos 
6874b588458SPeter Avalos /* strtod is supposed to be a proper test of what's a valid number */
6884b588458SPeter Avalos /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
6894b588458SPeter Avalos /* wrong: violates 4.10.1.4 of ansi C standard */
6904b588458SPeter Avalos 
6914b588458SPeter Avalos #include <math.h>
6924b588458SPeter Avalos int is_number(const char *s)
6934b588458SPeter Avalos {
6944b588458SPeter Avalos 	double r;
6954b588458SPeter Avalos 	char *ep;
6964b588458SPeter Avalos 	errno = 0;
6974b588458SPeter Avalos 	r = strtod(s, &ep);
6984b588458SPeter Avalos 	if (ep == s || r == HUGE_VAL || errno == ERANGE)
6994b588458SPeter Avalos 		return 0;
7004b588458SPeter Avalos 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
7014b588458SPeter Avalos 		ep++;
7024b588458SPeter Avalos 	if (*ep == '\0')
7034b588458SPeter Avalos 		return 1;
7044b588458SPeter Avalos 	else
7054b588458SPeter Avalos 		return 0;
7064b588458SPeter Avalos }
707