source: trunk/src/helpers/nlscache.c@ 319

Last change on this file since 319 was 297, checked in by pr, 20 years ago

Update functions using exception handlers to force non-register variables

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1
2/*
3 *@@sourcefile nlscache.c:
4 *
5 * Usage: All OS/2 programs.
6 *
7 * Function prefixes (new with V0.81):
8 * -- nls*
9 *
10 * This file is new with V0.9.19, but contains functions
11 * formerly in nls.c.
12 *
13 * Note: Version numbering in this file relates to XWorkplace version
14 * numbering.
15 *
16 *@@header "helpers\nlscache.h"
17 *@@added V0.9.19 (2002-06-13) [umoeller]
18 */
19
20/*
21 * Copyright (C) 2001-2005 Ulrich M”ller.
22 * This file is part of the "XWorkplace helpers" source package.
23 * This is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published
25 * by the Free Software Foundation, in version 2 as it comes in the
26 * "COPYING" file of the XWorkplace main distribution.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 */
32
33#define OS2EMX_PLAIN_CHAR
34 // this is needed for "os2emx.h"; if this is defined,
35 // emx will define PSZ as _signed_ char, otherwise
36 // as unsigned char
37
38#define INCL_DOSNLS
39#define INCL_DOSDATETIME
40#define INCL_DOSSEMAPHORES
41#define INCL_DOSEXCEPTIONS
42#define INCL_DOSPROCESS
43#define INCL_DOSERRORS
44#define INCL_WINSHELLDATA
45#include <os2.h>
46
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <math.h>
51#include <setjmp.h>
52
53// XWP's setup.h replaces strchr and the like, and
54// we want the originals in here
55#define DONT_REPLACE_FOR_DBCS
56#include "setup.h" // code generation and debugging options
57
58#include "helpers\except.h"
59#include "helpers\nls.h"
60#include "helpers\nlscache.h"
61#include "helpers\prfh.h"
62#include "helpers\standards.h"
63#include "helpers\stringh.h"
64#include "helpers\tree.h"
65#include "helpers\xstring.h"
66
67#pragma hdrstop
68
69/*
70 *@@category: Helpers\National Language Support\String cache
71 * See nls.c.
72 */
73
74/* ******************************************************************
75 *
76 * NLS string cache
77 *
78 ********************************************************************/
79
80static HAB G_hab = NULLHANDLE;
81static HMODULE G_hmod = NULLHANDLE;
82static PCSTRINGENTITY G_paEntities = NULL;
83static ULONG G_cEntities = 0;
84
85static HMTX G_hmtxStringsCache = NULLHANDLE;
86static TREE *G_StringsCache;
87static LONG G_cStringsInCache = 0;
88
89
90/*
91 *@@ nlsReplaceEntities:
92 *
93 *@@added V0.9.16 (2001-09-29) [umoeller]
94 */
95
96ULONG nlsReplaceEntities(PXSTRING pstr)
97{
98 ULONG ul,
99 rc = 0;
100
101 for (ul = 0;
102 ul < G_cEntities;
103 ul++)
104 {
105 ULONG ulOfs = 0;
106 PCSTRINGENTITY pThis = &G_paEntities[ul];
107 while (xstrFindReplaceC(pstr,
108 &ulOfs,
109 pThis->pcszEntity,
110 *(pThis->ppcszString)))
111 rc++;
112 }
113
114 return rc;
115}
116
117/*
118 *@@ nlsLoadString:
119 *
120 *@@changed V0.9.0 [umoeller]: "string not found" is now re-allocated using strdup (avoids crashes)
121 *@@changed V0.9.0 (99-11-28) [umoeller]: added more meaningful error message
122 *@@changed V0.9.2 (2000-02-26) [umoeller]: made temporary buffer larger
123 *@@changed V0.9.16 (2001-09-29) [umoeller]: added entities support
124 *@@changed V0.9.16 (2002-01-26) [umoeller]: added pulLength param
125 *@@changed V1.0.0 (2002-09-17) [umoeller]: optimized
126 *@@changed V1.0.1 (2002-12-11) [umoeller]: moved this here from XWorkplace common.c
127 */
128
129VOID nlsLoadString(ULONG ulID,
130 PSZ *ppsz,
131 PULONG pulLength) // out: length of new string (ptr can be NULL)
132{
133 CHAR szBuf[500];
134 XSTRING str;
135
136 if (*ppsz)
137 free(*ppsz);
138
139 if (!WinLoadString(G_hab,
140 G_hmod,
141 ulID,
142 sizeof(szBuf),
143 szBuf))
144 // loading failed:
145 sprintf(szBuf,
146 "LoadString error: string resource %d not found in module 0x%lX",
147 ulID,
148 G_hmod);
149
150 xstrInitCopy(&str, szBuf, 0);
151 nlsReplaceEntities(&str);
152 *ppsz = str.psz;
153 if (pulLength)
154 *pulLength = str.ulLength;
155 // do not free string
156}
157
158/*
159 *@@ LockStrings:
160 *
161 *@@added V0.9.9 (2001-04-04) [umoeller]
162 */
163
164STATIC BOOL LockStrings(VOID)
165{
166 BOOL brc = FALSE;
167
168 if (G_hmtxStringsCache == NULLHANDLE)
169 {
170 brc = !DosCreateMutexSem(NULL,
171 &G_hmtxStringsCache,
172 0,
173 TRUE);
174 treeInit(&G_StringsCache,
175 &G_cStringsInCache);
176 }
177 else
178 brc = !DosRequestMutexSem(G_hmtxStringsCache, SEM_INDEFINITE_WAIT);
179
180 return brc;
181}
182
183/*
184 *@@ UnlockStrings:
185 *
186 *@@added V0.9.9 (2001-04-04) [umoeller]
187 */
188
189STATIC VOID UnlockStrings(VOID)
190{
191 DosReleaseMutexSem(G_hmtxStringsCache);
192}
193
194/*
195 *@@ STRINGTREENODE:
196 * internal string node structure for cmnGetString.
197 *
198 *@@added V0.9.9 (2001-04-04) [umoeller]
199 *@@changed V0.9.16 (2002-01-26) [umoeller]: no longer using malloc() for string
200 */
201
202typedef struct _STRINGTREENODE
203{
204 TREE Tree; // tree node (src\helpers\tree.c)
205 CHAR szLoaded[1]; // string that was loaded;
206 // the struct is dynamic in size now
207 // V0.9.16 (2002-01-26) [umoeller]
208} STRINGTREENODE, *PSTRINGTREENODE;
209
210/*
211 *@@ Unload:
212 * removes all loaded strings from memory.
213 *
214 *@@added V0.9.9 (2001-04-04) [umoeller]
215 *@@changed V1.0.1 (2002-12-11) [umoeller]: moved this here from XWorkplace common.c
216 */
217
218STATIC VOID Unload(VOID)
219{
220 // to delete all nodes, build a temporary
221 // array of all string node pointers;
222 // we don't want to rebalance the tree
223 // for each node
224 LONG cNodes = G_cStringsInCache;
225 PSTRINGTREENODE *papNodes
226 = (PSTRINGTREENODE*)treeBuildArray(G_StringsCache,
227 &cNodes);
228 if (papNodes)
229 {
230 // delete all nodes in array
231 ULONG ul;
232 for (ul = 0;
233 ul < cNodes;
234 ul++)
235 {
236 free(papNodes[ul]);
237 }
238
239 free(papNodes);
240 }
241
242 // reset the tree to "empty"
243 treeInit(&G_StringsCache,
244 &G_cStringsInCache);
245}
246
247/*
248 *@@ nlsInitStrings:
249 * initializes the NLS strings cache. Call this
250 * before calling nlsGetString for the first time.
251 *
252 *@@added V0.9.18 (2002-03-08) [umoeller]
253 */
254
255VOID nlsInitStrings(HAB hab, // in: anchor block
256 HMODULE hmod, // in: module handle to load strings from
257 PCSTRINGENTITY paEntities, // in: entities array or NULL
258 ULONG cEntities) // in: array item count of paEntities or 0
259{
260 volatile BOOL fLocked = FALSE; // XWP V1.0.4 (2005-10-09) [pr]
261
262 TRY_LOUD(excpt1)
263 {
264 if (fLocked = LockStrings())
265 {
266 if (G_cStringsInCache)
267 // not first call:
268 Unload();
269
270 G_hab = hab;
271 G_hmod = hmod;
272 G_paEntities = paEntities;
273 G_cEntities = cEntities;
274 }
275 }
276 CATCH(excpt1) {} END_CATCH();
277
278 if (fLocked)
279 UnlockStrings();
280}
281
282/*
283 *@@ nlsGetString:
284 * returns a resource NLS string.
285 *
286 * Before calling this for the first time, initialize
287 * the engine with nlsInitStrings.
288 *
289 * After that, this function implements a fast string
290 * cache for various NLS strings. Compared to the
291 * standard method of preloading all NLS strings at
292 * program startup, this method of on-demand string
293 * loading has the following advantages:
294 *
295 * -- Memory is only consumed for strings that are actually
296 * used.
297 *
298 * -- Program startup should be a bit faster because we don't
299 * have to load a thousand strings at startup.
300 *
301 * -- The memory buffer holding the string is probably close
302 * to the rest of the heap data that the caller allocated,
303 * so this might lead to less memory page fragmentation.
304 * (This is a wild guess though.)
305 *
306 * -- To add a new NLS string, before this mechanism existed,
307 * three files had to be changed (and kept in sync): common.h
308 * to add a field to the NLSSTRINGS structure, dlgids.h to
309 * add the string ID, and xfldrXXX.rc to add the resource.
310 * With the new mechanism, there's no need to change common.h
311 * any more, so the danger of forgetting something is a bit
312 * reduced. Anyway, fewer recompiles are needed (maybe),
313 * and sending in patches to the code is a bit easier.
314 *
315 * On input, specify a string resouce ID that exists
316 * in the hmod that was given to nlsInitStrings.
317 *
318 * The way this works is that the function maintains a
319 * fast cache of string IDs and only loads the string
320 * resources on demand from the given NLS DLL. If a
321 * string ID is queried for the first time, the string
322 * is loaded. Otherwise the cached copy is returned.
323 *
324 * There is a slight overhead to this function compared to
325 * simply getting a static string from an array, because
326 * the cache needs to be searched for the string ID. However,
327 * this uses a binary tree (balanced according to string IDs)
328 * internally, so this is quite fast still.
329 *
330 * This never releases the strings again.
331 *
332 * This never returns NULL. Even if loading the string failed,
333 * a string is returned; in that case, it's a meaningful error
334 * message specifying the ID that failed.
335 *
336 *@@added V0.9.9 (2001-04-04) [umoeller]
337 *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed bad string count which was never set
338 *@@changed V0.9.16 (2002-01-26) [umoeller]: optimized heap locality
339 *@@changed V1.0.1 (2002-12-11) [umoeller]: moved this here from XWorkplace common.c
340 */
341
342PCSZ nlsGetString(ULONG ulStringID)
343{
344 volatile BOOL fLocked = FALSE; // XWP V1.0.4 (2005-10-09) [pr]
345 PSZ pszReturn = "Error";
346
347 TRY_LOUD(excpt1)
348 {
349 if (fLocked = LockStrings())
350 {
351 PSTRINGTREENODE pNode;
352
353 if (pNode = (PSTRINGTREENODE)treeFind(G_StringsCache,
354 ulStringID,
355 treeCompareKeys))
356 // already loaded:
357 pszReturn = pNode->szLoaded;
358 else
359 {
360 // not loaded: load now
361 PSZ psz = NULL;
362 ULONG ulLength = 0;
363
364 nlsLoadString(ulStringID,
365 &psz,
366 &ulLength);
367
368 if ( (!psz)
369 || (!(pNode = (PSTRINGTREENODE)malloc( sizeof(STRINGTREENODE)
370 // has one byte for null
371 // terminator already
372 + ulLength)))
373 )
374 pszReturn = "malloc() failed.";
375 else
376 {
377 pNode->Tree.ulKey = ulStringID;
378 memcpy(pNode->szLoaded,
379 psz,
380 ulLength + 1);
381 treeInsert(&G_StringsCache,
382 &G_cStringsInCache, // fixed V0.9.16 (2001-10-19) [umoeller]
383 (TREE*)pNode,
384 treeCompareKeys);
385 pszReturn = pNode->szLoaded;
386 }
387
388 if (psz)
389 free(psz);
390 }
391 }
392 else
393 // we must always return a string, never NULL
394 pszReturn = "Cannot get strings lock.";
395 }
396 CATCH(excpt1)
397 {
398 pszReturn = "Error";
399 }
400 END_CATCH();
401
402 if (fLocked)
403 UnlockStrings();
404
405 return pszReturn;
406}
407
Note: See TracBrowser for help on using the repository browser.