xref: /aosp_15_r20/bionic/libc/stdio/parsefloat.c (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1*8d67ca89SAndroid Build Coastguard Worker /*-
2*8d67ca89SAndroid Build Coastguard Worker  * Copyright (c) 1990, 1993
3*8d67ca89SAndroid Build Coastguard Worker  *	The Regents of the University of California.  All rights reserved.
4*8d67ca89SAndroid Build Coastguard Worker  *
5*8d67ca89SAndroid Build Coastguard Worker  * This code is derived from software contributed to Berkeley by
6*8d67ca89SAndroid Build Coastguard Worker  * Chris Torek.
7*8d67ca89SAndroid Build Coastguard Worker  *
8*8d67ca89SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
9*8d67ca89SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
10*8d67ca89SAndroid Build Coastguard Worker  * are met:
11*8d67ca89SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
12*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
13*8d67ca89SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
14*8d67ca89SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
15*8d67ca89SAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
16*8d67ca89SAndroid Build Coastguard Worker  * 3. Neither the name of the University nor the names of its contributors
17*8d67ca89SAndroid Build Coastguard Worker  *    may be used to endorse or promote products derived from this software
18*8d67ca89SAndroid Build Coastguard Worker  *    without specific prior written permission.
19*8d67ca89SAndroid Build Coastguard Worker  *
20*8d67ca89SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21*8d67ca89SAndroid Build Coastguard Worker  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*8d67ca89SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*8d67ca89SAndroid Build Coastguard Worker  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24*8d67ca89SAndroid Build Coastguard Worker  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*8d67ca89SAndroid Build Coastguard Worker  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*8d67ca89SAndroid Build Coastguard Worker  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*8d67ca89SAndroid Build Coastguard Worker  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*8d67ca89SAndroid Build Coastguard Worker  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*8d67ca89SAndroid Build Coastguard Worker  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*8d67ca89SAndroid Build Coastguard Worker  * SUCH DAMAGE.
31*8d67ca89SAndroid Build Coastguard Worker  */
32*8d67ca89SAndroid Build Coastguard Worker 
33*8d67ca89SAndroid Build Coastguard Worker #include <ctype.h>
34*8d67ca89SAndroid Build Coastguard Worker #include <stdlib.h>
35*8d67ca89SAndroid Build Coastguard Worker 
36*8d67ca89SAndroid Build Coastguard Worker #include "local.h"
37*8d67ca89SAndroid Build Coastguard Worker 
38*8d67ca89SAndroid Build Coastguard Worker #define	BUF		513	/* Maximum length of numeric string. */
39*8d67ca89SAndroid Build Coastguard Worker 
parsefloat(FILE * fp,char * buf,char * end)40*8d67ca89SAndroid Build Coastguard Worker size_t parsefloat(FILE *fp, char *buf, char *end) {
41*8d67ca89SAndroid Build Coastguard Worker 	char *commit, *p;
42*8d67ca89SAndroid Build Coastguard Worker 	int infnanpos = 0;
43*8d67ca89SAndroid Build Coastguard Worker 	enum {
44*8d67ca89SAndroid Build Coastguard Worker 		S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
45*8d67ca89SAndroid Build Coastguard Worker 		S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
46*8d67ca89SAndroid Build Coastguard Worker 	} state = S_START;
47*8d67ca89SAndroid Build Coastguard Worker 	unsigned char c;
48*8d67ca89SAndroid Build Coastguard Worker 	int gotmantdig = 0, ishex = 0;
49*8d67ca89SAndroid Build Coastguard Worker 
50*8d67ca89SAndroid Build Coastguard Worker 	/*
51*8d67ca89SAndroid Build Coastguard Worker 	 * We set commit = p whenever the string we have read so far
52*8d67ca89SAndroid Build Coastguard Worker 	 * constitutes a valid representation of a floating point
53*8d67ca89SAndroid Build Coastguard Worker 	 * number by itself.  At some point, the parse will complete
54*8d67ca89SAndroid Build Coastguard Worker 	 * or fail, and we will ungetc() back to the last commit point.
55*8d67ca89SAndroid Build Coastguard Worker 	 * To ensure that the file offset gets updated properly, it is
56*8d67ca89SAndroid Build Coastguard Worker 	 * always necessary to read at least one character that doesn't
57*8d67ca89SAndroid Build Coastguard Worker 	 * match; thus, we can't short-circuit "infinity" or "nan(...)".
58*8d67ca89SAndroid Build Coastguard Worker 	 */
59*8d67ca89SAndroid Build Coastguard Worker 	commit = buf - 1;
60*8d67ca89SAndroid Build Coastguard Worker 	for (p = buf; p < end; ) {
61*8d67ca89SAndroid Build Coastguard Worker 		c = *fp->_p;
62*8d67ca89SAndroid Build Coastguard Worker reswitch:
63*8d67ca89SAndroid Build Coastguard Worker 		switch (state) {
64*8d67ca89SAndroid Build Coastguard Worker 		case S_START:
65*8d67ca89SAndroid Build Coastguard Worker 			state = S_GOTSIGN;
66*8d67ca89SAndroid Build Coastguard Worker 			if (c == '-' || c == '+')
67*8d67ca89SAndroid Build Coastguard Worker 				break;
68*8d67ca89SAndroid Build Coastguard Worker 			else
69*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
70*8d67ca89SAndroid Build Coastguard Worker 		case S_GOTSIGN:
71*8d67ca89SAndroid Build Coastguard Worker 			switch (c) {
72*8d67ca89SAndroid Build Coastguard Worker 			case '0':
73*8d67ca89SAndroid Build Coastguard Worker 				state = S_MAYBEHEX;
74*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
75*8d67ca89SAndroid Build Coastguard Worker 				break;
76*8d67ca89SAndroid Build Coastguard Worker 			case 'I':
77*8d67ca89SAndroid Build Coastguard Worker 			case 'i':
78*8d67ca89SAndroid Build Coastguard Worker 				state = S_INF;
79*8d67ca89SAndroid Build Coastguard Worker 				break;
80*8d67ca89SAndroid Build Coastguard Worker 			case 'N':
81*8d67ca89SAndroid Build Coastguard Worker 			case 'n':
82*8d67ca89SAndroid Build Coastguard Worker 				state = S_NAN;
83*8d67ca89SAndroid Build Coastguard Worker 				break;
84*8d67ca89SAndroid Build Coastguard Worker 			default:
85*8d67ca89SAndroid Build Coastguard Worker 				state = S_DIGITS;
86*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
87*8d67ca89SAndroid Build Coastguard Worker 			}
88*8d67ca89SAndroid Build Coastguard Worker 			break;
89*8d67ca89SAndroid Build Coastguard Worker 		case S_INF:
90*8d67ca89SAndroid Build Coastguard Worker 			if (infnanpos > 6 ||
91*8d67ca89SAndroid Build Coastguard Worker 			    (c != "nfinity"[infnanpos] &&
92*8d67ca89SAndroid Build Coastguard Worker 			     c != "NFINITY"[infnanpos]))
93*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
94*8d67ca89SAndroid Build Coastguard Worker 			if (infnanpos == 1 || infnanpos == 6)
95*8d67ca89SAndroid Build Coastguard Worker 				commit = p;	/* inf or infinity */
96*8d67ca89SAndroid Build Coastguard Worker 			infnanpos++;
97*8d67ca89SAndroid Build Coastguard Worker 			break;
98*8d67ca89SAndroid Build Coastguard Worker 		case S_NAN:
99*8d67ca89SAndroid Build Coastguard Worker 			switch (infnanpos) {
100*8d67ca89SAndroid Build Coastguard Worker 			case -1:	/* XXX kludge to deal with nan(...) */
101*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
102*8d67ca89SAndroid Build Coastguard Worker 			case 0:
103*8d67ca89SAndroid Build Coastguard Worker 				if (c != 'A' && c != 'a')
104*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
105*8d67ca89SAndroid Build Coastguard Worker 				break;
106*8d67ca89SAndroid Build Coastguard Worker 			case 1:
107*8d67ca89SAndroid Build Coastguard Worker 				if (c != 'N' && c != 'n')
108*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
109*8d67ca89SAndroid Build Coastguard Worker 				else
110*8d67ca89SAndroid Build Coastguard Worker 					commit = p;
111*8d67ca89SAndroid Build Coastguard Worker 				break;
112*8d67ca89SAndroid Build Coastguard Worker 			case 2:
113*8d67ca89SAndroid Build Coastguard Worker 				if (c != '(')
114*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
115*8d67ca89SAndroid Build Coastguard Worker 				break;
116*8d67ca89SAndroid Build Coastguard Worker 			default:
117*8d67ca89SAndroid Build Coastguard Worker 				if (c == ')') {
118*8d67ca89SAndroid Build Coastguard Worker 					commit = p;
119*8d67ca89SAndroid Build Coastguard Worker 					infnanpos = -2;
120*8d67ca89SAndroid Build Coastguard Worker 				} else if (!isalnum(c) && c != '_')
121*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
122*8d67ca89SAndroid Build Coastguard Worker 				break;
123*8d67ca89SAndroid Build Coastguard Worker 			}
124*8d67ca89SAndroid Build Coastguard Worker 			infnanpos++;
125*8d67ca89SAndroid Build Coastguard Worker 			break;
126*8d67ca89SAndroid Build Coastguard Worker 		case S_MAYBEHEX:
127*8d67ca89SAndroid Build Coastguard Worker 			state = S_DIGITS;
128*8d67ca89SAndroid Build Coastguard Worker 			if (c == 'X' || c == 'x') {
129*8d67ca89SAndroid Build Coastguard Worker 				ishex = 1;
130*8d67ca89SAndroid Build Coastguard Worker 				break;
131*8d67ca89SAndroid Build Coastguard Worker 			} else {	/* we saw a '0', but no 'x' */
132*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
133*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
134*8d67ca89SAndroid Build Coastguard Worker 			}
135*8d67ca89SAndroid Build Coastguard Worker 		case S_DIGITS:
136*8d67ca89SAndroid Build Coastguard Worker 			if ((ishex && isxdigit(c)) || isdigit(c))
137*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
138*8d67ca89SAndroid Build Coastguard Worker 			else {
139*8d67ca89SAndroid Build Coastguard Worker 				state = S_FRAC;
140*8d67ca89SAndroid Build Coastguard Worker 				if (c != '.')
141*8d67ca89SAndroid Build Coastguard Worker 					goto reswitch;
142*8d67ca89SAndroid Build Coastguard Worker 			}
143*8d67ca89SAndroid Build Coastguard Worker 			if (gotmantdig)
144*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
145*8d67ca89SAndroid Build Coastguard Worker 			break;
146*8d67ca89SAndroid Build Coastguard Worker 		case S_FRAC:
147*8d67ca89SAndroid Build Coastguard Worker 			if (((c == 'E' || c == 'e') && !ishex) ||
148*8d67ca89SAndroid Build Coastguard Worker 			    ((c == 'P' || c == 'p') && ishex)) {
149*8d67ca89SAndroid Build Coastguard Worker 				if (!gotmantdig)
150*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
151*8d67ca89SAndroid Build Coastguard Worker 				else
152*8d67ca89SAndroid Build Coastguard Worker 					state = S_EXP;
153*8d67ca89SAndroid Build Coastguard Worker 			} else if ((ishex && isxdigit(c)) || isdigit(c)) {
154*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
155*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
156*8d67ca89SAndroid Build Coastguard Worker 			} else
157*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
158*8d67ca89SAndroid Build Coastguard Worker 			break;
159*8d67ca89SAndroid Build Coastguard Worker 		case S_EXP:
160*8d67ca89SAndroid Build Coastguard Worker 			state = S_EXPDIGITS;
161*8d67ca89SAndroid Build Coastguard Worker 			if (c == '-' || c == '+')
162*8d67ca89SAndroid Build Coastguard Worker 				break;
163*8d67ca89SAndroid Build Coastguard Worker 			else
164*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
165*8d67ca89SAndroid Build Coastguard Worker 		case S_EXPDIGITS:
166*8d67ca89SAndroid Build Coastguard Worker 			if (isdigit(c))
167*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
168*8d67ca89SAndroid Build Coastguard Worker 			else
169*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
170*8d67ca89SAndroid Build Coastguard Worker 			break;
171*8d67ca89SAndroid Build Coastguard Worker 		default:
172*8d67ca89SAndroid Build Coastguard Worker 			abort();
173*8d67ca89SAndroid Build Coastguard Worker 		}
174*8d67ca89SAndroid Build Coastguard Worker 		*p++ = c;
175*8d67ca89SAndroid Build Coastguard Worker 		if (--fp->_r > 0)
176*8d67ca89SAndroid Build Coastguard Worker 			fp->_p++;
177*8d67ca89SAndroid Build Coastguard Worker 		else if (__srefill(fp))
178*8d67ca89SAndroid Build Coastguard Worker 			break;	/* EOF */
179*8d67ca89SAndroid Build Coastguard Worker 	}
180*8d67ca89SAndroid Build Coastguard Worker 
181*8d67ca89SAndroid Build Coastguard Worker parsedone:
182*8d67ca89SAndroid Build Coastguard Worker 	while (commit < --p)
183*8d67ca89SAndroid Build Coastguard Worker 		(void)ungetc(*(unsigned char *)p, fp);
184*8d67ca89SAndroid Build Coastguard Worker 	*++commit = '\0';
185*8d67ca89SAndroid Build Coastguard Worker 	return commit - buf;
186*8d67ca89SAndroid Build Coastguard Worker }
187*8d67ca89SAndroid Build Coastguard Worker 
wparsefloat(FILE * fp,wchar_t * buf,wchar_t * end)188*8d67ca89SAndroid Build Coastguard Worker size_t wparsefloat(FILE *fp, wchar_t *buf, wchar_t *end) {
189*8d67ca89SAndroid Build Coastguard Worker 	wchar_t *commit, *p;
190*8d67ca89SAndroid Build Coastguard Worker 	int infnanpos = 0;
191*8d67ca89SAndroid Build Coastguard Worker 	enum {
192*8d67ca89SAndroid Build Coastguard Worker 		S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
193*8d67ca89SAndroid Build Coastguard Worker 		S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
194*8d67ca89SAndroid Build Coastguard Worker 	} state = S_START;
195*8d67ca89SAndroid Build Coastguard Worker 	wint_t c;
196*8d67ca89SAndroid Build Coastguard Worker 	int gotmantdig = 0, ishex = 0;
197*8d67ca89SAndroid Build Coastguard Worker 
198*8d67ca89SAndroid Build Coastguard Worker 	/*
199*8d67ca89SAndroid Build Coastguard Worker 	 * We set commit = p whenever the string we have read so far
200*8d67ca89SAndroid Build Coastguard Worker 	 * constitutes a valid representation of a floating point
201*8d67ca89SAndroid Build Coastguard Worker 	 * number by itself.  At some point, the parse will complete
202*8d67ca89SAndroid Build Coastguard Worker 	 * or fail, and we will ungetc() back to the last commit point.
203*8d67ca89SAndroid Build Coastguard Worker 	 * To ensure that the file offset gets updated properly, it is
204*8d67ca89SAndroid Build Coastguard Worker 	 * always necessary to read at least one character that doesn't
205*8d67ca89SAndroid Build Coastguard Worker 	 * match; thus, we can't short-circuit "infinity" or "nan(...)".
206*8d67ca89SAndroid Build Coastguard Worker 	 */
207*8d67ca89SAndroid Build Coastguard Worker 	commit = buf - 1;
208*8d67ca89SAndroid Build Coastguard Worker 	c = WEOF;
209*8d67ca89SAndroid Build Coastguard Worker 	for (p = buf; p < end; ) {
210*8d67ca89SAndroid Build Coastguard Worker 		if ((c = __fgetwc_unlock(fp)) == WEOF)
211*8d67ca89SAndroid Build Coastguard Worker 			break;
212*8d67ca89SAndroid Build Coastguard Worker reswitch:
213*8d67ca89SAndroid Build Coastguard Worker 		switch (state) {
214*8d67ca89SAndroid Build Coastguard Worker 		case S_START:
215*8d67ca89SAndroid Build Coastguard Worker 			state = S_GOTSIGN;
216*8d67ca89SAndroid Build Coastguard Worker 			if (c == '-' || c == '+')
217*8d67ca89SAndroid Build Coastguard Worker 				break;
218*8d67ca89SAndroid Build Coastguard Worker 			else
219*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
220*8d67ca89SAndroid Build Coastguard Worker 		case S_GOTSIGN:
221*8d67ca89SAndroid Build Coastguard Worker 			switch (c) {
222*8d67ca89SAndroid Build Coastguard Worker 			case '0':
223*8d67ca89SAndroid Build Coastguard Worker 				state = S_MAYBEHEX;
224*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
225*8d67ca89SAndroid Build Coastguard Worker 				break;
226*8d67ca89SAndroid Build Coastguard Worker 			case 'I':
227*8d67ca89SAndroid Build Coastguard Worker 			case 'i':
228*8d67ca89SAndroid Build Coastguard Worker 				state = S_INF;
229*8d67ca89SAndroid Build Coastguard Worker 				break;
230*8d67ca89SAndroid Build Coastguard Worker 			case 'N':
231*8d67ca89SAndroid Build Coastguard Worker 			case 'n':
232*8d67ca89SAndroid Build Coastguard Worker 				state = S_NAN;
233*8d67ca89SAndroid Build Coastguard Worker 				break;
234*8d67ca89SAndroid Build Coastguard Worker 			default:
235*8d67ca89SAndroid Build Coastguard Worker 				state = S_DIGITS;
236*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
237*8d67ca89SAndroid Build Coastguard Worker 			}
238*8d67ca89SAndroid Build Coastguard Worker 			break;
239*8d67ca89SAndroid Build Coastguard Worker 		case S_INF:
240*8d67ca89SAndroid Build Coastguard Worker 			if (infnanpos > 6 ||
241*8d67ca89SAndroid Build Coastguard Worker 			    (c != (wint_t)"nfinity"[infnanpos] &&
242*8d67ca89SAndroid Build Coastguard Worker 			     c != (wint_t)"NFINITY"[infnanpos]))
243*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
244*8d67ca89SAndroid Build Coastguard Worker 			if (infnanpos == 1 || infnanpos == 6)
245*8d67ca89SAndroid Build Coastguard Worker 				commit = p;	/* inf or infinity */
246*8d67ca89SAndroid Build Coastguard Worker 			infnanpos++;
247*8d67ca89SAndroid Build Coastguard Worker 			break;
248*8d67ca89SAndroid Build Coastguard Worker 		case S_NAN:
249*8d67ca89SAndroid Build Coastguard Worker 			switch (infnanpos) {
250*8d67ca89SAndroid Build Coastguard Worker 			case -1:	/* XXX kludge to deal with nan(...) */
251*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
252*8d67ca89SAndroid Build Coastguard Worker 			case 0:
253*8d67ca89SAndroid Build Coastguard Worker 				if (c != 'A' && c != 'a')
254*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
255*8d67ca89SAndroid Build Coastguard Worker 				break;
256*8d67ca89SAndroid Build Coastguard Worker 			case 1:
257*8d67ca89SAndroid Build Coastguard Worker 				if (c != 'N' && c != 'n')
258*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
259*8d67ca89SAndroid Build Coastguard Worker 				else
260*8d67ca89SAndroid Build Coastguard Worker 					commit = p;
261*8d67ca89SAndroid Build Coastguard Worker 				break;
262*8d67ca89SAndroid Build Coastguard Worker 			case 2:
263*8d67ca89SAndroid Build Coastguard Worker 				if (c != '(')
264*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
265*8d67ca89SAndroid Build Coastguard Worker 				break;
266*8d67ca89SAndroid Build Coastguard Worker 			default:
267*8d67ca89SAndroid Build Coastguard Worker 				if (c == ')') {
268*8d67ca89SAndroid Build Coastguard Worker 					commit = p;
269*8d67ca89SAndroid Build Coastguard Worker 					infnanpos = -2;
270*8d67ca89SAndroid Build Coastguard Worker 				} else if (!iswalnum(c) && c != '_')
271*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
272*8d67ca89SAndroid Build Coastguard Worker 				break;
273*8d67ca89SAndroid Build Coastguard Worker 			}
274*8d67ca89SAndroid Build Coastguard Worker 			infnanpos++;
275*8d67ca89SAndroid Build Coastguard Worker 			break;
276*8d67ca89SAndroid Build Coastguard Worker 		case S_MAYBEHEX:
277*8d67ca89SAndroid Build Coastguard Worker 			state = S_DIGITS;
278*8d67ca89SAndroid Build Coastguard Worker 			if (c == 'X' || c == 'x') {
279*8d67ca89SAndroid Build Coastguard Worker 				ishex = 1;
280*8d67ca89SAndroid Build Coastguard Worker 				break;
281*8d67ca89SAndroid Build Coastguard Worker 			} else {	/* we saw a '0', but no 'x' */
282*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
283*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
284*8d67ca89SAndroid Build Coastguard Worker 			}
285*8d67ca89SAndroid Build Coastguard Worker 		case S_DIGITS:
286*8d67ca89SAndroid Build Coastguard Worker 			if ((ishex && iswxdigit(c)) || iswdigit(c))
287*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
288*8d67ca89SAndroid Build Coastguard Worker 			else {
289*8d67ca89SAndroid Build Coastguard Worker 				state = S_FRAC;
290*8d67ca89SAndroid Build Coastguard Worker 				if (c != L'.')
291*8d67ca89SAndroid Build Coastguard Worker 					goto reswitch;
292*8d67ca89SAndroid Build Coastguard Worker 			}
293*8d67ca89SAndroid Build Coastguard Worker 			if (gotmantdig)
294*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
295*8d67ca89SAndroid Build Coastguard Worker 			break;
296*8d67ca89SAndroid Build Coastguard Worker 		case S_FRAC:
297*8d67ca89SAndroid Build Coastguard Worker 			if (((c == 'E' || c == 'e') && !ishex) ||
298*8d67ca89SAndroid Build Coastguard Worker 			    ((c == 'P' || c == 'p') && ishex)) {
299*8d67ca89SAndroid Build Coastguard Worker 				if (!gotmantdig)
300*8d67ca89SAndroid Build Coastguard Worker 					goto parsedone;
301*8d67ca89SAndroid Build Coastguard Worker 				else
302*8d67ca89SAndroid Build Coastguard Worker 					state = S_EXP;
303*8d67ca89SAndroid Build Coastguard Worker 			} else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
304*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
305*8d67ca89SAndroid Build Coastguard Worker 				gotmantdig = 1;
306*8d67ca89SAndroid Build Coastguard Worker 			} else
307*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
308*8d67ca89SAndroid Build Coastguard Worker 			break;
309*8d67ca89SAndroid Build Coastguard Worker 		case S_EXP:
310*8d67ca89SAndroid Build Coastguard Worker 			state = S_EXPDIGITS;
311*8d67ca89SAndroid Build Coastguard Worker 			if (c == '-' || c == '+')
312*8d67ca89SAndroid Build Coastguard Worker 				break;
313*8d67ca89SAndroid Build Coastguard Worker 			else
314*8d67ca89SAndroid Build Coastguard Worker 				goto reswitch;
315*8d67ca89SAndroid Build Coastguard Worker 		case S_EXPDIGITS:
316*8d67ca89SAndroid Build Coastguard Worker 			if (iswdigit(c))
317*8d67ca89SAndroid Build Coastguard Worker 				commit = p;
318*8d67ca89SAndroid Build Coastguard Worker 			else
319*8d67ca89SAndroid Build Coastguard Worker 				goto parsedone;
320*8d67ca89SAndroid Build Coastguard Worker 			break;
321*8d67ca89SAndroid Build Coastguard Worker 		default:
322*8d67ca89SAndroid Build Coastguard Worker 			abort();
323*8d67ca89SAndroid Build Coastguard Worker 		}
324*8d67ca89SAndroid Build Coastguard Worker 		*p++ = c;
325*8d67ca89SAndroid Build Coastguard Worker 		c = WEOF;
326*8d67ca89SAndroid Build Coastguard Worker 	}
327*8d67ca89SAndroid Build Coastguard Worker 
328*8d67ca89SAndroid Build Coastguard Worker parsedone:
329*8d67ca89SAndroid Build Coastguard Worker 	if (c != WEOF)
330*8d67ca89SAndroid Build Coastguard Worker 		ungetwc(c, fp);
331*8d67ca89SAndroid Build Coastguard Worker 	while (commit < --p)
332*8d67ca89SAndroid Build Coastguard Worker 		ungetwc(*p, fp);
333*8d67ca89SAndroid Build Coastguard Worker 	*++commit = '\0';
334*8d67ca89SAndroid Build Coastguard Worker 	return (int)(commit - buf);
335*8d67ca89SAndroid Build Coastguard Worker }
336