Bug Summary

File:src/usr.bin/awk/lib.c
Warning:line 343, column 14
Although the value stored to 'sep' is used in the enclosing expression, the value is never actually read from 'sep'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name lib.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.bin/awk/obj -resource-dir /usr/local/lib/clang/13.0.0 -I . -I /usr/src/usr.bin/awk -D HAS_ISBLANK -D NDEBUG -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.bin/awk/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.bin/awk/lib.c
1/* $OpenBSD: lib.c,v 1.47 2021/11/02 15:29:41 millert Exp $ */
2/****************************************************************
3Copyright (C) Lucent Technologies 1997
4All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and
7its documentation for any purpose and without fee is hereby
8granted, provided that the above copyright notice appear in all
9copies and that both that the copyright notice and this
10permission notice and warranty disclaimer appear in supporting
11documentation, and that the name Lucent Technologies or any of
12its entities not be used in advertising or publicity pertaining
13to distribution of the software without specific, written prior
14permission.
15
16LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23THIS SOFTWARE.
24****************************************************************/
25
26#define DEBUG
27#include <stdio.h>
28#include <string.h>
29#include <ctype.h>
30#include <errno(*__errno()).h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <limits.h>
34#include <math.h>
35#include "awk.h"
36
37char EMPTY[] = { '\0' };
38FILE *infile = NULL((void *)0);
39bool_Bool innew; /* true = infile has not been read by readrec */
40char *file = EMPTY;
41char *record;
42int recsize = RECSIZE(8 * 1024);
43char *fields;
44int fieldssize = RECSIZE(8 * 1024);
45
46Cell **fldtab; /* pointers to Cells */
47static size_t len_inputFS = 0;
48static char *inputFS = NULL((void *)0); /* FS at time of input, for field splitting */
49
50#define MAXFLD2 2
51int nfields = MAXFLD2; /* last allocated slot for $i */
52
53bool_Bool donefld; /* true = implies rec broken into fields */
54bool_Bool donerec; /* true = record is valid (no flds have changed) */
55
56int lastfld = 0; /* last used field */
57int argno = 1; /* current input argument number */
58extern Awkfloat *ARGC;
59
60static Cell dollar0 = { OCELL1, CFLD1, NULL((void *)0), EMPTY, 0.0, REC0200|STR02|DONTFREE04, NULL((void *)0), NULL((void *)0) };
61static Cell dollar1 = { OCELL1, CFLD1, NULL((void *)0), EMPTY, 0.0, FLD0100|STR02|DONTFREE04, NULL((void *)0), NULL((void *)0) };
62
63void recinit(unsigned int n)
64{
65 if ( (record = (char *) malloc(n)) == NULL((void *)0)
66 || (fields = (char *) malloc(n+1)) == NULL((void *)0)
67 || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL((void *)0)
68 || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL((void *)0))
69 FATAL("out of space for $0 and fields");
70 *record = '\0';
71 *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++) {
83 fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
84 if (fldtab[i] == NULL((void *)0))
85 FATAL("out of space in makefields %d", i);
86 *fldtab[i] = dollar1;
87 snprintf(temp, sizeof(temp), "%d", i);
88 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((void *)0) || *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(&__sF[0]); /* no filenames, so use stdin */
111 innew = true1;
112}
113
114/*
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{
125 size_t len = strlen(getsval(fsloc));
126 if (len >= len_inputFS) {
127 len_inputFS = len + 1;
128 inputFS = (char *) realloc(inputFS, len_inputFS);
129 if (inputFS == NULL((void *)0))
130 FATAL("field separator %.10s... is too long", *FS);
131 }
132 if (strlcpy(inputFS, *FS, len_inputFS) >= len_inputFS)
133 FATAL("field separator %.10s... is too long", *FS);
134}
135
136static bool_Bool firsttime = true1;
137
138int getrec(char **pbuf, int *pbufsize, bool_Bool isrecord) /* get next input record */
139{ /* note: cares whether buf == record */
140 int c;
141 char *buf = *pbuf;
142 uschar saveb0;
143 int bufsize = *pbufsize, savebufsize = bufsize;
144
145 if (firsttime) {
146 firsttime = false0;
147 initgetrec();
148 }
149 DPRINTF("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n",if (dbg) printf("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n"
, *RS, *FS, *ARGC, *FILENAME)
150 *RS, *FS, *ARGC, *FILENAME)if (dbg) printf("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n"
, *RS, *FS, *ARGC, *FILENAME)
;
151 if (isrecord) {
152 donefld = false0;
153 donerec = true1;
154 savefs();
155 }
156 saveb0 = buf[0];
157 buf[0] = 0;
158 while (argno < *ARGC || infile == stdin(&__sF[0])) {
159 DPRINTF("argno=%d, file=|%s|\n", argno, file)if (dbg) printf("argno=%d, file=|%s|\n", argno, file);
160 if (infile == NULL((void *)0)) { /* have to open a new file */
161 file = getargv(argno);
162 if (file == NULL((void *)0) || *file == '\0') { /* deleted or zapped */
163 argno++;
164 continue;
165 }
166 if (isclvar(file)) { /* a var=value arg */
167 setclvar(file);
168 argno++;
169 continue;
170 }
171 *FILENAME = file;
172 DPRINTF("opening file %s\n", file)if (dbg) printf("opening file %s\n", file);
173 if (*file == '-' && *(file+1) == '\0')
174 infile = stdin(&__sF[0]);
175 else if ((infile = fopen(file, "r")) == NULL((void *)0))
176 FATAL("can't open file %s", file);
177 innew = true1;
178 setfval(fnrloc, 0.0);
179 }
180 c = readrec(&buf, &bufsize, infile, innew);
181 if (innew)
182 innew = false0;
183 if (c != 0 || buf[0] != '\0') { /* normal record */
184 if (isrecord) {
185 double result;
186
187 if (freeable(fldtab[0])( ((fldtab[0])->tval & (02|04)) == 02 ))
188 xfree(fldtab[0]->sval){ if ((fldtab[0]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[0]->sval)); (fldtab[0]->sval) = ((void *)0); }
}
;
189 fldtab[0]->sval = buf; /* buf == record */
190 fldtab[0]->tval = REC0200 | STR02 | DONTFREE04;
191 if (is_number(fldtab[0]->sval, & result)is_valid_number(fldtab[0]->sval, 0, ((void *)0), & result
)
) {
192 fldtab[0]->fval = result;
193 fldtab[0]->tval |= NUM01;
194 }
195 }
196 setfval(nrloc, nrloc->fval+1);
197 setfval(fnrloc, fnrloc->fval+1);
198 *pbuf = buf;
199 *pbufsize = bufsize;
200 return 1;
201 }
202 /* EOF arrived on this file; set up next */
203 if (infile != stdin(&__sF[0]))
204 fclose(infile);
205 infile = NULL((void *)0);
206 argno++;
207 }
208 buf[0] = saveb0;
209 *pbuf = buf;
210 *pbufsize = savebufsize;
211 return 0; /* true end of file */
212}
213
214void nextfile(void)
215{
216 if (infile != NULL((void *)0) && infile != stdin(&__sF[0]))
217 fclose(infile);
218 infile = NULL((void *)0);
219 argno++;
220}
221
222int readrec(char **pbuf, int *pbufsize, FILE *inf, bool_Bool newflag) /* read one record into buf */
223{
224 int sep, c, isrec;
225 char *rr, *buf = *pbuf;
226 int bufsize = *pbufsize;
227 char *rs = getsval(rsloc);
228
229 if (*rs && rs[1]) {
230 bool_Bool found;
231
232 fa *pfa = makedfa(rs, 1);
233 if (newflag)
234 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
235 else {
236 int tempstat = pfa->initstat;
237 pfa->initstat = 2;
238 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
239 pfa->initstat = tempstat;
240 }
241 if (found)
242 setptr(patbeg, '\0')(*(char *)(intptr_t)(patbeg)) = ('\0');
243 isrec = (found == 0 && *buf == '\0') ? 0 : 1;
244 } else {
245 if ((sep = *rs) == 0) {
246 sep = '\n';
247 while ((c=getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) == '\n' && c != EOF(-1)) /* skip leading \n's */
248 ;
249 if (c != EOF(-1))
250 ungetc(c, inf);
251 }
252 for (rr = buf; ; ) {
253 for (; (c=getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) != sep && c != EOF(-1); ) {
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(-1))
261 break;
262 if ((c = getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) == '\n' || c == EOF(-1)) /* 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';
268 *rr++ = c;
269 }
270 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
271 FATAL("input record `%.30s...' too long", buf);
272 *rr = 0;
273 isrec = (c == EOF(-1) && rr == buf) ? 0 : 1;
274 }
275 *pbuf = buf;
276 *pbufsize = bufsize;
277 DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec)if (dbg) printf("readrec saw <%s>, returns %d\n", buf, isrec
)
;
278 return isrec;
279}
280
281char *getargv(int n) /* get ARGV[n] */
282{
283 Cell *x;
284 char *s, temp[50];
285 extern Array *ARGVtab;
286
287 snprintf(temp, sizeof(temp), "%d", n);
288 if (lookup(temp, ARGVtab) == NULL((void *)0))
289 return NULL((void *)0);
290 x = setsymtab(temp, "", 0.0, STR02, ARGVtab);
291 s = getsval(x);
292 DPRINTF("getargv(%d) returns |%s|\n", n, s)if (dbg) printf("getargv(%d) returns |%s|\n", n, s);
293 return s;
294}
295
296void setclvar(char *s) /* set var=value from s */
297{
298 char *p;
299 Cell *q;
300 double result;
301
302 for (p=s; *p != '='; p++)
303 ;
304 *p++ = 0;
305 p = qstring(p, '\0');
306 q = setsymtab(s, p, 0.0, STR02, symtab);
307 setsval(q, p);
308 if (is_number(q->sval, & result)is_valid_number(q->sval, 0, ((void *)0), & result)) {
309 q->fval = result;
310 q->tval |= NUM01;
311 }
312 DPRINTF("command line set %s to |%s|\n", s, p)if (dbg) printf("command line set %s to |%s|\n", s, p);
313}
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])((fldtab[0])->tval & 02))
328 getsval(fldtab[0]);
329 r = fldtab[0]->sval;
330 n = strlen(r);
331 if (n > fieldssize) {
332 xfree(fields){ if ((fields) != ((void *)0)) { free((void *)(intptr_t)(fields
)); (fields) = ((void *)0); } }
;
333 if ((fields = (char *) malloc(n+2)) == NULL((void *)0)) /* possibly 2 final \0s */
334 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 */
339 if (inputFS == NULL((void *)0)) /* make sure we have a copy of FS */
340 savefs();
341 if (strlen(inputFS) > 1) { /* it's a regular expression */
342 i = refldbld(r, inputFS);
343 } else if ((sep = *inputFS) == ' ') { /* default whitespace */
Although the value stored to 'sep' is used in the enclosing expression, the value is never actually read from 'sep'
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])( ((fldtab[i])->tval & (02|04)) == 02 ))
353 xfree(fldtab[i]->sval){ if ((fldtab[i]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[i]->sval)); (fldtab[i]->sval) = ((void *)0); }
}
;
354 fldtab[i]->sval = fr;
355 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
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 */
363 for (i = 0; *r != '\0'; r += n) {
364 char buf[MB_LEN_MAX4 + 1];
365
366 i++;
367 if (i > nfields)
368 growfldtab(i);
369 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
370 xfree(fldtab[i]->sval){ if ((fldtab[i]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[i]->sval)); (fldtab[i]->sval) = ((void *)0); }
}
;
371 n = mblen(r, MB_LEN_MAX4);
372 if (n < 0)
373 n = 1;
374 memcpy(buf, r, n);
375 buf[n] = '\0';
376 fldtab[i]->sval = tostring(buf);
377 fldtab[i]->tval = FLD0100 | STR02;
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])( ((fldtab[i])->tval & (02|04)) == 02 ))
393 xfree(fldtab[i]->sval){ if ((fldtab[i]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[i]->sval)); (fldtab[i]->sval) = ((void *)0); }
}
;
394 fldtab[i]->sval = fr;
395 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
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;
408 donefld = true1;
409 for (j = 1; j <= lastfld; j++) {
410 double result;
411
412 p = fldtab[j];
413 if(is_number(p->sval, & result)is_valid_number(p->sval, 0, ((void *)0), & result)) {
414 p->fval = result;
415 p->tval |= NUM01;
416 }
417 }
418 setfval(nfloc, (Awkfloat) lastfld);
419 donerec = true1; /* restore */
420 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)( ((p)->tval & (02|04)) == 02 ))
436 xfree(p->sval){ if ((p->sval) != ((void *)0)) { free((void *)(intptr_t)(
p->sval)); (p->sval) = ((void *)0); } }
;
437 p->sval = EMPTY,
438 p->tval = FLD0100 | STR02 | DONTFREE04;
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
451void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
452{
453 if (n < 0)
454 FATAL("cannot set NF to a negative value");
455 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
466Cell *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? */
483 if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
484 fldtab = (Cell **) realloc(fldtab, s);
485 else /* overflow sizeof int */
486 xfree(fldtab){ if ((fldtab) != ((void *)0)) { free((void *)(intptr_t)(fldtab
)); (fldtab) = ((void *)0); } }
; /* make it null */
487 if (fldtab == NULL((void *)0))
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){ if ((fields) != ((void *)0)) { free((void *)(intptr_t)(fields
)); (fields) = ((void *)0); } }
;
504 if ((fields = (char *) malloc(n+1)) == NULL((void *)0))
505 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);
513 DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)if (dbg) printf("into refldbld, rec = <%s>, pat = <%s>\n"
, rec, fs)
;
514 tempstat = pfa->initstat;
515 for (i = 1; ; i++) {
516 const size_t fss_rem = fields + fieldssize + 1 - fr;
517 if (i > nfields)
518 growfldtab(i);
519 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
520 xfree(fldtab[i]->sval){ if ((fldtab[i]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[i]->sval)); (fldtab[i]->sval) = ((void *)0); }
}
;
521 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
522 fldtab[i]->sval = fr;
523 DPRINTF("refldbld: i=%d\n", i)if (dbg) printf("refldbld: i=%d\n", i);
524 if (nematch(pfa, rec)) {
525 const size_t reclen = patbeg - rec;
526 pfa->initstat = 2; /* horrible coupling to b.c */
527 DPRINTF("match %s (%d chars)\n", patbeg, patlen)if (dbg) printf("match %s (%d chars)\n", patbeg, patlen);
528 if (reclen >= fss_rem)
529 FATAL("out of space for fields in refldbld");
530 memcpy(fr, rec, reclen);
531 fr += reclen;
532 *fr++ = '\0';
533 rec = patbeg + patlen;
534 } else {
535 DPRINTF("no match %s\n", rec)if (dbg) printf("no match %s\n", rec);
536 if (strlcpy(fr, rec, fss_rem) >= fss_rem)
537 FATAL("out of space for fields in refldbld");
538 pfa->initstat = tempstat;
539 break;
540 }
541 }
542 return i;
543}
544
545void recbld(void) /* create $0 from $1..$NF if necessary */
546{
547 int i;
548 char *r, *p;
549 char *sep = getsval(ofsloc);
550
551 if (donerec)
552 return;
553 r = record;
554 for (i = 1; i <= *NF; i++) {
555 p = getsval(fldtab[i]);
556 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
557 FATAL("created $0 `%.30s...' too long", record);
558 while ((*r = *p++) != 0)
559 r++;
560 if (i < *NF) {
561 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
562 FATAL("created $0 `%.30s...' too long", record);
563 for (p = sep; (*r = *p++) != 0; )
564 r++;
565 }
566 }
567 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
568 FATAL("built giant record `%.30s...'", record);
569 *r = '\0';
570 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0])if (dbg) printf("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, (void*)fldtab[0])
;
571
572 if (freeable(fldtab[0])( ((fldtab[0])->tval & (02|04)) == 02 ))
573 xfree(fldtab[0]->sval){ if ((fldtab[0]->sval) != ((void *)0)) { free((void *)(intptr_t
)(fldtab[0]->sval)); (fldtab[0]->sval) = ((void *)0); }
}
;
574 fldtab[0]->tval = REC0200 | STR02 | DONTFREE04;
575 fldtab[0]->sval = record;
576
577 DPRINTF("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS, (void*)fldtab[0])if (dbg) printf("in recbld inputFS=%s, fldtab[0]=%p\n", inputFS
, (void*)fldtab[0])
;
578 DPRINTF("recbld = |%s|\n", record)if (dbg) printf("recbld = |%s|\n", record);
579 donerec = true1;
580}
581
582int errorflag = 0;
583
584void yyerror(const char *s)
585{
586 SYNTAX("%s", s);
587}
588
589void SYNTAX(const char *fmt, ...)
590{
591 extern char *cmdname, *curfname;
592 static int been_here = 0;
593 va_list varg;
594
595 if (been_here++ > 2)
596 return;
597 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
598 va_start(varg, fmt)__builtin_va_start(varg, fmt);
599 vfprintf(stderr(&__sF[2]), fmt, varg);
600 va_end(varg)__builtin_va_end(varg);
601 fprintf(stderr(&__sF[2]), " at source line %d", lineno);
602 if (curfname != NULL((void *)0))
603 fprintf(stderr(&__sF[2]), " in function %s", curfname);
604 if (compile_time == COMPILING && cursource() != NULL((void *)0))
605 fprintf(stderr(&__sF[2]), " source file %s", cursource());
606 fprintf(stderr(&__sF[2]), "\n");
607 errorflag = 2;
608 eprint();
609}
610
611extern int bracecnt, brackcnt, parencnt;
612
613void bracecheck(void)
614{
615 int c;
616 static int beenhere = 0;
617
618 if (beenhere++)
619 return;
620 while ((c = input()) != EOF(-1) && c != '\0')
621 bclass(c);
622 bcheck2(bracecnt, '{', '}');
623 bcheck2(brackcnt, '[', ']');
624 bcheck2(parencnt, '(', ')');
625}
626
627void bcheck2(int n, int c1, int c2)
628{
629 if (n == 1)
630 fprintf(stderr(&__sF[2]), "\tmissing %c\n", c2);
631 else if (n > 1)
632 fprintf(stderr(&__sF[2]), "\t%d missing %c's\n", n, c2);
633 else if (n == -1)
634 fprintf(stderr(&__sF[2]), "\textra %c\n", c2);
635 else if (n < -1)
636 fprintf(stderr(&__sF[2]), "\t%d extra %c's\n", -n, c2);
637}
638
639void FATAL(const char *fmt, ...)
640{
641 extern char *cmdname;
642 va_list varg;
643
644 fflush(stdout(&__sF[1]));
645 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
646 va_start(varg, fmt)__builtin_va_start(varg, fmt);
647 vfprintf(stderr(&__sF[2]), fmt, varg);
648 va_end(varg)__builtin_va_end(varg);
649 error();
650 if (dbg > 1) /* core dump if serious debugging on */
651 abort();
652 exit(2);
653}
654
655void WARNING(const char *fmt, ...)
656{
657 extern char *cmdname;
658 va_list varg;
659
660 fflush(stdout(&__sF[1]));
661 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
662 va_start(varg, fmt)__builtin_va_start(varg, fmt);
663 vfprintf(stderr(&__sF[2]), fmt, varg);
664 va_end(varg)__builtin_va_end(varg);
665 error();
666}
667
668void error()
669{
670 extern Node *curnode;
671
672 fprintf(stderr(&__sF[2]), "\n");
673 if (compile_time != ERROR_PRINTING) {
674 if (NR && *NR > 0) {
675 fprintf(stderr(&__sF[2]), " input record number %d", (int) (*FNR));
676 if (strcmp(*FILENAME, "-") != 0)
677 fprintf(stderr(&__sF[2]), ", file %s", *FILENAME);
678 fprintf(stderr(&__sF[2]), "\n");
679 }
680 if (curnode)
681 fprintf(stderr(&__sF[2]), " source line number %d", curnode->lineno);
682 else if (lineno)
683 fprintf(stderr(&__sF[2]), " source line number %d", lineno);
684 if (compile_time == COMPILING && cursource() != NULL((void *)0))
685 fprintf(stderr(&__sF[2]), " source file %s", cursource());
686 fprintf(stderr(&__sF[2]), "\n");
687 eprint();
688 }
689}
690
691void eprint(void) /* try to print context around error */
692{
693 char *p, *q;
694 int c;
695 static int been_here = 0;
696 extern char ebuf[], *ep;
697
698 if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
699 return;
700 p = ep - 1;
701 if (p > ebuf && *p == '\n')
702 p--;
703 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
704 ;
705 while (*p == '\n')
706 p++;
707 fprintf(stderr(&__sF[2]), " context is\n\t");
708 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
709 ;
710 for ( ; p < q; p++)
711 if (*p)
712 putc(*p, stderr)(!__isthreaded ? __sputc(*p, (&__sF[2])) : (putc)(*p, (&
__sF[2])))
;
713 fprintf(stderr(&__sF[2]), " >>> ");
714 for ( ; p < ep; p++)
715 if (*p)
716 putc(*p, stderr)(!__isthreaded ? __sputc(*p, (&__sF[2])) : (putc)(*p, (&
__sF[2])))
;
717 fprintf(stderr(&__sF[2]), " <<< ");
718 if (*ep)
719 while ((c = input()) != '\n' && c != '\0' && c != EOF(-1)) {
720 putc(c, stderr)(!__isthreaded ? __sputc(c, (&__sF[2])) : (putc)(c, (&
__sF[2])))
;
721 bclass(c);
722 }
723 putc('\n', stderr)(!__isthreaded ? __sputc('\n', (&__sF[2])) : (putc)('\n',
(&__sF[2])))
;
724 ep = ebuf;
725}
726
727void bclass(int c)
728{
729 switch (c) {
730 case '{': bracecnt++; break;
731 case '}': bracecnt--; break;
732 case '[': brackcnt++; break;
733 case ']': brackcnt--; break;
734 case '(': parencnt++; break;
735 case ')': parencnt--; break;
736 }
737}
738
739double errcheck(double x, const char *s)
740{
741
742 if (errno(*__errno()) == EDOM33) {
743 errno(*__errno()) = 0;
744 WARNING("%s argument out of domain", s);
745 x = 1;
746 } else if (errno(*__errno()) == ERANGE34) {
747 errno(*__errno()) = 0;
748 WARNING("%s result out of range", s);
749 x = 1;
750 }
751 return x;
752}
753
754int isclvar(const char *s) /* is s of form var=something ? */
755{
756 const char *os = s;
757
758 if (!isalpha((uschar) *s) && *s != '_')
759 return 0;
760 for ( ; *s; s++)
761 if (!(isalnum((uschar) *s) || *s == '_'))
762 break;
763 return *s == '=' && s > os;
764}
765
766/* strtod is supposed to be a proper test of what's a valid number */
767/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
768/* wrong: violates 4.10.1.4 of ansi C standard */
769
770/* well, not quite. As of C99, hex floating point is allowed. so this is
771 * a bit of a mess. We work around the mess by checking for a hexadecimal
772 * value and disallowing it. Similarly, we now follow gawk and allow only
773 * +nan, -nan, +inf, and -inf for NaN and infinity values.
774 */
775
776/*
777 * This routine now has a more complicated interface, the main point
778 * being to avoid the double conversion of a string to double, and
779 * also to convey out, if requested, the information that the numeric
780 * value was a leading string or is all of the string. The latter bit
781 * is used in getfval().
782 */
783
784bool_Bool is_valid_number(const char *s, bool_Bool trailing_stuff_ok,
785 bool_Bool *no_trailing, double *result)
786{
787 double r;
788 char *ep;
789 bool_Bool retval = false0;
790 bool_Bool is_nan = false0;
791 bool_Bool is_inf = false0;
792
793 if (no_trailing)
794 *no_trailing = false0;
795
796 while (isspace((uschar)*s))
797 s++;
798
799 // no hex floating point, sorry
800 if (s[0] == '0' && tolower((uschar)s[1]) == 'x')
801 return false0;
802
803 // allow +nan, -nan, +inf, -inf, any other letter, no
804 if (s[0] == '+' || s[0] == '-') {
805 is_nan = (strncasecmp(s+1, "nan", 3) == 0);
806 is_inf = (strncasecmp(s+1, "inf", 3) == 0);
807 if ((is_nan || is_inf)
808 && (isspace((uschar)s[4]) || s[4] == '\0'))
809 goto convert;
810 else if (! isdigit((uschar)s[1]) && s[1] != '.')
811 return false0;
812 }
813 else if (! isdigit((uschar)s[0]) && s[0] != '.')
814 return false0;
815
816convert:
817 errno(*__errno()) = 0;
818 r = strtod(s, &ep);
819 if (ep == s || errno(*__errno()) == ERANGE34)
820 return false0;
821
822 if (isnan(r)((sizeof (r) == sizeof (float)) ? __isnanf(r) : (sizeof (r) ==
sizeof (double)) ? __isnan(r) : __isnanl(r))
&& s[0] == '-' && signbit(r)((sizeof (r) == sizeof (float)) ? __signbitf(r) : (sizeof (r)
== sizeof (double)) ? __signbit(r) : __signbitl(r))
== 0)
823 r = -r;
824
825 if (result != NULL((void *)0))
826 *result = r;
827
828 /*
829 * check for trailing stuff
830 */
831 while (isspace((uschar)*ep))
832 ep++;
833
834 if (no_trailing != NULL((void *)0))
835 *no_trailing = (*ep == '\0');
836
837 // return true if found the end, or trailing stuff is allowed
838 retval = *ep == '\0' || trailing_stuff_ok;
839
840 return retval;
841}