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 */