GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/lib.c Lines: 217 447 48.5 %
Date: 2017-11-13 Branches: 138 389 35.5 %

Line Branch Exec Source
1
/*	$OpenBSD: lib.c,v 1.24 2017/10/09 14:51:31 deraadt 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
{
62
1461
	if ( (record = (char *) malloc(n)) == NULL
63
974
	  || (fields = (char *) malloc(n+1)) == NULL
64
974
	  || (fldtab = (Cell **) calloc(nfields+1, sizeof(Cell *))) == NULL
65
974
	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
66
		FATAL("out of space for $0 and fields");
67
487
	*record = '\0';
68
487
	*fldtab[0] = dollar0;
69
487
	fldtab[0]->sval = record;
70
487
	fldtab[0]->nval = tostring("0");
71
487
	makefields(1, nfields);
72
487
}
73
74
void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
75
{
76
1618
	char temp[50];
77
	int i;
78
79
6474
	for (i = n1; i <= n2; i++) {
80
2428
		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
81
2428
		if (fldtab[i] == NULL)
82
			FATAL("out of space in makefields %d", i);
83
2428
		*fldtab[i] = dollar1;
84
2428
		snprintf(temp, sizeof temp, "%d", i);
85
2428
		fldtab[i]->nval = tostring(temp);
86
	}
87
809
}
88
89
void initgetrec(void)
90
{
91
	int i;
92
	char *p;
93
94
1352
	for (i = 1; i < *ARGC; i++) {
95
88
		p = getargv(i); /* find 1st real filename */
96

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

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

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

599247
		if (c != 0 || buf[0] != '\0') {	/* normal record */
154
598471
			if (isrecord) {
155
598471
				if (freeable(fldtab[0]))
156
					xfree(fldtab[0]->sval);
157
598471
				fldtab[0]->sval = buf;	/* buf == record */
158
598471
				fldtab[0]->tval = REC | STR | DONTFREE;
159
598471
				if (is_number(fldtab[0]->sval)) {
160
481583
					fldtab[0]->fval = atof(fldtab[0]->sval);
161
481583
					fldtab[0]->tval |= NUM;
162
481583
				}
163
			}
164
598471
			setfval(nrloc, nrloc->fval+1);
165
598471
			setfval(fnrloc, fnrloc->fval+1);
166
598471
			*pbuf = buf;
167
598471
			*pbufsize = bufsize;
168
598471
			return 1;
169
		}
170
		/* EOF arrived on this file; set up next */
171
388
		if (infile != stdin)
172
72
			fclose(infile);
173
388
		infile = NULL;
174
388
		argno++;
175
	}
176
388
	buf[0] = saveb0;
177
388
	*pbuf = buf;
178
388
	*pbufsize = savebufsize;
179
388
	return 0;	/* true end of file */
180
598859
}
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
{
192
	int sep, c;
193
1197718
	char *rr, *buf = *pbuf;
194
598859
	int bufsize = *pbufsize;
195
196
598859
	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
598859
	strlcpy(inputFS, *FS, sizeof inputFS);	/* for subsequent field splitting */
200
598859
	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
598859
	for (rr = buf; ; ) {
208

33922880
		for (; (c=getc(inf)) != sep && c != EOF; ) {
209
6185717
			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
6185717
			*rr++ = c;
213
		}
214
598859
		if (**RS == sep || c == EOF)
215
			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
598859
	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
224
		FATAL("input record `%.30s...' too long", buf);
225
598859
	*rr = 0;
226

598859
	   DPRINTF( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
227
598859
	*pbuf = buf;
228
598859
	*pbufsize = bufsize;
229
1796965
	return c == EOF && rr == buf ? 0 : 1;
230
598859
}
231
232
char *getargv(int n)	/* get ARGV[n] */
233
{
234
	Cell *x;
235
320
	char *s, temp[50];
236
	extern Array *ARGVtab;
237
238
160
	snprintf(temp, sizeof temp, "%d", n);
239
160
	if (lookup(temp, ARGVtab) == NULL)
240
		return NULL;
241
160
	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
242
160
	s = getsval(x);
243
160
	   DPRINTF( ("getargv(%d) returns |%s|\n", n, s) );
244
160
	return s;
245
160
}
246
247
void setclvar(char *s)	/* set var=value from s */
248
{
249
	char *p;
250
	Cell *q;
251
252
340
	for (p=s; *p != '='; p++)
253
		;
254
16
	*p++ = 0;
255
16
	p = qstring(p, '\0');
256
16
	q = setsymtab(s, p, 0.0, STR, symtab);
257
16
	setsval(q, p);
258
16
	if (is_number(q->sval)) {
259
10
		q->fval = atof(q->sval);
260
10
		q->tval |= NUM;
261
10
	}
262
16
	   DPRINTF( ("command line set %s to |%s|\n", s, p) );
263
16
}
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
42530
	if (donefld)
276
		return;
277
21265
	if (!isstr(fldtab[0]))
278
		getsval(fldtab[0]);
279
21265
	r = fldtab[0]->sval;
280
21265
	n = strlen(r);
281
21265
	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
21265
	fr = fields;
288
	i = 0;	/* number of fields accumulated here */
289
21265
	strlcpy(inputFS, *FS, sizeof(inputFS));
290
21265
	if (strlen(inputFS) > 1) {	/* it's a regular expression */
291
		i = refldbld(r, inputFS);
292
21265
	} else if ((sep = *inputFS) == ' ') {	/* default whitespace */
293
133035
		for (i = 0; ; ) {
294

1047415
			while (*r == ' ' || *r == '\t' || *r == '\n')
295
109271
				r++;
296
133035
			if (*r == 0)
297
				break;
298
111946
			i++;
299
111946
			if (i > nfields)
300
272
				growfldtab(i);
301
111946
			if (freeable(fldtab[i]))
302
				xfree(fldtab[i]->sval);
303
111946
			fldtab[i]->sval = fr;
304
111946
			fldtab[i]->tval = FLD | STR | DONTFREE;
305
111946
			do
306
849551
				*fr++ = *r++;
307

1650446
			while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
308
111946
			*fr++ = 0;
309
		}
310
21089
		*fr = 0;
311
21265
	} 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
176
	} 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
176
		if (strlen(*RS) > 0)
332
176
			rtest = '\0';
333
352
		for (;;) {
334
352
			i++;
335
352
			if (i > nfields)
336
				growfldtab(i);
337
352
			if (freeable(fldtab[i]))
338
				xfree(fldtab[i]->sval);
339
352
			fldtab[i]->sval = fr;
340
352
			fldtab[i]->tval = FLD | STR | DONTFREE;
341

7392
			while (*r != sep && *r != rtest && *r != '\0')	/* \n is always a separator */
342
1628
				*fr++ = *r++;
343
352
			*fr++ = 0;
344
352
			if (*r++ == 0)
345
				break;
346
		}
347
176
		*fr = 0;
348
176
	}
349
21265
	if (i > nfields)
350
		FATAL("record `%.30s...' has too many fields; can't happen", r);
351
21265
	cleanfld(i+1, lastfld);	/* clean out junk from previous record */
352
21265
	lastfld = i;
353
21265
	donefld = 1;
354
267126
	for (j = 1; j <= lastfld; j++) {
355
112298
		p = fldtab[j];
356
112298
		if(is_number(p->sval)) {
357
21300
			p->fval = atof(p->sval);
358
21300
			p->tval |= NUM;
359
21300
		}
360
	}
361
21265
	setfval(nfloc, (Awkfloat) lastfld);
362
21265
	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
42530
}
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
84199
	for (i = n1; i <= n2; i++) {
376
10202
		p = fldtab[i];
377
10202
		if (freeable(p))
378
			xfree(p->sval);
379
10202
		p->sval = "";
380
10202
		p->tval = FLD | STR | DONTFREE;
381
	}
382
21265
}
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
{
395
5197454
	if (n < 0)
396
		FATAL("trying to access out of range field %d", n);
397
2598727
	if (n > nfields)	/* fields after NF are empty */
398
50
		growfldtab(n);	/* but does not increase NF */
399
2598727
	return(fldtab[n]);
400
}
401
402
void growfldtab(int n)	/* make new fields up to at least $n */
403
{
404
644
	int nf = 2 * nfields;
405
	size_t s;
406
407
322
	if (n > nf)
408
32
		nf = n;
409
322
	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
410
322
	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
411
322
		fldtab = (Cell **) realloc(fldtab, s);
412
	else					/* overflow sizeof int */
413
		xfree(fldtab);	/* make it null */
414
644
	if (fldtab == NULL)
415
		FATAL("out of space creating %d fields", nf);
416
322
	makefields(nfields+1, nf);
417
322
	nfields = nf;
418
322
}
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
16
	char *r, *p;
471
472
8
	if (donerec == 1)
473
		return;
474
8
	r = record;
475
16
	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
8
	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
489
		FATAL("built giant record `%.30s...'", record);
490
8
	*r = '\0';
491
8
	   DPRINTF( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
492
493
8
	if (freeable(fldtab[0]))
494
		xfree(fldtab[0]->sval);
495
8
	fldtab[0]->tval = REC | STR | DONTFREE;
496
8
	fldtab[0]->sval = record;
497
498
8
	   DPRINTF( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
499
8
	   DPRINTF( ("recbld = |%s|\n", record) );
500
8
	donerec = 1;
501
16
}
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
__dead 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
{
711
	const char *os = s;
712
713

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

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

200
	return *s == '=' && s > os && *(s+1) != '=';
719
160
}
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
{
728
	double r;
729
6448474
	char *ep;
730
3224237
	errno = 0;
731
3224237
	r = strtod(s, &ep);
732

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

15147156
	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
735
11664
		ep++;
736
3022060
	if (*ep == '\0')
737
3004253
		return 1;
738
	else
739
17807
		return 0;
740
3224237
}