#include #include #include #include #include #include namespace { // Values of the C locale are defined by the C standard. constexpr lconv c_lconv = { const_cast("."), // decimal_point const_cast(""), // thousands_sep const_cast(""), // grouping const_cast(""), // mon_decimal_point const_cast(""), // mon_thousands_sep const_cast(""), // mon_grouping const_cast(""), // positive_sign const_cast(""), // negative_sign const_cast(""), // currency_symbol CHAR_MAX, // frac_digits CHAR_MAX, // p_cs_precedes CHAR_MAX, // n_cs_precedes CHAR_MAX, // p_sep_by_space CHAR_MAX, // n_sep_by_space CHAR_MAX, // p_sign_posn CHAR_MAX, // n_sign_posn const_cast(""), // int_curr_symbol CHAR_MAX, // int_frac_digits CHAR_MAX, // int_p_cs_precedes CHAR_MAX, // int_n_cs_precedes CHAR_MAX, // int_p_sep_by_space CHAR_MAX, // int_n_sep_by_space CHAR_MAX, // int_p_sign_posn CHAR_MAX // int_n_sign_posn }; } namespace mlibc { struct locale_description { // Identifier of this locale. used in setlocale(). const char *name; lconv lc; }; constinit const locale_description c_locale{ .name = "C", .lc = c_lconv }; constinit const locale_description posix_locale{ .name = "POSIX", .lc = c_lconv }; const locale_description *query_locale_description(const char *name) { if(!strcmp(name, "C")) return &c_locale; if(!strcmp(name, "POSIX")) return &posix_locale; return nullptr; } const locale_description *collate_facet; const locale_description *ctype_facet; const locale_description *monetary_facet; const locale_description *numeric_facet; const locale_description *time_facet; const locale_description *messages_facet; } void __mlibc_initLocale() { mlibc::collate_facet = &mlibc::c_locale; mlibc::ctype_facet = &mlibc::c_locale; mlibc::monetary_facet = &mlibc::c_locale; mlibc::numeric_facet = &mlibc::c_locale; mlibc::time_facet = &mlibc::c_locale; mlibc::messages_facet = &mlibc::c_locale; } char *setlocale(int category, const char *name) { if(category == LC_ALL) { // ´TODO: Implement correct return value when categories differ. auto current_desc = mlibc::collate_facet; __ensure(current_desc == mlibc::ctype_facet); __ensure(current_desc == mlibc::monetary_facet); __ensure(current_desc == mlibc::numeric_facet); __ensure(current_desc == mlibc::time_facet); __ensure(current_desc == mlibc::messages_facet); if(name) { // Our default C locale is the C locale. if(!strlen(name)) name = "C"; auto new_desc = mlibc::query_locale_description(name); if(!new_desc) { mlibc::infoLogger() << "mlibc: Locale " << name << " is not supported" << frg::endlog; return nullptr; } mlibc::collate_facet = new_desc; mlibc::ctype_facet = new_desc; mlibc::monetary_facet = new_desc; mlibc::numeric_facet = new_desc; mlibc::time_facet = new_desc; mlibc::messages_facet = new_desc; } return const_cast(current_desc->name); }else{ const mlibc::locale_description **facet_ptr; switch(category) { case LC_COLLATE: facet_ptr = &mlibc::collate_facet; break; case LC_CTYPE: facet_ptr = &mlibc::ctype_facet; break; case LC_MONETARY: facet_ptr = &mlibc::monetary_facet; break; case LC_NUMERIC: facet_ptr = &mlibc::numeric_facet; break; case LC_TIME: facet_ptr = &mlibc::time_facet; break; case LC_MESSAGES: facet_ptr = &mlibc::messages_facet; break; default: mlibc::infoLogger() << "mlibc: Unexpected value " << category << " for category in setlocale()" << frg::endlog; return nullptr; } auto current_desc = *facet_ptr; if(name) { // Our default C locale is the C locale. if(!strlen(name)) name = "C"; auto new_desc = mlibc::query_locale_description(name); if(!new_desc) { mlibc::infoLogger() << "mlibc: Locale " << name << " is not supported" << frg::endlog; return nullptr; } *facet_ptr = new_desc; } return const_cast(current_desc->name); } } namespace { lconv effective_lc; } struct lconv *localeconv(void) { // Numeric locale. const auto &numeric_lc = mlibc::numeric_facet->lc; effective_lc.decimal_point = numeric_lc.decimal_point; effective_lc.thousands_sep = numeric_lc.thousands_sep; effective_lc.grouping = numeric_lc.grouping; // Monetary locale. const auto &monetary_lc = mlibc::monetary_facet->lc; effective_lc.mon_decimal_point = monetary_lc.mon_decimal_point; effective_lc.mon_thousands_sep = monetary_lc.mon_thousands_sep; effective_lc.mon_grouping = monetary_lc.mon_grouping; effective_lc.positive_sign = monetary_lc.positive_sign; effective_lc.negative_sign = monetary_lc.negative_sign; effective_lc.currency_symbol = monetary_lc.currency_symbol; effective_lc.frac_digits = monetary_lc.frac_digits; effective_lc.p_cs_precedes = monetary_lc.p_cs_precedes; effective_lc.n_cs_precedes = monetary_lc.n_cs_precedes; effective_lc.p_sep_by_space = monetary_lc.p_sep_by_space; effective_lc.n_sep_by_space = monetary_lc.n_sep_by_space; effective_lc.p_sign_posn = monetary_lc.p_sign_posn; effective_lc.n_sign_posn = monetary_lc.n_sign_posn; effective_lc.int_curr_symbol = monetary_lc.int_curr_symbol; effective_lc.int_frac_digits = monetary_lc.int_frac_digits; effective_lc.int_p_cs_precedes = monetary_lc.int_p_cs_precedes; effective_lc.int_n_cs_precedes = monetary_lc.int_n_cs_precedes; effective_lc.int_p_sep_by_space = monetary_lc.int_p_sep_by_space; effective_lc.int_n_sep_by_space = monetary_lc.int_n_sep_by_space; effective_lc.int_p_sign_posn = monetary_lc.int_p_sign_posn; effective_lc.int_n_sign_posn = monetary_lc.int_n_sign_posn; return &effective_lc; }