1 /****************************************************************
2 Copyright (C) Lucent Technologies 1997
3 All Rights Reserved
4 
5 Permission to use, copy, modify, and distribute this software and
6 its documentation for any purpose and without fee is hereby
7 granted, provided that the above copyright notice appear in all
8 copies and that both that the copyright notice and this
9 permission notice and warranty disclaimer appear in supporting
10 documentation, and that the name Lucent Technologies or any of
11 its entities not be used in advertising or publicity pertaining
12 to distribution of the software without specific, written prior
13 permission.
14 
15 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 THIS SOFTWARE.
23 ****************************************************************/
24 
25 #if HAVE_NBTOOL_CONFIG_H
26 #include "nbtool_config.h"
27 #endif
28 
29 #define DEBUG
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include "awk.h"
37 #include "awkgram.h"
38 
39 char	EMPTY[] = { '\0' };
40 FILE	*infile	= NULL;
41 int	innew;		/* 1 = infile has not been read by readrec */
42 char	*file	= EMPTY;
43 uschar	*record;
44 int	recsize	= RECSIZE;
45 char	*fields;
46 int	fieldssize = RECSIZE;
47 
48 Cell	**fldtab;	/* pointers to Cells */
49 
50 static size_t	len_inputFS = 0;
51 static char	*inputFS = NULL;
52 
53 #define	MAXFLD	2
54 int	nfields	= MAXFLD;	/* last allocated slot for $i */
55 
56 int	donefld;	/* 1 = implies rec broken into fields */
57 int	donerec;	/* 1 = record is valid (no flds have changed) */
58 
59 int	lastfld	= 0;	/* last used field */
60 int	argno	= 1;	/* current input argument number */
61 extern	Awkfloat *ARGC;
62 
63 static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL };
64 static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL };
65 
recinit(unsigned int n)66 void recinit(unsigned int n)
67 {
68 	if ( (record = malloc(n)) == NULL
69 	  || (fields = malloc(n+1)) == NULL
70 	  || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL
71 	  || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL )
72 		FATAL("out of space for $0 and fields");
73 	*fldtab[0] = dollar0;
74 	fldtab[0]->sval = record;
75 	fldtab[0]->nval = tostring("0");
76 	makefields(1, nfields);
77 }
78 
makefields(int n1,int n2)79 void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
80 {
81 	char temp[50];
82 	int i;
83 
84 	for (i = n1; i <= n2; i++) {
85 		fldtab[i] = malloc(sizeof(**fldtab));
86 		if (fldtab[i] == NULL)
87 			FATAL("out of space in makefields %d", i);
88 		*fldtab[i] = dollar1;
89 		snprintf(temp, sizeof(temp), "%d", i);
90 		fldtab[i]->nval = tostring(temp);
91 	}
92 }
93 
initgetrec(void)94 void initgetrec(void)
95 {
96 	int i;
97 	char *p;
98 
99 	for (i = 1; i < *ARGC; i++) {
100 		p = getargv(i); /* find 1st real filename */
101 		if (p == NULL || *p == '\0') {  /* deleted or zapped */
102 			argno++;
103 			continue;
104 		}
105 		if (!isclvar(p)) {
106 			setsval(lookup("FILENAME", symtab), p);
107 			return;
108 		}
109 		setclvar(p);	/* a commandline assignment before filename */
110 		argno++;
111 	}
112 	infile = stdin;		/* no filenames, so use stdin */
113 	innew = 1;
114 }
115 
116 static int firsttime = 1;
117 
getrec(uschar ** pbuf,int * pbufsize,int isrecord)118 int getrec(uschar **pbuf, int *pbufsize, int isrecord)	/* get next input record */
119 {			/* note: cares whether buf == record */
120 	int c;
121 	uschar *buf = *pbuf;
122 	uschar saveb0;
123 	int bufsize = *pbufsize, savebufsize = bufsize;
124 
125 	if (firsttime) {
126 		firsttime = 0;
127 		initgetrec();
128 	}
129 	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
130 		*RS, *FS, *ARGC, *FILENAME) );
131 	if (isrecord) {
132 		donefld = 0;
133 		donerec = 1;
134 	}
135 	saveb0 = buf[0];
136 	buf[0] = 0;
137 	while (argno < *ARGC || infile == stdin) {
138 		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
139 		if (infile == NULL) {	/* have to open a new file */
140 			file = getargv(argno);
141 			if (file == NULL || *file == '\0') {	/* deleted or zapped */
142 				argno++;
143 				continue;
144 			}
145 			if (isclvar(file)) {	/* a var=value arg */
146 				setclvar(file);
147 				argno++;
148 				continue;
149 			}
150 			*FILENAME = file;
151 			   dprintf( ("opening file %s\n", file) );
152 			if (*file == '-' && *(file+1) == '\0')
153 				infile = stdin;
154 			else if ((infile = fopen(file, "r")) == NULL)
155 				FATAL("can't open file %s", file);
156 			innew = 1;
157 			setfval(fnrloc, 0.0);
158 		}
159 		c = readrec(&buf, &bufsize, infile, innew);
160 		if (innew)
161 			innew = 0;
162 		if (c != 0 || buf[0] != '\0') {	/* normal record */
163 			if (isrecord) {
164 				if (freeable(fldtab[0]))
165 					xfree(fldtab[0]->sval);
166 				fldtab[0]->sval = buf;	/* buf == record */
167 				fldtab[0]->tval = REC | STR | DONTFREE;
168 				if (is_number(fldtab[0]->sval)) {
169 					fldtab[0]->fval = atof(fldtab[0]->sval);
170 					fldtab[0]->tval |= NUM;
171 				}
172 			}
173 			setfval(nrloc, nrloc->fval+1);
174 			setfval(fnrloc, fnrloc->fval+1);
175 			*pbuf = buf;
176 			*pbufsize = bufsize;
177 			return 1;
178 		}
179 		/* EOF arrived on this file; set up next */
180 		if (infile != stdin)
181 			fclose(infile);
182 		infile = NULL;
183 		argno++;
184 	}
185 	buf[0] = saveb0;
186 	*pbuf = buf;
187 	*pbufsize = savebufsize;
188 	return 0;	/* true end of file */
189 }
190 
nextfile(void)191 void nextfile(void)
192 {
193 	if (infile != NULL && infile != stdin)
194 		fclose(infile);
195 	infile = NULL;
196 	argno++;
197 }
198 
readrec(uschar ** pbuf,int * pbufsize,FILE * inf,int newflag)199 int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag)	/* read one record into buf */
200 {
201 	int sep, c, isrec, found, tempstat;
202 	uschar *rr, *buf = *pbuf;
203 	int bufsize = *pbufsize;
204 	size_t len;
205 
206 	if ((len = strlen(*FS)) < len_inputFS) {
207 		strcpy(inputFS, *FS);	/* for subsequent field splitting */
208 	} else {
209 		len_inputFS = len + 1;
210 		inputFS = realloc(inputFS, len_inputFS);
211 		if (inputFS == NULL)
212 			FATAL("field separator %.10s... is too long", *FS);
213 		memcpy(inputFS, *FS, len_inputFS);
214 	}
215 	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
216 	if (**RS && (*RS)[1]) {
217 		fa *pfa = makedfa(*RS, 1);
218 		if (newflag)
219 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
220 		else {
221 			tempstat = pfa->initstat;
222 			pfa->initstat = 2;
223 			found = fnematch(pfa, inf, &buf, &bufsize, recsize);
224 			pfa->initstat = tempstat;
225 		}
226 		if (found)
227 			*patbeg = 0;
228 	} else {
229 		if ((sep = **RS) == 0) {
230 			sep = '\n';
231 			while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
232 				;
233 			if (c != EOF)
234 				ungetc(c, inf);
235 		}
236 		for (rr = buf; ; ) {
237 			for (; (c=getc(inf)) != sep && c != EOF; ) {
238 				if (rr-buf+1 > bufsize)
239 					if (!adjbuf(&buf, &bufsize, 1+rr-buf,
240 					    recsize, &rr, "readrec 1"))
241 						FATAL("input record `%.30s...'"
242 						    " too long", buf);
243 				*rr++ = c;
244 			}
245 			if (**RS == sep || c == EOF)
246 				break;
247 			if ((c = getc(inf)) == '\n' || c == EOF)
248 				/* 2 in a row */
249 				break;
250 			if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
251 			    "readrec 2"))
252 				FATAL("input record `%.30s...' too long", buf);
253 			*rr++ = '\n';
254 			*rr++ = c;
255 		}
256 		if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
257 			FATAL("input record `%.30s...' too long", buf);
258 		*rr = 0;
259 	}
260 	*pbuf = buf;
261 	*pbufsize = bufsize;
262 	isrec = *buf || !feof(inf);
263 	   dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
264 	return isrec;
265 }
266 
getargv(int n)267 char *getargv(int n)	/* get ARGV[n] */
268 {
269 	Cell *x;
270 	char *s, temp[50];
271 	extern Array *ARGVtab;
272 
273 	snprintf(temp, sizeof(temp), "%d", n);
274 	if (lookup(temp, ARGVtab) == NULL)
275 		return NULL;
276 	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
277 	s = getsval(x);
278 	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
279 	return s;
280 }
281 
setclvar(char * s)282 void setclvar(char *s)	/* set var=value from s */
283 {
284 	char *p;
285 	Cell *q;
286 
287 	for (p=s; *p != '='; p++)
288 		;
289 	*p++ = 0;
290 	p = qstring(p, '\0');
291 	q = setsymtab(s, p, 0.0, STR, symtab);
292 	setsval(q, p);
293 	if (is_number(q->sval)) {
294 		q->fval = atof(q->sval);
295 		q->tval |= NUM;
296 	}
297 	   dprintf( ("command line set %s to |%s|\n", s, p) );
298 }
299 
300 
fldbld(void)301 void fldbld(void)	/* create fields from current record */
302 {
303 	/* this relies on having fields[] the same length as $0 */
304 	/* the fields are all stored in this one array with \0's */
305 	/* possibly with a final trailing \0 not associated with any field */
306 	char *r, *fr, sep;
307 	Cell *p;
308 	int i, j, n;
309 
310 	if (donefld)
311 		return;
312 	if (!isstr(fldtab[0]))
313 		getsval(fldtab[0]);
314 	r = fldtab[0]->sval;
315 	n = strlen(r);
316 	if (n > fieldssize) {
317 		xfree(fields);
318 		if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */
319 			FATAL("out of space for fields in fldbld %d", n);
320 		fieldssize = n;
321 	}
322 	fr = fields;
323 	i = 0;	/* number of fields accumulated here */
324 	if (!inputFS) {
325 		/* do nothing */
326 	} else if (inputFS[0] && inputFS[1]) {	/* it's a regular expression */
327 		i = refldbld(r, inputFS);
328 	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
329 		for (i = 0; ; ) {
330 			while (*r == ' ' || *r == '\t' || *r == '\n')
331 				r++;
332 			if (*r == 0)
333 				break;
334 			i++;
335 			if (i > nfields)
336 				growfldtab(i);
337 			if (freeable(fldtab[i]))
338 				xfree(fldtab[i]->sval);
339 			fldtab[i]->sval = fr;
340 			fldtab[i]->tval = FLD | STR | DONTFREE;
341 			do
342 				*fr++ = *r++;
343 			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
344 			*fr++ = 0;
345 		}
346 		*fr = 0;
347 	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
348 		for (i = 0; *r != 0; r++) {
349 			char buf[2];
350 			i++;
351 			if (i > nfields)
352 				growfldtab(i);
353 			if (freeable(fldtab[i]))
354 				xfree(fldtab[i]->sval);
355 			buf[0] = *r;
356 			buf[1] = 0;
357 			fldtab[i]->sval = tostring(buf);
358 			fldtab[i]->tval = FLD | STR;
359 		}
360 		*fr = 0;
361 	} else if (*r != 0) {	/* if 0, it's a null field */
362 		/* subtlecase : if length(FS) == 1 && length(RS > 0)
363 		 * \n is NOT a field separator (cf awk book 61,84).
364 		 * this variable is tested in the inner while loop.
365 		 */
366 		int rtest = '\n';  /* normal case */
367 		if (strlen(*RS) > 0)
368 			rtest = '\0';
369 		for (;;) {
370 			i++;
371 			if (i > nfields)
372 				growfldtab(i);
373 			if (freeable(fldtab[i]))
374 				xfree(fldtab[i]->sval);
375 			fldtab[i]->sval = fr;
376 			fldtab[i]->tval = FLD | STR | DONTFREE;
377 			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
378 				*fr++ = *r++;
379 			*fr++ = 0;
380 			if (*r++ == 0)
381 				break;
382 		}
383 		*fr = 0;
384 	}
385 	if (i > nfields)
386 		FATAL("record `%.30s...' has too many fields; can't happen", r);
387 	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
388 	lastfld = i;
389 	donefld = 1;
390 	for (j = 1; j <= lastfld; j++) {
391 		p = fldtab[j];
392 		if(is_number(p->sval)) {
393 			p->fval = atof(p->sval);
394 			p->tval |= NUM;
395 		}
396 	}
397 	setfval(nfloc, (Awkfloat) lastfld);
398 	donerec = 1; /* restore */
399 	if (dbg) {
400 		for (j = 0; j <= lastfld; j++) {
401 			p = fldtab[j];
402 			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
403 		}
404 	}
405 }
406 
cleanfld(int n1,int n2)407 void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
408 {				/* nvals remain intact */
409 	Cell *p;
410 	int i;
411 
412 	for (i = n1; i <= n2; i++) {
413 		p = fldtab[i];
414 		if (freeable(p))
415 			xfree(p->sval);
416 		p->sval = EMPTY;
417 		p->tval = FLD | STR | DONTFREE;
418 	}
419 }
420 
newfld(int n)421 void newfld(int n)	/* add field n after end of existing lastfld */
422 {
423 	if (n > nfields)
424 		growfldtab(n);
425 	cleanfld(lastfld+1, n);
426 	lastfld = n;
427 	setfval(nfloc, (Awkfloat) n);
428 }
429 
setlastfld(int n)430 void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
431 {
432 	if (n > nfields)
433 		growfldtab(n);
434 
435 	if (lastfld < n)
436 	    cleanfld(lastfld+1, n);
437 	else
438 	    cleanfld(n+1, lastfld);
439 
440 	lastfld = n;
441 }
442 
fieldadr(int n)443 Cell *fieldadr(int n)	/* get nth field */
444 {
445 	if (n < 0)
446 		FATAL("trying to access out of range field %d", n);
447 	if (n > nfields)	/* fields after NF are empty */
448 		growfldtab(n);	/* but does not increase NF */
449 	return(fldtab[n]);
450 }
451 
growfldtab(int n)452 void growfldtab(int n)	/* make new fields up to at least $n */
453 {
454 	int nf = 2 * nfields;
455 	size_t s;
456 
457 	if (n > nf)
458 		nf = n;
459 	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
460 	if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
461 		fldtab = realloc(fldtab, s);
462 	else					/* overflow sizeof int */
463 		xfree(fldtab);	/* make it null */
464 	if (fldtab == NULL)
465 		FATAL("out of space creating %d fields", nf);
466 	makefields(nfields+1, nf);
467 	nfields = nf;
468 }
469 
refldbld(const char * rec,const char * fs)470 int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
471 {
472 	/* this relies on having fields[] the same length as $0 */
473 	/* the fields are all stored in this one array with \0's */
474 	char *fr;
475 	int i, tempstat, n;
476 	fa *pfa;
477 
478 	n = strlen(rec);
479 	if (n > fieldssize) {
480 		xfree(fields);
481 		if ((fields = malloc(n+1)) == NULL)
482 			FATAL("out of space for fields in refldbld %d", n);
483 		fieldssize = n;
484 	}
485 	fr = fields;
486 	*fr = '\0';
487 	if (*rec == '\0')
488 		return 0;
489 	pfa = makedfa(fs, 1);
490 	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
491 	tempstat = pfa->initstat;
492 	for (i = 1; ; i++) {
493 		if (i > nfields)
494 			growfldtab(i);
495 		if (freeable(fldtab[i]))
496 			xfree(fldtab[i]->sval);
497 		fldtab[i]->tval = FLD | STR | DONTFREE;
498 		fldtab[i]->sval = fr;
499 		   dprintf( ("refldbld: i=%d\n", i) );
500 		if (nematch(pfa, rec)) {
501 			pfa->initstat = 2;	/* horrible coupling to b.c */
502 			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
503 			strncpy(fr, rec, ((const char*)patbeg)-rec);
504 			fr += ((const char*)patbeg) - rec + 1;
505 			*(fr-1) = '\0';
506 			rec = patbeg + patlen;
507 		} else {
508 			   dprintf( ("no match %s\n", rec) );
509 			strcpy(fr, rec);
510 			pfa->initstat = tempstat;
511 			break;
512 		}
513 	}
514 	return i;
515 }
516 
recbld(void)517 void recbld(void)	/* create $0 from $1..$NF if necessary */
518 {
519 	int i;
520 	uschar *r;
521 	char *p;
522 
523 	if (donerec == 1)
524 		return;
525 	r = record;
526 	for (i = 1; i <= *NF; i++) {
527 		p = getsval(fldtab[i]);
528 		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
529 			FATAL("created $0 `%.30s...' too long", record);
530 		while ((*r = *p++) != 0)
531 			r++;
532 		if (i < *NF) {
533 			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
534 				FATAL("created $0 `%.30s...' too long", record);
535 			for (p = *OFS; (*r = *p++) != 0; )
536 				r++;
537 		}
538 	}
539 	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
540 		FATAL("built giant record `%.30s...'", record);
541 	*r = '\0';
542 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
543 
544 	if (freeable(fldtab[0]))
545 		xfree(fldtab[0]->sval);
546 	fldtab[0]->tval = REC | STR | DONTFREE;
547 	fldtab[0]->sval = record;
548 
549 	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, fldtab[0]) );
550 	   dprintf( ("recbld = |%s|\n", record) );
551 	donerec = 1;
552 }
553 
554 int	errorflag	= 0;
555 
yyerror(const char * s)556 void yyerror(const char *s)
557 {
558 	SYNTAX("%s", s);
559 }
560 
SYNTAX(const char * fmt,...)561 void SYNTAX(const char *fmt, ...)
562 {
563 	extern char *cmdname, *curfname;
564 	static int been_here = 0;
565 	va_list varg;
566 
567 	if (been_here++ > 2)
568 		return;
569 	fprintf(stderr, "%s: ", cmdname);
570 	va_start(varg, fmt);
571 	vfprintf(stderr, fmt, varg);
572 	va_end(varg);
573 	fprintf(stderr, " at source line %d", lineno);
574 	if (curfname != NULL)
575 		fprintf(stderr, " in function %s", curfname);
576 	if (compile_time == 1 && cursource() != NULL)
577 		fprintf(stderr, " source file %s", cursource());
578 	fprintf(stderr, "\n");
579 	errorflag = 2;
580 	eprint();
581 }
582 
583 extern int bracecnt, brackcnt, parencnt;
584 
bracecheck(void)585 void bracecheck(void)
586 {
587 	int c;
588 	static int beenhere = 0;
589 
590 	if (beenhere++)
591 		return;
592 	while ((c = input()) != EOF && c != '\0')
593 		bclass(c);
594 	bcheck2(bracecnt, '{', '}');
595 	bcheck2(brackcnt, '[', ']');
596 	bcheck2(parencnt, '(', ')');
597 }
598 
bcheck2(int n,int c1,int c2)599 void bcheck2(int n, int c1, int c2)
600 {
601 	if (n == 1)
602 		fprintf(stderr, "\tmissing %c\n", c2);
603 	else if (n > 1)
604 		fprintf(stderr, "\t%d missing %c's\n", n, c2);
605 	else if (n == -1)
606 		fprintf(stderr, "\textra %c\n", c2);
607 	else if (n < -1)
608 		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
609 }
610 
FATAL(const char * fmt,...)611 void FATAL(const char *fmt, ...)
612 {
613 	extern char *cmdname;
614 	va_list varg;
615 
616 	fflush(stdout);
617 	fprintf(stderr, "%s: ", cmdname);
618 	va_start(varg, fmt);
619 	vfprintf(stderr, fmt, varg);
620 	va_end(varg);
621 	error();
622 	if (dbg > 1)		/* core dump if serious debugging on */
623 		abort();
624 	exit(2);
625 }
626 
WARNING(const char * fmt,...)627 void WARNING(const char *fmt, ...)
628 {
629 	extern char *cmdname;
630 	va_list varg;
631 
632 	fflush(stdout);
633 	fprintf(stderr, "%s: ", cmdname);
634 	va_start(varg, fmt);
635 	vfprintf(stderr, fmt, varg);
636 	va_end(varg);
637 	error();
638 }
639 
error()640 void error()
641 {
642 	extern Node *curnode;
643 
644 	fprintf(stderr, "\n");
645 	if (compile_time != 2 && NR && *NR > 0) {
646 		fprintf(stderr, " input record number %d", (int) (*FNR));
647 		if (strcmp(*FILENAME, "-") != 0)
648 			fprintf(stderr, ", file %s", *FILENAME);
649 		fprintf(stderr, "\n");
650 	}
651 	if (compile_time != 2 && curnode)
652 		fprintf(stderr, " source line number %d", curnode->lineno);
653 	else if (compile_time != 2 && lineno)
654 		fprintf(stderr, " source line number %d", lineno);
655 	if (compile_time == 1 && cursource() != NULL)
656 		fprintf(stderr, " source file %s", cursource());
657 	fprintf(stderr, "\n");
658 	eprint();
659 }
660 
eprint(void)661 void eprint(void)	/* try to print context around error */
662 {
663 	char *p, *q;
664 	static int been_here = 0;
665 	extern char ebuf[], *ep;
666 
667 	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
668 		return;
669 	p = ep - 1;
670 	if (p > ebuf && *p == '\n')
671 		p--;
672 	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
673 		;
674 	while (*p == '\n')
675 		p++;
676 	fprintf(stderr, " context is\n\t");
677 	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
678 		;
679 	for ( ; p < q; p++)
680 		if (*p)
681 			putc(*p, stderr);
682 	fprintf(stderr, " >>> ");
683 	for ( ; p < ep; p++)
684 		if (*p)
685 			putc(*p, stderr);
686 	fprintf(stderr, " <<< ");
687 #if 0
688 	/*
689 	 * The following code was used to print the rest of the line of
690 	 * error context. It naively counts brackets, parens and braces in
691 	 * order to minimize the parsing effect of dropping the rest of the
692 	 * line but it does not work in all the cases. It is too much work
693 	 * to save the current program input point and restore it in all the
694 	 * cases just for the benefit of error printing so for now this
695 	 * code is disabled. In particular this code is confused if the
696 	 * [ { ( ) } ] is inside a quoted string or a pattern.
697 	 */
698 	if (*ep) {
699 		int c;
700 		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
701 			putc(c, stderr);
702 			bclass(c);
703 		}
704 	}
705 #endif
706 	putc('\n', stderr);
707 	ep = ebuf;
708 }
709 
bclass(int c)710 void bclass(int c)
711 {
712 	switch (c) {
713 	case '{': bracecnt++; break;
714 	case '}': bracecnt--; break;
715 	case '[': brackcnt++; break;
716 	case ']': brackcnt--; break;
717 	case '(': parencnt++; break;
718 	case ')': parencnt--; break;
719 	}
720 }
721 
errcheck(double x,const char * s)722 double errcheck(double x, const char *s)
723 {
724 
725 	if (errno == EDOM) {
726 		errno = 0;
727 		WARNING("%s argument out of domain", s);
728 		x = 1;
729 	} else if (errno == ERANGE) {
730 		errno = 0;
731 		WARNING("%s result out of range", s);
732 		x = 1;
733 	}
734 	return x;
735 }
736 
isclvar(const char * s)737 int isclvar(const char *s)	/* is s of form var=something ? */
738 {
739 	const char *os = s;
740 
741 	if (!isalpha((uschar) *s) && *s != '_')
742 		return 0;
743 	for ( ; *s; s++)
744 		if (!(isalnum((uschar) *s) || *s == '_'))
745 			break;
746 	return *s == '=' && s > os && *(s+1) != '=';
747 }
748 
749 /* strtod is supposed to be a proper test of what's a valid number */
750 /* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
751 /* wrong: violates 4.10.1.4 of ansi C standard */
752 
753 #include <math.h>
is_number(const char * s)754 int is_number(const char *s)
755 {
756 	char *ep;
757 	errno = 0;
758 	(void)strtod(s, &ep);
759 	if (ep == s || errno == ERANGE)
760 		return 0;
761 	if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0)
762 		return 0;
763 	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
764 		ep++;
765 	if (*ep == '\0')
766 		return 1;
767 	else
768 		return 0;
769 }
770