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/12 20:38:08 UTC

svn commit: r898481 - in /commons/sandbox/runtime/trunk/src/main/native: include/acr_args.h include/arch/windows/acr_arch_registry.h os/win32/registry.c shared/args.c shared/ini.c shared/string.c test/testsuite.c

Author: mturk
Date: Tue Jan 12 19:38:08 2010
New Revision: 898481

URL: http://svn.apache.org/viewvc?rev=898481&view=rev
Log:
Implement Registry interpreter search

Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_args.h
    commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_registry.h
    commons/sandbox/runtime/trunk/src/main/native/os/win32/registry.c
    commons/sandbox/runtime/trunk/src/main/native/shared/args.c
    commons/sandbox/runtime/trunk/src/main/native/shared/ini.c
    commons/sandbox/runtime/trunk/src/main/native/shared/string.c
    commons/sandbox/runtime/trunk/src/main/native/test/testsuite.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=898481&r1=898480&r2=898481&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 12 19:38:08 2010
@@ -32,24 +32,53 @@
  */
 
 /**
+ * This function expands $(FOO) or ${FOO} to ACR_GetEnv("FOO")
+ * unless the $(FOO) is enclosed inside single quotes.
+ * Input string is freed if expansion took place.
+ * 
+ * @param str Input string to expand.
+ * @return expanded string.
+ */
+ACR_DECLARE(char *) ACR_ArgumentExpandA(char *str);
+
+/**
+ * This function expands $(FOO) or ${FOO} to ACR_GetEnv("FOO")
+ * unless the $(FOO) is enclosed inside single quotes.
+ * Input string is freed if expansion took place.
+ * 
+ * @param str Input string to expand.
+ * @return expanded string.
+ */
+ACR_DECLARE(wchar_t *) ACR_ArgumentExpandW(wchar_t *str);
+
+/**
  * This function provides a way to parse a generic argument string
  * into a standard argv[] form of argument list. It respects the
- * usual "whitespace" and quoteing rules. In the future this could
- * be expanded to include support for the apr_call_exec command line
- * string processing (including converting '+' to ' ' and doing the
- * url processing. It does not currently support this function.
+ * usual "whitespace" and quoteing rules.
+ * Params are used for single arguments $1...9 or %1...9 if provided
+ * the argument is replaced with empty string.
+ * Special $* or %* argument is replaced with space separated
+ * params.
+ * After the parameters are processed each argument is expanded
+ * using ACR_ArgumentExpand function.
  *
  * @param cmdline Input argument string for conversion to argv[].
- * @param argv Output location. This is a pointer to an array
- *             of pointers to strings (ie. &(char *argv[]).
- *             This value will be allocated from the contexts
- *             pool and filled in with copies of the tokens
- *             found during parsing of the cmdline.
- * @return number of argumennts in argv array or -1 in case of error.
+ * @param nparams Number of optional parameters.
+ * @param params Optional parameters array.
+ * @param argv Output location. Use ACR_Afree when no longer needed.
+ *
+ * @return number of arguments in argv array or -1 in case of error.
  */
 ACR_DECLARE(int) ACR_StringToArgvA(const char *cmdline,
+                                   int nparams,
+                                   char *const *params,
                                    char ***argv);
 
+ACR_DECLARE(int) ACR_StringToArgvW(const wchar_t *cmdline,
+                                   int nparams,
+                                   const wchar_t *const *params,
+                                   wchar_t ***argv);
+
 /**
  * Merge two argument arrays into one.
  * @param argv1 Source argument array.

Modified: commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_registry.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_registry.h?rev=898481&r1=898480&r2=898481&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_registry.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/arch/windows/acr_arch_registry.h Tue Jan 12 19:38:08 2010
@@ -69,6 +69,8 @@
     wchar_t    *name;
 } x_registry_t;
 
+ACR_DECLARE(int) ACR_GetInterpreterFromRegistry(const wchar_t *fname,
+                                                wchar_t ***args);
 
 #ifdef __cplusplus
 }

Modified: commons/sandbox/runtime/trunk/src/main/native/os/win32/registry.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/os/win32/registry.c?rev=898481&r1=898480&r2=898481&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/os/win32/registry.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/os/win32/registry.c Tue Jan 12 19:38:08 2010
@@ -23,12 +23,16 @@
 #include "acr_memory.h"
 #include "acr_string.h"
 #include "acr_tlsd.h"
+#include "acr_args.h"
+#include "acr_port.h"
 #include "acr_vm.h"
 
 #include <shlwapi.h>
 /* Windows Registry utility functions
  */
 
+extern wchar_t *SHELL_PATH;
+
 static HKEY reg_rootnamed(const char *name)
 {
     if (!strnicmp(name, "HKLM", 4))
@@ -439,7 +443,7 @@
         ACR_SET_OS_ERROR(ACR_EINVAL);
         return NULL;
     }
-    if ((rc = (LONG)RegQueryValueExW(k->key, name, NULL,
+    if ((rc = (int)RegQueryValueExW(k->key, name, NULL,
                         &rt, NULL, &rl)) != ERROR_SUCCESS) {
         goto cleanup;
     }
@@ -748,6 +752,139 @@
     return i;
 }
 
+ACR_DECLARE(int) ACR_GetInterpreterFromRegistry(const wchar_t *fname,
+                                                wchar_t ***args)
+{
+    int rc, argc;
+    wchar_t *cmd;
+    wchar_t *exn;
+    wchar_t **argv;
+    wchar_t  basename[MAX_PATH] = L"";
+    const wchar_t *ext;
+    const wchar_t *const opt[] = { fname, NULL };
+    x_registry_t k;
+
+    *args     = NULL;
+
+    if (*fname == L'.' && *(fname + 1) && iswalnum(*(fname + 1))) {
+        ext = fname;
+    }
+    else {
+        if (!basename_w(fname, basename, MAX_PATH))
+            return ACR_EINVAL;
+
+        ext = wcsrchr(basename, L'.');
+    }
+    if (!ext || !iswalnum(*(ext + 1))) {
+        /* Files without extension should be handled
+         * before calling this function
+         */
+        return ACR_EINVAL;
+    }
+    k.key  = NULL;
+    k.name = NULL;
+    k.sam  = KEY_READ;
+
+    /* Check if the fname is fname.exe in which case
+     * try the App Path first.
+     */
+    if (wcscmp(basename, fname) == 0 && wcscasecmp(ext, L".EXE") == 0) {
+        /* XXX: What is first checked? SearchPath or App Paths?
+         */
+        exn = ACR_StrvcatW(INVALID_HANDLE_VALUE, THROW_NMARK,
+                           NULL,
+                           L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\",
+                           basename,
+                           NULL);
+        if (exn == NULL)
+            return ACR_ENOMEM;
+
+        rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, exn, 0, k.sam, &k.key);
+        x_free(exn);
+        if (rc == 0) {
+            /* Key was found
+             */
+            exn = RegistryGetW(&k, NULL, 0);
+            SAFE_CLOSE_KEY(k.key);
+            if (exn) {
+                *args = s_malloc(wchar_t *, 2);
+                (*args)[0] = ACR_ArgumentExpandW(exn);
+                (*args)[1] = NULL;
+
+                return 0;
+            }
+        }
+        SAFE_CLOSE_KEY(k.key);
+    }
+
+    /* Step 1:
+     * Get the Shell handler from the HKCR
+     */
+
+    rc = RegOpenKeyExW(HKEY_CLASSES_ROOT, ext, 0, k.sam, &k.key);
+    if (rc) {
+        /* Extension was't found
+         */
+        return ACR_EBADF;
+    }
+    exn = RegistryGetW(&k, NULL, 0);
+    SAFE_CLOSE_KEY(k.key);
+
+    if (exn == NULL)
+        return ACR_ENOENT;
+
+    /* Step 2:
+     * Get the Shell open command
+     */
+    exn = ACR_StrvcatW(INVALID_HANDLE_VALUE, THROW_NMARK,
+                       exn, L"\\SHELL\\OPEN\\COMMAND", NULL);
+    if (exn == NULL)
+        return ACR_ENOMEM;
+
+    rc = RegOpenKeyExW(HKEY_CLASSES_ROOT, exn, 0, k.sam, &k.key);
+    x_free(exn);
+    if (rc) {
+        /* Shell handler was't found
+         * Corrupted registry?
+         */
+        return ACR_ENOENT;
+    }
+
+    cmd = RegistryGetW(&k, NULL, 0);
+    SAFE_CLOSE_KEY(k.key);
+
+    if (cmd == NULL)
+        return ACR_ENOENT;
+
+    if (wcscasecmp(ext, L".BAT") == 0 ||
+        wcscasecmp(ext, L".CMD") == 0) {
+        /* Special case for batch files */
+        wchar_t *sh = ACR_StrvcatW(INVALID_HANDLE_VALUE, THROW_NMARK,
+                                   NULL,
+                                   SHELL_PATH,
+                                   L" /D /C ",
+                                   cmd,
+                                   NULL);;
+        x_free(cmd);
+        cmd = sh;
+    }
+    /* Interpreter contains the raw Shell cmdline
+     * AFAICT the format is as follows:
+     * [["]Interpreter.exe["]] [additional cmd line options] [["]%1["]] [["]%*["]]
+     *
+     *
+     */
+    argc = ACR_StringToArgvW(cmd, 1, opt, &argv);
+    x_free(cmd);
+
+    if (argc > 0) {
+        *args = argv;
+        return 0;
+    }
+    else
+        return ACR_EOF;
+}
+
 static REGSAM _regsam_translate(int nsam)
 {
     REGSAM rsam = 0;

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=898481&r1=898480&r2=898481&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 12 19:38:08 2010
@@ -28,33 +28,64 @@
 
 /**
  * Just like strpbrk but it doesn't break if the char
- * is escaped by single quote
+ * is escaped inside single quotes
  */
 static char *strpbrk_s(const char *s1, const char *s2)
 {
     const char *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++) != 0;) {
-            if (sc == c && pc != '\'')
+        for (scanp = s2; (sc = *scanp++) != '\0';) {
+            if (sc == c && inquote == 0)
                 return (char *)(s1 - 1);
         }
         /* Don't update the previous marker if it was \' already
          * In that case we have escaped single quote.
          */
-        if (pc == '\\' && c == '\'')
-            pc = 0;
-        else
-            pc = c;
+        if (c == '\'' && pc != '\\')
+            inquote = !inquote;
+        pc = c;
     }
     return NULL;
 }
 
-static char *_strexpand(char *str)
+#if defined(WIN32)
+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;
+}
+#endif
+
+/* Expand $(FOO) or ${FOO} to ACR_GetEnv("FOO")
+ * Do not expand if the $(FOO) is enclosed inside
+ * single quotes.
+ * Input string is freed if expansion took place
+ */
+ACR_DECLARE(char *) ACR_ArgumentExpandA(char *str)
 {
     char        *var_pos;
     char        *var_end;
@@ -68,24 +99,6 @@
         return str; /* Guard against zero input */
     var_pos = strpbrk_s(var_ptr, "$");
     if (!var_pos) {
-#if defined(WIN32)
-        char *buf;
-        DWORD siz;
-
-        siz = ExpandEnvironmentStringsA(str, NULL, 0);
-        if (siz) {
-            buf = s_malloc(char, siz);
-            if (buf == NULL)
-                return str;
-            siz = ExpandEnvironmentStringsA(str, buf, siz);
-            if (!siz) {
-                x_free(buf);
-                return str;
-            }
-            x_free(str);
-            return buf;
-        }
-#endif
         /* Nothing to replace.
          */
         return str;
@@ -94,34 +107,39 @@
     /* Loop for each unescaped $ */
     while (var_pos) {
         int wch = 0;
+        int sch = *(var_pos);
+        int bch = *(var_pos + 1);
         var_end = NULL;
         var_rep = NULL;
-        if (*(var_pos + 1) == '(') {
+
+        *var_pos++ = '\0';
+        if (bch == '(') {
             var_end = strpbrk(var_pos + 1, " })");
             wch = ')';
         }
-        else if (*(var_pos + 1) == '{') {
+        else if (bch == '{') {
             var_end = strpbrk(var_pos + 1, " })");
             wch = '}';
         }
+        /* Add the string before $ */
+        acr_sbuf_cat(&sbuf, var_ptr);
+
         if (var_end && *var_end == wch) {
             *var_pos++ = '\0';
-            *var_pos++ = '\0';
             *var_end++ = '\0';
-            /* Add the string before $ */
-            acr_sbuf_cat(&sbuf, var_ptr);
-            /* var_pos holds the variable name */
+            /* var_pos holds the variable name
+             */
             var_rep = ACR_EnvGet(var_pos);
             if (var_rep) {
+                /* Replace ${FOO} with getenv("FOO")
+                 */
                 acr_sbuf_cat(&sbuf, var_rep);
                 x_free(var_rep);
             }
             else {
+                /* Put back the ${FOO} */
                 acr_sbuf_putc(&sbuf, '$');
-                if (wch == '}')
-                    acr_sbuf_putc(&sbuf, '{');
-                else
-                    acr_sbuf_putc(&sbuf, '(');
+                acr_sbuf_putc(&sbuf, bch);
                 acr_sbuf_cat(&sbuf, var_pos);
                 acr_sbuf_putc(&sbuf, wch);
             }
@@ -129,8 +147,6 @@
             var_pos = strpbrk_s(var_ptr, "$");
         }
         else {
-            *var_pos++ = '\0';
-            acr_sbuf_cat(&sbuf, var_ptr);
             acr_sbuf_putc(&sbuf, '$');
             var_ptr = var_pos;
             var_pos = strpbrk_s(var_ptr, "$");
@@ -138,40 +154,142 @@
     }
     /* Add what's left from the original string */
     acr_sbuf_cat(&sbuf, var_ptr);
+    acr_sbuf_rtrim(&sbuf);
     acr_sbuf_finish(&sbuf);
     x_free(str);
 
     str = acr_sbuf_data(&sbuf);
+#if defined(WIN32)
+    /* Check for the possible %FOO% */
+    if (strchr(str, '%')) {
+        char *buf;
+        DWORD siz;
+
+        siz = ExpandEnvironmentStringsA(str, NULL, 0);
+        if (siz) {
+            buf = s_malloc(char, siz);
+            if (buf == NULL)
+                return str;
+            siz = ExpandEnvironmentStringsA(str, buf, siz);
+            if (!siz) {
+                x_free(buf);
+                return str;
+            }
+            x_free(str);
+            return buf;
+        }
+    }
+#endif
+
     return str;
 }
 
-/*
- * This function provides a way to parse a generic argument string
- * into a standard argv[] form of argument list. It respects the
- * usual "whitespace" and quoteing rules. In the future this could
- * be expanded to include support for the apr_call_exec command line
- * string processing (including converting '+' to ' ' and doing the
- * url processing. It does not currently support this function.
- *
- *    cmdline:       Input argument string for conversion to argv[].
- *    argv:          Output location. This is a pointer to an array
- *                   of pointers to strings (ie. &(char *argv[]).
- *                   This value will be allocated from the contexts
- *                   pool and filled in with copies of the tokens
- *                   found during parsing of the cmdline.
+/* Expand $(FOO) or ${FOO} to ACR_GetEnv("FOO")
+ * Do not expand if the $(FOO) is enclosed inside
+ * single quotes.
+ * Input string is freed if expansion took place
  */
-ACR_DECLARE(int) ACR_StringToArgvA(const char *cmdline,
-                                   char ***argv)
+ACR_DECLARE(wchar_t *) ACR_ArgumentExpandW(wchar_t *str)
 {
-    const char *cp;
-    const char *ct;
-    char *cleaned, *dirty;
-    char *args;
-    char *argp;
-    char *exps;
-    int escaped;
-    int isquoted, numargs = 0, argnum;
-    size_t offset;
+#if defined(WIN32)
+    /* This function is noop for non windows platforms
+     */
+    wchar_t     *var_pos;
+    wchar_t     *var_end;
+    wchar_t     *var_ptr;
+    wchar_t     *var_rep;
+    acr_wbuf_t   sbuf;
+
+    var_ptr = str;
+
+    if (!var_ptr || !*var_ptr)
+        return str; /* Guard against zero input */
+    var_pos = wcspbrk_s(var_ptr, L"$");
+    if (!var_pos) {
+        /* Nothing to replace.
+         */
+        return str;
+    }
+    acr_wbuf_new(&sbuf, NULL, wcslen(str), ACR_SBUF_AUTOEXTEND);
+    /* Loop for each unescaped $ */
+    while (var_pos) {
+        wchar_t wch = 0;
+        wchar_t sch = *(var_pos);
+        wchar_t bch = *(var_pos + 1);
+        var_end = NULL;
+        var_rep = NULL;
+
+        *var_pos++ = L'\0';
+        if (bch == L'(') {
+            var_end = wcspbrk(var_pos + 1, L" })");
+            wch = L')';
+        }
+        else if (bch == L'{') {
+            var_end = wcspbrk(var_pos + 1, L" })");
+            wch = L'}';
+        }
+        /* Add the string before $ */
+        acr_wbuf_cat(&sbuf, var_ptr);
+
+        if (var_end && *var_end == wch) {
+            *var_pos++ = L'\0';
+            *var_end++ = L'\0';
+            /* var_pos holds the variable name
+             */
+            var_rep = acr_EnvGetW(var_pos);
+            if (var_rep) {
+                /* Replace ${FOO} with getenv("FOO")
+                 */
+                acr_wbuf_cat(&sbuf, var_rep);
+                x_free(var_rep);
+            }
+            else {
+                /* Put back the ${FOO} */
+                acr_wbuf_putc(&sbuf, L'$');
+                acr_wbuf_putc(&sbuf, bch);
+                acr_wbuf_cat(&sbuf, var_pos);
+                acr_wbuf_putc(&sbuf, wch);
+            }
+            var_ptr = var_end;
+            var_pos = wcspbrk_s(var_ptr, L"$");
+        }
+        else {
+            acr_wbuf_putc(&sbuf, L'$');
+            var_ptr = var_pos;
+            var_pos = wcspbrk_s(var_ptr, L"$");
+        }
+    }
+    /* Add what's left from the original string */
+    acr_wbuf_cat(&sbuf, var_ptr);
+    acr_wbuf_rtrim(&sbuf);
+    acr_wbuf_finish(&sbuf);
+    x_free(str);
+
+    str = acr_wbuf_data(&sbuf);
+    /* Check for the possible %FOO% */
+    if (wcschr(str, L'%')) {
+        wchar_t *buf;
+        DWORD    siz;
+
+        siz = ExpandEnvironmentStringsW(str, NULL, 0);
+        if (siz) {
+            buf = s_malloc(wchar_t, siz);
+            if (buf == NULL)
+                return str;
+            siz = ExpandEnvironmentStringsW(str, buf, siz);
+            if (!siz) {
+                x_free(buf);
+                return str;
+            }
+            x_free(str);
+            return buf;
+        }
+    }
+#endif
+
+    return str;
+}
+
 #define SKIP_WHITESPACEA(C)                 \
     for ( ; *C == ' ' || *C == '\t'; ) {    \
         C++;                                \
@@ -210,27 +328,252 @@
  * 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_CHARSA(C, D, E)   \
-    E = 0;                              \
-    while(*D) {                         \
-        if (!E && *D == '\\') {         \
-            E = 1;                      \
-        }                               \
-        else {                          \
-            E = 0;                      \
-            *C++ = *D;                  \
-        }                               \
-        ++D;                            \
-    }                                   \
+#define REMOVE_ESCAPE_CHARSA(C, D, E)                               \
+    E = 0;                                                          \
+    while(*D) {                                                     \
+        if (!E &&                                                   \
+            (*D == '\\' && (*(D+1) == ' ' || *(D+1) == '\t' ||      \
+                            *(D+1) == '"' || *(D+1) == '\''))) {    \
+            E = 1;                                                  \
+        }                                                           \
+        else {                                                      \
+            E = 0;                                                  \
+            *C++ = *D;                                              \
+        }                                                           \
+        ++D;                                                        \
+    }                                                               \
+    *C = 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.
+ */
+#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
 
+ACR_DECLARE(char *) ACR_StringGetWordA(char **line)
+{
+    char *cleaned;
+    char *dirty;
+    char *argp;
+    char *args = *line;
+    char *word;
+    int   escaped;
+    int   isquoted;
+
+    if (!*args)
+        return NULL;
+    SKIP_WHITESPACEA(args);
+    CHECK_QUOTATIONA(args, isquoted);
+    argp = args;
+    DETERMINE_NEXTSTRINGA(args, isquoted);
+    word = argp;
+    if (*args)
+        *(args++) = '\0';
+
+    cleaned = dirty = word;
+    REMOVE_ESCAPE_CHARSA(cleaned, dirty, escaped);
+
+    *line = args;
+    return word;
+}
+
+ACR_DECLARE(wchar_t *) ACR_StringGetWordW(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;
+}
+
+/*
+ * This function provides a way to parse a generic argument string
+ * into a standard argv[] form of argument list. It respects the
+ * usual "whitespace" and quoteing rules. In the future this could
+ * be expanded to include support for the apr_call_exec command line
+ * string processing (including converting '+' to ' ' and doing the
+ * url processing. It does not currently support this function.
+ *
+ *    cmdline:       Input argument string for conversion to argv[].
+ *    argv:          Output location. This is a pointer to an array
+ *                   of pointers to strings (ie. &(char *argv[]).
+ *                   This value will be allocated from the contexts
+ *                   pool and filled in with copies of the tokens
+ *                   found during parsing of the cmdline.
+ */
+ACR_DECLARE(int) ACR_StringToArgvA(const char *cmdline,
+                                   int nparams,
+                                   char *const *params,
+                                   char ***argv)
+{
+    const char *cp;
+    char *args;
+    char *cmds;
+    int isquoted, numargs, argnum, argidx = 0;
+
+    SKIP_WHITESPACEA(cmdline);
     cp = cmdline;
-    SKIP_WHITESPACEA(cp);
-    exps = x_strdup(cp);
-    if (!exps)
+
+    /* 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 != '\0') {
+        CHECK_QUOTATIONA(cp, isquoted);
+        DETERMINE_NEXTSTRINGA(cp, isquoted);
+        if (*cp != '\0') {
+            cp++;
+        }
+        numargs++;
+        SKIP_WHITESPACEA(cp);
+    }
+    if (!argv) {
+        /* We are only interested in the number of arguments
+         */
+        return numargs;
+    }
+    cmds = x_strdup(cmdline);
+    if (!cmds)
+        return -1;
+    *argv = s_calloc(char *, numargs);
+    if (!*argv) {
+        x_free(cmds);
         return -1;
-    exps = _strexpand(exps);
-    ct   = exps;
+    }
+    args = cmds;
+    /*  determine first argument */
+    for (argnum = 0; argnum < (numargs - 1); argnum++) {
+        char *argument  = ACR_StringGetWordA(&args);
+
+        if (!argument)
+            break;
+        if (*argument == '%' || *argument == '$') {
+            cp = argument + 1;
+            if (*cp == '*' && *(cp + 1) == '\0') {
+                if (argidx <= nparams)
+                    break;
+                argument = x_strdup(params[argidx++]);
+                for (; argidx < nparams; argidx++) {
+                    argument = ACR_StrvcatA(INVALID_HANDLE_VALUE,
+                                            THROW_NMARK,
+                                            argument, " ",
+                                            params[argidx],
+                                            NULL);
+                }
+                (*argv)[argnum] = ACR_ArgumentExpandA(argument);
+                continue;
+            }
+            else if (acr_isdigit(*cp) && *(cp + 1) == '\0') {
+                argidx = *cp - '0';
+                if (argidx == 0) {
+                    if (argnum == 0) {
+                        /* Guard against '$0 ...' strings
+                         */
+                        break;
+                    }
+                    (*argv)[argnum] = x_strdup((*argv)[0]);
+                    continue;
+                }
+                else if (argidx <= nparams) {
+                    /* $n <- params[n-1] */
+                    argument = (char *)params[argidx-1];
+                }
+                else {
+                    /* We have $n without params[n-1]
+                     * Stop processing
+                     */
+                    break;
+                }
+            }
+        }
+        (*argv)[argnum] = ACR_ArgumentExpandA(x_strdup(argument));
+    }
+
+    x_free(cmds);
+    return argnum;
+}
+
+ACR_DECLARE(int) ACR_StringToArgvW(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
@@ -239,45 +582,78 @@
      * Must account for the trailing NULL arg.
      */
     numargs = 1;
-    while (*ct != '\0') {
-        CHECK_QUOTATIONA(ct, isquoted);
-        DETERMINE_NEXTSTRINGA(ct, isquoted);
-        if (*ct != '\0') {
-            ct++;
+    while (*cp != L'\0') {
+        CHECK_QUOTATIONW(cp, isquoted);
+        DETERMINE_NEXTSTRINGW(cp, isquoted);
+        if (*cp != L'\0') {
+            cp++;
         }
         numargs++;
-        SKIP_WHITESPACEA(ct);
+        SKIP_WHITESPACEW(cp);
     }
     if (!argv) {
-        x_free(exps);
+        /* We are only interested in the number of arguments
+         */
         return numargs;
     }
-    offset = ACR_ALIGN_DEFAULT(numargs * sizeof(char*));
-    args   = x_malloc(offset + strlen(exps) + 1);
-    if (!args) {
-        x_free(exps);
+    cmds = x_wcsdup(cmdline);
+    if (!cmds)
+        return -1;
+    *argv = s_calloc(wchar_t *, numargs);
+    if (!*argv) {
+        x_free(cmds);
         return -1;
     }
-    *argv = (char **)args;
-    args += offset;
-    strcpy(args, exps);
-    x_free(exps);
+    args = cmds;
     /*  determine first argument */
     for (argnum = 0; argnum < (numargs-1); argnum++) {
-        SKIP_WHITESPACEA(args);
-        CHECK_QUOTATIONA(args, isquoted);
-        argp = args;
-        DETERMINE_NEXTSTRINGA(args, isquoted);
-        args++;
-        (*argv)[argnum] = argp;
-        (*argv)[argnum][args - argp - 1] = '\0';
+        wchar_t *argument  = ACR_StringGetWordW(&args);
 
-        cleaned = dirty = (*argv)[argnum];
-        REMOVE_ESCAPE_CHARSA(cleaned, dirty, escaped);
+        if (!argument)
+            break;
+        if (*argument == L'%' || *argument == L'$') {
+            cp = argument + 1;
+            if (*cp == L'*' && *(cp + 1) == L'\0') {
+                if (argidx >= nparams)
+                    break;
+                argument = x_wcsdup(params[argidx++]);
+                for (; argidx < nparams; argidx++) {
+                    argument = ACR_StrvcatW(INVALID_HANDLE_VALUE,
+                                            THROW_NMARK,
+                                            argument, L" ",
+                                            params[argidx],
+                                            NULL);
+                }
+                (*argv)[argnum] = ACR_ArgumentExpandW(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] = x_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] = ACR_ArgumentExpandW(x_wcsdup(argument));
     }
-    /* Always NULL terminate the array */
-    (*argv)[argnum] = NULL;
 
+    x_free(cmds);
     return argnum;
 }
 

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/ini.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/ini.c?rev=898481&r1=898480&r2=898481&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/ini.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/ini.c Tue Jan 12 19:38:08 2010
@@ -435,28 +435,28 @@
 
 /**
  * Just like strpbrk but it doesn't break if the char
- * is escaped by single quote
+ * is escaped inside single quotes.
  */
 static char *strpbrk_s(const char *s1, const char *s2)
 {
     const char *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++) != 0;) {
-            if (sc == c && pc != '\'')
+        for (scanp = s2; (sc = *scanp++) != '\0';) {
+            if (sc == c && inquote == 0)
                 return (char *)(s1 - 1);
         }
         /* Don't update the previous marker if it was \' already
          * In that case we have escaped single quote.
          */
-        if (pc == '\\' && c == '\'')
-            pc = 0;
-        else
-            pc = c;
+        if (c == '\'' && pc != '\\')
+            inquote = !inquote;
+        pc = c;
     }
     return NULL;
 }

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/string.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/string.c?rev=898481&r1=898480&r2=898481&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/string.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/string.c Tue Jan 12 19:38:08 2010
@@ -1026,9 +1026,10 @@
         else {
             len = strlen(argp);
         }
-
-        memcpy(cp, argp, len);
-        cp += len;
+        if (len) {
+            memcpy(cp, argp, len);
+            cp += len;
+        }
     }
     va_end(adummy);
 
@@ -1063,7 +1064,11 @@
 
     /* Allocate the required string */
 
-    res = (wchar_t *)ACR_Malloc(_E, file, line, (len + 1) * sizeof(wchar_t));
+    res = ACR_MALLOC(wchar_t, len + 1);
+    if (!res) {
+        x_free(p);
+        return NULL;    
+    }
     cp = res;
     if (p) {
         memcpy(cp, p, wcslen(p) * sizeof(wchar_t));

Modified: commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c?rev=898481&r1=898480&r2=898481&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c Tue Jan 12 19:38:08 2010
@@ -56,6 +56,7 @@
 #define _TXT(X)       L ## X
 static LPWSTR wide_args[64];
 static LPWSTR *wargv = NULL;
+#include "acr_arch_registry.h"
 #else
 extern mode_t acr_default_umask;
 extern mode_t acr_default_perms;
@@ -656,6 +657,32 @@
     return 0;
 }
 
+#if defined(WIN32)
+static int test_registry(int argc, const char *const argv[])
+{
+    wchar_t **args;
+    wchar_t **ap;
+    int rc;
+
+    if (argc < 1) {
+        return ACR_EINVAL;
+    }
+    rc = ACR_GetInterpreterFromRegistry(wargv[0], &args);
+    if (rc) {
+        fprintf(stderr, "Failed with %d\n", rc);
+        return rc;
+    }
+    ap = args;
+    while(*ap) {
+        fprintf(stdout, "ARG : %S.\n", *ap);    
+        ap++;
+    }
+    ACR_Afree(INVALID_HANDLE_VALUE, THROW_FMARK, args);
+    return 0;
+}
+
+#endif
+
 int main(int argc, const char *const argv[])
 {
     int rv = 0;
@@ -767,6 +794,12 @@
         else if (!strcasecmp(run_test, "daemon")) {
             rv = test_exec4(argc, argv);
         }
+#if defined(WIN32)
+        else if (!strcasecmp(run_test, "registry")) {
+            rv = test_registry(argc, argv);
+        }
+
+#endif        
     }
 
 cleanup: