aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2025-01-10 22:06:06 +0100
committerSébastien Dailly <sebastien@dailly.me>2025-01-22 12:22:26 +0100
commit5e15341857e57671a3c617579e3d5dcc89040936 (patch)
tree8d90ea72c77ccef7f6b6d5eba199204ce01b27d6
parent413b86050e364db51eb4f1bb095f70b141c02919 (diff)
Print the float numbers using the user locale
-rwxr-xr-xlib/configuration/dune1
-rw-r--r--lib/configuration/importConf.ml12
-rw-r--r--lib/configuration/locale.c12
-rw-r--r--lib/configuration/of_json.ml1
-rw-r--r--lib/configuration/read_conf.ml9
-rw-r--r--lib/configuration/syntax.ml1
-rw-r--r--lib/csv/dataType.ml4
-rwxr-xr-xlib/csv/dune1
-rw-r--r--lib/csv/format.c49
-rw-r--r--readme.rst5
-rw-r--r--tests/analyser_dependency.ml2
-rw-r--r--tests/analyser_query_test.ml5
12 files changed, 96 insertions, 6 deletions
diff --git a/lib/configuration/dune b/lib/configuration/dune
index 27d31a6..b08e9bd 100755
--- a/lib/configuration/dune
+++ b/lib/configuration/dune
@@ -12,6 +12,7 @@
importExpression
importErrors
)
+ (foreign_stubs (language c) (names locale))
(preprocess (pps ppx_yojson_conv ppx_deriving.ord))
)
diff --git a/lib/configuration/importConf.ml b/lib/configuration/importConf.ml
index 3406a11..aa0e2f3 100644
--- a/lib/configuration/importConf.ml
+++ b/lib/configuration/importConf.ml
@@ -5,6 +5,8 @@ module Path = ImportDataTypes.Path
module T = Read_conf
module Expression = ImportExpression.T
+external set_locale : string -> unit = "set_locale"
+
let current_syntax = 1
let t_of_yojson : Yojson.Safe.t -> Syntax.t =
@@ -39,7 +41,14 @@ let t_of_toml : Otoml.t -> (Syntax.t, string) result =
[ "version" ]
in
match version with
- | n when n = latest_version -> TomlReader.read toml
+ | n when n = latest_version ->
+ let conf = TomlReader.read toml in
+ let () =
+ Result.iter
+ (fun conf -> set_locale (Option.value ~default:"" conf.Syntax.locale))
+ conf
+ in
+ conf
| _ ->
Printf.eprintf "Unsuported version : %d\n" version;
exit 1
@@ -49,6 +58,7 @@ let dummy_conf =
{
source = { file = ""; tab = 0; name = "" };
version = 1;
+ locale = Some "C";
externals = [];
columns = [];
filters = [];
diff --git a/lib/configuration/locale.c b/lib/configuration/locale.c
new file mode 100644
index 0000000..eeafd26
--- /dev/null
+++ b/lib/configuration/locale.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <locale.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+
+CAMLprim value set_locale( value param )
+{
+ const char *s;
+ s = String_val(param);
+ setlocale(LC_NUMERIC, s);
+ return Val_unit;
+}
diff --git a/lib/configuration/of_json.ml b/lib/configuration/of_json.ml
index e6ee7a4..6ac59a2 100644
--- a/lib/configuration/of_json.ml
+++ b/lib/configuration/of_json.ml
@@ -123,6 +123,7 @@ let yojson_of_predicate () = `Null
type t = Syntax.t = {
version : int; [@default current_syntax]
+ locale : string option;
source : table;
externals : syntax_v1_extern list; [@default []]
columns : path expression list;
diff --git a/lib/configuration/read_conf.ml b/lib/configuration/read_conf.ml
index 952c43c..df1a728 100644
--- a/lib/configuration/read_conf.ml
+++ b/lib/configuration/read_conf.ml
@@ -184,17 +184,18 @@ module Make (S : Decoders.Decode.S) = struct
S.field_opt_or ~default:[] "uniq"
@@ S.list (self#parse_expression ExpressionParser.path)
in
- S.succeed @@ fun version source externals ->
- Syntax.{ version; source; externals; columns; filters; sort; uniq }
+ S.succeed @@ fun version source externals locale ->
+ Syntax.
+ { version; source; externals; columns; filters; sort; uniq; locale }
method conf =
let* source = S.field "source" self#source
and* externals =
S.field_opt_or ~default:[] "externals"
(S.key_value_pairs_seq self#external_)
- in
+ and* locale = S.field_opt "locale" S.string in
let* sheet =
- S.field "sheet" self#sheet >|= fun v -> v 1 source externals
+ S.field "sheet" self#sheet >|= fun v -> v 1 source externals locale
in
S.succeed sheet
diff --git a/lib/configuration/syntax.ml b/lib/configuration/syntax.ml
index 1eb3c70..253720e 100644
--- a/lib/configuration/syntax.ml
+++ b/lib/configuration/syntax.ml
@@ -54,6 +54,7 @@ end
type t = {
version : int;
+ locale : string option;
source : Table.t;
externals : Extern.t list;
columns : Path.t E.t list;
diff --git a/lib/csv/dataType.ml b/lib/csv/dataType.ml
index c582b9c..1d2c7f9 100644
--- a/lib/csv/dataType.ml
+++ b/lib/csv/dataType.ml
@@ -1,3 +1,5 @@
+external show_float : float -> string = "show_float"
+
let match_date = Re.Str.regexp {|[0-9]+/[0-9]+/[0-9]+|}
type t =
@@ -11,7 +13,7 @@ let to_string = function
| Null -> ""
| Error s -> s
| Integer i -> string_of_int i
- | Float f -> string_of_float f
+ | Float f -> show_float f
| Content c -> (
match String.starts_with ~prefix:"0" c with
| false -> c
diff --git a/lib/csv/dune b/lib/csv/dune
index b0f4a72..2cdc868 100755
--- a/lib/csv/dune
+++ b/lib/csv/dune
@@ -3,4 +3,5 @@
(libraries
re
)
+ (foreign_stubs (language c) (names format))
)
diff --git a/lib/csv/format.c b/lib/csv/format.c
new file mode 100644
index 0000000..31e4bbe
--- /dev/null
+++ b/lib/csv/format.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <locale.h>
+#include <caml/memory.h>
+#include <caml/alloc.h>
+
+#ifndef _vscprintf
+/* For some reason, MSVC fails to honour this #ifndef. */
+/* Hence function renamed to _vscprintf_so(). */
+int _vscprintf_so(const char * format, va_list pargs) {
+ int retval;
+ va_list argcopy;
+ va_copy(argcopy, pargs);
+ retval = vsnprintf(NULL, 0, format, argcopy);
+ va_end(argcopy);
+ return retval;}
+#endif // _vscprintf
+
+#ifndef vasprintf
+int vasprintf(char **strp, const char *fmt, va_list ap) {
+ int len = _vscprintf_so(fmt, ap);
+ if (len == -1) return -1;
+ char *str = malloc((size_t) len + 1);
+ if (!str) return -1;
+ int r = vsnprintf(str, len + 1, fmt, ap); /* "secure" version of vsprintf */
+ if (r == -1) return free(str), -1;
+ *strp = str;
+ return r;}
+#endif // vasprintf
+
+#ifndef asprintf
+int asprintf(char *strp[], const char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ int r = vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return r;}
+#endif // asprintf
+
+CAMLprim value show_float( value float_param )
+{
+ CAMLparam1( float_param );
+ CAMLlocal1( ml_data );
+ double f = Double_val(float_param);
+ char* raw_data;
+ int data_len = asprintf(&raw_data, "%f", f);
+ ml_data = caml_copy_string( raw_data );
+ free(raw_data);
+ CAMLreturn( ml_data );
+}
diff --git a/readme.rst b/readme.rst
index 1318846..3c7c1a9 100644
--- a/readme.rst
+++ b/readme.rst
@@ -158,7 +158,11 @@ source
:tab: optionnellement l’onglet concerné
:name: le nom sous lequel le fichier sera associé.
+locale
+ Permet de définir la locale à utiliser lors de la génération du fichier CSV.
+ Utilise la valeur du système si non renseigné.
+ Exemples de valeurs possibles : `C`, `fr_FR.UTF-8`
Le chargement des dépendances
-----------------------------
@@ -692,3 +696,4 @@ Elles prennent se basent sur deux paramètres supplémentaires :
`max(expression, [regroupement, …], [tri, …])`
+
diff --git a/tests/analyser_dependency.ml b/tests/analyser_dependency.ml
index dea7727..279b5e5 100644
--- a/tests/analyser_dependency.ml
+++ b/tests/analyser_dependency.ml
@@ -140,6 +140,7 @@ let test_unlinked =
{
version = 1;
source = external_table_source;
+ locale = None;
externals =
[
{
@@ -171,6 +172,7 @@ let conf_with_unlinked =
{
version = 1;
source = external_table_source;
+ locale = None;
externals =
[
{
diff --git a/tests/analyser_query_test.ml b/tests/analyser_query_test.ml
index 8f531ce..5d7366b 100644
--- a/tests/analyser_query_test.ml
+++ b/tests/analyser_query_test.ml
@@ -27,6 +27,7 @@ let conf =
Syntax.
{
version = 1;
+ locale = None;
source = { file = "source.xlsx"; tab = 1; name = "source" };
externals =
[
@@ -100,6 +101,7 @@ let previous =
Syntax.
{
version = 1;
+ locale = None;
source = { file = "source.xlsx"; tab = 1; name = "previous" };
externals = [];
columns =
@@ -130,6 +132,7 @@ let sum =
Syntax.
{
version = 1;
+ locale = None;
source = { file = "source.xlsx"; tab = 1; name = "previous" };
externals = [];
columns =
@@ -160,6 +163,7 @@ let sum_total =
Syntax.
{
version = 1;
+ locale = None;
source = { file = "source.xlsx"; tab = 1; name = "previous" };
externals = [];
columns = [ Window (Sum (Path { alias = None; column = 5 }), [], []) ];
@@ -182,6 +186,7 @@ let sum_unfiltered =
Syntax.
{
version = 1;
+ locale = None;
source = { file = "source.xlsx"; tab = 1; name = "previous" };
externals = [];
columns =