/* * Copyright (c) 2012, 2015, 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 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 #include #include #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 int copyCh(USHORT ch, char* dest) { if (HIBYTE(ch) == 0) { *dest = (char)ch; return 1; } else { *((USHORT *)dest) = ch; return 2; } } 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; // "prev"/"ch" may contain either a single byte, or a double byte // character encoded in CP_ACP. USHORT prev = 0; USHORT ch = 0; int i; jboolean done = JNI_FALSE; ptrdiff_t charLength; *wildcard = JNI_FALSE; while (!done) { charLength = CharNextExA(CP_ACP, src, 0) - src; if (charLength == 0) { break; } else if (charLength == 1) { ch = (USHORT)(UCHAR)src[0]; } else { ch = ((USHORT *)src)[0]; } switch (ch) { case L'"': if (separator) { done = JNI_TRUE; break; } if (prev == L'\\') { for (i = 1; i < slashes; i += 2) { dest += copyCh(prev, dest); } if (slashes % 2 == 1) { dest += copyCh(ch, dest); } else { quotes++; } } else if (prev == L'"' && quotes % 2 == 0) { quotes++; dest += copyCh(ch, dest); // emit every other consecutive quote } else if (quotes == 0) { quotes++; // starting quote } else { quotes--; // matching quote } slashes = 0; break; case L'\\': slashes++; if (separator) { done = JNI_TRUE; separator = JNI_FALSE; } break; case L' ': case L'\t': if (prev == L'\\') { for (i = 0 ; i < slashes; i++) { dest += copyCh(prev, dest); } } if (quotes % 2 == 1) { dest += copyCh(ch, dest); } else { separator = JNI_TRUE; } slashes = 0; break; case L'*': case L'?': if (separator) { done = JNI_TRUE; separator = JNI_FALSE; break; } if (quotes % 2 == 0) { *wildcard = JNI_TRUE; } if (prev == L'\\') { for (i = 0 ; i < slashes ; i++) { dest += copyCh(prev, dest); } } dest += copyCh(ch, dest); break; default: if (prev == L'\\') { for (i = 0 ; i < slashes ; i++) { dest += copyCh(prev, dest); } dest += copyCh(ch, dest); } else if (separator) { done = JNI_TRUE; } else { dest += copyCh(ch, dest); } slashes = 0; } if (!done) { prev = ch; src += charLength; } } if (prev == L'\\') { for (i = 0; i < slashes; i++) { dest += copyCh(prev, dest); } } *dest = 0; return done ? src : NULL; } int JLI_GetStdArgc() { return stdargc; } StdArg* JLI_GetStdArgs() { return stdargs; } void JLI_ReleaseStdArgs() { StdArg* stdarg; for (stdarg = stdargs; stdarg < stdargs + stdargc; ++stdarg) { JLI_MemFree(stdarg->arg); } JLI_MemFree(stdargs); stdargs = NULL; stdargc = 0; } 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; *arg = '\0'; nargs++; } while (src != NULL); JLI_MemFree(arg); 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; v= new Vector(argv[0], "a b\\\\ d"); v->add("a", FALSE); v->add("b\\\\", FALSE); v->add("d", FALSE); vectors[i++] = v; v= new Vector(argv[0], "\\\\?"); v->add("\\\\?", TRUE); vectors[i++] = v; v= new Vector(argv[0], "\\\\*"); v->add("\\\\*", TRUE); vectors[i++] = v; dotest(vectors); printf("All tests pass [%d]\n", i); doexit(0); } #endif /* IDE_STANDALONE */