GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/lib.c Lines: 113 436 25.9 %
Date: 2016-12-06 Branches: 72 417 17.3 %

Line Branch Exec Source
1
/*	$OpenBSD: lib.c,v 1.22 2016/04/12 19:43:38 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 "ytab.h"
36
37
FILE	*infile	= NULL;
38
char	*file	= "";
39
char	*record;
40
int	recsize	= RECSIZE;
41
char	*fields;
42
int	fieldssize = RECSIZE;
43
44
Cell	**fldtab;	/* pointers to Cells */
45
char	inputFS[100] = " ";
46
47
#define	MAXFLD	2
48
int	nfields	= MAXFLD;	/* last allocated slot for $i */
49
50
int	donefld;	/* 1 = implies rec broken into fields */
51
int	donerec;	/* 1 = record is valid (no flds have changed) */
52
53
int	lastfld	= 0;	/* last used field */
54
int	argno	= 1;	/* current input argument number */
55
extern	Awkfloat *ARGC;
56
57
static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
58
static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
59
60
void recinit(unsigned int n)
61
31
{
62


31
	if ( (record = (char *) malloc(n)) == NULL
63
	  || (fields = (char *) malloc(n+1)) == NULL
64
	  || (fldtab = (Cell **) calloc(nfields+1, sizeof(Cell *))) == NULL
65
	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
66
		FATAL("out of space for $0 and fields");
67
31
	*record = '\0';
68
31
	*fldtab[0] = dollar0;
69
31
	fldtab[0]->sval = record;
70
31
	fldtab[0]->nval = tostring("0");
71
31
	makefields(1, nfields);
72
31
}
73
74
void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
75
31
{
76
	char temp[50];
77
	int i;
78
79
93
	for (i = n1; i <= n2; i++) {
80
62
		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
81
62
		if (fldtab[i] == NULL)
82
			FATAL("out of space in makefields %d", i);
83
62
		*fldtab[i] = dollar1;
84
62
		snprintf(temp, sizeof temp, "%d", i);
85
62
		fldtab[i]->nval = tostring(temp);
86
	}
87
31
}
88
89
void initgetrec(void)
90
29
{
91
	int i;
92
	char *p;
93
94
29
	for (i = 1; i < *ARGC; i++) {
95
1
		p = getargv(i); /* find 1st real filename */
96

1
		if (p == NULL || *p == '\0') {  /* deleted or zapped */
97
			argno++;
98
			continue;
99
		}
100
1
		if (!isclvar(p)) {
101
1
			setsval(lookup("FILENAME", symtab), p);
102
1
			return;
103
		}
104
		setclvar(p);	/* a commandline assignment before filename */
105
		argno++;
106
	}
107
28
	infile = stdin;		/* no filenames, so use stdin */
108
}
109
110
static int firsttime = 1;
111
112
int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
113
27163
{			/* note: cares whether buf == record */
114
	int c;
115
27163
	char *buf = *pbuf;
116
	uschar saveb0;
117
27163
	int bufsize = *pbufsize, savebufsize = bufsize;
118
119
27163
	if (firsttime) {
120
29
		firsttime = 0;
121
29
		initgetrec();
122
	}
123
27163
	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
124
		*RS, *FS, *ARGC, *FILENAME) );
125
27163
	if (isrecord) {
126
27163
		donefld = 0;
127
27163
		donerec = 1;
128
	}
129
27163
	saveb0 = buf[0];
130
27163
	buf[0] = 0;
131

54339
	while (argno < *ARGC || infile == stdin) {
132
27163
		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
133
27163
		if (infile == NULL) {	/* have to open a new file */
134
1
			file = getargv(argno);
135

1
			if (file == NULL || *file == '\0') {	/* deleted or zapped */
136
				argno++;
137
				continue;
138
			}
139
1
			if (isclvar(file)) {	/* a var=value arg */
140
				setclvar(file);
141
				argno++;
142
				continue;
143
			}
144
1
			*FILENAME = file;
145
1
			   dprintf( ("opening file %s\n", file) );
146

1
			if (*file == '-' && *(file+1) == '\0')
147
				infile = stdin;
148
1
			else if ((infile = fopen(file, "r")) == NULL)
149
				FATAL("can't open file %s", file);
150
1
			setfval(fnrloc, 0.0);
151
		}
152
27163
		c = readrec(&buf, &bufsize, infile);
153

27163
		if (c != 0 || buf[0] != '\0') {	/* normal record */
154
27150
			if (isrecord) {
155
27150
				if (freeable(fldtab[0]))
156
					xfree(fldtab[0]->sval);
157
27150
				fldtab[0]->sval = buf;	/* buf == record */
158
27150
				fldtab[0]->tval = REC | STR | DONTFREE;
159
27150
				if (is_number(fldtab[0]->sval)) {
160
					fldtab[0]->fval = atof(fldtab[0]->sval);
161
					fldtab[0]->tval |= NUM;
162
				}
163
			}
164
27150
			setfval(nrloc, nrloc->fval+1);
165
27150
			setfval(fnrloc, fnrloc->fval+1);
166
27150
			*pbuf = buf;
167
27150
			*pbufsize = bufsize;
168
27150
			return 1;
169
		}
170
		/* EOF arrived on this file; set up next */
171
13
		if (infile != stdin)
172
1
			fclose(infile);
173
13
		infile = NULL;
174
13
		argno++;
175
	}
176
13
	buf[0] = saveb0;
177
13
	*pbuf = buf;
178
13
	*pbufsize = savebufsize;
179
13
	return 0;	/* true end of file */
180
}
181
182
void nextfile(void)
183
{
184
	if (infile != NULL && infile != stdin)
185
		fclose(infile);
186
	infile = NULL;
187
	argno++;
188
}
189
190
int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
191
27163
{
192
	int sep, c;
193
27163
	char *rr, *buf = *pbuf;
194
27163
	int bufsize = *pbufsize;
195
196
27163
	if (strlen(*FS) >= sizeof(inputFS))
197
		FATAL("field separator %.10s... is too long", *FS);
198
	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
199
27163
	strlcpy(inputFS, *FS, sizeof inputFS);	/* for subsequent field splitting */
200
27163
	if ((sep = **RS) == 0) {
201
		sep = '\n';
202
		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
203
			;
204
		if (c != EOF)
205
			ungetc(c, inf);
206
	}
207
27163
	for (rr = buf; ; ) {
208


524160
		for (; (c=getc(inf)) != sep && c != EOF; ) {
209
496997
			if (rr-buf+1 > bufsize)
210
				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
211
					FATAL("input record `%.30s...' too long", buf);
212
496997
			*rr++ = c;
213
		}
214
27163
		if (**RS == sep || c == EOF)
215
27163
			break;
216
		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
217
			break;
218
		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
219
			FATAL("input record `%.30s...' too long", buf);
220
		*rr++ = '\n';
221
		*rr++ = c;
222
	}
223
27163
	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
224
		FATAL("input record `%.30s...' too long", buf);
225
27163
	*rr = 0;
226

27163
	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
227
27163
	*pbuf = buf;
228
27163
	*pbufsize = bufsize;
229

27163
	return c == EOF && rr == buf ? 0 : 1;
230
}
231
232
char *getargv(int n)	/* get ARGV[n] */
233
2
{
234
	Cell *x;
235
	char *s, temp[50];
236
	extern Array *ARGVtab;
237
238
2
	snprintf(temp, sizeof temp, "%d", n);
239
2
	if (lookup(temp, ARGVtab) == NULL)
240
		return NULL;
241
2
	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
242
2
	s = getsval(x);
243
2
	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
244
2
	return s;
245
}
246
247
void setclvar(char *s)	/* set var=value from s */
248
{
249
	char *p;
250
	Cell *q;
251
252
	for (p=s; *p != '='; p++)
253
		;
254
	*p++ = 0;
255
	p = qstring(p, '\0');
256
	q = setsymtab(s, p, 0.0, STR, symtab);
257
	setsval(q, p);
258
	if (is_number(q->sval)) {
259
		q->fval = atof(q->sval);
260
		q->tval |= NUM;
261
	}
262
	   dprintf( ("command line set %s to |%s|\n", s, p) );
263
}
264
265
266
void fldbld(void)	/* create fields from current record */
267
{
268
	/* this relies on having fields[] the same length as $0 */
269
	/* the fields are all stored in this one array with \0's */
270
	/* possibly with a final trailing \0 not associated with any field */
271
	char *r, *fr, sep;
272
	Cell *p;
273
	int i, j, n;
274
275
	if (donefld)
276
		return;
277
	if (!isstr(fldtab[0]))
278
		getsval(fldtab[0]);
279
	r = fldtab[0]->sval;
280
	n = strlen(r);
281
	if (n > fieldssize) {
282
		xfree(fields);
283
		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
284
			FATAL("out of space for fields in fldbld %d", n);
285
		fieldssize = n;
286
	}
287
	fr = fields;
288
	i = 0;	/* number of fields accumulated here */
289
	strlcpy(inputFS, *FS, sizeof(inputFS));
290
	if (strlen(inputFS) > 1) {	/* it's a regular expression */
291
		i = refldbld(r, inputFS);
292
	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
293
		for (i = 0; ; ) {
294
			while (*r == ' ' || *r == '\t' || *r == '\n')
295
				r++;
296
			if (*r == 0)
297
				break;
298
			i++;
299
			if (i > nfields)
300
				growfldtab(i);
301
			if (freeable(fldtab[i]))
302
				xfree(fldtab[i]->sval);
303
			fldtab[i]->sval = fr;
304
			fldtab[i]->tval = FLD | STR | DONTFREE;
305
			do
306
				*fr++ = *r++;
307
			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
308
			*fr++ = 0;
309
		}
310
		*fr = 0;
311
	} else if ((sep = *inputFS) == 0) {		/* new: FS="" => 1 char/field */
312
		for (i = 0; *r != 0; r++) {
313
			char buf[2];
314
			i++;
315
			if (i > nfields)
316
				growfldtab(i);
317
			if (freeable(fldtab[i]))
318
				xfree(fldtab[i]->sval);
319
			buf[0] = *r;
320
			buf[1] = 0;
321
			fldtab[i]->sval = tostring(buf);
322
			fldtab[i]->tval = FLD | STR;
323
		}
324
		*fr = 0;
325
	} else if (*r != 0) {	/* if 0, it's a null field */
326
		/* subtlecase : if length(FS) == 1 && length(RS > 0)
327
		 * \n is NOT a field separator (cf awk book 61,84).
328
		 * this variable is tested in the inner while loop.
329
		 */
330
		int rtest = '\n';  /* normal case */
331
		if (strlen(*RS) > 0)
332
			rtest = '\0';
333
		for (;;) {
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
			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
342
				*fr++ = *r++;
343
			*fr++ = 0;
344
			if (*r++ == 0)
345
				break;
346
		}
347
		*fr = 0;
348
	}
349
	if (i > nfields)
350
		FATAL("record `%.30s...' has too many fields; can't happen", r);
351
	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
352
	lastfld = i;
353
	donefld = 1;
354
	for (j = 1; j <= lastfld; j++) {
355
		p = fldtab[j];
356
		if(is_number(p->sval)) {
357
			p->fval = atof(p->sval);
358
			p->tval |= NUM;
359
		}
360
	}
361
	setfval(nfloc, (Awkfloat) lastfld);
362
	if (dbg) {
363
		for (j = 0; j <= lastfld; j++) {
364
			p = fldtab[j];
365
			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
366
		}
367
	}
368
}
369
370
void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
371
{				/* nvals remain intact */
372
	Cell *p;
373
	int i;
374
375
	for (i = n1; i <= n2; i++) {
376
		p = fldtab[i];
377
		if (freeable(p))
378
			xfree(p->sval);
379
		p->sval = "";
380
		p->tval = FLD | STR | DONTFREE;
381
	}
382
}
383
384
void newfld(int n)	/* add field n after end of existing lastfld */
385
{
386
	if (n > nfields)
387
		growfldtab(n);
388
	cleanfld(lastfld+1, n);
389
	lastfld = n;
390
	setfval(nfloc, (Awkfloat) n);
391
}
392
393
Cell *fieldadr(int n)	/* get nth field */
394
63840
{
395
63840
	if (n < 0)
396
		FATAL("trying to access out of range field %d", n);
397
63840
	if (n > nfields)	/* fields after NF are empty */
398
		growfldtab(n);	/* but does not increase NF */
399
63840
	return(fldtab[n]);
400
}
401
402
void growfldtab(int n)	/* make new fields up to at least $n */
403
{
404
	int nf = 2 * nfields;
405
	size_t s;
406
407
	if (n > nf)
408
		nf = n;
409
	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
410
	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
411
		fldtab = (Cell **) realloc(fldtab, s);
412
	else					/* overflow sizeof int */
413
		xfree(fldtab);	/* make it null */
414
	if (fldtab == NULL)
415
		FATAL("out of space creating %d fields", nf);
416
	makefields(nfields+1, nf);
417
	nfields = nf;
418
}
419
420
int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
421
{
422
	/* this relies on having fields[] the same length as $0 */
423
	/* the fields are all stored in this one array with \0's */
424
	char *fr;
425
	int i, tempstat, n;
426
	fa *pfa;
427
428
	n = strlen(rec);
429
	if (n > fieldssize) {
430
		xfree(fields);
431
		if ((fields = (char *) malloc(n+1)) == NULL)
432
			FATAL("out of space for fields in refldbld %d", n);
433
		fieldssize = n;
434
	}
435
	fr = fields;
436
	*fr = '\0';
437
	if (*rec == '\0')
438
		return 0;
439
	pfa = makedfa(fs, 1);
440
	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
441
	tempstat = pfa->initstat;
442
	for (i = 1; ; i++) {
443
		if (i > nfields)
444
			growfldtab(i);
445
		if (freeable(fldtab[i]))
446
			xfree(fldtab[i]->sval);
447
		fldtab[i]->tval = FLD | STR | DONTFREE;
448
		fldtab[i]->sval = fr;
449
		   dprintf( ("refldbld: i=%d\n", i) );
450
		if (nematch(pfa, rec)) {
451
			pfa->initstat = 2;	/* horrible coupling to b.c */
452
			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
453
			strncpy(fr, rec, patbeg-rec);
454
			fr += patbeg - rec + 1;
455
			*(fr-1) = '\0';
456
			rec = patbeg + patlen;
457
		} else {
458
			   dprintf( ("no match %s\n", rec) );
459
			strlcpy(fr, rec, fields + fieldssize - fr);
460
			pfa->initstat = tempstat;
461
			break;
462
		}
463
	}
464
	return i;
465
}
466
467
void recbld(void)	/* create $0 from $1..$NF if necessary */
468
{
469
	int i;
470
	char *r, *p;
471
472
	if (donerec == 1)
473
		return;
474
	r = record;
475
	for (i = 1; i <= *NF; i++) {
476
		p = getsval(fldtab[i]);
477
		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
478
			FATAL("created $0 `%.30s...' too long", record);
479
		while ((*r = *p++) != 0)
480
			r++;
481
		if (i < *NF) {
482
			if (!adjbuf(&record, &recsize, 2+strlen(*OFS)+r-record, recsize, &r, "recbld 2"))
483
				FATAL("created $0 `%.30s...' too long", record);
484
			for (p = *OFS; (*r = *p++) != 0; )
485
				r++;
486
		}
487
	}
488
	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
489
		FATAL("built giant record `%.30s...'", record);
490
	*r = '\0';
491
	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
492
493
	if (freeable(fldtab[0]))
494
		xfree(fldtab[0]->sval);
495
	fldtab[0]->tval = REC | STR | DONTFREE;
496
	fldtab[0]->sval = record;
497
498
	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
499
	   dprintf( ("recbld = |%s|\n", record) );
500
	donerec = 1;
501
}
502
503
int	errorflag	= 0;
504
505
void yyerror(const char *s)
506
{
507
	SYNTAX("%s", s);
508
}
509
510
void SYNTAX(const char *fmt, ...)
511
{
512
	extern char *cmdname, *curfname;
513
	static int been_here = 0;
514
	va_list varg;
515
516
	if (been_here++ > 2)
517
		return;
518
	fprintf(stderr, "%s: ", cmdname);
519
	va_start(varg, fmt);
520
	vfprintf(stderr, fmt, varg);
521
	va_end(varg);
522
	fprintf(stderr, " at source line %d", lineno);
523
	if (curfname != NULL)
524
		fprintf(stderr, " in function %s", curfname);
525
	if (compile_time == 1 && cursource() != NULL)
526
		fprintf(stderr, " source file %s", cursource());
527
	fprintf(stderr, "\n");
528
	errorflag = 2;
529
	eprint();
530
}
531
532
void fpecatch(int sig)
533
{
534
	extern Node *curnode;
535
	char buf[1024];
536
537
	snprintf(buf, sizeof buf, "floating point exception\n");
538
	write(STDERR_FILENO, buf, strlen(buf));
539
540
	if (compile_time != 2 && NR && *NR > 0) {
541
		snprintf(buf, sizeof buf, " input record number %d", (int) (*FNR));
542
		write(STDERR_FILENO, buf, strlen(buf));
543
544
		if (strcmp(*FILENAME, "-") != 0) {
545
			snprintf(buf, sizeof buf, ", file %s", *FILENAME);
546
			write(STDERR_FILENO, buf, strlen(buf));
547
		}
548
		write(STDERR_FILENO, "\n", 1);
549
	}
550
	if (compile_time != 2 && curnode) {
551
		snprintf(buf, sizeof buf, " source line number %d", curnode->lineno);
552
		write(STDERR_FILENO, buf, strlen(buf));
553
	} else if (compile_time != 2 && lineno) {
554
		snprintf(buf, sizeof buf, " source line number %d", lineno);
555
		write(STDERR_FILENO, buf, strlen(buf));
556
	}
557
	if (compile_time == 1 && cursource() != NULL) {
558
		snprintf(buf, sizeof buf, " source file %s", cursource());
559
		write(STDERR_FILENO, buf, strlen(buf));
560
	}
561
	write(STDERR_FILENO, "\n", 1);
562
	if (dbg > 1)		/* core dump if serious debugging on */
563
		abort();
564
	_exit(1);
565
}
566
567
extern int bracecnt, brackcnt, parencnt;
568
569
void bracecheck(void)
570
{
571
	int c;
572
	static int beenhere = 0;
573
574
	if (beenhere++)
575
		return;
576
	while ((c = input()) != EOF && c != '\0')
577
		bclass(c);
578
	bcheck2(bracecnt, '{', '}');
579
	bcheck2(brackcnt, '[', ']');
580
	bcheck2(parencnt, '(', ')');
581
}
582
583
void bcheck2(int n, int c1, int c2)
584
{
585
	if (n == 1)
586
		fprintf(stderr, "\tmissing %c\n", c2);
587
	else if (n > 1)
588
		fprintf(stderr, "\t%d missing %c's\n", n, c2);
589
	else if (n == -1)
590
		fprintf(stderr, "\textra %c\n", c2);
591
	else if (n < -1)
592
		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
593
}
594
595
void FATAL(const char *fmt, ...)
596
{
597
	extern char *cmdname;
598
	va_list varg;
599
600
	fflush(stdout);
601
	fprintf(stderr, "%s: ", cmdname);
602
	va_start(varg, fmt);
603
	vfprintf(stderr, fmt, varg);
604
	va_end(varg);
605
	error();
606
	if (dbg > 1)		/* core dump if serious debugging on */
607
		abort();
608
	exit(2);
609
}
610
611
void WARNING(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
}
623
624
void error()
625
{
626
	extern Node *curnode;
627
628
	fprintf(stderr, "\n");
629
	if (compile_time != 2 && NR && *NR > 0) {
630
		fprintf(stderr, " input record number %d", (int) (*FNR));
631
		if (strcmp(*FILENAME, "-") != 0)
632
			fprintf(stderr, ", file %s", *FILENAME);
633
		fprintf(stderr, "\n");
634
	}
635
	if (compile_time != 2 && curnode)
636
		fprintf(stderr, " source line number %d", curnode->lineno);
637
	else if (compile_time != 2 && lineno)
638
		fprintf(stderr, " source line number %d", lineno);
639
	if (compile_time == 1 && cursource() != NULL)
640
		fprintf(stderr, " source file %s", cursource());
641
	fprintf(stderr, "\n");
642
	eprint();
643
}
644
645
void eprint(void)	/* try to print context around error */
646
{
647
	char *p, *q;
648
	int c;
649
	static int been_here = 0;
650
	extern char ebuf[], *ep;
651
652
	if (compile_time == 2 || compile_time == 0 || been_here++ > 0 ||
653
	    ebuf == ep)
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
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
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
709
int isclvar(const char *s)	/* is s of form var=something ? */
710
2
{
711
2
	const char *os = s;
712
713

4
	if (!isalpha((uschar) *s) && *s != '_')
714
		return 0;
715
12
	for ( ; *s; s++)
716

28
		if (!(isalnum((uschar) *s) || *s == '_'))
717
2
			break;
718

2
	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>
726
int is_number(const char *s)
727
92919
{
728
	double r;
729
	char *ep;
730
92919
	errno = 0;
731
92919
	r = strtod(s, &ep);
732

92919
	if (ep == s || r == HUGE_VAL || errno == ERANGE)
733
27380
		return 0;
734

65540
	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
735
1
		ep++;
736
65539
	if (*ep == '\0')
737
63863
		return 1;
738
	else
739
1676
		return 0;
740
}