c-strtod.c 2.5 KB

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