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