diff --git a/dtool/pptempl/Template.unix.pp b/dtool/pptempl/Template.unix.pp index 62db932899..73673a8366 100644 --- a/dtool/pptempl/Template.unix.pp +++ b/dtool/pptempl/Template.unix.pp @@ -122,7 +122,7 @@ // And $[frameworks] is the set of OSX-style frameworks we will link with. #defer frameworks $[unique $[get_frameworks]] -#defer bin_frameworks $[unique $[all_libs $[get_frameworks],$[complete_local_libs]]] +#defer bin_frameworks $[unique $[get_frameworks] $[all_libs $[get_frameworks],$[complete_local_libs]]] //#defer bin_frameworks $[unique $[get_frameworks]] // This is the set of files we might copy into *.prebuilt, if we have diff --git a/dtool/src/cppparser/cppPreprocessor.cxx b/dtool/src/cppparser/cppPreprocessor.cxx index cd47e27fe2..f48a057cb1 100644 --- a/dtool/src/cppparser/cppPreprocessor.cxx +++ b/dtool/src/cppparser/cppPreprocessor.cxx @@ -25,6 +25,7 @@ #include "cppCommentBlock.h" #include "cppBison.h" #include "indent.h" +#include "pstrtod.h" #include #include @@ -1915,7 +1916,7 @@ get_number(int c, int c2) { _last_c = c; YYSTYPE result; - result.u.real = strtod(num.c_str(), (char **)NULL); + result.u.real = pstrtod(num.c_str(), (char **)NULL); return CPPToken(REAL, first_line, first_col, first_file, num, result); } diff --git a/dtool/src/dtoolbase/Sources.pp b/dtool/src/dtoolbase/Sources.pp index 06e995856c..7dafe631f1 100644 --- a/dtool/src/dtoolbase/Sources.pp +++ b/dtool/src/dtoolbase/Sources.pp @@ -29,6 +29,7 @@ nearly_zero.h \ neverFreeMemory.h neverFreeMemory.I \ numeric_types.h \ + pstrtod.h \ register_type.I register_type.h \ selectThreadImpl.h \ stl_compares.I stl_compares.h \ @@ -56,6 +57,7 @@ mutexWin32Impl.cxx \ mutexSpinlockImpl.cxx \ neverFreeMemory.cxx \ + pstrtod.cxx \ register_type.cxx \ typeHandle.cxx \ typeRegistry.cxx typeRegistryNode.cxx \ @@ -83,6 +85,7 @@ nearly_zero.h \ neverFreeMemory.h neverFreeMemory.I \ numeric_types.h \ + pstrtod.h \ register_type.I register_type.h \ selectThreadImpl.h \ stl_compares.I stl_compares.h \ @@ -95,3 +98,9 @@ lookup3.h #end lib_target + +#begin test_bin_target + #define TARGET test_strtod + #define SOURCES test_strtod.cxx pstrtod.cxx pstrtod.h + +#end test_bin_target diff --git a/dtool/src/dtoolbase/dtoolbase_composite2.cxx b/dtool/src/dtoolbase/dtoolbase_composite2.cxx index 4b307c38e4..3bac46d398 100644 --- a/dtool/src/dtoolbase/dtoolbase_composite2.cxx +++ b/dtool/src/dtoolbase/dtoolbase_composite2.cxx @@ -2,6 +2,7 @@ #include "mutexWin32Impl.cxx" #include "mutexSpinlockImpl.cxx" #include "neverFreeMemory.cxx" +#include "pstrtod.cxx" #include "register_type.cxx" #include "typeHandle.cxx" #include "typeRegistry.cxx" diff --git a/dtool/src/dtoolbase/pstrtod.cxx b/dtool/src/dtoolbase/pstrtod.cxx new file mode 100644 index 0000000000..bed73a1b82 --- /dev/null +++ b/dtool/src/dtoolbase/pstrtod.cxx @@ -0,0 +1,179 @@ +// Filename: pstrtod.cxx +// Created by: drose (13Jun09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "pstrtod.h" + +#include +#include + +//////////////////////////////////////////////////////////////////// +// Function: pstrnicmp +// Description: This case-insenstive string compare function is used +// by pstrtod, below. +//////////////////////////////////////////////////////////////////// +static int +pstrnicmp(const char *s1, const char *s2, size_t n) { + if (n == 0) { + // Trivial equivalence. + return 0; + } + while (tolower(*s1) == tolower(*s2)) { + --n; + if ((*s1) == '\0' || n == 0) { + // They reached the end of the string together. + return 0; + } + ++s1; + ++s2; + } + + // There's a difference somewhere. + return (int)(unsigned char)(*s1) - (int)(unsigned char)(*s2); +} + + +//////////////////////////////////////////////////////////////////// +// Function: pstrtod +// Description: This function re-implements strtod, to avoid the +// problems that occur when the LC_NUMERIC locale gets +// set to anything other than "C". Regardless of the +// user's locale, we need to be able to parse +// floating-point numbers internally understanding a "." +// as the decimal point. +//////////////////////////////////////////////////////////////////// +double +pstrtod(const char *nptr, char **endptr) { + // First, skip whitespace. + const char *p = nptr; + while (isspace(*p)) { + ++p; + } + + // Skip an optional leading sign. + char sign = '+'; + if (*p == '+' || *p == '-') { + sign = *p; + ++p; + } + + double value = 0.0; + + if (pstrnicmp(p, "infinity", 8) == 0) { + value = INFINITY; + p += 8; + } else if (pstrnicmp(p, "inf", 3) == 0) { + value = INFINITY; + p += 3; + } else if (pstrnicmp(p, "nan", 3) == 0) { + value = NAN; + p += 3; + if (pstrnicmp(p, "0x", 2) == 0) { + // The NaN code also appears in the string. Use it. + static const size_t nan_code_size = 32; + char nan_code[nan_code_size + 1]; + nan_code[0] = '0'; + nan_code[1] = 'x'; + const char *q = p + 2; + int ni = 2; + while (isdigit(*q) || (tolower(*q) >= 'a' && tolower(*q) <= 'f')) { + if (ni < nan_code_size) { + nan_code[ni] = *q; + ++ni; + } + ++q; + } + nan_code[ni] = '\0'; + value = nan(nan_code); + p = q; + } + + } else { + + // Start reading decimal digits to the left of the decimal point. + bool found_digits = false; + while (isdigit(*p)) { + value = (value * 10.0) + (*p - '0'); + found_digits = true; + ++p; + } + + if (*p == '.') { + ++p; + // Read decimal digits to the right of the decimal point. + double multiplicand = 0.1; + while (isdigit(*p)) { + value += (*p - '0') * multiplicand; + ++p; + found_digits = true; + multiplicand *= 0.1; + } + } + + if (!found_digits) { + // Not a valid float. + if (endptr != NULL) { + *endptr = (char *)nptr; + } + return 0.0; + } + + if (tolower(*p) == 'e') { + // There's an exponent. + ++p; + + char esign = '+'; + if (*p == '+' || *p == '-') { + esign = *p; + ++p; + } + + // Start reading decimal digits to the left of the decimal point. + double evalue = 0.0; + while (isdigit(*p)) { + evalue = (evalue * 10.0) + (*p - '0'); + ++p; + } + + if (esign == '-') { + value /= pow(evalue, 10.0); + } else { + value *= pow(evalue, 10.0); + } + } + } + + if (sign == '-') { + value = -value; + } + + if (endptr != NULL) { + *endptr = (char *)p; + } + return value; +} + + +//////////////////////////////////////////////////////////////////// +// Function: patof +// Description: This function re-implements atof, to avoid the +// problems that occur when the LC_NUMERIC locale gets +// set to anything other than "C". Regardless of the +// user's locale, we need to be able to parse +// floating-point numbers internally understanding a "." +// as the decimal point. +//////////////////////////////////////////////////////////////////// +double +patof(const char *str) { + return pstrtod(str, (char **)NULL); +} diff --git a/dtool/src/dtoolbase/pstrtod.h b/dtool/src/dtoolbase/pstrtod.h new file mode 100644 index 0000000000..fef5c844c3 --- /dev/null +++ b/dtool/src/dtoolbase/pstrtod.h @@ -0,0 +1,34 @@ +// Filename: pstrtod.h +// Created by: drose (13Jun09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef PSTRTOD_H +#define PSTRTOD_H + +#include "dtoolbase.h" + +#ifdef __cplusplus +extern "C" { +#endif + +EXPCL_DTOOL double +pstrtod(const char *nptr, char **endptr); + +EXPCL_DTOOL double +patof(const char *str); + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +#endif diff --git a/dtool/src/dtoolbase/test_strtod.cxx b/dtool/src/dtoolbase/test_strtod.cxx new file mode 100644 index 0000000000..dd61f4f03a --- /dev/null +++ b/dtool/src/dtoolbase/test_strtod.cxx @@ -0,0 +1,36 @@ +// Filename: test_strtod.cxx +// Created by: drose (14Jun09) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "pstrtod.h" + +#ifndef _WIN32 +#include +#endif + +int +main(int argc, char *argv[]) { +#ifndef _WIN32 + setlocale(LC_ALL, ""); +#endif + + for (int i = 1; i < argc; ++i) { + char *endptr = NULL; + double result = pstrtod(argv[i], &endptr); + cerr << "pstrtod - " << argv[i] << " : " << result << " : " << endptr << "\n"; + result = strtod(argv[i], &endptr); + cerr << "strtod - " << argv[i] << " : " << result << " : " << endptr << "\n"; + } + + return 0; +}