diff options
Diffstat (limited to 'src/strtod.cpp')
| -rw-r--r-- | src/strtod.cpp | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/src/strtod.cpp b/src/strtod.cpp new file mode 100644 index 00000000..5a360c2e --- /dev/null +++ b/src/strtod.cpp @@ -0,0 +1,195 @@ +/****************************************************************************** + * + * Derived from GDAL port/cpl_strtod.cpp + * Purpose: Functions to convert ASCII string to floating point number. + * Author: Andrey Kiselev, dron@ak4719.spb.edu. + * + ****************************************************************************** + * Copyright (c) 2006, Andrey Kiselev + * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ****************************************************************************/ + +#include <errno.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> + +#include "projects.h" + +/* Windows nmake build doesn't have a proj_config.h, but HAVE_LOCALECONV */ +/* is defined in the compilation line */ +#ifndef HAVE_LOCALECONV +#include "proj_config.h" +#endif + +#define PJ_STRTOD_WORK_BUFFER_SIZE 64 + +/************************************************************************/ +/* pj_atof() */ +/************************************************************************/ + +/** + * Converts ASCII string to floating point number. + * + * This function converts the initial portion of the string pointed to + * by nptr to double floating point representation. The behaviour is the + * same as + * + * pj_strtod(nptr, (char **)NULL); + * + * This function does the same as standard atof(3), but does not take + * locale in account. That means, the decimal delimiter is always '.' + * (decimal point). + * + * @param nptr Pointer to string to convert. + * + * @return Converted value. + */ +double pj_atof( const char* nptr ) +{ + return pj_strtod(nptr, nullptr); +} + + +/************************************************************************/ +/* replace_point_by_locale_point() */ +/************************************************************************/ + +static char* replace_point_by_locale_point(const char* pszNumber, char point, + char* pszWorkBuffer) +{ +#if !defined(HAVE_LOCALECONV) + +#if defined(_MSC_VER) /* Visual C++ */ +#pragma message("localeconv not available") +#else +#warning "localeconv not available" +#endif + + static char byPoint = 0; + if (byPoint == 0) + { + char szBuf[16]; + sprintf(szBuf, "%.1f", 1.0); + byPoint = szBuf[1]; + } + if (point != byPoint) + { + const char* pszPoint = strchr(pszNumber, point); + if (pszPoint) + { + char* pszNew; + if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) + { + strcpy(pszWorkBuffer, pszNumber); + pszNew = pszWorkBuffer; + } + else { + pszNew = pj_strdup(pszNumber); + if (!pszNew) + return NULL; + } + pszNew[pszPoint - pszNumber] = byPoint; + return pszNew; + } + } +#else + struct lconv *poLconv = localeconv(); + if ( poLconv + && poLconv->decimal_point + && poLconv->decimal_point[0] != '\0' ) + { + char byPoint = poLconv->decimal_point[0]; + + if (point != byPoint) + { + const char* pszLocalePoint = strchr(pszNumber, byPoint); + const char* pszPoint = strchr(pszNumber, point); + if (pszPoint || pszLocalePoint) + { + char* pszNew; + if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE ) + { + strcpy(pszWorkBuffer, pszNumber); + pszNew = pszWorkBuffer; + } + else { + pszNew = pj_strdup(pszNumber); + if (!pszNew) + return nullptr; + } + if( pszLocalePoint ) + pszNew[pszLocalePoint - pszNumber] = ' '; + if( pszPoint ) + pszNew[pszPoint - pszNumber] = byPoint; + return pszNew; + } + } + } +#endif + return (char*) pszNumber; +} + +/************************************************************************/ +/* pj_strtod() */ +/************************************************************************/ + +/** + * Converts ASCII string to floating point number. + * + * This function converts the initial portion of the string pointed to + * by nptr to double floating point representation. This function does the + * same as standard strtod(3), but does not take locale in account and use + * decimal point. + * + * @param nptr Pointer to string to convert. + * @param endptr If is not NULL, a pointer to the character after the last + * character used in the conversion is stored in the location referenced + * by endptr. + * + * @return Converted value. + */ +double pj_strtod( const char *nptr, char **endptr ) +{ +/* -------------------------------------------------------------------- */ +/* We are implementing a simple method here: copy the input string */ +/* into the temporary buffer, replace the specified decimal delimiter */ +/* with the one, taken from locale settings and use standard strtod() */ +/* on that buffer. */ +/* -------------------------------------------------------------------- */ + double dfValue; + int nError; + char szWorkBuffer[PJ_STRTOD_WORK_BUFFER_SIZE]; + + char* pszNumber = replace_point_by_locale_point(nptr, '.', szWorkBuffer); + + dfValue = strtod( pszNumber, endptr ); + nError = errno; + + if ( endptr ) + *endptr = (char *)nptr + (*endptr - pszNumber); + + if (pszNumber != (char*) nptr && pszNumber != szWorkBuffer ) + free( pszNumber ); + + errno = nError; + return dfValue; +} |
