Index: /trunk/include/helpers/dosh.h
===================================================================
--- /trunk/include/helpers/dosh.h	(revision 42)
+++ /trunk/include/helpers/dosh.h	(revision 43)
@@ -330,4 +330,10 @@
      *
      ********************************************************************/
+
+    APIRET doshFindExecutable(const char *pcszCommand,
+                              PSZ pszExecutable,
+                              ULONG cbExecutable,
+                              const char **papcszExtensions,
+                              ULONG cExtensions);
 
     APIRET doshExecVIO(const char *pcszExecWithArgs,
Index: /trunk/include/helpers/winh.h
===================================================================
--- /trunk/include/helpers/winh.h	(revision 42)
+++ /trunk/include/helpers/winh.h	(revision 43)
@@ -591,4 +591,11 @@
 
     #ifdef INCL_WINPROGRAMLIST
+        // additional PROG_* flags for winhQueryAppType
+        #define PROG_XWP_DLL            998      // dynamic link library
+
+        APIRET winhQueryAppType(const char *pcszExecutable,
+                                PULONG pulDosAppType,
+                                PULONG pulWinAppType);
+
         HAPP XWPENTRY winhStartApp(HWND hwndNotify, const PROGDETAILS *pcProgDetails);
     #endif
Index: /trunk/src/helpers/dosh.c
===================================================================
--- /trunk/src/helpers/dosh.c	(revision 42)
+++ /trunk/src/helpers/dosh.c	(revision 43)
@@ -1874,4 +1874,81 @@
 
 /*
+ *@@ doshFindExecutable:
+ *      this searches the PATH for the specified pcszCommand
+ *      by calling DosSearchPath.
+ *
+ *      papcszExtensions determines if additional searches are to be
+ *      performed if DosSearchPath returns ERROR_FILE_NOT_FOUND.
+ *      This must point to an array of strings specifying the extra
+ *      extensions to search for.
+ *
+ *      If both papcszExtensions and cExtensions are null, no
+ *      extra searches are performed.
+ *
+ *      If this returns NO_ERROR, pszExecutable receives
+ *      the full path of the executable found by DosSearchPath.
+ *      Otherwise ERROR_FILE_NOT_FOUND is returned.
+ *
+ *      Example:
+ *
+ +      const char *aExtensions[] = {  "EXE",
+ +                                     "COM",
+ +                                     "CMD"
+ +                                  };
+ +      CHAR szExecutable[CCHMAXPATH];
+ +      APIRET arc = doshFindExecutable("lvm",
+ +                                      szExecutable,
+ +                                      sizeof(szExecutable),
+ +                                      aExtensions,
+ +                                      3);
+ *
+ *@@added V0.9.9 (2001-03-07) [umoeller]
+ */
+
+APIRET doshFindExecutable(const char *pcszCommand,      // in: command (e.g. "lvm")
+                          PSZ pszExecutable,            // out: full path (e.g. "F:\os2\lvm.exe")
+                          ULONG cbExecutable,           // in: sizeof (*pszExecutable)
+                          const char **papcszExtensions, // in: array of extensions (without dots)
+                          ULONG cExtensions)            // in: array item count
+{
+    APIRET arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
+                               "PATH",
+                               (PSZ)pcszCommand,
+                               pszExecutable,
+                               cbExecutable);
+    if (    (arc == ERROR_FILE_NOT_FOUND)           // not found?
+         && (cExtensions)                    // any extra searches wanted?
+       )
+    {
+        // try additional things then
+        PSZ psz2 = malloc(strlen(pcszCommand) + 20);
+        if (psz2)
+        {
+            ULONG   ul;
+            for (ul = 0;
+                 ul < cExtensions;
+                 ul++)
+            {
+                const char *pcszExtThis = papcszExtensions[ul];
+                sprintf(psz2, "%s.%s", pcszCommand, pcszExtThis);
+                arc = DosSearchPath(SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY,
+                                    "PATH",
+                                    psz2,
+                                    pszExecutable,
+                                    cbExecutable);
+                if (arc != ERROR_FILE_NOT_FOUND)
+                    break;
+            }
+
+            free(psz2);
+        }
+        else
+            arc = ERROR_NOT_ENOUGH_MEMORY;
+    }
+
+    return (arc);
+}
+
+/*
  *@@ doshExecVIO:
  *      executes cmd.exe with the /c parameter
Index: /trunk/src/helpers/winh.c
===================================================================
--- /trunk/src/helpers/winh.c	(revision 42)
+++ /trunk/src/helpers/winh.c	(revision 43)
@@ -41,4 +41,5 @@
 #define INCL_DOSDEVICES
 #define INCL_DOSDEVIOCTL
+#define INCL_DOSSESMGR
 #define INCL_DOSERRORS
 
@@ -2557,4 +2558,76 @@
 
 /*
+ *@@ winhQueryAppType:
+ *      returns the Control Program (Dos) and
+ *      Win* PROG_* application types for the
+ *      specified executable. Essentially, this
+ *      is a wrapper around DosQueryAppType.
+ *
+ *      pcszExecutable must be fully qualified.
+ *      You can use doshFindExecutable to qualify
+ *      it.
+ *
+ *      This returns the APIRET of DosQueryAppType.
+ *      If this is NO_ERROR; *pulDosAppType receives
+ *      the app type of DosQueryAppType. In addition,
+ *      *pulWinAppType is set to one of the following:
+ *
+ *      --  PROG_FULLSCREEN
+ *
+ *      --  PROG_PDD
+ *
+ *      --  PROG_VDD
+ *
+ *      --  PROG_XWP_DLL: new apptype defined in winh.h for
+ *          dynamic link libraries.
+ *
+ *      --  PROG_WINDOWEDVDM
+ *
+ *      --  PROG_PM
+ *
+ *      --  PROG_31_ENH
+ *
+ *      --  PROG_WINDOWABLEVIO
+ *
+ *@@added V0.9.9 (2001-03-07) [umoeller]
+ */
+
+APIRET winhQueryAppType(const char *pcszExecutable,
+                        PULONG pulDosAppType,
+                        PULONG pulWinAppType)
+{
+    APIRET arc = DosQueryAppType((PSZ)pcszExecutable, pulDosAppType);
+    if (arc == NO_ERROR)
+    {
+        ULONG _ulDosAppType = *pulDosAppType;
+
+        if (_ulDosAppType == 0)
+            *pulWinAppType = PROG_FULLSCREEN;
+        else if (_ulDosAppType & 0x40)
+            *pulWinAppType = PROG_PDD;
+        else if (_ulDosAppType & 0x80)
+            *pulWinAppType = PROG_VDD;
+        else if ((_ulDosAppType & 0xF0) == 0x10)
+            // DLL bit set
+            *pulWinAppType = PROG_XWP_DLL;
+        else if (_ulDosAppType & 0x20)
+            // DOS bit set?
+            *pulWinAppType = PROG_WINDOWEDVDM;
+        else if ((_ulDosAppType & 0x0003) == 0x0003) // "Window-API" == PM
+            *pulWinAppType = PROG_PM;
+        else if (   ((_ulDosAppType & 0xFFFF) == 0x1000) // windows program (?!?)
+                 || ((_ulDosAppType & 0xFFFF) == 0x0400) // windows program (?!?)
+                )
+            *pulWinAppType = PROG_31_ENH;
+        else if ((_ulDosAppType & 0x03) == 0x02)
+            *pulWinAppType = PROG_WINDOWABLEVIO;
+        else if ((_ulDosAppType & 0x03) == 0x01)
+            *pulWinAppType = PROG_FULLSCREEN;
+    }
+
+    return (arc);
+}
+
+/*
  *@@ winhStartApp:
  *      wrapper around WinStartApp which fixes the
@@ -2569,4 +2642,10 @@
  *      -- starting ".CMD" and ".BAT" files as
  *         PROGDETAILS.pszExecutable.
+ *
+ *      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
@@ -2802,19 +2881,4 @@
             }
         }
-
-        // _Pmpf((__FUNCTION__ ": calling WinStartApp"));
-        // _Pmpf(("    exec: %s",
-        //             (ProgDetails.pszExecutable)
-                        // ? ProgDetails.pszExecutable
-                    // : "NULL"));
-        // _Pmpf(("    startupDir: %s",
-           //      (ProgDetails.pszStartupDir)
-              //       ? ProgDetails.pszStartupDir
-                 //    : "NULL"));
-        // _Pmpf(("    params: %s",
-           //      (pszParamsPatched)
-              //       ? pszParamsPatched
-                 //    : "NULL"));
-        // _Pmpf(("    new progc: 0x%lX", ProgDetails.progt.progc));
 
         ProgDetails.pszParameters = strParamsPatched.psz;
@@ -3282,8 +3346,8 @@
                          ULONG flFrameCreateFlags,  // in: FCF_* flags
                          ULONG ulFrameStyle,        // in: WS_* flags (e.g. WS_VISIBLE, WS_ANIMATE)
-                         const char *pcszFrameTitle,
+                         const char *pcszFrameTitle, // in: frame title (title bar)
                          ULONG ulResourcesID,       // in: according to FCF_* flags
-                         const char *pcszClassClient,
-                         ULONG flStyleClient,
+                         const char *pcszClassClient, // in: client class name
+                         ULONG flStyleClient,       // in: client style
                          ULONG ulID,                // in: frame window ID
                          PVOID pClientCtlData,      // in: pCtlData structure pointer for client
Index: /trunk/src/helpers/xstring.c
===================================================================
--- /trunk/src/helpers/xstring.c	(revision 42)
+++ /trunk/src/helpers/xstring.c	(revision 43)
@@ -1083,4 +1083,41 @@
 }
 
+// static encoding table for xstrEncode
+static PSZ apszEncoding[] =
+{
+    "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
+    "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
+    "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
+    "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
+    "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
+    "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F",
+    "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37",
+    "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
+    "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47",
+    "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F",
+    "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57",
+    "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F",
+    "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67",
+    "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F",
+    "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77",
+    "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F",
+    "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
+    "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
+    "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
+    "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
+    "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
+    "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
+    "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
+    "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
+    "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
+    "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
+    "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
+    "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
+    "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
+    "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
+    "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
+    "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
+};
+
 /*
  *@@ xstrEncode:
@@ -1116,7 +1153,8 @@
  +          S%61mple %63hara%63ters.
  *
- *      Memory cost: None, except for that of xstrFindReplace.
+ *      Memory cost: None, except for that of xstrcpy.
  *
  *@@added V0.9.9 (2001-02-28) [umoeller]
+ *@@changed V0.9.9 (2001-03-06) [lafaix]: rewritten.
  */
 
@@ -1125,37 +1163,57 @@
 {
     ULONG ulrc = 0,
-          ul;
-
-    // now encode the widget setup string...
-    for (ul = 0;
-         ul < strlen(pcszEncode);
-         ul++)
-    {
-        CHAR        szFind[3] = "?",
-                    szReplace[10] = "%xx";
-        XSTRING     strFind,
-                    strReplace;
-        size_t      ShiftTable[256];
-        BOOL        fRepeat = FALSE;
-        ULONG       ulOfs = 0;
-
-        // search string:
-        szFind[0] = pcszEncode[ul];
-        xstrInitSet(&strFind, szFind);
-
-        // replace string: ASCII encoding
-        sprintf(szReplace, "%%%lX", pcszEncode[ul]);
-        xstrInitSet(&strReplace, szReplace);
-
-        // replace all occurences
-        while (xstrFindReplace(pxstr,
-                               &ulOfs,
-                               &strFind,
-                               &strReplace,
-                               ShiftTable,
-                               &fRepeat))
-                ulrc++;
-
-    } // for ul; next encoding
+          ul,
+          ulEncodeLength;
+
+    if (    (pxstr)
+         && (pxstr->ulLength)
+         && (pcszEncode)
+         && (ulEncodeLength = strlen(pcszEncode)))
+    {
+        PSZ pszDest = (PSZ)malloc(pxstr->ulLength * 3
+                                  + 1),
+            pszDestCurr = pszDest;
+
+        if (pszDest)
+        {
+            for (ul = 0;
+                 ul < pxstr->ulLength;
+                 ul++)
+            {
+                ULONG ulEncode;
+
+                for (ulEncode = 0;
+                     ulEncode < ulEncodeLength;
+                     ulEncode++)
+                {
+                    if (pxstr->psz[ul] == pcszEncode[ulEncode])
+                    {
+                        // use the static encoding table for speed
+                        memcpy(pszDestCurr,
+                               apszEncoding[(unsigned char)pcszEncode[ulEncode]],
+                               3);
+                        pszDestCurr += 3;
+                        ulrc++;
+                        goto iterate;
+                    }
+                }
+
+                *pszDestCurr++ = pxstr->psz[ul];
+
+                iterate:
+                    ;
+            }
+        }
+
+        // something was encoded; update pxstr
+        if (ulrc)
+        {
+            *pszDestCurr = 0;
+
+            xstrcpy(pxstr, pszDest, pszDestCurr-pszDest);
+        }
+
+        free(pszDest);
+    }
 
     return (ulrc);
@@ -1174,10 +1232,8 @@
  *      Returns the no. of encodings replaced.
  *
- *      Memory cost: Creates a temporary buffer with the
- *      length of pxstr and replaces pxstr with it, if any
- *      encodings were found. In other words, this is
- *      expensive for very large strings.
+ *      Memory cost: None.
  *
  *@@added V0.9.9 (2001-02-28) [umoeller]
+ *@@changed V0.9.9 (2001-03-06) [lafaix]: removed memory allocation
  */
 
@@ -1190,68 +1246,51 @@
        )
     {
-        ULONG   cbAllocated = pxstr->ulLength + 1;
-            // decoded string cannot be longer than source
-        PSZ     pszDest = (PSZ)malloc(cbAllocated);
-
-        if (pszDest)
+        const char  *pSource = pxstr->psz;
+        PSZ         pszDest  = (PSZ)pSource,
+                    pDest    = (PSZ)pSource;
+        CHAR        c;
+
+        while ((c = *pSource++))
         {
-            const char  *pSource = pxstr->psz;
-            PSZ         pDest = pszDest;
-
-            CHAR    c;
-
-            while ((c = *pSource++))
+            // pSource points to next char now
+
+            if (c == '%')
             {
-                // pSource points to next char now
-
-                if (c == '%')
+                static char ach[] = "0123456789ABCDEF";
+
+                // convert two chars after '%'
+                CHAR        c2,         // first char after '%'     --> hi-nibble
+                            c3;         // second char after '%'    --> lo-nibble
+                const char  *p2,        // for first char: points into ach or is NULL
+                            *p3;        // for second char: points into ach or is NULL
+                if (    (c2 = *pSource)
+                     && (p2 = strchr(ach, c2))
+                     && (c3 = *(pSource + 1))
+                     && (p3 = strchr(ach, c3))
+                   )
                 {
-                    static char ach[] = "0123456789ABCDEF";
-
-                    // convert two chars after '%'
-                    CHAR        c2,         // first char after '%'     --> hi-nibble
-                                c3;         // second char after '%'    --> lo-nibble
-                    const char  *p2,        // for first char: points into ach or is NULL
-                                *p3;        // for second char: points into ach or is NULL
-                    if (    (c2 = *pSource)
-                         && (p2 = strchr(ach, c2))
-                         && (c3 = *(pSource + 1))
-                         && (p3 = strchr(ach, c3))
-                       )
-                    {
-                        // both chars after '%' were valid:
-                        *pDest++ =    // lo-nibble:
-                                      (p3 - ach) // 0 for '0', 10 for 'A', ...
-                                      // hi-nibble:
-                                    + ((p2 - ach) << 4);
-                        // go on after that
-                        pSource += 2;
-                        // raise return count
-                        ulrc++;
-                        // next in loop
-                        continue;
-                    }
+                    // both chars after '%' were valid:
+                    *pDest++ =    // lo-nibble:
+                                  (p3 - ach) // 0 for '0', 10 for 'A', ...
+                                  // hi-nibble:
+                                + ((p2 - ach) << 4);
+                    // go on after that
+                    pSource += 2;
+                    // raise return count
+                    ulrc++;
+                    // next in loop
+                    continue;
                 }
-
-                // not encoding, or null after '%', or invalid encoding:
-                // just copy this
-                *pDest++ = c;
-            } // while ((ch = *pSource++))
-
-            if (ulrc)
-            {
-                // any encodings found:
-                // terminate target
-                *pDest = 0;
-
-                // replace source with target
-                free(pxstr->psz);
-                pxstr->psz = pszDest;
-                pxstr->cbAllocated = cbAllocated;
-                pxstr->ulLength = (pDest - pszDest);
             }
-            else
-                // no encodings found:
-                free(pszDest);
+
+            // not encoding, or null after '%', or invalid encoding:
+            // just copy this
+            *pDest++ = c;
+        } // while ((ch = *pSource++))
+
+        if (ulrc)
+        {
+            *pDest = 0;
+            pxstr->ulLength = (pDest - pszDest);
         }
     }
