1/*
2 * Copyright (c) 1999
3 * Silicon Graphics Computer Systems, Inc.
4 *
5 * Copyright (c) 1999
6 * Boris Fomitchev
7 *
8 * This material is provided "as is", with absolutely no warranty expressed
9 * or implied. Any use is at your own risk.
10 *
11 * Permission to use or copy this software for any purpose is hereby granted
12 * without fee, provided the above notices are retained on all copies.
13 * Permission to modify the code and to distribute modified code is granted,
14 * provided the above notices are retained, and a notice that the code was
15 * modified is included with the above copyright notice.
16 *
17 */
18#include "stlport_prefix.h"
19
20#include <typeinfo>
21
22#include "message_facets.h"
23#include "acquire_release.h"
24
25_STLP_BEGIN_NAMESPACE
26
27_STLP_MOVE_TO_PRIV_NAMESPACE
28
29void _Catalog_locale_map::insert(nl_catd_type key, const locale& L) {
30  _STLP_TRY {
31#if !defined (_STLP_NO_TYPEINFO) && !defined (_STLP_NO_RTTI)
32    // Don't bother to do anything unless we're using a non-default ctype facet
33#  ifdef _STLP_NO_WCHAR_T
34    typedef char _Char;
35#  else
36    typedef wchar_t _Char;
37#  endif
38
39    typedef ctype<_Char> wctype;
40    wctype const& wct = use_facet<wctype>(L);
41    if (typeid(wct) != typeid(wctype)) {
42#endif
43      if (!M)
44        M = new map_type;
45
46      M->insert(map_type::value_type(key, L));
47#if !defined (_STLP_NO_TYPEINFO) && !defined (_STLP_NO_RTTI)
48    }
49#endif
50  }
51  _STLP_CATCH_ALL {}
52}
53
54void _Catalog_locale_map::erase(nl_catd_type key) {
55  if (M)
56    M->erase(key);
57}
58
59locale _Catalog_locale_map::lookup(nl_catd_type key) const {
60  if (M) {
61    map_type::const_iterator i = M->find(key);
62    return i != M->end() ? (*i).second : locale::classic();
63  }
64  else
65    return locale::classic();
66}
67
68
69#if defined (_STLP_USE_NL_CATD_MAPPING)
70_STLP_VOLATILE __stl_atomic_t _Catalog_nl_catd_map::_count = 0;
71
72messages_base::catalog _Catalog_nl_catd_map::insert(nl_catd_type cat) {
73  messages_base::catalog &res = Mr[cat];
74  if ( res == 0 ) {
75#if defined (_STLP_ATOMIC_INCREMENT)
76    res = __STATIC_CAST(int, _STLP_ATOMIC_INCREMENT(&_count));
77#else
78    static _STLP_STATIC_MUTEX _Count_lock _STLP_MUTEX_INITIALIZER;
79    {
80      _STLP_auto_lock sentry(_Count_lock);
81      res = __STATIC_CAST(int, ++_count);
82    }
83#endif
84    M[res] = cat;
85  }
86  return res;
87}
88
89void _Catalog_nl_catd_map::erase(messages_base::catalog cat) {
90  map_type::iterator mit(M.find(cat));
91  if (mit != M.end()) {
92    Mr.erase((*mit).second);
93    M.erase(mit);
94  }
95}
96#endif
97
98//----------------------------------------------------------------------
99//
100_Messages::_Messages(bool is_wide, const char *name) :
101  _M_message_obj(0), _M_map(0) {
102  if (!name)
103    locale::_M_throw_on_null_name();
104
105  int __err_code;
106  char buf[_Locale_MAX_SIMPLE_NAME];
107  _M_message_obj = _STLP_PRIV __acquire_messages(name, buf, 0, &__err_code);
108  if (!_M_message_obj)
109    locale::_M_throw_on_creation_failure(__err_code, name, "messages");
110
111  if (is_wide)
112    _M_map = new _Catalog_locale_map;
113}
114
115_Messages::_Messages(bool is_wide, _Locale_messages* msg) :
116  _M_message_obj(msg), _M_map(is_wide ? new _Catalog_locale_map() : 0)
117{}
118
119_Messages::~_Messages() {
120  __release_messages(_M_message_obj);
121  delete _M_map;
122}
123
124_Messages::catalog _Messages::do_open(const string& filename, const locale& L) const {
125  nl_catd_type result = _M_message_obj ? _Locale_catopen(_M_message_obj, filename.c_str())
126    : (nl_catd_type)(-1);
127
128  if ( result != (nl_catd_type)(-1) ) {
129    if ( _M_map != 0 ) {
130      _M_map->insert(result, L);
131    }
132    return _STLP_MUTABLE(_Messages_impl, _M_cat).insert( result );
133  }
134
135  return -1;
136}
137
138string _Messages::do_get(catalog cat,
139                         int set, int p_id, const string& dfault) const {
140  return _M_message_obj != 0 && cat >= 0
141    ? string(_Locale_catgets(_M_message_obj, _STLP_MUTABLE(_Messages_impl, _M_cat)[cat],
142                             set, p_id, dfault.c_str()))
143    : dfault;
144}
145
146#if !defined (_STLP_NO_WCHAR_T)
147
148wstring
149_Messages::do_get(catalog thecat,
150                  int set, int p_id, const wstring& dfault) const {
151  typedef ctype<wchar_t> wctype;
152  const wctype& ct = use_facet<wctype>(_M_map->lookup(_STLP_MUTABLE(_Messages_impl, _M_cat)[thecat]));
153
154  const char* str = _Locale_catgets(_M_message_obj, _STLP_MUTABLE(_Messages_impl, _M_cat)[thecat], set, p_id, "");
155
156  // Verify that the lookup failed; an empty string might represent success.
157  if (!str)
158    return dfault;
159  else if (str[0] == '\0') {
160    const char* str2 = _Locale_catgets(_M_message_obj, _STLP_MUTABLE(_Messages_impl, _M_cat)[thecat], set, p_id, "*");
161    if (!str2 || ((str2[0] == '*') && (str2[1] == '\0')))
162      return dfault;
163  }
164
165  // str is correct.  Now we must widen it to get a wstring.
166  size_t n = strlen(str);
167
168  // NOT PORTABLE.  What we're doing relies on internal details of the
169  // string implementation.  (Contiguity of string elements.)
170  wstring result(n, wchar_t(0));
171  ct.widen(str, str + n, &*result.begin());
172  return result;
173}
174
175#endif
176
177void _Messages::do_close(catalog thecat) const {
178  if (_M_message_obj)
179    _Locale_catclose(_M_message_obj, _STLP_MUTABLE(_Messages_impl, _M_cat)[thecat]);
180  if (_M_map) _M_map->erase(_STLP_MUTABLE(_Messages_impl, _M_cat)[thecat]);
181  _STLP_MUTABLE(_Messages_impl, _M_cat).erase( thecat );
182}
183
184_STLP_MOVE_TO_STD_NAMESPACE
185
186//----------------------------------------------------------------------
187// messages<char>
188messages<char>::messages(size_t refs)
189  : locale::facet(refs) {}
190
191messages_byname<char>::messages_byname(const char *name, size_t refs)
192  : messages<char>(refs), _M_impl(new _STLP_PRIV _Messages(false, name)) {}
193
194messages_byname<char>::messages_byname(_Locale_messages* msg)
195  : messages<char>(0), _M_impl(new _STLP_PRIV _Messages(false, msg)) {}
196
197messages_byname<char>::~messages_byname()
198{ delete _M_impl; }
199
200messages_byname<char>::catalog
201messages_byname<char>::do_open(const string& filename, const locale& l) const
202{ return _M_impl->do_open(filename, l); }
203
204string
205messages_byname<char>::do_get(catalog cat, int set, int p_id,
206                              const string& dfault) const
207{ return _M_impl->do_get(cat, set, p_id, dfault); }
208
209void messages_byname<char>::do_close(catalog cat) const
210{ _M_impl->do_close(cat); }
211
212#if !defined (_STLP_NO_WCHAR_T)
213
214//----------------------------------------------------------------------
215// messages<wchar_t>
216
217messages<wchar_t>::messages(size_t refs)
218  : locale::facet(refs) {}
219
220messages_byname<wchar_t>::messages_byname(const char *name, size_t refs)
221  : messages<wchar_t>(refs), _M_impl(new _STLP_PRIV _Messages(true, name)) {}
222
223messages_byname<wchar_t>::messages_byname(_Locale_messages* msg)
224  : messages<wchar_t>(0), _M_impl(new _STLP_PRIV _Messages(true, msg)) {}
225
226messages_byname<wchar_t>::~messages_byname()
227{ delete _M_impl; }
228
229messages_byname<wchar_t>::catalog
230messages_byname<wchar_t>::do_open(const string& filename, const locale& L) const
231{ return _M_impl->do_open(filename, L); }
232
233wstring
234messages_byname<wchar_t>::do_get(catalog thecat,
235                                 int set, int p_id, const wstring& dfault) const
236{ return _M_impl->do_get(thecat, set, p_id, dfault); }
237
238void messages_byname<wchar_t>::do_close(catalog cat) const
239{ _M_impl->do_close(cat); }
240
241#endif
242
243_STLP_END_NAMESPACE
244
245// Local Variables:
246// mode:C++
247// End:
248