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