xref: /csrg-svn/usr.bin/pascal/libpc/READ8.c (revision 15302)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)READ8.c 1.7 10/28/83";
4 
5 #include "h00vars.h"
6 #include <errno.h>
7 extern int errno;
8 
9 double
10 READ8(curfile)
11 
12 	register struct iorec	*curfile;
13 {
14 	double			data;
15 	int			retval;
16 
17 	if (curfile->funit & FWRITE) {
18 		ERROR("%s: Attempt to read, but open for writing\n",
19 			curfile->pfname);
20 		return;
21 	}
22 	UNSYNC(curfile);
23 	errno = 0;
24 	retval = readreal(curfile, &data);
25 	if (retval == EOF) {
26 		ERROR("%s: Tried to read past end of file\n", curfile->pfname);
27 		return;
28 	}
29 	if (retval == 0) {
30 		ERROR("%s: Bad data found on real read\n", curfile->pfname);
31 		return;
32 	}
33 	if (errno == ERANGE) {
34 		if (data == 0.0)
35 			ERROR("%s: Underflow on real read\n", curfile->pfname);
36 		else
37 			ERROR("%s: Overflow on real read\n", curfile->pfname);
38 		return;
39 	}
40 	if (errno != 0) {
41 		PERROR("Error encountered on real read ", curfile->pfname);
42 		return;
43 	}
44 	return (data);
45 }
46 
47 /*
48  *	given a file pointer, read a sequence of characters of the
49  *	syntax of section 6.1.5 and form them into a double.
50  *
51  *	the syntax of a signed-real is:
52  *	    [-|+] digit {digit} e [+|-] digit {digit}
53  *	or
54  *	    [-|+] digit {digit} . digit {digit} [e [+|-] digit {digit}]
55  *
56  *	returns:
57  *		1	for success (with value in *doublep)
58  *		0	on error (with *doublep unchanged)
59  *	       -1	on end-of-file during read (with *doublep unchanged)
60  *	side effects:
61  *	      errno	may be set to ERANGE if atof() sets it.
62  */
63 readreal(curfile, doublep)
64 	struct iorec	*curfile;
65 	double		*doublep;
66 {
67 	FILE	*filep = curfile->fbuf;	/* current file variable */
68 	char	*sequencep;		/* a pointer into sequence */
69 	int	read;			/* return value from fscanf() */
70 	char	sequence[BUFSIZ];	/* the character sequence */
71 	double	atof();
72 
73 #define PUSHBACK(curfile, sequencep) \
74 	if (ungetc(*--(sequencep), (curfile)->fbuf) != EOF) { \
75 		*(sequencep) = '\0'; \
76 	} else if ((curfile)->funit & SYNC) { \
77 		(curfile)->funit &= ~SYNC; \
78 		*(curfile)->fileptr = *(sequencep); \
79 		*(sequencep) = '\0'; \
80 	} else { \
81 		return (0); \
82 	}
83 
84 #define	RETURN_ON_EOF(read) \
85 	if (read == EOF) \
86 		return (EOF); \
87 	else \
88 		/* void */;
89 
90 #define	PUSH_TO_NULL(sequencep) \
91 	while (*sequencep) \
92 		sequencep++;
93 
94 #define	SOME(read, filep, format, sequencep) \
95 	read = fscanf(filep, format, sequencep); \
96 	RETURN_ON_EOF(read); \
97 	PUSH_TO_NULL(sequencep);
98 
99 #define	AT_LEAST_ONE(read, filep, format, sequencep) \
100 	read = fscanf(filep, format, sequencep); \
101 	RETURN_ON_EOF(read); \
102 	if (strlen(sequencep) < 1) \
103 		return (0); \
104 	PUSH_TO_NULL(sequencep);
105 
106 #define	EXACTLY_ONE(read, filep, format, sequencep) \
107 	read = fscanf(filep, format, sequencep); \
108 	RETURN_ON_EOF(read); \
109 	if (strlen(sequencep) != 1) \
110 		return (0); \
111 	PUSH_TO_NULL(sequencep);
112 
113 #define	AT_MOST_ONE(read, filep, format, sequencep) \
114 	read = fscanf(filep, format, sequencep); \
115 	RETURN_ON_EOF(read); \
116 	if (strlen(sequencep) > 1) \
117 		return (0); \
118 	PUSH_TO_NULL(sequencep);
119 
120 	sequencep = &sequence[0];
121 	*sequencep = '\0';
122 	/*
123 	 * skip leading whitespace
124 	 */
125 	SOME(read, filep, "%*[ \t\n]", sequencep);
126 	/*
127 	 *	[ "+" | "-" ] digit {digits}
128 	 */
129 	AT_MOST_ONE(read, filep, "%[+-]", sequencep);
130 	AT_LEAST_ONE(read, filep, "%[0123456789]", sequencep);
131 	/*
132 	 *	either
133 	 *		"." digit {digit} [ "e" [ "+" | "-" ] digit {digits} ]
134 	 *	or
135 	 *		"e" [ "+" | "-" ] digit {digits}
136 	 */
137 	AT_MOST_ONE(read, filep, "%c", sequencep);
138 	switch (sequencep[-1]) {
139 	default:
140 		PUSHBACK(curfile, sequencep);
141 		goto convert;
142 	case '.':
143 		SOME(read, filep, "%[0123456789]", sequencep);
144 		if (!read) {
145 			PUSHBACK(curfile, sequencep);
146 			goto convert;
147 		}
148 		AT_MOST_ONE(read, filep, "%c", sequencep);
149 		if (sequencep[-1] != 'e') {
150 			PUSHBACK(curfile, sequencep);
151 			goto convert;
152 		}
153 		/* fall through */
154 	case 'e':
155 		AT_MOST_ONE(read, filep, "%c", sequencep);
156 		if (sequencep[-1] != '+' && sequencep[-1] != '-') {
157 			PUSHBACK(curfile, sequencep);
158 			SOME(read, filep, "%[0123456789]", sequencep);
159 			if (!read)
160 				PUSHBACK(curfile, sequencep);
161 			goto convert;
162 		}
163 		SOME(read, filep, "%[0123456789]", sequencep);
164 		if (!read) {
165 			PUSHBACK(curfile, sequencep);
166 			PUSHBACK(curfile, sequencep);
167 		}
168 	}
169 
170 convert:
171 	/*
172 	 * convert sequence to double
173 	 */
174 	*doublep = atof(&sequence[0]);
175 	return (1);
176 }
177