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

Last change on this file since 243 was 243, checked in by umoeller, 23 years ago

New build system, multimedia, other misc fixes.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 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-2002 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 BOOL fLocked = FALSE;
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, this has the following advantages:
292 *
293 * -- Memory is only consumed for strings that are actually
294 * used. The NLSSTRINGS array had become terribly big,
295 * and lots of strings were loaded that were never used.
296 *
297 * -- Program startup should be a bit faster because we don't
298 * have to load a thousand strings at startup.
299 *
300 * -- The memory buffer holding the string is probably close
301 * to the rest of the heap data that the caller allocated,
302 * so this might lead to less memory page fragmentation.
303 *
304 * -- To add a new NLS string, before this mechanism existed,
305 * three files had to be changed (and kept in sync): common.h
306 * to add a field to the NLSSTRINGS structure, dlgids.h to
307 * add the string ID, and xfldrXXX.rc to add the resource.
308 * With the new mechanism, there's no need to change common.h
309 * any more, so the danger of forgetting something is a bit
310 * reduced. Anyway, fewer recompiles are needed (maybe),
311 * and sending in patches to the code is a bit easier.
312 *
313 * On input, specify a string resouce ID that exists
314 * in the hmod that was given to nlsInitStrings.
315 *
316 * The way this works is that the function maintains a
317 * fast cache of string IDs and only loads the string
318 * resources on demand from the given NLS DLL. If a
319 * string ID is queried for the first time, the string
320 * is loaded. Otherwise the cached copy is returned.
321 *
322 * There is a slight overhead to this function compared to
323 * simply getting a static string from an array, because
324 * the cache needs to be searched for the string ID. However,
325 * this uses a binary tree (balanced according to string IDs)
326 * internally, so this is quite fast still.
327 *
328 * This never releases the strings again.
329 *
330 * This never returns NULL. Even if loading the string failed,
331 * a string is returned; in that case, it's a meaningful error
332 * message specifying the ID that failed.
333 *
334 *@@added V0.9.9 (2001-04-04) [umoeller]
335 *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed bad string count which was never set
336 *@@changed V0.9.16 (2002-01-26) [umoeller]: optimized heap locality
337 *@@changed V1.0.1 (2002-12-11) [umoeller]: moved this here from XWorkplace common.c
338 */
339
340PCSZ nlsGetString(ULONG ulStringID)
341{
342 BOOL fLocked = FALSE;
343 PSZ pszReturn = "Error";
344
345 TRY_LOUD(excpt1)
346 {
347 if (fLocked = LockStrings())
348 {
349 PSTRINGTREENODE pNode;
350
351 if (pNode = (PSTRINGTREENODE)treeFind(G_StringsCache,
352 ulStringID,
353 treeCompareKeys))
354 // already loaded:
355 pszReturn = pNode->szLoaded;
356 else
357 {
358 // not loaded: load now
359 PSZ psz = NULL;
360 ULONG ulLength = 0;
361
362 nlsLoadString(ulStringID,
363 &psz,
364 &ulLength);
365
366 if ( (!psz)
367 || (!(pNode = (PSTRINGTREENODE)malloc( sizeof(STRINGTREENODE)
368 // has one byte for null
369 // terminator already
370 + ulLength)))
371 )
372 pszReturn = "malloc() failed.";
373 else
374 {
375 pNode->Tree.ulKey = ulStringID;
376 memcpy(pNode->szLoaded,
377 psz,
378 ulLength + 1);
379 treeInsert(&G_StringsCache,
380 &G_cStringsInCache, // fixed V0.9.16 (2001-10-19) [umoeller]
381 (TREE*)pNode,
382 treeCompareKeys);
383 pszReturn = pNode->szLoaded;
384 }
385
386 if (psz)
387 free(psz);
388 }
389 }
390 else
391 // we must always return a string, never NULL
392 pszReturn = "Cannot get strings lock.";
393 }
394 CATCH(excpt1) {} END_CATCH();
395
396 if (fLocked)
397 UnlockStrings();
398
399 return pszReturn;
400}
401
402
Note: See TracBrowser for help on using the repository browser.