185587Sobrien/****************************************************************
285587SobrienCopyright (C) Lucent Technologies 1997
385587SobrienAll Rights Reserved
485587Sobrien
585587SobrienPermission to use, copy, modify, and distribute this software and
685587Sobrienits documentation for any purpose and without fee is hereby
785587Sobriengranted, provided that the above copyright notice appear in all
885587Sobriencopies and that both that the copyright notice and this
985587Sobrienpermission notice and warranty disclaimer appear in supporting
1085587Sobriendocumentation, and that the name Lucent Technologies or any of
1185587Sobrienits entities not be used in advertising or publicity pertaining
1285587Sobriento distribution of the software without specific, written prior
1385587Sobrienpermission.
1485587Sobrien
1585587SobrienLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1685587SobrienINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1785587SobrienIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1885587SobrienSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1985587SobrienWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2085587SobrienIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2185587SobrienARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2285587SobrienTHIS SOFTWARE.
2385587Sobrien****************************************************************/
2485587Sobrien
2585587Sobrien#define DEBUG
2685587Sobrien#include <stdio.h>
2785587Sobrien#include <string.h>
2885587Sobrien#include <ctype.h>
2985587Sobrien#include <errno.h>
3085587Sobrien#include <stdlib.h>
3185587Sobrien#include <stdarg.h>
3285587Sobrien#include "awk.h"
3385587Sobrien#include "ytab.h"
3485587Sobrien
3585587SobrienFILE	*infile	= NULL;
3685587Sobrienchar	*file	= "";
3785587Sobrienchar	*record;
3885587Sobrienint	recsize	= RECSIZE;
3985587Sobrienchar	*fields;
4085587Sobrienint	fieldssize = RECSIZE;
4185587Sobrien
4285587SobrienCell	**fldtab;	/* pointers to Cells */
43172958Sobrienchar	inputFS[100] = " ";
4485587Sobrien
45170331Srafan#define	MAXFLD	2
4685587Sobrienint	nfields	= MAXFLD;	/* last allocated slot for $i */
4785587Sobrien
4885587Sobrienint	donefld;	/* 1 = implies rec broken into fields */
4985587Sobrienint	donerec;	/* 1 = record is valid (no flds have changed) */
5085587Sobrien
5185587Sobrienint	lastfld	= 0;	/* last used field */
5285587Sobrienint	argno	= 1;	/* current input argument number */
5385587Sobrienextern	Awkfloat *ARGC;
5485587Sobrien
5585587Sobrienstatic Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
5685587Sobrienstatic Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
5785587Sobrien
5885587Sobrienvoid recinit(unsigned int n)
5985587Sobrien{
60146299Sru	if ( (record = (char *) malloc(n)) == NULL
61172958Sobrien	  || (fields = (char *) malloc(n+1)) == NULL
62146299Sru	  || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL
63146299Sru	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
6485587Sobrien		FATAL("out of space for $0 and fields");
6585587Sobrien	*fldtab[0] = dollar0;
6685587Sobrien	fldtab[0]->sval = record;
6785587Sobrien	fldtab[0]->nval = tostring("0");
6885587Sobrien	makefields(1, nfields);
6985587Sobrien}
7085587Sobrien
7185587Sobrienvoid makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
7285587Sobrien{
7385587Sobrien	char temp[50];
7485587Sobrien	int i;
7585587Sobrien
7685587Sobrien	for (i = n1; i <= n2; i++) {
7785587Sobrien		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
7885587Sobrien		if (fldtab[i] == NULL)
7985587Sobrien			FATAL("out of space in makefields %d", i);
8085587Sobrien		*fldtab[i] = dollar1;
8185587Sobrien		sprintf(temp, "%d", i);
8285587Sobrien		fldtab[i]->nval = tostring(temp);
8385587Sobrien	}
8485587Sobrien}
8585587Sobrien
8685587Sobrienvoid initgetrec(void)
8785587Sobrien{
8885587Sobrien	int i;
8985587Sobrien	char *p;
9085587Sobrien
9185587Sobrien	for (i = 1; i < *ARGC; i++) {
92224776Sru		p = getargv(i); /* find 1st real filename */
93224776Sru		if (p == NULL || *p == '\0') {  /* deleted or zapped */
94224776Sru			argno++;
95224776Sru			continue;
96224776Sru		}
97224776Sru		if (!isclvar(p)) {
98224776Sru			setsval(lookup("FILENAME", symtab), p);
9985587Sobrien			return;
10085587Sobrien		}
10185587Sobrien		setclvar(p);	/* a commandline assignment before filename */
10285587Sobrien		argno++;
10385587Sobrien	}
10485587Sobrien	infile = stdin;		/* no filenames, so use stdin */
10585587Sobrien}
10685587Sobrien
107146299Srustatic int firsttime = 1;
108146299Sru
10985587Sobrienint getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
11085587Sobrien{			/* note: cares whether buf == record */
11185587Sobrien	int c;
11285587Sobrien	char *buf = *pbuf;
113146299Sru	uschar saveb0;
114146299Sru	int bufsize = *pbufsize, savebufsize = bufsize;
11585587Sobrien
11685587Sobrien	if (firsttime) {
11785587Sobrien		firsttime = 0;
11885587Sobrien		initgetrec();
11985587Sobrien	}
12085587Sobrien	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
12185587Sobrien		*RS, *FS, *ARGC, *FILENAME) );
12285587Sobrien	if (isrecord) {
12385587Sobrien		donefld = 0;
12485587Sobrien		donerec = 1;
12585587Sobrien	}
126146299Sru	saveb0 = buf[0];
12785587Sobrien	buf[0] = 0;
12885587Sobrien	while (argno < *ARGC || infile == stdin) {
12985587Sobrien		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
13085587Sobrien		if (infile == NULL) {	/* have to open a new file */
13185587Sobrien			file = getargv(argno);
132224731Sru			if (file == NULL || *file == '\0') {	/* deleted or zapped */
13385587Sobrien				argno++;
13485587Sobrien				continue;
13585587Sobrien			}
13685587Sobrien			if (isclvar(file)) {	/* a var=value arg */
13785587Sobrien				setclvar(file);
13885587Sobrien				argno++;
13985587Sobrien				continue;
14085587Sobrien			}
14185587Sobrien			*FILENAME = file;
14285587Sobrien			   dprintf( ("opening file %s\n", file) );
14385587Sobrien			if (*file == '-' && *(file+1) == '\0')
14485587Sobrien				infile = stdin;
14585587Sobrien			else if ((infile = fopen(file, "r")) == NULL)
14685587Sobrien				FATAL("can't open file %s", file);
14785587Sobrien			setfval(fnrloc, 0.0);
14885587Sobrien		}
14985587Sobrien		c = readrec(&buf, &bufsize, infile);
15085587Sobrien		if (c != 0 || buf[0] != '\0') {	/* normal record */
15185587Sobrien			if (isrecord) {
15285587Sobrien				if (freeable(fldtab[0]))
15385587Sobrien					xfree(fldtab[0]->sval);
15485587Sobrien				fldtab[0]->sval = buf;	/* buf == record */
15585587Sobrien				fldtab[0]->tval = REC | STR | DONTFREE;
15685587Sobrien				if (is_number(fldtab[0]->sval)) {
15785587Sobrien					fldtab[0]->fval = atof(fldtab[0]->sval);
15885587Sobrien					fldtab[0]->tval |= NUM;
15985587Sobrien				}
16085587Sobrien			}
16185587Sobrien			setfval(nrloc, nrloc->fval+1);
16285587Sobrien			setfval(fnrloc, fnrloc->fval+1);
16385587Sobrien			*pbuf = buf;
16485587Sobrien			*pbufsize = bufsize;
16585587Sobrien			return 1;
16685587Sobrien		}
16785587Sobrien		/* EOF arrived on this file; set up next */
16885587Sobrien		if (infile != stdin)
16985587Sobrien			fclose(infile);
17085587Sobrien		infile = NULL;
17185587Sobrien		argno++;
17285587Sobrien	}
173146299Sru	buf[0] = saveb0;
17485587Sobrien	*pbuf = buf;
175146299Sru	*pbufsize = savebufsize;
17685587Sobrien	return 0;	/* true end of file */
17785587Sobrien}
17885587Sobrien
17985587Sobrienvoid nextfile(void)
18085587Sobrien{
181170331Srafan	if (infile != NULL && infile != stdin)
18285587Sobrien		fclose(infile);
18385587Sobrien	infile = NULL;
18485587Sobrien	argno++;
18585587Sobrien}
18685587Sobrien
18785587Sobrienint readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
18885587Sobrien{
18985587Sobrien	int sep, c;
19085587Sobrien	char *rr, *buf = *pbuf;
19185587Sobrien	int bufsize = *pbufsize;
19285587Sobrien
19385587Sobrien	if (strlen(*FS) >= sizeof(inputFS))
19485587Sobrien		FATAL("field separator %.10s... is too long", *FS);
195224731Sru	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
19685587Sobrien	strcpy(inputFS, *FS);	/* for subsequent field splitting */
19785587Sobrien	if ((sep = **RS) == 0) {
19885587Sobrien		sep = '\n';
19985587Sobrien		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
20085587Sobrien			;
20185587Sobrien		if (c != EOF)
20285587Sobrien			ungetc(c, inf);
20385587Sobrien	}
20485587Sobrien	for (rr = buf; ; ) {
20585587Sobrien		for (; (c=getc(inf)) != sep && c != EOF; ) {
20685587Sobrien			if (rr-buf+1 > bufsize)
20785587Sobrien				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
20885587Sobrien					FATAL("input record `%.30s...' too long", buf);
20985587Sobrien			*rr++ = c;
21085587Sobrien		}
21185587Sobrien		if (**RS == sep || c == EOF)
21285587Sobrien			break;
21385587Sobrien		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
21485587Sobrien			break;
21585587Sobrien		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
21685587Sobrien			FATAL("input record `%.30s...' too long", buf);
21785587Sobrien		*rr++ = '\n';
21885587Sobrien		*rr++ = c;
21985587Sobrien	}
22085587Sobrien	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
22185587Sobrien		FATAL("input record `%.30s...' too long", buf);
22285587Sobrien	*rr = 0;
22385587Sobrien	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
22485587Sobrien	*pbuf = buf;
22585587Sobrien	*pbufsize = bufsize;
22685587Sobrien	return c == EOF && rr == buf ? 0 : 1;
22785587Sobrien}
22885587Sobrien
22985587Sobrienchar *getargv(int n)	/* get ARGV[n] */
23085587Sobrien{
23185587Sobrien	Cell *x;
23285587Sobrien	char *s, temp[50];
23385587Sobrien	extern Array *ARGVtab;
23485587Sobrien
23585587Sobrien	sprintf(temp, "%d", n);
236224731Sru	if (lookup(temp, ARGVtab) == NULL)
237224731Sru		return NULL;
23885587Sobrien	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
23985587Sobrien	s = getsval(x);
24085587Sobrien	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
24185587Sobrien	return s;
24285587Sobrien}
24385587Sobrien
24485587Sobrienvoid setclvar(char *s)	/* set var=value from s */
24585587Sobrien{
24685587Sobrien	char *p;
24785587Sobrien	Cell *q;
24885587Sobrien
24985587Sobrien	for (p=s; *p != '='; p++)
25085587Sobrien		;
25185587Sobrien	*p++ = 0;
25285587Sobrien	p = qstring(p, '\0');
25385587Sobrien	q = setsymtab(s, p, 0.0, STR, symtab);
25485587Sobrien	setsval(q, p);
25585587Sobrien	if (is_number(q->sval)) {
25685587Sobrien		q->fval = atof(q->sval);
25785587Sobrien		q->tval |= NUM;
25885587Sobrien	}
25985587Sobrien	   dprintf( ("command line set %s to |%s|\n", s, p) );
26085587Sobrien}
26185587Sobrien
26285587Sobrien
26385587Sobrienvoid fldbld(void)	/* create fields from current record */
26485587Sobrien{
26585587Sobrien	/* this relies on having fields[] the same length as $0 */
26685587Sobrien	/* the fields are all stored in this one array with \0's */
267221381Sru	/* possibly with a final trailing \0 not associated with any field */
26885587Sobrien	char *r, *fr, sep;
26985587Sobrien	Cell *p;
27085587Sobrien	int i, j, n;
27185587Sobrien
27285587Sobrien	if (donefld)
27385587Sobrien		return;
27485587Sobrien	if (!isstr(fldtab[0]))
27585587Sobrien		getsval(fldtab[0]);
27685587Sobrien	r = fldtab[0]->sval;
27785587Sobrien	n = strlen(r);
27885587Sobrien	if (n > fieldssize) {
27985587Sobrien		xfree(fields);
280221381Sru		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
28185587Sobrien			FATAL("out of space for fields in fldbld %d", n);
28285587Sobrien		fieldssize = n;
28385587Sobrien	}
28485587Sobrien	fr = fields;
28585587Sobrien	i = 0;	/* number of fields accumulated here */
286201951Sru	strcpy(inputFS, *FS);
28785587Sobrien	if (strlen(inputFS) > 1) {	/* it's a regular expression */
28885587Sobrien		i = refldbld(r, inputFS);
28985587Sobrien	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
29085587Sobrien		for (i = 0; ; ) {
29185587Sobrien			while (*r == ' ' || *r == '\t' || *r == '\n')
29285587Sobrien				r++;
29385587Sobrien			if (*r == 0)
29485587Sobrien				break;
29585587Sobrien			i++;
29685587Sobrien			if (i > nfields)
29785587Sobrien				growfldtab(i);
29885587Sobrien			if (freeable(fldtab[i]))
29985587Sobrien				xfree(fldtab[i]->sval);
30085587Sobrien			fldtab[i]->sval = fr;
30185587Sobrien			fldtab[i]->tval = FLD | STR | DONTFREE;
30285587Sobrien			do
30385587Sobrien				*fr++ = *r++;
30485587Sobrien			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
30585587Sobrien			*fr++ = 0;
30685587Sobrien		}
30785587Sobrien		*fr = 0;
30885587Sobrien	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
30985587Sobrien		for (i = 0; *r != 0; r++) {
31085587Sobrien			char buf[2];
31185587Sobrien			i++;
31285587Sobrien			if (i > nfields)
31385587Sobrien				growfldtab(i);
31485587Sobrien			if (freeable(fldtab[i]))
31585587Sobrien				xfree(fldtab[i]->sval);
31685587Sobrien			buf[0] = *r;
31785587Sobrien			buf[1] = 0;
31885587Sobrien			fldtab[i]->sval = tostring(buf);
31985587Sobrien			fldtab[i]->tval = FLD | STR;
32085587Sobrien		}
32185587Sobrien		*fr = 0;
32285587Sobrien	} else if (*r != 0) {	/* if 0, it's a null field */
323112336Sobrien		/* subtlecase : if length(FS) == 1 && length(RS > 0)
324112336Sobrien		 * \n is NOT a field separator (cf awk book 61,84).
325112336Sobrien		 * this variable is tested in the inner while loop.
326112336Sobrien		 */
327112336Sobrien		int rtest = '\n';  /* normal case */
328112336Sobrien		if (strlen(*RS) > 0)
329112336Sobrien			rtest = '\0';
33085587Sobrien		for (;;) {
33185587Sobrien			i++;
33285587Sobrien			if (i > nfields)
33385587Sobrien				growfldtab(i);
33485587Sobrien			if (freeable(fldtab[i]))
33585587Sobrien				xfree(fldtab[i]->sval);
33685587Sobrien			fldtab[i]->sval = fr;
33785587Sobrien			fldtab[i]->tval = FLD | STR | DONTFREE;
338112336Sobrien			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
33985587Sobrien				*fr++ = *r++;
34085587Sobrien			*fr++ = 0;
34185587Sobrien			if (*r++ == 0)
34285587Sobrien				break;
34385587Sobrien		}
34485587Sobrien		*fr = 0;
34585587Sobrien	}
34685587Sobrien	if (i > nfields)
34785587Sobrien		FATAL("record `%.30s...' has too many fields; can't happen", r);
34885587Sobrien	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
34985587Sobrien	lastfld = i;
35085587Sobrien	donefld = 1;
35185587Sobrien	for (j = 1; j <= lastfld; j++) {
35285587Sobrien		p = fldtab[j];
35385587Sobrien		if(is_number(p->sval)) {
35485587Sobrien			p->fval = atof(p->sval);
35585587Sobrien			p->tval |= NUM;
35685587Sobrien		}
35785587Sobrien	}
35885587Sobrien	setfval(nfloc, (Awkfloat) lastfld);
35985587Sobrien	if (dbg) {
36085587Sobrien		for (j = 0; j <= lastfld; j++) {
36185587Sobrien			p = fldtab[j];
36285587Sobrien			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
36385587Sobrien		}
36485587Sobrien	}
36585587Sobrien}
36685587Sobrien
36785587Sobrienvoid cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
36885587Sobrien{				/* nvals remain intact */
36985587Sobrien	Cell *p;
37085587Sobrien	int i;
37185587Sobrien
37285587Sobrien	for (i = n1; i <= n2; i++) {
37385587Sobrien		p = fldtab[i];
37485587Sobrien		if (freeable(p))
37585587Sobrien			xfree(p->sval);
37685587Sobrien		p->sval = "";
37785587Sobrien		p->tval = FLD | STR | DONTFREE;
37885587Sobrien	}
37985587Sobrien}
38085587Sobrien
38185587Sobrienvoid newfld(int n)	/* add field n after end of existing lastfld */
38285587Sobrien{
38385587Sobrien	if (n > nfields)
38485587Sobrien		growfldtab(n);
38585587Sobrien	cleanfld(lastfld+1, n);
38685587Sobrien	lastfld = n;
38785587Sobrien	setfval(nfloc, (Awkfloat) n);
38885587Sobrien}
38985587Sobrien
39085587SobrienCell *fieldadr(int n)	/* get nth field */
39185587Sobrien{
39285587Sobrien	if (n < 0)
393146299Sru		FATAL("trying to access out of range field %d", n);
39485587Sobrien	if (n > nfields)	/* fields after NF are empty */
39585587Sobrien		growfldtab(n);	/* but does not increase NF */
39685587Sobrien	return(fldtab[n]);
39785587Sobrien}
39885587Sobrien
39985587Sobrienvoid growfldtab(int n)	/* make new fields up to at least $n */
40085587Sobrien{
40185587Sobrien	int nf = 2 * nfields;
402146299Sru	size_t s;
40385587Sobrien
40485587Sobrien	if (n > nf)
40585587Sobrien		nf = n;
406146299Sru	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
407146299Sru	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
408146299Sru		fldtab = (Cell **) realloc(fldtab, s);
409146299Sru	else					/* overflow sizeof int */
410146299Sru		xfree(fldtab);	/* make it null */
41185587Sobrien	if (fldtab == NULL)
41285587Sobrien		FATAL("out of space creating %d fields", nf);
41385587Sobrien	makefields(nfields+1, nf);
41485587Sobrien	nfields = nf;
41585587Sobrien}
41685587Sobrien
417107806Sobrienint refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
41885587Sobrien{
41985587Sobrien	/* this relies on having fields[] the same length as $0 */
42085587Sobrien	/* the fields are all stored in this one array with \0's */
42185587Sobrien	char *fr;
42285587Sobrien	int i, tempstat, n;
42385587Sobrien	fa *pfa;
42485587Sobrien
42585587Sobrien	n = strlen(rec);
42685587Sobrien	if (n > fieldssize) {
42785587Sobrien		xfree(fields);
42885587Sobrien		if ((fields = (char *) malloc(n+1)) == NULL)
42985587Sobrien			FATAL("out of space for fields in refldbld %d", n);
43085587Sobrien		fieldssize = n;
43185587Sobrien	}
43285587Sobrien	fr = fields;
43385587Sobrien	*fr = '\0';
43485587Sobrien	if (*rec == '\0')
43585587Sobrien		return 0;
43685587Sobrien	pfa = makedfa(fs, 1);
43785587Sobrien	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
43885587Sobrien	tempstat = pfa->initstat;
43985587Sobrien	for (i = 1; ; i++) {
44085587Sobrien		if (i > nfields)
44185587Sobrien			growfldtab(i);
44285587Sobrien		if (freeable(fldtab[i]))
44385587Sobrien			xfree(fldtab[i]->sval);
44485587Sobrien		fldtab[i]->tval = FLD | STR | DONTFREE;
44585587Sobrien		fldtab[i]->sval = fr;
44685587Sobrien		   dprintf( ("refldbld: i=%d\n", i) );
44785587Sobrien		if (nematch(pfa, rec)) {
44885587Sobrien			pfa->initstat = 2;	/* horrible coupling to b.c */
44985587Sobrien			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
45085587Sobrien			strncpy(fr, rec, patbeg-rec);
45185587Sobrien			fr += patbeg - rec + 1;
45285587Sobrien			*(fr-1) = '\0';
45385587Sobrien			rec = patbeg + patlen;
45485587Sobrien		} else {
45585587Sobrien			   dprintf( ("no match %s\n", rec) );
45685587Sobrien			strcpy(fr, rec);
45785587Sobrien			pfa->initstat = tempstat;
45885587Sobrien			break;
45985587Sobrien		}
46085587Sobrien	}
46185587Sobrien	return i;
46285587Sobrien}
46385587Sobrien
46485587Sobrienvoid recbld(void)	/* create $0 from $1..$NF if necessary */
46585587Sobrien{
46685587Sobrien	int i;
46785587Sobrien	char *r, *p;
46885587Sobrien
46985587Sobrien	if (donerec == 1)
47085587Sobrien		return;
47185587Sobrien	r = record;
47285587Sobrien	for (i = 1; i <= *NF; i++) {
47385587Sobrien		p = getsval(fldtab[i]);
47485587Sobrien		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
47585587Sobrien			FATAL("created $0 `%.30s...' too long", record);
47685587Sobrien		while ((*r = *p++) != 0)
47785587Sobrien			r++;
47885587Sobrien		if (i < *NF) {
47985587Sobrien			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
48085587Sobrien				FATAL("created $0 `%.30s...' too long", record);
48185587Sobrien			for (p = *OFS; (*r = *p++) != 0; )
48285587Sobrien				r++;
48385587Sobrien		}
48485587Sobrien	}
48585587Sobrien	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
48685587Sobrien		FATAL("built giant record `%.30s...'", record);
48785587Sobrien	*r = '\0';
488224731Sru	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
48985587Sobrien
49085587Sobrien	if (freeable(fldtab[0]))
49185587Sobrien		xfree(fldtab[0]->sval);
49285587Sobrien	fldtab[0]->tval = REC | STR | DONTFREE;
49385587Sobrien	fldtab[0]->sval = record;
49485587Sobrien
495224731Sru	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
49685587Sobrien	   dprintf( ("recbld = |%s|\n", record) );
49785587Sobrien	donerec = 1;
49885587Sobrien}
49985587Sobrien
50085587Sobrienint	errorflag	= 0;
50185587Sobrien
502107806Sobrienvoid yyerror(const char *s)
50385587Sobrien{
504146299Sru	SYNTAX("%s", s);
50585587Sobrien}
50685587Sobrien
507107806Sobrienvoid SYNTAX(const char *fmt, ...)
50885587Sobrien{
50985587Sobrien	extern char *cmdname, *curfname;
51085587Sobrien	static int been_here = 0;
51185587Sobrien	va_list varg;
51285587Sobrien
51385587Sobrien	if (been_here++ > 2)
51485587Sobrien		return;
51585587Sobrien	fprintf(stderr, "%s: ", cmdname);
51685587Sobrien	va_start(varg, fmt);
51785587Sobrien	vfprintf(stderr, fmt, varg);
51885587Sobrien	va_end(varg);
51985587Sobrien	fprintf(stderr, " at source line %d", lineno);
52085587Sobrien	if (curfname != NULL)
52185587Sobrien		fprintf(stderr, " in function %s", curfname);
52285587Sobrien	if (compile_time == 1 && cursource() != NULL)
52385587Sobrien		fprintf(stderr, " source file %s", cursource());
52485587Sobrien	fprintf(stderr, "\n");
52585587Sobrien	errorflag = 2;
52685587Sobrien	eprint();
52785587Sobrien}
52885587Sobrien
52985587Sobrienvoid fpecatch(int n)
53085587Sobrien{
53185587Sobrien	FATAL("floating point exception %d", n);
53285587Sobrien}
53385587Sobrien
53485587Sobrienextern int bracecnt, brackcnt, parencnt;
53585587Sobrien
53685587Sobrienvoid bracecheck(void)
53785587Sobrien{
53885587Sobrien	int c;
53985587Sobrien	static int beenhere = 0;
54085587Sobrien
54185587Sobrien	if (beenhere++)
54285587Sobrien		return;
54385587Sobrien	while ((c = input()) != EOF && c != '\0')
54485587Sobrien		bclass(c);
54585587Sobrien	bcheck2(bracecnt, '{', '}');
54685587Sobrien	bcheck2(brackcnt, '[', ']');
54785587Sobrien	bcheck2(parencnt, '(', ')');
54885587Sobrien}
54985587Sobrien
55085587Sobrienvoid bcheck2(int n, int c1, int c2)
55185587Sobrien{
55285587Sobrien	if (n == 1)
55385587Sobrien		fprintf(stderr, "\tmissing %c\n", c2);
55485587Sobrien	else if (n > 1)
55585587Sobrien		fprintf(stderr, "\t%d missing %c's\n", n, c2);
55685587Sobrien	else if (n == -1)
55785587Sobrien		fprintf(stderr, "\textra %c\n", c2);
55885587Sobrien	else if (n < -1)
55985587Sobrien		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
56085587Sobrien}
56185587Sobrien
562107806Sobrienvoid FATAL(const char *fmt, ...)
56385587Sobrien{
56485587Sobrien	extern char *cmdname;
56585587Sobrien	va_list varg;
56685587Sobrien
56785587Sobrien	fflush(stdout);
56885587Sobrien	fprintf(stderr, "%s: ", cmdname);
56985587Sobrien	va_start(varg, fmt);
57085587Sobrien	vfprintf(stderr, fmt, varg);
57185587Sobrien	va_end(varg);
57285587Sobrien	error();
57385587Sobrien	if (dbg > 1)		/* core dump if serious debugging on */
57485587Sobrien		abort();
57585587Sobrien	exit(2);
57685587Sobrien}
57785587Sobrien
578107806Sobrienvoid WARNING(const char *fmt, ...)
57985587Sobrien{
58085587Sobrien	extern char *cmdname;
58185587Sobrien	va_list varg;
58285587Sobrien
58385587Sobrien	fflush(stdout);
58485587Sobrien	fprintf(stderr, "%s: ", cmdname);
58585587Sobrien	va_start(varg, fmt);
58685587Sobrien	vfprintf(stderr, fmt, varg);
58785587Sobrien	va_end(varg);
58885587Sobrien	error();
58985587Sobrien}
59085587Sobrien
59185587Sobrienvoid error()
59285587Sobrien{
59385587Sobrien	extern Node *curnode;
59485587Sobrien
59585587Sobrien	fprintf(stderr, "\n");
59685587Sobrien	if (compile_time != 2 && NR && *NR > 0) {
59785587Sobrien		fprintf(stderr, " input record number %d", (int) (*FNR));
59885587Sobrien		if (strcmp(*FILENAME, "-") != 0)
59985587Sobrien			fprintf(stderr, ", file %s", *FILENAME);
60085587Sobrien		fprintf(stderr, "\n");
60185587Sobrien	}
60285587Sobrien	if (compile_time != 2 && curnode)
60385587Sobrien		fprintf(stderr, " source line number %d", curnode->lineno);
60485587Sobrien	else if (compile_time != 2 && lineno)
60585587Sobrien		fprintf(stderr, " source line number %d", lineno);
60685587Sobrien	if (compile_time == 1 && cursource() != NULL)
60785587Sobrien		fprintf(stderr, " source file %s", cursource());
60885587Sobrien	fprintf(stderr, "\n");
60985587Sobrien	eprint();
61085587Sobrien}
61185587Sobrien
61285587Sobrienvoid eprint(void)	/* try to print context around error */
61385587Sobrien{
61485587Sobrien	char *p, *q;
61585587Sobrien	int c;
61685587Sobrien	static int been_here = 0;
61785587Sobrien	extern char ebuf[], *ep;
61885587Sobrien
61985587Sobrien	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
62085587Sobrien		return;
62185587Sobrien	p = ep - 1;
62285587Sobrien	if (p > ebuf && *p == '\n')
62385587Sobrien		p--;
62485587Sobrien	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
62585587Sobrien		;
62685587Sobrien	while (*p == '\n')
62785587Sobrien		p++;
62885587Sobrien	fprintf(stderr, " context is\n\t");
62985587Sobrien	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
63085587Sobrien		;
63185587Sobrien	for ( ; p < q; p++)
63285587Sobrien		if (*p)
63385587Sobrien			putc(*p, stderr);
63485587Sobrien	fprintf(stderr, " >>> ");
63585587Sobrien	for ( ; p < ep; p++)
63685587Sobrien		if (*p)
63785587Sobrien			putc(*p, stderr);
63885587Sobrien	fprintf(stderr, " <<< ");
63985587Sobrien	if (*ep)
64085587Sobrien		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
64185587Sobrien			putc(c, stderr);
64285587Sobrien			bclass(c);
64385587Sobrien		}
64485587Sobrien	putc('\n', stderr);
64585587Sobrien	ep = ebuf;
64685587Sobrien}
64785587Sobrien
64885587Sobrienvoid bclass(int c)
64985587Sobrien{
65085587Sobrien	switch (c) {
65185587Sobrien	case '{': bracecnt++; break;
65285587Sobrien	case '}': bracecnt--; break;
65385587Sobrien	case '[': brackcnt++; break;
65485587Sobrien	case ']': brackcnt--; break;
65585587Sobrien	case '(': parencnt++; break;
65685587Sobrien	case ')': parencnt--; break;
65785587Sobrien	}
65885587Sobrien}
65985587Sobrien
660107806Sobriendouble errcheck(double x, const char *s)
66185587Sobrien{
66285587Sobrien
66385587Sobrien	if (errno == EDOM) {
66485587Sobrien		errno = 0;
66585587Sobrien		WARNING("%s argument out of domain", s);
66685587Sobrien		x = 1;
66785587Sobrien	} else if (errno == ERANGE) {
66885587Sobrien		errno = 0;
66985587Sobrien		WARNING("%s result out of range", s);
67085587Sobrien		x = 1;
67185587Sobrien	}
67285587Sobrien	return x;
67385587Sobrien}
67485587Sobrien
675107806Sobrienint isclvar(const char *s)	/* is s of form var=something ? */
67685587Sobrien{
677107806Sobrien	const char *os = s;
67885587Sobrien
67985587Sobrien	if (!isalpha((uschar) *s) && *s != '_')
68085587Sobrien		return 0;
68185587Sobrien	for ( ; *s; s++)
68285587Sobrien		if (!(isalnum((uschar) *s) || *s == '_'))
68385587Sobrien			break;
68485587Sobrien	return *s == '=' && s > os && *(s+1) != '=';
68585587Sobrien}
68685587Sobrien
68785587Sobrien/* strtod is supposed to be a proper test of what's a valid number */
68885587Sobrien/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
68985587Sobrien/* wrong: violates 4.10.1.4 of ansi C standard */
69085587Sobrien
69185587Sobrien#include <math.h>
692107806Sobrienint is_number(const char *s)
69385587Sobrien{
69485587Sobrien	double r;
69585587Sobrien	char *ep;
69685587Sobrien	errno = 0;
69785587Sobrien	r = strtod(s, &ep);
69885587Sobrien	if (ep == s || r == HUGE_VAL || errno == ERANGE)
69985587Sobrien		return 0;
70085587Sobrien	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
70185587Sobrien		ep++;
70285587Sobrien	if (*ep == '\0')
70385587Sobrien		return 1;
70485587Sobrien	else
70585587Sobrien		return 0;
70685587Sobrien}
707