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