GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/lib.c Lines: 216 446 48.4 %
Date: 2017-11-07 Branches: 138 389 35.5 %

Line Branch Exec Source
1
/*	$OpenBSD: lib.c,v 1.23 2017/09/25 17:36:35 krw 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
2943
	if ( (record = (char *) malloc(n)) == NULL
63
1962
	  || (fields = (char *) malloc(n+1)) == NULL
64
1962
	  || (fldtab = (Cell **) calloc(nfields+1, sizeof(Cell *))) == NULL
65
1962
	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
66
		FATAL("out of space for $0 and fields");
67
981
	*record = '\0';
68
981
	*fldtab[0] = dollar0;
69
981
	fldtab[0]->sval = record;
70
981
	fldtab[0]->nval = tostring("0");
71
981
	makefields(1, nfields);
72
981
}
73
74
void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
75
{
76
3138
	char temp[50];
77
	int i;
78
79
12026
	for (i = n1; i <= n2; i++) {
80
4444
		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
81
4444
		if (fldtab[i] == NULL)
82
			FATAL("out of space in makefields %d", i);
83
4444
		*fldtab[i] = dollar1;
84
4444
		snprintf(temp, sizeof temp, "%d", i);
85
4444
		fldtab[i]->nval = tostring(temp);
86
	}
87
1569
}
88
89
void initgetrec(void)
90
{
91
	int i;
92
	char *p;
93
94
2656
	for (i = 1; i < *ARGC; i++) {
95
157
		p = getargv(i); /* find 1st real filename */
96

314
		if (p == NULL || *p == '\0') {  /* deleted or zapped */
97
			argno++;
98
			continue;
99
		}
100
157
		if (!isclvar(p)) {
101
137
			setsval(lookup("FILENAME", symtab), p);
102
137
			return;
103
		}
104
20
		setclvar(p);	/* a commandline assignment before filename */
105
		argno++;
106
20
	}
107
735
	infile = stdin;		/* no filenames, so use stdin */
108
1607
}
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
2755612
	char *buf = *pbuf;
116
	uschar saveb0;
117
1377806
	int bufsize = *pbufsize, savebufsize = bufsize;
118
119
1377806
	if (firsttime) {
120
872
		firsttime = 0;
121
872
		initgetrec();
122
872
	}
123
1377806
	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
124
		*RS, *FS, *ARGC, *FILENAME) );
125
1377806
	if (isrecord) {
126
1377806
		donefld = 0;
127
1377806
		donerec = 1;
128
1377806
	}
129
1377806
	saveb0 = buf[0];
130
1377806
	buf[0] = 0;
131
2757050
	while (argno < *ARGC || infile == stdin) {
132
1377806
		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
133
1377806
		if (infile == NULL) {	/* have to open a new file */
134
137
			file = getargv(argno);
135

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

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

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

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

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

1427145
			while (*r == ' ' || *r == '\t' || *r == '\n')
295
138619
				r++;
296
189315
			if (*r == 0)
297
				break;
298
153005
			i++;
299
153005
			if (i > nfields)
300
492
				growfldtab(i);
301
153005
			if (freeable(fldtab[i]))
302
				xfree(fldtab[i]->sval);
303
153005
			fldtab[i]->sval = fr;
304
153005
			fldtab[i]->tval = FLD | STR | DONTFREE;
305
153005
			do
306
1075599
				*fr++ = *r++;
307

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

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

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

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

380
	return *s == '=' && s > os && *(s+1) != '=';
719
294
}
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
14571734
	char *ep;
730
7285867
	errno = 0;
731
7285867
	r = strtod(s, &ep);
732

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

27703085
	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
735
27649
		ep++;
736
6903638
	if (*ep == '\0')
737
6859099
		return 1;
738
	else
739
44539
		return 0;
740
7285867
}