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