Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
96 7u83 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
#define DEBUG
26
#include <stdio.h>
27
#include <string.h>
28
#include <ctype.h>
29
#include <errno.h>
30
#include <stdlib.h>
31
#include <stdarg.h>
32
#include "awk.h"
33
#include "ytab.h"
34
 
35
FILE	*infile	= NULL;
36
char	*file	= "";
37
char	*record;
38
int	recsize	= RECSIZE;
39
char	*fields;
40
int	fieldssize = RECSIZE;
41
 
42
Cell	**fldtab;	/* pointers to Cells */
43
char	inputFS[100] = " ";
44
 
45
#define	MAXFLD	2
46
int	nfields	= MAXFLD;	/* last allocated slot for $i */
47
 
48
int	donefld;	/* 1 = implies rec broken into fields */
49
int	donerec;	/* 1 = record is valid (no flds have changed) */
50
 
51
int	lastfld	= 0;	/* last used field */
52
int	argno	= 1;	/* current input argument number */
53
extern	Awkfloat *ARGC;
54
 
55
static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
56
static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
57
 
58
void recinit(unsigned int n)
59
{
60
	if ( (record = (char *) malloc(n)) == NULL
61
	  || (fields = (char *) malloc(n+1)) == NULL
62
	  || (fldtab = (Cell **) malloc((nfields+2) * sizeof(Cell *))) == NULL
63
	  || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
64
		FATAL("out of space for $0 and fields");
65
	*fldtab[0] = dollar0;
66
	fldtab[0]->sval = record;
67
	fldtab[0]->nval = tostring("0");
68
	makefields(1, nfields);
69
}
70
 
71
void makefields(int n1, int n2)		/* create $n1..$n2 inclusive */
72
{
73
	char temp[50];
74
	int i;
75
 
76
	for (i = n1; i <= n2; i++) {
77
		fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
78
		if (fldtab[i] == NULL)
79
			FATAL("out of space in makefields %d", i);
80
		*fldtab[i] = dollar1;
81
		sprintf(temp, "%d", i);
82
		fldtab[i]->nval = tostring(temp);
83
	}
84
}
85
 
86
void initgetrec(void)
87
{
88
	int i;
89
	char *p;
90
 
91
	for (i = 1; i < *ARGC; i++) {
92
		p = getargv(i); /* find 1st real filename */
93
		if (p == NULL || *p == '\0') {  /* deleted or zapped */
94
			argno++;
95
			continue;
96
		}
97
		if (!isclvar(p)) {
98
			setsval(lookup("FILENAME", symtab), p);
99
			return;
100
		}
101
		setclvar(p);	/* a commandline assignment before filename */
102
		argno++;
103
	}
104
	infile = stdin;		/* no filenames, so use stdin */
105
}
106
 
107
static int firsttime = 1;
108
 
109
int getrec(char **pbuf, int *pbufsize, int isrecord)	/* get next input record */
110
{			/* note: cares whether buf == record */
111
	int c;
112
	char *buf = *pbuf;
113
	uschar saveb0;
114
	int bufsize = *pbufsize, savebufsize = bufsize;
115
 
116
	if (firsttime) {
117
		firsttime = 0;
118
		initgetrec();
119
	}
120
	   dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
121
		*RS, *FS, *ARGC, *FILENAME) );
122
	if (isrecord) {
123
		donefld = 0;
124
		donerec = 1;
125
	}
126
	saveb0 = buf[0];
127
	buf[0] = 0;
128
	while (argno < *ARGC || infile == stdin) {
129
		   dprintf( ("argno=%d, file=|%s|\n", argno, file) );
130
		if (infile == NULL) {	/* have to open a new file */
131
			file = getargv(argno);
132
			if (file == NULL || *file == '\0') {	/* deleted or zapped */
133
				argno++;
134
				continue;
135
			}
136
			if (isclvar(file)) {	/* a var=value arg */
137
				setclvar(file);
138
				argno++;
139
				continue;
140
			}
141
			*FILENAME = file;
142
			   dprintf( ("opening file %s\n", file) );
143
			if (*file == '-' && *(file+1) == '\0')
144
				infile = stdin;
145
			else if ((infile = fopen(file, "r")) == NULL)
146
				FATAL("can't open file %s", file);
147
			setfval(fnrloc, 0.0);
148
		}
149
		c = readrec(&buf, &bufsize, infile);
150
		if (c != 0 || buf[0] != '\0') {	/* normal record */
151
			if (isrecord) {
152
				if (freeable(fldtab[0]))
153
					xfree(fldtab[0]->sval);
154
				fldtab[0]->sval = buf;	/* buf == record */
155
				fldtab[0]->tval = REC | STR | DONTFREE;
156
				if (is_number(fldtab[0]->sval)) {
157
					fldtab[0]->fval = atof(fldtab[0]->sval);
158
					fldtab[0]->tval |= NUM;
159
				}
160
			}
161
			setfval(nrloc, nrloc->fval+1);
162
			setfval(fnrloc, fnrloc->fval+1);
163
			*pbuf = buf;
164
			*pbufsize = bufsize;
165
			return 1;
166
		}
167
		/* EOF arrived on this file; set up next */
168
		if (infile != stdin)
169
			fclose(infile);
170
		infile = NULL;
171
		argno++;
172
	}
173
	buf[0] = saveb0;
174
	*pbuf = buf;
175
	*pbufsize = savebufsize;
176
	return 0;	/* true end of file */
177
}
178
 
179
void nextfile(void)
180
{
181
	if (infile != NULL && infile != stdin)
182
		fclose(infile);
183
	infile = NULL;
184
	argno++;
185
}
186
 
187
int readrec(char **pbuf, int *pbufsize, FILE *inf)	/* read one record into buf */
188
{
189
	int sep, c;
190
	char *rr, *buf = *pbuf;
191
	int bufsize = *pbufsize;
192
	char *rs = getsval(rsloc);
193
 
194
	if (strlen(getsval(fsloc)) >= sizeof (inputFS))
195
		FATAL("field separator %.10s... is too long", *FS);
196
	/*fflush(stdout); avoids some buffering problem but makes it 25% slower*/
197
	strcpy(inputFS, *FS);	/* for subsequent field splitting */
198
	if ((sep = *rs) == 0) {
199
		sep = '\n';
200
		while ((c=getc(inf)) == '\n' && c != EOF)	/* skip leading \n's */
201
			;
202
		if (c != EOF)
203
			ungetc(c, inf);
204
	}
205
	for (rr = buf; ; ) {
206
		for (; (c=getc(inf)) != sep && c != EOF; ) {
207
			if (rr-buf+1 > bufsize)
208
				if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1"))
209
					FATAL("input record `%.30s...' too long", buf);
210
			*rr++ = c;
211
		}
212
		if (*rs == sep || c == EOF)
213
			break;
214
		if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
215
			break;
216
		if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2"))
217
			FATAL("input record `%.30s...' too long", buf);
218
		*rr++ = '\n';
219
		*rr++ = c;
220
	}
221
	if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
222
		FATAL("input record `%.30s...' too long", buf);
223
	*rr = 0;
224
	   dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) );
225
	*pbuf = buf;
226
	*pbufsize = bufsize;
227
	return c == EOF && rr == buf ? 0 : 1;
228
}
229
 
230
char *getargv(int n)	/* get ARGV[n] */
231
{
232
	Cell *x;
233
	char *s, temp[50];
234
	extern Array *ARGVtab;
235
 
236
	sprintf(temp, "%d", n);
237
	if (lookup(temp, ARGVtab) == NULL)
238
		return NULL;
239
	x = setsymtab(temp, "", 0.0, STR, ARGVtab);
240
	s = getsval(x);
241
	   dprintf( ("getargv(%d) returns |%s|\n", n, s) );
242
	return s;
243
}
244
 
245
void setclvar(char *s)	/* set var=value from s */
246
{
247
	char *p;
248
	Cell *q;
249
 
250
	for (p=s; *p != '='; p++)
251
		;
252
	*p++ = 0;
253
	p = qstring(p, '\0');
254
	q = setsymtab(s, p, 0.0, STR, symtab);
255
	setsval(q, p);
256
	if (is_number(q->sval)) {
257
		q->fval = atof(q->sval);
258
		q->tval |= NUM;
259
	}
260
	   dprintf( ("command line set %s to |%s|\n", s, p) );
261
}
262
 
263
 
264
void fldbld(void)	/* create fields from current record */
265
{
266
	/* this relies on having fields[] the same length as $0 */
267
	/* the fields are all stored in this one array with \0's */
268
	/* possibly with a final trailing \0 not associated with any field */
269
	char *r, *fr, sep;
270
	Cell *p;
271
	int i, j, n;
272
 
273
	if (donefld)
274
		return;
275
	if (!isstr(fldtab[0]))
276
		getsval(fldtab[0]);
277
	r = fldtab[0]->sval;
278
	n = strlen(r);
279
	if (n > fieldssize) {
280
		xfree(fields);
281
		if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
282
			FATAL("out of space for fields in fldbld %d", n);
283
		fieldssize = n;
284
	}
285
	fr = fields;
286
	i = 0;	/* number of fields accumulated here */
287
	if (strlen(getsval(fsloc)) >= sizeof (inputFS))
288
		FATAL("field separator %.10s... is too long", *FS);
289
	strcpy(inputFS, *FS);
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
	donerec = 1; /* restore */
363
	if (dbg) {
364
		for (j = 0; j <= lastfld; j++) {
365
			p = fldtab[j];
366
			printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
367
		}
368
	}
369
}
370
 
371
void cleanfld(int n1, int n2)	/* clean out fields n1 .. n2 inclusive */
372
{				/* nvals remain intact */
373
	Cell *p;
374
	int i;
375
 
376
	for (i = n1; i <= n2; i++) {
377
		p = fldtab[i];
378
		if (freeable(p))
379
			xfree(p->sval);
380
		p->sval = "";
381
		p->tval = FLD | STR | DONTFREE;
382
	}
383
}
384
 
385
void newfld(int n)	/* add field n after end of existing lastfld */
386
{
387
	if (n > nfields)
388
		growfldtab(n);
389
	cleanfld(lastfld+1, n);
390
	lastfld = n;
391
	setfval(nfloc, (Awkfloat) n);
392
}
393
 
394
void setlastfld(int n)	/* set lastfld cleaning fldtab cells if necessary */
395
{
396
	if (n < 0)
397
		FATAL("cannot set NF to a negative value");
398
	if (n > nfields)
399
		growfldtab(n);
400
 
401
	if (lastfld < n)
402
	    cleanfld(lastfld+1, n);
403
	else
404
	    cleanfld(n+1, lastfld);
405
 
406
	lastfld = n;
407
}
408
 
409
Cell *fieldadr(int n)	/* get nth field */
410
{
411
	if (n < 0)
412
		FATAL("trying to access out of range field %d", n);
413
	if (n > nfields)	/* fields after NF are empty */
414
		growfldtab(n);	/* but does not increase NF */
415
	return(fldtab[n]);
416
}
417
 
418
void growfldtab(int n)	/* make new fields up to at least $n */
419
{
420
	int nf = 2 * nfields;
421
	size_t s;
422
 
423
	if (n > nf)
424
		nf = n;
425
	s = (nf+1) * (sizeof (struct Cell *));  /* freebsd: how much do we need? */
426
	if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
427
		fldtab = (Cell **) realloc(fldtab, s);
428
	else					/* overflow sizeof int */
429
		xfree(fldtab);	/* make it null */
430
	if (fldtab == NULL)
431
		FATAL("out of space creating %d fields", nf);
432
	makefields(nfields+1, nf);
433
	nfields = nf;
434
}
435
 
436
int refldbld(const char *rec, const char *fs)	/* build fields from reg expr in FS */
437
{
438
	/* this relies on having fields[] the same length as $0 */
439
	/* the fields are all stored in this one array with \0's */
440
	char *fr;
441
	int i, tempstat, n;
442
	fa *pfa;
443
 
444
	n = strlen(rec);
445
	if (n > fieldssize) {
446
		xfree(fields);
447
		if ((fields = (char *) malloc(n+1)) == NULL)
448
			FATAL("out of space for fields in refldbld %d", n);
449
		fieldssize = n;
450
	}
451
	fr = fields;
452
	*fr = '\0';
453
	if (*rec == '\0')
454
		return 0;
455
	pfa = makedfa(fs, 1);
456
	   dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
457
	tempstat = pfa->initstat;
458
	for (i = 1; ; i++) {
459
		if (i > nfields)
460
			growfldtab(i);
461
		if (freeable(fldtab[i]))
462
			xfree(fldtab[i]->sval);
463
		fldtab[i]->tval = FLD | STR | DONTFREE;
464
		fldtab[i]->sval = fr;
465
		   dprintf( ("refldbld: i=%d\n", i) );
466
		if (nematch(pfa, rec)) {
467
			pfa->initstat = 2;	/* horrible coupling to b.c */
468
			   dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
469
			strncpy(fr, rec, patbeg-rec);
470
			fr += patbeg - rec + 1;
471
			*(fr-1) = '\0';
472
			rec = patbeg + patlen;
473
		} else {
474
			   dprintf( ("no match %s\n", rec) );
475
			strcpy(fr, rec);
476
			pfa->initstat = tempstat;
477
			break;
478
		}
479
	}
480
	return i;		
481
}
482
 
483
void recbld(void)	/* create $0 from $1..$NF if necessary */
484
{
485
	int i;
486
	char *r, *p;
487
	char *sep = getsval(ofsloc);
488
 
489
	if (donerec == 1)
490
		return;
491
	r = record;
492
	for (i = 1; i <= *NF; i++) {
493
		p = getsval(fldtab[i]);
494
		if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
495
			FATAL("created $0 `%.30s...' too long", record);
496
		while ((*r = *p++) != 0)
497
			r++;
498
		if (i < *NF) {
499
			if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
500
				FATAL("created $0 `%.30s...' too long", record);
501
			for (p = sep; (*r = *p++) != 0; )
502
				r++;
503
		}
504
	}
505
	if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
506
		FATAL("built giant record `%.30s...'", record);
507
	*r = '\0';
508
	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
509
 
510
	if (freeable(fldtab[0]))
511
		xfree(fldtab[0]->sval);
512
	fldtab[0]->tval = REC | STR | DONTFREE;
513
	fldtab[0]->sval = record;
514
 
515
	   dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
516
	   dprintf( ("recbld = |%s|\n", record) );
517
	donerec = 1;
518
}
519
 
520
int	errorflag	= 0;
521
 
522
void yyerror(const char *s)
523
{
524
	SYNTAX("%s", s);
525
}
526
 
527
void SYNTAX(const char *fmt, ...)
528
{
529
	extern char *cmdname, *curfname;
530
	static int been_here = 0;
531
	va_list varg;
532
 
533
	if (been_here++ > 2)
534
		return;
535
	fprintf(stderr, "%s: ", cmdname);
536
	va_start(varg, fmt);
537
	vfprintf(stderr, fmt, varg);
538
	va_end(varg);
539
	fprintf(stderr, " at source line %d", lineno);
540
	if (curfname != NULL)
541
		fprintf(stderr, " in function %s", curfname);
542
	if (compile_time == 1 && cursource() != NULL)
543
		fprintf(stderr, " source file %s", cursource());
544
	fprintf(stderr, "\n");
545
	errorflag = 2;
546
	eprint();
547
}
548
 
549
void fpecatch(int n)
550
{
551
	FATAL("floating point exception %d", n);
552
}
553
 
554
extern int bracecnt, brackcnt, parencnt;
555
 
556
void bracecheck(void)
557
{
558
	int c;
559
	static int beenhere = 0;
560
 
561
	if (beenhere++)
562
		return;
563
	while ((c = input()) != EOF && c != '\0')
564
		bclass(c);
565
	bcheck2(bracecnt, '{', '}');
566
	bcheck2(brackcnt, '[', ']');
567
	bcheck2(parencnt, '(', ')');
568
}
569
 
570
void bcheck2(int n, int c1, int c2)
571
{
572
	if (n == 1)
573
		fprintf(stderr, "\tmissing %c\n", c2);
574
	else if (n > 1)
575
		fprintf(stderr, "\t%d missing %c's\n", n, c2);
576
	else if (n == -1)
577
		fprintf(stderr, "\textra %c\n", c2);
578
	else if (n < -1)
579
		fprintf(stderr, "\t%d extra %c's\n", -n, c2);
580
}
581
 
582
void FATAL(const char *fmt, ...)
583
{
584
	extern char *cmdname;
585
	va_list varg;
586
 
587
	fflush(stdout);
588
	fprintf(stderr, "%s: ", cmdname);
589
	va_start(varg, fmt);
590
	vfprintf(stderr, fmt, varg);
591
	va_end(varg);
592
	error();
593
	if (dbg > 1)		/* core dump if serious debugging on */
594
		abort();
595
	exit(2);
596
}
597
 
598
void WARNING(const char *fmt, ...)
599
{
600
	extern char *cmdname;
601
	va_list varg;
602
 
603
	fflush(stdout);
604
	fprintf(stderr, "%s: ", cmdname);
605
	va_start(varg, fmt);
606
	vfprintf(stderr, fmt, varg);
607
	va_end(varg);
608
	error();
609
}
610
 
611
void error()
612
{
613
	extern Node *curnode;
614
 
615
	fprintf(stderr, "\n");
616
	if (compile_time != 2 && NR && *NR > 0) {
617
		fprintf(stderr, " input record number %d", (int) (*FNR));
618
		if (strcmp(*FILENAME, "-") != 0)
619
			fprintf(stderr, ", file %s", *FILENAME);
620
		fprintf(stderr, "\n");
621
	}
622
	if (compile_time != 2 && curnode)
623
		fprintf(stderr, " source line number %d", curnode->lineno);
624
	else if (compile_time != 2 && lineno)
625
		fprintf(stderr, " source line number %d", lineno);
626
	if (compile_time == 1 && cursource() != NULL)
627
		fprintf(stderr, " source file %s", cursource());
628
	fprintf(stderr, "\n");
629
	eprint();
630
}
631
 
632
void eprint(void)	/* try to print context around error */
633
{
634
	char *p, *q;
635
	int c;
636
	static int been_here = 0;
637
	extern char ebuf[], *ep;
638
 
639
	if (compile_time == 2 || compile_time == 0 || been_here++ > 0)
640
		return;
641
	if (ebuf == ep)
642
		return;
643
	p = ep - 1;
644
	if (p > ebuf && *p == '\n')
645
		p--;
646
	for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
647
		;
648
	while (*p == '\n')
649
		p++;
650
	fprintf(stderr, " context is\n\t");
651
	for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
652
		;
653
	for ( ; p < q; p++)
654
		if (*p)
655
			putc(*p, stderr);
656
	fprintf(stderr, " >>> ");
657
	for ( ; p < ep; p++)
658
		if (*p)
659
			putc(*p, stderr);
660
	fprintf(stderr, " <<< ");
661
	if (*ep)
662
		while ((c = input()) != '\n' && c != '\0' && c != EOF) {
663
			putc(c, stderr);
664
			bclass(c);
665
		}
666
	putc('\n', stderr);
667
	ep = ebuf;
668
}
669
 
670
void bclass(int c)
671
{
672
	switch (c) {
673
	case '{': bracecnt++; break;
674
	case '}': bracecnt--; break;
675
	case '[': brackcnt++; break;
676
	case ']': brackcnt--; break;
677
	case '(': parencnt++; break;
678
	case ')': parencnt--; break;
679
	}
680
}
681
 
682
double errcheck(double x, const char *s)
683
{
684
 
685
	if (errno == EDOM) {
686
		errno = 0;
687
		WARNING("%s argument out of domain", s);
688
		x = 1;
689
	} else if (errno == ERANGE) {
690
		errno = 0;
691
		WARNING("%s result out of range", s);
692
		x = 1;
693
	}
694
	return x;
695
}
696
 
697
int isclvar(const char *s)	/* is s of form var=something ? */
698
{
699
	const char *os = s;
700
 
701
	if (!isalpha((uschar) *s) && *s != '_')
702
		return 0;
703
	for ( ; *s; s++)
704
		if (!(isalnum((uschar) *s) || *s == '_'))
705
			break;
706
	return *s == '=' && s > os && *(s+1) != '=';
707
}
708
 
709
/* strtod is supposed to be a proper test of what's a valid number */
710
/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
711
/* wrong: violates 4.10.1.4 of ansi C standard */
712
 
713
#include <math.h>
714
int is_number(const char *s)
715
{
716
	double r;
717
	char *ep;
718
	errno = 0;
719
	r = strtod(s, &ep);
720
	if (ep == s || r == HUGE_VAL || errno == ERANGE)
721
		return 0;
722
	while (*ep == ' ' || *ep == '\t' || *ep == '\n')
723
		ep++;
724
	if (*ep == '\0')
725
		return 1;
726
	else
727
		return 0;
728
}