hbase

heirloom base
git clone git://git.2f30.org/hbase
Log | Files | Refs | README

lib.c (18507B)


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