diff --git a/src/gmio_core/error.h b/src/gmio_core/error.h
index ce2416e..7bb3cf3 100644
--- a/src/gmio_core/error.h
+++ b/src/gmio_core/error.h
@@ -31,6 +31,9 @@ enum gmio_error
/*! No error occurred, success */
GMIO_ERROR_OK = 0,
+ /*! Unknown error */
+ GMIO_ERROR_UNKNOWN,
+
/*! Pointer on argument memory block is NULL */
GMIO_ERROR_NULL_MEMBLOCK,
@@ -50,8 +53,8 @@ enum gmio_error
*/
GMIO_ERROR_STDIO,
- /*! Unknown error */
- GMIO_ERROR_UNKNOWN
+ /*! Checking of \c LC_NUMERIC failed(should be "C" or "POSIX") */
+ GMIO_ERROR_BAD_LC_NUMERIC
};
/*! Returns true if code == GMIO_NO_ERROR */
diff --git a/src/gmio_core/internal/locale_utils.c b/src/gmio_core/internal/locale_utils.c
new file mode 100644
index 0000000..bbc8da9
--- /dev/null
+++ b/src/gmio_core/internal/locale_utils.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+** gmio
+** Copyright Fougue (24 Jun. 2016)
+** contact@fougue.pro
+**
+** This software is a reusable library whose purpose is to provide complete
+** I/O support for various CAD file formats (eg. STL)
+**
+** This software is governed by the CeCILL-B license under French law and
+** abiding by the rules of distribution of free software. You can use,
+** modify and/ or redistribute the software under the terms of the CeCILL-B
+** license as circulated by CEA, CNRS and INRIA at the following URL
+** "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html".
+****************************************************************************/
+
+#include "locale_utils.h"
+
+#include "../error.h"
+#include "string_ascii_utils.h"
+
+#include
+#include
+#include
+
+const char *gmio_lc_numeric()
+{
+ const char* lcnum = setlocale(LC_NUMERIC, NULL);
+ return lcnum != NULL ? lcnum : "";
+}
+
+bool gmio_lc_numeric_is_C()
+{
+ const char* lc = gmio_lc_numeric();
+ return (gmio_ascii_stricmp(lc, "C") == 0
+ || gmio_ascii_stricmp(lc, "POSIX") == 0);
+}
+
+bool gmio_check_lc_numeric(int *error)
+{
+ if (!gmio_lc_numeric_is_C())
+ *error = GMIO_ERROR_BAD_LC_NUMERIC;
+ return gmio_no_error(*error);
+}
+
+static char global_lc_numeric[64] = {0};
+
+void gmio_lc_numeric_save()
+{
+ /* Save LC_NUMERIC
+ * POSIX specifies that the pointer returned by setlocale(), not just the
+ * contents of the pointed-to string, may be invalidated by subsequent calls
+ * to setlocale */
+ strncpy(global_lc_numeric,
+ setlocale(LC_NUMERIC, NULL),
+ GMIO_ARRAY_SIZE(global_lc_numeric));
+}
+
+void gmio_lc_numeric_restore()
+{
+ if (global_lc_numeric[0] != '\0')
+ setlocale(LC_NUMERIC, global_lc_numeric);
+}
diff --git a/src/gmio_core/internal/locale_utils.h b/src/gmio_core/internal/locale_utils.h
new file mode 100644
index 0000000..7fe7b8d
--- /dev/null
+++ b/src/gmio_core/internal/locale_utils.h
@@ -0,0 +1,28 @@
+/****************************************************************************
+** gmio
+** Copyright Fougue (24 Jun. 2016)
+** contact@fougue.pro
+**
+** This software is a reusable library whose purpose is to provide complete
+** I/O support for various CAD file formats (eg. STL)
+**
+** This software is governed by the CeCILL-B license under French law and
+** abiding by the rules of distribution of free software. You can use,
+** modify and/ or redistribute the software under the terms of the CeCILL-B
+** license as circulated by CEA, CNRS and INRIA at the following URL
+** "http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html".
+****************************************************************************/
+
+#include "../global.h"
+
+const char* gmio_lc_numeric();
+
+/*! Returns result of case-insensitive test LC_NUMERIC == "C|POSIX" */
+bool gmio_lc_numeric_is_C();
+
+/*! Checks gmio_lc_numeric_is_C(), if false sets \p *error to
+ * \c GMIO_ERROR_BAD_LC_NUMERIC*/
+bool gmio_check_lc_numeric(int* error);
+
+void gmio_lc_numeric_save();
+void gmio_lc_numeric_restore();
diff --git a/src/gmio_stl/internal/stla_write.c b/src/gmio_stl/internal/stla_write.c
index 73f7cbe..81438d4 100644
--- a/src/gmio_stl/internal/stla_write.c
+++ b/src/gmio_stl/internal/stla_write.c
@@ -25,6 +25,7 @@
#include "../../gmio_core/internal/helper_memblock.h"
#include "../../gmio_core/internal/helper_stream.h"
#include "../../gmio_core/internal/helper_task_iface.h"
+#include "../../gmio_core/internal/locale_utils.h"
#include "../../gmio_core/internal/min_max.h"
#include "../../gmio_core/internal/safe_cast.h"
@@ -180,6 +181,8 @@ int gmio_stla_write(
const struct gmio_stl_write_options* opts)
{
/* Constants */
+ const bool check_lcnum =
+ opts != NULL ? !opts->stla_dont_check_lc_numeric : true;
const struct gmio_task_iface* task = opts != NULL ? &opts->task_iface : NULL;
struct gmio_memblock_helper mblock_helper =
gmio_memblock_helper(opts != NULL ? &opts->stream_memblock : NULL);
@@ -225,6 +228,8 @@ int gmio_stla_write(
}
/* Check validity of input parameters */
+ if (check_lcnum && !gmio_check_lc_numeric(&error))
+ goto label_end;
if (!gmio_check_memblock_size(&error, mblock, GMIO_STLA_FACET_SIZE_P2))
goto label_end;
if (!gmio_stl_check_mesh(&error, mesh))
diff --git a/src/gmio_stl/stl_io_options.h b/src/gmio_stl/stl_io_options.h
index df02ee3..36ef92a 100644
--- a/src/gmio_stl/stl_io_options.h
+++ b/src/gmio_stl/stl_io_options.h
@@ -30,7 +30,12 @@
#include "../gmio_core/task_iface.h"
#include "../gmio_core/text_format.h"
-/*! Options of function gmio_stl_read() */
+/*! Options of function gmio_stl_read()
+ *
+ * Initialising gmio_stl_read_options with \c {0} (or \c {} in C++) is the
+ * convenient way to set default values(passing \c NULL to gmio_stl_read() has
+ * the same effect).
+ */
struct gmio_stl_read_options
{
/*! Used by the stream to bufferize I/O operations
@@ -59,9 +64,27 @@ struct gmio_stl_read_options
gmio_streamsize_t (*func_stla_get_streamsize)(
struct gmio_stream* stream,
struct gmio_memblock* stream_memblock);
+
+ /*! Flag allowing to disable checking of the current locale's numeric
+ * formatting category
+ *
+ * If \c false then \c LC_NUMERIC is checked to be "C" or "POSIX". If check
+ * fails then the function returns \c GMIO_ERROR_BAD_LC_NUMERIC
+ *
+ * This applies only for STL ascii, where it affects text-related standard
+ * C functions(snprintf(), strtod(), ...)
+ *
+ * \c LC_NUMERIC checking is enabled by default.
+ */
+ bool stla_dont_check_lc_numeric;
};
-/*! Options of function gmio_stl_write() */
+/*! Options of function gmio_stl_write()
+ *
+ * Initialising gmio_stl_write_options with \c {0} (or \c {} in C++) is the
+ * convenient way to set default values(passing \c NULL to gmio_stl_write() has
+ * the same effect).
+ */
struct gmio_stl_write_options
{
/*! See gmio_stl_read_options::stream_memblock */
@@ -70,6 +93,9 @@ struct gmio_stl_write_options
/*! See gmio_stl_read_options::task_iface */
struct gmio_task_iface task_iface;
+ /*! See gmio_stl_read_options::stla_dont_check_lc_numeric */
+ bool stla_dont_check_lc_numeric;
+
/*! Flag allowing to skip writting of any header/footer data, but just
* triangles
*
diff --git a/src/gmio_stl/stla_read.c b/src/gmio_stl/stla_read.c
index 98c5858..6f1ccc3 100644
--- a/src/gmio_stl/stla_read.c
+++ b/src/gmio_stl/stla_read.c
@@ -26,6 +26,7 @@
#include "../gmio_core/internal/helper_memblock.h"
#include "../gmio_core/internal/helper_stream.h"
#include "../gmio_core/internal/helper_task_iface.h"
+#include "../gmio_core/internal/locale_utils.h"
#include "../gmio_core/internal/min_max.h"
#include "../gmio_core/internal/safe_cast.h"
#include "../gmio_core/internal/stringstream.h"
@@ -114,11 +115,17 @@ int gmio_stla_read(
struct gmio_stl_mesh_creator* mesh_creator,
const struct gmio_stl_read_options* opts)
{
+ const bool check_lcnum =
+ opts != NULL ? !opts->stla_dont_check_lc_numeric : true;
struct gmio_memblock_helper mblock_helper =
gmio_memblock_helper(opts != NULL ? &opts->stream_memblock : NULL);
struct gmio_memblock* const mblock = &mblock_helper.memblock;
char fixed_buffer[GMIO_STLA_READ_STRING_MAX_LEN];
struct gmio_stla_parse_data parse_data;
+ int error = GMIO_ERROR_OK;
+
+ if (check_lcnum && !gmio_check_lc_numeric(&error))
+ goto label_end;
parse_data.token = unknown_token;
parse_data.error = false;
@@ -145,13 +152,14 @@ int gmio_stla_read(
parse_solid(&parse_data);
- gmio_memblock_helper_release(&mblock_helper);
-
if (parse_data.error)
- return GMIO_STL_ERROR_PARSING;
+ error = GMIO_STL_ERROR_PARSING;
if (parse_data.strstream_cookie.is_stop_requested)
- return GMIO_ERROR_TRANSFER_STOPPED;
- return GMIO_ERROR_OK;
+ error = GMIO_ERROR_TRANSFER_STOPPED;
+
+label_end:
+ gmio_memblock_helper_release(&mblock_helper);
+ return error;
}
diff --git a/tests/main_test_core.c b/tests/main_test_core.c
index 1095780..a3a238a 100644
--- a/tests/main_test_core.c
+++ b/tests/main_test_core.c
@@ -35,9 +35,10 @@ const char* all_tests()
UTEST_RUN(test_internal__byte_swap);
UTEST_RUN(test_internal__byte_codec);
UTEST_RUN(test_internal__fast_atof);
+ UTEST_RUN(test_internal__locale_utils);
UTEST_RUN(test_internal__safe_cast);
UTEST_RUN(test_internal__stringstream);
- UTEST_RUN(test_internal__string_utils);
+ UTEST_RUN(test_internal__string_ascii_utils);
UTEST_RUN(test_internal__benchmark_gmio_fast_atof);
return NULL;
diff --git a/tests/main_test_stl.c b/tests/main_test_stl.c
index 25f12fe..efdf788 100644
--- a/tests/main_test_stl.c
+++ b/tests/main_test_stl.c
@@ -46,6 +46,7 @@ const char* all_tests()
UTEST_RUN(test_stl_read);
UTEST_RUN(test_stl_read_multi_solid);
+ UTEST_RUN(test_stla_lc_numeric);
UTEST_RUN(test_stla_write);
UTEST_RUN(test_stlb_read);
UTEST_RUN(test_stlb_write);
diff --git a/tests/test_core_internal.c b/tests/test_core_internal.c
index 6d410a6..5b3936a 100644
--- a/tests/test_core_internal.c
+++ b/tests/test_core_internal.c
@@ -17,16 +17,19 @@
#include "stream_buffer.h"
+#include "../src/gmio_core/error.h"
#include "../src/gmio_core/internal/byte_codec.h"
#include "../src/gmio_core/internal/byte_swap.h"
#include "../src/gmio_core/internal/convert.h"
#include "../src/gmio_core/internal/fast_atof.h"
+#include "../src/gmio_core/internal/locale_utils.h"
#include "../src/gmio_core/internal/numeric_utils.h"
#include "../src/gmio_core/internal/safe_cast.h"
#include "../src/gmio_core/internal/stringstream.h"
#include "../src/gmio_core/internal/stringstream_fast_atof.h"
#include "../src/gmio_core/internal/string_ascii_utils.h"
+#include
#include
#include
#include
@@ -264,7 +267,7 @@ static const char* test_internal__stringstream()
return NULL;
}
-static const char* test_internal__string_utils()
+static const char* test_internal__string_ascii_utils()
{
char c; /* for loop counter */
@@ -328,3 +331,40 @@ static const char* test_internal__string_utils()
return NULL;
}
+
+static const char* __tc__test_internal__locale_utils()
+{
+ const char* lc = setlocale(LC_NUMERIC, "");
+ if (lc != NULL
+ && gmio_ascii_stricmp(lc, "C") != 0
+ && gmio_ascii_stricmp(lc, "POSIX") != 0)
+ {
+ int error = GMIO_ERROR_OK;
+ UTEST_ASSERT(!gmio_lc_numeric_is_C());
+ UTEST_ASSERT(!gmio_check_lc_numeric(&error));
+ UTEST_COMPARE_INT(GMIO_ERROR_BAD_LC_NUMERIC, error);
+ }
+ else {
+ fprintf(stderr, "\nskip: default locale is NULL or already C/POSIX");
+ }
+
+ lc = setlocale(LC_NUMERIC, "C");
+ if (lc != NULL) {
+ int error = GMIO_ERROR_OK;
+ UTEST_ASSERT(gmio_lc_numeric_is_C());
+ UTEST_ASSERT(gmio_check_lc_numeric(&error));
+ UTEST_COMPARE_INT(GMIO_ERROR_OK, error);
+ }
+
+ return NULL;
+}
+
+static const char* test_internal__locale_utils()
+{
+ const char* error_str = NULL;
+ gmio_lc_numeric_save();
+ printf("\ninfo: current locale is \"%s\"", gmio_lc_numeric());
+ error_str = __tc__test_internal__locale_utils();
+ gmio_lc_numeric_restore();
+ return error_str;
+}
diff --git a/tests/test_stl_io.c b/tests/test_stl_io.c
index 468c47a..18e8d6c 100644
--- a/tests/test_stl_io.c
+++ b/tests/test_stl_io.c
@@ -22,11 +22,13 @@
#include "../src/gmio_core/error.h"
#include "../src/gmio_core/internal/min_max.h"
#include "../src/gmio_core/internal/string.h"
+#include "../src/gmio_core/internal/locale_utils.h"
#include "../src/gmio_stl/stl_error.h"
#include "../src/gmio_stl/stl_infos.h"
#include "../src/gmio_stl/stl_io.h"
#include "../src/gmio_stl/stl_io_options.h"
+#include
#include
#include
@@ -342,6 +344,39 @@ static const char* test_stl_read_multi_solid()
return res;
}
+
+static const char* test_stla_lc_numeric()
+{
+ struct gmio_stream null_stream = {0};
+ const struct gmio_stl_mesh null_mesh = {0};
+ struct gmio_stl_mesh_creator null_meshcreator = {0};
+ int error[4] = {0};
+
+ gmio_lc_numeric_save();
+ setlocale(LC_NUMERIC, "");
+ if (!gmio_lc_numeric_is_C()) {
+ struct gmio_stl_read_options read_opts = {0};
+ struct gmio_stl_write_options write_opts = {0};
+
+ /* By default, check LC_NUMERIC */
+ error[0] = gmio_stla_read(&null_stream, &null_meshcreator, NULL);
+ error[1] = gmio_stl_write(
+ GMIO_STL_FORMAT_ASCII, &null_stream, &null_mesh, NULL);
+ error[2] = gmio_stla_read(&null_stream, &null_meshcreator, &read_opts);
+ error[3] = gmio_stl_write(
+ GMIO_STL_FORMAT_ASCII, &null_stream, &null_mesh, &write_opts);
+ }
+ else {
+ fprintf(stderr, "\nskip: default locale is NULL or already C/POSIX");
+ }
+ gmio_lc_numeric_restore();
+ for (size_t i = 0; i < GMIO_ARRAY_SIZE(error); ++i) {
+ UTEST_COMPARE_INT(GMIO_ERROR_BAD_LC_NUMERIC, error[i]);
+ }
+
+ return NULL;
+}
+
static void generate_stlb_tests_models()
{
{