summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst8
-rw-r--r--Makefile1
-rw-r--r--libgcompat/locale.c56
3 files changed, 65 insertions, 0 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 1330b68..b88a0a7 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -11,6 +11,14 @@
0.9.0 (2020-07-??)
==================
+locale
+------
+
+* New module.
+
+* Adds newlocale and freelocale, which provide a glibc-compatible locale_t ABI.
+ This is necessary for software using the libstdc++ <locale>/<ctype> modules.
+
unistd
------
diff --git a/Makefile b/Makefile
index 6a36129..fd46a19 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ LIBGCOMPAT_SRC = \
libgcompat/gnulib.c \
libgcompat/grp.c \
libgcompat/internal.c \
+ libgcompat/locale.c \
libgcompat/malloc.c \
libgcompat/math.c \
libgcompat/misc.c \
diff --git a/libgcompat/locale.c b/libgcompat/locale.c
new file mode 100644
index 0000000..a7ac2c0
--- /dev/null
+++ b/libgcompat/locale.c
@@ -0,0 +1,56 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include "internal.h"
+
+void *__newlocale(int, const char *, void *);
+void __freelocale(void *);
+
+struct glibc_locale {
+ /* hopefully nobody pokes at this */
+ void *__locales[13];
+
+ const unsigned short int *__ctype_b;
+ const int *__ctype_tolower;
+ const int *__ctype_toupper;
+
+ const char *__names[13];
+};
+
+const unsigned short **__ctype_b_loc(void);
+const int32_t **__ctype_tolower_loc(void);
+const int32_t **__ctype_toupper_loc(void);
+
+const char *__gcompat_valid_locales[] = {"C", "POSIX"};
+
+bool _is_valid_locale(const char *candidate) {
+ for(int i = 0; i < sizeof __gcompat_valid_locales; i++) {
+ if(strcmp(candidate, __gcompat_valid_locales[i]) == 0) return true;
+ }
+ return false;
+}
+
+struct glibc_locale *newlocale(int mask, const char *name, locale_t base) {
+ GCOMPAT__assert_with_reason(_is_valid_locale(name),
+ "locale %s not supported\n", name);
+ struct glibc_locale *ret = malloc(sizeof(struct glibc_locale));
+ if(ret == NULL) return NULL;
+
+ ret->__locales[0] = __newlocale(mask, name, base);
+ for(int l = 1; l < 13; l++) ret->__locales[l] = ret->__locales[0];
+ ret->__ctype_b = *__ctype_b_loc();
+ ret->__ctype_tolower = *__ctype_tolower_loc();
+ ret->__ctype_toupper = *__ctype_toupper_loc();
+
+ ret->__names[0] = strdup("C");
+ for(int i = 1; i < 13; i++) ret->__names[i] = ret->__names[0];
+
+ return ret;
+}
+
+void freelocale(struct glibc_locale *loc) {
+ free(loc->__names[0]);
+ __freelocale(loc->__locales[0]);
+ free(loc);
+}