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