1 /******************************************************************************
2 *
3 * Derived from GDAL port/cpl_strtod.cpp
4 * Purpose: Functions to convert ASCII string to floating point number.
5 * Author: Andrey Kiselev, dron@ak4719.spb.edu.
6 *
7 ******************************************************************************
8 * Copyright (c) 2006, Andrey Kiselev
9 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "projects.h"
31
32 /* Windows nmake build doesn't have a proj_config.h, but HAVE_LOCALECONV */
33 /* is defined in the compilation line */
34 #ifndef HAVE_LOCALECONV
35 #include "proj_config.h"
36 #endif
37
38 #include <stdlib.h>
39 #include <locale.h>
40 #include <errno.h>
41
42 #define PJ_STRTOD_WORK_BUFFER_SIZE 64
43
44 /************************************************************************/
45 /* pj_atof() */
46 /************************************************************************/
47
48 /**
49 * Converts ASCII string to floating point number.
50 *
51 * This function converts the initial portion of the string pointed to
52 * by nptr to double floating point representation. The behaviour is the
53 * same as
54 *
55 * pj_strtod(nptr, (char **)NULL);
56 *
57 * This function does the same as standard atof(3), but does not take
58 * locale in account. That means, the decimal delimiter is always '.'
59 * (decimal point).
60 *
61 * @param nptr Pointer to string to convert.
62 *
63 * @return Converted value.
64 */
pj_atof(const char * nptr)65 double pj_atof( const char* nptr )
66 {
67 return pj_strtod(nptr, NULL);
68 }
69
70
71 /************************************************************************/
72 /* pj_replace_point_by_locale_point() */
73 /************************************************************************/
74
pj_replace_point_by_locale_point(const char * pszNumber,char point,char * pszWorkBuffer)75 static char* pj_replace_point_by_locale_point(const char* pszNumber, char point,
76 char* pszWorkBuffer)
77 {
78 #if !defined(HAVE_LOCALECONV) || defined(_WIN32_WCE)
79
80 #if defined(_MSC_VER) /* Visual C++ */
81 #pragma message("localeconv not available")
82 #else
83 #warning "localeconv not available"
84 #endif
85
86 static char byPoint = 0;
87 if (byPoint == 0)
88 {
89 char szBuf[16];
90 sprintf(szBuf, "%.1f", 1.0);
91 byPoint = szBuf[1];
92 }
93 if (point != byPoint)
94 {
95 const char* pszPoint = strchr(pszNumber, point);
96 if (pszPoint)
97 {
98 char* pszNew;
99 if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE )
100 {
101 strcpy(pszWorkBuffer, pszNumber);
102 pszNew = pszWorkBuffer;
103 }
104 else
105 pszNew = strdup(pszNumber);
106 pszNew[pszPoint - pszNumber] = byPoint;
107 return pszNew;
108 }
109 }
110 #else
111 struct lconv *poLconv = localeconv();
112 if ( poLconv
113 && poLconv->decimal_point
114 && poLconv->decimal_point[0] != '\0' )
115 {
116 char byPoint = poLconv->decimal_point[0];
117
118 if (point != byPoint)
119 {
120 const char* pszLocalePoint = strchr(pszNumber, byPoint);
121 const char* pszPoint = strchr(pszNumber, point);
122 if (pszPoint || pszLocalePoint)
123 {
124 char* pszNew;
125 if( strlen(pszNumber) < PJ_STRTOD_WORK_BUFFER_SIZE )
126 {
127 strcpy(pszWorkBuffer, pszNumber);
128 pszNew = pszWorkBuffer;
129 }
130 else
131 pszNew = strdup(pszNumber);
132 if( pszLocalePoint )
133 pszNew[pszLocalePoint - pszNumber] = ' ';
134 if( pszPoint )
135 pszNew[pszPoint - pszNumber] = byPoint;
136 return pszNew;
137 }
138 }
139 }
140 #endif
141 return (char*) pszNumber;
142 }
143
144 /************************************************************************/
145 /* pj_strtod() */
146 /************************************************************************/
147
148 /**
149 * Converts ASCII string to floating point number.
150 *
151 * This function converts the initial portion of the string pointed to
152 * by nptr to double floating point representation. This function does the
153 * same as standard strtod(3), but does not take locale in account and use
154 * decimal point.
155 *
156 * @param nptr Pointer to string to convert.
157 * @param endptr If is not NULL, a pointer to the character after the last
158 * character used in the conversion is stored in the location referenced
159 * by endptr.
160 * @param point Decimal delimiter.
161 *
162 * @return Converted value.
163 */
pj_strtod(const char * nptr,char ** endptr)164 double pj_strtod( const char *nptr, char **endptr )
165 {
166 /* -------------------------------------------------------------------- */
167 /* We are implementing a simple method here: copy the input string */
168 /* into the temporary buffer, replace the specified decimal delimiter */
169 /* with the one, taken from locale settings and use standard strtod() */
170 /* on that buffer. */
171 /* -------------------------------------------------------------------- */
172 double dfValue;
173 int nError;
174 char szWorkBuffer[PJ_STRTOD_WORK_BUFFER_SIZE];
175
176 char* pszNumber = pj_replace_point_by_locale_point(nptr, '.', szWorkBuffer);
177
178 dfValue = strtod( pszNumber, endptr );
179 nError = errno;
180
181 if ( endptr )
182 *endptr = (char *)nptr + (*endptr - pszNumber);
183
184 if (pszNumber != (char*) nptr && pszNumber != szWorkBuffer )
185 free( pszNumber );
186
187 errno = nError;
188 return dfValue;
189 }
190
191