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