1//
2// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
3// Copyright (c) 2022-2023 Alexander Grund
4//
5// Distributed under the Boost Software License, Version 1.0.
6// https://www.boost.org/LICENSE_1_0.txt
7
8#include "boost/locale/posix/posix_backend.hpp"
9#include <boost/locale/gnu_gettext.hpp>
10#include <boost/locale/info.hpp>
11#include <boost/locale/localization_backend.hpp>
12#include <boost/locale/util.hpp>
13#include <boost/locale/util/locale_data.hpp>
14#include <algorithm>
15#include <iterator>
16#include <langinfo.h>
17#include <vector>
18#if defined(__FreeBSD__)
19# include <xlocale.h>
20#endif
21
22#include "boost/locale/posix/all_generator.hpp"
23#include "boost/locale/shared/message.hpp"
24#include "boost/locale/util/gregorian.hpp"
25#include "boost/locale/util/make_std_unique.hpp"
26
27namespace boost { namespace locale { namespace impl_posix {
28
29 class posix_localization_backend : public localization_backend {
30 public:
31 posix_localization_backend() : invalid_(true) {}
32 posix_localization_backend(const posix_localization_backend& other) :
33 localization_backend(), paths_(other.paths_), domains_(other.domains_), locale_id_(other.locale_id_),
34 invalid_(true)
35 {}
36 posix_localization_backend* clone() const override { return new posix_localization_backend(*this); }
37
38 void set_option(const std::string& name, const std::string& value) override
39 {
40 invalid_ = true;
41 if(name == "locale")
42 locale_id_ = value;
43 else if(name == "message_path")
44 paths_.push_back(x: value);
45 else if(name == "message_application")
46 domains_.push_back(x: value);
47 }
48 void clear_options() override
49 {
50 invalid_ = true;
51 locale_id_.clear();
52 paths_.clear();
53 domains_.clear();
54 }
55
56 static void free_locale_by_ptr(locale_t* lc)
57 {
58 freelocale(dataset: *lc);
59 delete lc;
60 }
61
62 void prepare_data()
63 {
64 if(!invalid_)
65 return;
66
67 real_id_ = locale_id_.empty() ? util::get_system_locale() : locale_id_;
68 data_.parse(locale_name: real_id_);
69
70 lc_.reset();
71 locale_t tmp = newlocale(LC_ALL_MASK, locale: real_id_.c_str(), base: nullptr);
72 if(!tmp)
73 tmp = newlocale(LC_ALL_MASK, locale: "C", base: nullptr);
74 if(!tmp)
75 throw std::runtime_error("newlocale failed");
76
77 locale_t* tmp_p;
78 try {
79 tmp_p = new locale_t(tmp);
80 } catch(...) {
81 freelocale(dataset: tmp);
82 throw;
83 }
84 lc_ = std::shared_ptr<locale_t>(tmp_p, free_locale_by_ptr);
85 invalid_ = false;
86 }
87
88 std::locale install(const std::locale& base, category_t category, char_facet_t type) override
89 {
90 prepare_data();
91
92 switch(category) {
93 case category_t::convert: return create_convert(in: base, lc: lc_, type);
94 case category_t::collation: return create_collate(in: base, lc: lc_, type);
95 case category_t::formatting: return create_formatting(in: base, lc: lc_, type);
96 case category_t::parsing: return create_parsing(in: base, lc: lc_, type);
97 case category_t::codepage: return create_codecvt(in: base, encoding: nl_langinfo_l(CODESET, l: *lc_), type);
98 case category_t::calendar: return util::install_gregorian_calendar(in: base, terr: data_.country());
99 case category_t::message: return detail::install_message_facet(in: base, type, data: data_, domains: domains_, paths: paths_);
100 case category_t::information: return util::create_info(in: base, name: real_id_);
101 case category_t::boundary: break; // Not implemented
102 }
103 return base;
104 }
105
106 private:
107 std::vector<std::string> paths_;
108 std::vector<std::string> domains_;
109 std::string locale_id_;
110 std::string real_id_;
111 util::locale_data data_;
112
113 bool invalid_;
114 std::shared_ptr<locale_t> lc_;
115 };
116
117 std::unique_ptr<localization_backend> create_localization_backend()
118 {
119 return make_std_unique<posix_localization_backend>();
120 }
121
122}}} // namespace boost::locale::impl_posix
123

source code of boost/libs/locale/src/boost/locale/posix/posix_backend.cpp