1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27 /* 28 * Converts a single string command line to the traditional argc, argv. 29 * There are rules which govern the breaking of the arguments, and 30 * these rules are embodied in the regression tests below, and duplicated 31 * in the jdk regression tests. 32 */ 33 34 #include <assert.h> 35 36 #ifndef IDE_STANDALONE 37 #include "java.h" 38 #include "jni.h" 39 #include "jli_util.h" 40 #else /* IDE_STANDALONE */ 41 // The defines we need for stand alone testing 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <Windows.h> 45 #define JNI_TRUE TRUE 46 #define JNI_FALSE FALSE 47 #define JLI_MemRealloc realloc 48 #define JLI_StringDup _strdup 49 #define JLI_MemFree free 50 #define jboolean boolean 51 typedef struct { 52 char* arg; 53 boolean has_wildcard; 54 } StdArg ; 55 #endif 56 static StdArg *stdargs; 57 static int stdargc; 58 59 static int copyCh(USHORT ch, char* dest) { 60 if (HIBYTE(ch) == 0) { 61 *dest = (char)ch; 62 return 1; 63 } else { 64 *((USHORT *)dest) = ch; 65 return 2; 66 } 67 } 68 69 static char* next_arg(char* cmdline, char* arg, jboolean* wildcard) { 70 71 char* src = cmdline; 72 char* dest = arg; 73 jboolean separator = JNI_FALSE; 74 int quotes = 0; 75 int slashes = 0; 76 77 // "prev"/"ch" may contain either a single byte, or a double byte 78 // character encoded in CP_ACP. 79 USHORT prev = 0; 80 USHORT ch = 0; 81 int i; 82 jboolean done = JNI_FALSE; 83 ptrdiff_t charLength; 84 85 *wildcard = JNI_FALSE; 86 while (!done) { 87 charLength = CharNextExA(CP_ACP, src, 0) - src; 88 if (charLength == 0) { 89 break; 90 } else if (charLength == 1) { 91 ch = (USHORT)(UCHAR)src[0]; 92 } else { 93 ch = ((USHORT *)src)[0]; 94 } 95 96 switch (ch) { 97 case L'"': 98 if (separator) { 99 done = JNI_TRUE; 100 break; 101 } 102 if (prev == L'\\') { 103 for (i = 1; i < slashes; i += 2) { 104 dest += copyCh(prev, dest); 105 } 106 if (slashes % 2 == 1) { 107 dest += copyCh(ch, dest); 108 } else { 109 quotes++; 110 } 111 } else if (prev == L'"' && quotes % 2 == 0) { 112 quotes++; 113 dest += copyCh(ch, dest); // emit every other consecutive quote 114 } else if (quotes == 0) { 115 quotes++; // starting quote 116 } else { 117 quotes--; // matching quote 118 } 119 slashes = 0; 120 break; 121 122 case L'\\': 123 slashes++; 124 if (separator) { 125 done = JNI_TRUE; 126 separator = JNI_FALSE; 127 } 128 break; 129 130 case L' ': 131 case L'\t': 132 if (prev == L'\\') { 133 for (i = 0 ; i < slashes; i++) { 134 dest += copyCh(prev, dest); 135 } 136 } 137 if (quotes % 2 == 1) { 138 dest += copyCh(ch, dest); 139 } else { 140 separator = JNI_TRUE; 141 } 142 slashes = 0; 143 break; 144 145 case L'*': 146 case L'?': 147 if (separator) { 148 done = JNI_TRUE; 149 separator = JNI_FALSE; 150 break; 151 } 152 if (quotes % 2 == 0) { 153 *wildcard = JNI_TRUE; 154 } 155 if (prev == L'\\') { 156 for (i = 0 ; i < slashes ; i++) { 157 dest += copyCh(prev, dest); 158 } 159 } 160 dest += copyCh(ch, dest); 161 slashes = 0; 162 break; 163 164 default: 165 if (prev == L'\\') { 166 for (i = 0 ; i < slashes ; i++) { 167 dest += copyCh(prev, dest); 168 } 169 dest += copyCh(ch, dest); 170 } else if (separator) { 171 done = JNI_TRUE; 172 } else { 173 dest += copyCh(ch, dest); 174 } 175 slashes = 0; 176 } 177 178 if (!done) { 179 prev = ch; 180 src += charLength; 181 } 182 } 183 if (prev == L'\\') { 184 for (i = 0; i < slashes; i++) { 185 dest += copyCh(prev, dest); 186 } 187 } 188 *dest = 0; 189 return done ? src : NULL; 190 } 191 192 JNIEXPORT int JNICALL 193 JLI_GetStdArgc() { 194 return stdargc; 195 } 196 197 JNIEXPORT StdArg* JNICALL 198 JLI_GetStdArgs() { 199 return stdargs; 200 } 201 202 JNIEXPORT void JNICALL 203 JLI_CmdToArgs(char* cmdline) { 204 int nargs = 0; 205 StdArg* argv = NULL; 206 jboolean wildcard = JNI_FALSE; 207 char* src = cmdline, *arg = NULL; 208 JLI_List argsInFile; 209 size_t i, cnt; 210 211 JLI_List envArgs = JLI_List_new(1); 212 if (JLI_AddArgsFromEnvVar(envArgs, JDK_JAVA_OPTIONS)) { 213 // JLI_SetTraceLauncher is not called yet 214 // Show _JAVA_OPTIONS content along with JDK_JAVA_OPTIONS to aid diagnosis 215 if (getenv(JLDEBUG_ENV_ENTRY)) { 216 char *tmp = getenv("_JAVA_OPTIONS"); 217 if (NULL != tmp) { 218 JLI_ReportMessage(ARG_INFO_ENVVAR, "_JAVA_OPTIONS", tmp); 219 } 220 } 221 } 222 cnt = envArgs->size + 1; 223 argv = JLI_MemAlloc(cnt * sizeof(StdArg)); 224 225 // allocate arg buffer with sufficient space to receive the largest arg 226 arg = JLI_StringDup(cmdline); 227 228 src = next_arg(src, arg, &wildcard); 229 // first argument is the app name, do not preprocess and make sure remains first 230 argv[0].arg = JLI_StringDup(arg); 231 argv[0].has_wildcard = wildcard; 232 nargs++; 233 234 for (i = 1; i < cnt; i++) { 235 argv[i].arg = envArgs->elements[i - 1]; 236 // wildcard is not supported in argfile 237 argv[i].has_wildcard = JNI_FALSE; 238 nargs++; 239 } 240 JLI_MemFree(envArgs->elements); 241 JLI_MemFree(envArgs); 242 243 assert ((size_t) nargs == cnt); 244 *arg = '\0'; 245 246 // iterate through rest of command line 247 while (src != NULL) { 248 src = next_arg(src, arg, &wildcard); 249 argsInFile = JLI_PreprocessArg(arg); 250 if (argsInFile != NULL) { 251 // resize to accommodate another Arg 252 cnt = argsInFile->size; 253 argv = (StdArg*) JLI_MemRealloc(argv, (nargs + cnt) * sizeof(StdArg)); 254 for (i = 0; i < cnt; i++) { 255 argv[nargs].arg = argsInFile->elements[i]; 256 // wildcard is not supported in argfile 257 argv[nargs].has_wildcard = JNI_FALSE; 258 nargs++; 259 } 260 // Shallow free, we reuse the string to avoid copy 261 JLI_MemFree(argsInFile->elements); 262 JLI_MemFree(argsInFile); 263 } else { 264 // resize to accommodate another Arg 265 argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg)); 266 argv[nargs].arg = JLI_StringDup(arg); 267 argv[nargs].has_wildcard = wildcard; 268 *arg = '\0'; 269 nargs++; 270 } 271 *arg = '\0'; 272 } 273 274 JLI_MemFree(arg); 275 276 stdargc = nargs; 277 stdargs = argv; 278 } 279 280 #ifdef IDE_STANDALONE 281 void doexit(int rv) { 282 printf("Hit any key to quit\n"); 283 int c = getchar(); 284 exit(rv); 285 } 286 287 void doabort() { 288 doexit(1); 289 } 290 291 class Vector { 292 public: 293 char* cmdline; 294 int argc; 295 char* argv[10]; 296 boolean wildcard[10]; 297 boolean enabled; 298 299 Vector(){} 300 // Initialize our test vector with the program name, argv[0] 301 // and the single string command line. 302 Vector(char* pname, char* cline) { 303 argv[0] = pname; 304 wildcard[0] = FALSE; 305 cmdline = cline; 306 argc = 1; 307 enabled = TRUE; 308 } 309 310 // add our expected strings, the program name has already been 311 // added so ignore that 312 void add(char* arg, boolean w) { 313 argv[argc] = arg; 314 wildcard[argc] = w; 315 argc++; 316 } 317 318 void disable() { 319 enabled = FALSE; 320 } 321 322 // validate the returned arguments with the expected arguments, using the 323 // new CmdToArgs method. 324 bool check() { 325 // "pgmname" rest of cmdline ie. pgmname + 2 double quotes + space + cmdline from windows 326 char* cptr = (char*) malloc(strlen(argv[0]) + sizeof(char) * 3 + strlen(cmdline) + 1); 327 _snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline); 328 JLI_CmdToArgs(cptr); 329 free(cptr); 330 StdArg *kargv = JLI_GetStdArgs(); 331 int kargc = JLI_GetStdArgc(); 332 bool retval = true; 333 printf("\n===========================\n"); 334 printf("cmdline=%s\n", cmdline); 335 if (argc != kargc) { 336 printf("*** argument count does not match\n"); 337 printme(); 338 printtest(kargc, kargv); 339 doabort(); 340 } 341 for (int i = 0 ; i < argc && retval == true ; i++) { 342 if (strcmp(argv[i], kargv[i].arg) != 0) { 343 printf("*** argument at [%d] don't match\n got: %s\n exp: %s\n", 344 i, kargv[i].arg, argv[i]); 345 doabort(); 346 } 347 } 348 for (int i = 0 ; i < argc && retval == true ; i++) { 349 if (wildcard[i] != kargv[i].has_wildcard) { 350 printf("*** expansion flag at [%d] doesn't match\n got: %d\n exp: %d\n", 351 i, kargv[i].has_wildcard, wildcard[i]); 352 doabort(); 353 } 354 } 355 for (int i = 0 ; i < kargc ; i++) { 356 printf("k[%d]=%s\n", i, kargv[i].arg); 357 printf(" [%d]=%s\n", i, argv[i]); 358 } 359 return retval; 360 } 361 void printtest(int kargc, StdArg* kargv) { 362 for (int i = 0 ; i < kargc ; i++) { 363 printf("k[%d]=%s\n", i, kargv[i].arg); 364 } 365 } 366 void printme() { 367 for (int i = 0 ; i < argc ; i++) { 368 printf(" [%d]=%s\n", i, argv[i]); 369 } 370 } 371 }; 372 373 void dotest(Vector** vectors) { 374 Vector* v = vectors[0]; 375 for (int i = 0 ; v != NULL;) { 376 if (v->enabled) { 377 v->check(); 378 } 379 v = vectors[++i]; 380 } 381 } 382 383 #define MAXV 128 384 int main(int argc, char* argv[]) { 385 386 int n; 387 for (n=1; n < argc; n++) { 388 printf("%d %s\n", n, argv[n]); 389 } 390 if (n > 1) { 391 JLI_CmdToArgs(GetCommandLine()); 392 for (n = 0; n < stdargc; n++) { 393 printf(" [%d]=%s\n", n, stdargs[n].arg); 394 printf(" [%d]=%s\n", n, stdargs[n].has_wildcard ? "TRUE" : "FALSE"); 395 } 396 doexit(0); 397 } 398 399 Vector *vectors[MAXV]; 400 401 memset(vectors, 0, sizeof(vectors)); 402 int i = 0; 403 Vector* v = new Vector(argv[0], "abcd"); 404 v->add("abcd", FALSE); 405 // v->disable(); 406 vectors[i++] = v; 407 408 409 v = new Vector(argv[0], "\"a b c d\""); 410 v->add("a b c d", FALSE); 411 // v->disable(); 412 vectors[i++] = v; 413 414 415 v = new Vector(argv[0], "a\"b c d\"e"); 416 v->add("ab c de", FALSE); 417 // v->disable(); 418 vectors[i++] = v; 419 420 421 v = new Vector(argv[0], "ab\\\"cd"); 422 v->add("ab\"cd", FALSE); 423 // v->disable(); 424 vectors[i++] = v; 425 426 427 v = new Vector(argv[0], "\"a b c d\\\\\""); 428 v->add("a b c d\\", FALSE); 429 // v->disable(); 430 vectors[i++] = v; 431 432 433 v = new Vector(argv[0], "ab\\\\\\\"cd"); 434 v->add("ab\\\"cd", FALSE); 435 // v->disable(); 436 vectors[i++] = v; 437 438 439 // Windows tests 440 v = new Vector(argv[0], "a\\\\\\c"); 441 v->add("a\\\\\\c", FALSE); 442 // v->disable(); 443 vectors[i++] = v; 444 445 446 v = new Vector(argv[0], "\"a\\\\\\d\""); 447 v->add("a\\\\\\d", FALSE); 448 // v->disable(); 449 vectors[i++] = v; 450 451 452 v = new Vector(argv[0], "\"a b c\" d e"); 453 v->add("a b c", FALSE); 454 v->add("d", FALSE); 455 v->add("e", FALSE); 456 // v->disable(); 457 vectors[i++] = v; 458 459 460 v = new Vector(argv[0], "\"ab\\\"c\" \"\\\\\" d"); 461 v->add("ab\"c", FALSE); 462 v->add("\\", FALSE); 463 v->add("d", FALSE); 464 // v->disable(); 465 vectors[i++] = v; 466 467 468 v = new Vector(argv[0], "a\\\\\\c d\"e f\"g h"); 469 v->add("a\\\\\\c", FALSE); 470 v->add("de fg", FALSE); 471 v->add("h", FALSE); 472 // v->disable(); 473 vectors[i++] = v; 474 475 476 v = new Vector(argv[0], "a\\\\\\\"b c d"); 477 v->add("a\\\"b", FALSE); // XXX "a\\\\\\\"b" 478 v->add("c", FALSE); 479 v->add("d", FALSE); 480 // v->disable(); 481 vectors[i++] = v; 482 483 484 v = new Vector(argv[0], "a\\\\\\\\\"g c\" d e"); // XXX "a\\\\\\\\\"b c\" d e" 485 v->add("a\\\\\g c", FALSE); // XXX "a\\\\\\\\\"b c" 486 v->add("d", FALSE); 487 v->add("e", FALSE); 488 // v->disable(); 489 vectors[i++] = v; 490 491 492 // Additional tests 493 v = new Vector(argv[0], "\"a b c\"\""); 494 v->add("a b c\"", FALSE); 495 // v->disable(); 496 vectors[i++] = v; 497 498 499 v = new Vector(argv[0], "\"\"a b c\"\""); 500 v->add("a", FALSE); 501 v->add("b", FALSE); 502 v->add("c", FALSE); 503 // v->disable(); 504 vectors[i++] = v; 505 506 507 v = new Vector(argv[0], "\"\"\"a b c\"\"\""); 508 v->add("\"a b c\"", FALSE); 509 // v->disable(); 510 vectors[i++] = v; 511 512 513 v = new Vector(argv[0], "\"\"\"\"a b c\"\"\"\""); 514 v->add("\"a", FALSE); 515 v->add("b", FALSE); 516 v->add("c\"", FALSE); 517 // v->disable(); 518 vectors[i++] = v; 519 520 521 v = new Vector(argv[0], "\"\"\"\"\"a b c\"\"\"\"\""); 522 v->add("\"\"a b c\"\"", FALSE); 523 // v->disable(); 524 vectors[i++] = v; 525 526 527 v = new Vector(argv[0], "\"C:\\TEST A\\\\\""); 528 v->add("C:\\TEST A\\", FALSE); 529 // v->disable(); 530 vectors[i++] = v; 531 532 533 v = new Vector(argv[0], "\"\"C:\\TEST A\\\\\"\""); 534 v->add("C:\\TEST", FALSE); 535 v->add("A\\", FALSE); 536 // v->disable(); 537 vectors[i++] = v; 538 539 540 // test if a wildcard is present 541 v = new Vector(argv[0], "abc*def"); 542 v->add("abc*def", TRUE); 543 // v->disable(); 544 vectors[i++] = v; 545 546 547 v = new Vector(argv[0], "\"abc*def\""); 548 v->add("abc*def", FALSE); 549 // v->disable(); 550 vectors[i++] = v; 551 552 553 v = new Vector(argv[0], "*.abc"); 554 v->add("*.abc", TRUE); 555 // v->disable(); 556 vectors[i++] = v; 557 558 559 v = new Vector(argv[0], "\"*.abc\""); 560 v->add("*.abc", FALSE); 561 // v->disable(); 562 vectors[i++] = v; 563 564 565 v = new Vector(argv[0], "x.???"); 566 v->add("x.???", TRUE); 567 // v->disable(); 568 vectors[i++] = v; 569 570 571 v = new Vector(argv[0], "\"x.???\""); 572 v->add("x.???", FALSE); 573 // v->disable(); 574 vectors[i++] = v; 575 576 577 v = new Vector(argv[0], "Debug\\*"); 578 v->add("Debug\\*", TRUE); 579 // v->disable(); 580 vectors[i++] = v; 581 582 583 v = new Vector(argv[0], "Debug\\f?a"); 584 v->add("Debug\\f?a", TRUE); 585 // v->disable(); 586 vectors[i++] = v; 587 588 589 v = new Vector(argv[0], "Debug\\?a.java"); 590 v->add("Debug\\?a.java", TRUE); 591 // v->disable(); 592 vectors[i++] = v; 593 594 595 v = new Vector(argv[0], "foo *.noexts"); 596 v->add("foo", FALSE); 597 v->add("*.noexts", TRUE); 598 // v->disable(); 599 vectors[i++] = v; 600 601 602 v = new Vector(argv[0], "X\\Y\\Z"); 603 v->add("X\\Y\\Z", FALSE); 604 // v->disable(); 605 vectors[i++] = v; 606 607 608 v = new Vector(argv[0], "\\X\\Y\\Z"); 609 v->add("\\X\\Y\\Z", FALSE); 610 // v->disable(); 611 vectors[i++] = v; 612 613 614 v = new Vector(argv[0], "a b"); 615 v->add("a", FALSE); 616 v->add("b", FALSE); 617 // v->disable(); 618 vectors[i++] = v; 619 620 621 v = new Vector(argv[0], "a\tb"); 622 v->add("a", FALSE); 623 v->add("b", FALSE); 624 // v->disable(); 625 vectors[i++] = v; 626 627 628 v = new Vector(argv[0], "a \t b"); 629 v->add("a", FALSE); 630 v->add("b", FALSE); 631 // v->disable(); 632 vectors[i++] = v; 633 634 v = new Vector(argv[0], "*\\"); 635 v->add("*\\", TRUE); 636 // v->disable(); 637 vectors[i++] = v; 638 639 v = new Vector(argv[0], "*/"); 640 v->add("*/", TRUE); 641 // v->disable(); 642 vectors[i++] = v; 643 644 v = new Vector(argv[0], ".\\*"); 645 v->add(".\\*", TRUE); 646 // v->disable(); 647 vectors[i++] = v; 648 649 v = new Vector(argv[0], "./*"); 650 v->add("./*", TRUE); 651 // v->disable(); 652 vectors[i++] = v; 653 654 v = new Vector(argv[0], ".\\*"); 655 v->add(".\\*", TRUE); 656 // v->disable(); 657 vectors[i++] = v; 658 659 v = new Vector(argv[0], ".//*"); 660 v->add(".//*", TRUE); 661 // v->disable(); 662 vectors[i++] = v; 663 664 v = new Vector(argv[0], "..\\..\\*"); 665 v->add("..\\..\\*", TRUE); 666 // v->disable(); 667 vectors[i++] = v; 668 669 v = new Vector(argv[0], "../../*"); 670 v->add("../../*", TRUE); 671 // v->disable(); 672 vectors[i++] = v; 673 674 v = new Vector(argv[0], "..\\..\\"); 675 v->add("..\\..\\", FALSE); 676 // v->disable(); 677 vectors[i++] = v; 678 679 v = new Vector(argv[0], "../../"); 680 v->add("../../", FALSE); 681 // v->disable(); 682 vectors[i++] = v; 683 684 v= new Vector(argv[0], "a b\\\\ d"); 685 v->add("a", FALSE); 686 v->add("b\\\\", FALSE); 687 v->add("d", FALSE); 688 vectors[i++] = v; 689 690 v= new Vector(argv[0], "\\\\?"); 691 v->add("\\\\?", TRUE); 692 vectors[i++] = v; 693 694 v= new Vector(argv[0], "\\\\*"); 695 v->add("\\\\*", TRUE); 696 vectors[i++] = v; 697 698 dotest(vectors); 699 printf("All tests pass [%d]\n", i); 700 doexit(0); 701 } 702 #endif /* IDE_STANDALONE */