You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2010/01/19 20:43:54 UTC

svn commit: r900929 - in /commons/sandbox/runtime/trunk/src/main/native: include/acr_args.h include/acr_port.h os/win32/exec.c os/win32/subproc.c port/shquote.c shared/args.c support/win32/wsuexec.c

Author: mturk
Date: Tue Jan 19 19:43:54 2010
New Revision: 900929

URL: http://svn.apache.org/viewvc?rev=900929&view=rev
Log:
Rewrite the argument processing code for win32

Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h
    commons/sandbox/runtime/trunk/src/main/native/include/acr_port.h
    commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
    commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
    commons/sandbox/runtime/trunk/src/main/native/port/shquote.c
    commons/sandbox/runtime/trunk/src/main/native/shared/args.c
    commons/sandbox/runtime/trunk/src/main/native/support/win32/wsuexec.c

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h Tue Jan 19 19:43:54 2010
@@ -85,6 +85,10 @@
                                    char *const *params,
                                    char ***argv);
 
+/**
+ * This function provides a way to parse a generic argument string
+ * Unicode version of ACR_StringToArgv
+ */
 ACR_DECLARE(int) ACR_StringToArgvW(const wchar_t *cmdline,
                                    int nparams,
                                    const wchar_t *const *params,
@@ -124,13 +128,13 @@
  * Sort the array of string using case insensitive order
  * @param pointer to char array to sort.
  */
-ACR_DECLARE(void) ACR_ArgsSortA(char *const **args);
+ACR_DECLARE(void) ACR_StrArraySortA(char *const **args);
 
 /**
  * Sort the array of wide string using case insensitive order
  * @param pointer to the wide char array to sort.
  */
-ACR_DECLARE(void) ACR_ArgsSortW(wchar_t *const **args);
+ACR_DECLARE(void) ACR_StrArraySortW(wchar_t *const **args);
 
 
 #ifdef __cplusplus

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_port.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_port.h?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_port.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_port.h Tue Jan 19 19:43:54 2010
@@ -133,7 +133,6 @@
 size_t shquote(const char *, char *, size_t);
 size_t shquotev(int, char * const *, char *, size_t);
 #endif
-size_t strquote(const char *, char *, size_t);
 size_t wcsquote(const wchar_t *, wchar_t *, size_t);
 size_t wcsquotev(int argc, wchar_t * const *, wchar_t *, size_t);
 

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/exec.c Tue Jan 19 19:43:54 2010
@@ -187,7 +187,7 @@
     if (envp) {
         /* Environmet is supposed to be sorted
          */
-        ACR_ArgsSortW(&envp);
+        ACR_StrArraySortW(&envp);
         envb = ACR_ArrayToMszStrW(envp);
         if (!envb) {
             rc = ACR_ENOMEM;

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/subproc.c Tue Jan 19 19:43:54 2010
@@ -79,6 +79,29 @@
  */
 extern wchar_t *dll_dos_modname;
 
+static wchar_t **CommandLineToArrayW(const wchar_t *cmdline, int *argc)
+{
+    int    i, rc = 0;
+    wchar_t **argv;
+    wchar_t **args;
+
+    if ((argv = CommandLineToArgvW(cmdline, argc)) == NULL)
+        return NULL;
+    args = s_malloc(wchar_t *, *argc + 1);
+    if (!args) {
+        rc = ACR_ENOMEM;
+        goto cleanup;
+    }
+    for (i = 0; i < *argc; i++)
+        args[i] = x_wcsdup(argv[i]);
+    args[i] = NULL;
+
+cleanup:
+    LocalFree(argv);
+    ACR_SET_OS_ERROR(rc);
+    return args;
+}
+
  /*
   * Instead in Makefile exports could go here as well
   *
@@ -142,8 +165,8 @@
         goto cleanup;
     }
 
-    argc = ACR_StringToArgvW(GetCommandLineW(), 0, NULL, &args);
-    if (argc < 0) {
+    args = CommandLineToArrayW(GetCommandLineW(), &argc);
+    if (args == NULL) {
         rc = ACR_GET_OS_ERROR();
         goto cleanup;
     }
@@ -843,7 +866,7 @@
     if (envp) {
         /* Environmet is supposed to be sorted
          */
-        ACR_ArgsSortW(&envp);
+        ACR_StrArraySortW(&envp);
         envb = ACR_ArrayToMszStrW(envp);
         if (!envb) {
             rc = ACR_ENOMEM;

Modified: commons/sandbox/runtime/trunk/src/main/native/port/shquote.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/port/shquote.c?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/port/shquote.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/port/shquote.c Tue Jan 19 19:43:54 2010
@@ -200,57 +200,6 @@
 /* Just like shquote but surounds the arg by double quotes if
  * the arg contains space sharacters
  */
-size_t strquote(const char *arg, char *buf, size_t bufsize)
-{
-    char   c;
-    size_t rv     = 0;
-    size_t quoted = 0;
-    int n;
-
-    /* Empty args are skipped */
-    if (!*arg) {
-        PUTC('\0');
-        return 0;
-    }
-    if (strpbrk(arg, " \t")) {
-        quoted = 1;
-    }
-    if (quoted) {
-        PUTC('"');
-    }
-    for (;;) {
-        INCH();
-        if (n == 0)
-            break;
-
-        if (c == '"') {
-            PUTC('\\');
-        }
-        else if (c == '\\') {
-            const char *bsp = arg;
-            /* Add extra backslash for each backslash
-             * followed by double quoute.
-             */
-            while (*bsp && *bsp == '\\')
-                bsp++;
-            if (*bsp == '"') {
-                PUTC('\\');
-            }
-
-        }
-        PUTC(c);
-        arg++;
-    }
-    if (quoted) {
-        PUTC('"');
-    }
-    /* Put NUL terminator, but don't count the NUL. */
-    PUTC('\0');
-    rv--;
-
-    return rv;
-}
-
 size_t wcsquote(const wchar_t *arg, wchar_t *buf, size_t bufsize)
 {
     wchar_t c;
@@ -280,11 +229,11 @@
         else if (c == L'\\') {
             const wchar_t *bsp = arg;
             /* Add extra backslash for each backslash
-             * followed by double quoute.
+             * followed by a double quoute or NUL.
              */
             while (*bsp && *bsp == L'\\')
                 bsp++;
-            if (*bsp == L'"') {
+            if (*bsp == L'"' || (*bsp == L'\0' && quoted)) {
                 PUTC(L'\\');
             }
 

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/args.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/args.c?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/args.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/args.c Tue Jan 19 19:43:54 2010
@@ -790,7 +790,7 @@
         return NULL;
     }
     while (*ap) {
-        size_t al = strquote(*ap, NULL, 0);
+        size_t al = shquote(*ap, NULL, 0);
         if (al == (size_t) -1) {
             ACR_SET_OS_ERROR(ACR_EILSEQ);
             return NULL;
@@ -810,7 +810,7 @@
             *(cp++) = ' ';
             --length;
         }
-        arglen = strquote(*ap, cp, length);
+        arglen = shquote(*ap, cp, length);
         cp += arglen;
         length -= arglen;
         ap++;
@@ -875,7 +875,7 @@
                       *((const wchar_t **)arg2));
 }
 
-ACR_DECLARE(void) ACR_ArgsSortA(char *const **args)
+ACR_DECLARE(void) ACR_StrArraySortA(char *const **args)
 {
     size_t len = 0;
     char *const *sa = *args;
@@ -885,7 +885,7 @@
     qsort((void *)&args, len, sizeof(char *), _strcompare);
 }
 
-ACR_DECLARE(void) ACR_ArgsSortW(wchar_t *const **args)
+ACR_DECLARE(void) ACR_StrArraySortW(wchar_t *const **args)
 {
     size_t len = 0;
     wchar_t *const *sa = *args;

Modified: commons/sandbox/runtime/trunk/src/main/native/support/win32/wsuexec.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/support/win32/wsuexec.c?rev=900929&r1=900928&r2=900929&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/support/win32/wsuexec.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/support/win32/wsuexec.c Tue Jan 19 19:43:54 2010
@@ -58,61 +58,10 @@
         }                                   \
     } while (0)
 
-#define SKIP_WHITESPACEW(C)                 \
-    for ( ; *C == L' ' || *C == L'\t'; ) {  \
-        C++;                                \
-    };
-
-#define CHECK_QUOTATIONW(C, Q)              \
-    Q = 0;                                  \
-    if (*C == L'"') {                       \
-        Q = 1;                              \
-        C++;                                \
-    }                                       \
-    else if (*C == L'\'') {                 \
-        Q = 2;                              \
-        C++;                                \
-    }
-
-/* DETERMINE_NEXTSTRING:
- * At exit, cp will point to one of the following:  NULL, SPACE, TAB or QUOTE.
- * NULL implies the argument string has been fully traversed.
+/* List of 'safe' environment variables
+ * for GCI processes
  */
-#define DETERMINE_NEXTSTRINGW(C, Q)                                 \
-    for ( ; *C != L'\0'; C++) {                                     \
-        if ((*C == L'\\' && (*(C+1) == L' ' || *(C+1) == L'\t' ||   \
-                             *(C+1) == L'"' || *(C+1) == L'\''))) { \
-            C++;                                                    \
-            continue;                                               \
-        }                                                           \
-        if ((!Q && (*C == L' ' || *C == L'\t'))                     \
-            || (Q == 1 && *C == L'"')                               \
-            || (Q == 2 && *C == L'\'')) {                           \
-            break;                                                  \
-        }                                                           \
-    }
-
-/* REMOVE_ESCAPE_CHARS:
- * Compresses the arg string to remove all of the '\' escape chars.
- * The final argv strings should not have any extra escape chars in it.
- */
-#define REMOVE_ESCAPE_CHARSW(C, D, E)                               \
-    E = 0;                                                          \
-    while(*D) {                                                     \
-        if (!E &&                                                   \
-            (*D == L'\\' && (*(D+1) == L' ' || *(D+1) == L'\t' ||   \
-                             *(D+1) == L'"' || *(D+1) == L'\''))) { \
-            E = 1;                                                  \
-        }                                                           \
-        else {                                                      \
-            E = 0;                                                  \
-            *C++ = *D;                                              \
-        }                                                           \
-        ++D;                                                        \
-    }                                                               \
-    *C = 0
-
-static const wchar_t *const safe_elist[] =
+static const wchar_t *const safe_env_lst[] =
 {
     /* variable name starts with */
     L"HTTP_",
@@ -164,6 +113,35 @@
     NULL
 };
 
+#if defined(DEBUG) || defined(_DEBUG)
+static void _dbg_printf(const char *format, ...)
+{
+    char    buff[ACR_HBUFF_SIZ];
+    char    *bp = buff;
+    char    *ep;
+    time_t  timevar;
+    struct  tm *lt;
+    va_list ap;
+
+    time(&timevar);
+    lt = localtime(&timevar);
+    ep = bp + ACR_HBUFF_SIZ;
+    snprintf(bp, (size_t)(ep - bp),
+             "[%u] [%d-%.2d-%.2d %.2d:%.2d:%.2d] ",
+             GetCurrentThreadId(),
+             lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday,
+             lt->tm_hour, lt->tm_min, lt->tm_sec);
+    bp += strlen(buff);
+    va_start(ap, format);
+    _vsnprintf(bp, (size_t)(ep - bp), format, ap);
+    va_end(ap);
+    OutputDebugStringA(buff);
+}
+#define DBG_PRINTF(x) _dbg_printf x
+#else
+#define DBG_PRINTF(x) //
+#endif
+
 static size_t wcsquote(const wchar_t *arg, wchar_t *buf, size_t bufsize)
 {
     wchar_t c;
@@ -193,11 +171,11 @@
         else if (c == L'\\') {
             const wchar_t *bsp = arg;
             /* Add extra backslash for each backslash
-             * followed by double quoute.
+             * followed by a double quoute or NUL.
              */
             while (*bsp && *bsp == L'\\')
                 bsp++;
-            if (*bsp == L'"') {
+            if (*bsp == L'"' || (*bsp == L'\0' && quoted)) {
                 PUTC(L'\\');
             }
 
@@ -215,61 +193,10 @@
     return rv;
 }
 
-static wchar_t *wcspbrk_s(const wchar_t *s1, const wchar_t *s2)
-{
-    const wchar_t *scanp;
-    int inquote = 0;
-    int c, sc, pc = *s1;
-
-    /* Some early sanity check */
-    if (!s1 || !*s1)
-        return NULL;
-    while ((c = *s1++) != 0) {
-        for (scanp = s2; (sc = *scanp++) != L'\0';) {
-            if (sc == c && inquote == 0)
-                return (wchar_t *)(s1 - 1);
-        }
-        /* Don't update the previous marker if it was \' already
-         * In that case we have escaped single quote.
-         */
-        if (c == L'\'' && pc != L'\\')
-            inquote = !inquote;
-        pc = c;
-    }
-    return NULL;
-}
-
-static wchar_t *getword(wchar_t **line)
-{
-    wchar_t *cleaned;
-    wchar_t *dirty;
-    wchar_t *argp;
-    wchar_t *args = *line;
-    wchar_t *word;
-    int      escaped;
-    int      isquoted;
-
-    if (!*args)
-        return NULL;
-    SKIP_WHITESPACEW(args);
-    CHECK_QUOTATIONW(args, isquoted);
-    argp = args;
-    DETERMINE_NEXTSTRINGW(args, isquoted);
-    word = argp;
-    if (*args)
-        *(args++) = L'\0';
-
-    cleaned = dirty = word;
-    REMOVE_ESCAPE_CHARSW(cleaned, dirty, escaped);
-
-    *line = args;
-    return word;
-}
-
 /*
  * Input string is freed if expansion took place
  */
-static wchar_t *eexpand(wchar_t *str)
+static wchar_t *ExpandEnvStringW(wchar_t *str)
 {
     if (str == NULL)
         return NULL;
@@ -280,25 +207,25 @@
 
         siz = ExpandEnvironmentStringsW(str, NULL, 0);
         if (siz) {
-            buf = (wchar_t *)malloc(siz * sizeof(wchar_t));
+            buf = s_malloc(wchar_t, siz);
             if (buf == NULL) {
                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
                 return str;
             }
             siz = ExpandEnvironmentStringsW(str, buf, siz);
             if (siz == 0) {
-                free(buf);
+                x_free(buf);
                 return str;
             }
-            free(str);
+            x_free(str);
             return buf;
         }
     }
     return str;
 }
 
-static wchar_t **mergeargs(const wchar_t *const *argv1,
-                           const wchar_t *const *argv2)
+static wchar_t **MergeArrays(const wchar_t *const *argv1,
+                             const wchar_t *const *argv2)
 {
     size_t    argnum = 0;
     wchar_t **dupargv  = NULL;
@@ -325,7 +252,7 @@
          */
         return NULL;
     }
-    dupargv = malloc((argnum + 1) * sizeof(wchar_t *));
+    dupargv = s_malloc(wchar_t *, argnum + 1);
     if (!dupargv) {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
@@ -356,7 +283,7 @@
     return dupargv;
 }
 
-static wchar_t *argstostr(const wchar_t *const *argv)
+static wchar_t *ArgvToCommandLineW(const wchar_t *const *argv)
 {
     size_t argnum = 0;
     size_t length = 0;
@@ -369,7 +296,7 @@
         return NULL;
     }
     while (*ap) {
-        size_t al = (*ap, NULL, 0);
+        size_t al = wcsquote(*ap, NULL, 0);
         if (al == (size_t) -1) {
             SetLastError(ERROR_INVALID_PARAMETER);
             return NULL;
@@ -379,7 +306,7 @@
     }
     if (length == 0)
         return NULL;
-    args = cp = malloc((length + 1) * sizeof(wchar_t));
+    args = cp = s_malloc(wchar_t, length + 1);
     if (!args) {
         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
         return NULL;
@@ -400,101 +327,28 @@
     return args;
 }
 
-static int strtoargs(const wchar_t *cmdline,
-                     int nparams,
-                     const wchar_t *const *params,
-                     wchar_t ***argv)
-{
-    const wchar_t *cp;
-    wchar_t *args;
-    wchar_t *cmds;
-    int isquoted, numargs, argnum, argidx = 0;
-
-    SKIP_WHITESPACEW(cmdline);
-    cp = cmdline;
-
-    /* This is ugly and expensive, but if anyone wants to figure a
-     * way to support any number of args without counting and
-     * allocating, please go ahead and change the code.
-     *
-     * Must account for the trailing NULL arg.
-     */
-    numargs = 1;
-    while (*cp != L'\0') {
-        CHECK_QUOTATIONW(cp, isquoted);
-        DETERMINE_NEXTSTRINGW(cp, isquoted);
-        if (*cp != L'\0') {
-            cp++;
-        }
-        numargs++;
-        SKIP_WHITESPACEW(cp);
-    }
-    if (!argv) {
-        /* We are only interested in the number of arguments
-         */
-        return numargs;
-    }
-    cmds = wcsdup(cmdline);
-    if (!cmds) {
-        return -1;
-    }
-    *argv = calloc(numargs, sizeof(wchar_t *));
-    if (!*argv) {
-        x_free(cmds);
-        return -1;
-    }
-    args = cmds;
-    /*  determine first argument */
-    for (argnum = 0; argnum < (numargs-1); argnum++) {
-        wchar_t *argument  = getword(&args);
+static wchar_t **CommandLineToArrayW(const wchar_t *cmdline, int *argc)
+{
+    int    i, rc = 0;
+    wchar_t **argv;
+    wchar_t **args;
 
-        if (!argument)
-            break;
-        if (*argument == L'%' || *argument == L'$') {
-            cp = argument + 1;
-            if (*cp == L'*' && *(cp + 1) == L'\0') {
-                if (argidx >= nparams)
-                    break;
-                argument = wcsdup(params[argidx++]);
-                for (; argidx < nparams; argidx++) {
-                    wchar_t *as = malloc((wcslen(argument) + wcslen(params[argidx]) + 2) * sizeof(wchar_t));
-                    wcscpy(as, argument);
-                    wcscat(as, L" ");
-                    wcscat(as, params[argidx]);
-                    free(argument);
-                    argument = as;
-                }
-                (*argv)[argnum] = eexpand(argument);
-                continue;
-            }
-            else if (iswdigit(*cp) && *(cp + 1) == L'\0') {
-                argidx = *cp - L'0';
-                if (argidx == 0) {
-                    if (argnum == 0) {
-                        /* Guard against '$0 ...' strings
-                         */
-                        break;
-                    }
-                    (*argv)[argnum] = wcsdup((*argv)[0]);
-                    continue;
-                }
-                else if (argidx <= nparams) {
-                    /* $n <- params[n-1] */
-                    argument = (wchar_t *)params[argidx-1];
-                }
-                else {
-                    /* We have $n without params[n-1]
-                     * Stop processing
-                     */
-                    break;
-                }
-            }
-        }
-        (*argv)[argnum] = eexpand(wcsdup(argument));
+    if ((argv = CommandLineToArgvW(cmdline, argc)) == NULL)
+        return NULL;
+    args = s_malloc(wchar_t *, *argc + 1);
+    if (!args) {
+        rc = ERROR_NOT_ENOUGH_MEMORY;
+        goto cleanup;
     }
-
-    x_free(cmds);
-    return argnum;
+    for (i = 0; i < *argc; i++)
+        args[i] = x_wcsdup(argv[i]);
+    args[i] = NULL;
+
+cleanup:
+    LocalFree(argv);
+    if (rc)
+        SetLastError(rc);
+    return args;
 }
 
 static int _vwcsicmp(const void *arg1, const void *arg2)
@@ -504,7 +358,7 @@
                     *((const wchar_t **)arg2));
 }
 
-static void envsort(wchar_t *const **envp)
+static void SortEnvoronmentArray(wchar_t *const **envp)
 {
     size_t len = 0;
     wchar_t *const *ea = *envp;
@@ -514,12 +368,79 @@
     qsort((void *)&envp, len, sizeof(wchar_t *), _vwcsicmp);
 }
 
+static void dumpcmdline(const wchar_t *cmdline)
+{
+    wchar_t **args;
+    int i, nargs;
+
+    args = CommandLineToArgvW(cmdline, &nargs);
+
+    DBG_PRINTF(("Dumping %S", cmdline));
+    for (i = 0; i < nargs; i++) {
+        DBG_PRINTF(("ARGC[%d]='%S'\n", i, args[i]));
+    }
+}
+
+static void FreeArrayAndElements(void **arr)
+{
+    void **ptr = arr;
+
+    if (arr) {
+        while (*ptr != NULL)
+            x_free(*(ptr++));
+        x_free(arr);
+    }
+}
+
 int WINAPI wWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPWSTR lpCmdLine,
                     int nCmdShow)
 {
 
-    return 0;
-}
+    DWORD  rc = 0;
+    int    i;
+    int    argc;
+    wchar_t **args = NULL;
+    wchar_t **argv = NULL;
+    wchar_t  *cmdline = NULL;
+
+    args = CommandLineToArrayW(GetCommandLineW(), &argc);
+    if (args == NULL) {
+        rc = GetLastError();
+        goto cleanup;
+    }
+    argv = args;
+    if (argc < 2) {
+        /* First two arguments are wsuexec.exe and program to run
+         * Our private arguments always start with double hypen
+         * and end on first argument that doesn't start with it or
+         * with explicit "--" argument marker.
+         */
+        rc = ERROR_INVALID_PARAMETER;
+        goto cleanup;
+    }
+    cmdline = ArgvToCommandLineW(argv);
+    if (!cmdline) {
+        rc = ERROR_NOT_ENOUGH_MEMORY;
+        goto cleanup;
+    }
+    DBG_PRINTF(("CCMDLINE='%S'\n", cmdline));
+    for (i = 0; i < argc; i++) {
+        DBG_PRINTF(("ARGV[%d]='%S'\n", i, argv[i]));
+    }
+    /* Just for checking the CommandLineToArgvW parser
+     * and our wcsquote
+     */
+    dumpcmdline(cmdline);
 
+    FreeArrayAndElements(args);
+    return 0x20000000;
+
+cleanup:
+    FreeArrayAndElements(args);
+    /* We always return the Windows error code
+     * but add Error Severity and Customer code set.
+     */
+    return (rc | 0xE0000000);
+}