#include #include #include #include #include static __locale_t s_locale_posix { .name = "C", .encoding = __ENC_ASCII, }; static __locale_t s_locale_utf8 { .name = "C.UTF-8", .encoding = __ENC_UTF8, }; static locale_t s_current_locales[LC_ALL] { &s_locale_posix, &s_locale_posix, &s_locale_posix, &s_locale_posix, &s_locale_posix, &s_locale_posix, }; static_assert(LC_ALL == 6); static locale_t str_to_locale(const char* locale) { if (*locale == '\0') return &s_locale_utf8; if (strcmp(locale, "C") == 0 || strcmp(locale, "POSIX") == 0) return &s_locale_posix; if (strcmp(locale, "C.UTF-8") == 0) return &s_locale_utf8; return nullptr; } struct lconv* localeconv(void) { static lconv lconv; lconv.currency_symbol = const_cast(""); lconv.decimal_point = const_cast("."); lconv.frac_digits = CHAR_MAX; lconv.grouping = const_cast(""); lconv.int_curr_symbol = const_cast(""); lconv.int_frac_digits = CHAR_MAX; lconv.int_n_cs_precedes = CHAR_MAX; lconv.int_n_sep_by_space = CHAR_MAX; lconv.int_n_sign_posn = CHAR_MAX; lconv.int_p_cs_precedes = CHAR_MAX; lconv.int_p_sep_by_space = CHAR_MAX; lconv.int_p_sign_posn = CHAR_MAX; lconv.mon_decimal_point = const_cast(""); lconv.mon_grouping = const_cast(""); lconv.mon_thousands_sep = const_cast(""); lconv.negative_sign = const_cast(""); lconv.n_cs_precedes = CHAR_MAX; lconv.n_sep_by_space = CHAR_MAX; lconv.n_sign_posn = CHAR_MAX; lconv.positive_sign = const_cast(""); lconv.p_cs_precedes = CHAR_MAX; lconv.p_sep_by_space = CHAR_MAX; lconv.p_sign_posn = CHAR_MAX; lconv.thousands_sep = const_cast(""); return &lconv; } char* setlocale(int category, const char* locale_str) { static char s_locale_buffer[128]; if (locale_str == nullptr) { switch (category) { case LC_COLLATE: case LC_CTYPE: case LC_MESSAGES: case LC_MONETARY: case LC_NUMERIC: case LC_TIME: strcpy(s_locale_buffer, s_current_locales[category]->name); break; case LC_ALL: sprintf(s_locale_buffer, "%s;%s;%s;%s;%s;%s", s_current_locales[0]->name, s_current_locales[1]->name, s_current_locales[2]->name, s_current_locales[3]->name, s_current_locales[4]->name, s_current_locales[5]->name ); static_assert(LC_ALL == 6); break; default: return nullptr; } return s_locale_buffer; } locale_t locale = str_to_locale(locale_str); if (locale == nullptr) return nullptr; switch (category) { case LC_COLLATE: case LC_CTYPE: case LC_MESSAGES: case LC_MONETARY: case LC_NUMERIC: case LC_TIME: s_current_locales[category] = locale; break; case LC_ALL: for (auto& current : s_current_locales) current = locale; break; default: return nullptr; } strcpy(s_locale_buffer, locale->name); return s_locale_buffer; } locale_t __getlocale(int category) { switch (category) { case LC_COLLATE: case LC_CTYPE: case LC_MESSAGES: case LC_MONETARY: case LC_NUMERIC: case LC_TIME: return s_current_locales[category]; default: return nullptr; } } #include locale_t newlocale(int category_mask, const char* locale, locale_t base) { (void)category_mask; (void)locale; (void)base; dwarnln("TODO: newlocale"); return nullptr; } void freelocale(locale_t locobj) { (void)locobj; dwarnln("TODO: freelocale"); } locale_t uselocale(locale_t newloc) { (void)newloc; dwarnln("TODO: uselocale"); return nullptr; }