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