From 6aea4e2c5dff618e383a6da8eca3521ae6896c40 Mon Sep 17 00:00:00 2001 From: Felipe Olmos <92923444+folmos-at-orange@users.noreply.github.com> Date: Mon, 15 Jan 2024 10:49:19 +0100 Subject: [PATCH] Fix MacOS std::setlocale writing errno In MacOS std::setlocale writes errno. This provokes erroneus error messages in the Khiops logs. To fix it this patch implements a a portability wrapper p_SetLocale. --- src/Norm/base/Portability.cpp | 22 ++++++++++++++++++++-- src/Norm/base/Portability.h | 14 +++++++++----- src/Norm/base/UIObject.cpp | 10 +++++----- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Norm/base/Portability.cpp b/src/Norm/base/Portability.cpp index 9a82f081b..4349ce2d9 100644 --- a/src/Norm/base/Portability.cpp +++ b/src/Norm/base/Portability.cpp @@ -9,14 +9,32 @@ // Declaration de la methode de Standard.h permettant d'acceder aux buffers de travail extern char* StandardGetBuffer(); +// MacOS note: The MacOS libc implementation of setlocale sets errno to zero (it shouldn't from the +// spec). So, in MacOS we save the state of `errno` and restore it after the call to setlocale. +char* p_SetLocale(int category, const char* locale) +{ + char* currentLocale; +#ifdef __APPLE__ + int currentErrno; + + currentErrno = errno; +#endif + currentLocale = setlocale(category, locale); +#ifdef __APPLE__ + errno = currentErrno; +#endif + + return currentLocale; +} + void p_SetMachineLocale() { - setlocale(LC_ALL, ""); + p_SetLocale(LC_ALL, ""); } void p_SetApplicationLocale() { - setlocale(LC_ALL, "en_US.UTF-8"); + p_SetLocale(LC_ALL, "en_US.UTF-8"); } ///////////////////////////////////////////////////////////////// diff --git a/src/Norm/base/Portability.h b/src/Norm/base/Portability.h index 01705253f..3adec01df 100644 --- a/src/Norm/base/Portability.h +++ b/src/Norm/base/Portability.h @@ -217,12 +217,16 @@ char* p_strcpy(char* strDestination, const char* strSource); char* p_strncpy(char* strDest, const char* strSource, size_t count); char* p_strcat(char* strDestination, const char* strSource); -// Le locale de l'application est parametre de facon a etre independant de la machine, -// pour assurer l'unicite des conversions numeriques et de leur format d'export, des tris, -// et des comparaisons entre chaines de caracteres +// Portable wrapper of std::setlocale to avoid errno side effets in MacOS +// See the implementation for details. +char* p_SetLocale(int category, const char* locale); + +// Le locale de l'application est parametre de facon a etre independant de la machine, pour assurer +// l'unicite des conversions numeriques et de leur format d'export, des tris, et des comparaisons +// entre chaines de caracteres // -// Parametrage des locales: toute fonction de FileService base sur un nom de fichier entoure son appel -// d'un parametrage prealable au locale de la machine, puis restore le locale de l'application +// Parametrage des locales: toute fonction de FileService base sur un nom de fichier entoure son +// appel d'un parametrage prealable au locale de la machine, puis restore le locale de l'application // Dans le cas d'un besoin de parametrage de locale specifique, il est necessaire de repositionner // ensuite le locale par defaut par appel a p_SetApplicationLocale. void p_SetMachineLocale(); diff --git a/src/Norm/base/UIObject.cpp b/src/Norm/base/UIObject.cpp index 005588c3b..effc591ce 100644 --- a/src/Norm/base/UIObject.cpp +++ b/src/Norm/base/UIObject.cpp @@ -1203,7 +1203,7 @@ JNIEnv* UIObject::GraphicGetJNIEnv() bGraphicIsLoaded = true; // Memorisation du locale courant (modifie par Java) - sCurrentLocale = setlocale(LC_ALL, NULL); + sCurrentLocale = p_SetLocale(LC_ALL, NULL); // Recherche de la classe JFrame pour savoir si on a acces au GUI cls = env->FindClass("javax/swing/JFrame"); @@ -1564,7 +1564,7 @@ const ALString UIObject::NativeFromJstring(JNIEnv* envValue, const jstring value jbyte* p_bytes; // Memorisation du locale courant (modifie par Java: cf GraphicGetJNIEnv) - sCurrentLocale = setlocale(LC_ALL, NULL); + sCurrentLocale = p_SetLocale(LC_ALL, NULL); // On utilise directment l'API JNI (sans passer par GraphicGetClassID ou GraphicGetMethodID) // pour eviter les recursion avec GraphicGetJNIEnv @@ -1595,7 +1595,7 @@ const ALString UIObject::NativeFromJstring(JNIEnv* envValue, const jstring value envValue->ReleaseByteArrayElements(byte_array, p_bytes, 0); // Restitution du locale courant - setlocale(LC_ALL, sCurrentLocale); + p_SetLocale(LC_ALL, sCurrentLocale); return sResult; } @@ -1612,7 +1612,7 @@ const jstring UIObject::NativeToJstring(JNIEnv* envValue, const ALString& sValue require(envValue != NULL); // Memorisation du locale courant (modifie par Java: cf GraphicGetJNIEnv) - sCurrentLocale = setlocale(LC_ALL, NULL); + sCurrentLocale = p_SetLocale(LC_ALL, NULL); // On utilise directment l'API JNI (sans passer par GraphicGetClassID ou GraphicGetMethodID) // pour eviter les recursion avec GraphicGetJNIEnv @@ -1637,7 +1637,7 @@ const jstring UIObject::NativeToJstring(JNIEnv* envValue, const ALString& sValue jstringValue = (jstring)envValue->NewObject(class_java_lang_String, mid_string_ctor, byte_array, codeString); // Restitution du locale courant - setlocale(LC_ALL, sCurrentLocale); + p_SetLocale(LC_ALL, sCurrentLocale); return jstringValue; }