Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

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