aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2015-07-07 18:46:36 +0200
committerEven Rouault <even.rouault@spatialys.com>2015-07-07 18:46:36 +0200
commit2b5b97942016c2f18a0992b934d1b6b460391dac (patch)
tree46cffbdad4a652422cc94f6077e3ab3955e6dc0f
parent396afc3312243ff4a8e95c3b9398d56c5582e30d (diff)
downloadPROJ-2b5b97942016c2f18a0992b934d1b6b460391dac.tar.gz
PROJ-2b5b97942016c2f18a0992b934d1b6b460391dac.zip
Make pj_init() locale safe and no longer modify locale (#226)
Remove setlocale() use in pj_init_ctx(), and replace uses of atof() & strtod() by their locale safe variants pj_atof() and pj_strtod(). Proj versions from now advertize #define PJ_LOCALE_SAFE 1 in proj_api.h and export pj_atof() & pj_strtod()
-rw-r--r--ChangeLog6
-rw-r--r--cmake/Proj4Config.cmake3
-rw-r--r--cmake/proj_config.cmake.in3
-rwxr-xr-xconfigure8
-rw-r--r--configure.in2
-rw-r--r--nad/Makefile.in7
-rwxr-xr-xnad/testvarious10
-rw-r--r--src/Makefile.am3
-rw-r--r--src/Makefile.in7
-rw-r--r--src/cs2cs.c19
-rw-r--r--src/dmstor.c2
-rw-r--r--src/lib_proj.cmake2
-rw-r--r--src/makefile.vc6
-rw-r--r--src/pj_datum_set.c2
-rw-r--r--src/pj_gc_reader.c2
-rw-r--r--src/pj_init.c29
-rw-r--r--src/pj_param.c2
-rw-r--r--src/pj_strtod.c184
-rw-r--r--src/pj_utils.c11
-rw-r--r--src/proj.def2
-rw-r--r--src/proj_api.h4
-rw-r--r--src/proj_config.h.in16
-rw-r--r--src/projects.h5
23 files changed, 295 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 53db90f1..f56821f6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2015-07-27 Even Rouault <even.rouault@spatialys.com>
+ * : Remove setlocale() use in pj_init_ctx(), and replace uses of atof() &
+ strtod() by their locale safe variants pj_atof() and pj_strtod().
+ Proj versions from now advertize #define PJ_LOCALE_SAFE 1 in proj_api.h
+ and export pj_atof() & pj_strtod() (#226)
+
2015-02-21 Even Rouault <even.rouault@spatialys.com>
* nad/epsg: regenerate nad/epsg with GDAL r28536 to avoid
precision loss in TOWGS84 parameters, e.g. on Amersfoort / RD
diff --git a/cmake/Proj4Config.cmake b/cmake/Proj4Config.cmake
index e9aa1de5..fda9c9c2 100644
--- a/cmake/Proj4Config.cmake
+++ b/cmake/Proj4Config.cmake
@@ -9,6 +9,7 @@
################################################################################
include (CheckIncludeFiles)
include (CheckLibraryExists)
+include (CheckFunctionExists)
# check needed include file
check_include_files (dlfcn.h HAVE_DLFCN_H)
@@ -23,6 +24,8 @@ check_include_files (sys/types.h HAVE_SYS_TYPES_H)
check_include_files (unistd.h HAVE_UNISTD_H)
check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
+CHECK_FUNCTION_EXISTS(localeconv HAVE_LOCALECONV)
+
# check libm need on unix
check_library_exists(m ceil "" HAVE_LIBM)
diff --git a/cmake/proj_config.cmake.in b/cmake/proj_config.cmake.in
index 8f782a7c..bbdf3249 100644
--- a/cmake/proj_config.cmake.in
+++ b/cmake/proj_config.cmake.in
@@ -10,6 +10,9 @@
/* Define to 1 if you have the `m' library (-lm). */
#cmakedefine HAVE_LIBM 1
+/* Define to 1 if you have localeconv */
+#cmakedefine HAVE_LOCALECONV 1
+
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H 1
diff --git a/configure b/configure
index fbaf81dd..e770a0dc 100755
--- a/configure
+++ b/configure
@@ -12477,6 +12477,14 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi
+ac_fn_c_check_func "$LINENO" "localeconv" "ac_cv_func_localeconv"
+if test "x$ac_cv_func_localeconv" = xyes; then :
+
+$as_echo "#define HAVE_LOCALECONV 1" >>confdefs.h
+
+fi
+
+
JNI_INCLUDE=
export JNI_INCLUDE
diff --git a/configure.in b/configure.in
index fd7f3c03..b0f7176b 100644
--- a/configure.in
+++ b/configure.in
@@ -26,6 +26,8 @@ AC_CHECK_LIB(m,exp,,,)
dnl We check for headers
AC_HEADER_STDC
+AC_CHECK_FUNC(localeconv, [AC_DEFINE(HAVE_LOCALECONV,1,[Define to 1 if you have localeconv])])
+
dnl ---------------------------------------------------------------------------
dnl Check for JNI support.
dnl ---------------------------------------------------------------------------
diff --git a/nad/Makefile.in b/nad/Makefile.in
index 94437439..6cc682cb 100644
--- a/nad/Makefile.in
+++ b/nad/Makefile.in
@@ -272,15 +272,16 @@ TEST27 = $(NADPATH)/test27
TEST83 = $(NADPATH)/test83
TESTNTV2 = $(NADPATH)/testntv2
TESTVARIOUS = $(NADPATH)/testvarious
+TESTFLAKY = $(NADPATH)/testflaky
TESTDATUMFILE = $(NADPATH)/testdatumfile
TESTIGN = $(NADPATH)/testIGNF
-pkgdata_DATA = GL27 nad.lst nad27 nad83 world epsg esri \
+pkgdata_DATA = GL27 nad.lst proj_def.dat nad27 nad83 world epsg esri \
esri.extra other.extra \
CH IGNF
EXTRA_DIST = GL27 nad.lst nad27 nad83 pj_out27.dist pj_out83.dist td_out.dist \
- test27 test83 world epsg esri tv_out.dist \
- testvarious testdatumfile testntv2 ntv2_out.dist \
+ test27 test83 world epsg esri tv_out.dist tf_out.dist \
+ testflaky testvarious testdatumfile testntv2 ntv2_out.dist \
esri.extra other.extra \
CH IGNF testIGNF proj_outIGNF.dist \
makefile.vc CMakeLists.txt
diff --git a/nad/testvarious b/nad/testvarious
index a128eb50..694d0d19 100755
--- a/nad/testvarious
+++ b/nad/testvarious
@@ -22,6 +22,16 @@ if test ! -x ${EXE}; then
exit 1
fi
+# Would be great to have a universale way of selecting a locale with
+# a decimal separator that is not '.'
+if command locale >/dev/null 2>/dev/null; then
+ if test `locale -a | grep fr_FR.utf8`; then
+ echo "Using locale with comma as decimal separator"
+ export LC_ALL=fr_FR.UTF-8
+ export PROJ_USE_ENV_LOCALE=1
+ fi
+fi
+
echo "============================================"
echo "Running ${0} using ${EXE}:"
echo "============================================"
diff --git a/src/Makefile.am b/src/Makefile.am
index 2da16e7e..a996cbae 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -70,7 +70,8 @@ libproj_la_SOURCES = \
nad_cvt.c nad_init.c nad_intr.c emess.c emess.h \
pj_apply_gridshift.c pj_datums.c pj_datum_set.c pj_transform.c \
geocent.c geocent.h pj_utils.c pj_gridinfo.c pj_gridlist.c \
- jniproj.c pj_mutex.c pj_initcache.c pj_apply_vgridshift.c geodesic.c
+ jniproj.c pj_mutex.c pj_initcache.c pj_apply_vgridshift.c geodesic.c \
+ pj_strtod.c
install-exec-local:
rm -f $(DESTDIR)$(bindir)/invproj$(EXEEXT)
diff --git a/src/Makefile.in b/src/Makefile.in
index 8aa4143b..a71265df 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -161,7 +161,8 @@ am_libproj_la_OBJECTS = PJ_aeqd.lo PJ_gnom.lo PJ_laea.lo \
nad_intr.lo emess.lo pj_apply_gridshift.lo pj_datums.lo \
pj_datum_set.lo pj_transform.lo geocent.lo pj_utils.lo \
pj_gridinfo.lo pj_gridlist.lo jniproj.lo pj_mutex.lo \
- pj_initcache.lo pj_apply_vgridshift.lo geodesic.lo
+ pj_initcache.lo pj_apply_vgridshift.lo geodesic.lo \
+ pj_strtod.lo
libproj_la_OBJECTS = $(am_libproj_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -440,7 +441,8 @@ libproj_la_SOURCES = \
nad_cvt.c nad_init.c nad_intr.c emess.c emess.h \
pj_apply_gridshift.c pj_datums.c pj_datum_set.c pj_transform.c \
geocent.c geocent.h pj_utils.c pj_gridinfo.c pj_gridlist.c \
- jniproj.c pj_mutex.c pj_initcache.c pj_apply_vgridshift.c geodesic.c
+ jniproj.c pj_mutex.c pj_initcache.c pj_apply_vgridshift.c geodesic.c \
+ pj_strtod.c
all: proj_config.h
$(MAKE) $(AM_MAKEFLAGS) all-am
@@ -763,6 +765,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_qsfn.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_release.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_strerrno.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_strtod.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_transform.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_tsfn.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pj_units.Plo@am__quote@
diff --git a/src/cs2cs.c b/src/cs2cs.c
index 43f7bf86..90369326 100644
--- a/src/cs2cs.c
+++ b/src/cs2cs.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <math.h>
#include "emess.h"
+#include <locale.h>
#define MAX_LINE 1000
#define MAX_PARGS 100
@@ -167,6 +168,12 @@ int main(int argc, char **argv)
FILE *fid;
int from_argc=0, to_argc=0, eargc = 0, c, mon = 0;
int have_to_flag = 0, inverse = 0, i;
+ int use_env_locale = 0;
+
+ /* This is just to check that pj_init() is locale-safe */
+ /* Used by nad/testvarious */
+ if( getenv("PROJ_USE_ENV_LOCALE") != NULL )
+ use_env_locale = 1;
if ((emess_dat.Prog_name = strrchr(*argv,DIR_CHAR)) != NULL)
++emess_dat.Prog_name;
@@ -336,6 +343,12 @@ int main(int argc, char **argv)
to_argc = argcount;
}
+ if( use_env_locale )
+ {
+ /* Set locale from environment */
+ setlocale(LC_ALL, "");
+ }
+
if( from_argc == 0 && to_argc != 0 )
{
/* we will generate the from proj as the latlong of the +to in a bit */
@@ -389,6 +402,12 @@ int main(int argc, char **argv)
}
}
+ if( use_env_locale )
+ {
+ /* Restore C locale to avoid issues in parsing/outputing numbers*/
+ setlocale(LC_ALL, "C");
+ }
+
if (mon) {
printf( "%c ---- From Coordinate System ----\n", tag );
pj_pr_list(fromProj);
diff --git a/src/dmstor.c b/src/dmstor.c
index f1da5379..62c06f3d 100644
--- a/src/dmstor.c
+++ b/src/dmstor.c
@@ -108,6 +108,6 @@ proj_strtod(char *nptr, char **endptr)
/* no offending characters, just handle normally */
- return strtod(nptr, endptr);
+ return pj_strtod(nptr, endptr);
}
diff --git a/src/lib_proj.cmake b/src/lib_proj.cmake
index 8111c7aa..8a6349d8 100644
--- a/src/lib_proj.cmake
+++ b/src/lib_proj.cmake
@@ -200,6 +200,7 @@ SET(SRC_LIBPROJ_CORE
proj_rouss.c
rtodms.c
vector1.c
+ pj_strtod.c
${CMAKE_CURRENT_BINARY_DIR}/proj_config.h
)
@@ -213,6 +214,7 @@ set(HEADERS_LIBPROJ
source_group("Header Files" FILES ${HEADERS_LIBPROJ})
source_group("Source Files\\Core" FILES ${SRC_LIBPROJ_CORE})
source_group("Source Files\\PJ" FILES ${SRC_LIBPROJ_PJ})
+include_directories( ${CMAKE_CURRENT_BINARY_DIR})
source_group("CMake Files" FILES CMakeLists.txt)
diff --git a/src/makefile.vc b/src/makefile.vc
index 5e57c716..4a47f045 100644
--- a/src/makefile.vc
+++ b/src/makefile.vc
@@ -54,7 +54,9 @@ support = \
nad_cvt.obj nad_init.obj nad_intr.obj \
pj_utils.obj pj_gridlist.obj pj_gridinfo.obj \
proj_mdist.obj pj_mutex.obj pj_initcache.obj \
- pj_ctx.obj pj_fileapi.obj pj_log.obj pj_apply_vgridshift.obj
+ pj_ctx.obj pj_fileapi.obj pj_log.obj pj_apply_vgridshift.obj \
+ pj_strtod.obj
+
geodesic = geodesic.obj
LIBOBJ = $(support) $(pseudo) $(azimuthal) $(conic) $(cylinder) $(misc) \
$(geodesic)
@@ -68,7 +70,7 @@ GEOD_EXE = geod.exe
NAD2BIN_EXE = nad2bin.exe
CFLAGS = /nologo -I. -DPROJ_LIB=\"$(PROJ_LIB_DIR)\" \
- -DHAVE_STRERROR=1 $(OPTFLAGS)
+ -DHAVE_STRERROR=1 -DHAVE_LOCALECONV=1 $(OPTFLAGS)
default: all
diff --git a/src/pj_datum_set.c b/src/pj_datum_set.c
index 69b60469..194bfe57 100644
--- a/src/pj_datum_set.c
+++ b/src/pj_datum_set.c
@@ -118,7 +118,7 @@ int pj_datum_set(projCtx ctx, paralist *pl, PJ *projdef)
/* parse out the parameters */
for( s = towgs84; *s != '\0' && parm_count < 7; )
{
- projdef->datum_params[parm_count++] = atof(s);
+ projdef->datum_params[parm_count++] = pj_atof(s);
while( *s != '\0' && *s != ',' )
s++;
if( *s == ',' )
diff --git a/src/pj_gc_reader.c b/src/pj_gc_reader.c
index 81d0fb26..458737c1 100644
--- a/src/pj_gc_reader.c
+++ b/src/pj_gc_reader.c
@@ -152,7 +152,7 @@ double pj_gc_parsedate( projCtx ctx, const char *date_string )
}
else
{
- return atof(date_string);
+ return pj_atof(date_string);
}
}
diff --git a/src/pj_init.c b/src/pj_init.c
index 622e80bf..13d469da 100644
--- a/src/pj_init.c
+++ b/src/pj_init.c
@@ -32,7 +32,6 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
-#include <locale.h>
#include <ctype.h>
typedef struct {
@@ -389,25 +388,10 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
paralist *curr;
int i;
PJ *PIN = 0;
- char *old_locale;
ctx->last_errno = 0;
start = NULL;
- /*
- ** MS Visual Studio 2012+ may have problems in multithreaded cases
- ** as discussed in this ticket:
- ** http://trac.osgeo.org/proj/ticket/226
- */
- old_locale = setlocale(LC_NUMERIC, NULL);
- if (old_locale != NULL) {
- if (strcmp(old_locale,"C") != 0) {
- old_locale = strdup(old_locale);
- setlocale(LC_NUMERIC,"C");
- }else
- old_locale = NULL;
- }
-
/* put arguments into internal linked list */
if (argc <= 0) { pj_ctx_set_errno( ctx, -1 ); goto bum_call; }
start = curr = pj_mkparam(argv[0]);
@@ -554,9 +538,9 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
s = pj_units[i].to_meter;
}
if (s || (s = pj_param(ctx, start, "sto_meter").s)) {
- PIN->to_meter = strtod(s, &s);
+ PIN->to_meter = pj_strtod(s, &s);
if (*s == '/') /* ratio number */
- PIN->to_meter /= strtod(++s, 0);
+ PIN->to_meter /= pj_strtod(++s, 0);
PIN->fr_meter = 1. / PIN->to_meter;
} else
PIN->to_meter = PIN->fr_meter = 1.;
@@ -569,9 +553,9 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
s = pj_units[i].to_meter;
}
if (s || (s = pj_param(ctx, start, "svto_meter").s)) {
- PIN->vto_meter = strtod(s, &s);
+ PIN->vto_meter = pj_strtod(s, &s);
if (*s == '/') /* ratio number */
- PIN->vto_meter /= strtod(++s, 0);
+ PIN->vto_meter /= pj_strtod(++s, 0);
PIN->vfr_meter = 1. / PIN->vto_meter;
} else {
PIN->vto_meter = PIN->to_meter;
@@ -617,11 +601,6 @@ pj_init_ctx(projCtx ctx, int argc, char **argv) {
PIN = 0;
}
- if (old_locale != NULL) {
- setlocale(LC_NUMERIC,old_locale);
- free( (char*)old_locale );
- }
-
return PIN;
}
diff --git a/src/pj_param.c b/src/pj_param.c
index 119006e1..ed6ce27c 100644
--- a/src/pj_param.c
+++ b/src/pj_param.c
@@ -61,7 +61,7 @@ pj_param(projCtx ctx, paralist *pl, const char *opt) {
value.i = atoi(opt);
break;
case 'd': /* simple real input */
- value.f = atof(opt);
+ value.f = pj_atof(opt);
break;
case 'r': /* degrees input */
value.f = dmstor_ctx(ctx, opt, 0);
diff --git a/src/pj_strtod.c b/src/pj_strtod.c
new file mode 100644
index 00000000..9aac07e5
--- /dev/null
+++ b/src/pj_strtod.c
@@ -0,0 +1,184 @@
+/******************************************************************************
+ *
+ * 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 "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
+
+#include <stdlib.h>
+#include <locale.h>
+#include <errno.h>
+
+#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, NULL);
+}
+
+
+/************************************************************************/
+/* pj_replace_point_by_locale_point() */
+/************************************************************************/
+
+static char* pj_replace_point_by_locale_point(const char* pszNumber, char point,
+ char* pszWorkBuffer)
+{
+#if !defined(HAVE_LOCALECONV) || defined(_WIN32_WCE)
+#warning "localeconv not available"
+ 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 = strdup(pszNumber);
+ 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 = strdup(pszNumber);
+ 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.
+ * @param point Decimal delimiter.
+ *
+ * @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 = pj_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;
+}
+
diff --git a/src/pj_utils.c b/src/pj_utils.c
index bb4b6ae6..f11081fc 100644
--- a/src/pj_utils.c
+++ b/src/pj_utils.c
@@ -101,8 +101,15 @@ PJ *pj_latlong_from_proj( PJ *pj_in )
sprintf( defn+strlen(defn), " +f=%s",
pj_param(pj_in->ctx,pj_in->params,"sf").s );
else
- sprintf( defn+strlen(defn), " +es=%.16g",
- pj_in->es );
+ {
+ char* ptr = defn+strlen(defn);
+ sprintf( ptr, " +es=%.16g", pj_in->es );
+ for(; *ptr; ptr++)
+ {
+ if( *ptr == ',' )
+ *ptr = '.';
+ }
+ }
}
else
{
diff --git a/src/proj.def b/src/proj.def
index bfcf9f94..f3146551 100644
--- a/src/proj.def
+++ b/src/proj.def
@@ -72,3 +72,5 @@ EXPORTS
pj_ctx_ftell @70
pj_ctx_fclose @71
pj_open_lib @72
+ pj_atof @73
+ pj_strtod @74
diff --git a/src/proj_api.h b/src/proj_api.h
index 0c4be974..ed11d6a4 100644
--- a/src/proj_api.h
+++ b/src/proj_api.h
@@ -40,6 +40,10 @@ extern "C" {
/* Try to update this every version! */
#define PJ_VERSION 491
+/* pj_init() and similar functions can be used with a non-C locale */
+/* Can be detected too at runtime if the symbol pj_atof exists */
+#define PJ_LOCALE_SAFE 1
+
extern char const pj_release[]; /* global release id string */
#define RAD_TO_DEG 57.29577951308232
diff --git a/src/proj_config.h.in b/src/proj_config.h.in
index e4992e2c..7a8d6943 100644
--- a/src/proj_config.h.in
+++ b/src/proj_config.h.in
@@ -6,9 +6,18 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
+/* Define to 1 if you have the <jni.h> header file. */
+#undef HAVE_JNI_H
+
/* Define to 1 if you have the `m' library (-lm). */
#undef HAVE_LIBM
+/* Define to 1 if you have the `pthread' library (-lpthread). */
+#undef HAVE_LIBPTHREAD
+
+/* Define to 1 if you have localeconv */
+#undef HAVE_LOCALECONV
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -36,6 +45,10 @@
/* Enabled for Java/JNI Support */
#undef JNI_ENABLED
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
/* Name of package */
#undef PACKAGE
@@ -51,6 +64,9 @@
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
/* Define to the version of this package. */
#undef PACKAGE_VERSION
diff --git a/src/projects.h b/src/projects.h
index 062bd07d..ac95f69d 100644
--- a/src/projects.h
+++ b/src/projects.h
@@ -509,7 +509,10 @@ struct PJ_DATUMS *pj_get_datums_ref( void );
struct PJ_UNITS *pj_get_units_ref( void );
struct PJ_LIST *pj_get_list_ref( void );
struct PJ_PRIME_MERIDIANS *pj_get_prime_meridians_ref( void );
-
+
+double pj_atof( const char* nptr );
+double pj_strtod( const char *nptr, char **endptr );
+
#ifdef __cplusplus
}
#endif