summaryrefslogtreecommitdiffstats
path: root/gl/c-strtod.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/c-strtod.c')
-rw-r--r--gl/c-strtod.c48
1 files changed, 41 insertions, 7 deletions
diff --git a/gl/c-strtod.c b/gl/c-strtod.c
index 95624cc..51e996e 100644
--- a/gl/c-strtod.c
+++ b/gl/c-strtod.c
@@ -1,6 +1,6 @@
1/* Convert string to double, using the C locale. 1/* Convert string to double, using the C locale.
2 2
3 Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. 3 Copyright (C) 2003, 2004, 2006, 2009 Free Software Foundation, Inc.
4 4
5 This program is free software: you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published by
@@ -21,10 +21,10 @@
21 21
22#include "c-strtod.h" 22#include "c-strtod.h"
23 23
24#include <errno.h>
24#include <locale.h> 25#include <locale.h>
25#include <stdlib.h> 26#include <stdlib.h>
26 27#include <string.h>
27#include "xalloc.h"
28 28
29#if LONG 29#if LONG
30# define C_STRTOD c_strtold 30# define C_STRTOD c_strtold
@@ -43,6 +43,25 @@
43# define STRTOD strtod 43# define STRTOD strtod
44#endif 44#endif
45 45
46#ifdef LC_ALL_MASK
47
48/* Cache for the C locale object.
49 Marked volatile so that different threads see the same value
50 (avoids locking). */
51static 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. */
55static inline locale_t
56c_locale (void)
57{
58 if (!c_locale_cache)
59 c_locale_cache = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
60 return c_locale_cache;
61}
62
63#endif
64
46DOUBLE 65DOUBLE
47C_STRTOD (char const *nptr, char **endptr) 66C_STRTOD (char const *nptr, char **endptr)
48{ 67{
@@ -50,9 +69,15 @@ C_STRTOD (char const *nptr, char **endptr)
50 69
51#ifdef LC_ALL_MASK 70#ifdef LC_ALL_MASK
52 71
53 locale_t c_locale = newlocale (LC_ALL_MASK, "C", 0); 72 locale_t locale = c_locale ();
54 r = STRTOD_L (nptr, endptr, c_locale); 73 if (!locale)
55 freelocale (c_locale); 74 {
75 if (endptr)
76 *endptr = (char *) nptr;
77 return 0; /* errno is set here */
78 }
79
80 r = STRTOD_L (nptr, endptr, locale);
56 81
57#else 82#else
58 83
@@ -60,7 +85,13 @@ C_STRTOD (char const *nptr, char **endptr)
60 85
61 if (saved_locale) 86 if (saved_locale)
62 { 87 {
63 saved_locale = xstrdup (saved_locale); 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 }
64 setlocale (LC_NUMERIC, "C"); 95 setlocale (LC_NUMERIC, "C");
65 } 96 }
66 97
@@ -68,8 +99,11 @@ C_STRTOD (char const *nptr, char **endptr)
68 99
69 if (saved_locale) 100 if (saved_locale)
70 { 101 {
102 int saved_errno = errno;
103
71 setlocale (LC_NUMERIC, saved_locale); 104 setlocale (LC_NUMERIC, saved_locale);
72 free (saved_locale); 105 free (saved_locale);
106 errno = saved_errno;
73 } 107 }
74 108
75#endif 109#endif