Index: trunk/src/helpers/dosh2.c
===================================================================
--- trunk/src/helpers/dosh2.c	(revision 55)
+++ trunk/src/helpers/dosh2.c	(revision 56)
@@ -64,4 +64,6 @@
 
 #include "helpers\dosh.h"
+#include "helpers\ensure.h"
+#include "helpers\standards.h"
 #include "helpers\stringh.h"
 
@@ -1236,4 +1238,5 @@
  *@@added V0.9.9 (2001-03-11) [lafaix]
  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
  */
 
@@ -1242,10 +1245,9 @@
                                     PULONG pcModules)           // out: array item count
 {
-    APIRET      arc = NO_ERROR;
-
     if (    (pExec)
          && (pExec->ulOS == EXEOS_OS2)
        )
     {
+        ENSURE_BEGIN;
         ULONG       cModules = 0;
         PFSYSMODULE paModules = NULL;
@@ -1255,58 +1257,43 @@
         {
             // 32-bit OS/2 executable:
-            if (cModules = pExec->pLXHeader->ulImportModTblCnt)
+            cModules = pExec->pLXHeader->ulImportModTblCnt;
+
+            if (cModules)
             {
                 ULONG cb = sizeof(FSYSMODULE) * cModules; // V0.9.9 (2001-04-03) [umoeller]
+                ULONG ulDummy;
 
                 paModules = (PFSYSMODULE)malloc(cb);
                 if (!paModules)
-                    arc = ERROR_NOT_ENOUGH_MEMORY; // V0.9.9 (2001-04-03) [umoeller]
-                else
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY); // V0.9.9 (2001-04-03) [umoeller]
+
+                memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pLXHeader->ulImportModTblOfs
+                                            + pExec->pDosExeHeader->ulNewHeaderOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                for (i = 0; i < cModules; i++)
                 {
-                    ULONG ulDummy;
-
-                    memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
-
-                    // V0.9.9 (2001-04-03) [umoeller]:
-                    // Martin, I added error checking to all the below
-                    // Dos* calls. You can't just read around a file
-                    // and assume it will always be valid... especially
-                    // if you fill dynamically allocated memory.
-
-                    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                              pExec->pLXHeader->ulImportModTblOfs
-                                                + pExec->pDosExeHeader->ulNewHeaderOfs,
-                                              FILE_BEGIN,
-                                              &ulDummy)))
-                    {
-                        for (i = 0; i < cModules; i++)
-                        {
-                             BYTE bLen = 0;
-
-                             // reading the length of the module name
-                             if (!(arc = DosRead(pExec->hfExe,
-                                                 &bLen,
-                                                 1,
-                                                 &ulDummy)))
-                             {
-                                 // At most 127 bytes
-                                 bLen &= 0x7F;
-
-                                 // reading the module name
-                                 if (!(arc = DosRead(pExec->hfExe,
-                                                     paModules[i].achModuleName,
-                                                     bLen,
-                                                     &ulDummy)))
-                                    // module names are not null terminated, so we must
-                                    // do it now
-                                    paModules[i].achModuleName[bLen] = 0;
-                            }
-
-                            if (arc)
-                                break; // V0.9.9 (2001-04-03) [umoeller]
-
-                        } // end for
-                    }
-                }
+                    BYTE bLen = 0;
+
+                    // reading the length of the module name
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
+
+                    // At most 127 bytes
+                    bLen &= 0x7F;
+
+                    // reading the module name
+                    ENSURE_SAFE(DosRead(pExec->hfExe,
+                                        paModules[i].achModuleName,
+                                        bLen,
+                                        &ulDummy));
+
+                    // module names are not null terminated, so we must
+                    // do it now
+                    paModules[i].achModuleName[bLen] = 0;
+                } // end for
             }
         } // end LX
@@ -1314,5 +1301,7 @@
         {
             // 16-bit OS/2 executable:
-            if (cModules = pExec->pNEHeader->usModuleTblEntries)
+            cModules = pExec->pNEHeader->usModuleTblEntries;
+
+            if (cModules)
             {
                 ULONG cb = sizeof(FSYSMODULE) * cModules;
@@ -1320,77 +1309,64 @@
                 paModules = (PFSYSMODULE)malloc(cb);
                 if (!paModules)
-                    arc = ERROR_NOT_ENOUGH_MEMORY;  // V0.9.9 (2001-04-03) [umoeller]
-                else
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);  // V0.9.9 (2001-04-03) [umoeller]
+
+                memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
+
+                for (i = 0; i < cModules; i ++)
                 {
-                    memset(paModules, 0, cb);   // V0.9.9 (2001-04-03) [umoeller]
-
-                    for (i = 0; i < cModules; i ++)
-                    {
-                        BYTE bLen;
-                        USHORT usOfs;
-                        ULONG ulDummy;
-
-                        // the module reference table contains offsets
-                        // relative to the import table; we hence read
-                        // the offset in the module reference table, and
-                        // then we read the name in the import table
-
-                        if (    (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pNEHeader->usModRefTblOfs
-                                                         + pExec->pDosExeHeader->ulNewHeaderOfs
-                                                         + sizeof(usOfs) * i,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                             && (!(arc = DosRead(pExec->hfExe,
-                                                 &usOfs,
-                                                 2,
-                                                 &ulDummy)))
-                             && (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pNEHeader->usImportTblOfs
-                                                         + pExec->pDosExeHeader->ulNewHeaderOfs
-                                                         + usOfs,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                             && (!(arc = DosRead(pExec->hfExe,
-                                                 &bLen,
-                                                 1,
-                                                 &ulDummy)))
-                            )
-                        {
-                            bLen &= 0x7F;
-
-                            if (!(arc = DosRead(pExec->hfExe,
-                                                paModules[i].achModuleName,
-                                                bLen,
-                                                &ulDummy)))
-                                paModules[i].achModuleName[bLen] = 0;
-                        }
-
-                        if (arc)
-                            break;  // V0.9.9 (2001-04-03) [umoeller]
-                    } // end for
-                }
+                    BYTE bLen;
+                    USHORT usOfs;
+                    ULONG ulDummy;
+
+                    // the module reference table contains offsets
+                    // relative to the import table; we hence read
+                    // the offset in the module reference table, and
+                    // then we read the name in the import table
+
+                    ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                              pExec->pNEHeader->usModRefTblOfs
+                                                + pExec->pDosExeHeader->ulNewHeaderOfs
+                                                + sizeof(usOfs) * i,
+                                              FILE_BEGIN,
+                                              &ulDummy));
+
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &usOfs, 2, &ulDummy));
+
+                    ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                              pExec->pNEHeader->usImportTblOfs
+                                                + pExec->pDosExeHeader->ulNewHeaderOfs
+                                                + usOfs,
+                                              FILE_BEGIN,
+                                              &ulDummy));
+
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
+
+                    bLen &= 0x7F;
+
+                    ENSURE_SAFE(DosRead(pExec->hfExe,
+                                        paModules[i].achModuleName,
+                                        bLen,
+                                        &ulDummy));
+
+                    paModules[i].achModuleName[bLen] = 0;
+                } // end for
             }
         }
         else
-            arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-        if (arc)
-        {
+            ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+        // no error: output data
+        *ppaModules = paModules;
+        *pcModules = cModules;
+
+        ENSURE_FINALLY;
             // if we had an error above, clean up
-            if (paModules)
-                free(paModules);
-        }
-        else
-        {
-            // no error: output data
-            *ppaModules = paModules;
-            *pcModules = cModules;
-        }
+            free(paModules);
+        ENSURE_END;
     }
     else
-        arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-    return (arc);
+        ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+    ENSURE_OK;
 }
 
@@ -1404,6 +1380,5 @@
 APIRET doshExecFreeImportedModules(PFSYSMODULE paModules)
 {
-    if (paModules)          // V0.9.9 (2001-04-04) [umoeller]
-        free(paModules);
+    free(paModules);
     return (NO_ERROR);
 }
@@ -1418,4 +1393,5 @@
  *@@added V0.9.9 (2001-03-30) [lafaix]
  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
  */
 
@@ -1424,262 +1400,219 @@
                         PULONG pcEntries)        // out: entry table entry count; ptr can be NULL
 {
-    APIRET arc = NO_ERROR;
-
     ULONG  ulDummy;
-
-    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                              pExec->pLXHeader->ulEntryTblOfs
-                                + pExec->pDosExeHeader->ulNewHeaderOfs,
-                              FILE_BEGIN,
-                              &ulDummy)))
-    {
-        USHORT usOrdinal = 1,
-               usCurrent = 0;
-        int    i;
-
-        while (!arc)            // V0.9.9 (2001-04-03) [umoeller]
+    USHORT usOrdinal = 1,
+           usCurrent = 0;
+    int    i;
+
+    ENSURE(DosSetFilePtr(pExec->hfExe,
+                         pExec->pLXHeader->ulEntryTblOfs
+                           + pExec->pDosExeHeader->ulNewHeaderOfs,
+                         FILE_BEGIN,
+                         &ulDummy));
+
+    while (TRUE)
+    {
+        BYTE   bCnt,
+               bType,
+               bFlag;
+
+        ENSURE(DosRead(pExec->hfExe, &bCnt, 1, &ulDummy));
+
+        if (bCnt == 0)
+            // end of the entry table
+            break;
+
+        ENSURE(DosRead(pExec->hfExe, &bType, 1, &ulDummy));
+
+        switch (bType & 0x7F)
         {
-            BYTE   bCnt,
-                   bType,
-                   bFlag;
-
-            if (!(arc = DosRead(pExec->hfExe,
-                                &bCnt,
-                                1,
-                                &ulDummy)))
-            {
-                if (bCnt == 0)
-                    // end of the entry table
-                    break;
-
-                if (!(arc = DosRead(pExec->hfExe,
-                                    &bType,
-                                    1,
-                                    &ulDummy)))
+            /*
+             * unused entries
+             *
+             */
+
+            case 0:
+                usOrdinal += bCnt;
+            break;
+
+            /*
+             * 16-bit entries
+             *
+             * the bundle type is followed by the object number
+             * and by bCnt bFlag+usOffset entries
+             *
+             */
+
+            case 1:
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     sizeof(USHORT),
+                                     FILE_CURRENT,
+                                     &ulDummy));
+
+                for (i = 0; i < bCnt; i ++)
                 {
-                    switch (bType & 0x7F)
+                    ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
+
+                    if (bFlag & 0x01)
                     {
-                        /*
-                         * unused entries
-                         *
-                         */
-
-                        case 0:
-                           usOrdinal += bCnt;
-                        break;
-
-                        /*
-                         * 16-bit entries
-                         *
-                         * the bundle type is followed by the object number
-                         * and by bCnt bFlag+usOffset entries
-                         *
-                         */
-
-                        case 1:
-                            if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                      sizeof(USHORT),
-                                                      FILE_CURRENT,
-                                                      &ulDummy)))
-                            {
-                                for (i = 0; i < bCnt; i ++)
-                                {
-                                    if (!(arc = DosRead(pExec->hfExe,
-                                                        &bFlag,
-                                                        1,
-                                                        &ulDummy)))
-                                    {
-                                        if (bFlag & 0x01)
-                                        {
-                                            if (paFunctions)
-                                            {
-                                                paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                                paFunctions[usCurrent].ulType = 1;
-                                                paFunctions[usCurrent].achFunctionName[0] = 0;
-                                            }
-                                            usCurrent++;
-                                        }
-
-                                        usOrdinal++;
-
-                                        arc = DosSetFilePtr(pExec->hfExe,
-                                                            sizeof(USHORT),
-                                                            FILE_CURRENT,
-                                                            &ulDummy);
-                                    }
-
-                                    if (arc)
-                                        break; // V0.9.9 (2001-04-03) [umoeller]
-
-                                } // end for
-                            }
-                        break;
-
-                        /*
-                         * 286 call gate entries
-                         *
-                         * the bundle type is followed by the object number
-                         * and by bCnt bFlag+usOffset+usCallGate entries
-                         *
-                         */
-
-                        case 2:
-                            if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                      sizeof(USHORT),
-                                                      FILE_CURRENT,
-                                                      &ulDummy)))
-                            {
-                                for (i = 0; i < bCnt; i ++)
-                                {
-                                    if (!(arc = DosRead(pExec->hfExe,
-                                                        &bFlag,
-                                                        1,
-                                                        &ulDummy)))
-                                    {
-                                        if (bFlag & 0x01)
-                                        {
-                                            if (paFunctions)
-                                            {
-                                                paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                                paFunctions[usCurrent].ulType = 2;
-                                                paFunctions[usCurrent].achFunctionName[0] = 0;
-                                            }
-                                            usCurrent++;
-                                        }
-
-                                        usOrdinal++;
-
-                                        arc = DosSetFilePtr(pExec->hfExe,
-                                                            sizeof(USHORT) + sizeof(USHORT),
-                                                            FILE_CURRENT,
-                                                            &ulDummy);
-                                    }
-
-                                    if (arc)
-                                        break; // V0.9.9 (2001-04-03) [umoeller]
-
-                                } // end for
-                            }
-                        break;
-
-                        /*
-                         * 32-bit entries
-                         *
-                         * the bundle type is followed by the object number
-                         * and by bCnt bFlag+ulOffset entries
-                         *
-                         */
-
-                        case 3:
-                            if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                      sizeof(USHORT),
-                                                      FILE_CURRENT,
-                                                      &ulDummy)))
-                            {
-                                for (i = 0; i < bCnt; i ++)
-                                {
-                                    if (!(arc = DosRead(pExec->hfExe,
-                                                        &bFlag,
-                                                        1,
-                                                        &ulDummy)))
-                                    {
-                                        if (bFlag & 0x01)
-                                        {
-                                            if (paFunctions)
-                                            {
-                                                paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                                paFunctions[usCurrent].ulType = 3;
-                                                paFunctions[usCurrent].achFunctionName[0] = 0;
-                                            }
-                                            usCurrent++;
-                                        }
-
-                                        usOrdinal++;
-
-                                        arc = DosSetFilePtr(pExec->hfExe,
-                                                            sizeof(ULONG),
-                                                            FILE_CURRENT,
-                                                            &ulDummy);
-                                    }
-
-                                    if (arc)
-                                        break; // V0.9.9 (2001-04-03) [umoeller]
-                                } // end for
-                            }
-                        break;
-
-                        /*
-                         * forwarder entries
-                         *
-                         * the bundle type is followed by a reserved word
-                         * and by bCnt bFlag+usModOrd+ulOffsOrdNum entries
-                         *
-                         */
-
-                        case 4:
-                            if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                      sizeof(USHORT),
-                                                      FILE_CURRENT,
-                                                      &ulDummy)))
-                            {
-                                for (i = 0; i < bCnt; i ++)
-                                {
-                                    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                              sizeof(BYTE) + sizeof(USHORT) + sizeof(ULONG),
-                                                              FILE_CURRENT,
-                                                              &ulDummy)))
-                                    {
-                                        if (paFunctions)
-                                        {
-                                            paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                            paFunctions[usCurrent].ulType = 4;
-                                            paFunctions[usCurrent].achFunctionName[0] = 0;
-                                        }
-                                        usCurrent++;
-
-                                        usOrdinal++;
-                                    }
-
-                                    if (arc)
-                                        break; // V0.9.9 (2001-04-03) [umoeller]
-                                } // end for
-                            }
-                        break;
-
-                        /*
-                         * unknown bundle type
-                         *
-                         * we don't know how to handle this bundle, so we must
-                         * stop parsing the entry table here (as we don't know the
-                         * bundle size); if paFunctions is not null, we fill it with
-                         * informative data
-                         */
-
-                        default:
-                            if (paFunctions)
-                            {
-                                paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                paFunctions[usCurrent].ulType = bType;
-                                sprintf(paFunctions[usCurrent].achFunctionName,
-                                        "Unknown bundle type encountered (%d).  Aborting entry table scan.",
-                                        bType);
-
-                                arc = ERROR_INVALID_LIST_FORMAT;
-                                    // whatever
-                                    // V0.9.9 (2001-04-03) [umoeller]
-                            }
-
-                            usCurrent++;
-                    } // end switch (bType & 0x7F)
+                        if (paFunctions)
+                        {
+                            paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                            paFunctions[usCurrent].ulType = 1;
+                            paFunctions[usCurrent].achFunctionName[0] = 0;
+                        }
+                        usCurrent++;
+                    }
+
+                    usOrdinal++;
+
+                    ENSURE(DosSetFilePtr(pExec->hfExe,
+                                         sizeof(USHORT),
+                                         FILE_CURRENT,
+                                         &ulDummy));
+
+                } // end for
+            break;
+
+            /*
+             * 286 call gate entries
+             *
+             * the bundle type is followed by the object number
+             * and by bCnt bFlag+usOffset+usCallGate entries
+             *
+             */
+
+            case 2:
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     sizeof(USHORT),
+                                     FILE_CURRENT,
+                                     &ulDummy));
+
+                for (i = 0; i < bCnt; i ++)
+                {
+                    ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
+
+                    if (bFlag & 0x01)
+                    {
+                        if (paFunctions)
+                        {
+                            paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                            paFunctions[usCurrent].ulType = 2;
+                            paFunctions[usCurrent].achFunctionName[0] = 0;
+                        }
+                        usCurrent++;
+                    }
+
+                    usOrdinal++;
+
+                    ENSURE(DosSetFilePtr(pExec->hfExe,
+                                         sizeof(USHORT) + sizeof(USHORT),
+                                         FILE_CURRENT,
+                                         &ulDummy));
+
+                } // end for
+            break;
+
+            /*
+             * 32-bit entries
+             *
+             * the bundle type is followed by the object number
+             * and by bCnt bFlag+ulOffset entries
+             *
+             */
+
+            case 3:
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     sizeof(USHORT),
+                                     FILE_CURRENT,
+                                     &ulDummy));
+
+                for (i = 0; i < bCnt; i ++)
+                {
+                    ENSURE(DosRead(pExec->hfExe, &bFlag, 1, &ulDummy));
+
+                    if (bFlag & 0x01)
+                    {
+                        if (paFunctions)
+                        {
+                            paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                            paFunctions[usCurrent].ulType = 3;
+                            paFunctions[usCurrent].achFunctionName[0] = 0;
+                        }
+                        usCurrent++;
+                    }
+
+                    usOrdinal++;
+
+                    ENSURE(DosSetFilePtr(pExec->hfExe,
+                                         sizeof(ULONG),
+                                         FILE_CURRENT,
+                                         &ulDummy));
+                } // end for
+            break;
+
+            /*
+             * forwarder entries
+             *
+             * the bundle type is followed by a reserved word
+             * and by bCnt bFlag+usModOrd+ulOffsOrdNum entries
+             *
+             */
+
+            case 4:
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     sizeof(USHORT),
+                                     FILE_CURRENT,
+                                     &ulDummy));
+
+                for (i = 0; i < bCnt; i ++)
+                {
+                    ENSURE(DosSetFilePtr(pExec->hfExe,
+                                         sizeof(BYTE) + sizeof(USHORT) + sizeof(ULONG),
+                                         FILE_CURRENT,
+                                         &ulDummy));
+
+                    if (paFunctions)
+                    {
+                        paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                        paFunctions[usCurrent].ulType = 4;
+                        paFunctions[usCurrent].achFunctionName[0] = 0;
+                    }
+                    usCurrent++;
+
+                    usOrdinal++;
+                } // end for
+            break;
+
+            /*
+             * unknown bundle type
+             *
+             * we don't know how to handle this bundle, so we must
+             * stop parsing the entry table here (as we don't know the
+             * bundle size); if paFunctions is not null, we fill it with
+             * informative data
+             */
+
+            default:
+                if (paFunctions)
+                {
+                    paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                    paFunctions[usCurrent].ulType = bType;
+                    sprintf(paFunctions[usCurrent].achFunctionName,
+                            "Unknown bundle type encountered (%d).  Aborting entry table scan.",
+                            bType);
+
+                    usCurrent++;
                 }
-            }
-        } // end while (!arc)
-
-        if (!arc)
-            if (pcEntries)
-                *pcEntries = usCurrent;
-    }
-
-    return (arc);
+                ENSURE_FAIL(ERROR_INVALID_LIST_FORMAT);
+                    // whatever
+                    // V0.9.9 (2001-04-03) [umoeller]
+        } // end switch (bType & 0x7F)
+    } // end while (TRUE)
+
+    if (pcEntries)
+       *pcEntries = usCurrent;
+
+    ENSURE_OK;
 }
 
@@ -1693,4 +1626,5 @@
  *@@added V0.9.9 (2001-03-30) [lafaix]
  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
  */
 
@@ -1699,85 +1633,73 @@
                         PULONG pcEntries)        // out: entry table entry count; ptr can be NULL
 {
-    APIRET arc = NO_ERROR;
     ULONG  ulDummy;
-
-    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                              pExec->pNEHeader->usEntryTblOfs
-                                + pExec->pDosExeHeader->ulNewHeaderOfs,
-                              FILE_BEGIN,
-                              &ulDummy)))
-    {
-        USHORT usOrdinal = 1,
-               usCurrent = 0;
-        int    i;
-
-        while (!arc)        // V0.9.9 (2001-04-03) [umoeller]
+    USHORT usOrdinal = 1,
+           usCurrent = 0;
+    int    i;
+
+    ENSURE(DosSetFilePtr(pExec->hfExe,
+                         pExec->pNEHeader->usEntryTblOfs
+                           + pExec->pDosExeHeader->ulNewHeaderOfs,
+                         FILE_BEGIN,
+                         &ulDummy));
+
+    while (TRUE)
+    {
+        BYTE bCnt,
+             bType,
+             bFlag;
+
+        ENSURE(DosRead(pExec->hfExe, &bCnt, 1, &ulDummy));
+
+        if (bCnt == 0)
+            // end of the entry table
+            break;
+
+        ENSURE(DosRead(pExec->hfExe, &bType, 1, &ulDummy));
+
+        for (i = 0; i < bCnt; i++)
         {
-            BYTE bCnt,
-                 bType,
-                 bFlag;
-
-            if (!(arc = DosRead(pExec->hfExe,
-                                &bCnt,
-                                1,
-                                &ulDummy)))
+            ENSURE(DosRead(pExec->hfExe,
+                           &bFlag,
+                           1,
+                           &ulDummy));
+
+            if (bFlag & 0x01)
             {
-                if (bCnt == 0)
-                    // end of the entry table
-                    break;
-
-                if (!(arc = DosRead(pExec->hfExe,
-                                    &bType,
-                                    1,
-                                    &ulDummy)))
+                if (paFunctions)
                 {
-                    for (i = 0; i < bCnt; i++)
-                    {
-                        if (!(arc = DosRead(pExec->hfExe,
-                                            &bFlag,
-                                            1,
-                                            &ulDummy)))
-                        {
-                            if (bFlag & 0x01)
-                            {
-                                if (paFunctions)
-                                {
-                                    paFunctions[usCurrent].ulOrdinal = usOrdinal;
-                                    paFunctions[usCurrent].ulType = 1; // 16-bit entry
-                                    paFunctions[usCurrent].achFunctionName[0] = 0;
-                                }
-                                usCurrent++;
-                            }
-
-                            usOrdinal++;
-
-                            if (bType == 0xFF)
-                                // moveable segment
-                                arc = DosSetFilePtr(pExec->hfExe,
-                                                    5,
-                                                    FILE_CURRENT,
-                                                    &ulDummy);
-                            else
-                                // fixed segment
-                                arc = DosSetFilePtr(pExec->hfExe,
-                                                    2,
-                                                    FILE_CURRENT,
-                                                    &ulDummy);
-                        }
-
-                        if (arc)
-                            break; // V0.9.9 (2001-04-03) [umoeller]
-
-                    } // end for
+                    paFunctions[usCurrent].ulOrdinal = usOrdinal;
+                    paFunctions[usCurrent].ulType = 1; // 16-bit entry
+                    paFunctions[usCurrent].achFunctionName[0] = 0;
                 }
+                usCurrent++;
             }
-        } // end while (!arc)
-
-        if (!arc)
-            if (pcEntries)
-                *pcEntries = usCurrent;
-    }
-
-    return (arc);
+
+            usOrdinal++;
+
+            if (bType == 0xFF)
+            {
+                // moveable segment
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     5,
+                                     FILE_CURRENT,
+                                     &ulDummy));
+            }
+            else
+            {
+                // fixed segment
+                ENSURE(DosSetFilePtr(pExec->hfExe,
+                                     2,
+                                     FILE_CURRENT,
+                                     &ulDummy));
+            }
+
+        } // end for
+    } // end while (TRUE)
+
+    if (pcEntries)
+        *pcEntries = usCurrent;
+
+    ENSURE_OK;
 }
 
@@ -1787,4 +1709,5 @@
  *
  *@@added V0.9.9 (2001-04-01) [lafaix]
+ *@@changed V0.9.9 (2001-04-07) [umoeller]: added _Optlink, or this won't compile as C++
  */
 
@@ -1814,4 +1737,6 @@
  *@@changed V0.9.9 (2001-04-02) [lafaix]: the first entry is special
  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: removed the 127 char limit
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
  */
 
@@ -1820,12 +1745,10 @@
                      PFSYSFUNCTION paFunctions)
 {
-    APIRET  arc = NO_ERROR;
     ULONG   ulDummy;
 
     USHORT        usOrdinal;
     PFSYSFUNCTION pFunction;
-    BOOL          bFirst = TRUE;
-
-    while (!arc)        // V0.9.9 (2001-04-03) [umoeller]
+
+    while (TRUE)
     {
         BYTE   bLen;
@@ -1833,52 +1756,28 @@
         int    i;
 
-        if (!(arc = DosRead(pExec->hfExe,
-                            &bLen,
-                            1,
-                            &ulDummy)))
+        ENSURE(DosRead(pExec->hfExe, &bLen, 1, &ulDummy));
+
+        if (bLen == 0)
+            // end of the name table
+            break;
+
+        ENSURE(DosRead(pExec->hfExe, &achName, bLen, &ulDummy));
+        achName[bLen] = 0;
+
+        ENSURE(DosRead(pExec->hfExe, &usOrdinal, sizeof(USHORT), &ulDummy));
+
+        if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,
+                                                paFunctions,
+                                                cFunctions,
+                                                sizeof(FSYSFUNCTION),
+                                                Compare)))
         {
-            if (bLen == 0)
-                // end of the name table
-                break;
-
-            // the LX docs says that len is limited to 127 (the 8th bit being
-            // reserved for future use); but does this applies to 16bits
-            // tables too?
-            // in any case, we must skip the first entry (module name in the
-            // resident name table, and module description in non-resident
-            // name table)
-            if (bFirst)
-                bFirst = FALSE;
-            else
-                bLen &= 0x7F;
-
-            if (!(arc = DosRead(pExec->hfExe,
-                                &achName,
-                                bLen,
-                                &ulDummy)))
-            {
-                achName[bLen] = 0;
-
-                if (!(arc = DosRead(pExec->hfExe,
-                                    &usOrdinal,
-                                    sizeof(USHORT),
-                                    &ulDummy)))
-                {
-                    if ((pFunction = (PFSYSFUNCTION)bsearch(&usOrdinal,
-                                                            paFunctions,
-                                                            cFunctions,
-                                                            sizeof(FSYSFUNCTION),
-                                                            Compare)))
-                    {
-                        memcpy(pFunction->achFunctionName,
-                               achName,
-                               bLen+1);
-                    }
-                }
-            }
+            memcpy(pFunction->achFunctionName,
+                   achName,
+                   bLen+1);
         }
     }
 
-    return (arc);
+    ENSURE_OK;
 }
 
@@ -1911,4 +1810,5 @@
  *@@added V0.9.9 (2001-03-11) [lafaix]
  *@@changed V0.9.9 (2001-04-03) [umoeller]: added tons of error checking, changed prototype to return APIRET
+ *@@changed V0.9.9 (2001-04-05) [lafaix]: rewritten error checking code
  */
 
@@ -1917,10 +1817,9 @@
                                       PULONG pcFunctions)           // out: array item count
 {
-    APIRET arc = NO_ERROR;
-
     if (    (pExec)
          && (pExec->ulOS == EXEOS_OS2)
        )
     {
+        ENSURE_BEGIN;
         ULONG         cFunctions = 0;
         PFSYSFUNCTION paFunctions = NULL;
@@ -1936,44 +1835,42 @@
             // the entry table
 
-            if (!(arc = ScanLXEntryTable(pExec,
-                                         NULL,
-                                         &cFunctions)))
+            ENSURE(ScanLXEntryTable(pExec, NULL, &cFunctions));
+
+            // we now have the number of exported entries; let us
+            // build them
+
+            if (cFunctions)
             {
-                // we now have the number of exported entries; let us
-                // build them
-
-                if (cFunctions)
-                {
-                    ULONG cb = sizeof(FSYSFUNCTION) * cFunctions;
-
-                    paFunctions = (PFSYSFUNCTION)malloc(cb);
-                    if (!paFunctions)
-                        arc = ERROR_NOT_ENOUGH_MEMORY;  // V0.9.9 (2001-04-03) [umoeller]
-                    else
-                    {
-                        // we rescan the entry table (the cost is not as bad
-                        // as it may seem, due to disk caching)
-
-                        if (    (!(arc = ScanLXEntryTable(pExec, paFunctions, NULL)))
-                                // we now scan the resident name table entries
-                             && (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pLXHeader->ulResdNameTblOfs
-                                                         + pExec->pDosExeHeader->ulNewHeaderOfs,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                             && (!(arc = ScanNameTable(pExec, cFunctions, paFunctions)))
-                                // we now scan the non-resident name table entries,
-                                // whose offset is _from the begining of the file_
-                             && (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pLXHeader->ulNonResdNameTblOfs,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                           )
-                        {
-                            arc = ScanNameTable(pExec, cFunctions, paFunctions);
-                        }
-                    }
-                } // end if (cFunctions)
-            }
+                ULONG cb = sizeof(FSYSFUNCTION) * cFunctions;
+
+                paFunctions = (PFSYSFUNCTION)malloc(cb);
+                if (!paFunctions)
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
+
+                // we rescan the entry table (the cost is not as bad
+                // as it may seem, due to disk caching)
+
+                ENSURE_SAFE(ScanLXEntryTable(pExec, paFunctions, NULL));
+
+                // we now scan the resident name table entries
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pLXHeader->ulResdNameTblOfs
+                                            + pExec->pDosExeHeader->ulNewHeaderOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
+
+                // we now scan the non-resident name table entries,
+                // whose offset is _from the begining of the file_
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pLXHeader->ulNonResdNameTblOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
+            } // end if (cFunctions)
         }
         else if (pExec->ulExeFormat == EXEFORMAT_NE)
@@ -1985,66 +1882,60 @@
             // have to count them in the entry table
 
-            if (!(arc = ScanNEEntryTable(pExec,
-                                         NULL,
-                                         &cFunctions)))
+            ENSURE(ScanNEEntryTable(pExec, NULL, &cFunctions));
+
+            // we now have the number of exported entries; let us
+            // build them
+
+            if (cFunctions)
             {
-                // we now have the number of exported entries; let us
-                // build them
-
-                if (cFunctions)
-                {
-                    USHORT usOrdinal = 1,
-                           usCurrent = 0;
-
-                    paFunctions = (PFSYSFUNCTION)malloc(sizeof(FSYSFUNCTION) * cFunctions);
-                    if (!paFunctions)
-                        arc = ERROR_NOT_ENOUGH_MEMORY;
-                    else
-                    {
-                        // we rescan the entry table (the cost is not as bad
-                        // as it may seem, due to disk caching)
-
-                        if (    (!(arc = ScanNEEntryTable(pExec, paFunctions, NULL)))
-                                // we now scan the resident name table entries
-                             && (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pNEHeader->usResdNameTblOfs
-                                                         + pExec->pDosExeHeader->ulNewHeaderOfs,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                             && (!(arc = ScanNameTable(pExec, cFunctions, paFunctions)))
-                                // we now scan the non-resident name table entries,
-                                // whose offset is _from the begining of the file_
-                             && (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                       pExec->pNEHeader->ulNonResdTblOfs,
-                                                       FILE_BEGIN,
-                                                       &ulDummy)))
-                           )
-                        {
-                             arc = ScanNameTable(pExec, cFunctions, paFunctions);
-                        }
-                    }
-                }
+                USHORT usOrdinal = 1,
+                       usCurrent = 0;
+
+                paFunctions = (PFSYSFUNCTION)malloc(sizeof(FSYSFUNCTION) * cFunctions);
+                if (!paFunctions)
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
+
+                // we rescan the entry table (the cost is not as bad
+                // as it may seem, due to disk caching)
+
+                ENSURE_SAFE(ScanNEEntryTable(pExec, paFunctions, NULL));
+
+                // we now scan the resident name table entries
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pNEHeader->usResdNameTblOfs
+                                            + pExec->pDosExeHeader->ulNewHeaderOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
+
+                // we now scan the non-resident name table entries,
+                // whose offset is _from the begining of the file_
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pNEHeader->ulNonResdTblOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                ENSURE_SAFE(ScanNameTable(pExec, cFunctions, paFunctions));
             }
         }
         else
-            arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-        if (arc) // V0.9.9 (2001-04-03) [umoeller]
-        {
+            ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+        // no error: output data
+        *ppaFunctions = paFunctions;
+        *pcFunctions = cFunctions;
+
+        ENSURE_FINALLY;
             // if we had an error above, clean up
-            if (paFunctions)
-                free(paFunctions);
-        }
-        else
-        {
-            // no error: output data
-            *ppaFunctions = paFunctions;
-            *pcFunctions = cFunctions;
-        }
+            free(paFunctions);
+        ENSURE_END;
     }
     else
-        arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-    return (arc);
+        ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+    ENSURE_OK;
 }
 
@@ -2058,6 +1949,6 @@
 APIRET doshExecFreeExportedFunctions(PFSYSFUNCTION paFunctions)
 {
-    if (paFunctions)       // V0.9.9 (2001-04-04) [umoeller]
-        free(paFunctions);
+    free(paFunctions);
+
     return (NO_ERROR);
 }
@@ -2091,10 +1982,9 @@
                               PULONG pcResources)    // out: array item count
 {
-    APIRET          arc = NO_ERROR;
-
     if (    (pExec)
          && (pExec->ulOS == EXEOS_OS2)
        )
     {
+        ENSURE_BEGIN;
         ULONG           cResources = 0;
         PFSYSRESOURCE   paResources = NULL;
@@ -2103,113 +1993,85 @@
         {
             // 32-bit OS/2 executable:
-            if (cResources = pExec->pLXHeader->ulResTblCnt)
+            cResources = pExec->pLXHeader->ulResTblCnt;
+
+            if (cResources)
             {
+                #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
+                struct rsrc32               /* Resource Table Entry */
+                {
+                    unsigned short  type;   /* Resource type */
+                    unsigned short  name;   /* Resource name */
+                    unsigned long   cb;     /* Resource size */
+                    unsigned short  obj;    /* Object number */
+                    unsigned long   offset; /* Offset within object */
+                } rs;
+
+                struct o32_obj                    /* Flat .EXE object table entry */
+                {
+                    unsigned long   o32_size;     /* Object virtual size */
+                    unsigned long   o32_base;     /* Object base virtual address */
+                    unsigned long   o32_flags;    /* Attribute flags */
+                    unsigned long   o32_pagemap;  /* Object page map index */
+                    unsigned long   o32_mapsize;  /* Number of entries in object page map */
+                    unsigned long   o32_reserved; /* Reserved */
+                } ot;
+                #pragma pack() // V0.9.9 (2001-04-03) [umoeller]
+
                 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
+                ULONG ulDummy;
+                int i;
+
                 paResources = (PFSYSRESOURCE)malloc(cb);
                 if (!paResources)
-                    arc = ERROR_NOT_ENOUGH_MEMORY;
-                else
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
+
+                memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pLXHeader->ulResTblOfs
+                                            + pExec->pDosExeHeader->ulNewHeaderOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                for (i = 0; i < cResources; i++)
                 {
-                    ULONG ulDummy;
-
-                    memset(paResources, 0, cb); // V0.9.9 (2001-04-03) [umoeller]
-
-                    // V0.9.9 (2001-04-03) [umoeller]:
-                    // Martin, I added error checking to all the below
-                    // Dos* calls. You can't just read around a file
-                    // and assume it will always be valid... especially
-                    // if you fill dynamically allocated memory.
-                    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                              pExec->pLXHeader->ulResTblOfs
-                                                + pExec->pDosExeHeader->ulNewHeaderOfs,
-                                              FILE_BEGIN,
-                                              &ulDummy)))
-                    {
-                        int i;
-
-                        // V0.9.9 (2001-04-03) [umoeller]:
-                        // Besides, packing was missing.
-                        #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
-                        struct rsrc32               /* Resource Table Entry */
-                        {
-                            unsigned short  type;   /* Resource type */
-                            unsigned short  name;   /* Resource name */
-                            unsigned long   cb;     /* Resource size */
-                            unsigned short  obj;    /* Object number */
-                            unsigned long   offset; /* Offset within object */
-                        } rs;
-
-                        struct o32_obj                    /* Flat .EXE object table entry */
-                        {
-                            unsigned long   o32_size;     /* Object virtual size */
-                            unsigned long   o32_base;     /* Object base virtual address */
-                            unsigned long   o32_flags;    /* Attribute flags */
-                            unsigned long   o32_pagemap;  /* Object page map index */
-                            unsigned long   o32_mapsize;  /* Number of entries in object page map */
-                            unsigned long   o32_reserved; /* Reserved */
-                        } ot;
-                        #pragma pack() // V0.9.9 (2001-04-03) [umoeller]
-
-                        for (i = 0; i < cResources; i++)
-                        {
-                            arc = DosRead(pExec->hfExe,
-                                          &rs,
-                                          14,
-                                          &ulDummy);
-                            if (arc)
-                                break;      // V0.9.9 (2001-04-03) [umoeller]
-                            else
-                            {
-                                paResources[i].ulID = rs.name;
-                                paResources[i].ulType = rs.type;
-                                paResources[i].ulSize = rs.cb;
-                                paResources[i].ulFlag = rs.obj; // Temp storage for Object
-                                                                // number.  Will be filled
-                                                                // with resource flag
-                                                                // later.
-                            }
-                        }
-
-                        if (!arc)       // V0.9.9 (2001-04-03) [umoeller]
-                        {
-                            for (i = 0; i < cResources; i++)
-                            {
-                                ULONG ulOfsThis
-                                    =   pExec->pLXHeader->ulObjTblOfs
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &rs, 14, &ulDummy));
+
+                    paResources[i].ulID = rs.name;
+                    paResources[i].ulType = rs.type;
+                    paResources[i].ulSize = rs.cb;
+                    paResources[i].ulFlag = rs.obj; // Temp storage for Object
+                                                    // number.  Will be filled
+                                                    // with resource flag
+                                                    // later.
+                }
+
+                for (i = 0; i < cResources; i++)
+                {
+                    ULONG ulOfsThis =   pExec->pLXHeader->ulObjTblOfs
                                       + pExec->pDosExeHeader->ulNewHeaderOfs
                                       + (   sizeof(ot)
                                           * (paResources[i].ulFlag - 1));
 
-                                if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                          ulOfsThis,
-                                                          FILE_BEGIN,
-                                                          &ulDummy)))
-                                {
-                                    if (!(arc = DosRead(pExec->hfExe,
-                                                        &ot,
-                                                        sizeof(ot),
-                                                        &ulDummy)))
-                                    {
-                                        paResources[i].ulFlag  = ((ot.o32_flags & OBJWRITE)
-                                                                        ? 0
-                                                                        : RNPURE);
-                                        paResources[i].ulFlag |= ((ot.o32_flags & OBJDISCARD)
-                                                                        ? 4096
-                                                                        : 0);
-                                        paResources[i].ulFlag |= ((ot.o32_flags & OBJSHARED)
-                                                                        ? RNMOVE
-                                                                        : 0);
-                                        paResources[i].ulFlag |= ((ot.o32_flags & OBJPRELOAD)
-                                                                        ? RNPRELOAD
-                                                                        : 0);
-                                    }
-                                }
-
-                                if (arc)
-                                    break; // V0.9.9 (2001-04-03) [umoeller]
-                            } // end for
-                        }
-                    } // end if !DosSetFilePtr(pExec->hfExe,
-                } // end if paResources = (PFSYSRESOURCE)malloc(sizeof(FSYSRESOURCE) * cResources);
+                    ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                              ulOfsThis,
+                                              FILE_BEGIN,
+                                              &ulDummy));
+
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &ot, sizeof(ot), &ulDummy));
+
+                    paResources[i].ulFlag  = ((ot.o32_flags & OBJWRITE)
+                                                    ? 0
+                                                    : RNPURE);
+                    paResources[i].ulFlag |= ((ot.o32_flags & OBJDISCARD)
+                                                    ? 4096
+                                                    : 0);
+                    paResources[i].ulFlag |= ((ot.o32_flags & OBJSHARED)
+                                                    ? RNMOVE
+                                                    : 0);
+                    paResources[i].ulFlag |= ((ot.o32_flags & OBJPRELOAD)
+                                                    ? RNPRELOAD
+                                                    : 0);
+                } // end for
             } // end if (cResources)
         } // end if (pExec->ulExeFormat == EXEFORMAT_LX)
@@ -2217,5 +2079,7 @@
         {
             // 16-bit OS/2 executable:
-            if (cResources = pExec->pNEHeader->usResSegmCount)
+            cResources = pExec->pNEHeader->usResSegmCount;
+
+            if (cResources)
             {
                 #pragma pack(1)     // V0.9.9 (2001-04-02) [umoeller]
@@ -2231,92 +2095,69 @@
 
                 ULONG cb = sizeof(FSYSRESOURCE) * cResources;
+                ULONG ulDummy;
+                int i;
 
                 paResources = (PFSYSRESOURCE)malloc(cb);
                 if (!paResources)
-                    arc = ERROR_NOT_ENOUGH_MEMORY;
-                else
+                    ENSURE_FAIL(ERROR_NOT_ENOUGH_MEMORY);
+
+                memset(paResources, 0, cb);     // V0.9.9 (2001-04-03) [umoeller]
+
+                // we first read the resources IDs and types
+
+                ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                          pExec->pNEHeader->usResTblOfs
+                                            + pExec->pDosExeHeader->ulNewHeaderOfs,
+                                          FILE_BEGIN,
+                                          &ulDummy));
+
+                for (i = 0; i < cResources; i++)
                 {
-                    ULONG ulDummy;
-
-                    memset(paResources, 0, cb);     // V0.9.9 (2001-04-03) [umoeller]
-
-                    // we first read the resources IDs and types
-                    if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                              pExec->pNEHeader->usResTblOfs
-                                                 + pExec->pDosExeHeader->ulNewHeaderOfs,
-                                              FILE_BEGIN,
-                                              &ulDummy)))
-                    {
-                        int i;
-
-                        for (i = 0; i < cResources; i++)
-                        {
-                            arc = DosRead(pExec->hfExe, &rti, sizeof(rti), &ulDummy);
-                            if (arc)
-                                break;
-                            else
-                            {
-                                paResources[i].ulID = rti.name;
-                                paResources[i].ulType = rti.type;
-                            }
-                        }
-
-                        if (!arc)
-                        {
-                            // we then read their sizes and flags
-                            for (i = 0; i < cResources; i++)
-                            {
-                                if (!(arc = DosSetFilePtr(pExec->hfExe,
-                                                          pExec->pDosExeHeader->ulNewHeaderOfs
-                                                                 + pExec->pNEHeader->usSegTblOfs
-                                                                 + (sizeof(ns)
-                                                                     * (  pExec->pNEHeader->usSegTblEntries
-                                                                        - pExec->pNEHeader->usResSegmCount
-                                                                        + i)),
-                                                          FILE_BEGIN,
-                                                          &ulDummy)))
-                                {
-                                    if (!(arc = DosRead(pExec->hfExe,
-                                                        &ns,
-                                                        sizeof(ns),
-                                                        &ulDummy)))
-                                    {
-                                        paResources[i].ulSize = ns.ns_cbseg;
-
-                                        paResources[i].ulFlag  = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;
-                                        paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;
-                                        paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;
-                                        paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;
-                                    }
-                                }
-
-                                if (arc)
-                                    break; // V0.9.9 (2001-04-04) [umoeller]
-                            } // end for
-                        }
-                    } // end if !arc = DosSetFilePtr(pExec->hfExe,
-                } // end if paResources = (PFSYSRESOURCE)malloc(sizeof(FSYSRESOURCE) * cResources);
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &rti, sizeof(rti), &ulDummy));
+
+                    paResources[i].ulID = rti.name;
+                    paResources[i].ulType = rti.type;
+                }
+
+                // we then read their sizes and flags
+
+                for (i = 0; i < cResources; i++)
+                {
+                    ENSURE_SAFE(DosSetFilePtr(pExec->hfExe,
+                                              pExec->pDosExeHeader->ulNewHeaderOfs
+                                                + pExec->pNEHeader->usSegTblOfs
+                                                + (sizeof(ns)
+                                                * (  pExec->pNEHeader->usSegTblEntries
+                                                   - pExec->pNEHeader->usResSegmCount
+                                                   + i)),
+                                                FILE_BEGIN,
+                                                &ulDummy));
+
+                    ENSURE_SAFE(DosRead(pExec->hfExe, &ns, sizeof(ns), &ulDummy));
+
+                    paResources[i].ulSize = ns.ns_cbseg;
+
+                    paResources[i].ulFlag  = (ns.ns_flags & OBJPRELOAD) ? RNPRELOAD : 0;
+                    paResources[i].ulFlag |= (ns.ns_flags & OBJSHARED) ? RNPURE : 0;
+                    paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? RNMOVE : 0;
+                    paResources[i].ulFlag |= (ns.ns_flags & OBJDISCARD) ? 4096 : 0;
+                }
             } // end if (cResources)
         } // end else if (pExec->ulExeFormat == EXEFORMAT_NE)
         else
-            arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-        if (arc) // V0.9.9 (2001-04-03) [umoeller]
-        {
+            ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+        *ppaResources = paResources;
+        *pcResources = cResources;
+
+        ENSURE_FINALLY;
             // if we had an error above, clean up
-            if (paResources)
-                free(paResources);
-        }
-        else
-        {
-            // no error: output data
-            *ppaResources = paResources;
-            *pcResources = cResources;
-        }
+            free(paResources);
+        ENSURE_END;
     }
     else
-        arc = ERROR_INVALID_EXE_SIGNATURE; // V0.9.9 (2001-04-03) [umoeller]
-
-    return (arc);
+        ENSURE_FAIL(ERROR_INVALID_EXE_SIGNATURE); // V0.9.9 (2001-04-03) [umoeller]
+
+    ENSURE_OK;
 }
 
@@ -2330,6 +2171,5 @@
 APIRET doshExecFreeResources(PFSYSRESOURCE paResources)
 {
-    if (paResources)        // V0.9.9 (2001-04-04) [umoeller]
-        free(paResources);
+    free(paResources);
     return (NO_ERROR);
 }
@@ -2712,5 +2552,5 @@
                        PUSHORT posCount,            // in/out: partition count
                        BYTE bDisk,                  // in: disk of partition
-                       char *pszBootName,           // in: boot partition name
+                       const char *pszBootName,     // in: boot partition name
                        CHAR cLetter,                // in/out: drive letter
                        BYTE bFsType,                // in: file system type
@@ -2720,10 +2560,12 @@
 {
     APIRET arc = NO_ERROR;
-    PPARTITIONINFO ppiNew = (PPARTITIONINFO)malloc(sizeof(PARTITIONINFO));
+    PPARTITIONINFO ppiNew = NEW(PARTITIONINFO);
     if (ppiNew)
     {
+        ZERO(ppiNew);
+
         // store data
         ppiNew->bDisk = bDisk;
-        if (fBootable)
+        if ((fBootable) && (pszBootName) )
         {
             memcpy(ppiNew->szBootName, pszBootName, 8);
@@ -2806,7 +2648,8 @@
  *@@ doshGetBootManager:
  *      this goes thru the master boot records on all
- *      disks to find the boot manager partitions.
+ *      disks to find the boot manager partition.
  *
  *      Returns:
+ *
  *      -- NO_ERROR: boot manager found; in that case,
  *                   information about the boot manager
@@ -2814,4 +2657,5 @@
  *                   *BmInfo. Any of these pointers can
  *                   be NULL if you're not interested.
+ *
  *      -- ERROR_NOT_SUPPORTED (50): boot manager not installed.
  *
@@ -2823,5 +2667,5 @@
 APIRET doshGetBootManager(USHORT   *pusDisk,    // out: if != NULL, boot manager disk (1, 2, ...)
                           USHORT   *pusPart,    // out: if != NULL, index of bmgr primary partition (0-3)
-                          PAR_INFO *BmInfo)     // out: if != NULL, boot manager partition info
+                          PAR_INFO *pBmInfo)    // out: if != NULL, boot manager partition info
 {
     APIRET          arc = NO_ERROR;
@@ -2839,19 +2683,25 @@
         // for each disk, read the MBR, which has the
         // primary partitions
-        if ((arc = doshReadSector(usDisk, &MBoot,
-                                  0, 0, 1)))
+        if ((arc = doshReadSector(usDisk,
+                                  &MBoot,
+                                  0,            // head
+                                  0,            // cylinder
+                                  1)))          // sector
             return (arc);
 
-        // Lookup BootManager partition
+        // scan primary partitions for whether
+        // BootManager partition exists
         for (usPrim = 0; usPrim < 4; usPrim++)
         {
             if (MBoot.sPrtnInfo[usPrim].bFileSysCode == 0x0A)
             {
-                if (BmInfo)
-                    *BmInfo = MBoot.sPrtnInfo[usPrim];
+                // this is boot manager:
+                if (pBmInfo)
+                    *pBmInfo = MBoot.sPrtnInfo[usPrim];
                 if (pusPart)
                     *pusPart = usPrim;
                 if (pusDisk)
                     *pusDisk = usDisk;
+                // stop scanning
                 return (NO_ERROR);
             }
@@ -2868,5 +2718,7 @@
  *      This gets called from doshGetPartitionsList.
  *
- *      Returns 0 upon errors.
+ *      Returns:
+ *
+ *      -- ERROR_INVALID_PARAMETER: BMInfo is NULL.
  *
  *      Based on code (C) Dmitry A. Steklenev.
@@ -2877,13 +2729,13 @@
 APIRET GetPrimaryPartitions(PARTITIONINFO **pppiFirst,
                             PARTITIONINFO **pppiThis,
-                            PUSHORT posCount,    // in/out: partition count
-                            PCHAR pcLetter,      // in/out: drive letter counter
-                            UINT BmDisk,         // in: physical disk (1, 2, 3, ...) of boot manager or null
-                            PAR_INFO* BmInfo,    // in: info returned by doshGetBootManager or NULL
-                            UINT iDisk)          // in: system's physical disk count
+                            PUSHORT posCount,       // in/out: partition count
+                            PCHAR pcLetter,         // in/out: drive letter counter
+                            UINT BmDisk,            // in: physical disk (1, 2, 3, ...) of boot manager or null
+                            PAR_INFO* pBmInfo,      // in: info returned by doshGetBootManager or NULL
+                            UINT iDisk)             // in: system's physical disk count
 {
     APIRET  arc = NO_ERROR;
 
-    if (!BmInfo)
+    if (!pBmInfo)
         arc = ERROR_INVALID_PARAMETER;
     else
@@ -2892,16 +2744,24 @@
         memset(&MName, 0, sizeof(MName));
 
-        // read boot manager name table
+        // read boot manager name table;
+        // this is in the boot manager primary partition
+        // at sector offset 3 (?!?)
         if (!(arc = doshReadSector(BmDisk,
                                    &MName,
-                                   BmInfo->bBeginHead,
-                                   GetCyl(BmInfo->rBeginSecCyl),
-                                   GetSec(BmInfo->rBeginSecCyl) + 3)))
+                                   // head, cylinder, sector of bmgr primary partition:
+                                   pBmInfo->bBeginHead,
+                                   GetCyl(pBmInfo->rBeginSecCyl),
+                                   GetSec(pBmInfo->rBeginSecCyl) + 3)))
         {
+            // got bmgr name table:
             MBR_INFO        MBoot;      // Master Boot
             USHORT          i;
 
             // read master boot record of this disk
-            if (!(arc = doshReadSector(iDisk, &MBoot, 0, 0, 1)))
+            if (!(arc = doshReadSector(iDisk,
+                                       &MBoot,
+                                       0,           // head
+                                       0,           // cylinder
+                                       1)))         // sector
             {
                 for (i = 0;
@@ -2915,6 +2775,6 @@
                        )
                     {
-                        BOOL fBootable = (  (BmInfo)
-                                         && (MName[(iDisk-1) * 4 + i].bootable & 0x01)
+                        BOOL fBootable = (    (pBmInfo)
+                                           && (MName[(iDisk-1) * 4 + i].bootable & 0x01)
                                          );
                         // store this partition
@@ -3079,4 +2939,20 @@
 
 /*
+ *@@ CleanPartitionInfos:
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+VOID CleanPartitionInfos(PPARTITIONINFO ppiThis)
+{
+    while (ppiThis)
+    {
+        PPARTITIONINFO ppiNext = ppiThis->pNext;
+        free(ppiThis);
+        ppiThis = ppiNext;
+    }
+}
+
+/*
  *@@ doshGetPartitionsList:
  *      this returns lots of information about the
@@ -3093,14 +2969,24 @@
  *      free the resources allocated by this function.
  *
- *      The linked list starts out with all the primary
- *      partitions, followed by the logical drives in
- *      the extended partitions. This function attempts
- *      to guess the correct drive letters and stores
- *      these with the PARTITIONINFO items, but there's
- *      no guarantee that this is correct. We correctly
- *      ignore Linux partitions here and give all primary
- *      partitions the C: letter, but I have no idea
- *      what happens with NTFS partitions, since I have
- *      none.
+ *      What this function returns depends on whether
+ *      LVM is installed.
+ *
+ *      --  If LVM.DLL is found on the LIBPATH, this opens
+ *          the LVM engine and returns the info from the
+ *          LVM engine in the PARTITIONINFO structures.
+ *          The partitions are then sorted by disk in
+ *          ascending order.
+ *
+ *      --  Otherwise, we parse the partition tables
+ *          manually. The linked list then starts out with
+ *          all the primary partitions, followed by the
+ *          logical drives in the extended partitions.
+ *          This function attempts to guess the correct drive
+ *          letters and stores these with the PARTITIONINFO
+ *          items, but there's no guarantee that this is
+ *          correct. We correctly ignore Linux partitions here
+ *          and give all primary partitions the C: letter, but
+ *          I have no idea what happens with NTFS partitions,
+ *          since I have none.
  *
  *      If an error != NO_ERROR is returned, *pusContext
@@ -3113,97 +2999,686 @@
  *      --  3: secondary partitions error
  *
+ *      --  0: something else.
+ *
  *      Based on code (C) Dmitry A. Steklenev.
  *
  *@@added V0.9.0 [umoeller]
- */
-
-APIRET doshGetPartitionsList(PPARTITIONINFO *ppPartitionInfo,   // out: partition info array
-                             PUSHORT pusPartitionCount,         // out: count of items in **ppPartitionInfo
+ *@@changed V0.9.9 (2001-04-07) [umoeller]: added transparent LVM support; changed prototype
+ *@@changed V0.9.9 (2001-04-07) [umoeller]: added memory leaks on errors
+ */
+
+APIRET doshGetPartitionsList(PPARTITIONSLIST *ppList,
                              PUSHORT pusContext)                // out: error context
 {
     APIRET          arc = NO_ERROR;
-    PAR_INFO        BmInfo;     // BootManager partition
-    USHORT          usBmDisk;     // BootManager disk
-    USHORT          cDisks = doshQueryDiskCount();    // physical disks count
-    USHORT          i;
+
+    PLVMINFO        pLVMInfo = NULL;
 
     PARTITIONINFO   *pPartitionInfos = NULL, // linked list of all partitions
                     *ppiTemp = NULL;
-    USHORT          osCount;        // bootable partition count
-    CHAR            cLetter = 'C';  // first drive letter
-
-    if (cDisks > 8)              // Not above 8 disks
-        cDisks = 8;
-
-    // get boot manager disk and info
-    if ((arc = doshGetBootManager(&usBmDisk,
-                                  NULL,
-                                  &BmInfo)) != NO_ERROR)
-    {
-        *pusContext = 1;
-        return (arc);
-    }
-    // on each disk, read primary partitions
-    for (i = 1; i <= cDisks; i++)
-    {
-        if ((arc = GetPrimaryPartitions(&pPartitionInfos,
-                                        &ppiTemp,
-                                        &osCount,
-                                        &cLetter,
-                                        usBmDisk,
-                                        usBmDisk ? &BmInfo : 0,
-                                        i)))
+    USHORT          cPartitions = 0;        // bootable partition count
+
+    if (!ppList)
+        return (ERROR_INVALID_PARAMETER);
+
+    if (!(arc = doshQueryLVMInfo(&pLVMInfo)))
+    {
+        // LVM installed:
+        arc = doshReadLVMPartitions(pLVMInfo,         // in: LVM info
+                                    &pPartitionInfos, // out: partitions array
+                                    &cPartitions);      // out: partitions count
+        // copied to output below
+
+        if (arc)
         {
-            *pusContext = 2;
-            return (arc);
+            // error: start over
+            doshFreeLVMInfo(pLVMInfo);
+            CleanPartitionInfos(pPartitionInfos);
+            pPartitionInfos = NULL;
+            cPartitions = 0;
         }
     }
 
-    if (usBmDisk)
-    {
-        // boot manager found:
-        // on each disk, read extended partition
-        // with logical drives
-        for (i = 1; i <= cDisks; i++)
+    if (arc)
+    {
+        // LVM not installed, or failed:
+        // parse partitions manually
+        PAR_INFO        BmInfo;     // BootManager partition
+        USHORT          usBmDisk;     // BootManager disk
+        USHORT          cDisks = doshQueryDiskCount();    // physical disks count
+        USHORT          i;
+
+        CHAR            cLetter = 'C';  // first drive letter
+
+        // start over
+        arc = NO_ERROR;
+
+        if (cDisks > 8)              // Not above 8 disks
+            cDisks = 8;
+
+        // get boot manager disk and info
+        if ((arc = doshGetBootManager(&usBmDisk,
+                                      NULL,
+                                      &BmInfo)) != NO_ERROR)
         {
-            if ((arc = GetExtendedPartition(&pPartitionInfos,
-                                            &ppiTemp,
-                                            &osCount,
-                                            &cLetter,
-                                            &BmInfo,
-                                            i)))
+            *pusContext = 1;
+        }
+        else
+        {
+            // on each disk, read primary partitions
+            for (i = 1; i <= cDisks; i++)
             {
-                *pusContext = 3;
-                return (arc);
+                if ((arc = GetPrimaryPartitions(&pPartitionInfos,
+                                                &ppiTemp,
+                                                &cPartitions,
+                                                &cLetter,
+                                                usBmDisk,
+                                                usBmDisk ? &BmInfo : 0,
+                                                i)))
+                {
+                    *pusContext = 2;
+                }
+            }
+
+            if (!arc && usBmDisk)
+            {
+                // boot manager found:
+                // on each disk, read extended partition
+                // with logical drives
+                for (i = 1; i <= cDisks; i++)
+                {
+                    if ((arc = GetExtendedPartition(&pPartitionInfos,
+                                                    &ppiTemp,
+                                                    &cPartitions,
+                                                    &cLetter,
+                                                    &BmInfo,
+                                                    i)))
+                    {
+                        *pusContext = 3;
+                    }
+                }
+            }
+        } // end else if ((arc = doshGetBootManager(&usBmDisk,
+    } // end else if (!doshQueryLVMInfo(&pLVMInfo))
+
+    if (!arc)
+    {
+        // no error so far:
+        *pusContext = 0;
+
+        *ppList = NEW(PARTITIONSLIST);
+        if (!(*ppList))
+            arc = ERROR_NOT_ENOUGH_MEMORY;
+        else
+        {
+            ZERO(*ppList);
+
+            (*ppList)->pPartitionInfo = pPartitionInfos;
+            (*ppList)->cPartitions = cPartitions;
+
+            _Pmpf((__FUNCTION__ ": returning %d partitions", cPartitions));
+        }
+    }
+
+    if (arc)
+        CleanPartitionInfos(pPartitionInfos);
+
+    _Pmpf((__FUNCTION__ ": exiting, arc = %d", arc));
+
+    return (arc);
+}
+
+/*
+ *@@ doshFreePartitionsList:
+ *      this frees the resources allocated by
+ *      doshGetPartitionsList.
+ *
+ *@@added V0.9.0 [umoeller]
+ */
+
+APIRET doshFreePartitionsList(PPARTITIONSLIST ppList)
+{
+    if (!ppList)
+        return (ERROR_INVALID_PARAMETER);
+    else
+    {
+        CleanPartitionInfos(ppList->pPartitionInfo);
+        doshFreeLVMInfo(ppList->pLVMInfo);
+        free(ppList);
+    }
+
+    return (NO_ERROR);
+}
+
+/********************************************************************
+ *
+ *   LVM declarations
+ *
+ ********************************************************************/
+
+/*
+ *@@category: Helpers\Control program helpers\Partitions info\Quick LVM Interface
+ *      functions for transparently interfacing LVM.DLL.
+ */
+
+typedef unsigned char       BOOLEAN;
+typedef unsigned short int  CARDINAL16;
+typedef unsigned long       CARDINAL32;
+typedef unsigned int        CARDINAL;
+typedef unsigned long       DoubleWord;
+
+#ifdef ADDRESS
+#undef ADDRESS
+#endif
+
+typedef void* ADDRESS;
+
+#pragma pack(1)
+
+#define DISK_NAME_SIZE          20
+#define FILESYSTEM_NAME_SIZE    20
+#define PARTITION_NAME_SIZE     20
+#define VOLUME_NAME_SIZE        20
+
+/*
+ *@@ Drive_Control_Record:
+ *      invariant for a disk drive.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Drive_Control_Record
+{
+    CARDINAL32   Drive_Number;                      // OS/2 Drive Number for this drive.
+    CARDINAL32   Drive_Size;                        // The total number of sectors on the drive.
+    DoubleWord   Drive_Serial_Number;               // The serial number assigned to this drive.  For info. purposes only.
+    ADDRESS      Drive_Handle;                      // Handle used for operations on the disk that this record corresponds to.
+    CARDINAL32   Cylinder_Count;                    // The number of cylinders on the drive.
+    CARDINAL32   Heads_Per_Cylinder;                // The number of heads per cylinder for this drive.
+    CARDINAL32   Sectors_Per_Track;                 // The number of sectors per track for this drive.
+    BOOLEAN      Drive_Is_PRM;                      // Set to TRUE if this drive is a PRM.
+    BYTE         Reserved[3];                       // Alignment.
+} Drive_Control_Record;
+
+/*
+ *@@ Drive_Control_Array:
+ *      returned by the Get_Drive_Control_Data function
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Drive_Control_Array
+{
+    Drive_Control_Record *   Drive_Control_Data;    // An array of drive control records.
+    CARDINAL32               Count;                 // The number of entries in the array of drive control records.
+} Drive_Control_Array;
+
+/*
+ *@@ Drive_Information_Record:
+ *      defines the information that can be changed for a specific disk drive.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Drive_Information_Record
+{
+    CARDINAL32   Total_Available_Sectors;           // The number of sectors on the disk which are not currently assigned to a partition.
+    CARDINAL32   Largest_Free_Block_Of_Sectors;     // The number of sectors in the largest contiguous block of available sectors.
+    BOOLEAN      Corrupt_Partition_Table;           // If TRUE, then the partitioning information found on the drive is incorrect!
+    BOOLEAN      Unusable;                          // If TRUE, the drive's MBR is not accessible and the drive can not be partitioned.
+    BOOLEAN      IO_Error;                          // If TRUE, then the last I/O operation on this drive failed!
+    BOOLEAN      Is_Big_Floppy;                     // If TRUE, then the drive is a PRM formatted as a big floppy (i.e. the old style removable media support).
+    char         Drive_Name[DISK_NAME_SIZE];        // User assigned name for this disk drive.
+} Drive_Information_Record;
+
+/*
+ *@@ Partition_Information_Record:
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Partition_Information_Record
+{
+    ADDRESS      Partition_Handle;
+            // The handle used to perform operations on this partition.
+    ADDRESS      Volume_Handle;
+            // If this partition is part of a volume, this will be the handle of
+            // the volume.  If this partition is NOT part of a volume, then this
+            // handle will be 0.
+    ADDRESS      Drive_Handle;
+            // The handle for the drive this partition resides on.
+    DoubleWord   Partition_Serial_Number;
+            // The serial number assigned to this partition.
+    CARDINAL32   Partition_Start;
+            // The LBA of the first sector of the partition.
+    CARDINAL32   True_Partition_Size;
+            // The total number of sectors comprising the partition.
+    CARDINAL32   Usable_Partition_Size;
+            // The size of the partition as reported to the IFSM.  This is the
+            // size of the partition less any LVM overhead.
+    CARDINAL32   Boot_Limit;
+            // The maximum number of sectors from this block of free space that
+            // can be used to create a bootable partition if you allocate from the
+            // beginning of the block of free space.
+    BOOLEAN      Spanned_Volume;
+            // TRUE if this partition is part of a multi-partition volume.
+    BOOLEAN      Primary_Partition;
+            // True or False.  Any non-zero value here indicates that this partition
+            // is a primary partition.  Zero here indicates that this partition is
+            // a "logical drive" - i.e. it resides inside of an extended partition.
+    BYTE         Active_Flag;
+            // 80 = Partition is marked as being active.
+            // 0 = Partition is not active.
+    BYTE         OS_Flag;
+            // This field is from the partition table.  It is known as the OS flag,
+            // the Partition Type Field, Filesystem Type, and various other names.
+            //      Values of interest
+            //      If this field is: (values are in hex)
+            //      07 = The partition is a compatibility partition formatted for use
+            //      with an installable filesystem, such as HPFS or JFS.
+            //      00 = Unformatted partition
+            //      01 = FAT12 filesystem is in use on this partition.
+            //      04 = FAT16 filesystem is in use on this partition.
+            //      0A = OS/2 Boot Manager Partition
+            //      35 = LVM partition
+            //      84 = OS/2 FAT16 partition which has been relabeled by Boot Manager to "Hide" it.
+    BYTE         Partition_Type;
+            // 0 = Free Space
+            // 1 = LVM Partition (Part of an LVM Volume.)
+            // 2 = Compatibility Partition
+            // All other values are reserved for future use.
+    BYTE         Partition_Status;
+            // 0 = Free Space
+            // 1 = In Use - i.e. already assigned to a volume.
+            // 2 = Available - i.e. not currently assigned to a volume.
+    BOOLEAN      On_Boot_Manager_Menu;
+            // Set to TRUE if this partition is not part of a Volume yet is on the
+            // Boot Manager Menu.
+    BYTE         Reserved;
+            // Alignment.
+    char         Volume_Drive_Letter;
+            // The drive letter assigned to the volume that this partition is a part of.
+    char         Drive_Name[DISK_NAME_SIZE];
+            // User assigned name for this disk drive.
+    char         File_System_Name[FILESYSTEM_NAME_SIZE];
+            // The name of the filesystem in use on this partition, if it is known.
+    char         Partition_Name[PARTITION_NAME_SIZE];
+            // The user assigned name for this partition.
+    char         Volume_Name[VOLUME_NAME_SIZE];
+            // If this partition is part of a volume, then this will be the
+            // name of the volume that this partition is a part of.  If this
+            // record represents free space, then the Volume_Name will be
+            // "FREE SPACE xx", where xx is a unique numeric ID generated by
+            // LVM.DLL.  Otherwise it will be an empty string.
+} Partition_Information_Record;
+
+// The following defines are for use with the Partition_Type field in the
+// Partition_Information_Record.
+#define FREE_SPACE_PARTITION     0
+#define LVM_PARTITION            1
+#define COMPATIBILITY_PARTITION  2
+
+// The following defines are for use with the Partition_Status field in the
+// Partition_Information_Record.
+#define PARTITION_IS_IN_USE      1
+#define PARTITION_IS_AVAILABLE   2
+#define PARTITION_IS_FREE_SPACE  0
+
+/*
+ *@@ Partition_Information_Array:
+ *      returned by various functions in the LVM Engine.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Partition_Information_Array
+{
+    Partition_Information_Record * Partition_Array; // An array of Partition_Information_Records.
+    CARDINAL32                     Count;           // The number of entries in the Partition_Array.
+} Partition_Information_Array;
+
+/*
+ *@@ Volume_Information_Record:
+ *      variable information for a volume.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _Volume_Information_Record
+{
+    CARDINAL32 Volume_Size;
+            // The number of sectors comprising the volume.
+    CARDINAL32 Partition_Count;
+            // The number of partitions which comprise this volume.
+    CARDINAL32 Drive_Letter_Conflict;
+            // 0   indicates that the drive letter preference for this volume is unique.
+            // 1   indicates that the drive letter preference for this volume
+            //       is not unique, but this volume got its preferred drive letter anyway.
+            // 2   indicates that the drive letter preference for this volume
+            //       is not unique, and this volume did NOT get its preferred drive letter.
+            // 4   indicates that this volume is currently "hidden" - i.e. it has
+            //       no drive letter preference at the current time.
+    BOOLEAN    Compatibility_Volume;
+            // TRUE if this is for a compatibility volume, FALSE otherwise.
+    BOOLEAN    Bootable;
+            // Set to TRUE if this volume appears on the Boot Manager menu, or if it is
+            // a compatibility volume and its corresponding partition is the first active
+            // primary partition on the first drive.
+    char       Drive_Letter_Preference;
+            // The drive letter that this volume desires to be.
+    char       Current_Drive_Letter;
+            // The drive letter currently used to access this volume.
+            // May be different than Drive_Letter_Preference if there was a conflict ( i.e. Drive_Letter_Preference
+            // is already in use by another volume ).
+    char       Initial_Drive_Letter;
+            // The drive letter assigned to this volume by the operating system
+            // when LVM was started. This may be different from the
+            // Drive_Letter_Preference if there were conflicts, and
+            // may be different from the Current_Drive_Letter.  This
+            // will be 0x0 if the Volume did not exist when the LVM Engine
+            // was opened (i.e. it was created during this LVM session).
+    BOOLEAN    New_Volume;
+            // Set to FALSE if this volume existed before the LVM Engine was
+            // opened.  Set to TRUE if this volume was created after the LVM
+            // Engine was opened.
+    BYTE       Status;
+            // 0 = None.
+            // 1 = Bootable
+            // 2 = Startable
+            // 3 = Installable.
+    BYTE       Reserved_1;
+    char       Volume_Name[VOLUME_NAME_SIZE];
+            // The user assigned name for this volume.
+    char       File_System_Name[FILESYSTEM_NAME_SIZE];
+            // The name of the filesystem in use on this partition, if it
+            // is known.
+} Volume_Information_Record;
+
+#pragma pack()
+
+/********************************************************************
+ *
+ *   Quick LVM Interface API
+ *
+ ********************************************************************/
+
+/*
+ *@@ LVMINFOPRIVATE:
+ *      private structure used by doshQueryLVMInfo.
+ *      This is what the LVMINFO pointer really
+ *      points to.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+typedef struct _LVMINFOPRIVATE
+{
+    LVMINFO             LVMInfo;            // public structure (dosh.h)
+
+    // function pointers resolved from LVM.DLL
+
+    void (* _System     Open_LVM_Engine)(BOOLEAN Ignore_CHS,
+                                         CARDINAL32 *Error_Code);
+
+    void (* _System     Free_Engine_Memory)(ADDRESS Object);
+
+    void (* _System     Close_LVM_Engine)(void);
+
+    Drive_Control_Array (* _System
+                        Get_Drive_Control_Data)(CARDINAL32 *Error_Code);
+
+    Drive_Information_Record (* _System
+                        Get_Drive_Status)(ADDRESS Drive_Handle,
+                                          CARDINAL32 *Error_Code);
+
+    Partition_Information_Array (* _System
+                        Get_Partitions)(ADDRESS Handle,
+                                        CARDINAL32 *Error_Code);
+
+    Volume_Information_Record (*_System
+                        Get_Volume_Information)(ADDRESS Volume_Handle,
+                                                CARDINAL32 *Error_Code);
+
+} LVMINFOPRIVATE, *PLVMINFOPRIVATE;
+
+#define LVM_ERROR_FIRST             20000
+
+/*
+ *@@ doshQueryLVMInfo:
+ *      creates an LVMINFO structure if LVM is installed.
+ *      Returns that structure (which the caller must free
+ *      using doshFreeLVMInfo) or NULL if LVM.DLL was not
+ *      found along the LIBPATH.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+APIRET doshQueryLVMInfo(PLVMINFO *ppLVMInfo)
+{
+    APIRET          arc = NO_ERROR;
+    CHAR            szError[100];
+    PLVMINFOPRIVATE pLVMInfo = NULL;
+    HMODULE         hmodLVM = NULLHANDLE;
+
+    if (!(arc = DosLoadModule(szError,
+                              sizeof(szError),
+                              "LVM",
+                              &hmodLVM)))
+    {
+        // got LVM.DLL:
+        pLVMInfo = NEW(LVMINFOPRIVATE);
+        if (!pLVMInfo)
+            arc = ERROR_NOT_ENOUGH_MEMORY;
+        else
+        {
+            // array of function pointers to be resolved from LVM.DLL
+            RESOLVEFUNCTION     aFunctions[] =
+                    {
+                        "Open_LVM_Engine", (PFN*)&pLVMInfo->Open_LVM_Engine,
+                        "Free_Engine_Memory", (PFN*)&pLVMInfo->Free_Engine_Memory,
+                        "Close_LVM_Engine", (PFN*)&pLVMInfo->Close_LVM_Engine,
+                        "Get_Drive_Control_Data", (PFN*)&pLVMInfo->Get_Drive_Control_Data,
+                        "Get_Drive_Status", (PFN*)&pLVMInfo->Get_Drive_Status,
+                        "Get_Partitions", (PFN*)&pLVMInfo->Get_Partitions,
+                        "Get_Volume_Information", (PFN*)&pLVMInfo->Get_Volume_Information
+                    };
+            ULONG               ul;
+
+            ZERO(pLVMInfo);
+
+            pLVMInfo->LVMInfo.hmodLVM = hmodLVM;
+
+            // now resolve function pointers
+            for (ul = 0;
+                 ul < ARRAYITEMCOUNT(aFunctions);
+                 ul++)
+            {
+                PRESOLVEFUNCTION pFuncThis = &aFunctions[ul];
+                arc = DosQueryProcAddr(hmodLVM,
+                                       0,               // ordinal, ignored
+                                       (PSZ)pFuncThis->pcszFunctionName,
+                                       pFuncThis->ppFuncAddress);
+                if (!pFuncThis->ppFuncAddress)
+                    arc = ERROR_INVALID_NAME;
+
+                if (arc)
+                    break;
             }
         }
     }
 
-    *ppPartitionInfo = pPartitionInfos;
-    *pusPartitionCount = osCount;
-
-    return (NO_ERROR);  // 0
-}
-
-/*
- *@@ doshFreePartitionsList:
- *      this frees the resources allocated by
- *      doshGetPartitionsList.
- *
- *@@added V0.9.0 [umoeller]
- */
-
-APIRET doshFreePartitionsList(PPARTITIONINFO pPartitionInfo)
-{
-    PPARTITIONINFO ppiThis = NULL;
-    ppiThis = pPartitionInfo;
-    while (ppiThis)
-    {
-        PPARTITIONINFO ppiNext = ppiThis->pNext;
-        free(ppiThis);
-        ppiThis = ppiNext;
+    if (arc)
+        doshFreeLVMInfo((PLVMINFO)pLVMInfo);
+    else
+        *ppLVMInfo = (PLVMINFO)pLVMInfo;
+
+    return (arc);
+}
+
+/*
+ *@@ doshReadLVMPartitions:
+ *      using the LVMINFO parameter from doshQueryLVMInfo,
+ *      builds an array of PARTITIONINFO structures with
+ *      the data returned from LVM.DLL.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+APIRET doshReadLVMPartitions(PLVMINFO pInfo,         // in: LVM info
+                             PPARTITIONINFO *ppPartitionInfo, // out: partitions array
+                             PUSHORT pcPartitions)      // out: partitions count
+{
+    APIRET          arc = NO_ERROR;
+    CARDINAL32      Error = 0;
+
+    PARTITIONINFO   *pPartitionInfos = NULL, // linked list of all partitions
+                    *ppiTemp = NULL;
+    USHORT          cPartitions = 0;        // bootable partition count
+    PLVMINFOPRIVATE pLVMInfo = (PLVMINFOPRIVATE)pInfo;
+
+    _Pmpf((__FUNCTION__ ": entering"));
+
+    if (!pLVMInfo)
+        return (ERROR_INVALID_PARAMETER);
+
+    // initialize LVM engine
+    pLVMInfo->Open_LVM_Engine(TRUE,
+                              &Error);
+
+    _Pmpf(("  Open_LVM_Engine Error: %d"));
+
+    if (!Error)
+    {
+        Drive_Control_Array DCA = pLVMInfo->Get_Drive_Control_Data(&Error);
+                        // member records to be freed
+
+        _Pmpf(("  Get_Drive_Control_Data Error: %d, drive count: %d", Error, DCA.Count));
+
+        if (    (!Error)
+             && (DCA.Count)
+           )
+        {
+            // DCA.Drive_Control_Data now contains drive information records;
+            // this must be freed
+            ULONG   ulDisk;
+
+            for (ulDisk = 0;
+                 ulDisk < DCA.Count;
+                 ulDisk++)
+            {
+                Drive_Control_Record *pDriveControlRecord
+                    = &DCA.Drive_Control_Data[ulDisk];
+                ADDRESS hDrive = pDriveControlRecord->Drive_Handle;
+
+                Drive_Information_Record pDriveInfoRecord
+                    = pLVMInfo->Get_Drive_Status(hDrive,
+                                                 &Error);
+
+                _Pmpf(("  drive %d Get_Drive_Status Error: %d", ulDisk, Error));
+
+                if (!Error)
+                {
+                    Partition_Information_Array PIA
+                        = pLVMInfo->Get_Partitions(hDrive,
+                                                   &Error);
+
+                    _Pmpf(("    Get_Partitions Error: %d", Error));
+
+                    if (!Error)
+                    {
+                        // PIA.Partition_Array now contains
+                        // Partition_Information_Record; must be freed
+
+                        // now go thru partitions of this drive
+                        ULONG ulPart;
+                        for (ulPart = 0;
+                             ulPart < PIA.Count;
+                             ulPart++)
+                        {
+                            Partition_Information_Record *pPartition
+                                = &PIA.Partition_Array[ulPart];
+                            Volume_Information_Record VolumeInfo;
+
+                            const char  *pcszBootName = NULL; // for now
+                            BOOL        fBootable = FALSE;
+
+                            if (pPartition->Volume_Handle)
+                            {
+                                // this partition is part of a volume:
+                                // only then can it be bootable...
+                                // get the volume info
+                                VolumeInfo
+                                    = pLVMInfo->Get_Volume_Information(pPartition->Volume_Handle,
+                                                                       &Error);
+                                pcszBootName = VolumeInfo.Volume_Name;
+
+                                fBootable = (VolumeInfo.Status == 1);
+                            }
+
+
+                            if (arc = AppendPartition(&pPartitionInfos,
+                                                      &ppiTemp,
+                                                      &cPartitions,
+                                                      ulDisk + 1,
+                                                      pcszBootName,
+                                                      pPartition->Volume_Drive_Letter,
+                                                      pPartition->OS_Flag,  // FS type
+                                                      pPartition->Primary_Partition,
+                                                      fBootable,
+                                                      pPartition->True_Partition_Size))
+                                break;
+                        }
+
+                        // clean up partitions
+                        pLVMInfo->Free_Engine_Memory(PIA.Partition_Array);
+                    }
+                }
+                else
+                    // error:
+                    break;
+            }
+
+            // clean up drive data
+            pLVMInfo->Free_Engine_Memory(DCA.Drive_Control_Data);
+        }
     }
-    return (NO_ERROR);
-}
-
-
+
+    // close LVM
+    pLVMInfo->Close_LVM_Engine();
+
+    if (Error)
+    {
+        // if we got an error, return it with the
+        // LVM error offset
+        arc = LVM_ERROR_FIRST + Error;
+
+        CleanPartitionInfos(pPartitionInfos);
+    }
+
+    if (!arc)
+    {
+        *ppPartitionInfo = pPartitionInfos;
+        *pcPartitions = cPartitions;
+    }
+
+    _Pmpf((__FUNCTION__ ": exiting, arg = %d", arc));
+
+    return (arc);
+}
+
+/*
+ *@@ doshFreeLVMInfo:
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+VOID doshFreeLVMInfo(PLVMINFO pInfo)
+{
+    if (pInfo)
+    {
+        if (pInfo->hmodLVM)
+            DosFreeModule(pInfo->hmodLVM);
+
+        free(pInfo);
+    }
+}
Index: trunk/src/helpers/gpih.c
===================================================================
--- trunk/src/helpers/gpih.c	(revision 55)
+++ trunk/src/helpers/gpih.c	(revision 56)
@@ -102,4 +102,58 @@
 
 static HMTX     G_hmtxLCIDs = NULLHANDLE;
+
+/* ******************************************************************
+ *
+ *   Rectangle helpers
+ *
+ ********************************************************************/
+
+/*
+ *@@ gpihIsPointInRect:
+ *      like WinPtInRect, but doesn't need a HAB.
+ *
+ *      NOTE: as opposed to WinPtInRect, prcl is
+ *      considered inclusive, that is, TRUE is
+ *      returned even if x or y are exactly
+ *      the same as prcl->xRight or prcl->yTop.
+ *
+ *@@added V0.9.9 (2001-02-28) [umoeller]
+ */
+
+BOOL gpihIsPointInRect(PRECTL prcl,
+                       LONG x,
+                       LONG y)
+{
+    if (prcl)
+    {
+        return (    (x >= prcl->xLeft)
+                 && (x <= prcl->xRight)
+                 && (y >= prcl->yBottom)
+                 && (y <= prcl->yTop)
+               );
+    }
+
+    return (FALSE);
+}
+
+/*
+ *@@ gpihInflateRect:
+ *      Positive l will make the rectangle larger.
+ *      Negative l will make the rectangle smaller.
+ *
+ *@@added V0.9.9 (2001-02-28) [umoeller]
+ */
+
+VOID gpihInflateRect(PRECTL prcl,
+                     LONG l)
+{
+    if (prcl && l)
+    {
+        prcl->xLeft -= l;
+        prcl->yBottom -= l;
+        prcl->xRight += l;
+        prcl->yTop += l;
+    }
+}
 
 /* ******************************************************************
Index: trunk/src/helpers/helpers_post.in
===================================================================
--- trunk/src/helpers/helpers_post.in	(revision 55)
+++ trunk/src/helpers/helpers_post.in	(revision 56)
@@ -103,5 +103,5 @@
 $(OUTPUTDIR)\dosh2.obj:      $(@B).c $(HLPINC)\dosh.h \
                $(PROJECTINC)\setup.h \
-               $(HLPINC)\stringh.h
+               $(HLPINC)\ensure.h $(HLPINC)\standards.h $(HLPINC)\stringh.h
 
 $(OUTPUTDIR)\eah.obj:       $(@B).c $(HLPINC)\$(@B).h \
Index: trunk/src/helpers/stringh.c
===================================================================
--- trunk/src/helpers/stringh.c	(revision 55)
+++ trunk/src/helpers/stringh.c	(revision 56)
@@ -92,5 +92,6 @@
  *      Besides, this is guaranteed to only return -1, 0,
  *      or +1, while strcmp can return any positive or
- *      negative value.
+ *      negative value. This is useful for tree comparison
+ *      funcs.
  *
  *@@added V0.9.9 (2001-02-16) [umoeller]
@@ -102,4 +103,31 @@
     {
         int i = strcmp(p1, p2);
+        if (i < 0) return (-1);
+        if (i > 0) return (+1);
+    }
+    else if (p1)
+        // but p2 is NULL: p1 greater than p2 then
+        return (+1);
+    else if (p2)
+        // but p1 is NULL: p1 less than p2 then
+        return (-1);
+
+    // return 0 if strcmp returned 0 above or both strings are NULL
+    return (0);
+}
+
+/*
+ *@@ strhicmp:
+ *      like strhcmp, but compares without respect
+ *      to case.
+ *
+ *@@added V0.9.9 (2001-04-07) [umoeller]
+ */
+
+int strhicmp(const char *p1, const char *p2)
+{
+    if (p1 && p2)
+    {
+        int i = stricmp(p1, p2);
         if (i < 0) return (-1);
         if (i > 0) return (+1);
Index: trunk/src/helpers/tree.c
===================================================================
--- trunk/src/helpers/tree.c	(revision 55)
+++ trunk/src/helpers/tree.c	(revision 56)
@@ -24,11 +24,7 @@
  *      a tree-like structure.
  *
- *      For this, the functions here use the TREE structure. You can
- *      easily see that this has the "left" and "right" members,
- *      which make up the tree.
- *
- *      In addition, each tree has a "tree root" item, from which all
- *      other tree nodes can be reached by following the "left" and
- *      "right" pointers.
+ *      While lists have "next" and "previous" pointers, trees have
+ *      "left" and "right" pointers which keep the tree sorted at
+ *      all times.
  *
  *      Per definition, in our trees, if you follow the "left" pointer,
@@ -36,4 +32,15 @@
  *      Reversely, following the "right" pointer will lead you to a
  *      node which is "less than" the current node.
+ *
+ *      What is considered "less" or "greater" is determined by a
+ *      comparison callback to be supplied by the caller.
+ *
+ *      For this, the functions here use the TREE structure. You can
+ *      easily see that this has the "left" and "right" members,
+ *      which make up the tree.
+ *
+ *      In addition, each tree has a "tree root" item, from which all
+ *      other tree nodes can be reached by following the "left" and
+ *      "right" pointers.
  *
  *      The implementation here has the following characteristics:
@@ -66,5 +73,6 @@
  *      that the first member in the structure is a TREE structure
  *      (i.e. it has the left, right, parent, id, and colour members).
- *      The tree functions don't care what follows.
+ *      The tree functions don't care what follows, since they do
+ *      not manage any memory themselves.
  *
  *      So the implementation here is slightly different from the
@@ -106,5 +114,5 @@
  *         the TREE structure instead. If this flavor is used, an
  *         internal comparison function is used for comparing the
- *         "id" fields, which are plain ULONGs.
+ *         "id" fields, which are assumed to be plain ULONGs.
  *
  *      <B>Trees vs. linked lists</B>
@@ -139,5 +147,5 @@
  *      -- As opposed to a LISTNODE, the TREE structure (which
  *         represents a tree node) does not contain a data pointer,
- *         as said above.
+ *         as said above. The caller must do all memory management.
  *
  *@@added V0.9.5 (2000-09-29) [umoeller]
@@ -245,6 +253,6 @@
  +
  +          treeInsertID(&TreeRoot,
- +                     (TREE*)pTreeItem,
- +                     FALSE);
+ +                       (TREE*)pTreeItem,
+ +                       FALSE);
  *
  *      Returns:
@@ -699,7 +707,6 @@
                    unsigned long id)
 {
-    TREE
-       *current = *root,
-       *found = NULL;
+    TREE    *current = *root,
+            *found = NULL;
 
     while (current != TREE_NULL)
@@ -725,7 +732,6 @@
                    unsigned long idFind)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
@@ -752,7 +758,6 @@
                      FNTREE_COMPARE_NODES *comp)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
@@ -780,7 +785,6 @@
                      FNTREE_COMPARE_NODES *comp)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
@@ -807,7 +811,6 @@
                      FNTREE_COMPARE_NODES *comp)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
@@ -834,7 +837,6 @@
                      FNTREE_COMPARE_NODES *comp)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
@@ -861,7 +863,6 @@
                      FNTREE_COMPARE_NODES *comp)
 {
-    TREE
-       *current = *root,
-       *found;
+    TREE    *current = *root,
+            *found;
 
     found = NULL;
