Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
setlocale.cpp
Go to the documentation of this file.
1
32#define _RWSTD_LIB_SRC
33
34#include <rw/_defs.h>
35
36#if defined (__linux__) && !defined (_XOPEN_SOURCE)
37 // need S_IFDIR on Linux
38# define _XOPEN_SOURCE
39#endif // __linux__ && !_XOPEN_SOURCE
40
41#include <locale.h> // for setlocale()
42#include <stdlib.h> // for getenv()
43#include <string.h> // for memcpy(), strcmp()
44#include <time.h> // for struct tm
45
46#include <rw/_error.h>
47#include <rw/_mutex.h>
48
49#include "podarray.h" // for __rw_charray
50#include "setlocale.h"
51
52#ifndef _MSC_VER
53# include <limits.h> // for PATH_MAX
54# if defined (__INTERIX) && !defined (NAME_MAX)
55# define NAME_MAX 255
56# endif // __INTERIX && !NAME_MAX
57#else // if defined (_MSC_VER)
58# include <windows.h>
59#endif // _MSC_VER
60
61#include <sys/stat.h>
62
63
64#ifndef PATH_MAX
65# ifdef MAX_PATH
66# define PATH_MAX MAX_PATH
67# else // if defined (MAX_PATH)
68# define PATH_MAX 1024
69# endif // MAX_PATH
70#endif // PATH_MAX
71
72
74
75// "setlocale" synchronization (internal, not exported)
76__rw_mutex __rw_setlocale_mutex;
77
78// ctor changes the C library locale, saving the old locale to be
79// restored by the dtor
80__rw_setlocale::__rw_setlocale (const char *locname, int cat, int nothrow)
81 : _C_name (0), _C_guard (1), _C_cat (cat)
82{
83 // acquire global per-process lock
84 __rw_setlocale_mutex._C_acquire ();
85
86 // retrieve previous locale name and check if it is already set
87 const char* const curname = ::setlocale (cat, 0);
88
89 if (curname) {
90
91 // try to optimize away the following potential
92 // memory allocation if the locale is already set
93 if (locname && !nothrow && !::strcmp (locname, curname))
94 return;
95
96 // save the name of the current locale before making the call below
97 // even though it may fail, since a successful call may change the
98 // string pointed to by curname
99 const _RWSTD_SIZE_T size = ::strlen (curname) + 1;
100 _C_name = size <= sizeof _C_namebuf ? _C_namebuf : new char [size];
101
102 ::memcpy (_C_name, curname, size);
103
104 if (::setlocale (cat, locname)) {
105
106 // a NULL name is only used when we want to use the object
107 // as a retriever for the name of the current locale;
108 // no need for a lock then
109 if (!locname) {
110 _C_guard = 0;
111 __rw_setlocale_mutex._C_release ();
112 }
113
114 return;
115 }
116
117 if (_C_name != _C_namebuf)
118 delete[] _C_name;
119
120 _C_name = 0;
121 }
122
123 // bad locales OR bad locale names OR bad locale categories
124 _C_guard = 0;
125 __rw_setlocale_mutex._C_release ();
126
127 // failure in setting the locale
129 _RWSTD_FUNC ("std::setlocale(const char*)"),
130 locname));
131}
132
133
134// dtor restores the C library locale that
135// was in effect when the object was constructed
136__rw_setlocale::~__rw_setlocale ()
137{
138 // if guard is set, constructor changed the locale
139 if (_C_guard) {
140
141 // restore the locale
142 ::setlocale (_C_cat, _C_name);
143
144 // release the lock
145 __rw_setlocale_mutex._C_release ();
146 }
147
148 if (_C_name != _C_namebuf)
149 delete [] _C_name;
150}
151
152
153char* __rw_locale_name (int cat, const char *locname, __rw_chararray &namebuf)
154{
155 static char locale_root [PATH_MAX];
156
157 _RWSTD_ASSERT (0 != locname);
158
159 if (!*locale_root) {
160
161#ifndef _RWSTD_LOCALE_ROOT_ENVVAR
162# define _RWSTD_LOCALE_ROOT_ENVVAR "RWSTD_LOCALE_ROOT"
163#endif
164
165 const char* const envvar = getenv (_RWSTD_LOCALE_ROOT_ENVVAR);
166
167 if (envvar && strlen (envvar) < sizeof locale_root)
168 strcpy (locale_root, envvar);
169 }
170
171 // construct the pathname of the locale database
172 char locpath [PATH_MAX];
173 *locpath = '\0';
174
175 _RWSTD_SIZE_T namelen = strlen (locname);
176
177 _RWSTD_SIZE_T pathlen = 0;
178
179 if (*locale_root) {
180
181 if (namelen + strlen (locale_root) + 1 < sizeof locpath) {
182 strcpy (locpath, locale_root);
183
184 pathlen = strlen (locpath);
185
186 locpath [pathlen++] = _RWSTD_PATH_SEP;
187 locpath [pathlen] = '\0';
188 }
189 }
190
191 if (strlen (locpath) + namelen < sizeof locpath) {
192
193 strcpy (locpath + pathlen, locname);
194
195 // see if the directory containing the locale database exists
196 struct stat sb;
197 if (0 == stat (locpath, &sb) && sb.st_mode & S_IFDIR) {
198
199 namebuf.assign (locname);
200
201 return namebuf.data ();
202 }
203 }
204
205 // if the named locale is not found in the locale directory
206 // try to see if the locale refers to a libc locale
207 const __rw_setlocale tmp (locname, cat, 1 /* nothrow */);
208
209 if (!tmp.name ())
210 return 0;
211
212 // get the libc locale name in case locname is an abbreviation
213 const char* const fullname = setlocale (cat, locname);
214
215 _RWSTD_ASSERT (0 != fullname);
216
217 namebuf.assign (fullname);
218
219 return namebuf.data ();
220}
221
222
223} // namespace __rw
#define sb
Definition 17.names.cpp:542
#define tmp
Definition 17.names.cpp:553
const char * locale_root
const nothrow_t nothrow
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define _RWSTD_REQUIRES(pred, args)
Definition _defs.h:1132
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_FUNC(ignore)
Definition _defs.h:1120
#define _RWSTD_ASSERT(ignore)
Definition _defs.h:1108
#define _RWSTD_ERROR_LOCALE_BAD_NAME
Definition _error.h:105
#define _RWSTD_LOCALE_ROOT_ENVVAR
#define PATH_MAX
Definition setlocale.cpp:68