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