Panda3D
pstrtod.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file pstrtod.cxx
10  * @author drose
11  * @date 2009-06-13
12  */
13 
14 #include "pstrtod.h"
15 
16 #include <ctype.h>
17 #include <math.h>
18 #include <limits>
19 
20 #ifdef _WIN32
21 #define strncasecmp _strnicmp
22 #endif
23 
24 /**
25  * This function re-implements strtod, to avoid the problems that occur when
26  * the LC_NUMERIC locale gets set to anything other than "C". Regardless of
27  * the user's locale, we need to be able to parse floating-point numbers
28  * internally understanding a "." as the decimal point.
29  */
30 double
31 pstrtod(const char *nptr, char **endptr) {
32  // First, skip whitespace.
33  const char *p = nptr;
34  while (isspace(*p)) {
35  ++p;
36  }
37 
38  // Skip an optional leading sign.
39  char sign = '+';
40  if (*p == '+' || *p == '-') {
41  sign = *p;
42  ++p;
43  }
44 
45  double value = 0.0;
46 
47  if (isalpha(*p)) {
48  // Windows' implementation of strtod doesn't support "inf" or "nan", so
49  // check for those here.
50  if (strncasecmp(p, "inf", 3) == 0) {
51  p += 3;
52  if (strncasecmp(p, "inity", 5) == 0) {
53  p += 5;
54  }
55  value = std::numeric_limits<double>::infinity();
56 
57  } else if (strncasecmp(p, "nan", 3) == 0) {
58  p += 3;
59 
60  if (*p == 's' || *p == 'S') {
61  value = std::numeric_limits<double>::signaling_NaN();
62  ++p;
63  } else {
64  if (*p == 'q' || *p == 'Q') {
65  ++p;
66  }
67  value = std::numeric_limits<double>::quiet_NaN();
68  }
69 
70  // It is optionally possible to include a character sequence between
71  // parentheses after "nan", to be passed to the new nan() function.
72  // Since it isn't supported universally, we will only accept a pair of
73  // empty parentheses.
74  if (strncmp(p, "()", 2) == 0) {
75  p += 2;
76  }
77 
78  } else {
79  // Pass it up to the system implementation of strtod; perhaps it knows
80  // how to deal with this string.
81  return strtod(nptr, endptr);
82  }
83 
84  } else {
85  // Start reading decimal digits to the left of the decimal point.
86  bool found_digits = false;
87  while (isdigit(*p)) {
88  value = (value * 10.0) + (*p - '0');
89  found_digits = true;
90  ++p;
91  }
92 
93  if (*p == '.') {
94  ++p;
95  // Read decimal digits to the right of the decimal point.
96  double multiplicand = 0.1;
97  while (isdigit(*p)) {
98  value += (*p - '0') * multiplicand;
99  ++p;
100  found_digits = true;
101  multiplicand *= 0.1;
102  }
103  }
104 
105  if (!found_digits) {
106  // Not a valid float.
107  if (endptr != nullptr) {
108  *endptr = (char *)nptr;
109  }
110  return 0.0;
111  }
112 
113  if (tolower(*p) == 'e') {
114  // There's an exponent.
115  ++p;
116 
117  char esign = '+';
118  if (*p == '+' || *p == '-') {
119  esign = *p;
120  ++p;
121  }
122 
123  // Start reading decimal digits to the left of the decimal point.
124  double evalue = 0.0;
125  while (isdigit(*p)) {
126  evalue = (evalue * 10.0) + (*p - '0');
127  ++p;
128  }
129 
130  if (esign == '-') {
131  value /= pow(10.0, evalue);
132  } else {
133  value *= pow(10.0, evalue);
134  }
135  }
136  }
137 
138  if (sign == '-') {
139  value = -value;
140  }
141 
142  if (endptr != nullptr) {
143  *endptr = (char *)p;
144  }
145  return value;
146 }
147 
148 
149 /**
150  * This function re-implements atof, to avoid the problems that occur when the
151  * LC_NUMERIC locale gets set to anything other than "C". Regardless of the
152  * user's locale, we need to be able to parse floating-point numbers
153  * internally understanding a "." as the decimal point.
154  */
155 double
156 patof(const char *str) {
157  return pstrtod(str, nullptr);
158 }
double pstrtod(const char *nptr, char **endptr)
This function re-implements strtod, to avoid the problems that occur when the LC_NUMERIC locale gets ...
Definition: pstrtod.cxx:31
double patof(const char *str)
This function re-implements atof, to avoid the problems that occur when the LC_NUMERIC locale gets se...
Definition: pstrtod.cxx:156
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.