OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
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