blob: b08f0ba9547453bcc27d0d087b81150c09acc815 [file] [log] [blame]
Brian Kernighan87b94932012-12-22 10:35:39 -05001/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS 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
35FILE *infile = NULL;
36char *file = "";
37char *record;
38int recsize = RECSIZE;
39char *fields;
40int fieldssize = RECSIZE;
41
42Cell **fldtab; /* pointers to Cells */
43char inputFS[100] = " ";
44
45#define MAXFLD 2
46int nfields = MAXFLD; /* last allocated slot for $i */
47
48int donefld; /* 1 = implies rec broken into fields */
49int donerec; /* 1 = record is valid (no flds have changed) */
50
51int lastfld = 0; /* last used field */
52int argno = 1; /* current input argument number */
53extern Awkfloat *ARGC;
54
55static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE };
56static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE };
57
58void recinit(unsigned int n)
59{
60 if ( (record = (char *) malloc(n)) == NULL
61 || (fields = (char *) malloc(n+1)) == NULL
Cody Peter Mello75802352018-11-12 10:34:19 -080062 || (fldtab = (Cell **) malloc((nfields+2) * sizeof(Cell *))) == NULL
Brian Kernighan87b94932012-12-22 10:35:39 -050063 || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL )
64 FATAL("out of space for $0 and fields");
M. Warner Losh0939e332019-06-02 15:17:29 -060065 *record = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -050066 *fldtab[0] = dollar0;
67 fldtab[0]->sval = record;
68 fldtab[0]->nval = tostring("0");
69 makefields(1, nfields);
70}
71
72void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
73{
74 char temp[50];
75 int i;
76
77 for (i = n1; i <= n2; i++) {
78 fldtab[i] = (Cell *) malloc(sizeof (struct Cell));
79 if (fldtab[i] == NULL)
80 FATAL("out of space in makefields %d", i);
81 *fldtab[i] = dollar1;
82 sprintf(temp, "%d", i);
83 fldtab[i]->nval = tostring(temp);
84 }
85}
86
87void initgetrec(void)
88{
89 int i;
90 char *p;
91
92 for (i = 1; i < *ARGC; i++) {
93 p = getargv(i); /* find 1st real filename */
94 if (p == NULL || *p == '\0') { /* deleted or zapped */
95 argno++;
96 continue;
97 }
98 if (!isclvar(p)) {
99 setsval(lookup("FILENAME", symtab), p);
100 return;
101 }
102 setclvar(p); /* a commandline assignment before filename */
103 argno++;
104 }
105 infile = stdin; /* no filenames, so use stdin */
106}
107
Cody Peter Mellob4636802018-10-19 15:07:53 -0700108/*
109 * POSIX specifies that fields are supposed to be evaluated as if they were
110 * split using the value of FS at the time that the record's value ($0) was
111 * read.
112 *
113 * Since field-splitting is done lazily, we save the current value of FS
114 * whenever a new record is read in (implicitly or via getline), or when
115 * a new value is assigned to $0.
116 */
117void savefs(void)
118{
119 if (strlen(getsval(fsloc)) >= sizeof (inputFS))
120 FATAL("field separator %.10s... is too long", *FS);
121 strcpy(inputFS, *FS);
122}
123
Brian Kernighan87b94932012-12-22 10:35:39 -0500124static int firsttime = 1;
125
126int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */
127{ /* note: cares whether buf == record */
128 int c;
129 char *buf = *pbuf;
130 uschar saveb0;
131 int bufsize = *pbufsize, savebufsize = bufsize;
132
133 if (firsttime) {
134 firsttime = 0;
135 initgetrec();
136 }
137 dprintf( ("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
138 *RS, *FS, *ARGC, *FILENAME) );
139 if (isrecord) {
140 donefld = 0;
141 donerec = 1;
Cody Peter Mellob4636802018-10-19 15:07:53 -0700142 savefs();
Brian Kernighan87b94932012-12-22 10:35:39 -0500143 }
144 saveb0 = buf[0];
145 buf[0] = 0;
146 while (argno < *ARGC || infile == stdin) {
147 dprintf( ("argno=%d, file=|%s|\n", argno, file) );
148 if (infile == NULL) { /* have to open a new file */
149 file = getargv(argno);
150 if (file == NULL || *file == '\0') { /* deleted or zapped */
151 argno++;
152 continue;
153 }
154 if (isclvar(file)) { /* a var=value arg */
155 setclvar(file);
156 argno++;
157 continue;
158 }
159 *FILENAME = file;
160 dprintf( ("opening file %s\n", file) );
161 if (*file == '-' && *(file+1) == '\0')
162 infile = stdin;
163 else if ((infile = fopen(file, "r")) == NULL)
164 FATAL("can't open file %s", file);
165 setfval(fnrloc, 0.0);
166 }
167 c = readrec(&buf, &bufsize, infile);
168 if (c != 0 || buf[0] != '\0') { /* normal record */
169 if (isrecord) {
170 if (freeable(fldtab[0]))
171 xfree(fldtab[0]->sval);
172 fldtab[0]->sval = buf; /* buf == record */
173 fldtab[0]->tval = REC | STR | DONTFREE;
174 if (is_number(fldtab[0]->sval)) {
175 fldtab[0]->fval = atof(fldtab[0]->sval);
176 fldtab[0]->tval |= NUM;
177 }
178 }
179 setfval(nrloc, nrloc->fval+1);
180 setfval(fnrloc, fnrloc->fval+1);
181 *pbuf = buf;
182 *pbufsize = bufsize;
183 return 1;
184 }
185 /* EOF arrived on this file; set up next */
186 if (infile != stdin)
187 fclose(infile);
188 infile = NULL;
189 argno++;
190 }
191 buf[0] = saveb0;
192 *pbuf = buf;
193 *pbufsize = savebufsize;
194 return 0; /* true end of file */
195}
196
197void nextfile(void)
198{
199 if (infile != NULL && infile != stdin)
200 fclose(infile);
201 infile = NULL;
202 argno++;
203}
204
205int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */
206{
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300207 int sep, c, isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500208 char *rr, *buf = *pbuf;
209 int bufsize = *pbufsize;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700210 char *rs = getsval(rsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500211
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300212#ifdef RS_AS_REGEXP
213 if (*rs && rs[1]) {
214 int found;
215
216 fa *pfa = makedfa(rs, 1);
217 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
218 if (found)
219 *patbeg = 0;
220 } else {
221#endif
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';
Brian Kernighan87b94932012-12-22 10:35:39 -0500245 *rr++ = c;
246 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300247 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500248 FATAL("input record `%.30s...' too long", buf);
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300249 *rr = 0;
250#ifdef RS_AS_REGEXP
Brian Kernighan87b94932012-12-22 10:35:39 -0500251 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300252#endif
Brian Kernighan87b94932012-12-22 10:35:39 -0500253 *pbuf = buf;
254 *pbufsize = bufsize;
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300255 isrec = *buf || !feof(inf);
256 dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) );
257 return isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500258}
259
260char *getargv(int n) /* get ARGV[n] */
261{
262 Cell *x;
263 char *s, temp[50];
264 extern Array *ARGVtab;
265
266 sprintf(temp, "%d", n);
267 if (lookup(temp, ARGVtab) == NULL)
268 return NULL;
269 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
270 s = getsval(x);
271 dprintf( ("getargv(%d) returns |%s|\n", n, s) );
272 return s;
273}
274
275void setclvar(char *s) /* set var=value from s */
276{
277 char *p;
278 Cell *q;
279
280 for (p=s; *p != '='; p++)
281 ;
282 *p++ = 0;
283 p = qstring(p, '\0');
284 q = setsymtab(s, p, 0.0, STR, symtab);
285 setsval(q, p);
286 if (is_number(q->sval)) {
287 q->fval = atof(q->sval);
288 q->tval |= NUM;
289 }
290 dprintf( ("command line set %s to |%s|\n", s, p) );
291}
292
293
294void fldbld(void) /* create fields from current record */
295{
296 /* this relies on having fields[] the same length as $0 */
297 /* the fields are all stored in this one array with \0's */
298 /* possibly with a final trailing \0 not associated with any field */
299 char *r, *fr, sep;
300 Cell *p;
301 int i, j, n;
302
303 if (donefld)
304 return;
305 if (!isstr(fldtab[0]))
306 getsval(fldtab[0]);
307 r = fldtab[0]->sval;
308 n = strlen(r);
309 if (n > fieldssize) {
310 xfree(fields);
311 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
312 FATAL("out of space for fields in fldbld %d", n);
313 fieldssize = n;
314 }
315 fr = fields;
316 i = 0; /* number of fields accumulated here */
Brian Kernighan87b94932012-12-22 10:35:39 -0500317 if (strlen(inputFS) > 1) { /* it's a regular expression */
318 i = refldbld(r, inputFS);
319 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
320 for (i = 0; ; ) {
321 while (*r == ' ' || *r == '\t' || *r == '\n')
322 r++;
323 if (*r == 0)
324 break;
325 i++;
326 if (i > nfields)
327 growfldtab(i);
328 if (freeable(fldtab[i]))
329 xfree(fldtab[i]->sval);
330 fldtab[i]->sval = fr;
331 fldtab[i]->tval = FLD | STR | DONTFREE;
332 do
333 *fr++ = *r++;
334 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
335 *fr++ = 0;
336 }
337 *fr = 0;
338 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
339 for (i = 0; *r != 0; r++) {
340 char buf[2];
341 i++;
342 if (i > nfields)
343 growfldtab(i);
344 if (freeable(fldtab[i]))
345 xfree(fldtab[i]->sval);
346 buf[0] = *r;
347 buf[1] = 0;
348 fldtab[i]->sval = tostring(buf);
349 fldtab[i]->tval = FLD | STR;
350 }
351 *fr = 0;
352 } else if (*r != 0) { /* if 0, it's a null field */
353 /* subtlecase : if length(FS) == 1 && length(RS > 0)
354 * \n is NOT a field separator (cf awk book 61,84).
355 * this variable is tested in the inner while loop.
356 */
357 int rtest = '\n'; /* normal case */
358 if (strlen(*RS) > 0)
359 rtest = '\0';
360 for (;;) {
361 i++;
362 if (i > nfields)
363 growfldtab(i);
364 if (freeable(fldtab[i]))
365 xfree(fldtab[i]->sval);
366 fldtab[i]->sval = fr;
367 fldtab[i]->tval = FLD | STR | DONTFREE;
368 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
369 *fr++ = *r++;
370 *fr++ = 0;
371 if (*r++ == 0)
372 break;
373 }
374 *fr = 0;
375 }
376 if (i > nfields)
377 FATAL("record `%.30s...' has too many fields; can't happen", r);
378 cleanfld(i+1, lastfld); /* clean out junk from previous record */
379 lastfld = i;
380 donefld = 1;
381 for (j = 1; j <= lastfld; j++) {
382 p = fldtab[j];
383 if(is_number(p->sval)) {
384 p->fval = atof(p->sval);
385 p->tval |= NUM;
386 }
387 }
388 setfval(nfloc, (Awkfloat) lastfld);
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300389 donerec = 1; /* restore */
Brian Kernighan87b94932012-12-22 10:35:39 -0500390 if (dbg) {
391 for (j = 0; j <= lastfld; j++) {
392 p = fldtab[j];
393 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
394 }
395 }
396}
397
398void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
399{ /* nvals remain intact */
400 Cell *p;
401 int i;
402
403 for (i = n1; i <= n2; i++) {
404 p = fldtab[i];
405 if (freeable(p))
406 xfree(p->sval);
407 p->sval = "";
408 p->tval = FLD | STR | DONTFREE;
409 }
410}
411
412void newfld(int n) /* add field n after end of existing lastfld */
413{
414 if (n > nfields)
415 growfldtab(n);
416 cleanfld(lastfld+1, n);
417 lastfld = n;
418 setfval(nfloc, (Awkfloat) n);
419}
420
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300421void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
422{
Cody Peter Mello179536a2018-09-25 21:19:49 -0700423 if (n < 0)
424 FATAL("cannot set NF to a negative value");
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300425 if (n > nfields)
426 growfldtab(n);
427
428 if (lastfld < n)
429 cleanfld(lastfld+1, n);
430 else
431 cleanfld(n+1, lastfld);
432
433 lastfld = n;
434}
435
Brian Kernighan87b94932012-12-22 10:35:39 -0500436Cell *fieldadr(int n) /* get nth field */
437{
438 if (n < 0)
439 FATAL("trying to access out of range field %d", n);
440 if (n > nfields) /* fields after NF are empty */
441 growfldtab(n); /* but does not increase NF */
442 return(fldtab[n]);
443}
444
445void growfldtab(int n) /* make new fields up to at least $n */
446{
447 int nf = 2 * nfields;
448 size_t s;
449
450 if (n > nf)
451 nf = n;
452 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
453 if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */
454 fldtab = (Cell **) realloc(fldtab, s);
455 else /* overflow sizeof int */
456 xfree(fldtab); /* make it null */
457 if (fldtab == NULL)
458 FATAL("out of space creating %d fields", nf);
459 makefields(nfields+1, nf);
460 nfields = nf;
461}
462
463int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
464{
465 /* this relies on having fields[] the same length as $0 */
466 /* the fields are all stored in this one array with \0's */
467 char *fr;
468 int i, tempstat, n;
469 fa *pfa;
470
471 n = strlen(rec);
472 if (n > fieldssize) {
473 xfree(fields);
474 if ((fields = (char *) malloc(n+1)) == NULL)
475 FATAL("out of space for fields in refldbld %d", n);
476 fieldssize = n;
477 }
478 fr = fields;
479 *fr = '\0';
480 if (*rec == '\0')
481 return 0;
482 pfa = makedfa(fs, 1);
483 dprintf( ("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs) );
484 tempstat = pfa->initstat;
485 for (i = 1; ; i++) {
486 if (i > nfields)
487 growfldtab(i);
488 if (freeable(fldtab[i]))
489 xfree(fldtab[i]->sval);
490 fldtab[i]->tval = FLD | STR | DONTFREE;
491 fldtab[i]->sval = fr;
492 dprintf( ("refldbld: i=%d\n", i) );
493 if (nematch(pfa, rec)) {
494 pfa->initstat = 2; /* horrible coupling to b.c */
495 dprintf( ("match %s (%d chars)\n", patbeg, patlen) );
496 strncpy(fr, rec, patbeg-rec);
497 fr += patbeg - rec + 1;
498 *(fr-1) = '\0';
499 rec = patbeg + patlen;
500 } else {
501 dprintf( ("no match %s\n", rec) );
502 strcpy(fr, rec);
503 pfa->initstat = tempstat;
504 break;
505 }
506 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600507 return i;
Brian Kernighan87b94932012-12-22 10:35:39 -0500508}
509
510void recbld(void) /* create $0 from $1..$NF if necessary */
511{
512 int i;
513 char *r, *p;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700514 char *sep = getsval(ofsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500515
516 if (donerec == 1)
517 return;
518 r = record;
519 for (i = 1; i <= *NF; i++) {
520 p = getsval(fldtab[i]);
521 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
522 FATAL("created $0 `%.30s...' too long", record);
523 while ((*r = *p++) != 0)
524 r++;
525 if (i < *NF) {
Cody Peter Mello52566c02018-09-18 15:45:55 -0700526 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500527 FATAL("created $0 `%.30s...' too long", record);
Cody Peter Mello52566c02018-09-18 15:45:55 -0700528 for (p = sep; (*r = *p++) != 0; )
Brian Kernighan87b94932012-12-22 10:35:39 -0500529 r++;
530 }
531 }
532 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
533 FATAL("built giant record `%.30s...'", record);
534 *r = '\0';
535 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
536
537 if (freeable(fldtab[0]))
538 xfree(fldtab[0]->sval);
539 fldtab[0]->tval = REC | STR | DONTFREE;
540 fldtab[0]->sval = record;
541
542 dprintf( ("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]) );
543 dprintf( ("recbld = |%s|\n", record) );
544 donerec = 1;
545}
546
547int errorflag = 0;
548
549void yyerror(const char *s)
550{
551 SYNTAX("%s", s);
552}
553
554void SYNTAX(const char *fmt, ...)
555{
556 extern char *cmdname, *curfname;
557 static int been_here = 0;
558 va_list varg;
559
560 if (been_here++ > 2)
561 return;
562 fprintf(stderr, "%s: ", cmdname);
563 va_start(varg, fmt);
564 vfprintf(stderr, fmt, varg);
565 va_end(varg);
566 fprintf(stderr, " at source line %d", lineno);
567 if (curfname != NULL)
568 fprintf(stderr, " in function %s", curfname);
569 if (compile_time == 1 && cursource() != NULL)
570 fprintf(stderr, " source file %s", cursource());
571 fprintf(stderr, "\n");
572 errorflag = 2;
573 eprint();
574}
575
576void fpecatch(int n)
577{
578 FATAL("floating point exception %d", n);
579}
580
581extern int bracecnt, brackcnt, parencnt;
582
583void bracecheck(void)
584{
585 int c;
586 static int beenhere = 0;
587
588 if (beenhere++)
589 return;
590 while ((c = input()) != EOF && c != '\0')
591 bclass(c);
592 bcheck2(bracecnt, '{', '}');
593 bcheck2(brackcnt, '[', ']');
594 bcheck2(parencnt, '(', ')');
595}
596
597void bcheck2(int n, int c1, int c2)
598{
599 if (n == 1)
600 fprintf(stderr, "\tmissing %c\n", c2);
601 else if (n > 1)
602 fprintf(stderr, "\t%d missing %c's\n", n, c2);
603 else if (n == -1)
604 fprintf(stderr, "\textra %c\n", c2);
605 else if (n < -1)
606 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
607}
608
609void FATAL(const char *fmt, ...)
610{
611 extern char *cmdname;
612 va_list varg;
613
614 fflush(stdout);
615 fprintf(stderr, "%s: ", cmdname);
616 va_start(varg, fmt);
617 vfprintf(stderr, fmt, varg);
618 va_end(varg);
619 error();
620 if (dbg > 1) /* core dump if serious debugging on */
621 abort();
622 exit(2);
623}
624
625void WARNING(const char *fmt, ...)
626{
627 extern char *cmdname;
628 va_list varg;
629
630 fflush(stdout);
631 fprintf(stderr, "%s: ", cmdname);
632 va_start(varg, fmt);
633 vfprintf(stderr, fmt, varg);
634 va_end(varg);
635 error();
636}
637
638void error()
639{
640 extern Node *curnode;
641
642 fprintf(stderr, "\n");
643 if (compile_time != 2 && NR && *NR > 0) {
644 fprintf(stderr, " input record number %d", (int) (*FNR));
645 if (strcmp(*FILENAME, "-") != 0)
646 fprintf(stderr, ", file %s", *FILENAME);
647 fprintf(stderr, "\n");
648 }
649 if (compile_time != 2 && curnode)
650 fprintf(stderr, " source line number %d", curnode->lineno);
651 else if (compile_time != 2 && lineno)
652 fprintf(stderr, " source line number %d", lineno);
653 if (compile_time == 1 && cursource() != NULL)
654 fprintf(stderr, " source file %s", cursource());
655 fprintf(stderr, "\n");
656 eprint();
657}
658
659void eprint(void) /* try to print context around error */
660{
661 char *p, *q;
662 int c;
663 static int been_here = 0;
664 extern char ebuf[], *ep;
665
M. Warner Losh9310d452019-06-02 15:23:06 -0600666 if (compile_time == 2 || compile_time == 0 || been_here++ > 0 || ebuf == ep)
Brian Kernighan87b94932012-12-22 10:35:39 -0500667 return;
Brian Kernighan3ed9e242018-08-15 10:45:03 -0400668 if (ebuf == ep)
669 return;
Brian Kernighan87b94932012-12-22 10:35:39 -0500670 p = ep - 1;
671 if (p > ebuf && *p == '\n')
672 p--;
673 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
674 ;
675 while (*p == '\n')
676 p++;
677 fprintf(stderr, " context is\n\t");
678 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
679 ;
680 for ( ; p < q; p++)
681 if (*p)
682 putc(*p, stderr);
683 fprintf(stderr, " >>> ");
684 for ( ; p < ep; p++)
685 if (*p)
686 putc(*p, stderr);
687 fprintf(stderr, " <<< ");
688 if (*ep)
689 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
690 putc(c, stderr);
691 bclass(c);
692 }
693 putc('\n', stderr);
694 ep = ebuf;
695}
696
697void bclass(int c)
698{
699 switch (c) {
700 case '{': bracecnt++; break;
701 case '}': bracecnt--; break;
702 case '[': brackcnt++; break;
703 case ']': brackcnt--; break;
704 case '(': parencnt++; break;
705 case ')': parencnt--; break;
706 }
707}
708
709double errcheck(double x, const char *s)
710{
711
712 if (errno == EDOM) {
713 errno = 0;
714 WARNING("%s argument out of domain", s);
715 x = 1;
716 } else if (errno == ERANGE) {
717 errno = 0;
718 WARNING("%s result out of range", s);
719 x = 1;
720 }
721 return x;
722}
723
724int isclvar(const char *s) /* is s of form var=something ? */
725{
726 const char *os = s;
727
728 if (!isalpha((uschar) *s) && *s != '_')
729 return 0;
730 for ( ; *s; s++)
731 if (!(isalnum((uschar) *s) || *s == '_'))
732 break;
Arnold D. Robbins4189ef52019-05-29 21:04:18 +0300733 return *s == '=' && s > os;
Brian Kernighan87b94932012-12-22 10:35:39 -0500734}
735
736/* strtod is supposed to be a proper test of what's a valid number */
737/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
738/* wrong: violates 4.10.1.4 of ansi C standard */
739
740#include <math.h>
741int is_number(const char *s)
742{
743 double r;
744 char *ep;
745 errno = 0;
746 r = strtod(s, &ep);
747 if (ep == s || r == HUGE_VAL || errno == ERANGE)
748 return 0;
749 while (*ep == ' ' || *ep == '\t' || *ep == '\n')
750 ep++;
751 if (*ep == '\0')
752 return 1;
753 else
754 return 0;
755}