blob: c7709f798f6e60a4e54a80d8fa51663d26351348 [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);
Miguel Pineiro Jrfeaf62d2021-04-16 20:31:36 -0400179 innew = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500180 setfval(fnrloc, 0.0);
181 }
zoulascffee7782020-02-28 06:23:54 -0500182 c = readrec(&buf, &bufsize, infile, innew);
183 if (innew)
184 innew = false;
Brian Kernighan87b94932012-12-22 10:35:39 -0500185 if (c != 0 || buf[0] != '\0') { /* normal record */
186 if (isrecord) {
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200187 double result;
188
Brian Kernighan87b94932012-12-22 10:35:39 -0500189 if (freeable(fldtab[0]))
190 xfree(fldtab[0]->sval);
191 fldtab[0]->sval = buf; /* buf == record */
192 fldtab[0]->tval = REC | STR | DONTFREE;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200193 if (is_number(fldtab[0]->sval, & result)) {
194 fldtab[0]->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500195 fldtab[0]->tval |= NUM;
196 }
197 }
198 setfval(nrloc, nrloc->fval+1);
199 setfval(fnrloc, fnrloc->fval+1);
200 *pbuf = buf;
201 *pbufsize = bufsize;
202 return 1;
203 }
204 /* EOF arrived on this file; set up next */
205 if (infile != stdin)
206 fclose(infile);
207 infile = NULL;
208 argno++;
209 }
210 buf[0] = saveb0;
211 *pbuf = buf;
212 *pbufsize = savebufsize;
213 return 0; /* true end of file */
214}
215
216void nextfile(void)
217{
218 if (infile != NULL && infile != stdin)
219 fclose(infile);
220 infile = NULL;
221 argno++;
222}
223
zoulascffee7782020-02-28 06:23:54 -0500224int readrec(char **pbuf, int *pbufsize, FILE *inf, bool newflag) /* read one record into buf */
Brian Kernighan87b94932012-12-22 10:35:39 -0500225{
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300226 int sep, c, isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500227 char *rr, *buf = *pbuf;
228 int bufsize = *pbufsize;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700229 char *rs = getsval(rsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500230
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300231 if (*rs && rs[1]) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200232 bool found;
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300233
234 fa *pfa = makedfa(rs, 1);
zoulascffee7782020-02-28 06:23:54 -0500235 if (newflag)
236 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
237 else {
238 int tempstat = pfa->initstat;
239 pfa->initstat = 2;
240 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
241 pfa->initstat = tempstat;
242 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300243 if (found)
zoulasc65892082019-10-24 09:40:15 -0400244 setptr(patbeg, '\0');
ozan yigitaa8731e2021-07-25 14:37:03 -0400245 isrec = (found == 0 && *buf == '\0') ? false : true;
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300246 } else {
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300247 if ((sep = *rs) == 0) {
248 sep = '\n';
249 while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */
250 ;
251 if (c != EOF)
252 ungetc(c, inf);
253 }
254 for (rr = buf; ; ) {
255 for (; (c=getc(inf)) != sep && c != EOF; ) {
256 if (rr-buf+1 > bufsize)
257 if (!adjbuf(&buf, &bufsize, 1+rr-buf,
258 recsize, &rr, "readrec 1"))
259 FATAL("input record `%.30s...' too long", buf);
260 *rr++ = c;
261 }
262 if (*rs == sep || c == EOF)
263 break;
264 if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */
265 break;
266 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
267 "readrec 2"))
268 FATAL("input record `%.30s...' too long", buf);
269 *rr++ = '\n';
Brian Kernighan87b94932012-12-22 10:35:39 -0500270 *rr++ = c;
271 }
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300272 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500273 FATAL("input record `%.30s...' too long", buf);
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300274 *rr = 0;
ozan yigitaa8731e2021-07-25 14:37:03 -0400275 isrec = (c == EOF && rr == buf) ? false : true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500276 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500277 *pbuf = buf;
278 *pbufsize = bufsize;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600279 DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec);
Arnold D. Robbins643a5a32019-07-28 20:12:05 +0300280 return isrec;
Brian Kernighan87b94932012-12-22 10:35:39 -0500281}
282
283char *getargv(int n) /* get ARGV[n] */
284{
285 Cell *x;
286 char *s, temp[50];
287 extern Array *ARGVtab;
288
zoulasc0d8778b2019-10-25 10:59:10 -0400289 snprintf(temp, sizeof(temp), "%d", n);
Brian Kernighan87b94932012-12-22 10:35:39 -0500290 if (lookup(temp, ARGVtab) == NULL)
291 return NULL;
292 x = setsymtab(temp, "", 0.0, STR, ARGVtab);
293 s = getsval(x);
Todd C. Miller292d39f2020-06-25 12:32:34 -0600294 DPRINTF("getargv(%d) returns |%s|\n", n, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500295 return s;
296}
297
298void setclvar(char *s) /* set var=value from s */
299{
300 char *p;
301 Cell *q;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200302 double result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500303
304 for (p=s; *p != '='; p++)
305 ;
306 *p++ = 0;
307 p = qstring(p, '\0');
308 q = setsymtab(s, p, 0.0, STR, symtab);
309 setsval(q, p);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200310 if (is_number(q->sval, & result)) {
311 q->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500312 q->tval |= NUM;
313 }
Todd C. Miller292d39f2020-06-25 12:32:34 -0600314 DPRINTF("command line set %s to |%s|\n", s, p);
Brian Kernighan87b94932012-12-22 10:35:39 -0500315}
316
317
318void fldbld(void) /* create fields from current record */
319{
320 /* this relies on having fields[] the same length as $0 */
321 /* the fields are all stored in this one array with \0's */
322 /* possibly with a final trailing \0 not associated with any field */
323 char *r, *fr, sep;
324 Cell *p;
325 int i, j, n;
326
327 if (donefld)
328 return;
329 if (!isstr(fldtab[0]))
330 getsval(fldtab[0]);
331 r = fldtab[0]->sval;
332 n = strlen(r);
333 if (n > fieldssize) {
334 xfree(fields);
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300335 if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
Brian Kernighan87b94932012-12-22 10:35:39 -0500336 FATAL("out of space for fields in fldbld %d", n);
337 fieldssize = n;
338 }
339 fr = fields;
340 i = 0; /* number of fields accumulated here */
Arnold D. Robbins754cf932020-06-05 12:25:15 +0300341 if (inputFS == NULL) /* make sure we have a copy of FS */
342 savefs();
Brian Kernighan87b94932012-12-22 10:35:39 -0500343 if (strlen(inputFS) > 1) { /* it's a regular expression */
344 i = refldbld(r, inputFS);
345 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
346 for (i = 0; ; ) {
347 while (*r == ' ' || *r == '\t' || *r == '\n')
348 r++;
349 if (*r == 0)
350 break;
351 i++;
352 if (i > nfields)
353 growfldtab(i);
354 if (freeable(fldtab[i]))
355 xfree(fldtab[i]->sval);
356 fldtab[i]->sval = fr;
357 fldtab[i]->tval = FLD | STR | DONTFREE;
358 do
359 *fr++ = *r++;
360 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
361 *fr++ = 0;
362 }
363 *fr = 0;
364 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200365 for (i = 0; *r != '\0'; r += n) {
Michael Forney69325712020-01-30 22:23:34 -0800366 char buf[MB_LEN_MAX + 1];
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200367
Brian Kernighan87b94932012-12-22 10:35:39 -0500368 i++;
369 if (i > nfields)
370 growfldtab(i);
371 if (freeable(fldtab[i]))
372 xfree(fldtab[i]->sval);
Michael Forney69325712020-01-30 22:23:34 -0800373 n = mblen(r, MB_LEN_MAX);
Arnold D. Robbinsc879fbf2019-11-08 14:40:18 +0200374 if (n < 0)
375 n = 1;
376 memcpy(buf, r, n);
377 buf[n] = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500378 fldtab[i]->sval = tostring(buf);
379 fldtab[i]->tval = FLD | STR;
380 }
381 *fr = 0;
382 } else if (*r != 0) { /* if 0, it's a null field */
383 /* subtlecase : if length(FS) == 1 && length(RS > 0)
384 * \n is NOT a field separator (cf awk book 61,84).
385 * this variable is tested in the inner while loop.
386 */
387 int rtest = '\n'; /* normal case */
388 if (strlen(*RS) > 0)
389 rtest = '\0';
390 for (;;) {
391 i++;
392 if (i > nfields)
393 growfldtab(i);
394 if (freeable(fldtab[i]))
395 xfree(fldtab[i]->sval);
396 fldtab[i]->sval = fr;
397 fldtab[i]->tval = FLD | STR | DONTFREE;
398 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
399 *fr++ = *r++;
400 *fr++ = 0;
401 if (*r++ == 0)
402 break;
403 }
404 *fr = 0;
405 }
406 if (i > nfields)
407 FATAL("record `%.30s...' has too many fields; can't happen", r);
408 cleanfld(i+1, lastfld); /* clean out junk from previous record */
409 lastfld = i;
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200410 donefld = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500411 for (j = 1; j <= lastfld; j++) {
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200412 double result;
413
Brian Kernighan87b94932012-12-22 10:35:39 -0500414 p = fldtab[j];
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200415 if(is_number(p->sval, & result)) {
416 p->fval = result;
Brian Kernighan87b94932012-12-22 10:35:39 -0500417 p->tval |= NUM;
418 }
419 }
420 setfval(nfloc, (Awkfloat) lastfld);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200421 donerec = true; /* restore */
Brian Kernighan87b94932012-12-22 10:35:39 -0500422 if (dbg) {
423 for (j = 0; j <= lastfld; j++) {
424 p = fldtab[j];
425 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
426 }
427 }
428}
429
430void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
431{ /* nvals remain intact */
432 Cell *p;
433 int i;
434
435 for (i = n1; i <= n2; i++) {
436 p = fldtab[i];
437 if (freeable(p))
438 xfree(p->sval);
zoulasc6a877092020-01-24 04:11:59 -0500439 p->sval = EMPTY,
Brian Kernighan87b94932012-12-22 10:35:39 -0500440 p->tval = FLD | STR | DONTFREE;
441 }
442}
443
444void newfld(int n) /* add field n after end of existing lastfld */
445{
446 if (n > nfields)
447 growfldtab(n);
448 cleanfld(lastfld+1, n);
449 lastfld = n;
450 setfval(nfloc, (Awkfloat) n);
451}
452
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300453void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
454{
Cody Peter Mello179536a2018-09-25 21:19:49 -0700455 if (n < 0)
456 FATAL("cannot set NF to a negative value");
Arnold D. Robbins32093f52018-08-22 20:40:26 +0300457 if (n > nfields)
458 growfldtab(n);
459
460 if (lastfld < n)
461 cleanfld(lastfld+1, n);
462 else
463 cleanfld(n+1, lastfld);
464
465 lastfld = n;
466}
467
Brian Kernighan87b94932012-12-22 10:35:39 -0500468Cell *fieldadr(int n) /* get nth field */
469{
470 if (n < 0)
471 FATAL("trying to access out of range field %d", n);
472 if (n > nfields) /* fields after NF are empty */
473 growfldtab(n); /* but does not increase NF */
474 return(fldtab[n]);
475}
476
477void growfldtab(int n) /* make new fields up to at least $n */
478{
479 int nf = 2 * nfields;
480 size_t s;
481
482 if (n > nf)
483 nf = n;
484 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
zoulascc2c8ecb2020-02-19 13:44:49 -0500485 if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300486 fldtab = (Cell **) realloc(fldtab, s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500487 else /* overflow sizeof int */
488 xfree(fldtab); /* make it null */
489 if (fldtab == NULL)
490 FATAL("out of space creating %d fields", nf);
491 makefields(nfields+1, nf);
492 nfields = nf;
493}
494
495int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
496{
497 /* this relies on having fields[] the same length as $0 */
498 /* the fields are all stored in this one array with \0's */
499 char *fr;
500 int i, tempstat, n;
501 fa *pfa;
502
503 n = strlen(rec);
504 if (n > fieldssize) {
505 xfree(fields);
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300506 if ((fields = (char *) malloc(n+1)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500507 FATAL("out of space for fields in refldbld %d", n);
508 fieldssize = n;
509 }
510 fr = fields;
511 *fr = '\0';
512 if (*rec == '\0')
513 return 0;
514 pfa = makedfa(fs, 1);
Todd C. Miller292d39f2020-06-25 12:32:34 -0600515 DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs);
Brian Kernighan87b94932012-12-22 10:35:39 -0500516 tempstat = pfa->initstat;
517 for (i = 1; ; i++) {
518 if (i > nfields)
519 growfldtab(i);
520 if (freeable(fldtab[i]))
521 xfree(fldtab[i]->sval);
522 fldtab[i]->tval = FLD | STR | DONTFREE;
523 fldtab[i]->sval = fr;
Todd C. Miller292d39f2020-06-25 12:32:34 -0600524 DPRINTF("refldbld: i=%d\n", i);
Brian Kernighan87b94932012-12-22 10:35:39 -0500525 if (nematch(pfa, rec)) {
526 pfa->initstat = 2; /* horrible coupling to b.c */
Todd C. Miller292d39f2020-06-25 12:32:34 -0600527 DPRINTF("match %s (%d chars)\n", patbeg, patlen);
Brian Kernighan87b94932012-12-22 10:35:39 -0500528 strncpy(fr, rec, patbeg-rec);
529 fr += patbeg - rec + 1;
530 *(fr-1) = '\0';
531 rec = patbeg + patlen;
532 } else {
Todd C. Miller292d39f2020-06-25 12:32:34 -0600533 DPRINTF("no match %s\n", rec);
Brian Kernighan87b94932012-12-22 10:35:39 -0500534 strcpy(fr, rec);
535 pfa->initstat = tempstat;
536 break;
537 }
538 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600539 return i;
Brian Kernighan87b94932012-12-22 10:35:39 -0500540}
541
542void recbld(void) /* create $0 from $1..$NF if necessary */
543{
544 int i;
545 char *r, *p;
Cody Peter Mello52566c02018-09-18 15:45:55 -0700546 char *sep = getsval(ofsloc);
Brian Kernighan87b94932012-12-22 10:35:39 -0500547
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200548 if (donerec)
Brian Kernighan87b94932012-12-22 10:35:39 -0500549 return;
550 r = record;
551 for (i = 1; i <= *NF; i++) {
552 p = getsval(fldtab[i]);
553 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
554 FATAL("created $0 `%.30s...' too long", record);
555 while ((*r = *p++) != 0)
556 r++;
557 if (i < *NF) {
Cody Peter Mello52566c02018-09-18 15:45:55 -0700558 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
Brian Kernighan87b94932012-12-22 10:35:39 -0500559 FATAL("created $0 `%.30s...' too long", record);
Cody Peter Mello52566c02018-09-18 15:45:55 -0700560 for (p = sep; (*r = *p++) != 0; )
Brian Kernighan87b94932012-12-22 10:35:39 -0500561 r++;
562 }
563 }
564 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
565 FATAL("built giant record `%.30s...'", record);
566 *r = '\0';
Todd C. Miller292d39f2020-06-25 12:32:34 -0600567 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
Brian Kernighan87b94932012-12-22 10:35:39 -0500568
569 if (freeable(fldtab[0]))
570 xfree(fldtab[0]->sval);
571 fldtab[0]->tval = REC | STR | DONTFREE;
572 fldtab[0]->sval = record;
573
Todd C. Miller292d39f2020-06-25 12:32:34 -0600574 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0]);
575 DPRINTF("recbld = |%s|\n", record);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200576 donerec = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500577}
578
579int errorflag = 0;
580
581void yyerror(const char *s)
582{
583 SYNTAX("%s", s);
584}
585
586void SYNTAX(const char *fmt, ...)
587{
588 extern char *cmdname, *curfname;
589 static int been_here = 0;
590 va_list varg;
591
592 if (been_here++ > 2)
593 return;
594 fprintf(stderr, "%s: ", cmdname);
595 va_start(varg, fmt);
596 vfprintf(stderr, fmt, varg);
597 va_end(varg);
598 fprintf(stderr, " at source line %d", lineno);
599 if (curfname != NULL)
600 fprintf(stderr, " in function %s", curfname);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200601 if (compile_time == COMPILING && cursource() != NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500602 fprintf(stderr, " source file %s", cursource());
603 fprintf(stderr, "\n");
604 errorflag = 2;
605 eprint();
606}
607
Brian Kernighan87b94932012-12-22 10:35:39 -0500608extern int bracecnt, brackcnt, parencnt;
609
610void bracecheck(void)
611{
612 int c;
613 static int beenhere = 0;
614
615 if (beenhere++)
616 return;
617 while ((c = input()) != EOF && c != '\0')
618 bclass(c);
619 bcheck2(bracecnt, '{', '}');
620 bcheck2(brackcnt, '[', ']');
621 bcheck2(parencnt, '(', ')');
622}
623
624void bcheck2(int n, int c1, int c2)
625{
626 if (n == 1)
627 fprintf(stderr, "\tmissing %c\n", c2);
628 else if (n > 1)
629 fprintf(stderr, "\t%d missing %c's\n", n, c2);
630 else if (n == -1)
631 fprintf(stderr, "\textra %c\n", c2);
632 else if (n < -1)
633 fprintf(stderr, "\t%d extra %c's\n", -n, c2);
634}
635
636void FATAL(const char *fmt, ...)
637{
638 extern char *cmdname;
639 va_list varg;
640
641 fflush(stdout);
642 fprintf(stderr, "%s: ", cmdname);
643 va_start(varg, fmt);
644 vfprintf(stderr, fmt, varg);
645 va_end(varg);
646 error();
647 if (dbg > 1) /* core dump if serious debugging on */
648 abort();
649 exit(2);
650}
651
652void WARNING(const char *fmt, ...)
653{
654 extern char *cmdname;
655 va_list varg;
656
657 fflush(stdout);
658 fprintf(stderr, "%s: ", cmdname);
659 va_start(varg, fmt);
660 vfprintf(stderr, fmt, varg);
661 va_end(varg);
662 error();
663}
664
665void error()
666{
667 extern Node *curnode;
668
669 fprintf(stderr, "\n");
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200670 if (compile_time != ERROR_PRINTING) {
671 if (NR && *NR > 0) {
672 fprintf(stderr, " input record number %d", (int) (*FNR));
673 if (strcmp(*FILENAME, "-") != 0)
674 fprintf(stderr, ", file %s", *FILENAME);
675 fprintf(stderr, "\n");
676 }
677 if (curnode)
678 fprintf(stderr, " source line number %d", curnode->lineno);
679 else if (lineno)
680 fprintf(stderr, " source line number %d", lineno);
Todd C. Millerfeb247a2020-12-03 10:30:36 -0700681 if (compile_time == COMPILING && cursource() != NULL)
682 fprintf(stderr, " source file %s", cursource());
683 fprintf(stderr, "\n");
684 eprint();
Brian Kernighan87b94932012-12-22 10:35:39 -0500685 }
Brian Kernighan87b94932012-12-22 10:35:39 -0500686}
687
688void eprint(void) /* try to print context around error */
689{
690 char *p, *q;
691 int c;
692 static int been_here = 0;
693 extern char ebuf[], *ep;
694
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200695 if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
Brian Kernighan87b94932012-12-22 10:35:39 -0500696 return;
Brian Kernighan3ed9e242018-08-15 10:45:03 -0400697 if (ebuf == ep)
698 return;
Brian Kernighan87b94932012-12-22 10:35:39 -0500699 p = ep - 1;
700 if (p > ebuf && *p == '\n')
701 p--;
702 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
703 ;
704 while (*p == '\n')
705 p++;
706 fprintf(stderr, " context is\n\t");
707 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
708 ;
709 for ( ; p < q; p++)
710 if (*p)
711 putc(*p, stderr);
712 fprintf(stderr, " >>> ");
713 for ( ; p < ep; p++)
714 if (*p)
715 putc(*p, stderr);
716 fprintf(stderr, " <<< ");
717 if (*ep)
718 while ((c = input()) != '\n' && c != '\0' && c != EOF) {
719 putc(c, stderr);
720 bclass(c);
721 }
722 putc('\n', stderr);
723 ep = ebuf;
724}
725
726void bclass(int c)
727{
728 switch (c) {
729 case '{': bracecnt++; break;
730 case '}': bracecnt--; break;
731 case '[': brackcnt++; break;
732 case ']': brackcnt--; break;
733 case '(': parencnt++; break;
734 case ')': parencnt--; break;
735 }
736}
737
738double errcheck(double x, const char *s)
739{
740
741 if (errno == EDOM) {
742 errno = 0;
743 WARNING("%s argument out of domain", s);
744 x = 1;
745 } else if (errno == ERANGE) {
746 errno = 0;
747 WARNING("%s result out of range", s);
748 x = 1;
749 }
750 return x;
751}
752
753int isclvar(const char *s) /* is s of form var=something ? */
754{
755 const char *os = s;
756
757 if (!isalpha((uschar) *s) && *s != '_')
758 return 0;
759 for ( ; *s; s++)
760 if (!(isalnum((uschar) *s) || *s == '_'))
761 break;
Arnold D. Robbins4189ef52019-05-29 21:04:18 +0300762 return *s == '=' && s > os;
Brian Kernighan87b94932012-12-22 10:35:39 -0500763}
764
765/* strtod is supposed to be a proper test of what's a valid number */
766/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
767/* wrong: violates 4.10.1.4 of ansi C standard */
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200768
Arnold D. Robbinscef51802020-06-12 14:30:03 +0300769/* well, not quite. As of C99, hex floating point is allowed. so this is
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200770 * a bit of a mess. We work around the mess by checking for a hexadecimal
771 * value and disallowing it. Similarly, we now follow gawk and allow only
772 * +nan, -nan, +inf, and -inf for NaN and infinity values.
Arnold D. Robbinscef51802020-06-12 14:30:03 +0300773 */
Brian Kernighan87b94932012-12-22 10:35:39 -0500774
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200775/*
776 * This routine now has a more complicated interface, the main point
777 * being to avoid the double conversion of a string to double, and
778 * also to convey out, if requested, the information that the numeric
779 * value was a leading string or is all of the string. The latter bit
780 * is used in getfval().
781 */
782
783bool is_valid_number(const char *s, bool trailing_stuff_ok,
784 bool *no_trailing, double *result)
Brian Kernighan87b94932012-12-22 10:35:39 -0500785{
786 double r;
787 char *ep;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200788 bool retval = false;
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200789 bool is_nan = false;
790 bool is_inf = false;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200791
792 if (no_trailing)
793 *no_trailing = false;
794
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200795 while (isspace(*s))
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200796 s++;
797
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200798 // no hex floating point, sorry
799 if (s[0] == '0' && tolower(s[1]) == 'x')
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200800 return false;
801
802 // allow +nan, -nan, +inf, -inf, any other letter, no
803 if (s[0] == '+' || s[0] == '-') {
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200804 is_nan = (strncasecmp(s+1, "nan", 3) == 0);
805 is_inf = (strncasecmp(s+1, "inf", 3) == 0);
806 if ((is_nan || is_inf)
807 && (isspace(s[4]) || s[4] == '\0'))
808 goto convert;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200809 else if (! isdigit(s[1]) && s[1] != '.')
810 return false;
811 }
812 else if (! isdigit(s[0]) && s[0] != '.')
813 return false;
814
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200815convert:
Brian Kernighan87b94932012-12-22 10:35:39 -0500816 errno = 0;
817 r = strtod(s, &ep);
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200818 if (ep == s || errno == ERANGE)
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200819 return false;
820
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200821 if (isnan(r) && s[0] == '-' && signbit(r) == 0)
822 r = -r;
823
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200824 if (result != NULL)
825 *result = r;
826
ozan s. yigit1fd5fa32021-01-06 18:37:48 -0500827 /*
828 * check for trailing stuff
829 */
830 while (isspace(*ep))
831 ep++;
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200832
Arnold D. Robbins8909e002020-12-18 11:57:48 +0200833 if (no_trailing != NULL)
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200834 *no_trailing = (*ep == '\0');
835
ozan s. yigit1fd5fa32021-01-06 18:37:48 -0500836 // return true if found the end, or trailing stuff is allowed
837 retval = *ep == '\0' || trailing_stuff_ok;
838
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200839 return retval;
Brian Kernighan87b94932012-12-22 10:35:39 -0500840}