This source file includes following definitions.
- locale_isspace
- decimal_point_char
- LDEXP
- scale_radix_exp
- parse_number
- minus_zero
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 #if ! defined USE_LONG_DOUBLE
18 # include <config.h>
19 #endif
20
21
22 #include <stdlib.h>
23
24 #include <ctype.h>
25 #include <errno.h>
26 #include <float.h>
27 #include <limits.h>
28 #include <locale.h>
29 #include <math.h>
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <string.h>
33 #if HAVE_NL_LANGINFO
34 # include <langinfo.h>
35 #endif
36
37 #include "c-ctype.h"
38
39 #undef MIN
40 #undef MAX
41 #ifdef USE_LONG_DOUBLE
42 # define STRTOD strtold
43 # define LDEXP ldexpl
44 # if defined __hpux && defined __hppa
45
46
47 # define HAVE_UNDERLYING_STRTOD 0
48 # elif STRTOLD_HAS_UNDERFLOW_BUG
49
50 # define HAVE_UNDERLYING_STRTOD 0
51 # else
52 # define HAVE_UNDERLYING_STRTOD HAVE_STRTOLD
53 # endif
54 # define DOUBLE long double
55 # define MIN LDBL_MIN
56 # define MAX LDBL_MAX
57 # define L_(literal) literal##L
58 #else
59 # define STRTOD strtod
60 # define LDEXP ldexp
61 # define HAVE_UNDERLYING_STRTOD 1
62 # define DOUBLE double
63 # define MIN DBL_MIN
64 # define MAX DBL_MAX
65 # define L_(literal) literal
66 #endif
67
68 #if (defined USE_LONG_DOUBLE ? HAVE_LDEXPM_IN_LIBC : HAVE_LDEXP_IN_LIBC)
69 # define USE_LDEXP 1
70 #else
71 # define USE_LDEXP 0
72 #endif
73
74
75
76 static bool
77 locale_isspace (char c)
78 {
79 unsigned char uc = c;
80 return isspace (uc) != 0;
81 }
82
83
84 static char
85 decimal_point_char (void)
86 {
87 const char *point;
88
89
90
91
92 #if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__))
93 point = nl_langinfo (RADIXCHAR);
94 #elif 1
95 char pointbuf[5];
96 sprintf (pointbuf, "%#.0f", 1.0);
97 point = &pointbuf[1];
98 #else
99 point = localeconv () -> decimal_point;
100 #endif
101
102 return (point[0] != '\0' ? point[0] : '.');
103 }
104
105 #if !USE_LDEXP
106 #undef LDEXP
107 #define LDEXP dummy_ldexp
108
109 static DOUBLE LDEXP (_GL_UNUSED DOUBLE x, _GL_UNUSED int exponent)
110 {
111 abort ();
112 return L_(0.0);
113 }
114 #endif
115
116
117
118 static DOUBLE
119 scale_radix_exp (DOUBLE x, int radix, long int exponent)
120 {
121
122
123
124
125
126 long int e = exponent;
127
128 if (USE_LDEXP && radix == 2)
129 return LDEXP (x, e < INT_MIN ? INT_MIN : INT_MAX < e ? INT_MAX : e);
130 else
131 {
132 DOUBLE r = x;
133
134 if (r != 0)
135 {
136 if (e < 0)
137 {
138 while (e++ != 0)
139 {
140 r /= radix;
141 if (r == 0 && x != 0)
142 {
143 errno = ERANGE;
144 break;
145 }
146 }
147 }
148 else
149 {
150 while (e-- != 0)
151 {
152 if (r < -MAX / radix)
153 {
154 errno = ERANGE;
155 return -HUGE_VAL;
156 }
157 else if (MAX / radix < r)
158 {
159 errno = ERANGE;
160 return HUGE_VAL;
161 }
162 else
163 r *= radix;
164 }
165 }
166 }
167
168 return r;
169 }
170 }
171
172
173
174
175
176
177 static DOUBLE
178 parse_number (const char *nptr,
179 int base, int radix, int radix_multiplier, char radixchar,
180 char expchar,
181 char **endptr)
182 {
183 const char *s = nptr;
184 const char *digits_start;
185 const char *digits_end;
186 const char *radixchar_ptr;
187 long int exponent;
188 DOUBLE num;
189
190
191 digits_start = s;
192 radixchar_ptr = NULL;
193 for (;; ++s)
194 {
195 if (base == 16 ? c_isxdigit (*s) : c_isdigit (*s))
196 ;
197 else if (radixchar_ptr == NULL && *s == radixchar)
198 {
199
200 radixchar_ptr = s;
201 }
202 else
203
204 break;
205 }
206 digits_end = s;
207
208
209
210 if (false)
211 {
212 exponent =
213 (radixchar_ptr != NULL
214 ? - (long int) (digits_end - radixchar_ptr - 1)
215 : 0);
216 }
217 else
218 {
219
220 while (digits_end > digits_start)
221 {
222 if (digits_end - 1 == radixchar_ptr || *(digits_end - 1) == '0')
223 digits_end--;
224 else
225 break;
226 }
227 exponent =
228 (radixchar_ptr != NULL
229 ? (digits_end > radixchar_ptr
230 ? - (long int) (digits_end - radixchar_ptr - 1)
231 : (long int) (radixchar_ptr - digits_end))
232 : (long int) (s - digits_end));
233 }
234
235
236 {
237 const char *dp;
238 num = 0;
239 for (dp = digits_start; dp < digits_end; dp++)
240 if (dp != radixchar_ptr)
241 {
242 int digit;
243
244
245 if (!(num <= MAX / base))
246 {
247
248
249
250
251
252 exponent +=
253 (digits_end - dp)
254 - (radixchar_ptr >= dp && radixchar_ptr < digits_end ? 1 : 0);
255 break;
256 }
257
258
259 if (c_isdigit (*dp))
260 digit = *dp - '0';
261 else if (base == 16 && c_isxdigit (*dp))
262 digit = c_tolower (*dp) - ('a' - 10);
263 else
264 abort ();
265 num = num * base + digit;
266 }
267 }
268
269 exponent = exponent * radix_multiplier;
270
271
272 if (c_tolower (*s) == expchar && ! locale_isspace (s[1]))
273 {
274
275 int saved_errno = errno;
276 char *end;
277 long int value = strtol (s + 1, &end, 10);
278 errno = saved_errno;
279
280 if (s + 1 != end)
281 {
282
283
284 s = end;
285 exponent =
286 (exponent < 0
287 ? (value < LONG_MIN - exponent ? LONG_MIN : exponent + value)
288 : (LONG_MAX - exponent < value ? LONG_MAX : exponent + value));
289 }
290 }
291
292 *endptr = (char *) s;
293 return scale_radix_exp (num, radix, exponent);
294 }
295
296
297
298
299
300 static DOUBLE
301 minus_zero (void)
302 {
303 #if defined __hpux || defined __sgi || defined __ICC
304 return -MIN * MIN;
305 #else
306 return -0.0;
307 #endif
308 }
309
310
311
312 DOUBLE
313 STRTOD (const char *nptr, char **endptr)
314 #if HAVE_UNDERLYING_STRTOD
315 # ifdef USE_LONG_DOUBLE
316 # undef strtold
317 # else
318 # undef strtod
319 # endif
320 #else
321 # undef STRTOD
322 # define STRTOD(NPTR,ENDPTR) \
323 parse_number (NPTR, 10, 10, 1, radixchar, 'e', ENDPTR)
324 #endif
325
326
327 {
328 char radixchar;
329 bool negative = false;
330
331
332 DOUBLE num;
333
334 const char *s = nptr;
335 const char *end;
336 char *endbuf;
337 int saved_errno = errno;
338
339 radixchar = decimal_point_char ();
340
341
342 while (locale_isspace (*s))
343 ++s;
344
345
346 negative = *s == '-';
347 if (*s == '-' || *s == '+')
348 ++s;
349
350 num = STRTOD (s, &endbuf);
351 end = endbuf;
352
353 if (c_isdigit (s[*s == radixchar]))
354 {
355
356
357
358
359 if (*s == '0' && c_tolower (s[1]) == 'x')
360 {
361 if (! c_isxdigit (s[2 + (s[2] == radixchar)]))
362 {
363 end = s + 1;
364
365
366 errno = saved_errno;
367 }
368 else if (end <= s + 2)
369 {
370 num = parse_number (s + 2, 16, 2, 4, radixchar, 'p', &endbuf);
371 end = endbuf;
372 }
373 else
374 {
375 const char *p = s + 2;
376 while (p < end && c_tolower (*p) != 'p')
377 p++;
378 if (p < end && ! c_isdigit (p[1 + (p[1] == '-' || p[1] == '+')]))
379 {
380 char *dup = strdup (s);
381 errno = saved_errno;
382 if (!dup)
383 {
384
385
386 num =
387 parse_number (s + 2, 16, 2, 4, radixchar, 'p', &endbuf);
388 }
389 else
390 {
391 dup[p - s] = '\0';
392 num = STRTOD (dup, &endbuf);
393 saved_errno = errno;
394 free (dup);
395 errno = saved_errno;
396 }
397 end = p;
398 }
399 }
400 }
401 else
402 {
403
404
405
406 const char *e = s + 1;
407 while (e < end && c_tolower (*e) != 'e')
408 e++;
409 if (e < end && ! c_isdigit (e[1 + (e[1] == '-' || e[1] == '+')]))
410 {
411 char *dup = strdup (s);
412 errno = saved_errno;
413 if (!dup)
414 {
415
416
417 num = parse_number (s, 10, 10, 1, radixchar, 'e', &endbuf);
418 }
419 else
420 {
421 dup[e - s] = '\0';
422 num = STRTOD (dup, &endbuf);
423 saved_errno = errno;
424 free (dup);
425 errno = saved_errno;
426 }
427 end = e;
428 }
429 }
430
431 s = end;
432 }
433
434
435 else if (c_tolower (*s) == 'i'
436 && c_tolower (s[1]) == 'n'
437 && c_tolower (s[2]) == 'f')
438 {
439 s += 3;
440 if (c_tolower (*s) == 'i'
441 && c_tolower (s[1]) == 'n'
442 && c_tolower (s[2]) == 'i'
443 && c_tolower (s[3]) == 't'
444 && c_tolower (s[4]) == 'y')
445 s += 5;
446 num = HUGE_VAL;
447 errno = saved_errno;
448 }
449 else if (c_tolower (*s) == 'n'
450 && c_tolower (s[1]) == 'a'
451 && c_tolower (s[2]) == 'n')
452 {
453 s += 3;
454 if (*s == '(')
455 {
456 const char *p = s + 1;
457 while (c_isalnum (*p))
458 p++;
459 if (*p == ')')
460 s = p + 1;
461 }
462
463
464
465
466
467
468 if (s != end || num == num)
469 num = NAN;
470 errno = saved_errno;
471 }
472 else
473 {
474
475 errno = EINVAL;
476 s = nptr;
477 }
478
479 if (endptr != NULL)
480 *endptr = (char *) s;
481
482
483 if (!num && negative)
484 return minus_zero ();
485 return negative ? -num : num;
486 }