Panda3D
|
00001 // Filename: pstrtod.cxx 00002 // Created by: drose (13Jun09) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pstrtod.h" 00016 00017 #include <ctype.h> 00018 #include <math.h> 00019 00020 00021 //////////////////////////////////////////////////////////////////// 00022 // Function: pstrtod 00023 // Description: This function re-implements strtod, to avoid the 00024 // problems that occur when the LC_NUMERIC locale gets 00025 // set to anything other than "C". Regardless of the 00026 // user's locale, we need to be able to parse 00027 // floating-point numbers internally understanding a "." 00028 // as the decimal point. 00029 //////////////////////////////////////////////////////////////////// 00030 double 00031 pstrtod(const char *nptr, char **endptr) { 00032 // First, skip whitespace. 00033 const char *p = nptr; 00034 while (isspace(*p)) { 00035 ++p; 00036 } 00037 00038 // Skip an optional leading sign. 00039 char sign = '+'; 00040 if (*p == '+' || *p == '-') { 00041 sign = *p; 00042 ++p; 00043 } 00044 00045 double value = 0.0; 00046 00047 if (isalpha(*p)) { 00048 // For special cases like "inf" and "nan", pass these up to the 00049 // system implementation of strtod. 00050 return strtod(nptr, endptr); 00051 } 00052 00053 // Start reading decimal digits to the left of the decimal point. 00054 bool found_digits = false; 00055 while (isdigit(*p)) { 00056 value = (value * 10.0) + (*p - '0'); 00057 found_digits = true; 00058 ++p; 00059 } 00060 00061 if (*p == '.') { 00062 ++p; 00063 // Read decimal digits to the right of the decimal point. 00064 double multiplicand = 0.1; 00065 while (isdigit(*p)) { 00066 value += (*p - '0') * multiplicand; 00067 ++p; 00068 found_digits = true; 00069 multiplicand *= 0.1; 00070 } 00071 } 00072 00073 if (!found_digits) { 00074 // Not a valid float. 00075 if (endptr != NULL) { 00076 *endptr = (char *)nptr; 00077 } 00078 return 0.0; 00079 } 00080 00081 if (tolower(*p) == 'e') { 00082 // There's an exponent. 00083 ++p; 00084 00085 char esign = '+'; 00086 if (*p == '+' || *p == '-') { 00087 esign = *p; 00088 ++p; 00089 } 00090 00091 // Start reading decimal digits to the left of the decimal point. 00092 double evalue = 0.0; 00093 while (isdigit(*p)) { 00094 evalue = (evalue * 10.0) + (*p - '0'); 00095 ++p; 00096 } 00097 00098 if (esign == '-') { 00099 value /= pow(evalue, 10.0); 00100 } else { 00101 value *= pow(evalue, 10.0); 00102 } 00103 } 00104 00105 if (sign == '-') { 00106 value = -value; 00107 } 00108 00109 if (endptr != NULL) { 00110 *endptr = (char *)p; 00111 } 00112 return value; 00113 } 00114 00115 00116 //////////////////////////////////////////////////////////////////// 00117 // Function: patof 00118 // Description: This function re-implements atof, to avoid the 00119 // problems that occur when the LC_NUMERIC locale gets 00120 // set to anything other than "C". Regardless of the 00121 // user's locale, we need to be able to parse 00122 // floating-point numbers internally understanding a "." 00123 // as the decimal point. 00124 //////////////////////////////////////////////////////////////////// 00125 double 00126 patof(const char *str) { 00127 return pstrtod(str, (char **)NULL); 00128 }