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