blob: 18adbd2d1fd653ed887e0a3e257ef58277b45a5c [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>
Michael Forney38e525f2020-12-15 04:46:30 -080028#include <strings.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050029#include <ctype.h>
30#include <errno.h>
31#include <stdlib.h>
32#include <stdarg.h>
Michael Forney69325712020-01-30 22:23:34 -080033#include <limits.h>
Arnold Robbinscc9e9b62020-12-08 08:05:22 +020034#include <math.h>
Brian Kernighan87b94932012-12-22 10:35:39 -050035#include "awk.h"
Brian Kernighan87b94932012-12-22 10:35:39 -050036
zoulasc6a877092020-01-24 04:11:59 -050037char EMPTY[] = { '\0' };
Brian Kernighan87b94932012-12-22 10:35:39 -050038FILE *infile = NULL;
zoulascffee7782020-02-28 06:23:54 -050039bool innew; /* true = infile has not been read by readrec */
zoulasc6a877092020-01-24 04:11:59 -050040char *file = EMPTY;
Brian Kernighan87b94932012-12-22 10:35:39 -050041char *record;
42int recsize = RECSIZE;
43char *fields;
44int fieldssize = RECSIZE;
45
46Cell **fldtab; /* pointers to Cells */
zoulasc6a877092020-01-24 04:11:59 -050047static size_t len_inputFS = 0;
48static char *inputFS = NULL; /* FS at time of input, for field splitting */
Brian Kernighan87b94932012-12-22 10:35:39 -050049
50#define MAXFLD 2
51int nfields = MAXFLD; /* last allocated slot for $i */
52
Arnold D. Robbins108224b2019-11-10 21:19:18 +020053bool donefld; /* true = implies rec broken into fields */
54bool donerec; /* true = record is valid (no flds have changed) */
Brian Kernighan87b94932012-12-22 10:35:39 -050055
56int lastfld = 0; /* last used field */
57int argno = 1; /* current input argument number */
58extern Awkfloat *ARGC;
59
zoulascc2c8ecb2020-02-19 13:44:49 -050060static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL, NULL };
61static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, NULL };
Brian Kernighan87b94932012-12-22 10:35:39 -050062
63void recinit(unsigned int n)
64{
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +030065 if ( (record = (char *) malloc(n)) == NULL
66 || (fields = (char *) malloc(n+1)) == NULL
67 || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
68 || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -050069 FATAL("out of space for $0 and fields");
M. Warner Losh0939e332019-06-02 15:17:29 -060070 *record = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -050071 *fldtab[0] = dollar0;
72 fldtab[0]->sval = record;
73 fldtab[0]->nval = tostring("0");
74 makefields(1, nfields);
75}
76
77void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
78{
79 char temp[50];
80 int i;
81
82 for (i = n1; i <= n2; i++) {
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +030083 fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
Brian Kernighan87b94932012-12-22 10:35:39 -050084 if (fldtab[i] == NULL)
85 FATAL("out of space in makefields %d", i);
86 *fldtab[i] = dollar1;
zoulasc0d8778b2019-10-25 10:59:10 -040087 snprintf(temp, sizeof(temp), "%d", i);
Brian Kernighan87b94932012-12-22 10:35:39 -050088 fldtab[i]->nval = tostring(temp);
89 }
90}
91
92void initgetrec(void)
93{
94 int i;
95 char *p;
96
97 for (i = 1; i < *ARGC; i++) {
98 p = getargv(i); /* find 1st real filename */
99 if (p == NULL || *p == '\0') { /* deleted or zapped */
100 argno++;
101 continue;
102 }
103 if (!isclvar(p)) {
104 setsval(lookup("FILENAME", symtab), p);
105 return;
106 }
107 setclvar(p); /* a commandline assignment before filename */
108 argno++;
109 }
110 infile = stdin; /* no filenames, so use stdin */
zoulascffee7782020-02-28 06:23:54 -0500111 innew = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500112}
113
Cody Peter Mellob4636802018-10-19 15:07:53 -0700114/*
115 * POSIX specifies that fields are supposed to be evaluated as if they were
116 * split using the value of FS at the time that the record's value ($0) was
117 * read.
118 *
119 * Since field-splitting is done lazily, we save the current value of FS
120 * whenever a new record is read in (implicitly or via getline), or when
121 * a new value is assigned to $0.
122 */
123void savefs(void)
124{
zoulasc6a877092020-01-24 04:11:59 -0500125 size_t len;
126 if ((len = strlen(getsval(fsloc))) < len_inputFS) {
127 strcpy(inputFS, *FS); /* for subsequent field splitting */
128 return;
129 }
130
131 len_inputFS = len + 1;
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300132 inputFS = (char *) realloc(inputFS, len_inputFS);
zoulasc6a877092020-01-24 04:11:59 -0500133 if (inputFS == NULL)
Cody Peter Mellob4636802018-10-19 15:07:53 -0700134 FATAL("field separator %.10s... is too long", *FS);
zoulasc6a877092020-01-24 04:11:59 -0500135 memcpy(inputFS, *FS, len_inputFS);
Cody Peter Mellob4636802018-10-19 15:07:53 -0700136}
137
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200138static bool firsttime = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500139
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200140int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record */
Brian Kernighan87b94932012-12-22 10:35:39 -0500141{ /* note: cares whether buf == record */
142 int c;
143 char *buf = *pbuf;
144 uschar saveb0;
145 int bufsize = *pbufsize, savebufsize = bufsize;
146
147 if (firsttime) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200148 firsttime = false;
Brian Kernighan87b94932012-12-22 10:35:39 -0500149 initgetrec();
150 }
Todd C. Miller292d39f2020-06-25 12:32:34 -0600151 DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",
152 *RS, *FS, *ARGC, *FILENAME);
Brian Kernighan87b94932012-12-22 10:35:39 -0500153 if (isrecord) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200154 donefld = false;
155 donerec = true;
Cody Peter Mellob4636802018-10-19 15:07:53 -0700156 savefs();
Brian Kernighan87b94932012-12-22 10:35:39 -0500157 }
158 saveb0 = buf[0];
159 buf[0] = 0;
160 while (argno < *ARGC || infile == stdin) {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600161 DPRINTF("argno=%d, file=|%s|\n", argno, file);
Brian Kernighan87b94932012-12-22 10:35:39 -0500162 if (infile == NULL) { /* have to open a new file */
163 file = getargv(argno);
164 if (file == NULL || *file == '\0') { /* deleted or zapped */
165 argno++;
166 continue;
167 }
168 if (isclvar(file)) { /* a var=value arg */
169 setclvar(file);
170 argno++;
171 continue;
172 }
173 *FILENAME = file;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600174 DPRINTF("opening file %s\n", file);
Brian Kernighan87b94932012-12-22 10:35:39 -0500175 if (*file == '-' && *(file+1) == '\0')
176 infile = stdin;
177 else if ((infile = fopen(file, "r")) == NULL)
178 FATAL("can't open file %s", file);
179 setfval(fnrloc, 0.0);
180 }
zoulascffee7782020-02-28 06:23:54 -0500181 c = readrec(&buf, &bufsize, infile, innew);
182 if (innew)
183 innew = false;
Brian Kernighan87b94932012-12-22 10:35:39 -0500184 if (c != 0 || buf[0] != '\0') { /* normal record */
185 if (isrecord) {
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200186 double result;
187
Brian Kernighan87b94932012-12-22 10:35:39 -0500188 if (freeable(fldtab[0]))
189 xfree(fldtab[0]->sval);
190 fldtab[0]->sval = buf; /* buf == record */
191 fldtab[0]->tval = REC | STR | DONTFREE;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200192 if (is_number(fldtab[0]->sval, & result)) {
193 fldtab[0]->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500194 fldtab[0]->tval |= NUM;
195 }
196 }
197 setfval(nrloc, nrloc->fval+1);
198 setfval(fnrloc, fnrloc->fval+1);
199 *pbuf = buf;
200 *pbufsize = bufsize;
201 return 1;
202 }
203 /* EOF arrived on this file; set up next */
204 if (infile != stdin)
205 fclose(infile);
206 infile = NULL;
207 argno++;
208 }
209 buf[0] = saveb0;
210 *pbuf = buf;
211 *pbufsize = savebufsize;
212 return 0; /* true end of file */
213}
214
215void nextfile(void)
216{
217 if (infile != NULL && infile != stdin)
218 fclose(infile);
219 infile = NULL;
220 argno++;
221}
222
zoulascffee7782020-02-28 06:23:54 -0500223int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */
Brian Kernighan87b94932012-12-22 10:35:39 -0500224{
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300225 int sep, c, isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500226 char *rr, *buf = *pbuf;
227 int bufsize = *pbufsize;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700228 char *rs = getsval(rsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500229
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300230 if (*rs && rs[1]) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200231 bool found;
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300232
233 fa *pfa = makedfa(rs, 1);
zoulascffee7782020-02-28 06:23:54 -0500234 if (newflag)
235 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
236 else {
237 int tempstat = pfa->initstat;
238 pfa->initstat = 2;
239 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
240 pfa->initstat = tempstat;
241 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300242 if (found)
zoulasc65892082019-10-24 09:40:15 -0400243 setptr(patbeg, '\0');
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300244 } else {
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300245 if ((sep = *rs) == 0) {
246 sep = '\n';
247 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
248 ;
249 if (c != EOF)
250 ungetc(c, inf);
251 }
252 for (rr = buf; ; ) {
253 for (; (c=getc(inf)) != sep && c != EOF; ) {
254 if (rr-buf+1 > bufsize)
255 if (!adjbuf(&buf, &bufsize, 1+rr-buf,
256 recsize, &rr, "readrec 1"))
257 FATAL("input record `%.30s...' too long", buf);
258 *rr++ = c;
259 }
260 if (*rs == sep || c == EOF)
261 break;
262 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
263 break;
264 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
265 "readrec 2"))
266 FATAL("input record `%.30s...' too long", buf);
267 *rr++ = '\n';
Brian Kernighan87b94932012-12-22 10:35:39 -0500268 *rr++ = c;
269 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300270 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500271 FATAL("input record `%.30s...' too long", buf);
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300272 *rr = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -0500273 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500274 *pbuf = buf;
275 *pbufsize = bufsize;
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300276 isrec = *buf || !feof(inf);
Todd C. Miller292d39f2020-06-25 12:32:34 -0600277 DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300278 return isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500279}
280
281char *getargv(int n) /* get ARGV[n] */
282{
283 Cell *x;
284 char *s, temp[50];
285 extern Array *ARGVtab;
286
zoulasc0d8778b2019-10-25 10:59:10 -0400287 snprintf(temp, sizeof(temp), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -0500288 if (lookup(temp, ARGVtab) == NULL)
289 return NULL;
290 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
291 s = getsval(x);
Todd C. Miller292d39f2020-06-25 12:32:34 -0600292 DPRINTF("getargv(%d) returns |%s|\n", n, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500293 return s;
294}
295
296void setclvar(char *s) /* set var=value from s */
297{
298 char *p;
299 Cell *q;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200300 double result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500301
302 for (p=s; *p != '='; p++)
303 ;
304 *p++ = 0;
305 p = qstring(p, '\0');
306 q = setsymtab(s, p, 0.0, STR, symtab);
307 setsval(q, p);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200308 if (is_number(q->sval, & result)) {
309 q->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500310 q->tval |= NUM;
311 }
Todd C. Miller292d39f2020-06-25 12:32:34 -0600312 DPRINTF("command line set %s to |%s|\n", s, p);
Brian Kernighan87b94932012-12-22 10:35:39 -0500313}
314
315
316void fldbld(void) /* create fields from current record */
317{
318 /* this relies on having fields[] the same length as $0 */
319 /* the fields are all stored in this one array with \0's */
320 /* possibly with a final trailing \0 not associated with any field */
321 char *r, *fr, sep;
322 Cell *p;
323 int i, j, n;
324
325 if (donefld)
326 return;
327 if (!isstr(fldtab[0]))
328 getsval(fldtab[0]);
329 r = fldtab[0]->sval;
330 n = strlen(r);
331 if (n > fieldssize) {
332 xfree(fields);
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300333 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
Brian Kernighan87b94932012-12-22 10:35:39 -0500334 FATAL("out of space for fields in fldbld %d", n);
335 fieldssize = n;
336 }
337 fr = fields;
338 i = 0; /* number of fields accumulated here */
Arnold D. Robbins754cf932020-06-05 12:25:15 +0300339 if (inputFS == NULL) /* make sure we have a copy of FS */
340 savefs();
Brian Kernighan87b94932012-12-22 10:35:39 -0500341 if (strlen(inputFS) > 1) { /* it's a regular expression */
342 i = refldbld(r, inputFS);
343 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
344 for (i = 0; ; ) {
345 while (*r == ' ' || *r == '\t' || *r == '\n')
346 r++;
347 if (*r == 0)
348 break;
349 i++;
350 if (i > nfields)
351 growfldtab(i);
352 if (freeable(fldtab[i]))
353 xfree(fldtab[i]->sval);
354 fldtab[i]->sval = fr;
355 fldtab[i]->tval = FLD | STR | DONTFREE;
356 do
357 *fr++ = *r++;
358 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
359 *fr++ = 0;
360 }
361 *fr = 0;
362 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200363 for (i = 0; *r != '\0'; r += n) {
Michael Forney69325712020-01-30 22:23:34 -0800364 char buf[MB_LEN_MAX + 1];
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200365
Brian Kernighan87b94932012-12-22 10:35:39 -0500366 i++;
367 if (i > nfields)
368 growfldtab(i);
369 if (freeable(fldtab[i]))
370 xfree(fldtab[i]->sval);
Michael Forney69325712020-01-30 22:23:34 -0800371 n = mblen(r, MB_LEN_MAX);
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200372 if (n < 0)
373 n = 1;
374 memcpy(buf, r, n);
375 buf[n] = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500376 fldtab[i]->sval = tostring(buf);
377 fldtab[i]->tval = FLD | STR;
378 }
379 *fr = 0;
380 } else if (*r != 0) { /* if 0, it's a null field */
381 /* subtlecase : if length(FS) == 1 && length(RS > 0)
382 * \n is NOT a field separator (cf awk book 61,84).
383 * this variable is tested in the inner while loop.
384 */
385 int rtest = '\n'; /* normal case */
386 if (strlen(*RS) > 0)
387 rtest = '\0';
388 for (;;) {
389 i++;
390 if (i > nfields)
391 growfldtab(i);
392 if (freeable(fldtab[i]))
393 xfree(fldtab[i]->sval);
394 fldtab[i]->sval = fr;
395 fldtab[i]->tval = FLD | STR | DONTFREE;
396 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
397 *fr++ = *r++;
398 *fr++ = 0;
399 if (*r++ == 0)
400 break;
401 }
402 *fr = 0;
403 }
404 if (i > nfields)
405 FATAL("record `%.30s...' has too many fields; can't happen", r);
406 cleanfld(i+1, lastfld); /* clean out junk from previous record */
407 lastfld = i;
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200408 donefld = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500409 for (j = 1; j <= lastfld; j++) {
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200410 double result;
411
Brian Kernighan87b94932012-12-22 10:35:39 -0500412 p = fldtab[j];
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200413 if(is_number(p->sval, & result)) {
414 p->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500415 p->tval |= NUM;
416 }
417 }
418 setfval(nfloc, (Awkfloat) lastfld);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200419 donerec = true; /* restore */
Brian Kernighan87b94932012-12-22 10:35:39 -0500420 if (dbg) {
421 for (j = 0; j <= lastfld; j++) {
422 p = fldtab[j];
423 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
424 }
425 }
426}
427
428void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
429{ /* nvals remain intact */
430 Cell *p;
431 int i;
432
433 for (i = n1; i <= n2; i++) {
434 p = fldtab[i];
435 if (freeable(p))
436 xfree(p->sval);
zoulasc6a877092020-01-24 04:11:59 -0500437 p->sval = EMPTY,
Brian Kernighan87b94932012-12-22 10:35:39 -0500438 p->tval = FLD | STR | DONTFREE;
439 }
440}
441
442void newfld(int n) /* add field n after end of existing lastfld */
443{
444 if (n > nfields)
445 growfldtab(n);
446 cleanfld(lastfld+1, n);
447 lastfld = n;
448 setfval(nfloc, (Awkfloat) n);
449}
450
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300451void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
452{
Cody Peter Mello179536a2018-09-25 21:19:49 -0700453 if (n < 0)
454 FATAL("cannot set NF to a negative value");
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300455 if (n > nfields)
456 growfldtab(n);
457
458 if (lastfld < n)
459 cleanfld(lastfld+1, n);
460 else
461 cleanfld(n+1, lastfld);
462
463 lastfld = n;
464}
465
Brian Kernighan87b94932012-12-22 10:35:39 -0500466Cell *fieldadr(int n) /* get nth field */
467{
468 if (n < 0)
469 FATAL("trying to access out of range field %d", n);
470 if (n > nfields) /* fields after NF are empty */
471 growfldtab(n); /* but does not increase NF */
472 return(fldtab[n]);
473}
474
475void growfldtab(int n) /* make new fields up to at least $n */
476{
477 int nf = 2 * nfields;
478 size_t s;
479
480 if (n > nf)
481 nf = n;
482 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
zoulascc2c8ecb2020-02-19 13:44:49 -0500483 if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300484 fldtab = (Cell **) realloc(fldtab, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500485 else /* overflow sizeof int */
486 xfree(fldtab); /* make it null */
487 if (fldtab == NULL)
488 FATAL("out of space creating %d fields", nf);
489 makefields(nfields+1, nf);
490 nfields = nf;
491}
492
493int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
494{
495 /* this relies on having fields[] the same length as $0 */
496 /* the fields are all stored in this one array with \0's */
497 char *fr;
498 int i, tempstat, n;
499 fa *pfa;
500
501 n = strlen(rec);
502 if (n > fieldssize) {
503 xfree(fields);
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300504 if ((fields = (char *) malloc(n+1)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500505 FATAL("out of space for fields in refldbld %d", n);
506 fieldssize = n;
507 }
508 fr = fields;
509 *fr = '\0';
510 if (*rec == '\0')
511 return 0;
512 pfa = makedfa(fs, 1);
Todd C. Miller292d39f2020-06-25 12:32:34 -0600513 DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs);
Brian Kernighan87b94932012-12-22 10:35:39 -0500514 tempstat = pfa->initstat;
515 for (i = 1; ; i++) {
516 if (i > nfields)
517 growfldtab(i);
518 if (freeable(fldtab[i]))
519 xfree(fldtab[i]->sval);
520 fldtab[i]->tval = FLD | STR | DONTFREE;
521 fldtab[i]->sval = fr;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600522 DPRINTF("refldbld: i=%d\n", i);
Brian Kernighan87b94932012-12-22 10:35:39 -0500523 if (nematch(pfa, rec)) {
524 pfa->initstat = 2; /* horrible coupling to b.c */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600525 DPRINTF("match %s (%d chars)\n", patbeg, patlen);
Brian Kernighan87b94932012-12-22 10:35:39 -0500526 strncpy(fr, rec, patbeg-rec);
527 fr += patbeg - rec + 1;
528 *(fr-1) = '\0';
529 rec = patbeg + patlen;
530 } else {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600531 DPRINTF("no match %s\n", rec);
Brian Kernighan87b94932012-12-22 10:35:39 -0500532 strcpy(fr, rec);
533 pfa->initstat = tempstat;
534 break;
535 }
536 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600537 return i;
Brian Kernighan87b94932012-12-22 10:35:39 -0500538}
539
540void recbld(void) /* create $0 from $1..$NF if necessary */
541{
542 int i;
543 char *r, *p;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700544 char *sep = getsval(ofsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500545
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200546 if (donerec)
Brian Kernighan87b94932012-12-22 10:35:39 -0500547 return;
548 r = record;
549 for (i = 1; i <= *NF; i++) {
550 p = getsval(fldtab[i]);
551 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
552 FATAL("created $0 `%.30s...' too long", record);
553 while ((*r = *p++) != 0)
554 r++;
555 if (i < *NF) {
Cody Peter Mello52566c02018-09-18 15:45:55 -0700556 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500557 FATAL("created $0 `%.30s...' too long", record);
Cody Peter Mello52566c02018-09-18 15:45:55 -0700558 for (p = sep; (*r = *p++) != 0; )
Brian Kernighan87b94932012-12-22 10:35:39 -0500559 r++;
560 }
561 }
562 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
563 FATAL("built giant record `%.30s...'", record);
564 *r = '\0';
Todd C. Miller292d39f2020-06-25 12:32:34 -0600565 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500566
567 if (freeable(fldtab[0]))
568 xfree(fldtab[0]->sval);
569 fldtab[0]->tval = REC | STR | DONTFREE;
570 fldtab[0]->sval = record;
571
Todd C. Miller292d39f2020-06-25 12:32:34 -0600572 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
573 DPRINTF("recbld = |%s|\n", record);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200574 donerec = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500575}
576
577int errorflag = 0;
578
579void yyerror(const char *s)
580{
581 SYNTAX("%s", s);
582}
583
584void SYNTAX(const char *fmt, ...)
585{
586 extern char *cmdname, *curfname;
587 static int been_here = 0;
588 va_list varg;
589
590 if (been_here++ > 2)
591 return;
592 fprintf(stderr, "%s: ", cmdname);
593 va_start(varg, fmt);
594 vfprintf(stderr, fmt, varg);
595 va_end(varg);
596 fprintf(stderr, " at source line %d", lineno);
597 if (curfname != NULL)
598 fprintf(stderr, " in function %s", curfname);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200599 if (compile_time == COMPILING && cursource() != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500600 fprintf(stderr, " source file %s", cursource());
601 fprintf(stderr, "\n");
602 errorflag = 2;
603 eprint();
604}
605
Brian Kernighan87b94932012-12-22 10:35:39 -0500606extern int bracecnt, brackcnt, parencnt;
607
608void bracecheck(void)
609{
610 int c;
611 static int beenhere = 0;
612
613 if (beenhere++)
614 return;
615 while ((c = input()) != EOF && c != '\0')
616 bclass(c);
617 bcheck2(bracecnt, '{', '}');
618 bcheck2(brackcnt, '[', ']');
619 bcheck2(parencnt, '(', ')');
620}
621
622void bcheck2(int n, int c1, int c2)
623{
624 if (n == 1)
625 fprintf(stderr, "\tmissing %c\n", c2);
626 else if (n > 1)
627 fprintf(stderr, "\t%d missing %c's\n", n, c2);
628 else if (n == -1)
629 fprintf(stderr, "\textra %c\n", c2);
630 else if (n < -1)
631 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
632}
633
634void FATAL(const char *fmt, ...)
635{
636 extern char *cmdname;
637 va_list varg;
638
639 fflush(stdout);
640 fprintf(stderr, "%s: ", cmdname);
641 va_start(varg, fmt);
642 vfprintf(stderr, fmt, varg);
643 va_end(varg);
644 error();
645 if (dbg > 1) /* core dump if serious debugging on */
646 abort();
647 exit(2);
648}
649
650void WARNING(const char *fmt, ...)
651{
652 extern char *cmdname;
653 va_list varg;
654
655 fflush(stdout);
656 fprintf(stderr, "%s: ", cmdname);
657 va_start(varg, fmt);
658 vfprintf(stderr, fmt, varg);
659 va_end(varg);
660 error();
661}
662
663void error()
664{
665 extern Node *curnode;
666
667 fprintf(stderr, "\n");
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200668 if (compile_time != ERROR_PRINTING) {
669 if (NR && *NR > 0) {
670 fprintf(stderr, " input record number %d", (int) (*FNR));
671 if (strcmp(*FILENAME, "-") != 0)
672 fprintf(stderr, ", file %s", *FILENAME);
673 fprintf(stderr, "\n");
674 }
675 if (curnode)
676 fprintf(stderr, " source line number %d", curnode->lineno);
677 else if (lineno)
678 fprintf(stderr, " source line number %d", lineno);
Todd C. Millerfeb247a2020-12-03 10:30:36 -0700679 if (compile_time == COMPILING && cursource() != NULL)
680 fprintf(stderr, " source file %s", cursource());
681 fprintf(stderr, "\n");
682 eprint();
Brian Kernighan87b94932012-12-22 10:35:39 -0500683 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500684}
685
686void eprint(void) /* try to print context around error */
687{
688 char *p, *q;
689 int c;
690 static int been_here = 0;
691 extern char ebuf[], *ep;
692
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200693 if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
Brian Kernighan87b94932012-12-22 10:35:39 -0500694 return;
Brian Kernighan3ed9e242018-08-15 10:45:03 -0400695 if (ebuf == ep)
696 return;
Brian Kernighan87b94932012-12-22 10:35:39 -0500697 p = ep - 1;
698 if (p > ebuf && *p == '\n')
699 p--;
700 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
701 ;
702 while (*p == '\n')
703 p++;
704 fprintf(stderr, " context is\n\t");
705 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
706 ;
707 for ( ; p < q; p++)
708 if (*p)
709 putc(*p, stderr);
710 fprintf(stderr, " >>> ");
711 for ( ; p < ep; p++)
712 if (*p)
713 putc(*p, stderr);
714 fprintf(stderr, " <<< ");
715 if (*ep)
716 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
717 putc(c, stderr);
718 bclass(c);
719 }
720 putc('\n', stderr);
721 ep = ebuf;
722}
723
724void bclass(int c)
725{
726 switch (c) {
727 case '{': bracecnt++; break;
728 case '}': bracecnt--; break;
729 case '[': brackcnt++; break;
730 case ']': brackcnt--; break;
731 case '(': parencnt++; break;
732 case ')': parencnt--; break;
733 }
734}
735
736double errcheck(double x, const char *s)
737{
738
739 if (errno == EDOM) {
740 errno = 0;
741 WARNING("%s argument out of domain", s);
742 x = 1;
743 } else if (errno == ERANGE) {
744 errno = 0;
745 WARNING("%s result out of range", s);
746 x = 1;
747 }
748 return x;
749}
750
751int isclvar(const char *s) /* is s of form var=something ? */
752{
753 const char *os = s;
754
755 if (!isalpha((uschar) *s) && *s != '_')
756 return 0;
757 for ( ; *s; s++)
758 if (!(isalnum((uschar) *s) || *s == '_'))
759 break;
Arnold D. Robbins4189ef52019-05-29 21:04:18 +0300760 return *s == '=' && s > os;
Brian Kernighan87b94932012-12-22 10:35:39 -0500761}
762
763/* strtod is supposed to be a proper test of what's a valid number */
764/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
765/* wrong: violates 4.10.1.4 of ansi C standard */
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200766
Arnold D. Robbinscef51802020-06-12 14:30:03 +0300767/* well, not quite. As of C99, hex floating point is allowed. so this is
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200768 * a bit of a mess. We work around the mess by checking for a hexadecimal
769 * value and disallowing it. Similarly, we now follow gawk and allow only
770 * +nan, -nan, +inf, and -inf for NaN and infinity values.
Arnold D. Robbinscef51802020-06-12 14:30:03 +0300771 */
Brian Kernighan87b94932012-12-22 10:35:39 -0500772
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200773/*
774 * This routine now has a more complicated interface, the main point
775 * being to avoid the double conversion of a string to double, and
776 * also to convey out, if requested, the information that the numeric
777 * value was a leading string or is all of the string. The latter bit
778 * is used in getfval().
779 */
780
781bool is_valid_number(const char *s, bool trailing_stuff_ok,
782 bool *no_trailing, double *result)
Brian Kernighan87b94932012-12-22 10:35:39 -0500783{
784 double r;
785 char *ep;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200786 bool retval = false;
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200787 bool is_nan = false;
788 bool is_inf = false;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200789
790 if (no_trailing)
791 *no_trailing = false;
792
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200793 while (isspace(*s))
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200794 s++;
795
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200796 // no hex floating point, sorry
797 if (s[0] == '0' && tolower(s[1]) == 'x')
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200798 return false;
799
800 // allow +nan, -nan, +inf, -inf, any other letter, no
801 if (s[0] == '+' || s[0] == '-') {
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200802 is_nan = (strncasecmp(s+1, "nan", 3) == 0);
803 is_inf = (strncasecmp(s+1, "inf", 3) == 0);
804 if ((is_nan || is_inf)
805 && (isspace(s[4]) || s[4] == '\0'))
806 goto convert;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200807 else if (! isdigit(s[1]) && s[1] != '.')
808 return false;
809 }
810 else if (! isdigit(s[0]) && s[0] != '.')
811 return false;
812
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200813convert:
Brian Kernighan87b94932012-12-22 10:35:39 -0500814 errno = 0;
815 r = strtod(s, &ep);
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200816 if (ep == s || errno == ERANGE)
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200817 return false;
818
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200819 if (isnan(r) && s[0] == '-' && signbit(r) == 0)
820 r = -r;
821
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200822 if (result != NULL)
823 *result = r;
824
ozan s. yigit1fd5fa32021-01-06 18:37:48 -0500825 /*
826 * check for trailing stuff
827 */
828 while (isspace(*ep))
829 ep++;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200830
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200831 if (no_trailing != NULL)
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200832 *no_trailing = (*ep == '\0');
833
ozan s. yigit1fd5fa32021-01-06 18:37:48 -0500834 // return true if found the end, or trailing stuff is allowed
835 retval = *ep == '\0' || trailing_stuff_ok;
836
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200837 return retval;
Brian Kernighan87b94932012-12-22 10:35:39 -0500838}