source: trunk/src/helpers/nls.c@ 165

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

Patches from Martin and Paul, plus regexp support.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1
2/*
3 *@@sourcefile nls.c:
4 * contains a few helpers for National Language Support (NLS),
5 * such as printing strings with the format specified by
6 * the "Country" object.
7 *
8 * Usage: All OS/2 programs.
9 *
10 * Function prefixes (new with V0.81):
11 * -- nls* NLS helpers
12 *
13 * This file is new with 0.9.16, but contains functions
14 * formerly in stringh.c.
15 *
16 * Note: Version numbering in this file relates to XWorkplace version
17 * numbering.
18 *
19 *@@header "helpers\nls.h"
20 *@@added V0.9.16 (2001-10-11) [umoeller]
21 */
22
23/*
24 * Copyright (C) 1997-2002 Ulrich M”ller.
25 * This file is part of the "XWorkplace helpers" source package.
26 * This is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published
28 * by the Free Software Foundation, in version 2 as it comes in the
29 * "COPYING" file of the XWorkplace main distribution.
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 */
35
36#define OS2EMX_PLAIN_CHAR
37 // this is needed for "os2emx.h"; if this is defined,
38 // emx will define PSZ as _signed_ char, otherwise
39 // as unsigned char
40
41#define INCL_DOSNLS
42#define INCL_DOSSEMAPHORES
43#define INCL_DOSEXCEPTIONS
44#define INCL_DOSPROCESS
45#define INCL_DOSERRORS
46#define INCL_WINSHELLDATA
47#include <os2.h>
48
49#include <stdlib.h>
50#include <stdio.h>
51#include <string.h>
52#include <math.h>
53#include <setjmp.h>
54
55#include "setup.h" // code generation and debugging options
56
57#include "helpers\except.h"
58#include "helpers\nls.h"
59#include "helpers\prfh.h"
60#include "helpers\standards.h"
61#include "helpers\stringh.h"
62#include "helpers\tree.h"
63#include "helpers\xstring.h"
64
65#pragma hdrstop
66
67/*
68 *@@category: Helpers\National Language Support
69 * See nls.c.
70 */
71
72/*
73 *@@ nlsQueryCountrySettings:
74 * this returns the most frequently used country settings
75 * all at once into a COUNTRYSETTINGS structure (prfh.h).
76 * This data corresponds to the user settings in the
77 * WPS "Country" object (which writes the data in "PM_National"
78 * in OS2.INI).
79 *
80 * In case a key cannot be found, the following (English)
81 * default values are set:
82 * -- ulDateFormat = 0 (English date format, mm.dd.yyyy);
83 * -- ulTimeFormat = 0 (12-hour clock);
84 * -- cDateSep = '/' (date separator);
85 * -- cTimeSep = ':' (time separator);
86 * -- cDecimal = '.' (decimal separator).
87 * -- cThousands = ',' (thousands separator).
88 *
89 *@@added V0.9.0 [umoeller]
90 *@@changed V0.9.7 (2000-12-02) [umoeller]: added cDecimal
91 */
92
93VOID nlsQueryCountrySettings(PCOUNTRYSETTINGS pcs)
94{
95 if (pcs)
96 {
97 pcs->ulDateFormat = PrfQueryProfileInt(HINI_USER,
98 (PSZ)PMINIAPP_NATIONAL,
99 "iDate",
100 0);
101 pcs->ulTimeFormat = PrfQueryProfileInt(HINI_USER,
102 (PSZ)PMINIAPP_NATIONAL,
103 "iTime",
104 0);
105 pcs->cDateSep = prfhQueryProfileChar(HINI_USER,
106 (PSZ)PMINIAPP_NATIONAL,
107 "sDate",
108 '/');
109 pcs->cTimeSep = prfhQueryProfileChar(HINI_USER,
110 (PSZ)PMINIAPP_NATIONAL,
111 "sTime",
112 ':');
113 pcs->cDecimal = prfhQueryProfileChar(HINI_USER,
114 (PSZ)PMINIAPP_NATIONAL,
115 "sDecimal",
116 '.');
117 pcs->cThousands = prfhQueryProfileChar(HINI_USER,
118 (PSZ)PMINIAPP_NATIONAL,
119 "sThousand",
120 ',');
121 }
122}
123
124/*
125 *@@ nlsThousandsULong:
126 * converts a ULONG into a decimal string, while
127 * inserting thousands separators into it. Specify
128 * the separator character in cThousands.
129 *
130 * Returns pszTarget so you can use it directly
131 * with sprintf and the "%s" flag.
132 *
133 * For cThousands, you should use the data in
134 * OS2.INI ("PM_National" application), which is
135 * always set according to the "Country" object.
136 * You can use nlsQueryCountrySettings to
137 * retrieve this setting.
138 *
139 * Use nlsThousandsDouble for "double" values.
140 */
141
142PSZ nlsThousandsULong(PSZ pszTarget, // out: decimal as string
143 ULONG ul, // in: decimal to convert
144 CHAR cThousands) // in: separator char (e.g. '.')
145{
146 USHORT ust, uss, usc;
147 CHAR szTemp[40];
148 sprintf(szTemp, "%lu", ul);
149
150 ust = 0;
151 usc = strlen(szTemp);
152 for (uss = 0; uss < usc; uss++)
153 {
154 if (uss)
155 if (((usc - uss) % 3) == 0)
156 {
157 pszTarget[ust] = cThousands;
158 ust++;
159 }
160 pszTarget[ust] = szTemp[uss];
161 ust++;
162 }
163 pszTarget[ust] = '\0';
164
165 return (pszTarget);
166}
167
168/*
169 * strhThousandsULong:
170 * wrapper around nlsThousandsULong for those
171 * who used the XFLDR.DLL export.
172 *
173 *added V0.9.16 (2001-10-11) [umoeller]
174 */
175
176PSZ APIENTRY strhThousandsULong(PSZ pszTarget, // out: decimal as string
177 ULONG ul, // in: decimal to convert
178 CHAR cThousands) // in: separator char (e.g. '.')
179{
180 return (nlsThousandsULong(pszTarget, ul, cThousands));
181}
182
183/*
184 *@@ nlsThousandsDouble:
185 * like nlsThousandsULong, but for a "double"
186 * value. Note that after-comma values are truncated.
187 */
188
189PSZ nlsThousandsDouble(PSZ pszTarget,
190 double dbl,
191 CHAR cThousands)
192{
193 USHORT ust, uss, usc;
194 CHAR szTemp[40];
195 sprintf(szTemp, "%.0f", floor(dbl));
196
197 ust = 0;
198 usc = strlen(szTemp);
199 for (uss = 0; uss < usc; uss++)
200 {
201 if (uss)
202 if (((usc - uss) % 3) == 0)
203 {
204 pszTarget[ust] = cThousands;
205 ust++;
206 }
207 pszTarget[ust] = szTemp[uss];
208 ust++;
209 }
210 pszTarget[ust] = '\0';
211
212 return (pszTarget);
213}
214
215/*
216 *@@ nlsVariableDouble:
217 * like nlsThousandsULong, but for a "double" value, and
218 * with a variable number of decimal places depending on the
219 * size of the quantity.
220 *
221 *@@added V0.9.6 (2000-11-12) [pr]
222 */
223
224PSZ nlsVariableDouble(PSZ pszTarget,
225 double dbl,
226 PSZ pszUnits,
227 CHAR cThousands)
228{
229 if (dbl < 100.0)
230 sprintf(pszTarget, "%.2f%s", dbl, pszUnits);
231 else
232 if (dbl < 1000.0)
233 sprintf(pszTarget, "%.1f%s", dbl, pszUnits);
234 else
235 strcat(nlsThousandsDouble(pszTarget, dbl, cThousands),
236 pszUnits);
237
238 return(pszTarget);
239}
240
241/*
242 *@@ nlsFileDate:
243 * converts file date data to a string (to pszBuf).
244 * You can pass any FDATE structure to this function,
245 * which are returned in those FILEFINDBUF* or
246 * FILESTATUS* structs by the Dos* functions.
247 *
248 * ulDateFormat is the PM setting for the date format,
249 * as set in the "Country" object, and can be queried using
250 + PrfQueryProfileInt(HINI_USER, "PM_National", "iDate", 0);
251 *
252 * meaning:
253 * -- 0 mm.dd.yyyy (English)
254 * -- 1 dd.mm.yyyy (e.g. German)
255 * -- 2 yyyy.mm.dd (Japanese, ISO)
256 * -- 3 yyyy.dd.mm
257 *
258 * cDateSep is used as a date separator (e.g. '.').
259 * This can be queried using:
260 + prfhQueryProfileChar(HINI_USER, "PM_National", "sDate", '/');
261 *
262 * Alternatively, you can query all the country settings
263 * at once using nlsQueryCountrySettings (prfh.c).
264 *
265 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
266 */
267
268VOID nlsFileDate(PSZ pszBuf, // out: string returned
269 FDATE *pfDate, // in: date information
270 ULONG ulDateFormat, // in: date format (0-3)
271 CHAR cDateSep) // in: date separator (e.g. '.')
272{
273 DATETIME dt;
274 dt.day = pfDate->day;
275 dt.month = pfDate->month;
276 dt.year = pfDate->year + 1980;
277
278 nlsDateTime(pszBuf,
279 NULL, // no time
280 &dt,
281 ulDateFormat,
282 cDateSep,
283 0, 0); // no time
284}
285
286/*
287 *@@ nlsFileTime:
288 * converts file time data to a string (to pszBuf).
289 * You can pass any FTIME structure to this function,
290 * which are returned in those FILEFINDBUF* or
291 * FILESTATUS* structs by the Dos* functions.
292 *
293 * ulTimeFormat is the PM setting for the time format,
294 * as set in the "Country" object, and can be queried using
295 + PrfQueryProfileInt(HINI_USER, "PM_National", "iTime", 0);
296 * meaning:
297 * -- 0 12-hour clock
298 * -- >0 24-hour clock
299 *
300 * cDateSep is used as a time separator (e.g. ':').
301 * This can be queried using:
302 + prfhQueryProfileChar(HINI_USER, "PM_National", "sTime", ':');
303 *
304 * Alternatively, you can query all the country settings
305 * at once using nlsQueryCountrySettings (prfh.c).
306 *
307 *@@changed V0.8.5 (99-03-15) [umoeller]: fixed 12-hour crash
308 *@@changed V0.9.0 (99-11-07) [umoeller]: now calling nlsDateTime
309 */
310
311VOID nlsFileTime(PSZ pszBuf, // out: string returned
312 FTIME *pfTime, // in: time information
313 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1)
314 CHAR cTimeSep) // in: time separator (e.g. ':')
315{
316 DATETIME dt;
317 dt.hours = pfTime->hours;
318 dt.minutes = pfTime->minutes;
319 dt.seconds = pfTime->twosecs * 2;
320
321 nlsDateTime(NULL, // no date
322 pszBuf,
323 &dt,
324 0, 0, // no date
325 ulTimeFormat,
326 cTimeSep);
327}
328
329/*
330 *@@ nlsDateTime:
331 * converts Control Program DATETIME info
332 * into two strings. See nlsFileDate and nlsFileTime
333 * for more detailed parameter descriptions.
334 *
335 *@@added V0.9.0 (99-11-07) [umoeller]
336 *@@changed V0.9.16 (2001-12-05) [pr]: fixed AM/PM hour bug
337 *@@changed V0.9.18 (2002-02-13) [umoeller]: fixed AM/PM hour bug fix
338 */
339
340VOID nlsDateTime(PSZ pszDate, // out: date string returned (can be NULL)
341 PSZ pszTime, // out: time string returned (can be NULL)
342 DATETIME *pDateTime, // in: date/time information
343 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
344 CHAR cDateSep, // in: date separator (e.g. '.')
345 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
346 CHAR cTimeSep) // in: time separator (e.g. ':')
347{
348 if (pszDate)
349 {
350 switch (ulDateFormat)
351 {
352 case 0: // mm.dd.yyyy (English)
353 sprintf(pszDate, "%02d%c%02d%c%04d",
354 pDateTime->month,
355 cDateSep,
356 pDateTime->day,
357 cDateSep,
358 pDateTime->year);
359 break;
360
361 case 1: // dd.mm.yyyy (e.g. German)
362 sprintf(pszDate, "%02d%c%02d%c%04d",
363 pDateTime->day,
364 cDateSep,
365 pDateTime->month,
366 cDateSep,
367 pDateTime->year);
368 break;
369
370 case 2: // yyyy.mm.dd (Japanese)
371 sprintf(pszDate, "%04d%c%02d%c%02d",
372 pDateTime->year,
373 cDateSep,
374 pDateTime->month,
375 cDateSep,
376 pDateTime->day);
377 break;
378
379 default: // yyyy.dd.mm
380 sprintf(pszDate, "%04d%c%02d%c%02d",
381 pDateTime->year,
382 cDateSep,
383 pDateTime->day,
384 cDateSep,
385 pDateTime->month);
386 break;
387 }
388 }
389
390 if (pszTime)
391 {
392 if (ulTimeFormat == 0)
393 {
394 // for 12-hour clock, we need additional INI data
395 CHAR szAMPM[10] = "err";
396
397 if (pDateTime->hours >= 12) // V0.9.16 (2001-12-05) [pr] if (pDateTime->hours > 12)
398 {
399 // yeah cool Paul, now we get 00:20 PM if it's 20 past noon
400 // V0.9.18 (2002-02-13) [umoeller]
401 ULONG ulHours;
402 if (!(ulHours = pDateTime->hours % 12))
403 ulHours = 12;
404
405 // >= 12h: PM.
406 PrfQueryProfileString(HINI_USER,
407 "PM_National",
408 "s2359", // key
409 "PM", // default
410 szAMPM, sizeof(szAMPM)-1);
411 sprintf(pszTime, "%02d%c%02d%c%02d %s",
412 // leave 12 == 12 (not 0)
413 ulHours,
414 cTimeSep,
415 pDateTime->minutes,
416 cTimeSep,
417 pDateTime->seconds,
418 szAMPM);
419 }
420 else
421 {
422 // < 12h: AM
423 PrfQueryProfileString(HINI_USER,
424 "PM_National",
425 "s1159", // key
426 "AM", // default
427 szAMPM, sizeof(szAMPM)-1);
428 sprintf(pszTime, "%02d%c%02d%c%02d %s",
429 pDateTime->hours,
430 cTimeSep,
431 pDateTime->minutes,
432 cTimeSep,
433 pDateTime->seconds,
434 szAMPM);
435 }
436 }
437 else
438 // 24-hour clock
439 sprintf(pszTime, "%02d%c%02d%c%02d",
440 pDateTime->hours,
441 cTimeSep,
442 pDateTime->minutes,
443 cTimeSep,
444 pDateTime->seconds);
445 }
446}
447
448/*
449 * strhDateTime:
450 * wrapper around nlsDateTime for those who used
451 * the XFLDR.DLL export.
452 */
453
454VOID APIENTRY strhDateTime(PSZ pszDate, // out: date string returned (can be NULL)
455 PSZ pszTime, // out: time string returned (can be NULL)
456 DATETIME *pDateTime, // in: date/time information
457 ULONG ulDateFormat, // in: date format (0-3); see nlsFileDate
458 CHAR cDateSep, // in: date separator (e.g. '.')
459 ULONG ulTimeFormat, // in: 24-hour time format (0 or 1); see nlsFileTime
460 CHAR cTimeSep) // in: time separator (e.g. ':')
461{
462 nlsDateTime(pszDate,
463 pszTime,
464 pDateTime,
465 ulDateFormat,
466 cDateSep,
467 ulTimeFormat,
468 cTimeSep);
469}
470
471
472/*
473 *@@ nlsUpper:
474 * quick hack for upper-casing a string.
475 *
476 * This uses DosMapCase with the default system country
477 * code and the process's codepage. WARNING: DosMapCase
478 * is a 16-bit API and therefore quite slow. Use this
479 * with care.
480 *
481 *@@added V0.9.16 (2001-10-25) [umoeller]
482 */
483
484APIRET nlsUpper(PSZ psz, // in/out: string
485 ULONG ulLength) // in: string length; if 0, we run strlen(psz)
486{
487 COUNTRYCODE cc;
488
489 if (psz)
490 {
491 if (!ulLength)
492 ulLength = strlen(psz);
493
494 if (ulLength)
495 {
496 cc.country = 0; // use system country code
497 cc.codepage = 0; // use process default codepage
498 return (DosMapCase(ulLength,
499 &cc,
500 psz));
501 }
502 }
503
504 return (ERROR_INVALID_PARAMETER);
505}
506
507/* ******************************************************************
508 *
509 * NLS strings
510 *
511 ********************************************************************/
512
513static HAB G_hab = NULLHANDLE;
514static HMODULE G_hmod = NULLHANDLE;
515static PCSTRINGENTITY G_paEntities = NULL;
516static ULONG G_cEntities = 0;
517
518/*
519 *@@ ReplaceEntities:
520 *
521 *@@added V0.9.16 (2001-09-29) [umoeller]
522 */
523
524static ULONG ReplaceEntities(PXSTRING pstr)
525{
526 ULONG ul,
527 rc = 0;
528
529 for (ul = 0;
530 ul < G_cEntities;
531 ul++)
532 {
533 ULONG ulOfs = 0;
534 PCSTRINGENTITY pThis = &G_paEntities[ul];
535 while (xstrFindReplaceC(pstr,
536 &ulOfs,
537 pThis->pcszEntity,
538 *(pThis->ppcszString)))
539 rc++;
540 }
541
542 return (rc);
543}
544
545/*
546 *@@ LoadString:
547 *
548 *@@added V0.9.18 (2002-03-08) [umoeller]
549 */
550
551static void LoadString(ULONG ulID,
552 PSZ *ppsz,
553 PULONG pulLength) // out: length of new string (ptr can be NULL)
554{
555 CHAR szBuf[500];
556 XSTRING str;
557
558 if (*ppsz)
559 free(*ppsz);
560
561 if (!WinLoadString(G_hab,
562 G_hmod,
563 ulID,
564 sizeof(szBuf),
565 szBuf))
566 // loading failed:
567 sprintf(szBuf,
568 "LoadString error: string resource %d not found in module 0x%lX",
569 ulID,
570 G_hmod);
571
572 xstrInitCopy(&str, szBuf, 0);
573 ReplaceEntities(&str);
574 *ppsz = str.psz;
575 if (pulLength)
576 *pulLength = str.ulLength;
577 // do not free string
578}
579
580static HMTX G_hmtxStringsCache = NULLHANDLE;
581static TREE *G_StringsCache;
582static LONG G_cStringsInCache = 0;
583
584/*
585 *@@ LockStrings:
586 *
587 *@@added V0.9.9 (2001-04-04) [umoeller]
588 */
589
590static BOOL LockStrings(VOID)
591{
592 BOOL brc = FALSE;
593
594 if (G_hmtxStringsCache == NULLHANDLE)
595 {
596 brc = !DosCreateMutexSem(NULL,
597 &G_hmtxStringsCache,
598 0,
599 TRUE);
600 treeInit(&G_StringsCache,
601 &G_cStringsInCache);
602 }
603 else
604 brc = !DosRequestMutexSem(G_hmtxStringsCache, SEM_INDEFINITE_WAIT);
605
606 return (brc);
607}
608
609/*
610 *@@ UnlockStrings:
611 *
612 *@@added V0.9.9 (2001-04-04) [umoeller]
613 */
614
615static VOID UnlockStrings(VOID)
616{
617 DosReleaseMutexSem(G_hmtxStringsCache);
618}
619
620/*
621 *@@ STRINGTREENODE:
622 * internal string node structure for cmnGetString.
623 *
624 *@@added V0.9.9 (2001-04-04) [umoeller]
625 *@@changed V0.9.16 (2002-01-26) [umoeller]: no longer using malloc() for string
626 */
627
628typedef struct _STRINGTREENODE
629{
630 TREE Tree; // tree node (src\helpers\tree.c)
631 CHAR szLoaded[1]; // string that was loaded;
632 // the struct is dynamic in size now
633 // V0.9.16 (2002-01-26) [umoeller]
634} STRINGTREENODE, *PSTRINGTREENODE;
635
636/*
637 *@@ nlsInitStrings:
638 * initializes the NLS strings cache. Call this
639 * before calling nlsGetString for the first time.
640 *
641 *@@added V0.9.18 (2002-03-08) [umoeller]
642 */
643
644VOID nlsInitStrings(HAB hab, // in: anchor block
645 HMODULE hmod, // in: module handle to load strings from
646 PCSTRINGENTITY paEntities, // in: entities array or NULL
647 ULONG cEntities) // in: array item count of paEntities or 0
648{
649 G_hab = hab;
650 G_hmod = hmod;
651 G_paEntities = paEntities;
652 G_cEntities = cEntities;
653}
654
655/*
656 *@@ nlsGetString:
657 * returns a resource NLS string.
658 *
659 * Before calling this for the first time, initialize
660 * the engine with nlsInitStrings.
661 *
662 * After that, this function implements a fast string
663 * cache for various NLS strings. Compared to the
664 * standard method, this has the following advantages:
665 *
666 * -- Memory is only consumed for strings that are actually
667 * used. The NLSSTRINGS array had become terribly big,
668 * and lots of strings were loaded that were never used.
669 *
670 * -- Program startup should be a bit faster because we don't
671 * have to load a thousand strings at startup.
672 *
673 * -- The memory buffer holding the string is probably close
674 * to the rest of the heap data that the caller allocated,
675 * so this might lead to less memory page fragmentation.
676 *
677 * -- To add a new NLS string, before this mechanism existed,
678 * three files had to be changed (and kept in sync): common.h
679 * to add a field to the NLSSTRINGS structure, dlgids.h to
680 * add the string ID, and xfldrXXX.rc to add the resource.
681 * With the new mechanism, there's no need to change common.h
682 * any more, so the danger of forgetting something is a bit
683 * reduced. Anyway, fewer recompiles are needed (maybe),
684 * and sending in patches to the code is a bit easier.
685 *
686 * On input, specify a string resouce ID that exists
687 * in the hmod that was given to nlsInitStrings.
688 *
689 * The way this works is that the function maintains a
690 * fast cache of string IDs and only loads the string
691 * resources on demand from the given NLS DLL. If a
692 * string ID is queried for the first time, the string
693 * is loaded. Otherwise the cached copy is returned.
694 *
695 * There is a slight overhead to this function compared to
696 * simply getting a static string from an array, because
697 * the cache needs to be searched for the string ID. However,
698 * this uses a binary tree (balanced according to string IDs)
699 * internally, so this is quite fast still.
700 *
701 * This never releases the strings again.
702 *
703 * This never returns NULL. Even if loading the string failed,
704 * a string is returned; in that case, it's a meaningful error
705 * message specifying the ID that failed.
706 *
707 *@@added V0.9.9 (2001-04-04) [umoeller]
708 *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed bad string count which was never set
709 *@@changed V0.9.16 (2002-01-26) [umoeller]: optimized heap locality
710 */
711
712PCSZ nlsGetString(ULONG ulStringID)
713{
714 BOOL fLocked = FALSE;
715 PSZ pszReturn = "Error";
716
717 TRY_LOUD(excpt1)
718 {
719 if (fLocked = LockStrings())
720 {
721 PSTRINGTREENODE pNode;
722
723 if (pNode = (PSTRINGTREENODE)treeFind(G_StringsCache,
724 ulStringID,
725 treeCompareKeys))
726 // already loaded:
727 pszReturn = pNode->szLoaded;
728 else
729 {
730 // not loaded: load now
731 PSZ psz = NULL;
732 ULONG ulLength = 0;
733
734 LoadString(ulStringID,
735 &psz,
736 &ulLength);
737
738 if ( (!psz)
739 || (!(pNode = (PSTRINGTREENODE)malloc( sizeof(STRINGTREENODE)
740 // has one byte for null
741 // terminator already
742 + ulLength)))
743 )
744 pszReturn = "malloc() failed.";
745 else
746 {
747 pNode->Tree.ulKey = ulStringID;
748 memcpy(pNode->szLoaded,
749 psz,
750 ulLength + 1);
751 treeInsert(&G_StringsCache,
752 &G_cStringsInCache, // fixed V0.9.16 (2001-10-19) [umoeller]
753 (TREE*)pNode,
754 treeCompareKeys);
755 pszReturn = pNode->szLoaded;
756 }
757
758 if (psz)
759 free(psz);
760 }
761 }
762 else
763 // we must always return a string, never NULL
764 pszReturn = "Cannot get strings lock.";
765 }
766 CATCH(excpt1) {} END_CATCH();
767
768 if (fLocked)
769 UnlockStrings();
770
771 return (pszReturn);
772}
773
Note: See TracBrowser for help on using the repository browser.