Index: trunk/src/helpers/apps.c
===================================================================
--- trunk/src/helpers/apps.c	(revision 152)
+++ trunk/src/helpers/apps.c	(revision 153)
@@ -49,5 +49,4 @@
 #include "setup.h"                      // code generation and debugging options
 
-#include "helpers\apps.h"
 #include "helpers\dosh.h"
 #include "helpers\except.h"             // exception handling
@@ -57,4 +56,6 @@
 #include "helpers\winh.h"
 #include "helpers\xstring.h"
+
+#include "helpers\apps.h"
 
 /*
@@ -843,17 +844,19 @@
  *
  *@@added V0.9.12 (2001-05-26) [umoeller]
- */
-
-PSZ appQueryDefaultWin31Environment(VOID)
+ *@@changed V0.9.19 (2002-03-28) [umoeller]: now returning APIRET
+ */
+
+APIRET appQueryDefaultWin31Environment(PSZ *ppsz)
 {
+    APIRET arc = NO_ERROR;
     PSZ pszReturn = NULL;
     ULONG ulSize = 0;
-    // get default environment (from Win-OS/2 settings object)
-    // from OS2.INI
-    PSZ pszDefEnv = prfhQueryProfileData(HINI_USER,
+
+    // get default environment (from Win-OS/2 settings object) from OS2.INI
+    PSZ pszDefEnv;
+    if (pszDefEnv = prfhQueryProfileData(HINI_USER,
                                          "WINOS2",
                                          "PM_GlobalWindows31Settings",
-                                         &ulSize);
-    if (pszDefEnv)
+                                         &ulSize))
     {
         if (pszReturn = (PSZ)malloc(ulSize + 2))
@@ -871,10 +874,16 @@
             // okay.... now we got an OS/2-style environment
             // with 0, 0, 00 strings
-        }
+
+            *ppsz = pszReturn;
+        }
+        else
+            arc = ERROR_NOT_ENOUGH_MEMORY;
 
         free(pszDefEnv);
     }
-
-    return (pszReturn);
+    else
+        arc = ERROR_BAD_ENVIRONMENT;
+
+    return (arc);
 }
 
@@ -957,8 +966,9 @@
 
 /*
- *@@ appFixProgDetails:
+ *@@ appBuildProgDetails:
  *      extracted code from appStartApp to fix the
  *      given PROGDETAILS data to support the typical
- *      WPS stuff.
+ *      WPS stuff and allocate a single block of
+ *      shared memory containing all the data.
  *
  *      This is now used by XWP's progOpenProgram
@@ -966,28 +976,142 @@
  *      session hangs.
  *
- *      The caller is responsible for cleaning out
- *      the given three memory buffers.
+ *      As input, this takes a PROGDETAILS structure,
+ *      which is converted in various ways. In detail,
+ *      this supports:
+ *
+ *      -- starting "*" executables (command prompts
+ *         for OS/2, DOS, Win-OS/2);
+ *
+ *      -- starting ".CMD" and ".BAT" files as
+ *         PROGDETAILS.pszExecutable; for those, we
+ *         convert the executable and parameters to
+ *         start CMD.EXE or COMMAND.COM with the "/C"
+ *         parameter instead;
+ *
+ *      -- starting apps which are not fully qualified
+ *         and therefore assumed to be on the PATH
+ *         (for which doshSearchPath("PATH") is called).
+ *
+ *      Unless it is "*", PROGDETAILS.pszExecutable must
+ *      be a proper file name. The full path may be omitted
+ *      if it is on the PATH, but the extension (.EXE etc.)
+ *      must be given. You can use doshFindExecutable to
+ *      find executables if you don't know the extension.
+ *
+ *      This also handles and merges special and default
+ *      environments for the app to be started. The
+ *      following should be respected:
+ *
+ *      --  As with WinStartApp, if PROGDETAILS.pszEnvironment
+ *          is NULL, the new app inherits the default environment
+ *          from the shell.
+ *
+ *      --  However, if you specify an environment, you _must_
+ *          specify a complete environment. This function
+ *          will not merge environments. Use
+ *          appSetEnvironmentVar to change environment
+ *          variables in a complete environment set.
+ *
+ *      --  If PROGDETAILS specifies a Win-OS/2 session
+ *          and PROGDETAILS.pszEnvironment is empty,
+ *          this uses the default Win-OS/2 environment
+ *          from OS2.INI. See appQueryDefaultWin31Environment.
+ *
+ *      Even though this isn't clearly said in PMREF,
+ *      PROGDETAILS.swpInitial is important:
+ *
+ *      -- To start a session minimized, set fl to SWP_MINIMIZE.
+ *
+ *      -- To start a VIO session with auto-close disabled,
+ *         set the half-documented SWP_NOAUTOCLOSE flag (0x8000)
+ *         This flag is now in the newer toolkit headers.
+ *
+ *      In addition, this supports the following session
+ *      flags with ulFlags if PROG_DEFAULT is specified:
+ *
+ *      --  APP_RUN_FULLSCREEN: start a fullscreen session
+ *          for VIO, DOS, and Win-OS/2 programs. Otherwise
+ *          we start a windowed or (share) a seamless session.
+ *          Ignored if the program is PM.
+ *
+ *      --  APP_RUN_ENHANCED: for Win-OS/2 sessions, use
+ *          enhanced mode.
+ *          Ignored if the program is not Win-OS/2.
+ *
+ *      --  APP_RUN_STANDARD: for Win-OS/2 sessions, use
+ *          standard mode.
+ *          Ignored if the program is not Win-OS/2.
+ *
+ *      --  APP_RUN_SEPARATE: for Win-OS/2 sessions, use
+ *          a separate session.
+ *          Ignored if the program is not Win-OS/2.
+ *
+ *      If NO_ERROR is returned, *ppDetails receives a
+ *      new buffer of shared memory containing all the
+ *      data packed together.
+ *
+ *      The shared memory is allocated unnamed and
+ *      with OBJ_GETTABLE. It is the responsibility
+ *      of the caller to call DosFreeMem on that buffer.
+ *
+ *      Returns:
+ *
+ *      --  NO_ERROR
+ *
+ *      --  ERROR_INVALID_PARAMETER: pcProgDetails or
+ *          ppDetails is NULL; or PROGDETAILS.pszExecutable is NULL.
+ *
+ *      --  ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND:
+ *          PROGDETAILS.pszExecutable and/or PROGDETAILS.pszStartupDir
+ *          are invalid.
+ *          A NULL PROGDETAILS.pszStartupDir is supported though.
+ *
+ *      --  ERROR_BAD_FORMAT
+ *
+ *      --  ERROR_BAD_ENVIRONMENT: environment is larger than 60.000 bytes.
+ *
+ *      --  ERROR_NOT_ENOUGH_MEMORY
+ *
+ *      plus the error codes from doshQueryPathAttr, doshSearchPath,
+ *      appParseEnvironment, appSetEnvironmentVar, and appConvertEnvironment.
  *
  *@@added V0.9.18 (2002-03-27) [umoeller]
- */
-
-APIRET appFixProgDetails(PPROGDETAILS pDetails,             // out: fixed program spec (req.)
-                         const PROGDETAILS *pcProgDetails,  // in: program spec (req.)
-                         ULONG ulFlags,                     // in: APP_RUN_* flags or 0
-                         PXSTRING pstrExecutablePatched,    // in: init'ed XSTRING, out: to be freed
-                         PXSTRING pstrParamsPatched,        // in: init'ed XSTRING, out: to be freed
-                         PSZ *ppszWinOS2Env)                // in: ptr to NULL, out: memory to be freed
+ *@@changed V0.9.19 (2002-03-28) [umoeller]: now allocating contiguous buffer
+ */
+
+APIRET appBuildProgDetails(PPROGDETAILS *ppDetails,           // out: shared mem with fixed program spec (req.)
+                           const PROGDETAILS *pcProgDetails,  // in: program spec (req.)
+                           ULONG ulFlags)                     // in: APP_RUN_* flags or 0
 {
     APIRET          arc = NO_ERROR;
 
-    memcpy(pDetails, pcProgDetails, sizeof(PROGDETAILS));
+    XSTRING         strExecutablePatched,
+                    strParamsPatched;
+    PSZ             pszWinOS2Env = 0;
+
+    PROGDETAILS     Details;
+
+    *ppDetails = NULL;
+
+    if (!pcProgDetails && !ppDetails)
+        return (ERROR_INVALID_PARAMETER);
+
+    /*
+     * part 1:
+     *      fix up the PROGDETAILS fields
+     */
+
+    xstrInit(&strExecutablePatched, 0);
+    xstrInit(&strParamsPatched, 0);
+
+    memcpy(&Details, pcProgDetails, sizeof(PROGDETAILS));
             // pointers still point into old prog details buffer
-    pDetails->Length = sizeof(PROGDETAILS);
-    pDetails->progt.fbVisible = SHE_VISIBLE;
+    Details.Length = sizeof(PROGDETAILS);
+    Details.progt.fbVisible = SHE_VISIBLE;
 
     // all this only makes sense if this contains something...
     // besides, this crashed on string comparisons V0.9.9 (2001-01-27) [umoeller]
-    if (    (!pDetails->pszExecutable)
-         || (!(*(pDetails->pszExecutable)))
+    if (    (!Details.pszExecutable)
+         || (!Details.pszExecutable[0])
        )
         arc = ERROR_INVALID_PARAMETER;
@@ -996,5 +1120,5 @@
         ULONG           ulIsWinApp;
 
-        // memset(&pDetails->swpInitial, 0, sizeof(SWP));
+        // memset(&Details.swpInitial, 0, sizeof(SWP));
         // this wasn't a good idea... WPProgram stores stuff
         // in here, such as the "minimize on startup" -> SWP_MINIMIZE
@@ -1002,19 +1126,19 @@
         // duplicate parameters...
         // we need this for string manipulations below...
-        if (    (pDetails->pszParameters)
-             && (*pDetails->pszParameters)    // V0.9.18
+        if (    (Details.pszParameters)
+             && (Details.pszParameters[0])    // V0.9.18
            )
-            xstrcpy(pstrParamsPatched,
-                    pDetails->pszParameters,
+            xstrcpy(&strParamsPatched,
+                    Details.pszParameters,
                     0);
 
         #ifdef DEBUG_PROGRAMSTART
             _Pmpf((__FUNCTION__ ": old progc: 0x%lX", pcProgDetails->progt.progc));
-            _Pmpf(("  pszTitle: %s", (pDetails->pszTitle) ? pDetails->pszTitle : NULL));
-            _Pmpf(("  pszIcon: %s", (pDetails->pszIcon) ? pDetails->pszIcon : NULL));
+            _Pmpf(("  pszTitle: %s", (Details.pszTitle) ? Details.pszTitle : NULL));
+            _Pmpf(("  pszIcon: %s", (Details.pszIcon) ? Details.pszIcon : NULL));
         #endif
 
         // program type fixups
-        switch (pDetails->progt.progc)        // that's a ULONG
+        switch (Details.progt.progc)        // that's a ULONG
         {
             case ((ULONG)-1):       // we get that sometimes...
@@ -1023,7 +1147,7 @@
                 // V0.9.12 (2001-05-26) [umoeller]
                 ULONG ulDosAppType;
-                appQueryAppType(pDetails->pszExecutable,
+                appQueryAppType(Details.pszExecutable,
                                 &ulDosAppType,
-                                &pDetails->progt.progc);
+                                &Details.progt.progc);
             }
             break;
@@ -1033,14 +1157,14 @@
         if (ulFlags & APP_RUN_FULLSCREEN)
         {
-            if (pDetails->progt.progc == PROG_WINDOWABLEVIO)
-                pDetails->progt.progc = PROG_FULLSCREEN;
-            else if (pDetails->progt.progc == PROG_WINDOWEDVDM)
-                pDetails->progt.progc = PROG_VDM;
-        }
-
-        if (ulIsWinApp = appIsWindowsApp(pDetails->progt.progc))
+            if (Details.progt.progc == PROG_WINDOWABLEVIO)
+                Details.progt.progc = PROG_FULLSCREEN;
+            else if (Details.progt.progc == PROG_WINDOWEDVDM)
+                Details.progt.progc = PROG_VDM;
+        }
+
+        if (ulIsWinApp = appIsWindowsApp(Details.progt.progc))
         {
             if (ulFlags & APP_RUN_FULLSCREEN)
-                pDetails->progt.progc = (ulFlags & APP_RUN_ENHANCED)
+                Details.progt.progc = (ulFlags & APP_RUN_ENHANCED)
                                                 ? PROG_31_ENH
                                                 : PROG_31_STD;
@@ -1048,9 +1172,9 @@
             {
                 if (ulFlags & APP_RUN_STANDARD)
-                    pDetails->progt.progc = (ulFlags & APP_RUN_SEPARATE)
+                    Details.progt.progc = (ulFlags & APP_RUN_SEPARATE)
                                                 ? PROG_31_STDSEAMLESSVDM
                                                 : PROG_31_STDSEAMLESSCOMMON;
                 else if (ulFlags & APP_RUN_ENHANCED)
-                    pDetails->progt.progc = (ulFlags & APP_RUN_SEPARATE)
+                    Details.progt.progc = (ulFlags & APP_RUN_SEPARATE)
                                                 ? PROG_31_ENHSEAMLESSVDM
                                                 : PROG_31_ENHSEAMLESSCOMMON;
@@ -1058,5 +1182,5 @@
 
             // re-run V0.9.16 (2001-10-19) [umoeller]
-            ulIsWinApp = appIsWindowsApp(pDetails->progt.progc);
+            ulIsWinApp = appIsWindowsApp(Details.progt.progc);
         }
 
@@ -1068,5 +1192,5 @@
              */
 
-            if (!strcmp(pDetails->pszExecutable, "*"))
+            if (!strcmp(Details.pszExecutable, "*"))
             {
                 /*
@@ -1079,13 +1203,13 @@
                     // enhanced Win-OS/2 session:
                     PSZ psz = NULL;
-                    if (pstrParamsPatched->ulLength)
+                    if (strParamsPatched.ulLength)
                         // "/3 " + existing params
-                        psz = strdup(pstrParamsPatched->psz);
-
-                    xstrcpy(pstrParamsPatched, "/3 ", 0);
+                        psz = strdup(strParamsPatched.psz);
+
+                    xstrcpy(&strParamsPatched, "/3 ", 0);
 
                     if (psz)
                     {
-                        xstrcat(pstrParamsPatched, psz, 0);
+                        xstrcat(&strParamsPatched, psz, 0);
                         free(psz);
                     }
@@ -1096,7 +1220,7 @@
                     // cheat: WinStartApp doesn't support NULL
                     // for Win-OS2 sessions, so manually start winos2.com
-                    pDetails->pszExecutable = "WINOS2.COM";
+                    Details.pszExecutable = "WINOS2.COM";
                     // this is a DOS app, so fix this to DOS fullscreen
-                    pDetails->progt.progc = PROG_VDM;
+                    Details.progt.progc = PROG_VDM;
                 }
                 else
@@ -1105,5 +1229,5 @@
                     // set pszExecutable to NULL; this will
                     // have WinStartApp start a cmd shell
-                    pDetails->pszExecutable = NULL;
+                    Details.pszExecutable = NULL;
 
             } // end if (strcmp(pProgDetails->pszExecutable, "*") == 0)
@@ -1112,18 +1236,18 @@
                 // check if the executable is fully qualified; if so,
                 // check if the executable file exists
-                if (    (pDetails->pszExecutable[1] == ':')
-                     && (strchr(pDetails->pszExecutable, '\\'))
+                if (    (Details.pszExecutable[1] == ':')
+                     && (strchr(Details.pszExecutable, '\\'))
                    )
                 {
                     ULONG ulAttr;
-                    if (!(arc = doshQueryPathAttr(pDetails->pszExecutable,
+                    if (!(arc = doshQueryPathAttr(Details.pszExecutable,
                                                   &ulAttr)))
                     {
                         // make sure startup dir is really a directory
-                        if (pDetails->pszStartupDir)
+                        if (Details.pszStartupDir)
                         {
                             // it is valid to specify a startup dir of "C:"
-                            if (    (strlen(pDetails->pszStartupDir) > 2)
-                                 && (!(arc = doshQueryPathAttr(pDetails->pszStartupDir,
+                            if (    (strlen(Details.pszStartupDir) > 2)
+                                 && (!(arc = doshQueryPathAttr(Details.pszStartupDir,
                                                                &ulAttr)))
                                  && (!(ulAttr & FILE_DIRECTORY))
@@ -1139,11 +1263,11 @@
                     CHAR    szFQExecutable[CCHMAXPATH];
                     if (!(arc = doshSearchPath("PATH",
-                                               pDetails->pszExecutable,
+                                               Details.pszExecutable,
                                                szFQExecutable,
                                                sizeof(szFQExecutable))))
                     {
                         // alright, found it:
-                        xstrcpy(pstrExecutablePatched, szFQExecutable, 0);
-                        pDetails->pszExecutable = pstrExecutablePatched->psz;
+                        xstrcpy(&strExecutablePatched, szFQExecutable, 0);
+                        Details.pszExecutable = strExecutablePatched.psz;
                     }
                 }
@@ -1152,5 +1276,5 @@
                 {
                     PSZ pszExtension;
-                    switch (pDetails->progt.progc)
+                    switch (Details.progt.progc)
                     {
                         /*
@@ -1162,10 +1286,10 @@
                         case PROG_WINDOWABLEVIO:    // OS/2 window
                         {
-                            if (    (pszExtension = doshGetExtension(pDetails->pszExecutable))
+                            if (    (pszExtension = doshGetExtension(Details.pszExecutable))
                                  && (!stricmp(pszExtension, "CMD"))
                                )
                             {
-                                CallBatchCorrectly(pDetails,
-                                                   pstrParamsPatched,
+                                CallBatchCorrectly(&Details,
+                                                   &strParamsPatched,
                                                    "OS2_SHELL",
                                                    "CMD.EXE");
@@ -1177,10 +1301,10 @@
                         case PROG_WINDOWEDVDM:      // DOS window
                         {
-                            if (    (pszExtension = doshGetExtension(pDetails->pszExecutable))
+                            if (    (pszExtension = doshGetExtension(Details.pszExecutable))
                                  && (!stricmp(pszExtension, "BAT"))
                                )
                             {
-                                CallBatchCorrectly(pDetails,
-                                                   pstrParamsPatched,
+                                CallBatchCorrectly(&Details,
+                                                   &strParamsPatched,
                                                    NULL,
                                                    "COMMAND.COM");
@@ -1188,5 +1312,5 @@
                         }
                         break;
-                    } // end switch (pDetails->progt.progc)
+                    } // end switch (Details.progt.progc)
                 }
             }
@@ -1196,6 +1320,6 @@
         {
             if (    (ulIsWinApp)
-                 && (    (pDetails->pszEnvironment == NULL)
-                      || (!strlen(pDetails->pszEnvironment))
+                 && (    (Details.pszEnvironment == NULL)
+                      || (!strlen(Details.pszEnvironment))
                     )
                )
@@ -1209,58 +1333,152 @@
 
                 // get standard WIN-OS/2 environment
-                PSZ pszTemp = appQueryDefaultWin31Environment();
-
-                if (!(arc = appParseEnvironment(pszTemp,
-                                                &Env)))
+                PSZ pszTemp;
+                if (!(arc = appQueryDefaultWin31Environment(&pszTemp)))
                 {
-                    // now override KBD_CTRL_BYPASS=CTRL_ESC
-                    if (    (!(arc = appSetEnvironmentVar(&Env,
-                                                          "KBD_CTRL_BYPASS=CTRL_ESC",
-                                                          FALSE)))        // add last
-                         && (!(arc = appConvertEnvironment(&Env,
-                                                           ppszWinOS2Env,   // freed at bottom
-                                                           NULL)))
-                       )
-                        pDetails->pszEnvironment = *ppszWinOS2Env;
-
-                    appFreeEnvironment(&Env);
+                    if (!(arc = appParseEnvironment(pszTemp,
+                                                    &Env)))
+                    {
+                        // now override KBD_CTRL_BYPASS=CTRL_ESC
+                        if (    (!(arc = appSetEnvironmentVar(&Env,
+                                                              "KBD_CTRL_BYPASS=CTRL_ESC",
+                                                              FALSE)))        // add last
+                             && (!(arc = appConvertEnvironment(&Env,
+                                                               &pszWinOS2Env,   // freed at bottom
+                                                               NULL)))
+                           )
+                            Details.pszEnvironment = pszWinOS2Env;
+
+                        appFreeEnvironment(&Env);
+                    }
+
+                    free(pszTemp);
                 }
-
-                free(pszTemp);
             }
 
             if (!arc)
             {
-                if (!pDetails->pszTitle)
-                    pDetails->pszTitle = pDetails->pszExecutable;
+                // if no title is given, use the executable
+                if (!Details.pszTitle)
+                    Details.pszTitle = Details.pszExecutable;
 
                 // make sure params have a leading space
                 // V0.9.18 (2002-03-27) [umoeller]
-                if (pstrParamsPatched->ulLength)
+                if (strParamsPatched.ulLength)
                 {
-                    if (pstrParamsPatched->psz[0] != ' ')
+                    if (strParamsPatched.psz[0] != ' ')
                     {
                         XSTRING str2;
                         xstrInit(&str2, 0);
                         xstrcpy(&str2, " ", 1);
-                        xstrcats(&str2, pstrParamsPatched);
-                        xstrcpys(pstrParamsPatched, &str2);
+                        xstrcats(&str2, &strParamsPatched);
+                        xstrcpys(&strParamsPatched, &str2);
                         xstrClear(&str2);
                                 // we really need xstrInsert or something
                     }
-                    pDetails->pszParameters = pstrParamsPatched->psz;
+                    Details.pszParameters = strParamsPatched.psz;
                 }
                 else
-                    pDetails->pszParameters = "";
-
-                if (!pDetails->pszIcon)
-                    pDetails->pszIcon = "";
-
-                if (!pDetails->pszStartupDir)
-                    pDetails->pszStartupDir = "";
+                    // never pass null pointers
+                    Details.pszParameters = "";
+
+                // never pass null pointers
+                if (!Details.pszIcon)
+                    Details.pszIcon = "";
+
+                // never pass null pointers
+                if (!Details.pszStartupDir)
+                    Details.pszStartupDir = "";
 
             }
         }
     }
+
+    /*
+     * part 2:
+     *      pack the fixed PROGDETAILS fields
+     */
+
+    if (!arc)
+    {
+        ULONG   cb,
+                cbTitle,
+                cbExecutable,
+                cbParameters,
+                cbStartupDir,
+                cbIcon,
+                cbEnvironment;
+
+        // allocate a chunk of tiled memory from OS/2 to make sure
+        // this is aligned on a 64K memory (backed up by a 16-bit
+        // LDT selector); if it is not, and the environment
+        // crosses segments, it gets truncated!!
+        cb = sizeof(PROGDETAILS);
+        if (cbTitle = strhSize(Details.pszTitle))
+            cb += cbTitle;
+
+        if (cbExecutable = strhSize(Details.pszExecutable))
+            cb += cbExecutable;
+
+        if (cbParameters = strhSize(Details.pszParameters))
+            cb += cbParameters;
+
+        if (cbStartupDir = strhSize(Details.pszStartupDir))
+            cb += cbStartupDir;
+
+        if (cbIcon = strhSize(Details.pszIcon))
+            cb += cbIcon;
+
+        if (cbEnvironment = appQueryEnvironmentLen(Details.pszEnvironment))
+            cb += cbEnvironment;
+
+        if (cb > 60000)     // to be on the safe side
+            arc = ERROR_BAD_ENVIRONMENT; // 10;
+        else
+        {
+            PPROGDETAILS pNewProgDetails;
+            // alright, allocate the shared memory now
+            if (!(arc = DosAllocSharedMem((PVOID*)&pNewProgDetails,
+                                          NULL,
+                                          cb,
+                                          PAG_COMMIT | OBJ_GETTABLE | OBJ_TILE | PAG_EXECUTE | PAG_READ | PAG_WRITE)))
+            {
+                // and copy stuff
+                PBYTE pThis;
+
+                memset(pNewProgDetails, 0, cb);
+
+                pNewProgDetails->Length = sizeof(PROGDETAILS);
+
+                pNewProgDetails->progt.progc = Details.progt.progc;
+
+                pNewProgDetails->progt.fbVisible = Details.progt.fbVisible;
+                memcpy(&pNewProgDetails->swpInitial, &Details.swpInitial, sizeof(SWP));
+
+                // start copying into buffer right after PROGDETAILS
+                pThis = (PBYTE)(pNewProgDetails + 1);
+
+                // handy macro to avoid typos
+                #define COPY(id) if (cb ## id) { \
+                    memcpy(pThis, Details.psz ## id, cb ## id); \
+                    pNewProgDetails->psz ## id = pThis; \
+                    pThis += cb ## id; }
+
+                COPY(Title);
+                COPY(Executable);
+                COPY(Parameters);
+                COPY(StartupDir);
+                COPY(Icon);
+                COPY(Environment);
+
+                *ppDetails = pNewProgDetails;
+            }
+        }
+    }
+
+    xstrClear(&strParamsPatched);
+    xstrClear(&strExecutablePatched);
+
+    if (pszWinOS2Env)
+        free(pszWinOS2Env);
 
     return (arc);
@@ -1434,264 +1652,123 @@
                               PSZ pszFailingName)
 {
-    ULONG   cb,
-            cbTitle,
-            cbExecutable,
-            cbParameters,
-            cbStartupDir,
-            cbIcon,
-            cbEnvironment;
-
-    APIRET  arc = NO_ERROR;
-
-    /*
-    if (WinMessageBox(HWND_DESKTOP,
-                      NULLHANDLE,
-                      (ProgDetails.pszExecutable) ? ProgDetails.pszExecutable : "NULL",
-                      "Start?",
-                      0,
-                      MB_YESNO | MB_MOVEABLE)
-              != MBID_YES)
-        return (ERROR_INTERRUPT);
-    */
-
-    // allocate a chunk of tiled memory from OS/2 to make sure
-    // this is aligned on a 64K memory (backed up by a 16-bit
-    // LDT selector)
-    cb = sizeof(PROGDETAILS);
-    if (cbTitle = strhSize(pcProgDetails->pszTitle))
-        cb += cbTitle;
-    else
+    APIRET arc = NO_ERROR;
+
+    if (!pcProgDetails)
         return (ERROR_INVALID_PARAMETER);
-    _Pmpf((__FUNCTION__ ": cbTitle is %d", cbTitle));
-
-    if (cbExecutable = strhSize(pcProgDetails->pszExecutable))
-        cb += cbExecutable;
-    else
-        return (ERROR_INVALID_PARAMETER);
-    _Pmpf(("    cbExecutable is %d", cbExecutable));
-
-    if (cbParameters = strhSize(pcProgDetails->pszParameters))
-        cb += cbParameters;
-    else
-        return (ERROR_INVALID_PARAMETER);
-    _Pmpf(("    cbParameters is %d", cbExecutable));
-
-    if (cbStartupDir = strhSize(pcProgDetails->pszStartupDir))
-        cb += cbStartupDir;
-    else
-        return (ERROR_INVALID_PARAMETER);
-    _Pmpf(("    cbStartupDir is %d", cbStartupDir));
-
-    if (cbIcon = strhSize(pcProgDetails->pszIcon))
-        cb += cbIcon;
-    else
-        return (ERROR_INVALID_PARAMETER);
-    _Pmpf(("    cbIcon is %d", cbIcon));
-
-    if (cbEnvironment = appQueryEnvironmentLen(pcProgDetails->pszEnvironment))
-        cb += cbEnvironment;
-    _Pmpf(("    cbEnvironment is %d", cbEnvironment));
-
-    _Pmpf(("    cbTotal is %d", cb));
-
-    if (cb > 60000)     // to be on the safe side
-        arc = ERROR_BAD_ENVIRONMENT; // 10;
-    else
-    {
-        PPROGDETAILS pNewProgDetails;
-        if (!(arc = DosAllocMem((PVOID*)&pNewProgDetails,
-                                cb,
-                                PAG_COMMIT | OBJ_TILE | PAG_READ | PAG_WRITE)))
-        {
-            // alright, copy stuff
-            memset(pNewProgDetails, 0, sizeof(PROGDETAILS));
-
-            pNewProgDetails->Length = sizeof(PROGDETAILS);
-
-            if (!(pNewProgDetails->progt.progc = pcProgDetails->progt.progc))
-                arc = ERROR_BAD_FORMAT;
-                        // this should never happen because we check
-                        // for this in appStartApp
-            else
+
+    if (pszFailingName)
+        *pszFailingName = '\0';
+
+    if (!(*phapp = WinStartApp(hwndNotify,
+                                        // receives WM_APPTERMINATENOTIFY
+                               (PPROGDETAILS)pcProgDetails,
+                               pcProgDetails->pszParameters,
+                               NULL,            // "reserved", PMREF says...
+                               SAF_INSTALLEDCMDLINE)))
+                                    // we MUST use SAF_INSTALLEDCMDLINE
+                                    // or no Win-OS/2 session will start...
+                                    // whatever is going on here... Warp 4 FP11
+
+                                    // do not use SAF_STARTCHILDAPP, or the
+                                    // app will be terminated automatically
+                                    // when the calling process terminates!
+    {
+        // cannot start app:
+        PERRINFO pei;
+
+        #ifdef DEBUG_PROGRAMSTART
+            _Pmpf((__FUNCTION__ ": WinStartApp failed"));
+        #endif
+
+        // unfortunately WinStartApp doesn't
+        // return meaningful codes like DosStartSession, so
+        // try to see what happened
+
+        if (pei = WinGetErrorInfo(0))
+        {
+            #ifdef DEBUG_PROGRAMSTART
+                _Pmpf(("  WinGetErrorInfo returned 0x%lX, errorid 0x%lX, %d",
+                            pei,
+                            pei->idError,
+                            ERRORIDERROR(pei->idError)));
+            #endif
+
+            switch (ERRORIDERROR(pei->idError))
             {
-                PBYTE pThis;
-
-                pNewProgDetails->progt.fbVisible = pcProgDetails->progt.fbVisible;
-                memcpy(&pNewProgDetails->swpInitial, &pcProgDetails->swpInitial, sizeof(SWP));
-
-                // start copying into buffer right after PROGDETAILS
-                pThis = (PBYTE)(pNewProgDetails + 1);
-
-                #define COPY(id) if (cb ## id) { \
-                    memcpy(pThis, pcProgDetails->psz ## id, cb ## id); \
-                    pNewProgDetails->psz ## id = pThis; \
-                    pThis += cb ## id; }
-
-                COPY(Title);
-                COPY(Executable);
-                COPY(Parameters);
-                COPY(StartupDir);
-                COPY(Icon);
-                COPY(Environment);
-
-                #ifdef DEBUG_PROGRAMSTART
-                    _Pmpf((__FUNCTION__ ": progt.progc: %d", pNewProgDetails->progt.progc));
-                    _Pmpf(("    progt.fbVisible: 0x%lX", pNewProgDetails->progt.fbVisible));
-                    _Pmpf(("    progt.pszTitle: \"%s\"", (pNewProgDetails->pszTitle) ? pNewProgDetails->pszTitle : "NULL"));
-                    _Pmpf(("    exec: \"%s\"", (pNewProgDetails->pszExecutable) ? pNewProgDetails->pszExecutable : "NULL"));
-                    _Pmpf(("    params: \"%s\"", (pNewProgDetails->pszParameters) ? pNewProgDetails->pszParameters : "NULL"));
-                    _Pmpf(("    startup: \"%s\"", (pNewProgDetails->pszStartupDir) ? pNewProgDetails->pszStartupDir : "NULL"));
-                    _Pmpf(("    pszIcon: \"%s\"", (pNewProgDetails->pszIcon) ? pNewProgDetails->pszIcon : "NULL"));
-                    _Pmpf(("    environment: "));
-                    {
-                        PSZ pszThis = pNewProgDetails->pszEnvironment;
-                        while (pszThis && *pszThis)
-                        {
-                            _Pmpf(("      \"%s\"", pszThis));
-                            pszThis += strlen(pszThis) + 1;
-                        }
-                    }
-
-                    _Pmpf(("    swpInitial.fl = 0x%lX, x = %d, y = %d, cx = %d, cy = %d:",
-                                pNewProgDetails->swpInitial.fl,
-                                pNewProgDetails->swpInitial.x,
-                                pNewProgDetails->swpInitial.y,
-                                pNewProgDetails->swpInitial.cx,
-                                pNewProgDetails->swpInitial.cy));
-                    _Pmpf(("    behind = %d, hwnd = %d, res1 = %d, res2 = %d",
-                                pNewProgDetails->swpInitial.hwndInsertBehind,
-                                pNewProgDetails->swpInitial.hwnd,
-                                pNewProgDetails->swpInitial.ulReserved1,
-                                pNewProgDetails->swpInitial.ulReserved2));
-
-                    /* DumpMemoryBlock((PBYTE)pNewProgDetails,
-                                    cb,
-                                    8); */
-
-                #endif
-
-                /* if (!(appIsWindowsApp(pNewProgDetails->progt.progc)))
-                    arc = CallDosStartSession(phapp,
-                                              pNewProgDetails,
+                case PMERR_DOS_ERROR: //  (0x1200)
+                {
+                    /*
+                    PUSHORT pausMsgOfs = (PUSHORT)(((PBYTE)pei) + pei->offaoffszMsg);
+                    PULONG  pulData    = (PULONG)(((PBYTE)pei) + pei->offBinaryData);
+                    PSZ     pszMsg     = (PSZ)(((PBYTE)pei) + *pausMsgOfs);
+
+                    CHAR szMsg[1000];
+                    sprintf(szMsg, "cDetail: %d\nmsg: %s\n*pul: %d",
+                            pei->cDetailLevel,
+                            pszMsg,
+                            *(pulData - 1));
+
+                    WinMessageBox(HWND_DESKTOP,
+                                  NULLHANDLE,
+                                  szMsg,
+                                  "Error",
+                                  0,
+                                  MB_OK | MB_MOVEABLE);
+
+                    // Very helpful. The message is "UNK 1200 E",
+                    // where I assume "UNK" means "unknown", which is
+                    // exactly what I was trying to find out. Oh my.
+                    // And cDetailLevel is always 1, which isn't terribly
+                    // helpful either. V0.9.18 (2002-03-27) [umoeller]
+                    // WHO THE &%õ$ CREATED THESE APIS?
+
+                    */
+
+                    // this is probably the case where the module
+                    // couldn't be loaded, so try DosStartSession
+                    // to get a meaningful return code... note that
+                    // this cannot handle hwndNotify then
+                    /* arc = CallDosStartSession(phapp,
+                                              pcProgDetails,
                                               cbFailingName,
-                                              pszFailingName);
-                else */
-                    // windoze app: use WinStartApp
-
-                if (!(*phapp = WinStartApp(hwndNotify,
-                                                    // receives WM_APPTERMINATENOTIFY
-                                           pNewProgDetails,
-                                           pNewProgDetails->pszParameters,
-                                           NULL,            // "reserved", PMREF says...
-                                           SAF_INSTALLEDCMDLINE)))
-                                                // we MUST use SAF_INSTALLEDCMDLINE
-                                                // or no Win-OS/2 session will start...
-                                                // whatever is going on here... Warp 4 FP11
-
-                                                // do not use SAF_STARTCHILDAPP, or the
-                                                // app will be terminated automatically
-                                                // when the WPS terminates!
-                {
-                    // cannot start app:
-                    PERRINFO pei;
-
-                    #ifdef DEBUG_PROGRAMSTART
-                        _Pmpf((__FUNCTION__ ": WinStartApp failed"));
-                    #endif
-
-                    // unfortunately WinStartApp doesn't
-                    // return meaningful codes like DosStartSession, so
-                    // try to see what happened
-
-                    if (pei = WinGetErrorInfo(0))
-                    {
-                        #ifdef DEBUG_PROGRAMSTART
-                            _Pmpf(("  WinGetErrorInfo returned 0x%lX, errorid 0x%lX, %d",
-                                        pei,
-                                        pei->idError,
-                                        ERRORIDERROR(pei->idError)));
-                        #endif
-
-                        switch (ERRORIDERROR(pei->idError))
-                        {
-                            case PMERR_DOS_ERROR: //  (0x1200)
-                            {
-                                /*
-                                PUSHORT pausMsgOfs = (PUSHORT)(((PBYTE)pei) + pei->offaoffszMsg);
-                                PULONG  pulData    = (PULONG)(((PBYTE)pei) + pei->offBinaryData);
-                                PSZ     pszMsg     = (PSZ)(((PBYTE)pei) + *pausMsgOfs);
-
-                                CHAR szMsg[1000];
-                                sprintf(szMsg, "cDetail: %d\nmsg: %s\n*pul: %d",
-                                        pei->cDetailLevel,
-                                        pszMsg,
-                                        *(pulData - 1));
-
-                                WinMessageBox(HWND_DESKTOP,
-                                              NULLHANDLE,
-                                              szMsg,
-                                              "Error",
-                                              0,
-                                              MB_OK | MB_MOVEABLE);
-
-                                // Very helpful. The message is "UNK 1200 E",
-                                // where I assume "UNK" means "unknown", which is
-                                // exactly what I was trying to find out. Oh my.
-                                // And cDetailLevel is always 1, which isn't terribly
-                                // helpful either. V0.9.18 (2002-03-27) [umoeller]
-                                // WHO THE &%õ$ CREATED THESE APIS?
-
-                                */
-
-                                // this is probably the case where the module
-                                // couldn't be loaded, so try DosStartSession
-                                // to get a meaningful return code... note that
-                                // this cannot handle hwndNotify then
-                                arc = CallDosStartSession(phapp,
-                                                          pNewProgDetails,
-                                                          cbFailingName,
-                                                          pszFailingName);
-                            }
-                            break;
-
-                            case PMERR_INVALID_APPL: //  (0x1530)
-                                    // Attempted to start an application whose type is not
-                                    // recognized by OS/2.
-                                    // This we get also if the executable doesn't exist...
-                                    // V0.9.18 (2002-03-27) [umoeller]
-                                // arc = ERROR_INVALID_EXE_SIGNATURE;
-                                arc = ERROR_FILE_NOT_FOUND;
-                            break;
-
-                            case PMERR_INVALID_PARAMETERS: //  (0x1208)
-                                    // An application parameter value is invalid for
-                                    // its converted PM type. For  example: a 4-byte
-                                    // value outside the range -32 768 to +32 767 cannot be
-                                    // converted to a SHORT, and a negative number cannot
-                                    // be converted to a ULONG or USHORT.
-                                arc = ERROR_INVALID_DATA;
-                            break;
-
-                            case PMERR_STARTED_IN_BACKGROUND: //  (0x1532)
-                                    // The application started a new session in the
-                                    // background.
-                                arc = ERROR_SMG_START_IN_BACKGROUND;
-                            break;
-
-                            case PMERR_INVALID_WINDOW: // (0x1206)
-                                    // The window specified with a Window List call
-                                    // is not a valid frame window.
-
-                            default:
-                                arc = ERROR_BAD_FORMAT;
-                            break;
-                        }
-
-                        WinFreeErrorInfo(pei);
-                    }
+                                              pszFailingName); */
+                    arc = ERROR_FILE_NOT_FOUND;
                 }
+                break;
+
+                case PMERR_INVALID_APPL: //  (0x1530)
+                        // Attempted to start an application whose type is not
+                        // recognized by OS/2.
+                        // This we get also if the executable doesn't exist...
+                        // V0.9.18 (2002-03-27) [umoeller]
+                    // arc = ERROR_INVALID_EXE_SIGNATURE;
+                    arc = ERROR_FILE_NOT_FOUND;
+                break;
+
+                case PMERR_INVALID_PARAMETERS: //  (0x1208)
+                        // An application parameter value is invalid for
+                        // its converted PM type. For  example: a 4-byte
+                        // value outside the range -32 768 to +32 767 cannot be
+                        // converted to a SHORT, and a negative number cannot
+                        // be converted to a ULONG or USHORT.
+                    arc = ERROR_INVALID_DATA;
+                break;
+
+                case PMERR_STARTED_IN_BACKGROUND: //  (0x1532)
+                        // The application started a new session in the
+                        // background.
+                    arc = ERROR_SMG_START_IN_BACKGROUND;
+                break;
+
+                case PMERR_INVALID_WINDOW: // (0x1206)
+                        // The window specified with a Window List call
+                        // is not a valid frame window.
+
+                default:
+                    arc = ERROR_BAD_FORMAT;
+                break;
             }
 
-            DosFreeMem(pNewProgDetails);
+            WinFreeErrorInfo(pei);
         }
     }
@@ -1706,59 +1783,6 @@
  *      work with all executable types.
  *
- *      This fixes the executable info to support:
- *
- *      -- starting "*" executables (command prompts
- *         for OS/2, DOS, Win-OS/2);
- *
- *      -- starting ".CMD" and ".BAT" files as
- *         PROGDETAILS.pszExecutable;
- *
- *      -- starting apps which are not fully qualified
- *         and therefore assumed to be on the PATH.
- *
- *      Unless it is "*", PROGDETAILS.pszExecutable must
- *      be a proper file name. The full path may be omitted
- *      if it is on the PATH, but the extension (.EXE etc.)
- *      must be given. You can use doshFindExecutable to
- *      find executables if you don't know the extension.
- *
- *      This also handles and merges special and default
- *      environments for the app to be started. The
- *      following should be respected:
- *
- *      --  As with WinStartApp, if PROGDETAILS.pszEnvironment
- *          is NULL, the new app inherits a default environment
- *          from the shell.
- *
- *      --  However, if you specify an environment, you _must_
- *          specify a complete environment. This function
- *          will not merge environments. Use
- *          appSetEnvironmentVar to change environment
- *          variables in a complete environment set.
- *
- *      --  If PROGDETAILS specifies a Win-OS/2 session
- *          and PROGDETAILS.pszEnvironment is empty,
- *          this uses the default Win-OS/2 environment.
- *          See appQueryDefaultWin31Environment.
- *
- *      Even though this isn't clearly said in PMREF,
- *      PROGDETAILS.swpInitial is important:
- *
- *      -- To start a session minimized, set SWP_MINIMIZE.
- *
- *      -- To start a VIO session with auto-close disabled,
- *         set the half-documented SWP_NOAUTOCLOSE flag (0x8000)
- *         This flag is now in the newer toolkit headers.
- *
- *      In addition, this supports the following session
- *      flags with ulFlags if PROG_DEFAULT is specified:
- *
- *      --  APP_RUN_FULLSCREEN
- *
- *      --  APP_RUN_ENHANCED
- *
- *      --  APP_RUN_STANDARD
- *
- *      --  APP_RUN_SEPARATE
+ *      This first calls appBuildProgDetails (see
+ *      remarks there) and then calls WinStartApp.
  *
  *      Since this calls WinStartApp in turn, this
@@ -1775,13 +1799,8 @@
  *          See remarks below.
  *
- *      --  ERROR_INVALID_PARAMETER: pcProgDetails or
- *          phapp is NULL; or PROGDETAILS.pszExecutable is NULL.
- *
- *      --  ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND:
- *          PROGDETAILS.pszExecutable and/or PROGDETAILS.pszStartupDir
- *          are invalid.
- *          A NULL PROGDETAILS.pszStartupDir is supported though.
- *
  *      --  ERROR_NOT_ENOUGH_MEMORY
+ *
+ *      plus the many error codes from appBuildProgDetails,
+ *      which gets called in turn.
  *
  *      <B>About enforcing thread 1</B>
@@ -1797,13 +1816,15 @@
  *          this is not running on thread 1.
  *
- *      --  By contrast, WinStartApp hangs the system with
- *          VIO sessions if we do the XWorkplace tricky of
- *          redirecting WPProgram::wpOpen to thread 1
- *          via WinPostMsg to the kernel thread-1 object
- *          window. This also happens with DosStartSession,
- *          so I suspect the bug is somewhere deeper in
- *          SESMGR or wherever. So we no longer return
- *          ERROR_INVALID_THREADID for non-Win-OS/2 sessions
- *          (V0.9.18).
+ *      --  By contrast, there are many situations where
+ *          calling WinStartApp from within the Workplace
+ *          process will hang the system, most notably
+ *          with VIO sessions. I have been unable to figure
+ *          out why this happens, so XWorkplace now uses
+ *          its daemon to call WinStartApp instead.
+ *
+ *          As a word of wisdom, do not call this from
+ *          within the Workplace process. For some strange
+ *          reason though, the XWorkplace "Run" dialog
+ *          (which uses this) _does_ work. Whatever.
  *
  *@@added V0.9.6 (2000-10-16) [umoeller]
@@ -1822,5 +1843,6 @@
  *@@changed V0.9.18 (2002-02-13) [umoeller]: added CallWinStartApp to fix possible memory problems
  *@@changed V0.9.18 (2002-03-27) [umoeller]: no longer returning ERROR_INVALID_THREADID, except for Win-OS/2 sessions
- *@@changed V0.9.18 (2002-03-27) [umoeller]: extracted appFixProgDetails
+ *@@changed V0.9.18 (2002-03-27) [umoeller]: extracted appBuildProgDetails
+ *@@changed V0.9.19 (2002-03-28) [umoeller]: adjusted for new appBuildProgDetails
  */
 
@@ -1833,29 +1855,18 @@
 {
     APIRET          arc;
-    PROGDETAILS     ProgDetails;
-    XSTRING         strExecutablePatched,
-                    strParamsPatched;
-    PSZ             pszWinOS2Env = 0;
-
-    if (pszFailingName)
-        *pszFailingName = '\0';
-
-    if (!pcProgDetails || !phapp)
+
+    PPROGDETAILS    pDetails;
+
+    if (!phapp)
         return (ERROR_INVALID_PARAMETER);
 
-    xstrInit(&strExecutablePatched, 0);
-    xstrInit(&strParamsPatched, 0);
-
-    if (!(arc = appFixProgDetails(&ProgDetails,
-                                  pcProgDetails,
-                                  ulFlags,
-                                  &strExecutablePatched,
-                                  &strParamsPatched,
-                                  &pszWinOS2Env)))
+    if (!(arc = appBuildProgDetails(&pDetails,
+                                    pcProgDetails,
+                                    ulFlags)))
     {
         if (pszFailingName)
-            strhncpy0(pszFailingName, ProgDetails.pszExecutable, cbFailingName);
-
-        if (    (appIsWindowsApp(ProgDetails.progt.progc))
+            strhncpy0(pszFailingName, pDetails->pszExecutable, cbFailingName);
+
+        if (    (appIsWindowsApp(pDetails->progt.progc))
              && (doshMyTID() != 1)          // V0.9.16 (2001-10-19) [umoeller]
            )
@@ -1864,14 +1875,11 @@
             arc = CallWinStartApp(phapp,
                                   hwndNotify,
-                                  &ProgDetails,
+                                  pDetails,
                                   cbFailingName,
                                   pszFailingName);
+
+        DosFreeMem(pDetails);
+
     } // end if (ProgDetails.pszExecutable)
-
-    xstrClear(&strParamsPatched);
-    xstrClear(&strExecutablePatched);
-
-    if (pszWinOS2Env)
-        free(pszWinOS2Env);
 
     #ifdef DEBUG_PROGRAMSTART
Index: trunk/src/helpers/cnrh.c
===================================================================
--- trunk/src/helpers/cnrh.c	(revision 152)
+++ trunk/src/helpers/cnrh.c	(revision 153)
@@ -1795,4 +1795,49 @@
 
 /*
+ *@@ cnrhOpenEdit:
+ *      begins direct text editing on the first
+ *      record that is currently cursored in
+ *      the container.
+ *
+ *      This is the recommended response when
+ *      the almost documented WM_TEXTEDIT
+ *      message comes into the container owner's
+ *      window procedure. This is the case when
+ *      the user presses the key combo that was
+ *      set for direct text editing in the "Keyboard"
+ *      object.
+ *
+ *      Returns TRUE if direct editing was
+ *      successfully started. If FALSE is returned,
+ *      there is either no record with CRA_CURSORED
+ *      emphasis, or that record has the read-only
+ *      flag set.
+ *
+ *@@added V0.9.19 (2002-04-02) [umoeller]
+ */
+
+BOOL cnrhOpenEdit(HWND hwndCnr)
+{
+    BOOL brc = FALSE;
+    CNREDITDATA ced;
+    memset(&ced, 0, sizeof(ced));
+    ced.cb = sizeof(ced);
+    ced.hwndCnr = hwndCnr;
+    if (ced.pRecord = (PRECORDCORE)WinSendMsg(hwndCnr,
+                                              CM_QUERYRECORDEMPHASIS,
+                                              (MPARAM)CMA_FIRST,
+                                              (MPARAM)CRA_CURSORED))
+    {
+        ced.id = WinQueryWindowUShort(hwndCnr, QWS_ID);
+        brc = (BOOL)WinSendMsg(hwndCnr,
+                               CM_OPENEDIT,
+                               (MPARAM)&ced,
+                               0);
+    }
+
+    return (brc);
+}
+
+/*
  *@@ cnrhInitDrag:
  *      this sets up the necessary structures to begin dragging
Index: trunk/src/helpers/dialog.c
===================================================================
--- trunk/src/helpers/dialog.c	(revision 152)
+++ trunk/src/helpers/dialog.c	(revision 153)
@@ -226,7 +226,4 @@
  *
  ********************************************************************/
-
-#define PM_GROUP_SPACING_X          16
-#define PM_GROUP_SPACING_TOP        16
 
 static APIRET ProcessTable(PTABLEDEF pTableDef,
@@ -1567,5 +1564,6 @@
 
                 pCurrentRow = NULL;
-            break; }
+            }
+            break;
 
             /*
@@ -1595,5 +1593,6 @@
                     }
                 }
-            break; }
+            }
+            break;
 
             /*
@@ -1611,5 +1610,6 @@
                     lstAppendItem(&pCurrentRow->llColumns,
                                   pColumnDef);
-            break; }
+            }
+            break;
 
             /*
@@ -1632,5 +1632,6 @@
                     lstRemoveNode(&llStack, pNode);
                 }
-            break; }
+            }
+            break;
 
             default:
Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 152)
+++ trunk/src/helpers/dosh.c	(revision 153)
@@ -1189,9 +1189,11 @@
  *      --  DRVFL_CHECKLONGNAMES: drive should always be
  *          checked for longname support. If this is
- *          set, we will try a DosOpen on the drive
- *          to see if it supports long filenames
- *          (unless it's a "well-known" file-system
- *          and we know it does). In enabled, the
- *          DFL_SUPPORTS_LONGNAMES flag is reliable.
+ *          set, we will try a DosOpen("\\long.name.file")
+ *          on the drive to see if it supports long
+ *          filenames (unless it's a "well-known"
+ *          file-system and we know it does). If enabled,
+ *          the DFL_SUPPORTS_LONGNAMES flag is reliable.
+ *          Note that this does not check for what special
+ *          characters are supported in file names.
  *
  *      This should return only one of the following:
@@ -1222,5 +1224,6 @@
  *          returns NO_ERROR for the given drive.
  *          This will rule out invalid drive letters
- *          and drives that are presently locked.
+ *          and drives that are presently locked by
+ *          CHKDSK or something.
  *
  *      2)  If so, check whether XDISKINFO.flDevice
@@ -2190,45 +2193,12 @@
 
 /*
- *@@ doshOpenExisting:
- *      opens an existing file for read-write access. Does
- *      not create a new file if the file doesn't exist.
- *
- *      This is just a simple wrapper around DosOpen.
- *
- *      ulOpenFlags is passed to DosOpen. Should be one
- *      of:
- *
- *      --  for read-only access:
- *
- +              OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY
- *
- *      --  for read-write access:
- *
- +              OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE
- *
- *      In addition, you can specify
- *
- +          OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_RANDOM
- +                          | OPEN_FLAGS_NOINHERIT
- *
- *@@added V0.9.13 (2001-06-14) [umoeller]
- */
-
-/*
-APIRET doshOpenExisting(PCSZ pcszFilename,   // in: file name
-                        ULONG ulOpenFlags,          // in: open flags
-                        HFILE *phf)                 // out: OS/2 file handle
-{
-    ULONG ulAction;
-    return (DosOpen((PSZ)pcszFilename,
-                    phf,
-                    &ulAction,
-                    0,          // cbFile
-                    0,          // attributes
-                    OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS,
-                    ulOpenFlags,
-                    NULL));     // EAs
-}
-*/
+ *@@category: Helpers\Control program helpers\File management\XFILEs
+ */
+
+/* ******************************************************************
+ *
+ *   XFILEs
+ *
+ ********************************************************************/
 
 /*
@@ -2295,5 +2265,5 @@
                 PXFILE *ppFile)
 {
-    APIRET arc = NO_ERROR;
+    APIRET  arc = NO_ERROR;
 
     ULONG   fsOpenFlags = 0,
@@ -2409,43 +2379,9 @@
     }
     else
-        arc = ERROR_INVALID_PARAMETER;
+        if (!arc)       // V0.9.19 (2002-04-02) [umoeller]
+            arc = ERROR_INVALID_PARAMETER;
 
     return (arc);
 }
-
-/*
- *@@ doshLockFile:
- *
- *@@added V0.9.16 (2001-10-19) [umoeller]
- */
-
-/* APIRET doshLockFile(PXFILE pFile)
-{
-    if (!pFile)
-        return (ERROR_INVALID_PARAMETER);
-
-    if (!pFile->hmtx)
-        // first call:
-        return (DosCreateMutexSem(NULL,
-                                  &pFile->hmtx,
-                                  0,
-                                  TRUE));        // request!
-
-    return (DosRequestMutexSem(pFile->hmtx, SEM_INDEFINITE_WAIT));
-} */
-
-/*
- *@@ doshUnlockFile:
- *
- *@@added V0.9.16 (2001-10-19) [umoeller]
- */
-
-/* APIRET doshUnlockFile(PXFILE pFile)
-{
-    if (pFile)
-        return (DosReleaseMutexSem(pFile->hmtx));
-
-    return (ERROR_INVALID_PARAMETER);
-} */
 
 /*
@@ -2483,172 +2419,173 @@
  *@@added V0.9.13 (2001-06-14) [umoeller]
  *@@changed V0.9.16 (2001-12-18) [umoeller]: now with XFILE, and always using FILE_BEGIN
+ *@@chaanged V0.9.19 (2002-04-02) [umoeller]: added params checking
  */
 
 APIRET doshReadAt(PXFILE pFile,
                   ULONG ulOffset,   // in: offset to read from (from beginning of file)
-                  PULONG pcb,       // in: bytes to read, out: bytes read
+                  PULONG pcb,       // in: bytes to read, out: bytes read (req.)
                   PBYTE pbData,     // out: read buffer (must be cb bytes)
                   ULONG fl)         // in: DRFL_* flags
 {
     APIRET arc = NO_ERROR;
-    ULONG cb = *pcb;
+    ULONG cb;
     ULONG ulDummy;
 
-    // if (!(arc = doshLockFile(pFile)))   // this checks for pFile
-    {
-        *pcb = 0;
-
-        // check if we have the data in the cache already;
-
-        if (    (pFile->pbCache)
-                // first byte must be in cache
-             && (ulOffset >= pFile->ulReadFrom)
-                // last byte must be in cache
-             && (    ulOffset + cb
-                  <= pFile->ulReadFrom + pFile->cbCache
-                )
+    if (!pFile || !pcb)
+        // V0.9.19 (2002-04-02) [umoeller]
+        return ERROR_INVALID_PARAMETER;
+
+    cb = *pcb;
+    *pcb = 0;
+
+    // check if we have the data in the cache already;
+
+    if (    (pFile->pbCache)
+            // first byte must be in cache
+         && (ulOffset >= pFile->ulReadFrom)
+            // last byte must be in cache
+         && (    ulOffset + cb
+              <= pFile->ulReadFrom + pFile->cbCache
+            )
+       )
+    {
+        // alright, return data from cache simply
+        ULONG ulOfsInCache = ulOffset - pFile->ulReadFrom;
+
+        memcpy(pbData,
+               pFile->pbCache + ulOfsInCache,
+               cb);
+        *pcb = cb;
+
+        #ifdef DEBUG_DOSOPEN
+        _Pmpf((__FUNCTION__ " %s: data is fully in cache",
+                    pFile->pszFilename));
+        _Pmpf(("  caller wants %d bytes from %d",
+                    cb, ulOffset));
+        _Pmpf(("  we got %d bytes from %d",
+                    pFile->cbCache, pFile->ulReadFrom));
+        _Pmpf(("  so copied %d bytes from cache ofs %d",
+                    cb, ulOfsInCache));
+        #endif
+    }
+    else
+    {
+        // data is not in cache:
+        // check how much it is... for small amounts,
+        // we load the cache first
+        if (    (cb <= 4096 - 512)
+             && (!(fl & DRFL_NOCACHE))
            )
         {
-            // alright, return data from cache simply
-            ULONG ulOfsInCache = ulOffset - pFile->ulReadFrom;
-
-            memcpy(pbData,
-                   pFile->pbCache + ulOfsInCache,
-                   cb);
-            *pcb = cb;
-
             #ifdef DEBUG_DOSOPEN
-            _Pmpf((__FUNCTION__ " %s: data is fully in cache",
-                        pFile->pszFilename));
+            _Pmpf((__FUNCTION__ " %s: filling cache anew",
+                    pFile->pszFilename));
             _Pmpf(("  caller wants %d bytes from %d",
                         cb, ulOffset));
-            _Pmpf(("  we got %d bytes from %d",
+            #endif
+
+            // OK, then fix the offset to read from
+            // to a multiple of 512 to get a full sector
+            pFile->ulReadFrom = ulOffset / 512L * 512L;
+            // and read 4096 bytes always plus the
+            // value we cut off above
+            pFile->cbCache = 4096;
+
+            #ifdef DEBUG_DOSOPEN
+            _Pmpf(("  getting %d bytes from %d",
                         pFile->cbCache, pFile->ulReadFrom));
-            _Pmpf(("  so copied %d bytes from cache ofs %d",
-                        cb, ulOfsInCache));
             #endif
-        }
-        else
-        {
-            // data is not in cache:
-            // check how much it is... for small amounts,
-            // we load the cache first
-            if (    (cb <= 4096 - 512)
-                 && (!(fl & DRFL_NOCACHE))
-               )
-            {
-                #ifdef DEBUG_DOSOPEN
-                _Pmpf((__FUNCTION__ " %s: filling cache anew",
-                        pFile->pszFilename));
-                _Pmpf(("  caller wants %d bytes from %d",
-                            cb, ulOffset));
-                #endif
-
-                // OK, then fix the offset to read from
-                // to a multiple of 512 to get a full sector
-                pFile->ulReadFrom = ulOffset / 512L * 512L;
-                // and read 4096 bytes always plus the
-                // value we cut off above
-                pFile->cbCache = 4096;
-
-                #ifdef DEBUG_DOSOPEN
-                _Pmpf(("  getting %d bytes from %d",
-                            pFile->cbCache, pFile->ulReadFrom));
-                #endif
-
-                // free old cache
-                if (pFile->pbCache)
-                    free(pFile->pbCache);
-
-                // allocate new cache
-                if (!(pFile->pbCache = (PBYTE)malloc(pFile->cbCache)))
-                    arc = ERROR_NOT_ENOUGH_MEMORY;
-                else
-                {
-                    ULONG ulOfsInCache = 0;
-
-                    if (!(arc = DosSetFilePtr(pFile->hf,
-                                              (LONG)pFile->ulReadFrom,
-                                              FILE_BEGIN,
-                                              &ulDummy)))
-                    {
-                        if (!(arc = DosRead(pFile->hf,
-                                            pFile->pbCache,
-                                            pFile->cbCache,
-                                            &ulDummy)))
-                        {
-                            // got data:
-                            #ifdef DEBUG_DOSOPEN
-                            _Pmpf(("        %d bytes read", ulDummy));
-                            #endif
-
-                            pFile->cbCache = ulDummy;
-
-                            // check bounds
-                            ulOfsInCache = ulOffset - pFile->ulReadFrom;
-
-                            /*
-                            if (ulOfsInCache + cb > pFile->cbCache)
-                            {
-                                cb = pFile->cbCache - ulOfsInCache;
-                                if (fl & DRFL_FAILIFLESS)
-                                    arc = ERROR_NO_DATA;
-                            }
-                            */
-                        }
-                    }
-
-                    if (!arc)
-                    {
-                        // copy to caller
-                        memcpy(pbData,
-                               pFile->pbCache + ulOfsInCache,
-                               cb);
-                        *pcb = cb;
-
-                        #ifdef DEBUG_DOSOPEN
-                        _Pmpf(("  so copied %d bytes from cache ofs %d",
-                                    cb, ulOfsInCache));
-                        #endif
-                    }
-                    else
-                    {
-                        free(pFile->pbCache);
-                        pFile->pbCache = NULL;
-                    }
-                } // end else if (!(pFile->pbCache = (PBYTE)malloc(pFile->cbCache)))
-            }
+
+            // free old cache
+            if (pFile->pbCache)
+                free(pFile->pbCache);
+
+            // allocate new cache
+            if (!(pFile->pbCache = (PBYTE)malloc(pFile->cbCache)))
+                arc = ERROR_NOT_ENOUGH_MEMORY;
             else
             {
-                // read uncached:
-                #ifdef DEBUG_DOSOPEN
-                _Pmpf(("  " __FUNCTION__ " %s: reading uncached",
-                            pFile->pszFilename));
-                _Pmpf(("      caller wants %d bytes from %d",
-                            cb, ulOffset));
-                #endif
+                ULONG ulOfsInCache = 0;
 
                 if (!(arc = DosSetFilePtr(pFile->hf,
-                                          (LONG)ulOffset,
+                                          (LONG)pFile->ulReadFrom,
                                           FILE_BEGIN,
                                           &ulDummy)))
                 {
                     if (!(arc = DosRead(pFile->hf,
-                                        pbData,
-                                        cb,
+                                        pFile->pbCache,
+                                        pFile->cbCache,
                                         &ulDummy)))
                     {
-                        if (    (fl & DRFL_FAILIFLESS)
-                             && (ulDummy != cb)
-                           )
-                            arc = ERROR_NO_DATA;
-                        else
-                            *pcb = ulDummy;     // bytes read
+                        // got data:
+                        #ifdef DEBUG_DOSOPEN
+                        _Pmpf(("        %d bytes read", ulDummy));
+                        #endif
+
+                        pFile->cbCache = ulDummy;
+
+                        // check bounds
+                        ulOfsInCache = ulOffset - pFile->ulReadFrom;
+
+                        /*
+                        if (ulOfsInCache + cb > pFile->cbCache)
+                        {
+                            cb = pFile->cbCache - ulOfsInCache;
+                            if (fl & DRFL_FAILIFLESS)
+                                arc = ERROR_NO_DATA;
+                        }
+                        */
                     }
+                }
+
+                if (!arc)
+                {
+                    // copy to caller
+                    memcpy(pbData,
+                           pFile->pbCache + ulOfsInCache,
+                           cb);
+                    *pcb = cb;
+
+                    #ifdef DEBUG_DOSOPEN
+                    _Pmpf(("  so copied %d bytes from cache ofs %d",
+                                cb, ulOfsInCache));
+                    #endif
+                }
+                else
+                {
+                    free(pFile->pbCache);
+                    pFile->pbCache = NULL;
+                }
+            } // end else if (!(pFile->pbCache = (PBYTE)malloc(pFile->cbCache)))
+        }
+        else
+        {
+            // read uncached:
+            #ifdef DEBUG_DOSOPEN
+            _Pmpf(("  " __FUNCTION__ " %s: reading uncached",
+                        pFile->pszFilename));
+            _Pmpf(("      caller wants %d bytes from %d",
+                        cb, ulOffset));
+            #endif
+
+            if (!(arc = DosSetFilePtr(pFile->hf,
+                                      (LONG)ulOffset,
+                                      FILE_BEGIN,
+                                      &ulDummy)))
+            {
+                if (!(arc = DosRead(pFile->hf,
+                                    pbData,
+                                    cb,
+                                    &ulDummy)))
+                {
+                    if (    (fl & DRFL_FAILIFLESS)
+                         && (ulDummy != cb)
+                       )
+                        arc = ERROR_NO_DATA;
+                    else
+                        *pcb = ulDummy;     // bytes read
                 }
             }
         }
-
-        // doshUnlockFile(pFile);
     }
 
@@ -2737,21 +2674,18 @@
 
             if (!arc)
-                // if (!(arc = doshLockFile(pFile)))   // this checks for pFile
+            {
+                ULONG cbWritten;
+                if (!(arc = DosWrite(pFile->hf,
+                                     (pszNew)
+                                            ? pszNew
+                                            : (PSZ)pbData,
+                                     cb,
+                                     &cbWritten)))
                 {
-                    ULONG cbWritten;
-                    if (!(arc = DosWrite(pFile->hf,
-                                         (pszNew)
-                                                ? pszNew
-                                                : (PSZ)pbData,
-                                         cb,
-                                         &cbWritten)))
-                    {
-                        pFile->cbCurrent += cbWritten;
-                        // invalidate the cache
-                        FREE(pFile->pbCache);
-                    }
-
-                    // doshUnlockFile(pFile);
+                    pFile->cbCurrent += cbWritten;
+                    // invalidate the cache
+                    FREE(pFile->pbCache);
                 }
+            }
 
             if (pszNew)
@@ -2778,23 +2712,20 @@
 {
     APIRET arc = NO_ERROR;
-    // if (!(arc = doshLockFile(pFile)))   // this checks for pFile
-    {
-        ULONG cbWritten;
-        if (!(arc = DosSetFilePtr(pFile->hf,
-                                  (LONG)ulOffset,
-                                  FILE_BEGIN,
-                                  &cbWritten)))
+    ULONG cbWritten;
+    if (!(arc = DosSetFilePtr(pFile->hf,
+                              (LONG)ulOffset,
+                              FILE_BEGIN,
+                              &cbWritten)))
+    {
+        if (!(arc = DosWrite(pFile->hf,
+                             (PSZ)pbData,
+                             cb,
+                             &cbWritten)))
         {
-            if (!(arc = DosWrite(pFile->hf,
-                                 (PSZ)pbData,
-                                 cb,
-                                 &cbWritten)))
-            {
-                if (ulOffset + cbWritten > pFile->cbCurrent)
-                    pFile->cbCurrent = ulOffset + cbWritten;
-            }
+            if (ulOffset + cbWritten > pFile->cbCurrent)
+                pFile->cbCurrent = ulOffset + cbWritten;
+            // invalidate the cache V0.9.19 (2002-04-02) [umoeller]
+            FREE(pFile->pbCache);
         }
-
-        // doshUnlockFile(pFile);
     }
 
@@ -2860,4 +2791,6 @@
 /*
  * doshClose:
+ *      closes an XFILE opened by doshOpen and
+ *      sets *ppFile to NULL.
  *
  *@@added V0.9.16 (2001-10-19) [umoeller]
@@ -2873,27 +2806,15 @@
        )
     {
-        // request the mutex so that we won't be
-        // taking the file away under someone's butt
-        // if (!(arc = doshLockFile(pFile)))
+        // set the ptr to NULL
+        *ppFile = NULL;
+
+        FREE(pFile->pbCache);
+        FREE(pFile->pszFilename);
+
+        if (pFile->hf)
         {
-            // HMTX hmtx = pFile->hmtx;
-            // pFile->hmtx = NULLHANDLE;
-
-            // now that the file is locked,
-            // set the ptr to NULL
-            *ppFile = NULL;
-
-            FREE(pFile->pbCache);
-            FREE(pFile->pszFilename);
-
-            if (pFile->hf)
-            {
-                DosSetFileSize(pFile->hf, pFile->cbCurrent);
-                DosClose(pFile->hf);
-                pFile->hf = NULLHANDLE;
-            }
-
-            // doshUnlockFile(pFile);
-            // DosCloseMutexSem(pFile->hmtx);
+            DosSetFileSize(pFile->hf, pFile->cbCurrent);
+            DosClose(pFile->hf);
+            pFile->hf = NULLHANDLE;
         }
 
Index: trunk/src/helpers/encodings.c
===================================================================
--- trunk/src/helpers/encodings.c	(revision 152)
+++ trunk/src/helpers/encodings.c	(revision 153)
@@ -41,6 +41,4 @@
 #pragma hdrstop
 
-#define ENCODINGENTRY(id)   enc_ ## id, G_ ## id, ARRAYITEMCOUNT(G_ ## id)
-
 /*
  *@@ G_aEncodings:
@@ -65,4 +63,6 @@
 } G_aEncodings[] =
     {
+        #define ENCODINGENTRY(id)   enc_ ## id, G_ ## id, ARRAYITEMCOUNT(G_ ## id)
+
         ENCODINGENTRY(cp437), 437, SINGLE, "DOS Latin US",
         ENCODINGENTRY(cp737), 737, SINGLE, "DOS Greek",
@@ -82,8 +82,10 @@
         ENCODINGENTRY(cp869), 869, SINGLE, "DOS Greek2",
         ENCODINGENTRY(cp874), 874, SINGLE, "DOS Thai (TIS-620)",        // default in Thailand
-        // ENCODINGENTRY(cp932), 932 or 943?, DOUBLE, "Japanese Windows",
-        // ENCODINGENTRY(cp936), 936 or 946?, DOUBLE, "Chinese",
-        // ENCODINGENTRY(cp949), 951 or 949?, DOUBLE, "Korean",
-        // ENCODINGENTRY(cp950), 947 or 950?, DOUBLE, "Taiwan Big-5",           // default in China?
+
+        ENCODINGENTRY(cp932), 932 /* or 943?*/ , DOUBLE, "Japanese Windows",
+        ENCODINGENTRY(cp936), 936 /* or 946?*/ , DOUBLE, "Chinese",
+        ENCODINGENTRY(cp949), 951 /* or 949?*/ , DOUBLE, "Korean",
+        ENCODINGENTRY(cp950), 947 /* or 950?*/ , DOUBLE, "Taiwan Big-5",           // default in China?
+
         ENCODINGENTRY(cp1004), 1004, SINGLE, "Windows Extended",
         ENCODINGENTRY(cp1250), 1250, SINGLE, "Windows Latin 2",
@@ -404,12 +406,18 @@
 unsigned long encDecodeUTF8(const char **ppch)
 {
-    unsigned long   ulChar = **ppch;
-
-    if (!ulChar)
+    unsigned long   ulChar;
+
+    if (!(ulChar = **ppch))
+        // null is null
         return 0;
 
     // if (ulChar < 0x80): simple, one byte only... use that
 
-    if (ulChar >= 0x80)
+    if (ulChar < 0x80)
+    {
+        (*ppch)++;
+        return (ulChar);
+    }
+    else
     {
         unsigned long ulCount = 1;
@@ -490,45 +498,7 @@
             *ppch += ulCount;
     }
-    else
-        (*ppch)++;
 
     return (ulChar);
 }
 
-#if 0
-
-/*
- *@@ encCodepageToUTF8:
- *
- *@@added V0.9.18 (2002-03-08) [umoeller]
- */
-
-void encCodepageToUTF8(const char **ppch)
-{
-
-}
-
-putwchar(c)
-{
-  if (c < 0x80) {
-    putchar (c);
-  }
-  else if (c < 0x800) {
-    putchar (0xC0 | c>>6);
-    putchar (0x80 | c & 0x3F);
-  }
-  else if (c < 0x10000) {
-    putchar (0xE0 | c>>12);
-    putchar (0x80 | c>>6 & 0x3F);
-    putchar (0x80 | c & 0x3F);
-  }
-  else if (c < 0x200000) {
-    putchar (0xF0 | c>>18);
-    putchar (0x80 | c>>12 & 0x3F);
-    putchar (0x80 | c>>6 & 0x3F);
-    putchar (0x80 | c & 0x3F);
-  }
-}
-
-#endif
-
+
Index: trunk/src/helpers/except.c
===================================================================
--- trunk/src/helpers/except.c	(revision 152)
+++ trunk/src/helpers/except.c	(revision 153)
@@ -461,4 +461,5 @@
  *@@changed V0.9.13 (2001-06-19) [umoeller]: added global flag for whether this is running
  *@@changed V0.9.16 (2001-11-02) [pr]: make object display signed
+ *@@changed V0.9.19 (2002-03-28) [umoeller]: added thread ordinal
  */
 
@@ -659,6 +660,8 @@
                     "\nTrapping thread information:"
                     "\n    Thread ID:       0x%lX (%lu)"
+                    "\n    Thread slot ID:  0x%lX (%lu)"        // added V0.9.19 (2002-03-28) [umoeller]
                     "\n    Priority:        0x%lX\n",
                     ptib->tib_ptib2->tib2_ultid, ptib->tib_ptib2->tib2_ultid,
+                    ptib->tib_ordinal, ptib->tib_ordinal,
                     ulOldPriority);
         }
Index: trunk/src/helpers/makefile
===================================================================
--- trunk/src/helpers/makefile	(revision 152)
+++ trunk/src/helpers/makefile	(revision 153)
@@ -190,5 +190,8 @@
     $(TESTCASE_DIR)\dosh.obj \
     $(TESTCASE_DIR)\prfh.obj \
-    $(TESTCASE_DIR)\nls.obj
+    $(TESTCASE_DIR)\nls.obj \
+    $(TESTCASE_DIR)\except.obj \
+    $(TESTCASE_DIR)\debug.obj \
+    $(TESTCASE_DIR)\tree.obj
 
 vcard.exe: $(VCARD_TEST_OBJS)
Index: trunk/src/helpers/prfh.c
===================================================================
--- trunk/src/helpers/prfh.c	(revision 152)
+++ trunk/src/helpers/prfh.c	(revision 153)
@@ -526,10 +526,12 @@
  *
  *@@added V0.9.4 (2000-07-19) [umoeller]
- */
-
-BOOL prfhSetUserProfile(HAB hab,
-                        const char *pcszUserProfile)     // in: new user profile (.INI)
-{
-    BOOL    brc = FALSE;
+ *@@changed V0.9.19 (2002-04-02) [umoeller]: now returning APIRET
+ */
+
+APIRET prfhSetUserProfile(HAB hab,
+                          const char *pcszUserProfile)     // in: new user profile (.INI)
+{
+    APIRET arc = NO_ERROR;
+
     // find out current profile names
     PRFPROFILE Profiles;
@@ -553,12 +555,19 @@
                 Profiles.pszUserName = (PSZ)pcszUserProfile;
                 Profiles.cchUserName = strlen(pcszUserProfile) + 1;
-                brc = PrfReset(hab, &Profiles);
+                if (!PrfReset(hab, &Profiles))
+                    arc = PRFERR_RESET;
                 free(Profiles.pszSysName);
             }
+            else
+                arc = PRFERR_QUERY;
         }
-    }
-
-    return (brc);
-}
-
-
+        else
+            arc = PRFERR_QUERY;
+    }
+    else
+        arc = PRFERR_QUERY;
+
+    return (arc);
+}
+
+
Index: trunk/src/helpers/stringh.c
===================================================================
--- trunk/src/helpers/stringh.c	(revision 152)
+++ trunk/src/helpers/stringh.c	(revision 153)
@@ -326,6 +326,5 @@
             strupr(pszSrchFor);
 
-            prc = strstr(pszSrchIn, pszSrchFor);
-            if (prc)
+            if (prc = strstr(pszSrchIn, pszSrchFor))
             {
                 // prc now has the first occurence of the string,
@@ -371,4 +370,20 @@
 
     return (ul);
+}
+
+/*
+ *@@ strhlen:
+ *      like strlen, but doesn't crash on
+ *      null strings, but returns 0 also.
+ *
+ *@@added V0.9.19 (2002-04-02) [umoeller]
+ */
+
+ULONG strhlen(PCSZ pcsz)
+{
+    if (pcsz)
+        return (strlen(pcsz));
+
+    return 0;
 }
 
Index: trunk/src/helpers/winh.c
===================================================================
--- trunk/src/helpers/winh.c	(revision 152)
+++ trunk/src/helpers/winh.c	(revision 153)
@@ -60,4 +60,5 @@
 #define INCL_WINSTATICS
 #define INCL_WINMENUS
+#define INCL_WINENTRYFIELDS
 #define INCL_WINSCROLLBARS
 #define INCL_WINLISTBOXES
@@ -2352,4 +2353,5 @@
  *
  *@@added V0.9.0 [umoeller]
+ *@@changed V0.9.19 (2001-04-13) [umoeller]: added correlation for entry field repositioning, this was always off
  */
 
@@ -2372,4 +2374,8 @@
         LONG    ldcx, ldcy;
         ULONG   cWindows = 0;
+
+        // V0.9.19 (2001-04-13) [umoeller]
+        LONG cxMarginEF = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CXBORDER);
+        LONG cyMarginEF = 3 * WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER);
 
         // setup mode:
@@ -2391,7 +2397,22 @@
             {
                 HWND hwndThis;
+                CHAR szClass[10];
                 if (hwndThis = WinWindowFromID(hwndDlg, SHORT1FROMMP(*pmpThis)))
                 {
                     WinQueryWindowPos(hwndThis, pswpThis);
+
+                    // correlate the stupid repositioning of entry fields
+                    // V0.9.19 (2001-04-13) [umoeller]
+                    if (    (WinQueryClassName(hwndThis, sizeof(szClass), szClass)
+                         && (!strcmp(szClass, "#6"))
+                         && (WinQueryWindowULong(hwndThis, QWL_STYLE) & ES_MARGIN))
+                       )
+                    {
+                        pswpThis->x += cxMarginEF;
+                        pswpThis->y += cyMarginEF;
+                        pswpThis->cx -= 2 * cxMarginEF;
+                        pswpThis->cy -= 2 * cyMarginEF;
+                    }
+
                     cWindows++;
                 }
@@ -2422,6 +2443,6 @@
                  ul++)
             {
-                HWND hwndThis = WinWindowFromID(hwndDlg, SHORT1FROMMP(*pmpThis));
-                if (hwndThis)
+                HWND hwndThis;
+                if (hwndThis = WinWindowFromID(hwndDlg, SHORT1FROMMP(*pmpThis)))
                 {
                     LONG    x = pswpThis->x,
Index: trunk/src/helpers/xml.c
===================================================================
--- trunk/src/helpers/xml.c	(revision 152)
+++ trunk/src/helpers/xml.c	(revision 153)
@@ -39,5 +39,5 @@
  *      was supposed to be a C-only interface, we cannot implement
  *      inheritance at the language level. Instead, each XML document
- *      is broken up into a tree of node structures only (see _DOMNODE),
+ *      is broken up into a tree of node structures only (see DOMNODE),
  *      each of which has a special type. The W3C DOM allows this
  *      (and calls this the "flattened" view, as opposed to the
@@ -55,5 +55,5 @@
  *          (internal subset).
  *
- *      --  Not all node types are implemented. See _DOMNODE for
+ *      --  Not all node types are implemented. See DOMNODE for
  *          the supported types.
  *
@@ -145,10 +145,10 @@
 
 /*
- *@@category: Helpers\C helpers\XML
+ *@@category: Helpers\XML
  *      see xml.c.
  */
 
 /*
- *@@category: Helpers\C helpers\XML\Document Object Model (DOM)
+ *@@category: Helpers\XML\Document Object Model (DOM)
  *      see xml.c.
  */
@@ -2650,5 +2650,5 @@
 /*
  *@@ xmlFindElementDecl:
- *      returns the _CMELEMENTDECLNODE for the element
+ *      returns the CMELEMENTDECLNODE for the element
  *      with the specified name or NULL if there's none.
  *
@@ -2678,5 +2678,5 @@
 /*
  *@@ xmlFindAttribDeclBase:
- *      returns the _CMATTRIBUTEDECLBASE for the specified
+ *      returns the CMATTRIBUTEDECLBASE for the specified
  *      element name, or NULL if none exists.
  *
@@ -2708,5 +2708,5 @@
 /*
  *@@ xmlFindAttribDecl:
- *      returns the _CMATTRIBUTEDEDECL for the specified
+ *      returns the CMATTRIBUTEDEDECL for the specified
  *      element and attribute name, or NULL if none exists.
  *
@@ -2766,5 +2766,5 @@
  *@@ xmlGetFirstChild:
  *      returns the first child node of pDomNode.
- *      See _DOMNODE for what a "child" can be for the
+ *      See DOMNODE for what a "child" can be for the
  *      various node types.
  *
@@ -2784,5 +2784,5 @@
  *@@ xmlGetLastChild:
  *      returns the last child node of pDomNode.
- *      See _DOMNODE for what a "child" can be for the
+ *      See DOMNODE for what a "child" can be for the
  *      various node types.
  *
@@ -2827,5 +2827,5 @@
 /*
  *@@ xmlGetElementsByTagName:
- *      returns a linked list of _DOMNODE nodes which
+ *      returns a linked list of DOMNODE nodes which
  *      match the specified element name. The special name
  *      "*" matches all elements.
@@ -2860,7 +2860,7 @@
             if (    (pDomNodeThis = (PDOMNODE)pNode->pItemData)
                  && (pDomNodeThis->NodeBase.ulNodeType == DOMNODE_ELEMENT)
-                 && (   fFindAll
-                     || (!strcmp(pcszName, pDomNodeThis->NodeBase.strNodeName.psz))
-                   )
+                 && (    (fFindAll)
+                      || (!strcmp(pcszName, pDomNodeThis->NodeBase.strNodeName.psz))
+                    )
                )
             {
@@ -2899,8 +2899,7 @@
     // note, cheap trick: no malloc here, but we need
     // an XSTRING for treeFind
-    pAttrNode = (PDOMNODE)treeFind(pElement->AttributesMap,
-                                   (ULONG)&str,
-                                   CompareXStrings);
-    if (pAttrNode)
+    if (pAttrNode = (PDOMNODE)treeFind(pElement->AttributesMap,
+                                       (ULONG)&str,
+                                       CompareXStrings))
         return (pAttrNode->pstrNodeValue);
 
Index: trunk/src/helpers/xmlparse.c
===================================================================
--- trunk/src/helpers/xmlparse.c	(revision 152)
+++ trunk/src/helpers/xmlparse.c	(revision 153)
@@ -63,5 +63,5 @@
 
 /*
- *@@category: Helpers\C helpers\XML\expat
+ *@@category: Helpers\XML\expat
  *      expat XML parser. See xmlparse.c.
  */
Index: trunk/src/helpers/xstring.c
===================================================================
--- trunk/src/helpers/xstring.c	(revision 152)
+++ trunk/src/helpers/xstring.c	(revision 153)
@@ -110,4 +110,5 @@
 #include <stdlib.h>
 #include <stdio.h>
+#include <stdarg.h>
 #include <string.h>
 
@@ -1523,4 +1524,30 @@
 }
 
+/*
+ *@@ xstrPrintf:
+ *      like sprintf, but prints into an XSTRING
+ *      bufer (which must be initialized).
+ *
+ *      Note that the internal stack buffer is
+ *      limited to 2000 bytes, so watch out.
+ *
+ *@@added V0.9.19 (2002-03-28) [umoeller]
+ */
+
+VOID xstrPrintf(XSTRING *pstr,       // in/out: string buffer (must be init'ed)
+                PCSZ pcszFormat,     // in: format string (like with printf)
+                ...)                 // in: additional stuff (like with printf)
+{
+    va_list     args;
+    CHAR        szBuf[2000];
+
+    va_start(args, pcszFormat);
+    vsprintf(szBuf, pcszFormat, args);
+    va_end(args);
+
+    xstrcpy(pstr, szBuf, 0);
+}
+
+
 // test case
 
