xref: /csrg-svn/contrib/awk.research/lib.c (revision 65390)
1*65390Sbostic /****************************************************************
2*65390Sbostic Copyright (C) AT&T 1993
3*65390Sbostic All Rights Reserved
4*65390Sbostic 
5*65390Sbostic Permission to use, copy, modify, and distribute this software and
6*65390Sbostic its documentation for any purpose and without fee is hereby
7*65390Sbostic granted, provided that the above copyright notice appear in all
8*65390Sbostic copies and that both that the copyright notice and this
9*65390Sbostic permission notice and warranty disclaimer appear in supporting
10*65390Sbostic documentation, and that the name of AT&T or any of its entities
11*65390Sbostic not be used in advertising or publicity pertaining to
12*65390Sbostic distribution of the software without specific, written prior
13*65390Sbostic permission.
14*65390Sbostic 
15*65390Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16*65390Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17*65390Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18*65390Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19*65390Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20*65390Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21*65390Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22*65390Sbostic THIS SOFTWARE.
23*65390Sbostic ****************************************************************/
24*65390Sbostic 
25*65390Sbostic #define DEBUG
26*65390Sbostic #include <stdio.h>
27*65390Sbostic #include <string.h>
28*65390Sbostic #include <ctype.h>
29*65390Sbostic #include <errno.h>
30*65390Sbostic #include <stdlib.h>
31*65390Sbostic #include "awk.h"
32*65390Sbostic #include "y.tab.h"
33*65390Sbostic 
34*65390Sbostic #define	getfval(p)	(((p)->tval & (ARR|FLD|REC|NUM)) == NUM ? (p)->fval : r_getfval(p))
35*65390Sbostic #define	getsval(p)	(((p)->tval & (ARR|FLD|REC|STR)) == STR ? (p)->sval : r_getsval(p))
36*65390Sbostic 
37*65390Sbostic FILE	*infile	= NULL;
38*65390Sbostic uchar	*file	= (uchar*) "";
39*65390Sbostic int	recsize	= RECSIZE;
40*65390Sbostic uchar	*recdata;
41*65390Sbostic uchar	*record;
42*65390Sbostic uchar	*fields;
43*65390Sbostic Cell	*fldtab;
44*65390Sbostic 
45*65390Sbostic #define	MAXFLD	200
46*65390Sbostic int	nfields	= MAXFLD;	/* can be set from commandline in main */
47*65390Sbostic 
48*65390Sbostic int	donefld;	/* 1 = implies rec broken into fields */
49*65390Sbostic int	donerec;	/* 1 = record is valid (no flds have changed) */
50*65390Sbostic 
51*65390Sbostic int	maxfld	= 0;	/* last used field */
52*65390Sbostic int	argno	= 1;	/* current input argument number */
53*65390Sbostic extern	Awkfloat *ARGC;
54*65390Sbostic 
55*65390Sbostic void recinit(unsigned int n)
56*65390Sbostic {
57*65390Sbostic 	static Cell dollar0 = {
58*65390Sbostic 	    OCELL, CFLD, (uchar*) "$0", /*recdata*/0, 0.0, REC|STR|DONTFREE };
59*65390Sbostic 	static Cell dollar1 = {
60*65390Sbostic 	    OCELL, CFLD, NULL, (uchar*) "", 0.0, FLD|STR|DONTFREE };
61*65390Sbostic 	int i;
62*65390Sbostic 
63*65390Sbostic 	record = recdata = (uchar *) malloc(n);
64*65390Sbostic 	fields = (uchar *) malloc(n);
65*65390Sbostic 	fldtab = (Cell *) malloc(nfields * sizeof(Cell));
66*65390Sbostic 	if (recdata == NULL || fields == NULL || fldtab == NULL)
67*65390Sbostic 		ERROR "out of space for $0 and fields" FATAL;
68*65390Sbostic 	fldtab[0] = dollar0;
69*65390Sbostic 	fldtab[0].sval = recdata;
70*65390Sbostic 	for (i = 1; i < nfields; i++)
71*65390Sbostic 		fldtab[i] = dollar1;
72*65390Sbostic }
73*65390Sbostic 
74*65390Sbostic void initgetrec(void)
75*65390Sbostic {
76*65390Sbostic 	int i;
77*65390Sbostic 	uchar *p;
78*65390Sbostic 
79*65390Sbostic 	for (i = 1; i < *ARGC; i++) {
80*65390Sbostic 		if (!isclvar(p = getargv(i))) {	/* find 1st real filename */
81*65390Sbostic 			setsval(lookup("FILENAME", symtab), getargv(i));
82*65390Sbostic 			return;
83*65390Sbostic 		}
84*65390Sbostic 		setclvar(p);	/* a commandline assignment before filename */
85*65390Sbostic 		argno++;
86*65390Sbostic 	}
87*65390Sbostic 	infile = stdin;		/* no filenames, so use stdin */
88*65390Sbostic }
89*65390Sbostic 
90*65390Sbostic getrec(uchar *buf)	/* get next input record from whatever source */
91*65390Sbostic {			/* note: tests whether buf == record */
92*65390Sbostic 	int c;
93*65390Sbostic 	static int firsttime = 1;
94*65390Sbostic 
95*65390Sbostic 	if (firsttime) {
96*65390Sbostic 		firsttime = 0;
97*65390Sbostic 		initgetrec();
98*65390Sbostic 	}
99*65390Sbostic 	dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
100*65390Sbostic 		*RS, *FS, *ARGC, *FILENAME) );
101*65390Sbostic 	donefld = 0;
102*65390Sbostic 	donerec = 1;
103*65390Sbostic 	buf[0] = 0;
104*65390Sbostic 	while (argno < *ARGC || infile == stdin) {
105*65390Sbostic 		dprintf( ("argno=%d, file=|%s|\n", argno, file) );
106*65390Sbostic 		if (infile == NULL) {	/* have to open a new file */
107*65390Sbostic 			file = getargv(argno);
108*65390Sbostic 			if (*file == '\0') {	/* it's been zapped */
109*65390Sbostic 				argno++;
110*65390Sbostic 				continue;
111*65390Sbostic 			}
112*65390Sbostic 			if (isclvar(file)) {	/* a var=value arg */
113*65390Sbostic 				setclvar(file);
114*65390Sbostic 				argno++;
115*65390Sbostic 				continue;
116*65390Sbostic 			}
117*65390Sbostic 			*FILENAME = file;
118*65390Sbostic 			dprintf( ("opening file %s\n", file) );
119*65390Sbostic 			if (*file == '-' && *(file+1) == '\0')
120*65390Sbostic 				infile = stdin;
121*65390Sbostic 			else if ((infile = fopen((char *)file, "r")) == NULL)
122*65390Sbostic 				ERROR "can't open file %s", file FATAL;
123*65390Sbostic 			setfval(fnrloc, 0.0);
124*65390Sbostic 		}
125*65390Sbostic 		c = readrec(buf, recsize, infile);
126*65390Sbostic 		if (c != 0 || buf[0] != '\0') {	/* normal record */
127*65390Sbostic 			if (buf == record) {
128*65390Sbostic 				if (!(recloc->tval & DONTFREE))
129*65390Sbostic 					xfree(recloc->sval);
130*65390Sbostic 				recloc->sval = record;
131*65390Sbostic 				recloc->tval = REC | STR | DONTFREE;
132*65390Sbostic 				if (isnumber(recloc->sval)) {
133*65390Sbostic 					recloc->fval = atof(recloc->sval);
134*65390Sbostic 					recloc->tval |= NUM;
135*65390Sbostic 				}
136*65390Sbostic 			}
137*65390Sbostic 			setfval(nrloc, nrloc->fval+1);
138*65390Sbostic 			setfval(fnrloc, fnrloc->fval+1);
139*65390Sbostic 			return 1;
140*65390Sbostic 		}
141*65390Sbostic 		/* EOF arrived on this file; set up next */
142*65390Sbostic 		if (infile != stdin)
143*65390Sbostic 			fclose(infile);
144*65390Sbostic 		infile = NULL;
145*65390Sbostic 		argno++;
146*65390Sbostic 	}
147*65390Sbostic 	return 0;	/* true end of file */
148*65390Sbostic }
149*65390Sbostic 
150*65390Sbostic readrec(uchar *buf, int bufsize, FILE *inf)	/* read one record into buf */
151*65390Sbostic {
152*65390Sbostic 	register int sep, c;
153*65390Sbostic 	register uchar *rr;
154*65390Sbostic 	register int nrr;
155*65390Sbostic 
156*65390Sbostic 	if ((sep = **RS) == 0) {
157*65390Sbostic 		sep = '\n';
158*65390Sbostic 		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
159*65390Sbostic 			;
160*65390Sbostic 		if (c != EOF)
161*65390Sbostic 			ungetc(c, inf);
162*65390Sbostic 	}
163*65390Sbostic 	for (rr = buf, nrr = bufsize; ; ) {
164*65390Sbostic 		for (; (c=getc(inf)) != sep && c != EOF; *rr++ = c)
165*65390Sbostic 			if (--nrr < 0)
166*65390Sbostic 				ERROR "input record `%.30s...' too long; try -mr n", buf FATAL;
167*65390Sbostic 		if (**RS == sep || c == EOF)
168*65390Sbostic 			break;
169*65390Sbostic 		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
170*65390Sbostic 			break;
171*65390Sbostic 		*rr++ = '\n';
172*65390Sbostic 		*rr++ = c;
173*65390Sbostic 	}
174*65390Sbostic 	if (rr > buf + bufsize)
175*65390Sbostic 		ERROR "input record `%.30s...' too long; try -mr n", buf FATAL;
176*65390Sbostic 	*rr = 0;
177*65390Sbostic 	dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
178*65390Sbostic 	return c == EOF && rr == buf ? 0 : 1;
179*65390Sbostic }
180*65390Sbostic 
181*65390Sbostic uchar *getargv(int n)	/* get ARGV[n] */
182*65390Sbostic {
183*65390Sbostic 	Cell *x;
184*65390Sbostic 	uchar *s, temp[10];
185*65390Sbostic 	extern Array *ARGVtab;
186*65390Sbostic 
187*65390Sbostic 	sprintf((char *)temp, "%d", n);
188*65390Sbostic 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
189*65390Sbostic 	s = getsval(x);
190*65390Sbostic 	dprintf( ("getargv(%d) returns |%s|\n", n, s) );
191*65390Sbostic 	return s;
192*65390Sbostic }
193*65390Sbostic 
194*65390Sbostic void setclvar(uchar *s)	/* set var=value from s */
195*65390Sbostic {
196*65390Sbostic 	uchar *p;
197*65390Sbostic 	Cell *q;
198*65390Sbostic 
199*65390Sbostic 	for (p=s; *p != '='; p++)
200*65390Sbostic 		;
201*65390Sbostic 	*p++ = 0;
202*65390Sbostic 	p = qstring(p, '\0');
203*65390Sbostic 	q = setsymtab(s, p, 0.0, STR, symtab);
204*65390Sbostic 	setsval(q, p);
205*65390Sbostic 	if (isnumber(q->sval)) {
206*65390Sbostic 		q->fval = atof(q->sval);
207*65390Sbostic 		q->tval |= NUM;
208*65390Sbostic 	}
209*65390Sbostic 	dprintf( ("command line set %s to |%s|\n", s, p) );
210*65390Sbostic }
211*65390Sbostic 
212*65390Sbostic 
213*65390Sbostic void fldbld(void)	/* create fields from current record */
214*65390Sbostic {
215*65390Sbostic 	register uchar *r, *fr, sep;
216*65390Sbostic 	Cell *p;
217*65390Sbostic 	int i;
218*65390Sbostic 
219*65390Sbostic 	if (donefld)
220*65390Sbostic 		return;
221*65390Sbostic 	if (!(recloc->tval & STR))
222*65390Sbostic 		getsval(recloc);
223*65390Sbostic 	r = recloc->sval;
224*65390Sbostic 	fr = fields;
225*65390Sbostic 	i = 0;	/* number of fields accumulated here */
226*65390Sbostic 	if (strlen(*FS) > 1) {	/* it's a regular expression */
227*65390Sbostic 		i = refldbld(r, *FS);
228*65390Sbostic 	} else if ((sep = **FS) == ' ') {	/* default whitespace */
229*65390Sbostic 		for (i = 0; ; ) {
230*65390Sbostic 			while (*r == ' ' || *r == '\t' || *r == '\n')
231*65390Sbostic 				r++;
232*65390Sbostic 			if (*r == 0)
233*65390Sbostic 				break;
234*65390Sbostic 			i++;
235*65390Sbostic 			if (i >= nfields)
236*65390Sbostic 				break;
237*65390Sbostic 			if (!(fldtab[i].tval & DONTFREE))
238*65390Sbostic 				xfree(fldtab[i].sval);
239*65390Sbostic 			fldtab[i].sval = fr;
240*65390Sbostic 			fldtab[i].tval = FLD | STR | DONTFREE;
241*65390Sbostic 			do
242*65390Sbostic 				*fr++ = *r++;
243*65390Sbostic 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
244*65390Sbostic 			*fr++ = 0;
245*65390Sbostic 		}
246*65390Sbostic 		*fr = 0;
247*65390Sbostic 	} else if (*r != 0) {	/* if 0, it's a null field */
248*65390Sbostic 		for (;;) {
249*65390Sbostic 			i++;
250*65390Sbostic 			if (i >= nfields)
251*65390Sbostic 				break;
252*65390Sbostic 			if (!(fldtab[i].tval & DONTFREE))
253*65390Sbostic 				xfree(fldtab[i].sval);
254*65390Sbostic 			fldtab[i].sval = fr;
255*65390Sbostic 			fldtab[i].tval = FLD | STR | DONTFREE;
256*65390Sbostic 			while (*r != sep && *r != '\n' && *r != '\0')	/* \n is always a separator */
257*65390Sbostic 				*fr++ = *r++;
258*65390Sbostic 			*fr++ = 0;
259*65390Sbostic 			if (*r++ == 0)
260*65390Sbostic 				break;
261*65390Sbostic 		}
262*65390Sbostic 		*fr = 0;
263*65390Sbostic 	}
264*65390Sbostic 	if (i >= nfields)
265*65390Sbostic 		ERROR "record `%.30s...' has too many fields; try -mf n", record FATAL;
266*65390Sbostic 	/* clean out junk from previous record */
267*65390Sbostic 	cleanfld(i, maxfld);
268*65390Sbostic 	maxfld = i;
269*65390Sbostic 	donefld = 1;
270*65390Sbostic 	for (p = fldtab+1; p <= fldtab+maxfld; p++) {
271*65390Sbostic 		if(isnumber(p->sval)) {
272*65390Sbostic 			p->fval = atof(p->sval);
273*65390Sbostic 			p->tval |= NUM;
274*65390Sbostic 		}
275*65390Sbostic 	}
276*65390Sbostic 	setfval(nfloc, (Awkfloat) maxfld);
277*65390Sbostic 	if (dbg)
278*65390Sbostic 		for (p = fldtab; p <= fldtab+maxfld; p++)
279*65390Sbostic 			printf("field %d: |%s|\n", p-fldtab, p->sval);
280*65390Sbostic }
281*65390Sbostic 
282*65390Sbostic void cleanfld(int n1, int n2)	/* clean out fields n1..n2 inclusive */
283*65390Sbostic {
284*65390Sbostic 	static uchar *nullstat = (uchar *) "";
285*65390Sbostic 	register Cell *p, *q;
286*65390Sbostic 
287*65390Sbostic 	for (p = &fldtab[n2], q = &fldtab[n1]; p > q; p--) {
288*65390Sbostic 		if (!(p->tval & DONTFREE))
289*65390Sbostic 			xfree(p->sval);
290*65390Sbostic 		p->tval = FLD | STR | DONTFREE;
291*65390Sbostic 		p->sval = nullstat;
292*65390Sbostic 	}
293*65390Sbostic }
294*65390Sbostic 
295*65390Sbostic void newfld(int n)	/* add field n (after end) */
296*65390Sbostic {
297*65390Sbostic 	if (n >= nfields)
298*65390Sbostic 		ERROR "creating too many fields (%d); try -mf n", n, record FATAL;
299*65390Sbostic 	cleanfld(maxfld, n);
300*65390Sbostic 	maxfld = n;
301*65390Sbostic 	setfval(nfloc, (Awkfloat) n);
302*65390Sbostic }
303*65390Sbostic 
304*65390Sbostic refldbld(uchar *rec, uchar *fs)	/* build fields from reg expr in FS */
305*65390Sbostic {
306*65390Sbostic 	uchar *fr;
307*65390Sbostic 	int i, tempstat;
308*65390Sbostic 	fa *pfa;
309*65390Sbostic 
310*65390Sbostic 	fr = fields;
311*65390Sbostic 	*fr = '\0';
312*65390Sbostic 	if (*rec == '\0')
313*65390Sbostic 		return 0;
314*65390Sbostic 	pfa = makedfa(fs, 1);
315*65390Sbostic 	dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
316*65390Sbostic 	tempstat = pfa->initstat;
317*65390Sbostic 	for (i = 1; i < nfields; i++) {
318*65390Sbostic 		if (!(fldtab[i].tval & DONTFREE))
319*65390Sbostic 			xfree(fldtab[i].sval);
320*65390Sbostic 		fldtab[i].tval = FLD | STR | DONTFREE;
321*65390Sbostic 		fldtab[i].sval = fr;
322*65390Sbostic 		dprintf( ("refldbld: i=%d\n", i) );
323*65390Sbostic 		if (nematch(pfa, rec)) {
324*65390Sbostic 			pfa->initstat = 2;	/* horrible coupling */
325*65390Sbostic 			dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
326*65390Sbostic 			strncpy(fr, rec, patbeg-rec);
327*65390Sbostic 			fr += patbeg - rec + 1;
328*65390Sbostic 			*(fr-1) = '\0';
329*65390Sbostic 			rec = patbeg + patlen;
330*65390Sbostic 		} else {
331*65390Sbostic 			dprintf( ("no match %s\n", rec) );
332*65390Sbostic 			strcpy(fr, rec);
333*65390Sbostic 			pfa->initstat = tempstat;
334*65390Sbostic 			break;
335*65390Sbostic 		}
336*65390Sbostic 	}
337*65390Sbostic 	return i;
338*65390Sbostic }
339*65390Sbostic 
340*65390Sbostic void recbld(void)	/* create $0 from $1..$NF if necessary */
341*65390Sbostic {
342*65390Sbostic 	register int i;
343*65390Sbostic 	register uchar *r, *p;
344*65390Sbostic 	static uchar *rec = 0;
345*65390Sbostic 
346*65390Sbostic 	if (donerec == 1)
347*65390Sbostic 		return;
348*65390Sbostic 	if (rec == 0) {
349*65390Sbostic 		rec = (uchar *) malloc(recsize);
350*65390Sbostic 		if (rec == 0)
351*65390Sbostic 			ERROR "out of space building $0, record size %d", recsize FATAL;
352*65390Sbostic 	}
353*65390Sbostic 	r = rec;
354*65390Sbostic 	for (i = 1; i <= *NF; i++) {
355*65390Sbostic 		p = getsval(&fldtab[i]);
356*65390Sbostic 		while (r < rec+recsize-1 && (*r = *p++))
357*65390Sbostic 			r++;
358*65390Sbostic 		if (i < *NF)
359*65390Sbostic 			for (p = *OFS; r < rec+recsize-1 && (*r = *p++); )
360*65390Sbostic 				r++;
361*65390Sbostic 	}
362*65390Sbostic 	if (r > rec + recsize - 1)
363*65390Sbostic 		ERROR "built giant record `%.30s...'; try -mr n", record FATAL;
364*65390Sbostic 	*r = '\0';
365*65390Sbostic 	dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
366*65390Sbostic 	recloc->tval = REC | STR | DONTFREE;
367*65390Sbostic 	recloc->sval = record = rec;
368*65390Sbostic 	dprintf( ("in recbld FS=%o, recloc=%o\n", **FS, recloc) );
369*65390Sbostic 	dprintf( ("recbld = |%s|\n", record) );
370*65390Sbostic 	donerec = 1;
371*65390Sbostic }
372*65390Sbostic 
373*65390Sbostic Cell *fieldadr(int n)
374*65390Sbostic {
375*65390Sbostic 	if (n < 0 || n >= nfields)
376*65390Sbostic 		ERROR "trying to access field %d; try -mf n", n FATAL;
377*65390Sbostic 	return(&fldtab[n]);
378*65390Sbostic }
379*65390Sbostic 
380*65390Sbostic int	errorflag	= 0;
381*65390Sbostic char	errbuf[200];
382*65390Sbostic 
383*65390Sbostic void yyerror(uchar *s)
384*65390Sbostic {
385*65390Sbostic 	extern uchar *cmdname, *curfname;
386*65390Sbostic 	static int been_here = 0;
387*65390Sbostic 
388*65390Sbostic 	if (been_here++ > 2)
389*65390Sbostic 		return;
390*65390Sbostic 	fprintf(stderr, "%s: %s", cmdname, s);
391*65390Sbostic 	fprintf(stderr, " at source line %d", lineno);
392*65390Sbostic 	if (curfname != NULL)
393*65390Sbostic 		fprintf(stderr, " in function %s", curfname);
394*65390Sbostic 	fprintf(stderr, "\n");
395*65390Sbostic 	errorflag = 2;
396*65390Sbostic 	eprint();
397*65390Sbostic }
398*65390Sbostic 
399*65390Sbostic void fpecatch(int n)
400*65390Sbostic {
401*65390Sbostic 	ERROR "floating point exception %d", n FATAL;
402*65390Sbostic }
403*65390Sbostic 
404*65390Sbostic extern int bracecnt, brackcnt, parencnt;
405*65390Sbostic 
406*65390Sbostic void bracecheck(void)
407*65390Sbostic {
408*65390Sbostic 	int c;
409*65390Sbostic 	static int beenhere = 0;
410*65390Sbostic 
411*65390Sbostic 	if (beenhere++)
412*65390Sbostic 		return;
413*65390Sbostic 	while ((c = input()) != EOF && c != '\0')
414*65390Sbostic 		bclass(c);
415*65390Sbostic 	bcheck2(bracecnt, '{', '}');
416*65390Sbostic 	bcheck2(brackcnt, '[', ']');
417*65390Sbostic 	bcheck2(parencnt, '(', ')');
418*65390Sbostic }
419*65390Sbostic 
420*65390Sbostic void bcheck2(int n, int c1, int c2)
421*65390Sbostic {
422*65390Sbostic 	if (n == 1)
423*65390Sbostic 		fprintf(stderr, "\tmissing %c\n", c2);
424*65390Sbostic 	else if (n > 1)
425*65390Sbostic 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
426*65390Sbostic 	else if (n == -1)
427*65390Sbostic 		fprintf(stderr, "\textra %c\n", c2);
428*65390Sbostic 	else if (n < -1)
429*65390Sbostic 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
430*65390Sbostic }
431*65390Sbostic 
432*65390Sbostic void error(int f, char *s)
433*65390Sbostic {
434*65390Sbostic 	extern Node *curnode;
435*65390Sbostic 	extern uchar *cmdname;
436*65390Sbostic 
437*65390Sbostic 	fflush(stdout);
438*65390Sbostic 	fprintf(stderr, "%s: ", cmdname);
439*65390Sbostic 	fprintf(stderr, "%s", s);
440*65390Sbostic 	fprintf(stderr, "\n");
441*65390Sbostic 	if (compile_time != 2 && NR && *NR > 0) {
442*65390Sbostic 		fprintf(stderr, " input record number %g", *FNR);
443*65390Sbostic 		if (strcmp(*FILENAME, "-") != 0)
444*65390Sbostic 			fprintf(stderr, ", file %s", *FILENAME);
445*65390Sbostic 		fprintf(stderr, "\n");
446*65390Sbostic 	}
447*65390Sbostic 	if (compile_time != 2 && curnode)
448*65390Sbostic 		fprintf(stderr, " source line number %d\n", curnode->lineno);
449*65390Sbostic 	else if (compile_time != 2 && lineno)
450*65390Sbostic 		fprintf(stderr, " source line number %d\n", lineno);
451*65390Sbostic 	eprint();
452*65390Sbostic 	if (f) {
453*65390Sbostic 		if (dbg > 1)		/* core dump if serious debugging on */
454*65390Sbostic 			abort();
455*65390Sbostic 		exit(2);
456*65390Sbostic 	}
457*65390Sbostic }
458*65390Sbostic 
459*65390Sbostic void eprint(void)	/* try to print context around error */
460*65390Sbostic {
461*65390Sbostic 	uchar *p, *q;
462*65390Sbostic 	int c;
463*65390Sbostic 	static int been_here = 0;
464*65390Sbostic 	extern uchar ebuf[], *ep;
465*65390Sbostic 
466*65390Sbostic 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
467*65390Sbostic 		return;
468*65390Sbostic 	p = ep - 1;
469*65390Sbostic 	if (p > ebuf && *p == '\n')
470*65390Sbostic 		p--;
471*65390Sbostic 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
472*65390Sbostic 		;
473*65390Sbostic 	while (*p == '\n')
474*65390Sbostic 		p++;
475*65390Sbostic 	fprintf(stderr, " context is\n\t");
476*65390Sbostic 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
477*65390Sbostic 		;
478*65390Sbostic 	for ( ; p < q; p++)
479*65390Sbostic 		if (*p)
480*65390Sbostic 			putc(*p, stderr);
481*65390Sbostic 	fprintf(stderr, " >>> ");
482*65390Sbostic 	for ( ; p < ep; p++)
483*65390Sbostic 		if (*p)
484*65390Sbostic 			putc(*p, stderr);
485*65390Sbostic 	fprintf(stderr, " <<< ");
486*65390Sbostic 	if (*ep)
487*65390Sbostic 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
488*65390Sbostic 			putc(c, stderr);
489*65390Sbostic 			bclass(c);
490*65390Sbostic 		}
491*65390Sbostic 	putc('\n', stderr);
492*65390Sbostic 	ep = ebuf;
493*65390Sbostic }
494*65390Sbostic 
495*65390Sbostic void bclass(int c)
496*65390Sbostic {
497*65390Sbostic 	switch (c) {
498*65390Sbostic 	case '{': bracecnt++; break;
499*65390Sbostic 	case '}': bracecnt--; break;
500*65390Sbostic 	case '[': brackcnt++; break;
501*65390Sbostic 	case ']': brackcnt--; break;
502*65390Sbostic 	case '(': parencnt++; break;
503*65390Sbostic 	case ')': parencnt--; break;
504*65390Sbostic 	}
505*65390Sbostic }
506*65390Sbostic 
507*65390Sbostic double errcheck(double x, uchar *s)
508*65390Sbostic {
509*65390Sbostic 	extern int errno;
510*65390Sbostic 
511*65390Sbostic 	if (errno == EDOM) {
512*65390Sbostic 		errno = 0;
513*65390Sbostic 		ERROR "%s argument out of domain", s WARNING;
514*65390Sbostic 		x = 1;
515*65390Sbostic 	} else if (errno == ERANGE) {
516*65390Sbostic 		errno = 0;
517*65390Sbostic 		ERROR "%s result out of range", s WARNING;
518*65390Sbostic 		x = 1;
519*65390Sbostic 	}
520*65390Sbostic 	return x;
521*65390Sbostic }
522*65390Sbostic 
523*65390Sbostic isclvar(uchar *s)	/* is s of form var=something ? */
524*65390Sbostic {
525*65390Sbostic 	uchar *os = s;
526*65390Sbostic 
527*65390Sbostic 	if (!isalpha(*s) && *s != '_')
528*65390Sbostic 		return 0;
529*65390Sbostic 	for ( ; *s; s++)
530*65390Sbostic 		if (!(isalnum(*s) || *s == '_'))
531*65390Sbostic 			break;
532*65390Sbostic 	return *s == '=' && s > os && *(s+1) != '=';
533*65390Sbostic }
534*65390Sbostic 
535*65390Sbostic #define	MAXEXPON	38	/* maximum exponent for fp number. should be IEEE */
536*65390Sbostic 
537*65390Sbostic isnumber(uchar *s)	/* probably should be done by a library function */
538*65390Sbostic {
539*65390Sbostic 	register int d1, d2;
540*65390Sbostic 	int point;
541*65390Sbostic 	uchar *es;
542*65390Sbostic 
543*65390Sbostic 	d1 = d2 = point = 0;
544*65390Sbostic 	while (*s == ' ' || *s == '\t' || *s == '\n')
545*65390Sbostic 		s++;
546*65390Sbostic 	if (*s == '\0')
547*65390Sbostic 		return(0);	/* empty stuff isn't number */
548*65390Sbostic 	if (*s == '+' || *s == '-')
549*65390Sbostic 		s++;
550*65390Sbostic 	if (!isdigit(*s) && *s != '.')
551*65390Sbostic 		return(0);
552*65390Sbostic 	if (isdigit(*s)) {
553*65390Sbostic 		do {
554*65390Sbostic 			d1++;
555*65390Sbostic 			s++;
556*65390Sbostic 		} while (isdigit(*s));
557*65390Sbostic 	}
558*65390Sbostic 	if (*s == '.') {
559*65390Sbostic 		point++;
560*65390Sbostic 		s++;
561*65390Sbostic 	}
562*65390Sbostic 	if (isdigit(*s)) {
563*65390Sbostic 		d2++;
564*65390Sbostic 		do {
565*65390Sbostic 			s++;
566*65390Sbostic 		} while (isdigit(*s));
567*65390Sbostic 	}
568*65390Sbostic 	if (!(d1 || point && d2))
569*65390Sbostic 		return(0);
570*65390Sbostic 	if (*s == 'e' || *s == 'E') {
571*65390Sbostic 		s++;
572*65390Sbostic 		if (*s == '+' || *s == '-')
573*65390Sbostic 			s++;
574*65390Sbostic 		if (!isdigit(*s))
575*65390Sbostic 			return(0);
576*65390Sbostic 		es = s;
577*65390Sbostic 		do {
578*65390Sbostic 			s++;
579*65390Sbostic 		} while (isdigit(*s));
580*65390Sbostic 		if (s - es > 2)
581*65390Sbostic 			return(0);
582*65390Sbostic 		else if (s - es == 2 && (int)(10 * (*es-'0') + *(es+1)-'0') >= MAXEXPON)
583*65390Sbostic 			return(0);
584*65390Sbostic 	}
585*65390Sbostic 	while (*s == ' ' || *s == '\t' || *s == '\n')
586*65390Sbostic 		s++;
587*65390Sbostic 	if (*s == '\0')
588*65390Sbostic 		return(1);
589*65390Sbostic 	else
590*65390Sbostic 		return(0);
591*65390Sbostic }
592