changeset 5562:107c19b4a22b

7188114: (launcher) need an alternate command line parser for Windows Reviewed-by: darcy, dholmes, jjh Contributed-by: akhil.arora@oracle.com
author ksrini
date Tue, 31 Jul 2012 06:10:01 -0700
parents 4e6d5548a253
children 7af05e99ff0e
files src/windows/bin/cmdtoargs.c
diffstat 1 files changed, 598 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/windows/bin/cmdtoargs.c	Tue Jul 31 06:10:01 2012 -0700
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * Converts a single string command line to the traditional argc, argv.
+ * There are rules which govern the breaking of the the arguments, and
+ * these rules are embodied in the regression tests below, and duplicated
+ * in the jdk regression tests.
+ */
+
+#ifndef IDE_STANDALONE
+#include "java.h"
+#include "jli_util.h"
+#else /* IDE_STANDALONE */
+// The defines we need for stand alone testing
+#include <stdio.h>
+#include <stdlib.h>
+#include <Windows.h>
+#define JNI_TRUE       TRUE
+#define JNI_FALSE      FALSE
+#define JLI_MemRealloc realloc
+#define JLI_StringDup  _strdup
+#define JLI_MemFree    free
+#define jboolean       boolean
+typedef struct  {
+    char* arg;
+    boolean has_wildcard;
+} StdArg ;
+#endif
+static StdArg *stdargs;
+static int    stdargc;
+
+static char* next_arg(char* cmdline, char* arg, jboolean* wildcard) {
+
+    char* src = cmdline;
+    char* dest = arg;
+    jboolean separator = JNI_FALSE;
+    int quotes = 0;
+    int slashes = 0;
+
+    char prev = 0;
+    char ch = 0;
+    int i;
+    jboolean done = JNI_FALSE;
+
+    *wildcard = JNI_FALSE;
+    while ((ch = *src) != 0 && !done) {
+        switch (ch) {
+        case '"':
+            if (separator) {
+                done = JNI_TRUE;
+                break;
+            }
+            if (prev == '\\') {
+                for (i = 1; i < slashes; i += 2) {
+                    *dest++ = prev;
+                }
+                if (slashes % 2 == 1) {
+                    *dest++ = ch;
+                } else {
+                    quotes++;
+                }
+            } else if (prev == '"' && quotes % 2 == 0) {
+                quotes++;
+                *dest++ = ch; // emit every other consecutive quote
+            } else if (quotes == 0) {
+                quotes++; // starting quote
+            } else {
+                quotes--; // matching quote
+            }
+            slashes = 0;
+            break;
+
+        case '\\':
+            slashes++;
+            if (separator) {
+                done = JNI_TRUE;
+                separator = JNI_FALSE;
+            }
+            break;
+
+        case ' ':
+        case '\t':
+            if (quotes % 2 == 1) {
+                *dest++ = ch;
+            } else {
+                separator = JNI_TRUE;
+            }
+            slashes = 0;
+            break;
+
+        case '*':
+        case '?':
+            if (separator) {
+                done = JNI_TRUE;
+                separator = JNI_FALSE;
+                break;
+            }
+            if (quotes % 2 == 0) {
+                *wildcard = JNI_TRUE;
+            }
+            if (prev == '\\') {
+                *dest++ = prev;
+            }
+            *dest++ = ch;
+            break;
+
+        default:
+            if (prev == '\\') {
+                for (i = 0 ; i < slashes ; i++) {
+                   *dest++ = prev;
+                }
+                *dest++ = ch;
+            } else if (separator) {
+                done = JNI_TRUE;
+            } else {
+                *dest++ = ch;
+            }
+            slashes = 0;
+        }
+
+        if (!done) {
+            prev = ch;
+            src++;
+        }
+    }
+    if (prev == '\\') {
+        for (i = 0; i < slashes; i++) {
+            *dest++ = prev;
+        }
+    }
+    *dest = 0;
+    return done ? src : NULL;
+}
+
+int JLI_GetStdArgc() {
+    return stdargc;
+}
+
+StdArg* JLI_GetStdArgs() {
+    return stdargs;
+}
+
+void JLI_CmdToArgs(char* cmdline) {
+    int nargs = 0;
+    StdArg* argv = NULL;
+    jboolean wildcard = JNI_FALSE;
+    char* src = cmdline;
+
+    // allocate arg buffer with sufficient space to receive the largest arg
+    char* arg = JLI_StringDup(cmdline);
+
+    do {
+        src = next_arg(src, arg, &wildcard);
+        // resize to accommodate another Arg
+        argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg));
+        argv[nargs].arg = JLI_StringDup(arg);
+        argv[nargs].has_wildcard = wildcard;
+
+        nargs++;
+    } while (src != NULL);
+
+    stdargc = nargs;
+    stdargs = argv;
+}
+
+#ifdef IDE_STANDALONE
+void doexit(int rv) {
+    printf("Hit any key to quit\n");
+    int c = getchar();
+    exit(rv);
+}
+
+void doabort() {
+    doexit(1);
+}
+
+class Vector {
+public:
+    char* cmdline;
+    int argc;
+    char* argv[10];
+    boolean wildcard[10];
+    boolean enabled;
+
+    Vector(){}
+    // Initialize our test vector with the program name, argv[0]
+    // and the single string command line.
+    Vector(char* pname, char* cline) {
+        argv[0] = pname;
+        wildcard[0] = FALSE;
+        cmdline = cline;
+        argc = 1;
+        enabled = TRUE;
+    }
+
+    // add our expected strings, the program name has already been
+    // added so ignore that
+    void add(char* arg, boolean w) {
+        argv[argc] = arg;
+        wildcard[argc] = w;
+        argc++;
+    }
+
+    void disable() {
+        enabled = FALSE;
+    }
+
+    // validate the returned arguments with the expected arguments, using the
+    // new CmdToArgs method.
+    bool check() {
+        // "pgmname" rest of cmdline ie. pgmname + 2 double quotes + space + cmdline from windows
+        char* cptr = (char*) malloc(strlen(argv[0]) + sizeof(char) * 3 + strlen(cmdline) + 1);
+        _snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline);
+        JLI_CmdToArgs(cptr);
+        free(cptr);
+        StdArg *kargv = JLI_GetStdArgs();
+        int     kargc = JLI_GetStdArgc();
+        bool retval = true;
+        printf("\n===========================\n");
+        printf("cmdline=%s\n", cmdline);
+        if (argc != kargc) {
+            printf("*** argument count does not match\n");
+            printme();
+            printtest(kargc, kargv);
+            doabort();
+        }
+        for (int i = 0 ; i < argc && retval == true ; i++) {
+            if (strcmp(argv[i], kargv[i].arg) != 0) {
+                printf("*** argument at [%d] don't match\n  got: %s\n  exp: %s\n",
+                       i, kargv[i].arg, argv[i]);
+                doabort();
+            }
+        }
+        for (int i = 0 ; i < argc && retval == true ; i++) {
+            if (wildcard[i] != kargv[i].has_wildcard) {
+                printf("*** expansion flag at [%d] doesn't match\n  got: %d\n  exp: %d\n",
+                       i, kargv[i].has_wildcard, wildcard[i]);
+                doabort();
+            }
+        }
+        for (int i = 0 ; i < kargc ; i++) {
+            printf("k[%d]=%s\n", i, kargv[i].arg);
+            printf(" [%d]=%s\n", i, argv[i]);
+        }
+        return retval;
+    }
+    void printtest(int kargc, StdArg* kargv) {
+        for (int i = 0 ; i < kargc ; i++) {
+            printf("k[%d]=%s\n", i, kargv[i].arg);
+        }
+    }
+    void printme() {
+        for (int i = 0 ; i < argc ; i++) {
+            printf(" [%d]=%s\n", i, argv[i]);
+        }
+    }
+};
+
+void dotest(Vector** vectors) {
+    Vector* v = vectors[0];
+    for (int i = 0 ; v != NULL;) {
+        if (v->enabled) {
+            v->check();
+        }
+        v = vectors[++i];
+    }
+}
+
+#define MAXV 128
+int main(int argc, char* argv[]) {
+
+    int n;
+    for (n=1; n < argc; n++) {
+        printf("%d %s\n", n, argv[n]);
+    }
+    if (n > 1) {
+        JLI_CmdToArgs(GetCommandLine());
+        for (n = 0; n < stdargc; n++) {
+            printf(" [%d]=%s\n", n, stdargs[n].arg);
+            printf(" [%d]=%s\n", n, stdargs[n].has_wildcard ? "TRUE" : "FALSE");
+        }
+        doexit(0);
+    }
+
+    Vector *vectors[MAXV];
+
+    memset(vectors, 0, sizeof(vectors));
+    int i = 0;
+    Vector* v = new Vector(argv[0], "abcd");
+    v->add("abcd", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"a b c d\"");
+    v->add("a b c d", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a\"b c d\"e");
+    v->add("ab c de", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "ab\\\"cd");
+    v->add("ab\"cd", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"a b c d\\\\\"");
+    v->add("a b c d\\", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "ab\\\\\\\"cd");
+    v->add("ab\\\"cd", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    // Windows tests
+    v = new Vector(argv[0], "a\\\\\\c");
+    v->add("a\\\\\\c", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"a\\\\\\d\"");
+    v->add("a\\\\\\d", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"a b c\" d e");
+    v->add("a b c", FALSE);
+    v->add("d", FALSE);
+    v->add("e", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"ab\\\"c\"  \"\\\\\"  d");
+    v->add("ab\"c", FALSE);
+    v->add("\\", FALSE);
+    v->add("d", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a\\\\\\c d\"e f\"g h");
+    v->add("a\\\\\\c", FALSE);
+    v->add("de fg", FALSE);
+    v->add("h", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a\\\\\\\"b c d");
+    v->add("a\\\"b", FALSE); // XXX "a\\\\\\\"b"
+    v->add("c", FALSE);
+    v->add("d", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a\\\\\\\\\"g c\" d e"); // XXX "a\\\\\\\\\"b c\" d e"
+    v->add("a\\\\\g c", FALSE); // XXX "a\\\\\\\\\"b c"
+    v->add("d", FALSE);
+    v->add("e", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    // Additional tests
+    v = new Vector(argv[0], "\"a b c\"\"");
+    v->add("a b c\"", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"\"a b c\"\"");
+    v->add("a", FALSE);
+    v->add("b", FALSE);
+    v->add("c", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"\"\"a b c\"\"\"");
+    v->add("\"a b c\"", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"\"\"\"a b c\"\"\"\"");
+    v->add("\"a", FALSE);
+    v->add("b", FALSE);
+    v->add("c\"", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"\"\"\"\"a b c\"\"\"\"\"");
+    v->add("\"\"a b c\"\"", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"C:\\TEST A\\\\\"");
+    v->add("C:\\TEST A\\", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"\"C:\\TEST A\\\\\"\"");
+    v->add("C:\\TEST", FALSE);
+    v->add("A\\", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    // test if a wildcard is present
+    v = new Vector(argv[0], "abc*def");
+    v->add("abc*def", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"abc*def\"");
+    v->add("abc*def", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "*.abc");
+    v->add("*.abc", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"*.abc\"");
+    v->add("*.abc", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "x.???");
+    v->add("x.???", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\"x.???\"");
+    v->add("x.???", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "Debug\\*");
+    v->add("Debug\\*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "Debug\\f?a");
+    v->add("Debug\\f?a", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "Debug\\?a.java");
+    v->add("Debug\\?a.java", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "foo *.noexts");
+    v->add("foo", FALSE);
+    v->add("*.noexts", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "X\\Y\\Z");
+    v->add("X\\Y\\Z", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "\\X\\Y\\Z");
+    v->add("\\X\\Y\\Z", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a b");
+    v->add("a", FALSE);
+    v->add("b", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a\tb");
+    v->add("a", FALSE);
+    v->add("b", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+
+    v = new Vector(argv[0], "a \t b");
+    v->add("a", FALSE);
+    v->add("b", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "*\\");
+    v->add("*\\", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "*/");
+    v->add("*/", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], ".\\*");
+    v->add(".\\*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "./*");
+    v->add("./*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], ".\\*");
+    v->add(".\\*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], ".//*");
+    v->add(".//*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "..\\..\\*");
+    v->add("..\\..\\*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "../../*");
+    v->add("../../*", TRUE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "..\\..\\");
+    v->add("..\\..\\", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+    v = new Vector(argv[0], "../../");
+    v->add("../../", FALSE);
+    // v->disable();
+    vectors[i++] = v;
+
+    dotest(vectors);
+    printf("All tests pass [%d]\n", i);
+    doexit(0);
+}
+#endif /* IDE_STANDALONE */