xref: /plan9-contrib/sys/src/cmd/awk/lib.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier Copyright (c) 1989 AT&T
33e12c5d1SDavid du Colombier 	All Rights Reserved
43e12c5d1SDavid du Colombier 
53e12c5d1SDavid du Colombier THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier The copyright notice above does not evidence any
83e12c5d1SDavid du Colombier actual or intended publication of such source code.
93e12c5d1SDavid du Colombier */
103e12c5d1SDavid du Colombier 
113e12c5d1SDavid du Colombier #define DEBUG
123e12c5d1SDavid du Colombier #include <stdio.h>
133e12c5d1SDavid du Colombier #include <string.h>
143e12c5d1SDavid du Colombier #include <ctype.h>
153e12c5d1SDavid du Colombier #include <errno.h>
163e12c5d1SDavid du Colombier #include <stdlib.h>
173e12c5d1SDavid du Colombier #include "awk.h"
183e12c5d1SDavid du Colombier #include "y.tab.h"
193e12c5d1SDavid du Colombier 
203e12c5d1SDavid du Colombier #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
213e12c5d1SDavid du Colombier #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier FILE	*infile	= NULL;
243e12c5d1SDavid du Colombier uchar	*file	= (uchar*) "";
25*219b2ee8SDavid du Colombier int	recsize	= RECSIZE;
26*219b2ee8SDavid du Colombier uchar	*recdata;
27*219b2ee8SDavid du Colombier uchar	*record;
28*219b2ee8SDavid du Colombier uchar	*fields;
29*219b2ee8SDavid du Colombier Cell	*fldtab;
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier #define	MAXFLD	200
32*219b2ee8SDavid du Colombier int	nfields	= MAXFLD;	/* can be set from commandline in main */
33*219b2ee8SDavid du Colombier 
343e12c5d1SDavid du Colombier int	donefld;	/* 1 = implies rec broken into fields */
353e12c5d1SDavid du Colombier int	donerec;	/* 1 = record is valid (no flds have changed) */
363e12c5d1SDavid du Colombier 
373e12c5d1SDavid du Colombier int	maxfld	= 0;	/* last used field */
383e12c5d1SDavid du Colombier int	argno	= 1;	/* current input argument number */
393e12c5d1SDavid du Colombier extern	Awkfloat *ARGC;
403e12c5d1SDavid du Colombier 
41*219b2ee8SDavid du Colombier void recinit(unsigned int n)
42*219b2ee8SDavid du Colombier {
43*219b2ee8SDavid du Colombier 	static Cell dollar0 = {
44*219b2ee8SDavid du Colombier 	    OCELL, CFLD, (uchar*) "$0", /*recdata*/0, 0.0, REC|STR|DONTFREE };
45*219b2ee8SDavid du Colombier 	static Cell dollar1 = {
46*219b2ee8SDavid du Colombier 	    OCELL, CFLD, NULL, (uchar*) "", 0.0, FLD|STR|DONTFREE };
47*219b2ee8SDavid du Colombier 	int i;
48*219b2ee8SDavid du Colombier 
49*219b2ee8SDavid du Colombier 	record = recdata = (uchar *) malloc(n);
50*219b2ee8SDavid du Colombier 	fields = (uchar *) malloc(n);
51*219b2ee8SDavid du Colombier 	fldtab = (Cell *) malloc(nfields * sizeof(Cell));
52*219b2ee8SDavid du Colombier 	if (recdata == NULL || fields == NULL || fldtab == NULL)
53*219b2ee8SDavid du Colombier 		ERROR "out of space for $0 and fields" FATAL;
54*219b2ee8SDavid du Colombier 	fldtab[0] = dollar0;
55*219b2ee8SDavid du Colombier 	fldtab[0].sval = recdata;
56*219b2ee8SDavid du Colombier 	for (i = 1; i < nfields; i++)
57*219b2ee8SDavid du Colombier 		fldtab[i] = dollar1;
58*219b2ee8SDavid du Colombier }
59*219b2ee8SDavid du Colombier 
603e12c5d1SDavid du Colombier void initgetrec(void)
613e12c5d1SDavid du Colombier {
623e12c5d1SDavid du Colombier 	int i;
633e12c5d1SDavid du Colombier 	uchar *p;
643e12c5d1SDavid du Colombier 
653e12c5d1SDavid du Colombier 	for (i = 1; i < *ARGC; i++) {
66*219b2ee8SDavid du Colombier 		if (!isclvar(p = getargv(i))) {	/* find 1st real filename */
67*219b2ee8SDavid du Colombier 			setsval(lookup("FILENAME", symtab), getargv(i));
683e12c5d1SDavid du Colombier 			return;
69*219b2ee8SDavid du Colombier 		}
703e12c5d1SDavid du Colombier 		setclvar(p);	/* a commandline assignment before filename */
713e12c5d1SDavid du Colombier 		argno++;
723e12c5d1SDavid du Colombier 	}
733e12c5d1SDavid du Colombier 	infile = stdin;		/* no filenames, so use stdin */
743e12c5d1SDavid du Colombier }
753e12c5d1SDavid du Colombier 
76*219b2ee8SDavid du Colombier getrec(uchar *buf)	/* get next input record from whatever source */
77*219b2ee8SDavid du Colombier {			/* note: tests whether buf == record */
783e12c5d1SDavid du Colombier 	int c;
793e12c5d1SDavid du Colombier 	static int firsttime = 1;
803e12c5d1SDavid du Colombier 
813e12c5d1SDavid du Colombier 	if (firsttime) {
823e12c5d1SDavid du Colombier 		firsttime = 0;
833e12c5d1SDavid du Colombier 		initgetrec();
843e12c5d1SDavid du Colombier 	}
853e12c5d1SDavid du Colombier 	dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
863e12c5d1SDavid du Colombier 		*RS, *FS, *ARGC, *FILENAME) );
873e12c5d1SDavid du Colombier 	donefld = 0;
883e12c5d1SDavid du Colombier 	donerec = 1;
893e12c5d1SDavid du Colombier 	buf[0] = 0;
903e12c5d1SDavid du Colombier 	while (argno < *ARGC || infile == stdin) {
913e12c5d1SDavid du Colombier 		dprintf( ("argno=%d, file=|%s|\n", argno, file) );
923e12c5d1SDavid du Colombier 		if (infile == NULL) {	/* have to open a new file */
933e12c5d1SDavid du Colombier 			file = getargv(argno);
943e12c5d1SDavid du Colombier 			if (*file == '\0') {	/* it's been zapped */
953e12c5d1SDavid du Colombier 				argno++;
963e12c5d1SDavid du Colombier 				continue;
973e12c5d1SDavid du Colombier 			}
983e12c5d1SDavid du Colombier 			if (isclvar(file)) {	/* a var=value arg */
993e12c5d1SDavid du Colombier 				setclvar(file);
1003e12c5d1SDavid du Colombier 				argno++;
1013e12c5d1SDavid du Colombier 				continue;
1023e12c5d1SDavid du Colombier 			}
1033e12c5d1SDavid du Colombier 			*FILENAME = file;
1043e12c5d1SDavid du Colombier 			dprintf( ("opening file %s\n", file) );
1053e12c5d1SDavid du Colombier 			if (*file == '-' && *(file+1) == '\0')
1063e12c5d1SDavid du Colombier 				infile = stdin;
1073e12c5d1SDavid du Colombier 			else if ((infile = fopen((char *)file, "r")) == NULL)
1083e12c5d1SDavid du Colombier 				ERROR "can't open file %s", file FATAL;
1093e12c5d1SDavid du Colombier 			setfval(fnrloc, 0.0);
1103e12c5d1SDavid du Colombier 		}
111*219b2ee8SDavid du Colombier 		c = readrec(buf, recsize, infile);
1123e12c5d1SDavid du Colombier 		if (c != 0 || buf[0] != '\0') {	/* normal record */
1133e12c5d1SDavid du Colombier 			if (buf == record) {
1143e12c5d1SDavid du Colombier 				if (!(recloc->tval & DONTFREE))
1153e12c5d1SDavid du Colombier 					xfree(recloc->sval);
1163e12c5d1SDavid du Colombier 				recloc->sval = record;
1173e12c5d1SDavid du Colombier 				recloc->tval = REC | STR | DONTFREE;
1183e12c5d1SDavid du Colombier 				if (isnumber(recloc->sval)) {
1193e12c5d1SDavid du Colombier 					recloc->fval = atof(recloc->sval);
1203e12c5d1SDavid du Colombier 					recloc->tval |= NUM;
1213e12c5d1SDavid du Colombier 				}
1223e12c5d1SDavid du Colombier 			}
1233e12c5d1SDavid du Colombier 			setfval(nrloc, nrloc->fval+1);
1243e12c5d1SDavid du Colombier 			setfval(fnrloc, fnrloc->fval+1);
1253e12c5d1SDavid du Colombier 			return 1;
1263e12c5d1SDavid du Colombier 		}
1273e12c5d1SDavid du Colombier 		/* EOF arrived on this file; set up next */
1283e12c5d1SDavid du Colombier 		if (infile != stdin)
1293e12c5d1SDavid du Colombier 			fclose(infile);
1303e12c5d1SDavid du Colombier 		infile = NULL;
1313e12c5d1SDavid du Colombier 		argno++;
1323e12c5d1SDavid du Colombier 	}
1333e12c5d1SDavid du Colombier 	return 0;	/* true end of file */
1343e12c5d1SDavid du Colombier }
1353e12c5d1SDavid du Colombier 
1363e12c5d1SDavid du Colombier readrec(uchar *buf, int bufsize, FILE *inf)	/* read one record into buf */
1373e12c5d1SDavid du Colombier {
1383e12c5d1SDavid du Colombier 	register int sep, c;
1393e12c5d1SDavid du Colombier 	register uchar *rr;
1403e12c5d1SDavid du Colombier 	register int nrr;
1413e12c5d1SDavid du Colombier 
1423e12c5d1SDavid du Colombier 	if ((sep = **RS) == 0) {
1433e12c5d1SDavid du Colombier 		sep = '\n';
1443e12c5d1SDavid du Colombier 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
1453e12c5d1SDavid du Colombier 			;
1463e12c5d1SDavid du Colombier 		if (c != EOF)
1473e12c5d1SDavid du Colombier 			ungetc(c, inf);
1483e12c5d1SDavid du Colombier 	}
1493e12c5d1SDavid du Colombier 	for (rr = buf, nrr = bufsize; ; ) {
1503e12c5d1SDavid du Colombier 		for (; (c=getc(inf)) != sep && c != EOF; *rr++ = c)
1513e12c5d1SDavid du Colombier 			if (--nrr < 0)
152*219b2ee8SDavid du Colombier 				ERROR "input record `%.30s...' too long; try -mr n", buf FATAL;
1533e12c5d1SDavid du Colombier 		if (**RS == sep || c == EOF)
1543e12c5d1SDavid du Colombier 			break;
1553e12c5d1SDavid du Colombier 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
1563e12c5d1SDavid du Colombier 			break;
1573e12c5d1SDavid du Colombier 		*rr++ = '\n';
1583e12c5d1SDavid du Colombier 		*rr++ = c;
1593e12c5d1SDavid du Colombier 	}
1603e12c5d1SDavid du Colombier 	if (rr > buf + bufsize)
161*219b2ee8SDavid du Colombier 		ERROR "input record `%.30s...' too long; try -mr n", buf FATAL;
1623e12c5d1SDavid du Colombier 	*rr = 0;
1633e12c5d1SDavid du Colombier 	dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
1643e12c5d1SDavid du Colombier 	return c == EOF && rr == buf ? 0 : 1;
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier uchar *getargv(int n)	/* get ARGV[n] */
1683e12c5d1SDavid du Colombier {
1693e12c5d1SDavid du Colombier 	Cell *x;
1703e12c5d1SDavid du Colombier 	uchar *s, temp[10];
1713e12c5d1SDavid du Colombier 	extern Array *ARGVtab;
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 	sprintf((char *)temp, "%d", n);
1743e12c5d1SDavid du Colombier 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
1753e12c5d1SDavid du Colombier 	s = getsval(x);
1763e12c5d1SDavid du Colombier 	dprintf( ("getargv(%d) returns |%s|\n", n, s) );
1773e12c5d1SDavid du Colombier 	return s;
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier void setclvar(uchar *s)	/* set var=value from s */
1813e12c5d1SDavid du Colombier {
1823e12c5d1SDavid du Colombier 	uchar *p;
1833e12c5d1SDavid du Colombier 	Cell *q;
1843e12c5d1SDavid du Colombier 
1853e12c5d1SDavid du Colombier 	for (p=s; *p != '='; p++)
1863e12c5d1SDavid du Colombier 		;
1873e12c5d1SDavid du Colombier 	*p++ = 0;
1883e12c5d1SDavid du Colombier 	p = qstring(p, '\0');
1893e12c5d1SDavid du Colombier 	q = setsymtab(s, p, 0.0, STR, symtab);
1903e12c5d1SDavid du Colombier 	setsval(q, p);
1913e12c5d1SDavid du Colombier 	if (isnumber(q->sval)) {
1923e12c5d1SDavid du Colombier 		q->fval = atof(q->sval);
1933e12c5d1SDavid du Colombier 		q->tval |= NUM;
1943e12c5d1SDavid du Colombier 	}
1953e12c5d1SDavid du Colombier 	dprintf( ("command line set %s to |%s|\n", s, p) );
1963e12c5d1SDavid du Colombier }
1973e12c5d1SDavid du Colombier 
1983e12c5d1SDavid du Colombier 
199*219b2ee8SDavid du Colombier void fldbld(void)	/* create fields from current record */
2003e12c5d1SDavid du Colombier {
2013e12c5d1SDavid du Colombier 	register uchar *r, *fr, sep;
2023e12c5d1SDavid du Colombier 	Cell *p;
2033e12c5d1SDavid du Colombier 	int i;
2043e12c5d1SDavid du Colombier 
2053e12c5d1SDavid du Colombier 	if (donefld)
2063e12c5d1SDavid du Colombier 		return;
2073e12c5d1SDavid du Colombier 	if (!(recloc->tval & STR))
2083e12c5d1SDavid du Colombier 		getsval(recloc);
209*219b2ee8SDavid du Colombier 	r = recloc->sval;
2103e12c5d1SDavid du Colombier 	fr = fields;
2113e12c5d1SDavid du Colombier 	i = 0;	/* number of fields accumulated here */
2123e12c5d1SDavid du Colombier 	if (strlen(*FS) > 1) {	/* it's a regular expression */
2133e12c5d1SDavid du Colombier 		i = refldbld(r, *FS);
214*219b2ee8SDavid du Colombier 	} else if ((sep = **FS) == ' ') {	/* default whitespace */
2153e12c5d1SDavid du Colombier 		for (i = 0; ; ) {
2163e12c5d1SDavid du Colombier 			while (*r == ' ' || *r == '\t' || *r == '\n')
2173e12c5d1SDavid du Colombier 				r++;
2183e12c5d1SDavid du Colombier 			if (*r == 0)
2193e12c5d1SDavid du Colombier 				break;
2203e12c5d1SDavid du Colombier 			i++;
221*219b2ee8SDavid du Colombier 			if (i >= nfields)
2223e12c5d1SDavid du Colombier 				break;
2233e12c5d1SDavid du Colombier 			if (!(fldtab[i].tval & DONTFREE))
2243e12c5d1SDavid du Colombier 				xfree(fldtab[i].sval);
2253e12c5d1SDavid du Colombier 			fldtab[i].sval = fr;
2263e12c5d1SDavid du Colombier 			fldtab[i].tval = FLD | STR | DONTFREE;
2273e12c5d1SDavid du Colombier 			do
2283e12c5d1SDavid du Colombier 				*fr++ = *r++;
2293e12c5d1SDavid du Colombier 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
2303e12c5d1SDavid du Colombier 			*fr++ = 0;
2313e12c5d1SDavid du Colombier 		}
2323e12c5d1SDavid du Colombier 		*fr = 0;
2333e12c5d1SDavid du Colombier 	} else if (*r != 0) {	/* if 0, it's a null field */
2343e12c5d1SDavid du Colombier 		for (;;) {
2353e12c5d1SDavid du Colombier 			i++;
236*219b2ee8SDavid du Colombier 			if (i >= nfields)
2373e12c5d1SDavid du Colombier 				break;
2383e12c5d1SDavid du Colombier 			if (!(fldtab[i].tval & DONTFREE))
2393e12c5d1SDavid du Colombier 				xfree(fldtab[i].sval);
2403e12c5d1SDavid du Colombier 			fldtab[i].sval = fr;
2413e12c5d1SDavid du Colombier 			fldtab[i].tval = FLD | STR | DONTFREE;
242*219b2ee8SDavid du Colombier 			while (*r != sep && *r != '\n' && *r != '\0')	/* \n is always a separator */
2433e12c5d1SDavid du Colombier 				*fr++ = *r++;
2443e12c5d1SDavid du Colombier 			*fr++ = 0;
2453e12c5d1SDavid du Colombier 			if (*r++ == 0)
2463e12c5d1SDavid du Colombier 				break;
2473e12c5d1SDavid du Colombier 		}
2483e12c5d1SDavid du Colombier 		*fr = 0;
2493e12c5d1SDavid du Colombier 	}
250*219b2ee8SDavid du Colombier 	if (i >= nfields)
251*219b2ee8SDavid du Colombier 		ERROR "record `%.30s...' has too many fields; try -mf n", record FATAL;
2523e12c5d1SDavid du Colombier 	/* clean out junk from previous record */
2533e12c5d1SDavid du Colombier 	cleanfld(i, maxfld);
2543e12c5d1SDavid du Colombier 	maxfld = i;
2553e12c5d1SDavid du Colombier 	donefld = 1;
2563e12c5d1SDavid du Colombier 	for (p = fldtab+1; p <= fldtab+maxfld; p++) {
2573e12c5d1SDavid du Colombier 		if(isnumber(p->sval)) {
2583e12c5d1SDavid du Colombier 			p->fval = atof(p->sval);
2593e12c5d1SDavid du Colombier 			p->tval |= NUM;
2603e12c5d1SDavid du Colombier 		}
2613e12c5d1SDavid du Colombier 	}
2623e12c5d1SDavid du Colombier 	setfval(nfloc, (Awkfloat) maxfld);
2633e12c5d1SDavid du Colombier 	if (dbg)
2643e12c5d1SDavid du Colombier 		for (p = fldtab; p <= fldtab+maxfld; p++)
2653e12c5d1SDavid du Colombier 			printf("field %d: |%s|\n", p-fldtab, p->sval);
2663e12c5d1SDavid du Colombier }
2673e12c5d1SDavid du Colombier 
2683e12c5d1SDavid du Colombier void cleanfld(int n1, int n2)	/* clean out fields n1..n2 inclusive */
2693e12c5d1SDavid du Colombier {
2703e12c5d1SDavid du Colombier 	static uchar *nullstat = (uchar *) "";
2713e12c5d1SDavid du Colombier 	register Cell *p, *q;
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier 	for (p = &fldtab[n2], q = &fldtab[n1]; p > q; p--) {
2743e12c5d1SDavid du Colombier 		if (!(p->tval & DONTFREE))
2753e12c5d1SDavid du Colombier 			xfree(p->sval);
2763e12c5d1SDavid du Colombier 		p->tval = FLD | STR | DONTFREE;
2773e12c5d1SDavid du Colombier 		p->sval = nullstat;
2783e12c5d1SDavid du Colombier 	}
2793e12c5d1SDavid du Colombier }
2803e12c5d1SDavid du Colombier 
2813e12c5d1SDavid du Colombier void newfld(int n)	/* add field n (after end) */
2823e12c5d1SDavid du Colombier {
283*219b2ee8SDavid du Colombier 	if (n >= nfields)
284*219b2ee8SDavid du Colombier 		ERROR "creating too many fields (%d); try -mf n", n, record FATAL;
2853e12c5d1SDavid du Colombier 	cleanfld(maxfld, n);
2863e12c5d1SDavid du Colombier 	maxfld = n;
2873e12c5d1SDavid du Colombier 	setfval(nfloc, (Awkfloat) n);
2883e12c5d1SDavid du Colombier }
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier refldbld(uchar *rec, uchar *fs)	/* build fields from reg expr in FS */
2913e12c5d1SDavid du Colombier {
2923e12c5d1SDavid du Colombier 	uchar *fr;
2933e12c5d1SDavid du Colombier 	void *p;
2943e12c5d1SDavid du Colombier 	int i;
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 	fr = fields;
2973e12c5d1SDavid du Colombier 	*fr = '\0';
2983e12c5d1SDavid du Colombier 	if (*rec == '\0')
2993e12c5d1SDavid du Colombier 		return 0;
3003e12c5d1SDavid du Colombier 	p = compre(fs);
3013e12c5d1SDavid du Colombier 	dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
302*219b2ee8SDavid du Colombier 	for (i = 1; i < nfields; i++) {
3033e12c5d1SDavid du Colombier 		if (!(fldtab[i].tval & DONTFREE))
3043e12c5d1SDavid du Colombier 			xfree(fldtab[i].sval);
3053e12c5d1SDavid du Colombier 		fldtab[i].tval = FLD | STR | DONTFREE;
3063e12c5d1SDavid du Colombier 		fldtab[i].sval = fr;
3073e12c5d1SDavid du Colombier 		dprintf( ("refldbld: i=%d\n", i) );
3083e12c5d1SDavid du Colombier 		if (nematch(p, rec, rec)) {
3093e12c5d1SDavid du Colombier 			dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
3103e12c5d1SDavid du Colombier 			strncpy(fr, rec, patbeg-rec);
3113e12c5d1SDavid du Colombier 			fr += patbeg - rec + 1;
3123e12c5d1SDavid du Colombier 			*(fr-1) = '\0';
3133e12c5d1SDavid du Colombier 			rec = patbeg + patlen;
3143e12c5d1SDavid du Colombier 		} else {
3153e12c5d1SDavid du Colombier 			dprintf( ("no match %s\n", rec) );
3163e12c5d1SDavid du Colombier 			strcpy(fr, rec);
3173e12c5d1SDavid du Colombier 			break;
3183e12c5d1SDavid du Colombier 		}
3193e12c5d1SDavid du Colombier 	}
3203e12c5d1SDavid du Colombier 	return i;
3213e12c5d1SDavid du Colombier }
3223e12c5d1SDavid du Colombier 
323*219b2ee8SDavid du Colombier void recbld(void)	/* create $0 from $1..$NF if necessary */
3243e12c5d1SDavid du Colombier {
325*219b2ee8SDavid du Colombier 	register int i;
3263e12c5d1SDavid du Colombier 	register uchar *r, *p;
327*219b2ee8SDavid du Colombier 	static uchar *rec = 0;
3283e12c5d1SDavid du Colombier 
3293e12c5d1SDavid du Colombier 	if (donerec == 1)
3303e12c5d1SDavid du Colombier 		return;
331*219b2ee8SDavid du Colombier 	if (rec == 0) {
332*219b2ee8SDavid du Colombier 		rec = (uchar *) malloc(recsize);
333*219b2ee8SDavid du Colombier 		if (rec == 0)
334*219b2ee8SDavid du Colombier 			ERROR "out of space building $0, record size %d", recsize FATAL;
335*219b2ee8SDavid du Colombier 	}
3363e12c5d1SDavid du Colombier 	r = rec;
3373e12c5d1SDavid du Colombier 	for (i = 1; i <= *NF; i++) {
3383e12c5d1SDavid du Colombier 		p = getsval(&fldtab[i]);
339*219b2ee8SDavid du Colombier 		while (r < rec+recsize-1 && (*r = *p++))
3403e12c5d1SDavid du Colombier 			r++;
3413e12c5d1SDavid du Colombier 		if (i < *NF)
342*219b2ee8SDavid du Colombier 			for (p = *OFS; r < rec+recsize-1 && (*r = *p++); )
3433e12c5d1SDavid du Colombier 				r++;
3443e12c5d1SDavid du Colombier 	}
345*219b2ee8SDavid du Colombier 	if (r > rec + recsize - 1)
346*219b2ee8SDavid du Colombier 		ERROR "built giant record `%.30s...'; try -mr n", record FATAL;
3473e12c5d1SDavid du Colombier 	*r = '\0';
3483e12c5d1SDavid du Colombier 	dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
3493e12c5d1SDavid du Colombier 	recloc->tval = REC | STR | DONTFREE;
3503e12c5d1SDavid du Colombier 	recloc->sval = record = rec;
3513e12c5d1SDavid du Colombier 	dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
3523e12c5d1SDavid du Colombier 	dprintf( ("recbld = |%s|\n", record) );
3533e12c5d1SDavid du Colombier 	donerec = 1;
3543e12c5d1SDavid du Colombier }
3553e12c5d1SDavid du Colombier 
3563e12c5d1SDavid du Colombier Cell *fieldadr(int n)
3573e12c5d1SDavid du Colombier {
358*219b2ee8SDavid du Colombier 	if (n < 0 || n >= nfields)
359*219b2ee8SDavid du Colombier 		ERROR "trying to access field %d; try -mf n", n FATAL;
3603e12c5d1SDavid du Colombier 	return(&fldtab[n]);
3613e12c5d1SDavid du Colombier }
3623e12c5d1SDavid du Colombier 
3633e12c5d1SDavid du Colombier int	errorflag	= 0;
3643e12c5d1SDavid du Colombier char	errbuf[200];
3653e12c5d1SDavid du Colombier 
3663e12c5d1SDavid du Colombier void yyerror(uchar *s)
3673e12c5d1SDavid du Colombier {
3683e12c5d1SDavid du Colombier 	extern uchar *cmdname, *curfname;
3693e12c5d1SDavid du Colombier 	static int been_here = 0;
3703e12c5d1SDavid du Colombier 
3713e12c5d1SDavid du Colombier 	if (been_here++ > 2)
3723e12c5d1SDavid du Colombier 		return;
3733e12c5d1SDavid du Colombier 	fprintf(stderr, "%s: %s", cmdname, s);
3743e12c5d1SDavid du Colombier 	fprintf(stderr, " at source line %d", lineno);
3753e12c5d1SDavid du Colombier 	if (curfname != NULL)
3763e12c5d1SDavid du Colombier 		fprintf(stderr, " in function %s", curfname);
3773e12c5d1SDavid du Colombier 	fprintf(stderr, "\n");
3783e12c5d1SDavid du Colombier 	errorflag = 2;
3793e12c5d1SDavid du Colombier 	eprint();
3803e12c5d1SDavid du Colombier }
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier void fpecatch(int n)
3833e12c5d1SDavid du Colombier {
3843e12c5d1SDavid du Colombier 	ERROR "floating point exception %d", n FATAL;
3853e12c5d1SDavid du Colombier }
3863e12c5d1SDavid du Colombier 
3873e12c5d1SDavid du Colombier extern int bracecnt, brackcnt, parencnt;
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier void bracecheck(void)
3903e12c5d1SDavid du Colombier {
3913e12c5d1SDavid du Colombier 	int c;
3923e12c5d1SDavid du Colombier 	static int beenhere = 0;
3933e12c5d1SDavid du Colombier 
3943e12c5d1SDavid du Colombier 	if (beenhere++)
3953e12c5d1SDavid du Colombier 		return;
3963e12c5d1SDavid du Colombier 	while ((c = input()) != EOF && c != '\0')
3973e12c5d1SDavid du Colombier 		bclass(c);
3983e12c5d1SDavid du Colombier 	bcheck2(bracecnt, '{', '}');
3993e12c5d1SDavid du Colombier 	bcheck2(brackcnt, '[', ']');
4003e12c5d1SDavid du Colombier 	bcheck2(parencnt, '(', ')');
4013e12c5d1SDavid du Colombier }
4023e12c5d1SDavid du Colombier 
4033e12c5d1SDavid du Colombier void bcheck2(int n, int c1, int c2)
4043e12c5d1SDavid du Colombier {
4053e12c5d1SDavid du Colombier 	if (n == 1)
4063e12c5d1SDavid du Colombier 		fprintf(stderr, "\tmissing %c\n", c2);
4073e12c5d1SDavid du Colombier 	else if (n > 1)
4083e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
4093e12c5d1SDavid du Colombier 	else if (n == -1)
4103e12c5d1SDavid du Colombier 		fprintf(stderr, "\textra %c\n", c2);
4113e12c5d1SDavid du Colombier 	else if (n < -1)
4123e12c5d1SDavid du Colombier 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
4133e12c5d1SDavid du Colombier }
4143e12c5d1SDavid du Colombier 
4153e12c5d1SDavid du Colombier void error(int f, char *s)
4163e12c5d1SDavid du Colombier {
4173e12c5d1SDavid du Colombier 	extern Node *curnode;
4183e12c5d1SDavid du Colombier 	extern uchar *cmdname;
4193e12c5d1SDavid du Colombier 
4203e12c5d1SDavid du Colombier 	fflush(stdout);
4213e12c5d1SDavid du Colombier 	fprintf(stderr, "%s: ", cmdname);
4223e12c5d1SDavid du Colombier 	fprintf(stderr, "%s", s);
4233e12c5d1SDavid du Colombier 	fprintf(stderr, "\n");
4243e12c5d1SDavid du Colombier 	if (compile_time != 2 && NR && *NR > 0) {
425*219b2ee8SDavid du Colombier 		fprintf(stderr, " input record number %d", (int) (*FNR));
4263e12c5d1SDavid du Colombier 		if (strcmp(*FILENAME, "-") != 0)
4273e12c5d1SDavid du Colombier 			fprintf(stderr, ", file %s", *FILENAME);
4283e12c5d1SDavid du Colombier 		fprintf(stderr, "\n");
4293e12c5d1SDavid du Colombier 	}
4303e12c5d1SDavid du Colombier 	if (compile_time != 2 && curnode)
4313e12c5d1SDavid du Colombier 		fprintf(stderr, " source line number %d\n", curnode->lineno);
4323e12c5d1SDavid du Colombier 	else if (compile_time != 2 && lineno)
4333e12c5d1SDavid du Colombier 		fprintf(stderr, " source line number %d\n", lineno);
4343e12c5d1SDavid du Colombier 	eprint();
4353e12c5d1SDavid du Colombier 	if (f) {
436*219b2ee8SDavid du Colombier 		if (dbg > 1)		/* core dump if serious debugging on */
4373e12c5d1SDavid du Colombier 			abort();
4383e12c5d1SDavid du Colombier 		exit(2);
4393e12c5d1SDavid du Colombier 	}
4403e12c5d1SDavid du Colombier }
4413e12c5d1SDavid du Colombier 
4423e12c5d1SDavid du Colombier void eprint(void)	/* try to print context around error */
4433e12c5d1SDavid du Colombier {
4443e12c5d1SDavid du Colombier 	uchar *p, *q;
4453e12c5d1SDavid du Colombier 	int c;
4463e12c5d1SDavid du Colombier 	static int been_here = 0;
447*219b2ee8SDavid du Colombier 	extern uchar ebuf[], *ep;
4483e12c5d1SDavid du Colombier 
4493e12c5d1SDavid du Colombier 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
4503e12c5d1SDavid du Colombier 		return;
4513e12c5d1SDavid du Colombier 	p = ep - 1;
4523e12c5d1SDavid du Colombier 	if (p > ebuf && *p == '\n')
4533e12c5d1SDavid du Colombier 		p--;
4543e12c5d1SDavid du Colombier 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
4553e12c5d1SDavid du Colombier 		;
4563e12c5d1SDavid du Colombier 	while (*p == '\n')
4573e12c5d1SDavid du Colombier 		p++;
4583e12c5d1SDavid du Colombier 	fprintf(stderr, " context is\n\t");
4593e12c5d1SDavid du Colombier 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
4603e12c5d1SDavid du Colombier 		;
4613e12c5d1SDavid du Colombier 	for ( ; p < q; p++)
4623e12c5d1SDavid du Colombier 		if (*p)
4633e12c5d1SDavid du Colombier 			putc(*p, stderr);
4643e12c5d1SDavid du Colombier 	fprintf(stderr, " >>> ");
4653e12c5d1SDavid du Colombier 	for ( ; p < ep; p++)
4663e12c5d1SDavid du Colombier 		if (*p)
4673e12c5d1SDavid du Colombier 			putc(*p, stderr);
4683e12c5d1SDavid du Colombier 	fprintf(stderr, " <<< ");
4693e12c5d1SDavid du Colombier 	if (*ep)
4703e12c5d1SDavid du Colombier 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
4713e12c5d1SDavid du Colombier 			putc(c, stderr);
4723e12c5d1SDavid du Colombier 			bclass(c);
4733e12c5d1SDavid du Colombier 		}
4743e12c5d1SDavid du Colombier 	putc('\n', stderr);
4753e12c5d1SDavid du Colombier 	ep = ebuf;
4763e12c5d1SDavid du Colombier }
4773e12c5d1SDavid du Colombier 
4783e12c5d1SDavid du Colombier void bclass(int c)
4793e12c5d1SDavid du Colombier {
4803e12c5d1SDavid du Colombier 	switch (c) {
4813e12c5d1SDavid du Colombier 	case '{': bracecnt++; break;
4823e12c5d1SDavid du Colombier 	case '}': bracecnt--; break;
4833e12c5d1SDavid du Colombier 	case '[': brackcnt++; break;
4843e12c5d1SDavid du Colombier 	case ']': brackcnt--; break;
4853e12c5d1SDavid du Colombier 	case '(': parencnt++; break;
4863e12c5d1SDavid du Colombier 	case ')': parencnt--; break;
4873e12c5d1SDavid du Colombier 	}
4883e12c5d1SDavid du Colombier }
4893e12c5d1SDavid du Colombier 
4903e12c5d1SDavid du Colombier double errcheck(double x, uchar *s)
4913e12c5d1SDavid du Colombier {
4923e12c5d1SDavid du Colombier 	extern int errno;
4933e12c5d1SDavid du Colombier 
4943e12c5d1SDavid du Colombier 	if (errno == EDOM) {
4953e12c5d1SDavid du Colombier 		errno = 0;
4963e12c5d1SDavid du Colombier 		ERROR "%s argument out of domain", s WARNING;
4973e12c5d1SDavid du Colombier 		x = 1;
4983e12c5d1SDavid du Colombier 	} else if (errno == ERANGE) {
4993e12c5d1SDavid du Colombier 		errno = 0;
5003e12c5d1SDavid du Colombier 		ERROR "%s result out of range", s WARNING;
5013e12c5d1SDavid du Colombier 		x = 1;
5023e12c5d1SDavid du Colombier 	}
5033e12c5d1SDavid du Colombier 	return x;
5043e12c5d1SDavid du Colombier }
5053e12c5d1SDavid du Colombier 
5063e12c5d1SDavid du Colombier isclvar(uchar *s)	/* is s of form var=something ? */
5073e12c5d1SDavid du Colombier {
5083e12c5d1SDavid du Colombier 	uchar *os = s;
5093e12c5d1SDavid du Colombier 
5103e12c5d1SDavid du Colombier 	if (!isalpha(*s) && *s != '_')
5113e12c5d1SDavid du Colombier 		return 0;
5123e12c5d1SDavid du Colombier 	for ( ; *s; s++)
5133e12c5d1SDavid du Colombier 		if (!(isalnum(*s) || *s == '_'))
5143e12c5d1SDavid du Colombier 			break;
5153e12c5d1SDavid du Colombier 	return *s == '=' && s > os && *(s+1) != '=';
5163e12c5d1SDavid du Colombier }
5173e12c5d1SDavid du Colombier 
518*219b2ee8SDavid du Colombier #define	MAXEXPON	38	/* maximum exponent for fp number. should be IEEE */
5193e12c5d1SDavid du Colombier 
520*219b2ee8SDavid du Colombier isnumber(uchar *s)	/* should be done by a library function */
5213e12c5d1SDavid du Colombier {
5223e12c5d1SDavid du Colombier 	register int d1, d2;
5233e12c5d1SDavid du Colombier 	int point;
5243e12c5d1SDavid du Colombier 	uchar *es;
5253e12c5d1SDavid du Colombier 
5263e12c5d1SDavid du Colombier 	d1 = d2 = point = 0;
5273e12c5d1SDavid du Colombier 	while (*s == ' ' || *s == '\t' || *s == '\n')
5283e12c5d1SDavid du Colombier 		s++;
5293e12c5d1SDavid du Colombier 	if (*s == '\0')
530*219b2ee8SDavid du Colombier 		return(0);	/* empty stuff isn't a number */
5313e12c5d1SDavid du Colombier 	if (*s == '+' || *s == '-')
5323e12c5d1SDavid du Colombier 		s++;
5333e12c5d1SDavid du Colombier 	if (!isdigit(*s) && *s != '.')
5343e12c5d1SDavid du Colombier 		return(0);
5353e12c5d1SDavid du Colombier 	if (isdigit(*s)) {
5363e12c5d1SDavid du Colombier 		do {
5373e12c5d1SDavid du Colombier 			d1++;
5383e12c5d1SDavid du Colombier 			s++;
5393e12c5d1SDavid du Colombier 		} while (isdigit(*s));
5403e12c5d1SDavid du Colombier 	}
5413e12c5d1SDavid du Colombier 	if (*s == '.') {
5423e12c5d1SDavid du Colombier 		point++;
5433e12c5d1SDavid du Colombier 		s++;
5443e12c5d1SDavid du Colombier 	}
5453e12c5d1SDavid du Colombier 	if (isdigit(*s)) {
5463e12c5d1SDavid du Colombier 		d2++;
5473e12c5d1SDavid du Colombier 		do {
5483e12c5d1SDavid du Colombier 			s++;
5493e12c5d1SDavid du Colombier 		} while (isdigit(*s));
5503e12c5d1SDavid du Colombier 	}
5513e12c5d1SDavid du Colombier 	if (!(d1 || point && d2))
5523e12c5d1SDavid du Colombier 		return(0);
5533e12c5d1SDavid du Colombier 	if (*s == 'e' || *s == 'E') {
5543e12c5d1SDavid du Colombier 		s++;
5553e12c5d1SDavid du Colombier 		if (*s == '+' || *s == '-')
5563e12c5d1SDavid du Colombier 			s++;
5573e12c5d1SDavid du Colombier 		if (!isdigit(*s))
5583e12c5d1SDavid du Colombier 			return(0);
5593e12c5d1SDavid du Colombier 		es = s;
5603e12c5d1SDavid du Colombier 		do {
5613e12c5d1SDavid du Colombier 			s++;
5623e12c5d1SDavid du Colombier 		} while (isdigit(*s));
5633e12c5d1SDavid du Colombier 		if (s - es > 2)
5643e12c5d1SDavid du Colombier 			return(0);
5653e12c5d1SDavid du Colombier 		else if (s - es == 2 && (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON)
5663e12c5d1SDavid du Colombier 			return(0);
5673e12c5d1SDavid du Colombier 	}
5683e12c5d1SDavid du Colombier 	while (*s == ' ' || *s == '\t' || *s == '\n')
5693e12c5d1SDavid du Colombier 		s++;
5703e12c5d1SDavid du Colombier 	if (*s == '\0')
5713e12c5d1SDavid du Colombier 		return(1);
5723e12c5d1SDavid du Colombier 	else
5733e12c5d1SDavid du Colombier 		return(0);
5743e12c5d1SDavid du Colombier }
575