Line data Source code
1 : /* Convert string to double, using the C locale.
2 :
3 : Copyright (C) 2003-2004, 2006, 2009-2016 Free Software Foundation, Inc.
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation; either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 :
18 : /* Written by Paul Eggert. */
19 :
20 : #include <config.h>
21 :
22 : #include "c-strtod.h"
23 :
24 : #include <errno.h>
25 : #include <locale.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 :
29 : #if LONG
30 : # define C_STRTOD c_strtold
31 : # define DOUBLE long double
32 : # define STRTOD_L strtold_l
33 : #else
34 : # define C_STRTOD c_strtod
35 : # define DOUBLE double
36 : # define STRTOD_L strtod_l
37 : #endif
38 :
39 : /* c_strtold falls back on strtod if strtold doesn't conform to C99. */
40 : #if LONG && HAVE_C99_STRTOLD
41 : # define STRTOD strtold
42 : #else
43 : # define STRTOD strtod
44 : #endif
45 :
46 : #if defined LC_ALL_MASK && (LONG ? HAVE_STRTOLD_L : HAVE_STRTOD_L)
47 :
48 : /* Cache for the C locale object.
49 : Marked volatile so that different threads see the same value
50 : (avoids locking). */
51 : static volatile locale_t c_locale_cache;
52 :
53 : /* Return the C locale object, or (locale_t) 0 with errno set
54 : if it cannot be created. */
55 : static locale_t
56 8 : c_locale (void)
57 : {
58 8 : if (!c_locale_cache)
59 1 : c_locale_cache = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
60 8 : return c_locale_cache;
61 : }
62 :
63 : #endif
64 :
65 : DOUBLE
66 8 : C_STRTOD (char const *nptr, char **endptr)
67 : {
68 : DOUBLE r;
69 :
70 : #if defined LC_ALL_MASK && (LONG ? HAVE_STRTOLD_L : HAVE_STRTOD_L)
71 :
72 8 : locale_t locale = c_locale ();
73 8 : if (!locale)
74 : {
75 0 : if (endptr)
76 0 : *endptr = (char *) nptr;
77 0 : return 0; /* errno is set here */
78 : }
79 :
80 8 : r = STRTOD_L (nptr, endptr, locale);
81 :
82 : #else
83 :
84 : char *saved_locale = setlocale (LC_NUMERIC, NULL);
85 :
86 : if (saved_locale)
87 : {
88 : saved_locale = strdup (saved_locale);
89 : if (saved_locale == NULL)
90 : {
91 : if (endptr)
92 : *endptr = (char *) nptr;
93 : return 0; /* errno is set here */
94 : }
95 : setlocale (LC_NUMERIC, "C");
96 : }
97 :
98 : r = STRTOD (nptr, endptr);
99 :
100 : if (saved_locale)
101 : {
102 : int saved_errno = errno;
103 :
104 : setlocale (LC_NUMERIC, saved_locale);
105 : free (saved_locale);
106 : errno = saved_errno;
107 : }
108 :
109 : #endif
110 :
111 8 : return r;
112 : }
|