Sat Jun 20 23:23:12 2009 UTC ()
PR/30294: John Darrow: nawk doesn't handle RS as a RE but as a single character


(christos)
diff -r1.16 -r1.17 src/dist/nawk/lib.c

cvs diff -r1.16 -r1.17 src/dist/nawk/Attic/lib.c (switch to unified diff)

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