Bug Summary

File:src/usr.bin/awk/lib.c
Warning:line 401, column 22
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.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name lib.c -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 -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -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/llvm16/lib/clang/16 -I . -I /usr/src/usr.bin/awk -D HAS_ISBLANK -D NDEBUG -internal-isystem /usr/local/llvm16/lib/clang/16/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 -fcf-protection=branch -fno-jump-tables -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/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.bin/awk/lib.c
1/* $OpenBSD: lib.c,v 1.55 2023/11/28 20:54:38 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 <strings.h>
30#include <ctype.h>
31#include <errno(*__errno()).h>
32#include <stdlib.h>
33#include <stdarg.h>
34#include <limits.h>
35#include <math.h>
36#include "awk.h"
37
38extern int u8_nextlen(const char *s);
39
40char EMPTY[] = { '\0' };
41FILE *infile = NULL((void *)0);
42bool_Bool innew; /* true = infile has not been read by readrec */
43char *file = EMPTY;
44char *record;
45int recsize = RECSIZE(8 * 1024);
46char *fields;
47int fieldssize = RECSIZE(8 * 1024);
48
49Cell **fldtab; /* pointers to Cells */
50static size_t len_inputFS = 0;
51static char *inputFS = NULL((void *)0); /* FS at time of input, for field splitting */
52
53#define MAXFLD2 2
54int nfields = MAXFLD2; /* last allocated slot for $i */
55
56bool_Bool donefld; /* true = implies rec broken into fields */
57bool_Bool donerec; /* true = record is valid (no flds have changed) */
58
59int lastfld = 0; /* last used field */
60int argno = 1; /* current input argument number */
61extern Awkfloat *ARGC;
62
63static Cell dollar0 = { OCELL1, CFLD1, NULL((void *)0), EMPTY, 0.0, REC0200|STR02|DONTFREE04, NULL((void *)0), NULL((void *)0) };
64static Cell dollar1 = { OCELL1, CFLD1, NULL((void *)0), EMPTY, 0.0, FLD0100|STR02|DONTFREE04, NULL((void *)0), NULL((void *)0) };
65
66void recinit(unsigned int n)
67{
68 if ( (record = (char *) malloc(n)) == NULL((void *)0)
69 || (fields = (char *) malloc(n+1)) == NULL((void *)0)
70 || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL((void *)0)
71 || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL((void *)0))
72 FATAL("out of space for $0 and fields");
73 *record = '\0';
74 *fldtab[0] = dollar0;
75 fldtab[0]->sval = record;
76 fldtab[0]->nval = tostring("0");
77 makefields(1, nfields);
78}
79
80void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
81{
82 char temp[50];
83 int i;
84
85 for (i = n1; i <= n2; i++) {
86 fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
87 if (fldtab[i] == NULL((void *)0))
88 FATAL("out of space in makefields %d", i);
89 *fldtab[i] = dollar1;
90 snprintf(temp, sizeof(temp), "%d", i);
91 fldtab[i]->nval = tostring(temp);
92 }
93}
94
95void initgetrec(void)
96{
97 int i;
98 char *p;
99
100 for (i = 1; i < *ARGC; i++) {
101 p = getargv(i); /* find 1st real filename */
102 if (p == NULL((void *)0) || *p == '\0') { /* deleted or zapped */
103 argno++;
104 continue;
105 }
106 if (!isclvar(p)) {
107 setsval(lookup("FILENAME", symtab), p);
108 return;
109 }
110 setclvar(p); /* a commandline assignment before filename */
111 argno++;
112 }
113 infile = stdin(&__sF[0]); /* no filenames, so use stdin */
114 innew = true1;
115}
116
117/*
118 * POSIX specifies that fields are supposed to be evaluated as if they were
119 * split using the value of FS at the time that the record's value ($0) was
120 * read.
121 *
122 * Since field-splitting is done lazily, we save the current value of FS
123 * whenever a new record is read in (implicitly or via getline), or when
124 * a new value is assigned to $0.
125 */
126void savefs(void)
127{
128 size_t len = strlen(getsval(fsloc));
129 if (len >= len_inputFS) {
130 len_inputFS = len + 1;
131 inputFS = (char *) realloc(inputFS, len_inputFS);
132 if (inputFS == NULL((void *)0))
133 FATAL("field separator %.10s... is too long", *FS);
134 }
135 if (strlcpy(inputFS, *FS, len_inputFS) >= len_inputFS)
136 FATAL("field separator %.10s... is too long", *FS);
137}
138
139static bool_Bool firsttime = true1;
140
141int getrec(char **pbuf, int *pbufsize, bool_Bool isrecord) /* get next input record */
142{ /* note: cares whether buf == record */
143 int c;
144 char *buf = *pbuf;
145 uschar saveb0;
146 int bufsize = *pbufsize, savebufsize = bufsize;
147
148 if (firsttime) {
149 firsttime = false0;
150 initgetrec();
151 }
152 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)
153 *RS, *FS, *ARGC, *FILENAME)if (dbg) printf("RS=<%s>, FS=<%s>, ARGC=%g, FILENAME=%s\n"
, *RS, *FS, *ARGC, *FILENAME)
;
154 saveb0 = buf[0];
155 buf[0] = 0;
156 while (argno < *ARGC || infile == stdin(&__sF[0])) {
157 DPRINTF("argno=%d, file=|%s|\n", argno, file)if (dbg) printf("argno=%d, file=|%s|\n", argno, file);
158 if (infile == NULL((void *)0)) { /* have to open a new file */
159 file = getargv(argno);
160 if (file == NULL((void *)0) || *file == '\0') { /* deleted or zapped */
161 argno++;
162 continue;
163 }
164 if (isclvar(file)) { /* a var=value arg */
165 setclvar(file);
166 argno++;
167 continue;
168 }
169 *FILENAME = file;
170 DPRINTF("opening file %s\n", file)if (dbg) printf("opening file %s\n", file);
171 if (*file == '-' && *(file+1) == '\0')
172 infile = stdin(&__sF[0]);
173 else if ((infile = fopen(file, "r")) == NULL((void *)0))
174 FATAL("can't open file %s", file);
175 innew = true1;
176 setfval(fnrloc, 0.0);
177 }
178 c = readrec(&buf, &bufsize, infile, innew);
179 if (innew)
180 innew = false0;
181 if (c != 0 || buf[0] != '\0') { /* normal record */
182 if (isrecord) {
183 double result;
184
185 if (freeable(fldtab[0])( ((fldtab[0])->tval & (02|04)) == 02 ))
186 xfree(fldtab[0]->sval){ free((void *)(intptr_t)(fldtab[0]->sval)); (fldtab[0]->
sval) = ((void *)0); }
;
187 fldtab[0]->sval = buf; /* buf == record */
188 fldtab[0]->tval = REC0200 | STR02 | DONTFREE04;
189 if (is_number(fldtab[0]->sval, & result)is_valid_number(fldtab[0]->sval, 0, ((void *)0), & result
)
) {
190 fldtab[0]->fval = result;
191 fldtab[0]->tval |= NUM01;
192 }
193 donefld = false0;
194 donerec = true1;
195 savefs();
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(&__sF[0]))
205 fclose(infile);
206 infile = NULL((void *)0);
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((void *)0) && infile != stdin(&__sF[0]))
218 fclose(infile);
219 infile = NULL((void *)0);
220 argno++;
221}
222
223extern int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool_Bool newflag);
224
225int readrec(char **pbuf, int *pbufsize, FILE *inf, bool_Bool newflag) /* read one record into buf */
226{
227 int sep, c, isrec; // POTENTIAL BUG? isrec is a macro in awk.h
228 char *rr = *pbuf, *buf = *pbuf;
229 int bufsize = *pbufsize;
230 char *rs = getsval(rsloc);
231
232 if (CSV) {
233 c = readcsvrec(pbuf, pbufsize, inf, newflag);
234 isrec = (c == EOF(-1) && rr == buf) ? false0 : true1;
235 } else if (*rs && rs[1]) {
236 bool_Bool found;
237
238 memset(buf, 0, bufsize);
239 fa *pfa = makedfa(rs, 1);
240 if (newflag)
241 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
242 else {
243 int tempstat = pfa->initstat;
244 pfa->initstat = 2;
245 found = fnematch(pfa, inf, &buf, &bufsize, recsize);
246 pfa->initstat = tempstat;
247 }
248 if (found)
249 setptr(patbeg, '\0')(*(char *)(intptr_t)(patbeg)) = ('\0');
250 isrec = (found == 0 && *buf == '\0') ? false0 : true1;
251 } else {
252 if ((sep = *rs) == 0) {
253 sep = '\n';
254 while ((c=getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) == '\n' && c != EOF(-1)) /* skip leading \n's */
255 ;
256 if (c != EOF(-1))
257 ungetc(c, inf);
258 }
259 for (rr = buf; ; ) {
260 for (; (c=getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) != sep && c != EOF(-1); ) {
261 if (rr-buf+1 > bufsize)
262 if (!adjbuf(&buf, &bufsize, 1+rr-buf,
263 recsize, &rr, "readrec 1"))
264 FATAL("input record `%.30s...' too long", buf);
265 *rr++ = c;
266 }
267 if (*rs == sep || c == EOF(-1))
268 break;
269 if ((c = getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) == '\n' || c == EOF(-1)) /* 2 in a row */
270 break;
271 if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr,
272 "readrec 2"))
273 FATAL("input record `%.30s...' too long", buf);
274 *rr++ = '\n';
275 *rr++ = c;
276 }
277 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3"))
278 FATAL("input record `%.30s...' too long", buf);
279 *rr = 0;
280 isrec = (c == EOF(-1) && rr == buf) ? false0 : true1;
281 }
282 *pbuf = buf;
283 *pbufsize = bufsize;
284 DPRINTF("readrec saw <%s>, returns %d\n", buf, isrec)if (dbg) printf("readrec saw <%s>, returns %d\n", buf, isrec
)
;
285 return isrec;
286}
287
288
289/*******************
290 * loose ends here:
291 * \r\n should become \n
292 * what about bare \r? Excel uses that for embedded newlines
293 * can't have "" in unquoted fields, according to RFC 4180
294*/
295
296int readcsvrec(char **pbuf, int *pbufsize, FILE *inf, bool_Bool newflag) /* csv can have \n's */
297{ /* so read a complete record that might be multiple lines */
298 int sep, c;
299 char *rr = *pbuf, *buf = *pbuf;
300 int bufsize = *pbufsize;
301 bool_Bool in_quote = false0;
302
303 sep = '\n'; /* the only separator; have to skip over \n embedded in "..." */
304 rr = buf;
305 while ((c = getc(inf)(!__isthreaded ? (--(inf)->_r < 0 ? __srget(inf) : (int
)(*(inf)->_p++)) : (getc)(inf))
) != EOF(-1)) {
306 if (c == sep) {
307 if (! in_quote)
308 break;
309 if (rr > buf && rr[-1] == '\r') // remove \r if was \r\n
310 rr--;
311 }
312
313 if (rr-buf+1 > bufsize)
314 if (!adjbuf(&buf, &bufsize, 1+rr-buf,
315 recsize, &rr, "readcsvrec 1"))
316 FATAL("input record `%.30s...' too long", buf);
317 *rr++ = c;
318 if (c == '"')
319 in_quote = ! in_quote;
320 }
321 if (c == '\n' && rr > buf && rr[-1] == '\r') // remove \r if was \r\n
322 rr--;
323
324 if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readcsvrec 4"))
325 FATAL("input record `%.30s...' too long", buf);
326 *rr = 0;
327 *pbuf = buf;
328 *pbufsize = bufsize;
329 DPRINTF("readcsvrec saw <%s>, returns %d\n", buf, c)if (dbg) printf("readcsvrec saw <%s>, returns %d\n", buf
, c)
;
330 return c;
331}
332
333char *getargv(int n) /* get ARGV[n] */
334{
335 Cell *x;
336 char *s, temp[50];
337 extern Array *ARGVtab;
338
339 snprintf(temp, sizeof(temp), "%d", n);
340 if (lookup(temp, ARGVtab) == NULL((void *)0))
341 return NULL((void *)0);
342 x = setsymtab(temp, "", 0.0, STR02, ARGVtab);
343 s = getsval(x);
344 DPRINTF("getargv(%d) returns |%s|\n", n, s)if (dbg) printf("getargv(%d) returns |%s|\n", n, s);
345 return s;
346}
347
348void setclvar(char *s) /* set var=value from s */
349{
350 char *e, *p;
351 Cell *q;
352 double result;
353
354/* commit f3d9187d4e0f02294fb1b0e31152070506314e67 broke T.argv test */
355/* I don't understand why it was changed. */
356
357 for (p=s; *p != '='; p++)
358 ;
359 e = p;
360 *p++ = 0;
361 p = qstring(p, '\0');
362 q = setsymtab(s, p, 0.0, STR02, symtab);
363 setsval(q, p);
364 if (is_number(q->sval, & result)is_valid_number(q->sval, 0, ((void *)0), & result)) {
365 q->fval = result;
366 q->tval |= NUM01;
367 }
368 DPRINTF("command line set %s to |%s|\n", s, p)if (dbg) printf("command line set %s to |%s|\n", s, p);
369 free(p);
370 *e = '=';
371}
372
373
374void fldbld(void) /* create fields from current record */
375{
376 /* this relies on having fields[] the same length as $0 */
377 /* the fields are all stored in this one array with \0's */
378 /* possibly with a final trailing \0 not associated with any field */
379 char *r, *fr, sep;
380 Cell *p;
381 int i, j, n;
382
383 if (donefld)
384 return;
385 if (!isstr(fldtab[0])((fldtab[0])->tval & 02))
386 getsval(fldtab[0]);
387 r = fldtab[0]->sval;
388 n = strlen(r);
389 if (n > fieldssize) {
390 xfree(fields){ free((void *)(intptr_t)(fields)); (fields) = ((void *)0); };
391 if ((fields = (char *) malloc(n+2)) == NULL((void *)0)) /* possibly 2 final \0s */
392 FATAL("out of space for fields in fldbld %d", n);
393 fieldssize = n;
394 }
395 fr = fields;
396 i = 0; /* number of fields accumulated here */
397 if (inputFS == NULL((void *)0)) /* make sure we have a copy of FS */
398 savefs();
399 if (!CSV && strlen(inputFS) > 1) { /* it's a regular expression */
400 i = refldbld(r, inputFS);
401 } else if (!CSV && (sep = *inputFS) == ' ') { /* default whitespace */
Although the value stored to 'sep' is used in the enclosing expression, the value is never actually read from 'sep'
402 for (i = 0; ; ) {
403 while (*r == ' ' || *r == '\t' || *r == '\n')
404 r++;
405 if (*r == 0)
406 break;
407 i++;
408 if (i > nfields)
409 growfldtab(i);
410 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
411 xfree(fldtab[i]->sval){ free((void *)(intptr_t)(fldtab[i]->sval)); (fldtab[i]->
sval) = ((void *)0); }
;
412 fldtab[i]->sval = fr;
413 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
414 do
415 *fr++ = *r++;
416 while (*r != ' ' && *r != '\t' && *r != '\n' && *r != '\0');
417 *fr++ = 0;
418 }
419 *fr = 0;
420 } else if (CSV) { /* CSV processing. no error handling */
421 if (*r != 0) {
422 for (;;) {
423 i++;
424 if (i > nfields)
425 growfldtab(i);
426 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
427 xfree(fldtab[i]->sval){ free((void *)(intptr_t)(fldtab[i]->sval)); (fldtab[i]->
sval) = ((void *)0); }
;
428 fldtab[i]->sval = fr;
429 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
430 if (*r == '"' ) { /* start of "..." */
431 for (r++ ; *r != '\0'; ) {
432 if (*r == '"' && r[1] != '\0' && r[1] == '"') {
433 r += 2; /* doubled quote */
434 *fr++ = '"';
435 } else if (*r == '"' && (r[1] == '\0' || r[1] == ',')) {
436 r++; /* skip over closing quote */
437 break;
438 } else {
439 *fr++ = *r++;
440 }
441 }
442 *fr++ = 0;
443 } else { /* unquoted field */
444 while (*r != ',' && *r != '\0')
445 *fr++ = *r++;
446 *fr++ = 0;
447 }
448 if (*r++ == 0)
449 break;
450
451 }
452 }
453 *fr = 0;
454 } else if ((sep = *inputFS) == 0) { /* new: FS="" => 1 char/field */
455 for (i = 0; *r != '\0'; ) {
456 char buf[10];
457 i++;
458 if (i > nfields)
459 growfldtab(i);
460 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
461 xfree(fldtab[i]->sval){ free((void *)(intptr_t)(fldtab[i]->sval)); (fldtab[i]->
sval) = ((void *)0); }
;
462 n = u8_nextlen(r);
463 for (j = 0; j < n; j++)
464 buf[j] = *r++;
465 buf[j] = '\0';
466 fldtab[i]->sval = tostring(buf);
467 fldtab[i]->tval = FLD0100 | STR02;
468 }
469 *fr = 0;
470 } else if (*r != 0) { /* if 0, it's a null field */
471 /* subtle case: if length(FS) == 1 && length(RS > 0)
472 * \n is NOT a field separator (cf awk book 61,84).
473 * this variable is tested in the inner while loop.
474 */
475 int rtest = '\n'; /* normal case */
476 if (strlen(*RS) > 0)
477 rtest = '\0';
478 for (;;) {
479 i++;
480 if (i > nfields)
481 growfldtab(i);
482 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
483 xfree(fldtab[i]->sval){ free((void *)(intptr_t)(fldtab[i]->sval)); (fldtab[i]->
sval) = ((void *)0); }
;
484 fldtab[i]->sval = fr;
485 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
486 while (*r != sep && *r != rtest && *r != '\0') /* \n is always a separator */
487 *fr++ = *r++;
488 *fr++ = 0;
489 if (*r++ == 0)
490 break;
491 }
492 *fr = 0;
493 }
494 if (i > nfields)
495 FATAL("record `%.30s...' has too many fields; can't happen", r);
496 cleanfld(i+1, lastfld); /* clean out junk from previous record */
497 lastfld = i;
498 donefld = true1;
499 for (j = 1; j <= lastfld; j++) {
500 double result;
501
502 p = fldtab[j];
503 if(is_number(p->sval, & result)is_valid_number(p->sval, 0, ((void *)0), & result)) {
504 p->fval = result;
505 p->tval |= NUM01;
506 }
507 }
508 setfval(nfloc, (Awkfloat) lastfld);
509 donerec = true1; /* restore */
510 if (dbg) {
511 for (j = 0; j <= lastfld; j++) {
512 p = fldtab[j];
513 printf("field %d (%s): |%s|\n", j, p->nval, p->sval);
514 }
515 }
516}
517
518void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */
519{ /* nvals remain intact */
520 Cell *p;
521 int i;
522
523 for (i = n1; i <= n2; i++) {
524 p = fldtab[i];
525 if (freeable(p)( ((p)->tval & (02|04)) == 02 ))
526 xfree(p->sval){ free((void *)(intptr_t)(p->sval)); (p->sval) = ((void
*)0); }
;
527 p->sval = EMPTY,
528 p->tval = FLD0100 | STR02 | DONTFREE04;
529 }
530}
531
532void newfld(int n) /* add field n after end of existing lastfld */
533{
534 if (n > nfields)
535 growfldtab(n);
536 cleanfld(lastfld+1, n);
537 lastfld = n;
538 setfval(nfloc, (Awkfloat) n);
539}
540
541void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */
542{
543 if (n < 0)
544 FATAL("cannot set NF to a negative value");
545 if (n > nfields)
546 growfldtab(n);
547
548 if (lastfld < n)
549 cleanfld(lastfld+1, n);
550 else
551 cleanfld(n+1, lastfld);
552
553 lastfld = n;
554}
555
556Cell *fieldadr(int n) /* get nth field */
557{
558 if (n < 0)
559 FATAL("trying to access out of range field %d", n);
560 if (n > nfields) /* fields after NF are empty */
561 growfldtab(n); /* but does not increase NF */
562 return(fldtab[n]);
563}
564
565void growfldtab(int n) /* make new fields up to at least $n */
566{
567 int nf = 2 * nfields;
568 size_t s;
569
570 if (n > nf)
571 nf = n;
572 s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
573 if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
574 fldtab = (Cell **) realloc(fldtab, s);
575 else /* overflow sizeof int */
576 xfree(fldtab){ free((void *)(intptr_t)(fldtab)); (fldtab) = ((void *)0); }; /* make it null */
577 if (fldtab == NULL((void *)0))
578 FATAL("out of space creating %d fields", nf);
579 makefields(nfields+1, nf);
580 nfields = nf;
581}
582
583int refldbld(const char *rec, const char *fs) /* build fields from reg expr in FS */
584{
585 /* this relies on having fields[] the same length as $0 */
586 /* the fields are all stored in this one array with \0's */
587 char *fr;
588 int i, tempstat, n;
589 fa *pfa;
590
591 n = strlen(rec);
592 if (n > fieldssize) {
593 xfree(fields){ free((void *)(intptr_t)(fields)); (fields) = ((void *)0); };
594 if ((fields = (char *) malloc(n+1)) == NULL((void *)0))
595 FATAL("out of space for fields in refldbld %d", n);
596 fieldssize = n;
597 }
598 fr = fields;
599 *fr = '\0';
600 if (*rec == '\0')
601 return 0;
602 pfa = makedfa(fs, 1);
603 DPRINTF("into refldbld, rec = <%s>, pat = <%s>\n", rec, fs)if (dbg) printf("into refldbld, rec = <%s>, pat = <%s>\n"
, rec, fs)
;
604 tempstat = pfa->initstat;
605 for (i = 1; ; i++) {
606 const size_t fss_rem = fields + fieldssize + 1 - fr;
607 if (i > nfields)
608 growfldtab(i);
609 if (freeable(fldtab[i])( ((fldtab[i])->tval & (02|04)) == 02 ))
610 xfree(fldtab[i]->sval){ free((void *)(intptr_t)(fldtab[i]->sval)); (fldtab[i]->
sval) = ((void *)0); }
;
611 fldtab[i]->tval = FLD0100 | STR02 | DONTFREE04;
612 fldtab[i]->sval = fr;
613 DPRINTF("refldbld: i=%d\n", i)if (dbg) printf("refldbld: i=%d\n", i);
614 if (nematch(pfa, rec)) {
615 const size_t reclen = patbeg - rec;
616 pfa->initstat = 2; /* horrible coupling to b.c */
617 DPRINTF("match %s (%d chars)\n", patbeg, patlen)if (dbg) printf("match %s (%d chars)\n", patbeg, patlen);
618 if (reclen >= fss_rem)
619 FATAL("out of space for fields in refldbld");
620 memcpy(fr, rec, reclen);
621 fr += reclen;
622 *fr++ = '\0';
623 rec = patbeg + patlen;
624 } else {
625 DPRINTF("no match %s\n", rec)if (dbg) printf("no match %s\n", rec);
626 if (strlcpy(fr, rec, fss_rem) >= fss_rem)
627 FATAL("out of space for fields in refldbld");
628 pfa->initstat = tempstat;
629 break;
630 }
631 }
632 return i;
633}
634
635void recbld(void) /* create $0 from $1..$NF if necessary */
636{
637 int i;
638 char *r, *p;
639 char *sep = getsval(ofsloc);
640
641 if (donerec)
642 return;
643 r = record;
644 for (i = 1; i <= *NF; i++) {
645 p = getsval(fldtab[i]);
646 if (!adjbuf(&record, &recsize, 1+strlen(p)+r-record, recsize, &r, "recbld 1"))
647 FATAL("created $0 `%.30s...' too long", record);
648 while ((*r = *p++) != 0)
649 r++;
650 if (i < *NF) {
651 if (!adjbuf(&record, &recsize, 2+strlen(sep)+r-record, recsize, &r, "recbld 2"))
652 FATAL("created $0 `%.30s...' too long", record);
653 for (p = sep; (*r = *p++) != 0; )
654 r++;
655 }
656 }
657 if (!adjbuf(&record, &recsize, 2+r-record, recsize, &r, "recbld 3"))
658 FATAL("built giant record `%.30s...'", record);
659 *r = '\0';
660 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])
;
661
662 if (freeable(fldtab[0])( ((fldtab[0])->tval & (02|04)) == 02 ))
663 xfree(fldtab[0]->sval){ free((void *)(intptr_t)(fldtab[0]->sval)); (fldtab[0]->
sval) = ((void *)0); }
;
664 fldtab[0]->tval = REC0200 | STR02 | DONTFREE04;
665 fldtab[0]->sval = record;
666
667 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])
;
668 DPRINTF("recbld = |%s|\n", record)if (dbg) printf("recbld = |%s|\n", record);
669 donerec = true1;
670}
671
672int errorflag = 0;
673
674void yyerror(const char *s)
675{
676 SYNTAX("%s", s);
677}
678
679void SYNTAX(const char *fmt, ...)
680{
681 extern char *cmdname, *curfname;
682 static int been_here = 0;
683 va_list varg;
684
685 if (been_here++ > 2)
686 return;
687 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
688 va_start(varg, fmt)__builtin_va_start((varg), fmt);
689 vfprintf(stderr(&__sF[2]), fmt, varg);
690 va_end(varg)__builtin_va_end((varg));
691 fprintf(stderr(&__sF[2]), " at source line %d", lineno);
692 if (curfname != NULL((void *)0))
693 fprintf(stderr(&__sF[2]), " in function %s", curfname);
694 if (compile_time == COMPILING && cursource() != NULL((void *)0))
695 fprintf(stderr(&__sF[2]), " source file %s", cursource());
696 fprintf(stderr(&__sF[2]), "\n");
697 errorflag = 2;
698 eprint();
699}
700
701extern int bracecnt, brackcnt, parencnt;
702
703void bracecheck(void)
704{
705 int c;
706 static int beenhere = 0;
707
708 if (beenhere++)
709 return;
710 while ((c = input()) != EOF(-1) && c != '\0')
711 bclass(c);
712 bcheck2(bracecnt, '{', '}');
713 bcheck2(brackcnt, '[', ']');
714 bcheck2(parencnt, '(', ')');
715}
716
717void bcheck2(int n, int c1, int c2)
718{
719 if (n == 1)
720 fprintf(stderr(&__sF[2]), "\tmissing %c\n", c2);
721 else if (n > 1)
722 fprintf(stderr(&__sF[2]), "\t%d missing %c's\n", n, c2);
723 else if (n == -1)
724 fprintf(stderr(&__sF[2]), "\textra %c\n", c2);
725 else if (n < -1)
726 fprintf(stderr(&__sF[2]), "\t%d extra %c's\n", -n, c2);
727}
728
729void FATAL(const char *fmt, ...)
730{
731 extern char *cmdname;
732 va_list varg;
733
734 fflush(stdout(&__sF[1]));
735 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
736 va_start(varg, fmt)__builtin_va_start((varg), fmt);
737 vfprintf(stderr(&__sF[2]), fmt, varg);
738 va_end(varg)__builtin_va_end((varg));
739 error();
740 if (dbg > 1) /* core dump if serious debugging on */
741 abort();
742 exit(2);
743}
744
745void WARNING(const char *fmt, ...)
746{
747 extern char *cmdname;
748 va_list varg;
749
750 fflush(stdout(&__sF[1]));
751 fprintf(stderr(&__sF[2]), "%s: ", cmdname);
752 va_start(varg, fmt)__builtin_va_start((varg), fmt);
753 vfprintf(stderr(&__sF[2]), fmt, varg);
754 va_end(varg)__builtin_va_end((varg));
755 error();
756}
757
758void error()
759{
760 extern Node *curnode;
761
762 fprintf(stderr(&__sF[2]), "\n");
763 if (compile_time != ERROR_PRINTING) {
764 if (NR && *NR > 0) {
765 fprintf(stderr(&__sF[2]), " input record number %d", (int) (*FNR));
766 if (strcmp(*FILENAME, "-") != 0)
767 fprintf(stderr(&__sF[2]), ", file %s", *FILENAME);
768 fprintf(stderr(&__sF[2]), "\n");
769 }
770 if (curnode)
771 fprintf(stderr(&__sF[2]), " source line number %d", curnode->lineno);
772 else if (lineno)
773 fprintf(stderr(&__sF[2]), " source line number %d", lineno);
774 if (compile_time == COMPILING && cursource() != NULL((void *)0))
775 fprintf(stderr(&__sF[2]), " source file %s", cursource());
776 fprintf(stderr(&__sF[2]), "\n");
777 eprint();
778 }
779}
780
781void eprint(void) /* try to print context around error */
782{
783 char *p, *q;
784 int c;
785 static int been_here = 0;
786 extern char ebuf[], *ep;
787
788 if (compile_time != COMPILING || been_here++ > 0 || ebuf == ep)
789 return;
790 p = ep - 1;
791 if (p > ebuf && *p == '\n')
792 p--;
793 for ( ; p > ebuf && *p != '\n' && *p != '\0'; p--)
794 ;
795 while (*p == '\n')
796 p++;
797 fprintf(stderr(&__sF[2]), " context is\n\t");
798 for (q=ep-1; q>=p && *q!=' ' && *q!='\t' && *q!='\n'; q--)
799 ;
800 for ( ; p < q; p++)
801 if (*p)
802 putc(*p, stderr)(!__isthreaded ? __sputc(*p, (&__sF[2])) : (putc)(*p, (&
__sF[2])))
;
803 fprintf(stderr(&__sF[2]), " >>> ");
804 for ( ; p < ep; p++)
805 if (*p)
806 putc(*p, stderr)(!__isthreaded ? __sputc(*p, (&__sF[2])) : (putc)(*p, (&
__sF[2])))
;
807 fprintf(stderr(&__sF[2]), " <<< ");
808 if (*ep)
809 while ((c = input()) != '\n' && c != '\0' && c != EOF(-1)) {
810 putc(c, stderr)(!__isthreaded ? __sputc(c, (&__sF[2])) : (putc)(c, (&
__sF[2])))
;
811 bclass(c);
812 }
813 putc('\n', stderr)(!__isthreaded ? __sputc('\n', (&__sF[2])) : (putc)('\n',
(&__sF[2])))
;
814 ep = ebuf;
815}
816
817void bclass(int c)
818{
819 switch (c) {
820 case '{': bracecnt++; break;
821 case '}': bracecnt--; break;
822 case '[': brackcnt++; break;
823 case ']': brackcnt--; break;
824 case '(': parencnt++; break;
825 case ')': parencnt--; break;
826 }
827}
828
829double errcheck(double x, const char *s)
830{
831
832 if (errno(*__errno()) == EDOM33) {
833 errno(*__errno()) = 0;
834 WARNING("%s argument out of domain", s);
835 x = 1;
836 } else if (errno(*__errno()) == ERANGE34) {
837 errno(*__errno()) = 0;
838 WARNING("%s result out of range", s);
839 x = 1;
840 }
841 return x;
842}
843
844int isclvar(const char *s) /* is s of form var=something ? */
845{
846 const char *os = s;
847
848 if (!isalpha((uschar) *s) && *s != '_')
849 return 0;
850 for ( ; *s; s++)
851 if (!(isalnum((uschar) *s) || *s == '_'))
852 break;
853 return *s == '=' && s > os;
854}
855
856/* strtod is supposed to be a proper test of what's a valid number */
857/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
858/* wrong: violates 4.10.1.4 of ansi C standard */
859
860/* well, not quite. As of C99, hex floating point is allowed. so this is
861 * a bit of a mess. We work around the mess by checking for a hexadecimal
862 * value and disallowing it. Similarly, we now follow gawk and allow only
863 * +nan, -nan, +inf, and -inf for NaN and infinity values.
864 */
865
866/*
867 * This routine now has a more complicated interface, the main point
868 * being to avoid the double conversion of a string to double, and
869 * also to convey out, if requested, the information that the numeric
870 * value was a leading string or is all of the string. The latter bit
871 * is used in getfval().
872 */
873
874bool_Bool is_valid_number(const char *s, bool_Bool trailing_stuff_ok,
875 bool_Bool *no_trailing, double *result)
876{
877 double r;
878 char *ep;
879 bool_Bool retval = false0;
880 bool_Bool is_nan = false0;
881 bool_Bool is_inf = false0;
882
883 if (no_trailing)
884 *no_trailing = false0;
885
886 while (isspace((uschar)*s))
887 s++;
888
889 /* no hex floating point, sorry */
890 if (s[0] == '0' && tolower((uschar)s[1]) == 'x')
891 return false0;
892
893 /* allow +nan, -nan, +inf, -inf, any other letter, no */
894 if (s[0] == '+' || s[0] == '-') {
895 is_nan = (strncasecmp(s+1, "nan", 3) == 0);
896 is_inf = (strncasecmp(s+1, "inf", 3) == 0);
897 if ((is_nan || is_inf)
898 && (isspace((uschar)s[4]) || s[4] == '\0'))
899 goto convert;
900 else if (! isdigit((uschar)s[1]) && s[1] != '.')
901 return false0;
902 }
903 else if (! isdigit((uschar)s[0]) && s[0] != '.')
904 return false0;
905
906convert:
907 errno(*__errno()) = 0;
908 r = strtod(s, &ep);
909 if (ep == s || errno(*__errno()) == ERANGE34)
910 return false0;
911
912 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)
913 r = -r;
914
915 if (result != NULL((void *)0))
916 *result = r;
917
918 /*
919 * check for trailing stuff
920 */
921 while (isspace((uschar)*ep))
922 ep++;
923
924 if (no_trailing != NULL((void *)0))
925 *no_trailing = (*ep == '\0');
926
927 /* return true if found the end, or trailing stuff is allowed */
928 retval = *ep == '\0' || trailing_stuff_ok;
929
930 return retval;
931}