140865Sbostic /*-
2*62096Sbostic * Copyright (c) 1979, 1993
3*62096Sbostic * The Regents of the University of California. All rights reserved.
440865Sbostic *
540865Sbostic * %sccs.include.redist.c%
640865Sbostic */
71680Smckusick
840865Sbostic #ifndef lint
9*62096Sbostic static char sccsid[] = "@(#)READ8.c 8.1 (Berkeley) 06/06/93";
1040865Sbostic #endif /* not lint */
111680Smckusick
121680Smckusick #include "h00vars.h"
136498Smckusick #include <errno.h>
146498Smckusick extern int errno;
151680Smckusick
161680Smckusick double
READ8(curfile)171680Smckusick READ8(curfile)
181680Smckusick register struct iorec *curfile;
191680Smckusick {
201680Smckusick double data;
212223Smckusic int retval;
221680Smckusick
231680Smckusick if (curfile->funit & FWRITE) {
243869Smckusic ERROR("%s: Attempt to read, but open for writing\n",
253869Smckusic curfile->pfname);
261680Smckusick }
271680Smckusick UNSYNC(curfile);
286498Smckusick errno = 0;
2915302Smckusick retval = readreal(curfile, &data);
302223Smckusic if (retval == EOF) {
313869Smckusic ERROR("%s: Tried to read past end of file\n", curfile->pfname);
322223Smckusic }
332223Smckusic if (retval == 0) {
343869Smckusic ERROR("%s: Bad data found on real read\n", curfile->pfname);
351680Smckusick }
366498Smckusick if (errno == ERANGE) {
376498Smckusick if (data == 0.0)
386498Smckusick ERROR("%s: Underflow on real read\n", curfile->pfname);
396498Smckusick else
406498Smckusick ERROR("%s: Overflow on real read\n", curfile->pfname);
416498Smckusick }
426498Smckusick if (errno != 0) {
4315127Smckusick PERROR("Error encountered on real read ", curfile->pfname);
446498Smckusick }
4515127Smckusick return (data);
461680Smckusick }
4715127Smckusick
4815127Smckusick /*
4915127Smckusick * given a file pointer, read a sequence of characters of the
5015127Smckusick * syntax of section 6.1.5 and form them into a double.
5115127Smckusick *
5215127Smckusick * the syntax of a signed-real is:
5315388Speter * [-|+] digit {digit} [ . digit {digit} ] [ e [+|-] digit {digit} ]
5415127Smckusick *
5515127Smckusick * returns:
5615127Smckusick * 1 for success (with value in *doublep)
5715127Smckusick * 0 on error (with *doublep unchanged)
5815127Smckusick * -1 on end-of-file during read (with *doublep unchanged)
5915127Smckusick * side effects:
6015127Smckusick * errno may be set to ERANGE if atof() sets it.
6115127Smckusick */
6215302Smckusick readreal(curfile, doublep)
6315302Smckusick struct iorec *curfile;
6415302Smckusick double *doublep;
6515127Smckusick {
6615302Smckusick FILE *filep = curfile->fbuf; /* current file variable */
6715127Smckusick char *sequencep; /* a pointer into sequence */
6815127Smckusick int read; /* return value from fscanf() */
6915302Smckusick char sequence[BUFSIZ]; /* the character sequence */
7015127Smckusick double atof();
7115127Smckusick
7215302Smckusick #define PUSHBACK(curfile, sequencep) \
7315302Smckusick if (ungetc(*--(sequencep), (curfile)->fbuf) != EOF) { \
7415302Smckusick *(sequencep) = '\0'; \
7515302Smckusick } else if ((curfile)->funit & SYNC) { \
7615302Smckusick (curfile)->funit &= ~SYNC; \
7715302Smckusick *(curfile)->fileptr = *(sequencep); \
7815302Smckusick *(sequencep) = '\0'; \
7915302Smckusick } else { \
8015302Smckusick return (0); \
8115302Smckusick }
8215302Smckusick
8315127Smckusick #define RETURN_ON_EOF(read) \
8415127Smckusick if (read == EOF) \
8515127Smckusick return (EOF); \
8615127Smckusick else \
8715127Smckusick /* void */;
8815127Smckusick
8915127Smckusick #define PUSH_TO_NULL(sequencep) \
9015127Smckusick while (*sequencep) \
9115127Smckusick sequencep++;
9215127Smckusick
9315388Speter /* general reader of the next character */
9415388Speter #define NEXT_CHAR(read, filep, format, sequencep) \
9515388Speter read = fscanf(filep, "%c", sequencep); \
9615388Speter RETURN_ON_EOF(read); \
9715388Speter *++sequencep = '\0';
9815388Speter
9915388Speter /* e.g. use %[0123456789] for {digit}, and check read */
10015127Smckusick #define SOME(read, filep, format, sequencep) \
10115127Smckusick read = fscanf(filep, format, sequencep); \
10215127Smckusick RETURN_ON_EOF(read); \
10315127Smckusick PUSH_TO_NULL(sequencep);
10415127Smckusick
10515388Speter /* e.g. use %[0123456789] for digit {digit} */
10615127Smckusick #define AT_LEAST_ONE(read, filep, format, sequencep) \
10715127Smckusick read = fscanf(filep, format, sequencep); \
10815127Smckusick RETURN_ON_EOF(read); \
10915127Smckusick if (strlen(sequencep) < 1) \
11015127Smckusick return (0); \
11115127Smckusick PUSH_TO_NULL(sequencep);
11215127Smckusick
11315388Speter #define ANY_ONE_OF(read, filep, format, sequencep) \
11415127Smckusick read = fscanf(filep, format, sequencep); \
11515127Smckusick RETURN_ON_EOF(read); \
11615127Smckusick if (strlen(sequencep) != 1) \
11715127Smckusick return (0); \
11815127Smckusick PUSH_TO_NULL(sequencep);
11915127Smckusick
12015127Smckusick #define AT_MOST_ONE(read, filep, format, sequencep) \
12115127Smckusick read = fscanf(filep, format, sequencep); \
12215127Smckusick RETURN_ON_EOF(read); \
12315127Smckusick if (strlen(sequencep) > 1) \
12415127Smckusick return (0); \
12515127Smckusick PUSH_TO_NULL(sequencep);
12615127Smckusick
12715127Smckusick sequencep = &sequence[0];
12815127Smckusick *sequencep = '\0';
12915127Smckusick /*
13015388Speter * skip leading whitespace
13115127Smckusick */
13215127Smckusick SOME(read, filep, "%*[ \t\n]", sequencep);
13315127Smckusick /*
13415388Speter * this much is required:
13515127Smckusick * [ "+" | "-" ] digit {digits}
13615127Smckusick */
13715127Smckusick AT_MOST_ONE(read, filep, "%[+-]", sequencep);
13815127Smckusick AT_LEAST_ONE(read, filep, "%[0123456789]", sequencep);
13915127Smckusick /*
14015388Speter * any of this is optional:
14115388Speter * [ `.' digit {digit} ] [ `e' [ `+' | `-' ] digit {digits} ]
14215127Smckusick */
14315388Speter NEXT_CHAR(read, filep, "%c", sequencep);
14415302Smckusick switch (sequencep[-1]) {
14515302Smckusick default:
14615302Smckusick PUSHBACK(curfile, sequencep);
14715302Smckusick goto convert;
14815302Smckusick case '.':
14915302Smckusick SOME(read, filep, "%[0123456789]", sequencep);
15015302Smckusick if (!read) {
15115302Smckusick PUSHBACK(curfile, sequencep);
15215302Smckusick goto convert;
15315127Smckusick }
15415388Speter NEXT_CHAR(read, filep, "%c", sequencep);
15515302Smckusick if (sequencep[-1] != 'e') {
15615302Smckusick PUSHBACK(curfile, sequencep);
15715302Smckusick goto convert;
15815302Smckusick }
15915302Smckusick /* fall through */
16015302Smckusick case 'e':
16115388Speter NEXT_CHAR(read, filep, "%c", sequencep);
16215302Smckusick if (sequencep[-1] != '+' && sequencep[-1] != '-') {
16315302Smckusick PUSHBACK(curfile, sequencep);
16415302Smckusick SOME(read, filep, "%[0123456789]", sequencep);
16515302Smckusick if (!read)
16615302Smckusick PUSHBACK(curfile, sequencep);
16715302Smckusick goto convert;
16815302Smckusick }
16915302Smckusick SOME(read, filep, "%[0123456789]", sequencep);
17015302Smckusick if (!read) {
17115302Smckusick PUSHBACK(curfile, sequencep);
17215302Smckusick PUSHBACK(curfile, sequencep);
17315302Smckusick }
17415127Smckusick }
17515302Smckusick
17615302Smckusick convert:
17715127Smckusick /*
17815127Smckusick * convert sequence to double
17915127Smckusick */
18015127Smckusick *doublep = atof(&sequence[0]);
18115127Smckusick return (1);
18215127Smckusick }
183