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