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