diff options
-rw-r--r-- | CHANGELOG.rst | 8 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | libgcompat/locale.c | 56 |
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 ------ @@ -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); +} |