Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
messages.cpp
Go to the documentation of this file.
1
29#define _RWSTD_LIB_SRC
30#include <rw/_defs.h>
31
32#include <new> // for placement new
33
34#include <string.h> // for memcpy, size_t
35
36#include <loc/_locale.h>
37#include <loc/_messages.h>
38
39#include <rw/_mutex.h>
40
41
42#if !defined (_RWSTD_NO_NL_TYPES_H) && !defined (_RWSTD_NO_CATOPEN_CATGETS)
43# include <nl_types.h>
44#else // _RWSTD_NO_NL_TYPES_H || _RWSTD_NO_CATOPEN_CATGETS
45# include "catalog.h"
46#endif // !_RWSTD_NO_NL_TYPES_H && !_RWSTD_NO_CATOPEN_CATGETS
47
48
49#define _RWSTD_BAD_CATD ((nl_catd)-1)
50
51
53
54
55// Implementation structure private to this module -- __rw_open_cat_data.
56// Keeps track of the association between an open message catalog (as
57// identified by the nl_catd handle returned by the C library catopen
58// function) and the locale specified by the user for character translation
59// in the call to messages<_CharT>::open.
60//
61// Also used as a parameter to rw_get_static_mutex to ensure uniqueness
62// of the mutex object used in sync'ing the threads using __rw_cat...
63// (see RWSTD_MT_STATIC_GUARD below)
64struct __rw_open_cat_data
65{
66 nl_catd catd;
67 union {
68 void *_C_align;
69 char _C_data [sizeof (_STD::locale)];
70 } loc;
71};
72
73struct __rw_open_cat_page
74{
75 static const size_t _C_size = 8;
76
77 __rw_open_cat_page* _C_next; // next page
78 __rw_open_cat_data _C_data [_C_size];
79};
80
81
82// manages a global, per-process repository of open catalogs according
83// to the following table:
84
85// cat _rw_open_cat_data algorithm
86// -1 0 invalid
87// -1 non-0 append the struct into the repository and
88// return a pointer to a struct containing
89// the new catalog and locale
90// > -1 0 return the a pointer to a struct
91// containing the locale associated with
92// this catalog
93// > -1 non-0 find the struct containg the locale and
94// catalog in the repository and invalidate
95// it.
96// Return a pointer to the struct
97
98static __rw_open_cat_data*
99__rw_manage_cat_data (int &cat, __rw_open_cat_data *pcat_data)
100{
101 // a per-process array of pointers to catalog data structs
102 static __rw_open_cat_data* catalog_buf [__rw_open_cat_page::_C_size];
103 static __rw_open_cat_data** catalogs = 0;
104
105 // first page of a per-process list of pages of catalog data structs
106 static __rw_open_cat_page catalog_page;
107
108 static size_t n_catalogs = 0;
109 static size_t catalog_bufsize = sizeof catalog_buf / sizeof *catalog_buf;
110 static size_t largest_cat = 0;
111
112 if (!catalogs) {
113
114 for (size_t i = 0; i < catalog_bufsize; ++i) {
115 catalog_page._C_data [i].catd = _RWSTD_BAD_CATD;
116 catalog_buf [i] = &catalog_page._C_data [i];
117 }
118
119 catalogs = catalog_buf;
120 }
121
122 if (-1 == cat) {
123 _RWSTD_ASSERT (0 != pcat_data);
124
125 // append the locale and return a struct with the associated catalog
126
127 if (pcat_data) {
128 if (n_catalogs == catalog_bufsize) {
129
130 // allocate new page of catalog data
131 __rw_open_cat_page* const page =
132 new __rw_open_cat_page;
133
134 // insert new page into singly-linked page list
135 page->_C_next = catalog_page._C_next;
136 catalog_page._C_next = page;
137
138 // initialize new page
139 for (size_t i = 0; i < __rw_open_cat_page::_C_size; ++i) {
140 page->_C_data [i].catd = _RWSTD_BAD_CATD;
141 }
142
143 // rwallocate buffer of catalog data pointers
144 __rw_open_cat_data** const data =
145 new __rw_open_cat_data* [n_catalogs + __rw_open_cat_page::_C_size];
146
147 memcpy (data, catalogs, n_catalogs * sizeof *data);
148
149 if (catalogs != catalog_buf)
150 delete[] catalogs;
151
152 catalogs = data;
153 catalog_bufsize += __rw_open_cat_page::_C_size;
154
155 for (size_t i = 0; i < __rw_open_cat_page::_C_size; ++i) {
156 catalogs [n_catalogs + i] = &page->_C_data [i];
157 }
158
159 cat = int (n_catalogs);
160
161 catalogs [cat]->catd = pcat_data->catd;
162 memcpy (&catalogs [cat]->loc, &pcat_data->loc,
163 sizeof (_STD::locale));
164
165 if (size_t (cat) > largest_cat)
166 largest_cat = size_t (cat);
167
168 ++n_catalogs;
169 }
170 else {
171 // find the first open slot and use it.
172 cat = 0;
173 while (catalogs [cat]->catd != _RWSTD_BAD_CATD) {
174 ++cat;
175 }
176
177 catalogs [cat]->catd = pcat_data->catd;
178 memcpy (&catalogs [cat]->loc, &pcat_data->loc,
179 sizeof (_STD::locale));
180
181 if (size_t (cat) > largest_cat)
182 largest_cat = size_t (cat);
183
184 ++n_catalogs;
185 }
186 }
187 }
188 else {
189
190 if (0 == pcat_data) {
191 // find struct and return it
192 if (size_t (cat) < catalog_bufsize)
193 return catalogs [cat];
194
195 return 0;
196 }
197
198 // initialize the struct to an invalid state
199 --n_catalogs;
200 catalogs [cat]->catd = _RWSTD_BAD_CATD;
201
202 if (size_t (cat) == largest_cat) {
203
204 // find the next smallest valid slot
205 largest_cat = 0;
206
207 for (int i = cat; i >= 0; --i) {
208 if (catalogs [i]->catd != _RWSTD_BAD_CATD) {
209 largest_cat = size_t (i);
210 break;
211 }
212 }
213
214 static const size_t bufsize =
215 sizeof catalog_buf / sizeof *catalog_buf;
216
217 if ((largest_cat < bufsize / 2) && (catalogs != catalog_buf)) {
218 // when there are no more open catalogs indexed beyond
219 // second half of the static pointer repository, copy
220 // the open catalog pointers back into the repository.
221
222 catalog_bufsize = bufsize;
223
224 memcpy (catalog_buf, catalogs,
225 catalog_bufsize * sizeof (*catalogs));
226
227 delete[] catalogs;
228
229 catalogs = catalog_buf;
230
231 // remove all pages, they're not in use
232 while (catalog_page._C_next)
233 {
234 // remove next page from page list
235 __rw_open_cat_page* page = catalog_page._C_next;
236 catalog_page._C_next = page->_C_next;
237
238 // deallocate that page
239 delete page;
240 }
241 }
242 }
243 }
244
245 return pcat_data;
246}
247
248
249
250// Open a message catalog and assign and return a handle for it.
251
252int __rw_cat_open (const _STD::string &cat_name, const _STD::locale &loc)
253{
254 _RWSTD_MT_CLASS_GUARD (__rw_open_cat_data);
255
256 const nl_catd catd = catopen (cat_name.c_str (), NL_CAT_LOCALE);
257 if (_RWSTD_BAD_CATD == catd)
258 return -1;
259
260 __rw_open_cat_data cat_data;
261 cat_data.catd = catd;
262 new (&cat_data.loc) _STD::locale (loc);
263
264 int cat = -1;
265 __rw_manage_cat_data (cat, &cat_data);
266
267 _RWSTD_ASSERT (0 <= cat);
268
269 return cat;
270}
271
272
273// Get message text from catalog.
274const char* __rw_get_message (int cat, int set_num, int msg_num)
275{
276 if (cat < 0)
277 return 0;
278
279 _RWSTD_MT_CLASS_GUARD (__rw_open_cat_data);
280
281 __rw_open_cat_data *const pcat_data = __rw_manage_cat_data (cat, 0);
282
283 if (pcat_data && _RWSTD_BAD_CATD != pcat_data->catd) {
284 // 22.2.7.1.2, p3: `catalog' must be valid
285
286 const char dflt[] = "";
287
288 const nl_catd catd = pcat_data->catd;
289
290 const char* const text = catgets (catd, set_num, msg_num, dflt);
291
292 if (text != dflt)
293 return text;
294 }
295
296 return 0;
297}
298
299
300// Get locale to be used for character translation for this message catalog.
301const _STD::locale& __rw_get_locale (int cat)
302{
303 _RWSTD_MT_CLASS_GUARD (__rw_open_cat_data);
304
305 _RWSTD_ASSERT (0 <= cat);
306 __rw_open_cat_data* const pcat_data = __rw_manage_cat_data (cat, 0);
307
308 _RWSTD_ASSERT (0 != pcat_data);
309
310 return *(_RWSTD_REINTERPRET_CAST (_STD::locale*, &(pcat_data->loc)));
311}
312
313
314// Close a catalog and release its handle.
315void __rw_cat_close (int cat)
316{
317 bool cat_closed = false;
318
319 {
320 // guard is local to this scope to avoid reacquiring the mutex
321 // if have to generate an exception message string below.
322 _RWSTD_MT_CLASS_GUARD (__rw_open_cat_data);
323
324 __rw_open_cat_data* const pcat_data =
325 cat < 0 ? 0 : __rw_manage_cat_data (cat, 0);
326
327 // 22.2.7.1.2, p5: `catalog' must be valid
328 if (pcat_data && pcat_data->catd != _RWSTD_BAD_CATD) {
329
330 catclose (pcat_data->catd);
331
332 _STD::locale* const ploc =
333 _RWSTD_REINTERPRET_CAST (_STD::locale*, &pcat_data->loc);
334
335 ploc->~locale ();
336
337 __rw_manage_cat_data (cat, pcat_data);
338
339 cat_closed = true;
340 }
341 else {
342 cat_closed = false;
343 }
344 }
345
347 _RWSTD_FUNC ("__rw_cat_close (int cat)")));
348}
349
350
351} // namespace __rw
#define i
Definition 17.names.cpp:126
#define loc
Definition 17.names.cpp:492
const char *const data[]
#define _RWSTD_REQUIRES(pred, args)
Definition _defs.h:1132
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_FUNC(ignore)
Definition _defs.h:1120
#define _RWSTD_MT_CLASS_GUARD(type)
Definition _defs.h:697
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_ERROR_INVALID_ARGUMENT
Definition _error.h:91
nl_catd catopen(const char *, int)
int catclose(nl_catd)
const char * catgets(nl_catd, int, int, const char *)
#define NL_CAT_LOCALE
Definition catalog.h:47
_RW::__rw_cat * nl_catd
Definition catalog.h:128
#define _RWSTD_BAD_CATD
Definition messages.cpp:49