home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / nlscache.c < prev    next >
C/C++ Source or Header  |  2002-06-14  |  11KB  |  342 lines

  1.  
  2. /*
  3.  *@@sourcefile nlscache.c:
  4.  *
  5.  *      Usage: All OS/2 programs.
  6.  *
  7.  *      Function prefixes (new with V0.81):
  8.  *      --  stc*
  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.  
  80. static HAB                 G_hab = NULLHANDLE;
  81. static HMODULE             G_hmod = NULLHANDLE;
  82. static PCSTRINGENTITY      G_paEntities = NULL;
  83. static ULONG               G_cEntities = 0;
  84.  
  85. /*
  86.  *@@ ReplaceEntities:
  87.  *
  88.  *@@added V0.9.16 (2001-09-29) [umoeller]
  89.  */
  90.  
  91. static ULONG ReplaceEntities(PXSTRING pstr)
  92. {
  93.     ULONG ul,
  94.           rc = 0;
  95.  
  96.     for (ul = 0;
  97.          ul < G_cEntities;
  98.          ul++)
  99.     {
  100.         ULONG ulOfs = 0;
  101.         PCSTRINGENTITY pThis = &G_paEntities[ul];
  102.         while (xstrFindReplaceC(pstr,
  103.                                 &ulOfs,
  104.                                 pThis->pcszEntity,
  105.                                 *(pThis->ppcszString)))
  106.             rc++;
  107.     }
  108.  
  109.     return (rc);
  110. }
  111.  
  112. /*
  113.  *@@ LoadString:
  114.  *
  115.  *@@added V0.9.18 (2002-03-08) [umoeller]
  116.  */
  117.  
  118. static void LoadString(ULONG ulID,
  119.                        PSZ *ppsz,
  120.                        PULONG pulLength)        // out: length of new string (ptr can be NULL)
  121. {
  122.     CHAR szBuf[500];
  123.     XSTRING str;
  124.  
  125.     if (*ppsz)
  126.         free(*ppsz);
  127.  
  128.     if (!WinLoadString(G_hab,
  129.                        G_hmod,
  130.                        ulID,
  131.                        sizeof(szBuf),
  132.                        szBuf))
  133.         // loading failed:
  134.         sprintf(szBuf,
  135.                 "LoadString error: string resource %d not found in module 0x%lX",
  136.                 ulID,
  137.                 G_hmod);
  138.  
  139.     xstrInitCopy(&str, szBuf, 0);
  140.     ReplaceEntities(&str);
  141.     *ppsz = str.psz;
  142.     if (pulLength)
  143.         *pulLength = str.ulLength;
  144.     // do not free string
  145. }
  146.  
  147. static HMTX        G_hmtxStringsCache = NULLHANDLE;
  148. static TREE        *G_StringsCache;
  149. static LONG        G_cStringsInCache = 0;
  150.  
  151. /*
  152.  *@@ LockStrings:
  153.  *
  154.  *@@added V0.9.9 (2001-04-04) [umoeller]
  155.  */
  156.  
  157. static BOOL LockStrings(VOID)
  158. {
  159.     BOOL brc = FALSE;
  160.  
  161.     if (G_hmtxStringsCache == NULLHANDLE)
  162.     {
  163.         brc = !DosCreateMutexSem(NULL,
  164.                                  &G_hmtxStringsCache,
  165.                                  0,
  166.                                  TRUE);
  167.         treeInit(&G_StringsCache,
  168.                  &G_cStringsInCache);
  169.     }
  170.     else
  171.         brc = !DosRequestMutexSem(G_hmtxStringsCache, SEM_INDEFINITE_WAIT);
  172.  
  173.     return brc;
  174. }
  175.  
  176. /*
  177.  *@@ UnlockStrings:
  178.  *
  179.  *@@added V0.9.9 (2001-04-04) [umoeller]
  180.  */
  181.  
  182. static VOID UnlockStrings(VOID)
  183. {
  184.     DosReleaseMutexSem(G_hmtxStringsCache);
  185. }
  186.  
  187. /*
  188.  *@@ STRINGTREENODE:
  189.  *      internal string node structure for cmnGetString.
  190.  *
  191.  *@@added V0.9.9 (2001-04-04) [umoeller]
  192.  *@@changed V0.9.16 (2002-01-26) [umoeller]: no longer using malloc() for string
  193.  */
  194.  
  195. typedef struct _STRINGTREENODE
  196. {
  197.     TREE        Tree;               // tree node (src\helpers\tree.c)
  198.     CHAR        szLoaded[1];        // string that was loaded;
  199.                                     // the struct is dynamic in size now
  200.                                     // V0.9.16 (2002-01-26) [umoeller]
  201. } STRINGTREENODE, *PSTRINGTREENODE;
  202.  
  203. /*
  204.  *@@ nlsInitStrings:
  205.  *      initializes the NLS strings cache. Call this
  206.  *      before calling nlsGetString for the first time.
  207.  *
  208.  *@@added V0.9.18 (2002-03-08) [umoeller]
  209.  */
  210.  
  211. VOID nlsInitStrings(HAB hab,                    // in: anchor block
  212.                     HMODULE hmod,               // in: module handle to load strings from
  213.                     PCSTRINGENTITY paEntities,  // in: entities array or NULL
  214.                     ULONG cEntities)            // in: array item count of paEntities or 0
  215. {
  216.     G_hab = hab;
  217.     G_hmod = hmod;
  218.     G_paEntities = paEntities;
  219.     G_cEntities = cEntities;
  220. }
  221.  
  222. /*
  223.  *@@ nlsGetString:
  224.  *      returns a resource NLS string.
  225.  *
  226.  *      Before calling this for the first time, initialize
  227.  *      the engine with nlsInitStrings.
  228.  *
  229.  *      After that, this function implements a fast string
  230.  *      cache for various NLS strings. Compared to the
  231.  *      standard method, this has the following advantages:
  232.  *
  233.  *      -- Memory is only consumed for strings that are actually
  234.  *         used. The NLSSTRINGS array had become terribly big,
  235.  *         and lots of strings were loaded that were never used.
  236.  *
  237.  *      -- Program startup should be a bit faster because we don't
  238.  *         have to load a thousand strings at startup.
  239.  *
  240.  *      -- The memory buffer holding the string is probably close
  241.  *         to the rest of the heap data that the caller allocated,
  242.  *         so this might lead to less memory page fragmentation.
  243.  *
  244.  *      -- To add a new NLS string, before this mechanism existed,
  245.  *         three files had to be changed (and kept in sync): common.h
  246.  *         to add a field to the NLSSTRINGS structure, dlgids.h to
  247.  *         add the string ID, and xfldrXXX.rc to add the resource.
  248.  *         With the new mechanism, there's no need to change common.h
  249.  *         any more, so the danger of forgetting something is a bit
  250.  *         reduced. Anyway, fewer recompiles are needed (maybe),
  251.  *         and sending in patches to the code is a bit easier.
  252.  *
  253.  *      On input, specify a string resouce ID that exists
  254.  *      in the hmod that was given to nlsInitStrings.
  255.  *
  256.  *      The way this works is that the function maintains a
  257.  *      fast cache of string IDs and only loads the string
  258.  *      resources on demand from the given NLS DLL. If a
  259.  *      string ID is queried for the first time, the string
  260.  *      is loaded. Otherwise the cached copy is returned.
  261.  *
  262.  *      There is a slight overhead to this function compared to
  263.  *      simply getting a static string from an array, because
  264.  *      the cache needs to be searched for the string ID. However,
  265.  *      this uses a binary tree (balanced according to string IDs)
  266.  *      internally, so this is quite fast still.
  267.  *
  268.  *      This never releases the strings again.
  269.  *
  270.  *      This never returns NULL. Even if loading the string failed,
  271.  *      a string is returned; in that case, it's a meaningful error
  272.  *      message specifying the ID that failed.
  273.  *
  274.  *@@added V0.9.9 (2001-04-04) [umoeller]
  275.  *@@changed V0.9.16 (2001-10-19) [umoeller]: fixed bad string count which was never set
  276.  *@@changed V0.9.16 (2002-01-26) [umoeller]: optimized heap locality
  277.  */
  278.  
  279. PCSZ nlsGetString(ULONG ulStringID)
  280. {
  281.     BOOL    fLocked = FALSE;
  282.     PSZ     pszReturn = "Error";
  283.  
  284.     TRY_LOUD(excpt1)
  285.     {
  286.         if (fLocked = LockStrings())
  287.         {
  288.             PSTRINGTREENODE pNode;
  289.  
  290.             if (pNode = (PSTRINGTREENODE)treeFind(G_StringsCache,
  291.                                                   ulStringID,
  292.                                                   treeCompareKeys))
  293.                 // already loaded:
  294.                 pszReturn = pNode->szLoaded;
  295.             else
  296.             {
  297.                 // not loaded: load now
  298.                 PSZ     psz = NULL;
  299.                 ULONG   ulLength = 0;
  300.  
  301.                 LoadString(ulStringID,
  302.                            &psz,
  303.                            &ulLength);
  304.  
  305.                 if (    (!psz)
  306.                      || (!(pNode = (PSTRINGTREENODE)malloc(   sizeof(STRINGTREENODE)
  307.                                                                // has one byte for null
  308.                                                                // terminator already
  309.                                                             + ulLength)))
  310.                    )
  311.                     pszReturn = "malloc() failed.";
  312.                 else
  313.                 {
  314.                     pNode->Tree.ulKey = ulStringID;
  315.                     memcpy(pNode->szLoaded,
  316.                            psz,
  317.                            ulLength + 1);
  318.                     treeInsert(&G_StringsCache,
  319.                                &G_cStringsInCache,      // fixed V0.9.16 (2001-10-19) [umoeller]
  320.                                (TREE*)pNode,
  321.                                treeCompareKeys);
  322.                     pszReturn = pNode->szLoaded;
  323.                 }
  324.  
  325.                 if (psz)
  326.                     free(psz);
  327.             }
  328.         }
  329.         else
  330.             // we must always return a string, never NULL
  331.             pszReturn = "Cannot get strings lock.";
  332.     }
  333.     CATCH(excpt1) {} END_CATCH();
  334.  
  335.     if (fLocked)
  336.         UnlockStrings();
  337.  
  338.     return (pszReturn);
  339. }
  340.  
  341.  
  342.