Thu Jan 20 21:23:11 2011 UTC ()
avoid crash if certain operations are done before an input record is
read, ie in a BEGIN rule


(drochner)
diff -r1.3 -r1.4 src/external/historical/nawk/dist/lib.c

cvs diff -r1.3 -r1.4 src/external/historical/nawk/dist/lib.c (switch to unified diff)

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