xref: /original-bsd/usr.bin/pascal/libpc/READ8.c (revision 7211505a)
1 /* Copyright (c) 1979 Regents of the University of California */
2 
3 static char sccsid[] = "@(#)READ8.c 1.9 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 	AT_LEAST_ONE(read, filep, "%[0123456789]", sequencep);
137 	/*
138 	 *	any of this is optional:
139 	 *	[ `.' digit {digit} ] [ `e' [ `+' | `-' ] digit {digits} ]
140 	 */
141 	NEXT_CHAR(read, filep, "%c", sequencep);
142 	switch (sequencep[-1]) {
143 	default:
144 		PUSHBACK(curfile, sequencep);
145 		goto convert;
146 	case '.':
147 		SOME(read, filep, "%[0123456789]", sequencep);
148 		if (!read) {
149 			PUSHBACK(curfile, sequencep);
150 			goto convert;
151 		}
152 		NEXT_CHAR(read, filep, "%c", sequencep);
153 		if (sequencep[-1] != 'e') {
154 			PUSHBACK(curfile, sequencep);
155 			goto convert;
156 		}
157 		/* fall through */
158 	case 'e':
159 		NEXT_CHAR(read, filep, "%c", sequencep);
160 		if (sequencep[-1] != '+' && sequencep[-1] != '-') {
161 			PUSHBACK(curfile, sequencep);
162 			SOME(read, filep, "%[0123456789]", sequencep);
163 			if (!read)
164 				PUSHBACK(curfile, sequencep);
165 			goto convert;
166 		}
167 		SOME(read, filep, "%[0123456789]", sequencep);
168 		if (!read) {
169 			PUSHBACK(curfile, sequencep);
170 			PUSHBACK(curfile, sequencep);
171 		}
172 	}
173 
174 convert:
175 	/*
176 	 * convert sequence to double
177 	 */
178 	*doublep = atof(&sequence[0]);
179 	return (1);
180 }
181