Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 189)
+++ trunk/src/helpers/dosh.c	(revision 190)
@@ -2854,4 +2854,63 @@
 
 /*
+ *@@ doshReadText:
+ *      reads all the contents of the given XFILE into
+ *      a newly allocated buffer. Handles Ctrl-Z properly.
+ *
+ *      Implementation for doshLoadTextFile, but can
+ *      be called separately now.
+ *
+ *@@added V0.9.20 (2002-07-19) [umoeller]
+ */
+
+APIRET doshReadText(PXFILE pFile,
+                    PSZ* ppszContent,   // out: newly allocated buffer with file's content
+                    PULONG pcbRead)     // out: size of that buffer including null byte (ptr can be NULL)
+{
+    APIRET  arc;
+    PSZ     pszContent;
+
+    if (!(pszContent = (PSZ)malloc(pFile->cbCurrent + 1)))
+        arc = ERROR_NOT_ENOUGH_MEMORY;
+    else
+    {
+        ULONG cbRead = 0;
+        if (!(arc = DosRead(pFile->hf,
+                            pszContent,
+                            pFile->cbCurrent,
+                            &cbRead)))
+        {
+            if (cbRead != pFile->cbCurrent)
+                arc = ERROR_NO_DATA;
+            else
+            {
+                PSZ p;
+                pszContent[cbRead] = '\0';
+
+                // check if we have a ctrl-z (EOF) marker
+                // this is present, for example, in config.sys
+                // after install, and stupid E.EXE writes this
+                // all the time when saving a file
+                // V0.9.18 (2002-03-08) [umoeller]
+                if (p = strchr(pszContent, '\26'))
+                {
+                    *p = '\0';
+                    cbRead = p - pszContent;
+                }
+
+                *ppszContent = pszContent;
+                if (pcbRead)
+                    *pcbRead = cbRead + 1;
+            }
+        }
+
+        if (arc)
+            free(pszContent);
+    }
+
+    return arc;
+}
+
+/*
  *@@ doshLoadTextFile:
  *      reads a text file from disk, allocates memory
@@ -2892,42 +2951,7 @@
                          &pFile)))
     {
-        PSZ pszContent;
-        if (!(pszContent = (PSZ)malloc(cbFile + 1)))
-            arc = ERROR_NOT_ENOUGH_MEMORY;
-        else
-        {
-            ULONG cbRead = 0;
-            if (!(arc = DosRead(pFile->hf,
-                                pszContent,
-                                cbFile,
-                                &cbRead)))
-            {
-                if (cbRead != cbFile)
-                    arc = ERROR_NO_DATA;
-                else
-                {
-                    PSZ p;
-                    pszContent[cbRead] = '\0';
-
-                    // check if we have a ctrl-z (EOF) marker
-                    // this is present, for example, in config.sys
-                    // after install
-                    // V0.9.18 (2002-03-08) [umoeller]
-                    if (p = strchr(pszContent, '\26'))
-                    {
-                        *p = '\0';
-                        cbRead = p - pszContent;
-                    }
-
-                    *ppszContent = pszContent;
-                    if (pcbRead)
-                        *pcbRead = cbRead + 1;
-                }
-            }
-
-            if (arc)
-                free(pszContent);
-        }
-
+        doshReadText(pFile,
+                     ppszContent,
+                     pcbRead);
         doshClose(&pFile);
     }
Index: trunk/src/helpers/gpih.c
===================================================================
--- trunk/src/helpers/gpih.c	(revision 189)
+++ trunk/src/helpers/gpih.c	(revision 190)
@@ -34,4 +34,6 @@
 
 #define INCL_DOSSEMAPHORES
+#define INCL_DOSMODULEMGR
+#define INCL_DOSRESOURCES
 #define INCL_DOSERRORS
 
@@ -140,5 +142,5 @@
     }
 
-    return (FALSE);
+    return FALSE;
 }
 
@@ -191,5 +193,5 @@
     }
 
-    return (DisplayCaps[ulIndex]);
+    return DisplayCaps[ulIndex];
 }
 
@@ -300,5 +302,5 @@
 BOOL gpihSwitchToRGB(HPS hps)
 {
-    return (GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL));
+    return GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
 }
 
@@ -567,5 +569,5 @@
     }
 
-    return (lHits);
+    return lHits;
 }
 
@@ -982,4 +984,5 @@
  *
  *@@added V0.9.1 (2000-02-15) [umoeller]
+ *@@changed V0.9.20 (2002-07-19) [umoeller]: optimized
  */
 
@@ -990,19 +993,17 @@
                                              // (e.g. "Courier")
 {
-    BOOL brc = FALSE;
-
-    if (pszFontNameSize)
+    PCHAR   pcDot;
+    if (    (pszFontNameSize)
+         && (pcDot = strchr(pszFontNameSize, '.'))
+       )
     {
-        PCHAR   pcDot = strchr(pszFontNameSize, '.');
-        if (pcDot)
-        {
-            // _Pmpf(("Found font PP: %s", pszFontFound));
-            sscanf(pszFontNameSize, "%lu", pulSize);
-            *ppszFaceName = pcDot + 1;
-            brc = TRUE;
-        }
+        // _Pmpf(("Found font PP: %s", pszFontFound));
+        // sscanf(pszFontNameSize, "%lu", pulSize);
+        *pulSize = atoi(pszFontNameSize);       // V0.9.20 (2002-07-19) [umoeller]
+        *ppszFaceName = pcDot + 1;
+        return TRUE;
     }
 
-    return brc;
+    return FALSE;
 }
 
@@ -1163,5 +1164,5 @@
     // _Pmpf((__FUNCTION__ ": Returning lcid %d", lcidNext));
 
-    return (lcidNext);
+    return lcidNext;
 }
 
@@ -1190,5 +1191,5 @@
     }
 
-    return (lLCIDReturn);
+    return lLCIDReturn;
 }
 
@@ -1371,6 +1372,6 @@
                   pFontMetrics);
 
-    return (gpihCreateFont(hps,
-                           &FontAttrs));
+    return gpihCreateFont(hps,
+                          &FontAttrs);
 
     // _Pmpf((__FUNCTION__ ": returning lcid %d", lLCIDReturn));
@@ -1451,14 +1452,14 @@
                 *plSize = ulFontSize;
             strcpy(szFaceName, pcDot + 1);
-            return (gpihFindFont(hps,
-                                 ulFontSize,
-                                 FALSE,         // face, not family name
-                                 szFaceName,
-                                 0,
-                                 pFontMetrics));
+            return gpihFindFont(hps,
+                                ulFontSize,
+                                FALSE,         // face, not family name
+                                szFaceName,
+                                0,
+                                pFontMetrics);
         }
     }
 
-    return (0);
+    return 0;
 }
 
@@ -1523,5 +1524,5 @@
     box.cy = (FIXED)(lPointSize / 72 * alDevRes[1]);
 
-    return (GpiSetCharBox(hps, &box));
+    return GpiSetCharBox(hps, &box);
 }
 
@@ -1547,6 +1548,6 @@
                    +fm.lExternalLeading)    // space advised by font designer
                );
-    else
-        return (15);
+
+    return 15;
 }
 
@@ -1640,9 +1641,9 @@
                          ULONG cy)          // in: height of new bitmap
 {
-    return (gpihCreateBitmap2(hpsMem,
-                              cx,
-                              cy,
-                              0,
-                              0));            // current screen bit count
+    return gpihCreateBitmap2(hpsMem,
+                             cx,
+                             cy,
+                             0,
+                             0);            // current screen bit count
 }
 
@@ -1715,5 +1716,5 @@
     }
 
-    return (hbm);
+    return hbm;
 }
 
@@ -1817,5 +1818,369 @@
     } // end if (hbmSource)
 
-    return (hbmReturn);
+    return hbmReturn;
+}
+
+/*
+typedef struct _BITMAPARRAYFILEHEADER {
+    USHORT               usType;     //  Type of structure.
+    ULONG                cbSize;     //  Size of the BITMAPARRAYFILEHEADER structure in bytes.
+    ULONG                offNext;    //  Offset of the next BITMAPARRAYFILEHEADER structure from the start of the file.
+    USHORT               cxDisplay;  //  Device width, in pels.
+    USHORT               cyDisplay;  //  Device height, in pels.
+    BITMAPFILEHEADER     bfh;        //  Bitmap file header structure.
+} BITMAPARRAYFILEHEADER;
+
+typedef struct _BITMAPARRAYFILEHEADER2 {
+    USHORT                usType;     //  Type of structure.
+    ULONG                 cbSize;     //  Size of the BITMAPARRAYFILEHEADER2 structure in bytes.
+    ULONG                 offNext;    //  Offset of the next BITMAPARRAYFILEHEADER2 structure from the start of the file.
+    USHORT                cxDisplay;  //  Device width, in pels.
+    USHORT                cyDisplay;  //  Device height, in pels.
+    BITMAPFILEHEADER2     bfh2;       //  Bitmap file header structure.
+} BITMAPARRAYFILEHEADER2;
+
+These two are binarily the same, except for the file header that is contained.
+*/
+
+/*      OLD FORMAT
+
+typedef struct _BITMAPFILEHEADER {
+    USHORT               usType;    //  Type of resource the file contains.
+    ULONG                cbSize;    //  Size of the BITMAPFILEHEADER structure in bytes.
+    SHORT                xHotspot;  //  Width of hotspot for icons and pointers.
+    SHORT                yHotspot;  //  Height of hotspot for icons and pointers.
+    USHORT               offBits;   //  Offset in bytes.
+    BITMAPINFOHEADER     bmp;       //  Bitmap information header structure.
+
+  typedef struct _BITMAPINFOHEADER {
+    ULONG      cbFix;      //  Length of structure.
+    USHORT     cx;         //  Bitmap width in pels.
+    USHORT     cy;         //  Bitmap height in pels.
+    USHORT     cPlanes;    //  Number of bit planes.
+    USHORT     cBitCount;  //  Number of bits per pel within a plane.
+  } BITMAPINFOHEADER;
+
+} BITMAPFILEHEADER;
+*/
+
+/*      NEW FORMAT
+
+typedef struct _BITMAPFILEHEADER2 {
+    USHORT                usType;    //  Type of resource the file contains.
+    ULONG                 cbSize;    //  Size of the BITMAPFILEHEADER2 structure in bytes.
+    SHORT                 xHotspot;  //  Width of hotspot for icons and pointers.
+    SHORT                 yHotspot;  //  Height of hotspot for icons and pointers.
+    USHORT                offBits;   //  Offset in bytes.
+    BITMAPINFOHEADER2     bmp2;      //  Bitmap information header structure.
+
+    typedef struct _BITMAPINFOHEADER2 {
+      ULONG      cbFix;            //  Length of structure.
+      ULONG      cx;               //  Bitmap width in pels.
+      ULONG      cy;               //  Bitmap height in pels.
+      USHORT     cPlanes;          //  Number of bit planes.
+      USHORT     cBitCount;        //  Number of bits per pel within a plane.
+      ULONG      ulCompression;    //  Compression scheme used to store the bit map.
+      ULONG      cbImage;          //  Length of bitmap storage data, in bytes.
+      ULONG      cxResolution;     //  Horizontal component of the resolution of target device.
+      ULONG      cyResolution;     //  Vertical component of the resolution of target device.
+      ULONG      cclrUsed;         //  Number of color indexes used.
+      ULONG      cclrImportant;    //  Minimum number of color indexes for satisfactory appearance of the bit map.
+      USHORT     usUnits;          //  Units of measure.
+      USHORT     usReserved;       //  Reserved.
+      USHORT     usRecording;      //  Recording algorithm.
+      USHORT     usRendering;      //  Halftoning algorithm.
+      ULONG      cSize1;           //  Size value 1.
+      ULONG      cSize2;           //  Size value 2.
+      ULONG      ulColorEncoding;  //  Color encoding.
+      ULONG      ulIdentifier;     //  Reserved for application use.
+    } BITMAPINFOHEADER2;
+
+    Because of the unfortunate replacement of USHORTs with ULONGs for
+    cx and cy in the info header, the cx, cy, and cBitCount data is
+    NOT the same between old and new formats. Well, IBM, good job.
+    And ICONEDIT _still_ writes the old format, too.
+
+} BITMAPFILEHEADER2;
+
+*/
+
+/*
+ *@@ gpihCreateBitmapFromFile:
+ *      creates a new HBITMAP from the given bitmap data,
+ *      which is assumed to be in a standard OS/2 1.3 or
+ *      2.0 bitmap file format. That is, it should start
+ *      with either a BITMAPFILEHEADER or BITMAPFILEHEADER2
+ *      (if single bitmap) or a BITMAPARRAYFILEHEADER or
+ *      BITMAPARRAYFILEHEADER2 (if bitmap array) and all
+ *      the bitmap bits following. This format is also
+ *      used by bitmap resources.
+ *
+ *      If the file contains only a single bitmap,
+ *      this bitmap is used.
+ *
+ *      If it contains a bitmap array, we use the
+ *      "best bitmap" in the array, which is determined
+ *      from the following criteria (in this order):
+ *
+ *      --  a device-dependent bitmap, if its device
+ *          resolution is not too large and the given
+ *          HPS can display all its colors;
+ *
+ *      --  a device-dependent bitmap, if its device
+ *          resolution is not too large, even if the
+ *          given HPS cannot display all its colors;
+ *
+ *      --  a device-independent bitmap, if the given
+ *          HPS can display all its colors;
+ *
+ *      --  the first device-independent bitmap in
+ *          the file;
+ *
+ *      --  the first bitmap in the file.
+ *
+ *      Support for bitmap arrays was added with V0.9.19.
+ *      I'm not quite sure if the above is the same way
+ *      of selecting the "best bitmap" that GpiLoadBitmap
+ *      would do, but without any documentation, who is
+ *      supposed to know. It appears to me however that
+ *      GpiLoadBitmap always does an _exact_ match of
+ *      device resolutions (in contrast to this function).
+ *      In other words, if you're running at 1152x864
+ *      and the device-dependent bitmap is for 1024x768,
+ *      _this_ function would use it, while GpiLoadBitmap
+ *      might load a device-independent VGA bitmap
+ *      instead. (Looks broken, if you ask me.)
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_INVALID_DATA: we can't understand this format.
+ *
+ *@@added V0.9.20 (2002-07-19) [umoeller]
+ */
+
+APIRET gpihCreateBitmapFromFile(HBITMAP *phbm,        // out: bitmap if NO_ERROR
+                                HPS hps,              // in: HPS for bmp
+                                PBYTE pData)          // in: bitmap data
+{
+    APIRET arc = NO_ERROR;
+
+    PBITMAPFILEHEADER2 pbfh = (PBITMAPFILEHEADER2)pData;
+
+    // check bitmap magic codes
+    switch (pbfh->usType)
+    {
+        case BFT_BMAP:     // "BM"
+            // single bitmap in file (no array):
+            if (!(*phbm = GpiCreateBitmap(hps,
+                                          &pbfh->bmp2,
+                                          CBM_INIT,
+                                          (PBYTE)pbfh + pbfh->offBits,
+                                          (PBITMAPINFO2)&pbfh->bmp2)))
+                arc = ERROR_INVALID_DATA;
+        break;
+
+        case BFT_BITMAPARRAY:   // "BA"
+        {
+            // define a handy union for all the above crap
+            typedef union
+            {
+                BITMAPFILEHEADER    Old;
+                BITMAPFILEHEADER2   New;
+            } BMPUNION, *PBMPUNION;
+
+            PBMPUNION
+                    puFirstDI = NULL,   // first device-independent bitmap
+                    puBestDI = NULL,    // best device-independent bitmap
+                    puFirstDD = NULL,   // first device-dependent bitmap
+                    puBestDD = NULL,    // best device-dependent bitmap
+                    puFirstAny = NULL,  // first bitmap of any type
+                    puUse;
+
+            // get device resolution for this HPS
+            // so we can select the "best bitmap"
+            #define GET_CAPS_FIRST  CAPS_WIDTH
+            #define GET_CAPS_LAST   CAPS_COLOR_BITCOUNT
+            #define GET_NO_CAPS     GET_CAPS_LAST - GET_CAPS_FIRST + 1
+
+            LONG alCaps[GET_NO_CAPS];
+            PBITMAPARRAYFILEHEADER2 pba = (PBITMAPARRAYFILEHEADER2)pData;
+
+            DevQueryCaps(GpiQueryDevice(hps),
+                         GET_CAPS_FIRST,
+                         GET_NO_CAPS,
+                         alCaps);
+
+            #define BITCOUNT    alCaps[CAPS_COLOR_BITCOUNT - GET_CAPS_FIRST]
+            #define WIDTH       alCaps[CAPS_WIDTH - GET_CAPS_FIRST]
+            #define HEIGHT      alCaps[CAPS_HEIGHT - GET_CAPS_FIRST]
+
+            // for-all-bitmaps-in-array loop
+            while (pba)
+            {
+                PBMPUNION puThis = (PBMPUNION)&pba->bfh2;
+
+                LONG cx = 0,
+                     cy,
+                     cBitCount;
+
+                // ignore this if the type isn't "BM"
+                if (puThis->Old.usType == BFT_BMAP)
+                {
+                    // fill the three, but watch out, the offsets are
+                    // different between old and new formats
+                    if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER))
+                    {
+                        // old format:
+                        cx = puThis->Old.bmp.cx;
+                        cy = puThis->Old.bmp.cy;
+                        cBitCount = puThis->Old.bmp.cBitCount;
+                    }
+                    else if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER2))
+                    {
+                        // new format:
+                        cx = puThis->New.bmp2.cx;
+                        cy = puThis->New.bmp2.cy;
+                        cBitCount = puThis->New.bmp2.cBitCount;
+                    }
+                }
+
+                if (cx)
+                {
+                    // remember the first bitmap from all that we see
+                    if (!puFirstAny)
+                        puFirstAny = puThis;
+
+                    // check device resolution... device-independent
+                    // one has cxDisplay and cyDisplay set to 0
+                    if (    (!pba->cxDisplay)
+                         && (!pba->cyDisplay)
+                       )
+                    {
+                        // device-independent:
+
+                        // remember the first device-independent bitmap
+                        if (!puFirstDI)
+                            puFirstDI = puThis;
+
+                        if (cBitCount <= BITCOUNT)
+                            // we can display all the colors:
+                            puBestDI = puThis;
+                    }
+                    else
+                    {
+                        // device-dependent:
+                        // ignore if device resolution is too large
+                        if (    (pba->cxDisplay <= WIDTH)
+                             && (pba->cyDisplay <= HEIGHT)
+                           )
+                        {
+                            // remember first matching device-dependent bitmap
+                            if (!puFirstDD)
+                                puFirstDD = puThis;
+
+                            if (cBitCount <= BITCOUNT)
+                                puBestDD = puThis;
+                        }
+                    }
+                } // end if cx
+
+                // go for next bmp in array
+                if (pba->offNext)
+                    // another one coming up:
+                    // this ofs is from the beginning of the file
+                    pba = (PBITMAPARRAYFILEHEADER2)(pData + pba->offNext);
+                else
+                    // no more bitmaps:
+                    break;
+            } // end while (pba)
+
+            if (    (puUse = puBestDD)
+                 || (puUse = puFirstDD)
+                 || (puUse = puBestDI)
+                 || (puUse = puFirstDI)
+                 || (puUse = puFirstAny)
+               )
+            {
+                PBITMAPINFOHEADER2 pbih2;
+                PBYTE pbInitData;
+
+                if (puUse->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER))
+                {
+                    // old format:
+                    pbih2 = (PBITMAPINFOHEADER2)&puUse->Old.bmp;
+                    pbInitData = (PBYTE)pData + puUse->Old.offBits;
+                }
+                else
+                {
+                    // new format:
+                    pbih2 = &puUse->New.bmp2;
+                    pbInitData = (PBYTE)pData + puUse->New.offBits;
+                }
+
+                if (!(*phbm = GpiCreateBitmap(hps,
+                                              pbih2,
+                                              CBM_INIT,
+                                              pbInitData,
+                                              (PBITMAPINFO2)pbih2)))
+                    arc = ERROR_INVALID_DATA;
+            }
+            else
+                arc = ERROR_INVALID_DATA;
+        }
+        break;
+    }
+
+    return arc;
+}
+
+/*
+ *@@ gpihLoadBitmap:
+ *      creates a new HBITMAP from the given resource.
+ *
+ *      This is a replacement for GpiLoadBitmap which handles
+ *      device-dependent bitmaps in bitmap arrays in a
+ *      non-brain-dead way.
+ *
+ *      Calls gpihCreateBitmapFromFile for handling the resource
+ *      data. See remarks there for how we select a bitmap from
+ *      bitmap arrays, which is _different_ from GpiLoadBitmap.
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR: *phbm has received new HBITMAP,
+ *          to be freed with GpiDeleteBitmap.
+ *
+ *      --  ERROR_INVALID_DATA: resource exists, but we
+ *          can't understand its format.
+ *
+ *      plus the error codes from DosGetResource.
+ *
+ *@@added V0.9.20 (2002-07-19) [umoeller]
+ */
+
+APIRET gpihLoadBitmap(HBITMAP *phbm,        // out: bitmap if NO_ERROR
+                      HPS hps,              // in: HPS for bmp
+                      HMODULE hmodResource, // in: module to load bitmap from
+                      ULONG idBitmap)       // in: resource ID for bitmap
+{
+    APIRET arc;
+
+    PBYTE pbData;
+
+    if (!(arc = DosGetResource(hmodResource,
+                               RT_BITMAP,
+                               idBitmap,
+                               (PVOID*)&pbData)))
+    {
+        arc = gpihCreateBitmapFromFile(phbm,
+                                       hps,
+                                       pbData);
+
+        DosFreeResource(pbData);
+    }
+
+    return arc;
 }
 
@@ -1826,32 +2191,7 @@
  *      yet selected into the HPS.
  *
- *      If the file contains only a single bitmap,
- *      this bitmap is used.
- *
- *      If it contains a bitmap array, we use the
- *      "best bitmap" in the array, which is determined
- *      from the following criteria (in this order):
- *
- *      --  a device-dependent bitmap, if its device
- *          resolution is not too large and the given
- *          HPS can display all its colors;
- *
- *      --  a device-dependent bitmap, if its device
- *          resolution is not too large, even if the
- *          given HPS cannot display all its colors;
- *
- *      --  a device-independent bitmap, if the given
- *          HPS can display all its colors;
- *
- *      --  the first device-independent bitmap in
- *          the file;
- *
- *      --  the first bitmap in the file.
- *
- *      Support for bitmap arrays was added with V0.9.19.
- *      I'm not quite sure if the above is the same way
- *      of selecting the "best bitmap" that GpiLoadBitmap
- *      would do, but without any documentation, who is
- *      supposed to know.
+ *      Calls gpihCreateBitmapFromFile for handling the resource
+ *      data. See remarks there for how we select a bitmap from
+ *      bitmap arrays, which is _different_ from GpiLoadBitmap.
  *
  *      Returns:
@@ -1869,4 +2209,5 @@
  *@@changed V0.9.4 (2000-08-03) [umoeller]: this didn't return NULLHANDLE on errors
  *@@changed V0.9.19 (2002-04-14) [umoeller]: rewritten to support bitmap arrays, prototype changed
+ *@@changed V0.9.20 (2002-07-19) [umoeller]: extracted bitmap selection into gpihCreateBitmapFromFile
  */
 
@@ -1897,253 +2238,9 @@
                                 cbFile,
                                 &cbFile)))
-            {
-                // check bitmap magic codes
-                PBITMAPFILEHEADER2  pbfh = (PBITMAPFILEHEADER2)pData;
-
-                switch (pbfh->usType)
-                {
-                    case BFT_BMAP:     // "BM"
-                        // single bitmap in file (no array):
-                        if (!(*phbm = GpiCreateBitmap(hps,
-                                                      &pbfh->bmp2,
-                                                      CBM_INIT,
-                                                      (PBYTE)pbfh + pbfh->offBits,
-                                                      (PBITMAPINFO2)&pbfh->bmp2)))
-                            arc = ERROR_INVALID_DATA;
-                    break;
-
-                    case BFT_BITMAPARRAY:   // "BA"
-                    {
-
-/*
- typedef struct _BITMAPARRAYFILEHEADER {
-   USHORT               usType;     //  Type of structure.
-   ULONG                cbSize;     //  Size of the BITMAPARRAYFILEHEADER structure in bytes.
-   ULONG                offNext;    //  Offset of the next BITMAPARRAYFILEHEADER structure from the start of the file.
-   USHORT               cxDisplay;  //  Device width, in pels.
-   USHORT               cyDisplay;  //  Device height, in pels.
-   BITMAPFILEHEADER     bfh;        //  Bitmap file header structure.
- } BITMAPARRAYFILEHEADER;
-
- typedef struct _BITMAPARRAYFILEHEADER2 {
-   USHORT                usType;     //  Type of structure.
-   ULONG                 cbSize;     //  Size of the BITMAPARRAYFILEHEADER2 structure in bytes.
-   ULONG                 offNext;    //  Offset of the next BITMAPARRAYFILEHEADER2 structure from the start of the file.
-   USHORT                cxDisplay;  //  Device width, in pels.
-   USHORT                cyDisplay;  //  Device height, in pels.
-   BITMAPFILEHEADER2     bfh2;       //  Bitmap file header structure.
- } BITMAPARRAYFILEHEADER2;
-
-    These two are binarily the same, except for the file header that is contained.
-*/
-
-/*      OLD FORMAT
-
- typedef struct _BITMAPFILEHEADER {
-   USHORT               usType;    //  Type of resource the file contains.
-   ULONG                cbSize;    //  Size of the BITMAPFILEHEADER structure in bytes.
-   SHORT                xHotspot;  //  Width of hotspot for icons and pointers.
-   SHORT                yHotspot;  //  Height of hotspot for icons and pointers.
-   USHORT               offBits;   //  Offset in bytes.
-   BITMAPINFOHEADER     bmp;       //  Bitmap information header structure.
-
-          typedef struct _BITMAPINFOHEADER {
-            ULONG      cbFix;      //  Length of structure.
-            USHORT     cx;         //  Bitmap width in pels.
-            USHORT     cy;         //  Bitmap height in pels.
-            USHORT     cPlanes;    //  Number of bit planes.
-            USHORT     cBitCount;  //  Number of bits per pel within a plane.
-          } BITMAPINFOHEADER;
-
- } BITMAPFILEHEADER;
-*/
-
-/*      NEW FORMAT
-
- typedef struct _BITMAPFILEHEADER2 {
-   USHORT                usType;    //  Type of resource the file contains.
-   ULONG                 cbSize;    //  Size of the BITMAPFILEHEADER2 structure in bytes.
-   SHORT                 xHotspot;  //  Width of hotspot for icons and pointers.
-   SHORT                 yHotspot;  //  Height of hotspot for icons and pointers.
-   USHORT                offBits;   //  Offset in bytes.
-   BITMAPINFOHEADER2     bmp2;      //  Bitmap information header structure.
-
-            typedef struct _BITMAPINFOHEADER2 {
-              ULONG      cbFix;            //  Length of structure.
-              ULONG      cx;               //  Bitmap width in pels.
-              ULONG      cy;               //  Bitmap height in pels.
-              USHORT     cPlanes;          //  Number of bit planes.
-              USHORT     cBitCount;        //  Number of bits per pel within a plane.
-              ULONG      ulCompression;    //  Compression scheme used to store the bit map.
-              ULONG      cbImage;          //  Length of bitmap storage data, in bytes.
-              ULONG      cxResolution;     //  Horizontal component of the resolution of target device.
-              ULONG      cyResolution;     //  Vertical component of the resolution of target device.
-              ULONG      cclrUsed;         //  Number of color indexes used.
-              ULONG      cclrImportant;    //  Minimum number of color indexes for satisfactory appearance of the bit map.
-              USHORT     usUnits;          //  Units of measure.
-              USHORT     usReserved;       //  Reserved.
-              USHORT     usRecording;      //  Recording algorithm.
-              USHORT     usRendering;      //  Halftoning algorithm.
-              ULONG      cSize1;           //  Size value 1.
-              ULONG      cSize2;           //  Size value 2.
-              ULONG      ulColorEncoding;  //  Color encoding.
-              ULONG      ulIdentifier;     //  Reserved for application use.
-            } BITMAPINFOHEADER2;
-
-    Because of the unfortunate replacement of USHORTs with ULONGs for
-    cx and cy in the info header, the cx, cy, and cBitCount data is
-    NOT the same between old and new formats. Well, IBM, good job.
-    And ICONEDIT _still_ writes the old format, unfortunately.
-
- } BITMAPFILEHEADER2;
-
-*/
-                        // define a handy union for all the above bullshit
-                        typedef union
-                        {
-                            BITMAPFILEHEADER    Old;
-                            BITMAPFILEHEADER2   New;
-                        } BMPUNION, *PBMPUNION;
-
-                        PBMPUNION       puFirstDI = NULL,   // first device-independent bitmap
-                                        puBestDI = NULL,    // best device-independent bitmap
-                                        puFirstDD = NULL,   // first device-dependent bitmap
-                                        puBestDD = NULL,    // best device-dependent bitmap
-                                        puFirstAny = NULL,  // first bitmap of any type
-                                        puUse;
-
-                        // get device resolution for this HPS
-                        // so we can select the "best bitmap"
-                        #define GET_CAPS_FIRST  CAPS_WIDTH
-                        #define GET_CAPS_LAST   CAPS_COLOR_BITCOUNT
-                        #define GET_NO_CAPS     GET_CAPS_LAST - GET_CAPS_FIRST + 1
-
-                        LONG alCaps[GET_NO_CAPS];
-                        PBITMAPARRAYFILEHEADER2 pba = (PBITMAPARRAYFILEHEADER2)pData;
-
-                        DevQueryCaps(GpiQueryDevice(hps),
-                                     GET_CAPS_FIRST,
-                                     GET_NO_CAPS,
-                                     alCaps);
-
-                        #define BITCOUNT    alCaps[CAPS_COLOR_BITCOUNT - GET_CAPS_FIRST]
-                        #define WIDTH       alCaps[CAPS_WIDTH - GET_CAPS_FIRST]
-                        #define HEIGHT      alCaps[CAPS_HEIGHT - GET_CAPS_FIRST]
-
-                        // for-all-bitmaps-in-array loop
-                        while (pba)
-                        {
-                            PBMPUNION puThis = (PBMPUNION)&pba->bfh2;
-
-                            LONG cx = 0,
-                                 cy,
-                                 cBitCount;
-
-                            // ignore this if the type isn't "BM"
-                            if (puThis->Old.usType == BFT_BMAP)
-                            {
-                                // fill the three, but watch out, the offsets are
-                                // different between old and new formats
-                                if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER))
-                                {
-                                    // old format:
-                                    cx = puThis->Old.bmp.cx;
-                                    cy = puThis->Old.bmp.cy;
-                                    cBitCount = puThis->Old.bmp.cBitCount;
-                                }
-                                else if (puThis->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER2))
-                                {
-                                    // new format:
-                                    cx = puThis->New.bmp2.cx;
-                                    cy = puThis->New.bmp2.cy;
-                                    cBitCount = puThis->New.bmp2.cBitCount;
-                                }
-                            }
-
-                            if (cx)
-                            {
-                                // store first bitmap of any type
-                                if (!puFirstAny)
-                                    puFirstAny = puThis;
-
-                                // check device resolution... device-independent
-                                // one has cxDisplay and cyDisplay set to 0
-                                if (    (!pba->cxDisplay)
-                                     && (!pba->cyDisplay)
-                                   )
-                                {
-                                    // device-independent:
-
-                                    // store first device-independent bmp
-                                    if (!puFirstDI)
-                                        puFirstDI = puThis;
-
-                                    if (cBitCount <= BITCOUNT)
-                                        // we can display all the colors:
-                                        puBestDI = puThis;
-                                }
-                                else
-                                {
-                                    // device-dependent:
-                                    // ignore if device resolution is too large
-                                    if (    (pba->cxDisplay <= WIDTH)
-                                         && (pba->cyDisplay <= HEIGHT)
-                                       )
-                                    {
-                                        if (!puFirstDD)
-                                            puFirstDD = puThis;
-
-                                        if (cBitCount <= BITCOUNT)
-                                            puBestDD = puThis;
-                                    }
-                                }
-                            } // end if cx
-
-                            // go for next bmp in array
-                            if (pba->offNext)
-                                // another one coming up:
-                                // this ofs is from the beginning of the file
-                                pba = (PBITMAPARRAYFILEHEADER2)(pData + pba->offNext);
-                            else
-                                // no more bitmaps:
-                                break;
-                        } // end while (pba)
-
-                        if (    (puUse = puBestDD)
-                             || (puUse = puFirstDD)
-                             || (puUse = puBestDI)
-                             || (puUse = puFirstDI)
-                             || (puUse = puFirstAny)
-                           )
-                        {
-                            PBITMAPINFOHEADER2 pbih2;
-                            PBYTE pbInitData;
-
-                            if (puUse->Old.bmp.cbFix == sizeof(BITMAPINFOHEADER))
-                            {
-                                // old format:
-                                pbih2 = (PBITMAPINFOHEADER2)&puUse->Old.bmp;
-                                pbInitData = (PBYTE)pData + puUse->Old.offBits;
-                            }
-                            else
-                            {
-                                // new format:
-                                pbih2 = &puUse->New.bmp2;
-                                pbInitData = (PBYTE)pData + puUse->New.offBits;
-                            }
-
-                            if (!(*phbm = GpiCreateBitmap(hps,
-                                                          pbih2,
-                                                          CBM_INIT,
-                                                          pbInitData,
-                                                          (PBITMAPINFO2)pbih2)))
-                                arc = ERROR_INVALID_DATA;
-                        }
-                        else
-                            arc = ERROR_INVALID_DATA;
-                    }
-                    break;
-                }
-            }
+                // extracted all the code into this extra func
+                // V0.9.20 (2002-07-19) [umoeller]
+                arc = gpihCreateBitmapFromFile(phbm,
+                                               hps,
+                                               (PBYTE)pData);
 
             free(pData);
@@ -2154,49 +2251,4 @@
 
     return arc;
-
-    /* if (stat(pszBmpFile, &st) == 0)
-    {
-
-        if ((pData = (PBYTE)malloc(st.st_size)))
-        {
-            // open bmp file
-            if ((BmpFile = fopen(pszBmpFile, "rb")))
-            {
-                // read bmp data
-                fread(pData, 1, st.st_size, BmpFile);
-                fclose(BmpFile);
-
-                // check bitmap magic codes
-                if (pData[0] == 'B' && pData[1] == 'M')
-                {
-                    pbfh = (PBITMAPFILEHEADER2)pData;
-                    hbm = GpiCreateBitmap(hps,
-                                          &pbfh->bmp2,
-                                          CBM_INIT,
-                                          (pData + pbfh->offBits),
-                                          (PBITMAPINFO2)&pbfh->bmp2);
-
-                    if (hbm == NULLHANDLE)
-                    {
-                        if (pulError)
-                        *pulError = -5;
-                    }
-                }
-                else if (pulError)
-                        *pulError = -4;
-
-            }
-            else if (pulError)
-                    *pulError = -3;
-
-            free(pData);
-        }
-        else if (pulError)
-                *pulError = -2;
-    }
-    else if (pulError)
-            *pulError = -1;
-
-    return (hbm);*/
 }
 
@@ -2243,5 +2295,4 @@
                        BOOL fProportional)  // in: preserve proportions when stretching?
 {
-    LONG                lHits = 0;
     BITMAPINFOHEADER2   bih2;
     POINTL              aptl[4];
@@ -2329,14 +2380,12 @@
     }
 
-    lHits = GpiWCBitBlt(hpsTarget,     // target HPS (bmp selected)
-                        hbmSource,
-                        4L,             // must always be 4
-                        &aptl[0],       // points array
-                        ROP_SRCCOPY,
-                        BBO_IGNORE);
+    return GpiWCBitBlt(hpsTarget,     // target HPS (bmp selected)
+                       hbmSource,
+                       4L,             // must always be 4
+                       &aptl[0],       // points array
+                       ROP_SRCCOPY,
+                       BBO_IGNORE);
                                 // ignore eliminated rows or
                                 // columns; useful for color
-
-    return (lHits);
 }
 
@@ -2459,9 +2508,11 @@
  *
  *      To do clipping with WinDrawPointer, one has to
- *      limit the clip rectangle for the current HPS,
- *      which is quite an overhead. This function instead
- *      allows for specifying a clip rectangle directly.
- *      Besides, since it uses GpiWCBitBlt, it should
- *      probably work with all types of device contexts.
+ *      alter the clip rectangle for the current HPS,
+ *      which involves creating regions and is thus quite
+ *      some overhead.
+ *
+ *      Instead, this function  allows for specifying a clip
+ *      rectangle directly. Besides, since it uses GpiWCBitBlt,
+ *      it should probably work with all types of device contexts.
  *
  *      This also replaces gpihIcon2Bitmap, which wasn't quite
@@ -2734,9 +2785,9 @@
                            LONG cy)         // in: bitmap height
 {
-    return (gpihCreateXBitmap2(hab,
-                               cx,
-                               cy,
-                               0,
-                               0));
+    return gpihCreateXBitmap2(hab,
+                              cx,
+                              cy,
+                              0,
+                              0);
 }
 
@@ -2744,5 +2795,5 @@
  *@@ gpihCreateXBitmap:
  *      creates an XBitmap, which is returned in an
- *      _XBITMAP structure.
+ *      XBITMAP structure.
  *
  *      The problem with all the GPI bitmap functions
@@ -2825,5 +2876,5 @@
     }
 
-    return (pbmp);
+    return pbmp;
 }
 
@@ -2849,5 +2900,5 @@
     GpiSetBitmap(pbmp->hpsMem, NULLHANDLE);
 
-    return (hbm);
+    return hbm;
 }
 
@@ -2935,11 +2986,10 @@
         aptl[2].y = prcl->yBottom;
 
-        if (GpiBitBlt(pBmp->hpsMem,
-                      hpsScreen,
-                      sizeof(aptl) / sizeof(POINTL), // Number of points in aptl
-                      aptl,
-                      ROP_SRCCOPY,
-                      BBO_IGNORE)
-                == GPI_ERROR)
+        if (GPI_ERROR == GpiBitBlt(pBmp->hpsMem,
+                                   hpsScreen,
+                                   sizeof(aptl) / sizeof(POINTL), // Number of points in aptl
+                                   aptl,
+                                   ROP_SRCCOPY,
+                                   BBO_IGNORE))
         {
             // error during bitblt:
@@ -2948,5 +2998,5 @@
     }
 
-    return (pBmp);
-}
-
+    return pBmp;
+}
+
Index: trunk/src/helpers/nls.c
===================================================================
--- trunk/src/helpers/nls.c	(revision 189)
+++ trunk/src/helpers/nls.c	(revision 190)
@@ -198,4 +198,6 @@
  *
  *@@added V0.9.19 (2002-06-13) [umoeller]
+ *@@changed V0.9.20 (2002-07-22) [umoeller]: optimized
+ *@@changed V0.9.20 (2002-07-22) [lafaix]: optimized
  */
 
@@ -203,5 +205,5 @@
 {
     PCSZ    p2;
-    ULONG   ulDBCS;
+    ULONG   ulDBCSType = TYPE_SBCS;
 
     if (!nlsDBCS())
@@ -209,4 +211,35 @@
         return strchr(p, c);
 
+    // we're on DBCS:
+
+    // we can't find c if it is a leading byte
+    if (G_afLeadByte[c] != TYPE_SBCS)
+        return NULL;
+
+    for (p2 = p;
+         *p2;
+         ++p2)
+    {
+        // check _previous_ DBCS type and refresh
+        // DBCS type accordingly
+        switch (ulDBCSType)
+        {
+            case TYPE_SBCS:
+            case TYPE_DBCS_2ND:
+                ulDBCSType = G_afLeadByte[*p2];
+                // we can safely do the test here (and skip rechecking
+                // the type) because c can't possibly be a leading byte
+                // V0.9.20 (2002-07-22) [lafaix]
+                if (*p2 == c)
+                    return (PSZ)p2;
+            break;
+
+            case TYPE_DBCS_1ST :
+                ulDBCSType = TYPE_DBCS_2ND;
+            break;
+        }
+    }
+
+    /*  old code V0.9.20 (2002-07-22) [umoeller]
     // we're on DBCS:
     for (p2 = p;
@@ -228,4 +261,5 @@
         }
     }
+    */
 
     return NULL;
@@ -240,11 +274,12 @@
  *
  *@@added V0.9.19 (2002-06-13) [umoeller]
+ *@@changed V0.9.20 (2002-07-22) [lafaix]: optimized
  */
 
 PSZ nlsrchr(PCSZ p, char c)
 {
-    PCSZ    p2;
-    ULONG   ulDBCS,
-            ulLength;
+    PCSZ    p2,
+            pLast = NULL;
+    ULONG   ulDBCSType = TYPE_SBCS;
 
     if (!nlsDBCS())
@@ -253,4 +288,34 @@
 
     // we're on DBCS:
+
+    // we can't find c if it is a leading byte
+    if (G_afLeadByte[c] != TYPE_SBCS)
+        return NULL;
+
+    for (p2 = p;
+         *p2;
+         ++p2)
+    {
+        // check _previous_ DBCS type and refresh
+        // DBCS type accordingly
+        switch (ulDBCSType)
+        {
+            case TYPE_SBCS:
+            case TYPE_DBCS_2ND:
+                ulDBCSType = G_afLeadByte[*p2];
+                if (*p2 == c)
+                    pLast = p2;
+            break;
+
+            case TYPE_DBCS_1ST :
+                ulDBCSType = TYPE_DBCS_2ND;
+            break;
+        }
+    }
+
+    return (PSZ)pLast;
+
+    // old code V0.9.20 (2002-07-22) [lafaix]
+    /*
     ulLength = strlen(p);
     for (p2 = p + ulLength - 1;
@@ -274,4 +339,5 @@
 
     return NULL;
+    */
 }
 
Index: trunk/src/helpers/tmsgfile.c
===================================================================
--- trunk/src/helpers/tmsgfile.c	(revision 189)
+++ trunk/src/helpers/tmsgfile.c	(revision 190)
@@ -105,4 +105,8 @@
 /*
  *@@ MSGENTRY:
+ *      private representation of a message in a text
+ *      message file. Each tree entry in
+ *      TMFMSGFILE.IDsTreeRoot points to one of these
+ *      structures.
  *
  *@@added V0.9.16 (2001-10-08) [umoeller]
@@ -111,8 +115,8 @@
 typedef struct _MSGENTRY
 {
-    TREE    Tree;               // ulKey points to strID.psz
-    XSTRING strID;              // message ID
-    ULONG   ulOfsText;          // offset of start of text (in C-format buffer)
-    ULONG   cbText;             // length of text in msg file
+    TREE        Tree;               // ulKey points to strID.psz
+    XSTRING     strID;              // message ID
+    ULONG       ulOfsText;          // offset of start of message text in file
+    ULONG       cbText;             // length of text in msg file
 } MSGENTRY, *PMSGENTRY;
 
@@ -143,14 +147,18 @@
  *
  *@@added V0.9.18 (2002-03-24) [umoeller]
- */
-
-APIRET LoadAndCompile(PTMFMSGFILE pFile)
+ *@@changed V0.9.20 (2002-07-19) [umoeller]: optimized, no longer holding all msgs im mem
+ */
+
+APIRET LoadAndCompile(PTMFMSGFILE pTmf,     // in: TMF struct to set up
+                      PXFILE pFile)         // in: opened XFILE for msg file
 {
-    APIRET arc;
-
-    PSZ pszContent = NULL;
-    if (!(arc = doshLoadTextFile(pFile->pszFilename,
-                                 &pszContent,
-                                 NULL)))
+    APIRET  arc;
+
+    PSZ     pszContent = NULL;
+    ULONG   cbRead;
+
+    if (!(arc = doshReadText(pFile,
+                             &pszContent,
+                             &cbRead)))    // bytes read including null char
     {
         // file loaded:
@@ -162,21 +170,29 @@
                 ulEndMarkerLength = strlen(G_pcszEndMarker);
 
+        XSTRING strContents;
+
         // initialize TMFMSGFILE struct
-        treeInit(&pFile->IDsTreeRoot, NULL);
-
-        xstrInitSet(&pFile->strContent, pszContent);
+        treeInit(&pTmf->IDsTreeRoot, NULL);
+
+        xstrInit(&strContents,
+                 cbRead);       // including null byte
+        xstrcpy(&strContents,
+                pszContent,
+                cbRead - 1);    // not including null byte
 
         // convert to plain C format
-        xstrConvertLineFormat(&pFile->strContent,
+        /* xstrConvertLineFormat(&pTmf->strContent,
                               CRLF2LF);
+        */
 
         // kick out all the comments
-        while (pStartOfMarker = strstr(pFile->strContent.psz, "\n;"))
+        /*
+        while (pStartOfMarker = strstr(pTmf->strContent.psz, "\n;"))
         {
             // copy the next line over this
             PCSZ pEOL = strhFindEOL(pStartOfMarker + 2, NULL);
-            xstrrpl(&pFile->strContent,
+            xstrrpl(&pTmf->strContent,
                     // ofs of first char to replace: "\n;"
-                    pStartOfMarker - pFile->strContent.psz,
+                    pStartOfMarker - pTmf->strContent.psz,
                     // no. of chars to replace:
                     pEOL - pStartOfMarker,
@@ -186,9 +202,10 @@
                     0);
         }
+        */
 
         // free excessive memory
-        xstrShrink(&pFile->strContent);
-
-        pStartOfFile = pFile->strContent.psz;
+        // xstrShrink(&pTmf->strContent);
+
+        pStartOfFile = strContents.psz;
 
         // go build a tree of all message IDs...
@@ -205,8 +222,8 @@
             // search next start marker
             PCSZ pStartOfNextMarker = strstr(pStartOfMsgID + 1,
-                                             G_pcszStartMarker);
+                                             G_pcszStartMarker);    // "\n<--"
             // and the end-marker
             PCSZ pEndOfMarker = strstr(pStartOfMsgID + 1,
-                                       G_pcszEndMarker);
+                                       G_pcszEndMarker);              // "-->:"
 
             PMSGENTRY pNew;
@@ -236,6 +253,7 @@
             {
                 // length of the ID
-                ULONG ulIDLength = pEndOfMarker - pStartOfMsgID;
-                PCSZ pStartOfText = pEndOfMarker + ulEndMarkerLength;
+                ULONG   ulIDLength = pEndOfMarker - pStartOfMsgID;
+                PCSZ    pStartOfText = pEndOfMarker + ulEndMarkerLength,
+                        pNextComment;
 
                 ZERO(pNew);
@@ -253,39 +271,49 @@
                     pStartOfText++;
 
-                // store start of text
+                // store offset of start of text
                 pNew->ulOfsText = pStartOfText - pStartOfFile;
 
                 // check if there's a comment before the
                 // next item
-                /* if (pNextComment = strstr(pStartOfText, "\n;"))
+                if (pNextComment = strstr(pStartOfText, "\n;"))
                 {
                     if (    (!pStartOfNextMarker)
                          || (pNextComment < pStartOfNextMarker)
                        )
-                        pEndOfText = pNextComment;
-                } */
-
-                if (pStartOfNextMarker)
-                    // other markers left:
-                    pNew->cbText =    // offset of next marker
-                                     (pStartOfNextMarker - pStartOfFile)
-                                   - pNew->ulOfsText;
+                        pNew->cbText =    // offset of comment marker
+                                          (pNextComment - pStartOfFile)
+                                        - pNew->ulOfsText;
+                    else
+                        // we have a next marker AND
+                        // the comment comes after it
+                        pNew->cbText =    // offset of next marker
+                                         (pStartOfNextMarker - pStartOfFile)
+                                       - pNew->ulOfsText;
+                }
                 else
-                    // this was the last message:
-                    pNew->cbText = strlen(pStartOfText);
+                    if (pStartOfNextMarker)
+                        // other markers left:
+                        pNew->cbText =    // offset of next marker
+                                         (pStartOfNextMarker - pStartOfFile)
+                                       - pNew->ulOfsText;
+                    else
+                        // this was the last message:
+                        pNew->cbText = strlen(pStartOfText);
 
                 // remove trailing newlines
                 while (    (pNew->cbText)
-                        && (pStartOfText[pNew->cbText-1] == '\n')
+                        && (    (pStartOfText[pNew->cbText - 1] == '\n')
+                             || (pStartOfText[pNew->cbText - 1] == '\r')
+                           )
                       )
                     (pNew->cbText)--;
 
                 // store this thing
-                if (!treeInsert(&pFile->IDsTreeRoot,
+                if (!treeInsert(&pTmf->IDsTreeRoot,
                                 NULL,
                                 (TREE*)pNew,
                                 treeCompareStrings))
                     // successfully inserted:
-                    (pFile->cIDs)++;
+                    (pTmf->cIDs)++;
             }
 
@@ -293,5 +321,8 @@
             pStartOfMarker = pStartOfNextMarker;
         } // end while (    (pStartOfMarker) ...
-    } // end else if (!(pFile = NEW(TMFMSGFILE)))
+
+        free(pszContent);
+
+    } // end else if (!(pTmf = NEW(TMFMSGFILE)))
 
     return arc;
@@ -318,4 +349,5 @@
  *
  *@@added V0.9.16 (2001-10-08) [umoeller]
+ *@@changed V0.9.20 (2002-07-19) [umoeller]: optimized, no longer holding all msgs im mem
  */
 
@@ -325,34 +357,45 @@
     APIRET arc;
 
-    FILESTATUS3 fs3;
-    if (!(arc = DosQueryPathInfo((PSZ)pcszMessageFile,
-                                 FIL_STANDARD,
-                                 &fs3,
-                                 sizeof(fs3))))
+    ULONG   cbFile;
+    PXFILE  pFile;
+    if (!(arc = doshOpen(pcszMessageFile,
+                         XOPEN_READ_EXISTING,
+                         &cbFile,
+                         &pFile)))
     {
         // create a TMFMSGFILE entry
-        PTMFMSGFILE pFile;
-        if (!(pFile = NEW(TMFMSGFILE)))
+        PTMFMSGFILE pTmf;
+        if (!(pTmf = NEW(TMFMSGFILE)))
             arc = ERROR_NOT_ENOUGH_MEMORY;
         else
         {
-            ZERO(pFile);
-            pFile->pszFilename = strdup(pcszMessageFile);
+            ZERO(pTmf);
+            pTmf->pszFilename = strdup(pcszMessageFile);
 
             // TMFMSGFILE created:
-            if (!(arc = LoadAndCompile(pFile)))
+            if (!(arc = LoadAndCompile(pTmf, pFile)))
             {
                 // set timestamp to that of the file
-                dtCreateFileTimeStamp(pFile->szTimestamp,
-                                      &fs3.fdateLastWrite,
-                                      &fs3.ftimeLastWrite);
-
-                // output
-                *ppMsgFile = pFile;
+                FILESTATUS3 fs3;
+                if (!(arc = DosQueryFileInfo(pFile->hf,
+                                             FIL_STANDARD,
+                                             &fs3,
+                                             sizeof(fs3))))
+                {
+                    dtCreateFileTimeStamp(pTmf->szTimestamp,
+                                          &fs3.fdateLastWrite,
+                                          &fs3.ftimeLastWrite);
+
+                    // output
+                    *ppMsgFile = pTmf;
+                }
             }
-            else
+
+            if (arc)
                 // error:
-                tmfCloseMessageFile(&pFile);
+                tmfCloseMessageFile(&pTmf);
         }
+
+        doshClose(&pFile);
     }
 
@@ -370,14 +413,12 @@
  */
 
-static VOID FreeInternalMem(PTMFMSGFILE pFile)
+static VOID FreeInternalMem(PTMFMSGFILE pTmf)
 {
     LONG   cItems;
     TREE**  papNodes;
 
-    xstrClear(&pFile->strContent);
-
-    if (cItems = pFile->cIDs)
+    if (cItems = pTmf->cIDs)
     {
-        if (papNodes = treeBuildArray(pFile->IDsTreeRoot,
+        if (papNodes = treeBuildArray(pTmf->IDsTreeRoot,
                                       &cItems))
         {
@@ -410,12 +451,12 @@
     if (ppMsgFile && *ppMsgFile)
     {
-        PTMFMSGFILE pFile = *ppMsgFile;
-
-        if (pFile->pszFilename)
-            free(pFile->pszFilename);
-
-        FreeInternalMem(pFile);
-
-        free(pFile);
+        PTMFMSGFILE pTmf = *ppMsgFile;
+
+        if (pTmf->pszFilename)
+            free(pTmf->pszFilename);
+
+        FreeInternalMem(pTmf);
+
+        free(pTmf);
         *ppMsgFile = NULL;
 
@@ -453,4 +494,5 @@
  *@@added V0.9.16 (2001-10-08) [umoeller]
  *@@changed V0.9.18 (2002-03-24) [umoeller]: now recompiling if last write date changed
+ *@@changed V0.9.20 (2002-07-19) [umoeller]: optimized, no longer holding all msgs im mem
  */
 
@@ -463,66 +505,97 @@
     APIRET arc = NO_ERROR;
 
-    if (!pMsgFile)
+    if (    (!pMsgFile)
+         || (!pMsgFile->pszFilename)
+       )
         arc = ERROR_INVALID_PARAMETER;
     else
     {
-        // check if last-write date/time changed compared
-        // to the last time we opened the thing...
-        // V0.9.18 (2002-03-24) [umoeller]
-        FILESTATUS3 fs3;
-        if (!(arc = DosQueryPathInfo(pMsgFile->pszFilename,
-                                     FIL_STANDARD,
-                                     &fs3,
-                                     sizeof(fs3))))
+        // open the file again V0.9.20 (2002-07-19) [umoeller]
+        ULONG   cbFile;
+        PXFILE  pFile;
+        if (!(arc = doshOpen(pMsgFile->pszFilename,
+                             XOPEN_READ_EXISTING,
+                             &cbFile,
+                             &pFile)))
         {
-            CHAR szTemp[30];
-            dtCreateFileTimeStamp(szTemp,
-                                  &fs3.fdateLastWrite,
-                                  &fs3.ftimeLastWrite);
-            if (strcmp(szTemp, pMsgFile->szTimestamp))
+            // check if last-write date/time changed compared
+            // to the last time we opened the thing...
+            // V0.9.18 (2002-03-24) [umoeller]
+            FILESTATUS3 fs3;
+            if (!(arc = DosQueryFileInfo(pFile->hf,
+                                         FIL_STANDARD,
+                                         &fs3,
+                                         sizeof(fs3))))
             {
-                // last write date changed:
-                _Pmpf((__FUNCTION__ ": timestamp changed, recompiling"));
-                FreeInternalMem(pMsgFile);
-                if (!(arc = LoadAndCompile(pMsgFile)))
-                    strcpy(pMsgFile->szTimestamp, szTemp);
+                CHAR szTemp[30];
+                dtCreateFileTimeStamp(szTemp,
+                                      &fs3.fdateLastWrite,
+                                      &fs3.ftimeLastWrite);
+                if (strcmp(szTemp, pMsgFile->szTimestamp))
+                {
+                    // last write date changed:
+                    _Pmpf((__FUNCTION__ ": timestamp changed, recompiling"));
+                    FreeInternalMem(pMsgFile);
+
+                    if (!(arc = LoadAndCompile(pMsgFile, pFile)))
+                        strcpy(pMsgFile->szTimestamp, szTemp);
+                }
             }
-        }
-
-        if (!arc)
-        {
-            // go find the message in the tree
-            PMSGENTRY pEntry;
-            if (pEntry = (PMSGENTRY)treeFind(pMsgFile->IDsTreeRoot,
-                                             (ULONG)pcszMessageName,
-                                             treeCompareStrings))
+
+            if (!arc)
             {
-                // copy the raw string to the output buffer
-                xstrcpy(pstr,
-                        pMsgFile->strContent.psz + pEntry->ulOfsText,
-                        pEntry->cbText);
-
-                // now replace strings from the table
-                if (cTableEntries && pTable)
+                // go find the message in the tree
+                PMSGENTRY pEntry;
+                if (!(pEntry = (PMSGENTRY)treeFind(pMsgFile->IDsTreeRoot,
+                                                   (ULONG)pcszMessageName,
+                                                   treeCompareStrings)))
+                    arc = ERROR_MR_MID_NOT_FOUND;
+                else
                 {
-                    CHAR szFind[10] = "%0";
-                    ULONG ul;
-                    for (ul = 0;
-                         ul < cTableEntries;
-                         ul++)
+                    PSZ     pszMsg;
+                    ULONG   cbRead = pEntry->cbText;
+
+                    if (!(pszMsg = (PSZ)malloc(cbRead + 1)))
+                        arc = ERROR_NOT_ENOUGH_MEMORY;
+                    else if (!(arc = doshReadAt(pFile,
+                                                pEntry->ulOfsText,
+                                                &cbRead,
+                                                pszMsg,
+                                                DRFL_NOCACHE | DRFL_FAILIFLESS)))
                     {
-                        ULONG ulOfs = 0;
-
-                        _ultoa(ul + 1, szFind + 1, 10);
-                        while (xstrFindReplaceC(pstr,
-                                                &ulOfs,
-                                                szFind,
-                                                pTable[ul]))
-                            ;
+                        // null-terminate
+                        pszMsg[cbRead] = '\0';
+                        xstrset2(pstr,
+                                 pszMsg,
+                                 cbRead);
+
+                        // kick out \r\n
+                        xstrConvertLineFormat(pstr,
+                                              CRLF2LF);
+
+                        // now replace strings from the table
+                        if (cTableEntries && pTable)
+                        {
+                            CHAR szFind[10] = "%0";
+                            ULONG ul;
+                            for (ul = 0;
+                                 ul < cTableEntries;
+                                 ul++)
+                            {
+                                ULONG ulOfs = 0;
+
+                                _ultoa(ul + 1, szFind + 1, 10);
+                                while (xstrFindReplaceC(pstr,
+                                                        &ulOfs,
+                                                        szFind,
+                                                        pTable[ul]))
+                                    ;
+                            }
+                        }
                     }
                 }
             }
-            else
-                arc = ERROR_MR_MID_NOT_FOUND;
+
+            doshClose(&pFile);
         }
     }
