Ignore:
Timestamp:
Jun 14, 2002, 2:20:11 PM (23 years ago)
Author:
umoeller
Message:

Misc updates.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/nls.c

    r167 r174  
    4040
    4141#define INCL_DOSNLS
    42 #define INCL_DOSSEMAPHORES
    43 #define INCL_DOSEXCEPTIONS
    44 #define INCL_DOSPROCESS
     42#define INCL_DOSDATETIME
    4543#define INCL_DOSERRORS
    4644#define INCL_WINSHELLDATA
     
    5149#include <string.h>
    5250#include <math.h>
    53 #include <setjmp.h>
    54 
     51
     52// XWP's setup.h replaces strchr and the like, and
     53// we want the originals in here
     54#define DONT_REPLACE_FOR_DBCS
    5555#include "setup.h"                      // code generation and debugging options
    5656
    57 #include "helpers\except.h"
    5857#include "helpers\nls.h"
    5958#include "helpers\prfh.h"
    6059#include "helpers\standards.h"
    61 #include "helpers\stringh.h"
    62 #include "helpers\tree.h"
    63 #include "helpers\xstring.h"
    6460
    6561#pragma hdrstop
     
    6965 *      See nls.c.
    7066 */
     67
     68/* ******************************************************************
     69 *
     70 *   DBCS support
     71 *
     72 ********************************************************************/
     73
     74#define MAX_LEADBYTE        256
     75
     76#pragma pack(1)
     77
     78typedef struct _DBCSVECTOR
     79{
     80   BYTE bLow;
     81   BYTE bHigh;
     82} DBCSVECTOR;
     83
     84#pragma pack()
     85
     86BOOL        G_afLeadByte[MAX_LEADBYTE] = {0};
     87ULONG       G_fDBCS = -1;       // not queried yet
     88COUNTRYCODE G_cc = { 0, 0 };
     89DBCSVECTOR  G_aDBCSVector[8];
     90
     91/*
     92 *@@ nlsDBCS:
     93 *      returns TRUE if the system is currently using DBCS.
     94 *
     95 *@@added V0.9.19 (2002-06-13) [umoeller]
     96 */
     97
     98BOOL nlsDBCS(VOID)
     99{
     100    int i;
     101
     102    if (G_fDBCS != -1)
     103        // already queried:
     104        return G_fDBCS;
     105
     106    if (DosQueryDBCSEnv(8 * sizeof(DBCSVECTOR),
     107                        &G_cc,
     108                        (PCHAR)G_aDBCSVector))
     109        // not DBCS:
     110        return (G_fDBCS = FALSE);
     111
     112    for (i = 0;
     113         i < 8;
     114         ++i)
     115    {
     116        if (    (G_aDBCSVector[i].bLow)
     117             && (G_aDBCSVector[i].bHigh)
     118           )
     119        {
     120            int n;
     121            for (n = G_aDBCSVector[i].bLow;
     122                 n <= G_aDBCSVector[i].bHigh;
     123                 ++n)
     124                G_afLeadByte[n] = TRUE;
     125            G_fDBCS = TRUE;
     126        }
     127        else
     128            break;
     129    }
     130
     131    return G_fDBCS;
     132}
     133
     134/*
     135 *@@ nlsQueryDBCSChar:
     136 *      returns the type of the DBCS character with
     137 *      the given index. Note that the index is the
     138 *      DBCS character index, not just the array
     139 *      index into the CHAR array.
     140 *
     141 *      Returns:
     142 *
     143 *      --  TYPE_SBCS: ulOfs is single byte.
     144 *
     145 *      --  TYPE_DBCS_1ST: ulOfs is a double-byte lead char.
     146 *
     147 *      --  TYPE_DBCS_2ND: ulOfs is a double-byte trail char.
     148 *
     149 *      Preconditions:
     150 *
     151 *      --  nlsDBCS must have been called to initialize our
     152 *          globals, and must have returned TRUE.
     153 *
     154 *@@added V0.9.19 (2002-06-13) [umoeller]
     155 */
     156
     157ULONG nlsQueryDBCSChar(PCSZ pcszString,
     158                       ULONG ulOfs)
     159
     160{
     161    ULONG ulDBCSType = TYPE_SBCS;
     162    ULONG i;
     163
     164    for (i = 0;
     165         i <= ulOfs;
     166         ++i)
     167    {
     168        switch (ulDBCSType)
     169        {
     170            case TYPE_SBCS:
     171            case TYPE_DBCS_2ND:
     172                ulDBCSType = G_afLeadByte[pcszString[i]];
     173            break;
     174
     175            case TYPE_DBCS_1ST :
     176                ulDBCSType = TYPE_DBCS_2ND;
     177            break;
     178        }
     179    }
     180
     181    return ulDBCSType;
     182}
     183
     184/*
     185 *@@ nlschr:
     186 *      replacement for strchr with DBCS support.
     187 *
     188 *      If the system is not running with DBCS,
     189 *      this calls plain strchr automatically.
     190 *
     191 *@@added V0.9.19 (2002-06-13) [umoeller]
     192 */
     193
     194PSZ nlschr(PCSZ p, char c)
     195{
     196    PCSZ    p2;
     197    ULONG   ulDBCS;
     198
     199    if (!nlsDBCS())
     200        // not DBCS:
     201        return strchr(p, c);
     202
     203    // we're on DBCS:
     204    for (p2 = p;
     205         *p2;
     206         ++p2)
     207    {
     208        if (*p2 == c)
     209        {
     210            // match: return this only if it's SBCS;
     211            // if it's a DBCS lead char, skip it
     212            switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p))
     213            {
     214                case TYPE_SBCS:
     215                    return (PSZ)p2;
     216
     217                case TYPE_DBCS_1ST:
     218                    ++p2;
     219            }
     220        }
     221    }
     222
     223    return NULL;
     224}
     225
     226/*
     227 *@@ nlsrchr:
     228 *      replacement for strrchr with DBCS support.
     229 *
     230 *      If the system is not running with DBCS,
     231 *      this calls plain strrchr automatically.
     232 *
     233 *@@added V0.9.19 (2002-06-13) [umoeller]
     234 */
     235
     236PSZ nlsrchr(PCSZ p, char c)
     237{
     238    PCSZ    p2;
     239    ULONG   ulDBCS,
     240            ulLength;
     241
     242    if (!nlsDBCS())
     243        // not DBCS:
     244        return strrchr(p, c);
     245
     246    // we're on DBCS:
     247    ulLength = strlen(p);
     248    for (p2 = p + ulLength - 1;
     249         p2 >= p;
     250         --p2)
     251    {
     252        if (*p2 == c)
     253        {
     254            // match: return this only if it's SBCS;
     255            // if it's a DBCS trail char, skip it
     256            switch (ulDBCS = nlsQueryDBCSChar(p, p2 - p))
     257            {
     258                case TYPE_SBCS:
     259                    return (PSZ)p2;
     260
     261                case TYPE_DBCS_2ND:
     262                    --p2;
     263            }
     264        }
     265    }
     266
     267    return NULL;
     268}
     269
     270/* ******************************************************************
     271 *
     272 *   Country-dependent formatting
     273 *
     274 ********************************************************************/
    71275
    72276/*
     
    505709}
    506710
    507 /* ******************************************************************
    508  *
    509  *   NLS strings
    510  *
    511  ********************************************************************/
    512 
    513 static HAB                 G_hab = NULLHANDLE;
    514 static HMODULE             G_hmod = NULLHANDLE;
    515 static PCSTRINGENTITY      G_paEntities = NULL;
    516 static ULONG               G_cEntities = 0;
    517 
    518 /*
    519  *@@ ReplaceEntities:
    520  *
    521  *@@added V0.9.16 (2001-09-29) [umoeller]
    522  */
    523 
    524 static 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 
    551 static 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 
    580 static HMTX        G_hmtxStringsCache = NULLHANDLE;
    581 static TREE        *G_StringsCache;
    582 static LONG        G_cStringsInCache = 0;
    583 
    584 /*
    585  *@@ LockStrings:
    586  *
    587  *@@added V0.9.9 (2001-04-04) [umoeller]
    588  */
    589 
    590 static 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 
    615 static 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 
    628 typedef 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 
    644 VOID 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 
    712 PCSZ 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 
     711
Note: See TracChangeset for help on using the changeset viewer.