user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user