Path: blob/master/src/java.base/windows/native/libjli/cmdtoargs.c
41119 views
/*1* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/242526/*27* Converts a single string command line to the traditional argc, argv.28* There are rules which govern the breaking of the arguments, and29* these rules are embodied in the regression tests below, and duplicated30* in the jdk regression tests.31*/3233#include <assert.h>3435#ifndef IDE_STANDALONE36#include "java.h"37#include "jni.h"38#include "jli_util.h"39#else /* IDE_STANDALONE */40// The defines we need for stand alone testing41#include <stdio.h>42#include <stdlib.h>43#include <Windows.h>44#define JNI_TRUE TRUE45#define JNI_FALSE FALSE46#define JLI_MemRealloc realloc47#define JLI_StringDup _strdup48#define JLI_MemFree free49#define jboolean boolean50typedef struct {51char* arg;52boolean has_wildcard;53} StdArg ;54#endif55static StdArg *stdargs;56static int stdargc;5758static int copyCh(USHORT ch, char* dest) {59if (HIBYTE(ch) == 0) {60*dest = (char)ch;61return 1;62} else {63*((USHORT *)dest) = ch;64return 2;65}66}6768static char* next_arg(char* cmdline, char* arg, jboolean* wildcard) {6970char* src = cmdline;71char* dest = arg;72jboolean separator = JNI_FALSE;73int quotes = 0;74int slashes = 0;7576// "prev"/"ch" may contain either a single byte, or a double byte77// character encoded in CP_ACP.78USHORT prev = 0;79USHORT ch = 0;80int i;81jboolean done = JNI_FALSE;82ptrdiff_t charLength;8384*wildcard = JNI_FALSE;85while (!done) {86charLength = CharNextExA(CP_ACP, src, 0) - src;87if (charLength == 0) {88break;89} else if (charLength == 1) {90ch = (USHORT)(UCHAR)src[0];91} else {92ch = ((USHORT *)src)[0];93}9495switch (ch) {96case L'"':97if (separator) {98done = JNI_TRUE;99break;100}101if (prev == L'\\') {102for (i = 1; i < slashes; i += 2) {103dest += copyCh(prev, dest);104}105if (slashes % 2 == 1) {106dest += copyCh(ch, dest);107} else {108quotes++;109}110} else if (prev == L'"' && quotes % 2 == 0) {111quotes++;112dest += copyCh(ch, dest); // emit every other consecutive quote113} else if (quotes == 0) {114quotes++; // starting quote115} else {116quotes--; // matching quote117}118slashes = 0;119break;120121case L'\\':122slashes++;123if (separator) {124done = JNI_TRUE;125separator = JNI_FALSE;126}127break;128129case L' ':130case L'\t':131if (prev == L'\\') {132for (i = 0 ; i < slashes; i++) {133dest += copyCh(prev, dest);134}135}136if (quotes % 2 == 1) {137dest += copyCh(ch, dest);138} else {139separator = JNI_TRUE;140}141slashes = 0;142break;143144case L'*':145case L'?':146if (separator) {147done = JNI_TRUE;148separator = JNI_FALSE;149break;150}151if (quotes % 2 == 0) {152*wildcard = JNI_TRUE;153}154if (prev == L'\\') {155for (i = 0 ; i < slashes ; i++) {156dest += copyCh(prev, dest);157}158}159dest += copyCh(ch, dest);160slashes = 0;161break;162163default:164if (prev == L'\\') {165for (i = 0 ; i < slashes ; i++) {166dest += copyCh(prev, dest);167}168dest += copyCh(ch, dest);169} else if (separator) {170done = JNI_TRUE;171} else {172dest += copyCh(ch, dest);173}174slashes = 0;175}176177if (!done) {178prev = ch;179src += charLength;180}181}182if (prev == L'\\') {183for (i = 0; i < slashes; i++) {184dest += copyCh(prev, dest);185}186}187*dest = 0;188return done ? src : NULL;189}190191JNIEXPORT int JNICALL192JLI_GetStdArgc() {193return stdargc;194}195196JNIEXPORT StdArg* JNICALL197JLI_GetStdArgs() {198return stdargs;199}200201JNIEXPORT void JNICALL202JLI_CmdToArgs(char* cmdline) {203int nargs = 0;204StdArg* argv = NULL;205jboolean wildcard = JNI_FALSE;206char* src = cmdline, *arg = NULL;207JLI_List argsInFile;208size_t i, cnt;209210JLI_List envArgs = JLI_List_new(1);211if (JLI_AddArgsFromEnvVar(envArgs, JDK_JAVA_OPTIONS)) {212// JLI_SetTraceLauncher is not called yet213// Show _JAVA_OPTIONS content along with JDK_JAVA_OPTIONS to aid diagnosis214if (getenv(JLDEBUG_ENV_ENTRY)) {215char *tmp = getenv("_JAVA_OPTIONS");216if (NULL != tmp) {217JLI_ReportMessage(ARG_INFO_ENVVAR, "_JAVA_OPTIONS", tmp);218}219}220}221cnt = envArgs->size + 1;222argv = JLI_MemAlloc(cnt * sizeof(StdArg));223224// allocate arg buffer with sufficient space to receive the largest arg225arg = JLI_StringDup(cmdline);226227src = next_arg(src, arg, &wildcard);228// first argument is the app name, do not preprocess and make sure remains first229argv[0].arg = JLI_StringDup(arg);230argv[0].has_wildcard = wildcard;231nargs++;232233for (i = 1; i < cnt; i++) {234argv[i].arg = envArgs->elements[i - 1];235// wildcard is not supported in argfile236argv[i].has_wildcard = JNI_FALSE;237nargs++;238}239JLI_MemFree(envArgs->elements);240JLI_MemFree(envArgs);241242assert ((size_t) nargs == cnt);243*arg = '\0';244245// iterate through rest of command line246while (src != NULL) {247src = next_arg(src, arg, &wildcard);248argsInFile = JLI_PreprocessArg(arg, JNI_TRUE);249if (argsInFile != NULL) {250// resize to accommodate another Arg251cnt = argsInFile->size;252argv = (StdArg*) JLI_MemRealloc(argv, (nargs + cnt) * sizeof(StdArg));253for (i = 0; i < cnt; i++) {254argv[nargs].arg = argsInFile->elements[i];255// wildcard is not supported in argfile256argv[nargs].has_wildcard = JNI_FALSE;257nargs++;258}259// Shallow free, we reuse the string to avoid copy260JLI_MemFree(argsInFile->elements);261JLI_MemFree(argsInFile);262} else {263// resize to accommodate another Arg264argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg));265argv[nargs].arg = JLI_StringDup(arg);266argv[nargs].has_wildcard = wildcard;267*arg = '\0';268nargs++;269}270*arg = '\0';271}272273JLI_MemFree(arg);274275stdargc = nargs;276stdargs = argv;277}278279#ifdef IDE_STANDALONE280void doexit(int rv) {281printf("Hit any key to quit\n");282int c = getchar();283exit(rv);284}285286void doabort() {287doexit(1);288}289290class Vector {291public:292char* cmdline;293int argc;294char* argv[10];295boolean wildcard[10];296boolean enabled;297298Vector(){}299// Initialize our test vector with the program name, argv[0]300// and the single string command line.301Vector(char* pname, char* cline) {302argv[0] = pname;303wildcard[0] = FALSE;304cmdline = cline;305argc = 1;306enabled = TRUE;307}308309// add our expected strings, the program name has already been310// added so ignore that311void add(char* arg, boolean w) {312argv[argc] = arg;313wildcard[argc] = w;314argc++;315}316317void disable() {318enabled = FALSE;319}320321// validate the returned arguments with the expected arguments, using the322// new CmdToArgs method.323bool check() {324// "pgmname" rest of cmdline ie. pgmname + 2 double quotes + space + cmdline from windows325char* cptr = (char*) malloc(strlen(argv[0]) + sizeof(char) * 3 + strlen(cmdline) + 1);326_snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline);327JLI_CmdToArgs(cptr);328free(cptr);329StdArg *kargv = JLI_GetStdArgs();330int kargc = JLI_GetStdArgc();331bool retval = true;332printf("\n===========================\n");333printf("cmdline=%s\n", cmdline);334if (argc != kargc) {335printf("*** argument count does not match\n");336printme();337printtest(kargc, kargv);338doabort();339}340for (int i = 0 ; i < argc && retval == true ; i++) {341if (strcmp(argv[i], kargv[i].arg) != 0) {342printf("*** argument at [%d] don't match\n got: %s\n exp: %s\n",343i, kargv[i].arg, argv[i]);344doabort();345}346}347for (int i = 0 ; i < argc && retval == true ; i++) {348if (wildcard[i] != kargv[i].has_wildcard) {349printf("*** expansion flag at [%d] doesn't match\n got: %d\n exp: %d\n",350i, kargv[i].has_wildcard, wildcard[i]);351doabort();352}353}354for (int i = 0 ; i < kargc ; i++) {355printf("k[%d]=%s\n", i, kargv[i].arg);356printf(" [%d]=%s\n", i, argv[i]);357}358return retval;359}360void printtest(int kargc, StdArg* kargv) {361for (int i = 0 ; i < kargc ; i++) {362printf("k[%d]=%s\n", i, kargv[i].arg);363}364}365void printme() {366for (int i = 0 ; i < argc ; i++) {367printf(" [%d]=%s\n", i, argv[i]);368}369}370};371372void dotest(Vector** vectors) {373Vector* v = vectors[0];374for (int i = 0 ; v != NULL;) {375if (v->enabled) {376v->check();377}378v = vectors[++i];379}380}381382#define MAXV 128383int main(int argc, char* argv[]) {384385int n;386for (n=1; n < argc; n++) {387printf("%d %s\n", n, argv[n]);388}389if (n > 1) {390JLI_CmdToArgs(GetCommandLine());391for (n = 0; n < stdargc; n++) {392printf(" [%d]=%s\n", n, stdargs[n].arg);393printf(" [%d]=%s\n", n, stdargs[n].has_wildcard ? "TRUE" : "FALSE");394}395doexit(0);396}397398Vector *vectors[MAXV];399400memset(vectors, 0, sizeof(vectors));401int i = 0;402Vector* v = new Vector(argv[0], "abcd");403v->add("abcd", FALSE);404// v->disable();405vectors[i++] = v;406407408v = new Vector(argv[0], "\"a b c d\"");409v->add("a b c d", FALSE);410// v->disable();411vectors[i++] = v;412413414v = new Vector(argv[0], "a\"b c d\"e");415v->add("ab c de", FALSE);416// v->disable();417vectors[i++] = v;418419420v = new Vector(argv[0], "ab\\\"cd");421v->add("ab\"cd", FALSE);422// v->disable();423vectors[i++] = v;424425426v = new Vector(argv[0], "\"a b c d\\\\\"");427v->add("a b c d\\", FALSE);428// v->disable();429vectors[i++] = v;430431432v = new Vector(argv[0], "ab\\\\\\\"cd");433v->add("ab\\\"cd", FALSE);434// v->disable();435vectors[i++] = v;436437438// Windows tests439v = new Vector(argv[0], "a\\\\\\c");440v->add("a\\\\\\c", FALSE);441// v->disable();442vectors[i++] = v;443444445v = new Vector(argv[0], "\"a\\\\\\d\"");446v->add("a\\\\\\d", FALSE);447// v->disable();448vectors[i++] = v;449450451v = new Vector(argv[0], "\"a b c\" d e");452v->add("a b c", FALSE);453v->add("d", FALSE);454v->add("e", FALSE);455// v->disable();456vectors[i++] = v;457458459v = new Vector(argv[0], "\"ab\\\"c\" \"\\\\\" d");460v->add("ab\"c", FALSE);461v->add("\\", FALSE);462v->add("d", FALSE);463// v->disable();464vectors[i++] = v;465466467v = new Vector(argv[0], "a\\\\\\c d\"e f\"g h");468v->add("a\\\\\\c", FALSE);469v->add("de fg", FALSE);470v->add("h", FALSE);471// v->disable();472vectors[i++] = v;473474475v = new Vector(argv[0], "a\\\\\\\"b c d");476v->add("a\\\"b", FALSE); // XXX "a\\\\\\\"b"477v->add("c", FALSE);478v->add("d", FALSE);479// v->disable();480vectors[i++] = v;481482483v = new Vector(argv[0], "a\\\\\\\\\"g c\" d e"); // XXX "a\\\\\\\\\"b c\" d e"484v->add("a\\\\\g c", FALSE); // XXX "a\\\\\\\\\"b c"485v->add("d", FALSE);486v->add("e", FALSE);487// v->disable();488vectors[i++] = v;489490491// Additional tests492v = new Vector(argv[0], "\"a b c\"\"");493v->add("a b c\"", FALSE);494// v->disable();495vectors[i++] = v;496497498v = new Vector(argv[0], "\"\"a b c\"\"");499v->add("a", FALSE);500v->add("b", FALSE);501v->add("c", FALSE);502// v->disable();503vectors[i++] = v;504505506v = new Vector(argv[0], "\"\"\"a b c\"\"\"");507v->add("\"a b c\"", FALSE);508// v->disable();509vectors[i++] = v;510511512v = new Vector(argv[0], "\"\"\"\"a b c\"\"\"\"");513v->add("\"a", FALSE);514v->add("b", FALSE);515v->add("c\"", FALSE);516// v->disable();517vectors[i++] = v;518519520v = new Vector(argv[0], "\"\"\"\"\"a b c\"\"\"\"\"");521v->add("\"\"a b c\"\"", FALSE);522// v->disable();523vectors[i++] = v;524525526v = new Vector(argv[0], "\"C:\\TEST A\\\\\"");527v->add("C:\\TEST A\\", FALSE);528// v->disable();529vectors[i++] = v;530531532v = new Vector(argv[0], "\"\"C:\\TEST A\\\\\"\"");533v->add("C:\\TEST", FALSE);534v->add("A\\", FALSE);535// v->disable();536vectors[i++] = v;537538539// test if a wildcard is present540v = new Vector(argv[0], "abc*def");541v->add("abc*def", TRUE);542// v->disable();543vectors[i++] = v;544545546v = new Vector(argv[0], "\"abc*def\"");547v->add("abc*def", FALSE);548// v->disable();549vectors[i++] = v;550551552v = new Vector(argv[0], "*.abc");553v->add("*.abc", TRUE);554// v->disable();555vectors[i++] = v;556557558v = new Vector(argv[0], "\"*.abc\"");559v->add("*.abc", FALSE);560// v->disable();561vectors[i++] = v;562563564v = new Vector(argv[0], "x.???");565v->add("x.???", TRUE);566// v->disable();567vectors[i++] = v;568569570v = new Vector(argv[0], "\"x.???\"");571v->add("x.???", FALSE);572// v->disable();573vectors[i++] = v;574575576v = new Vector(argv[0], "Debug\\*");577v->add("Debug\\*", TRUE);578// v->disable();579vectors[i++] = v;580581582v = new Vector(argv[0], "Debug\\f?a");583v->add("Debug\\f?a", TRUE);584// v->disable();585vectors[i++] = v;586587588v = new Vector(argv[0], "Debug\\?a.java");589v->add("Debug\\?a.java", TRUE);590// v->disable();591vectors[i++] = v;592593594v = new Vector(argv[0], "foo *.noexts");595v->add("foo", FALSE);596v->add("*.noexts", TRUE);597// v->disable();598vectors[i++] = v;599600601v = new Vector(argv[0], "X\\Y\\Z");602v->add("X\\Y\\Z", FALSE);603// v->disable();604vectors[i++] = v;605606607v = new Vector(argv[0], "\\X\\Y\\Z");608v->add("\\X\\Y\\Z", FALSE);609// v->disable();610vectors[i++] = v;611612613v = new Vector(argv[0], "a b");614v->add("a", FALSE);615v->add("b", FALSE);616// v->disable();617vectors[i++] = v;618619620v = new Vector(argv[0], "a\tb");621v->add("a", FALSE);622v->add("b", FALSE);623// v->disable();624vectors[i++] = v;625626627v = new Vector(argv[0], "a \t b");628v->add("a", FALSE);629v->add("b", FALSE);630// v->disable();631vectors[i++] = v;632633v = new Vector(argv[0], "*\\");634v->add("*\\", TRUE);635// v->disable();636vectors[i++] = v;637638v = new Vector(argv[0], "*/");639v->add("*/", TRUE);640// v->disable();641vectors[i++] = v;642643v = new Vector(argv[0], ".\\*");644v->add(".\\*", TRUE);645// v->disable();646vectors[i++] = v;647648v = new Vector(argv[0], "./*");649v->add("./*", TRUE);650// v->disable();651vectors[i++] = v;652653v = new Vector(argv[0], ".\\*");654v->add(".\\*", TRUE);655// v->disable();656vectors[i++] = v;657658v = new Vector(argv[0], ".//*");659v->add(".//*", TRUE);660// v->disable();661vectors[i++] = v;662663v = new Vector(argv[0], "..\\..\\*");664v->add("..\\..\\*", TRUE);665// v->disable();666vectors[i++] = v;667668v = new Vector(argv[0], "../../*");669v->add("../../*", TRUE);670// v->disable();671vectors[i++] = v;672673v = new Vector(argv[0], "..\\..\\");674v->add("..\\..\\", FALSE);675// v->disable();676vectors[i++] = v;677678v = new Vector(argv[0], "../../");679v->add("../../", FALSE);680// v->disable();681vectors[i++] = v;682683v= new Vector(argv[0], "a b\\\\ d");684v->add("a", FALSE);685v->add("b\\\\", FALSE);686v->add("d", FALSE);687vectors[i++] = v;688689v= new Vector(argv[0], "\\\\?");690v->add("\\\\?", TRUE);691vectors[i++] = v;692693v= new Vector(argv[0], "\\\\*");694v->add("\\\\*", TRUE);695vectors[i++] = v;696697dotest(vectors);698printf("All tests pass [%d]\n", i);699doexit(0);700}701#endif /* IDE_STANDALONE */702703704