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