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