Files
KirkOS/user/include/mlibc/options/ansi/generic/locale.cpp
T
kaguya 9a9b91c940 user: implement mlibc as the libc, finally.
It's finally done..

Signed-off-by: kaguya <vpshinomiya@protonmail.com>
2026-05-02 03:31:49 -04:00

197 lines
5.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <limits.h>
#include <locale.h>
#include <string.h>
#include <bits/ensure.h>
#include <mlibc/debug.hpp>
#include <frg/optional.hpp>
namespace {
// Values of the C locale are defined by the C standard.
constexpr lconv c_lconv = {
const_cast<char *>("."), // decimal_point
const_cast<char *>(""), // thousands_sep
const_cast<char *>(""), // grouping
const_cast<char *>(""), // mon_decimal_point
const_cast<char *>(""), // mon_thousands_sep
const_cast<char *>(""), // mon_grouping
const_cast<char *>(""), // positive_sign
const_cast<char *>(""), // negative_sign
const_cast<char *>(""), // 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<char *>(""), // 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
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;
} // namespace mlibc
[[gnu::constructor]]
static void init_locale() {
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<char *>(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<char *>(current_desc->name);
}
}
namespace {
lconv effective_lc;
} // namespace
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;
}