OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
locale.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// Borland WinSys Library
3// Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// TLocaleString implementation - localized name support
7/// TRegList implementation - runtime component and object registration list
8/// TRegItem implementation - runtime component and object registration item
9///
10/// \note This code must reside in the same module that the strings are defined
11/// The cache, NativeLangId, HINSTANCE are managed on a per-module basis
12/// TLocaleString::NativeLangId may be user-implemented to symbol langid
13/// TLocaleString::Module may be reset from this to another resource DLL
14//----------------------------------------------------------------------------
15
16#include <owl/pch.h>
17#include <owl/defs.h>
18#include <owl/lclstrng.h>
19//#include <stdio.h>
20
21#if defined(BI_MULTI_THREAD_RTL)
22#include <owl/thread.h>
23#endif
24
25#include <owl/appdict.h>
26#include <owl/applicat.h>
27
28
29namespace owl {
30
31//----------------------------------------------------------------------------
32// Module global default values - except for TLocaleString::NativeLangId
33//
37static const tchar* const null_string = _T("");
38TLocaleString TLocaleString::Null = {null_string};
39
40//----------------------------------------------------------------------------
41// _TLocaleCache definitions, private for implementation
42//
43
44#define AUTOLANG_CACHEDNEUT 0x02 // prefix indicates cache entry with neutral
45#define AUTOLANG_CACHEDLOAD 0x01 // prefix indicates Neutral is not a string
46const TLangId InvalidLangId = 0xFFFF;
47
48struct _TLocaleCache;
50
51//
52// Static object to hold destructable pointer
53//
54/// \cond
57 : public TLocalObject
58#endif
59{
61 {
62 }
63 ~_TLocaleCacheList(); // releases cache entries
64
65 _TLocaleCache* Lookup(const tchar* name); // returns cache entry, 0 if failed
66 void AddLink(_TLocaleCacheBase* next); // Add link
67
68 _TLocaleCacheBase* Next; // linked list of cached translations
69
70#if defined(BI_MULTI_THREAD_RTL)
71// TMRSWSection Lock;
72#endif
73};
74/// \endcond
75
76//
77// Static instance of the colors
78//
79static _TLocaleCacheList& GetLocaleCacheList()
80{
81#if defined(BI_MULTI_THREAD_RTL)
83 return localeCacheList.Get();
84#else
86 return localeCacheList;
87#endif
88};
89
90namespace
91{
92 //
93 // Ensure singleton initialization at start-up (single-threaded, safe).
94 //
95 _TLocaleCacheList& InitLocalCacheList = GetLocaleCacheList();
96}
97
98#if defined(BI_MULTI_THREAD_RTL)
99#define LOCKCASHE //TMRSWSection::TLock Lock(GetLocaleCacheList().Lock);
100#else
101#define LOCKCASHE
102#endif
103
104
105
106//
107// This base struct is used to cache failure to find language resource
108//
109/// \cond
110struct _TLocaleCacheBase {
111 long Hash; // hashed original string, for duplicate elimination
112 const tchar* Neutral; // original string, +1 if resource found and loaded
113 _TLocaleCacheBase* Next;// linked list of cached strings, for search, cleanup
114
115 _TLocaleCacheBase(const tchar* name, long hash);
116};
117
118//
119// Buffer follows this header, sized for maximum string + null term.
120//
121struct _TLocaleCache : public _TLocaleCacheBase {
122 void* operator new(size_t size, int buflen);
123#if defined(BI_COMP_MSC)
124 void operator delete(void* p, int buflen);
125#endif
126 _TLocaleCache(const tchar* name, long hash, HRSRC rscHdl, HGLOBAL resData);
127 ~_TLocaleCache() {}
128 const tchar* Translate(TLangId lang); // (re)translate string
129
130 TLangId ActLangId; // actual language ID of cached string
131 TLangId ReqLangId; // requested language ID of cached string
132 HRSRC ResHdl; // handle returned from ::FindResource()
133 tchar Buf[1]; // first character is string type
134};
135/// \endcond
136
137
138//----------------------------------------------------------------------------
139// _TLocaleCache implementation
140//
141
142_TLocaleCacheBase::_TLocaleCacheBase(const tchar* name, long hash)
143:
144 Hash(hash),
145 Neutral(name),
146 Next(nullptr)
147{
148 GetLocaleCacheList().AddLink(this);
149}
150
151void* _TLocaleCache::operator new(size_t size, int buflen)
152{
153 return ::operator new(size+buflen);
154}
155#if defined(BI_COMP_MSC)
156void _TLocaleCache::operator delete(void* p, int)
157{
158 ::operator delete(p);
159}
160#endif
161
162_TLocaleCache::_TLocaleCache(const tchar* name, long hash,
164:
167{
168 ReqLangId = ActLangId = InvalidLangId; // indicate initializing state
169 *(HGLOBAL*)(Buf+1) = resData; // store resource pointer temp in buffer
170}
171//
172//
173//
174_TLocaleCache* _TLocaleCacheList::Lookup(const tchar* name)
175{
177 const tchar* neut = name + 1; // skip over prefix flag tchar
178 long hash = 0;
179 const tchar* pc = name;
180 while (*pc)
181 hash = hash*2 ^ *pc++;
182 for (_TLocaleCacheBase* entry = Next; entry; entry = entry->Next) {
183 if (hash == entry->Hash) {
184 const tchar* pc = entry->Neutral;
185 if (*pc != *neut) // Neutral points to prefix if lookup failed
186 pc++;
187 if (TLocaleString::CompareLang(pc,neut,TLocaleString::NativeLangId) != 0)
188 return pc == entry->Neutral ? (_TLocaleCache*)entry : nullptr;
189 }
190 }
191 pc = name;
192 if (*name != AUTOLANG_RCID)
193 pc++; // '#' part of Id
194 HRSRC resHdl = ::FindResource(TLocaleString::Module ? TLocaleString::Module :
195 (HINSTANCE)*OWLGetAppDictionary().GetApplication(0),
197 if (!resHdl) {
198 new _TLocaleCacheBase(name, hash); // add cache entry for failed lookup
199 return nullptr;
200 }
201 HGLOBAL resData = ::LoadResource(TLocaleString::Module ? TLocaleString::Module :
202 (HINSTANCE)*OWLGetAppDictionary().GetApplication(0),
203 resHdl);
204 if (!resData) {
205 return nullptr; // should throw exception on failure?!!
206 }
208 int maxLen = sizeof(HGLOBAL); // scan for longest string, including null
209 _TUCHAR c = *pr; // check first byte of langid or neutral text
210 if (c == 0) { // check for empty resource string
212 new _TLocaleCacheBase(name, hash); // add failed cache entry if null or err
213 return nullptr;
214 }
215 if (c >= _T(' ')) // check for unprefixed neutral string first
216 pr--; // cancel ++ in for loop initialization
217 else
218 pr++; // start to skip over 2-byte language id
219 do { // loop to check for maximum string length
220 _TUCHAR * p = ++pr; // skip over id to start of translation
221 while ((c=*pr++) >= _T(' ')) ; // skip over translation string
222 if (static_cast<int>(pr-p) > maxLen) // update maximum, including terminator
223 maxLen = static_cast<int>(pr-p);
224 } while(c);
228 return cache;
229}
230//
231const tchar*
232_TLocaleCache::Translate(TLangId reqLang)
233{
235 if (ReqLangId == InvalidLangId) { // if first time called after construction
236 resData = *(HGLOBAL*)(Buf+1);
238 }
239 else {
240 if (Buf[0]==AUTOLANG_CACHEDNEUT && TLocaleString::IsNativeLangId(reqLang))
241 return Neutral;
242 if (reqLang == ActLangId)
243 return Buf+1;
244 if (reqLang == ReqLangId) {
245 if (ActLangId != InvalidLangId)
246 return Buf+1;
247 else if (Buf[0] == AUTOLANG_CACHEDNEUT)
248 return Neutral;
249 else
250 return nullptr;
251 }
252 if ((resData = ::LoadResource(TLocaleString::Module ? TLocaleString::Module :
253 (HINSTANCE)*OWLGetAppDictionary().GetApplication(0),
254 ResHdl)) == nullptr)
255 return Neutral; // should throw exception on failure?!!
256 }
257
259 _TUCHAR * translation = 0;
260 _TUCHAR * pr = resBuf;
263 _TUCHAR c;
264
265 while ((c = *pr) != 0) {
266 if (c > _T(' ')) { // check for initial neutral string, used with CACHEDLOAD
267 actLang = resLang = TLocaleString::NativeLangId;
268 translation = pr; // lowest preference match
269 }
270 else {
271 resLang = TLangId(((c - 1)<<10) | *++pr);
272 pr++;
273 }
274 if (resLang == reqLang) { // exact match
275 translation = pr;
277 break;
278 }
279 if ((tchar)resLang == (tchar)reqLang) { // base language match
280 if ((tchar)actLang != (tchar)reqLang || resLang == (reqLang & 0x00FF)) {
281 translation = pr;
283 }
284 }
285 for ( ; *pr >= _T(' '); ++pr) // skip over translation string till next Id
286 ;
287 }
288 const tchar* retVal;
289 if (translation) {
290 while (*translation < _T(' ')) // skip over multiple language IDs
291 translation += 2;
292 if (actLang != ActLangId) { // if same as in buffer, leave alone
293 tchar* pc;
294 for (pr = translation, pc = Buf + 1; *pr >= _T(' '); )
295 *pc++ = *pr++;
296 *pc = 0;
298 if (reqLang != ActLangId)
300 }
301 retVal = Buf+1;
302 }
303 else if (Buf[0] == AUTOLANG_CACHEDNEUT) {
304 retVal = Neutral;
305 }
306 else {
307 retVal = nullptr;
308 }
310 return retVal;
311}
312//
313_TLocaleCacheList::~_TLocaleCacheList()
314{
316 while (Next) {
317 _TLocaleCacheBase* p = Next;
318 Next = Next->Next;
319 delete p;
320 }
321}
322//
323void _TLocaleCacheList::AddLink(_TLocaleCacheBase* link)
324{
326 link->Next = Next;
327 Next = link;
328}
329
330
331//----------------------------------------------------------------------------
332// TLocaleString implementation, except for static int CompareLang(s1,s2,lang)
333//
334
335/// Translates the string to the given language. Translate follows this order of
336/// preference in order to choose a language for translation:
337/// - 1. Base language and dialect.
338/// - 2. Base language and no dialect.
339/// - 3. Base language and another dialect.
340/// - 4. The native language of the resource itself.
341/// - 5. Returns 0 if unable to translate the string. (This can happen only if an @
342/// or # prefix is used; otherwise, the ! prefix indicates that the string following
343/// is the native language itself.)
344const tchar* TLocaleString::Translate(TLangId reqLang)
345{
346 if (!Private) // check for null string pointer
347 return Private;
348
349 if (reqLang == LangNeutral)
350 reqLang = NativeLangId;
351 else if (reqLang == LangSysDefault)
352 reqLang = SystemDefaultLangId;
353 else if (reqLang == LangUserDefault)
354 reqLang = UserDefaultLangId;
355
357 switch (Private[0])
358 {
359 default: // untranslatable string, no prefix
360 return Private;
361
362 case AUTOLANG_XLAT: // not yet translated
363 if (IsNativeLangId(reqLang))
364 return Private+1; // resource name IS neutral or default name
365 if ((cache = GetLocaleCacheList().Lookup(Private)) == nullptr)
366 return ++Private; // permanently bump pointer to make constant
367 Private = cache->Buf; // point to buffer in cache
368 return cache->Translate(reqLang);
369
370 case AUTOLANG_LOAD: // named resource not accessed yet
371 case AUTOLANG_RCID: // numeric resource not accessed yet
372 if ((cache = GetLocaleCacheList().Lookup(Private)) == nullptr)
373 return (Private = nullptr); // permanently set pointer to null
374 Private = cache->Buf; // point to buffer in cache
375 return cache->Translate(reqLang);
376
377 case AUTOLANG_CACHEDNEUT: // string in cache with neutral pointer
378 case AUTOLANG_CACHEDLOAD: // string in cache with no neutral pointer
379 cache = (_TLocaleCache*)(Private+1) - 1; // backup to point to header
380 return cache->Translate(reqLang);
381 }
382}
383
384TLocaleString::operator const tchar*() const
385{
386 if (Private == nullptr)
387 return nullptr;
388
389 switch (Private[0]) {
390 case AUTOLANG_XLAT: // not yet translated
391 case AUTOLANG_CACHEDNEUT: // translated string in cache
392 case AUTOLANG_CACHEDLOAD: // translated or neutral name in cache
393 return Private+1;
394
395 case AUTOLANG_RCID: // resource not accessed yet
396 case AUTOLANG_LOAD: // resource not accessed yet
397 return nullptr;
398
399 default: // untranslatable string, no prefix
400 return Private;
401 }
402}
403
404/// Using the specified language (lang), Compare compares TLocaleString with another
405/// string. It uses the standard string compare and the language-specific collation
406/// scheme. It returns one of the following values:
407/// - \c \b 0 There is no match between the two strings.
408/// - \c \b 1 This string is greater than the other string.
409/// - \c \b -1 This string is less than the other string.
410int TLocaleString::Compare(const tchar * str, TLangId lang)
411{
412 return CompareLang(this->Translate(lang), str, lang);
413}
414
415/// Returns true if lang equals the native system language.
416int TLocaleString::IsNativeLangId(TLangId lang)
417{
418 return lang == NativeLangId || lang == (NativeLangId & 0x00FF);
419}
420
421
422} // OWL namespace
423
Definition of class TAppDictionary.
Definition of class TApplication.
#define _T(x)
Definition cygwin.h:51
TLocaleString - localized name support.
#define AUTOLANG_LOAD
indicates resource name to load (binary)
Definition lclstrng.h:108
#define AUTOLANG_XLAT
indicates name to be localized (binary)
Definition lclstrng.h:107
#define RT_LOCALIZATION
Definition lclstrng.h:113
#define AUTOLANG_RCID
indicates name specified by numeric ID
Definition lclstrng.h:106
#define AUTOLANG_CACHEDNEUT
Definition locale.cpp:44
#define AUTOLANG_CACHEDLOAD
Definition locale.cpp:45
#define LOCKCASHE
Definition locale.cpp:101
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
owl::uint16 TLangId
Holds a language ID, a predefined number that represents a base language and dialect.
Definition lclstrng.h:26
const TLangId InvalidLangId
Definition locale.cpp:46
char tchar
Definition defs.h:77
const TLangId LangNeutral
Definition lclstrng.h:32
const TLangId LangUserDefault
Definition lclstrng.h:31
TAppDictionary & OWLGetAppDictionary()
Global exported TAppDictionary in Owl.
Definition appdict.cpp:35
const TLangId LangSysDefault
Definition lclstrng.h:30
General definitions used by all ObjectWindows programs.
static TLangId SystemDefaultLangId
The default language identifier.
Definition lclstrng.h:84
static TLangId GetSystemLangId()
platform-dependent implementation
Definition localeco.cpp:17
static TLangId UserDefaultLangId
The user-defined default language identifier.
Definition lclstrng.h:87
static TLangId GetUserLangId()
platform-dependent implementation
Definition localeco.cpp:26
static HINSTANCE Module
The handle of the file containing the resource.
Definition lclstrng.h:93
static TLocaleString Null
reference a null string
Definition lclstrng.h:94