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_ReleaseStdArgs() {
 197     StdArg* stdarg;
 198     for (stdarg = stdargs; stdarg < stdargs + stdargc; ++stdarg) {
 199         JLI_MemFree(stdarg->arg);
 200     }
 201     JLI_MemFree(stdargs);
 202     stdargs = NULL;
 203     stdargc = 0;
 204 }
 205 
 206 void JLI_CmdToArgs(char* cmdline) {
 207     int nargs = 0;
 208     StdArg* argv = NULL;
 209     jboolean wildcard = JNI_FALSE;
 210     char* src = cmdline;
 211 
 212     // allocate arg buffer with sufficient space to receive the largest arg
 213     char* arg = JLI_StringDup(cmdline);
 214 
 215     do {
 216         src = next_arg(src, arg, &wildcard);
 217         // resize to accommodate another Arg
 218         argv = (StdArg*) JLI_MemRealloc(argv, (nargs+1) * sizeof(StdArg));
 219         argv[nargs].arg = JLI_StringDup(arg);
 220         argv[nargs].has_wildcard = wildcard;
 221         *arg = '\0';
 222         nargs++;
 223     } while (src != NULL);
 224 
 225     JLI_MemFree(arg);
 226 
 227     stdargc = nargs;
 228     stdargs = argv;
 229 }
 230 
 231 #ifdef IDE_STANDALONE
 232 void doexit(int rv) {
 233     printf("Hit any key to quit\n");
 234     int c = getchar();
 235     exit(rv);
 236 }
 237 
 238 void doabort() {
 239     doexit(1);
 240 }
 241 
 242 class Vector {
 243 public:
 244     char* cmdline;
 245     int argc;
 246     char* argv[10];
 247     boolean wildcard[10];
 248     boolean enabled;
 249 
 250     Vector(){}
 251     // Initialize our test vector with the program name, argv[0]
 252     // and the single string command line.
 253     Vector(char* pname, char* cline) {
 254         argv[0] = pname;
 255         wildcard[0] = FALSE;
 256         cmdline = cline;
 257         argc = 1;
 258         enabled = TRUE;
 259     }
 260 
 261     // add our expected strings, the program name has already been
 262     // added so ignore that
 263     void add(char* arg, boolean w) {
 264         argv[argc] = arg;
 265         wildcard[argc] = w;
 266         argc++;
 267     }
 268 
 269     void disable() {
 270         enabled = FALSE;
 271     }
 272 
 273     // validate the returned arguments with the expected arguments, using the
 274     // new CmdToArgs method.
 275     bool check() {
 276         // "pgmname" rest of cmdline ie. pgmname + 2 double quotes + space + cmdline from windows
 277         char* cptr = (char*) malloc(strlen(argv[0]) + sizeof(char) * 3 + strlen(cmdline) + 1);
 278         _snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline);
 279         JLI_CmdToArgs(cptr);
 280         free(cptr);
 281         StdArg *kargv = JLI_GetStdArgs();
 282         int     kargc = JLI_GetStdArgc();
 283         bool retval = true;
 284         printf("\n===========================\n");
 285         printf("cmdline=%s\n", cmdline);
 286         if (argc != kargc) {
 287             printf("*** argument count does not match\n");
 288             printme();
 289             printtest(kargc, kargv);
 290             doabort();
 291         }
 292         for (int i = 0 ; i < argc && retval == true ; i++) {
 293             if (strcmp(argv[i], kargv[i].arg) != 0) {
 294                 printf("*** argument at [%d] don't match\n  got: %s\n  exp: %s\n",
 295                        i, kargv[i].arg, argv[i]);
 296                 doabort();
 297             }
 298         }
 299         for (int i = 0 ; i < argc && retval == true ; i++) {
 300             if (wildcard[i] != kargv[i].has_wildcard) {
 301                 printf("*** expansion flag at [%d] doesn't match\n  got: %d\n  exp: %d\n",
 302                        i, kargv[i].has_wildcard, wildcard[i]);
 303                 doabort();
 304             }
 305         }
 306         for (int i = 0 ; i < kargc ; i++) {
 307             printf("k[%d]=%s\n", i, kargv[i].arg);
 308             printf(" [%d]=%s\n", i, argv[i]);
 309         }
 310         return retval;
 311     }
 312     void printtest(int kargc, StdArg* kargv) {
 313         for (int i = 0 ; i < kargc ; i++) {
 314             printf("k[%d]=%s\n", i, kargv[i].arg);
 315         }
 316     }
 317     void printme() {
 318         for (int i = 0 ; i < argc ; i++) {
 319             printf(" [%d]=%s\n", i, argv[i]);
 320         }
 321     }
 322 };
 323 
 324 void dotest(Vector** vectors) {
 325     Vector* v = vectors[0];
 326     for (int i = 0 ; v != NULL;) {
 327         if (v->enabled) {
 328             v->check();
 329         }
 330         v = vectors[++i];
 331     }
 332 }
 333 
 334 #define MAXV 128
 335 int main(int argc, char* argv[]) {
 336 
 337     int n;
 338     for (n=1; n < argc; n++) {
 339         printf("%d %s\n", n, argv[n]);
 340     }
 341     if (n > 1) {
 342         JLI_CmdToArgs(GetCommandLine());
 343         for (n = 0; n < stdargc; n++) {
 344             printf(" [%d]=%s\n", n, stdargs[n].arg);
 345             printf(" [%d]=%s\n", n, stdargs[n].has_wildcard ? "TRUE" : "FALSE");
 346         }
 347         doexit(0);
 348     }
 349 
 350     Vector *vectors[MAXV];
 351 
 352     memset(vectors, 0, sizeof(vectors));
 353     int i = 0;
 354     Vector* v = new Vector(argv[0], "abcd");
 355     v->add("abcd", FALSE);
 356     // v->disable();
 357     vectors[i++] = v;
 358 
 359 
 360     v = new Vector(argv[0], "\"a b c d\"");
 361     v->add("a b c d", FALSE);
 362     // v->disable();
 363     vectors[i++] = v;
 364 
 365 
 366     v = new Vector(argv[0], "a\"b c d\"e");
 367     v->add("ab c de", FALSE);
 368     // v->disable();
 369     vectors[i++] = v;
 370 
 371 
 372     v = new Vector(argv[0], "ab\\\"cd");
 373     v->add("ab\"cd", FALSE);
 374     // v->disable();
 375     vectors[i++] = v;
 376 
 377 
 378     v = new Vector(argv[0], "\"a b c d\\\\\"");
 379     v->add("a b c d\\", FALSE);
 380     // v->disable();
 381     vectors[i++] = v;
 382 
 383 
 384     v = new Vector(argv[0], "ab\\\\\\\"cd");
 385     v->add("ab\\\"cd", FALSE);
 386     // v->disable();
 387     vectors[i++] = v;
 388 
 389 
 390     // Windows tests
 391     v = new Vector(argv[0], "a\\\\\\c");
 392     v->add("a\\\\\\c", FALSE);
 393     // v->disable();
 394     vectors[i++] = v;
 395 
 396 
 397     v = new Vector(argv[0], "\"a\\\\\\d\"");
 398     v->add("a\\\\\\d", FALSE);
 399     // v->disable();
 400     vectors[i++] = v;
 401 
 402 
 403     v = new Vector(argv[0], "\"a b c\" d e");
 404     v->add("a b c", FALSE);
 405     v->add("d", FALSE);
 406     v->add("e", FALSE);
 407     // v->disable();
 408     vectors[i++] = v;
 409 
 410 
 411     v = new Vector(argv[0], "\"ab\\\"c\"  \"\\\\\"  d");
 412     v->add("ab\"c", FALSE);
 413     v->add("\\", FALSE);
 414     v->add("d", FALSE);
 415     // v->disable();
 416     vectors[i++] = v;
 417 
 418 
 419     v = new Vector(argv[0], "a\\\\\\c d\"e f\"g h");
 420     v->add("a\\\\\\c", FALSE);
 421     v->add("de fg", FALSE);
 422     v->add("h", 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", FALSE); // XXX "a\\\\\\\"b"
 429     v->add("c", FALSE);
 430     v->add("d", FALSE);
 431     // v->disable();
 432     vectors[i++] = v;
 433 
 434 
 435     v = new Vector(argv[0], "a\\\\\\\\\"g c\" d e"); // XXX "a\\\\\\\\\"b c\" d e"
 436     v->add("a\\\\\g c", FALSE); // XXX "a\\\\\\\\\"b c"
 437     v->add("d", FALSE);
 438     v->add("e", FALSE);
 439     // v->disable();
 440     vectors[i++] = v;
 441 
 442 
 443     // Additional tests
 444     v = new Vector(argv[0], "\"a b c\"\"");
 445     v->add("a b c\"", FALSE);
 446     // v->disable();
 447     vectors[i++] = v;
 448 
 449 
 450     v = new Vector(argv[0], "\"\"a b c\"\"");
 451     v->add("a", FALSE);
 452     v->add("b", FALSE);
 453     v->add("c", FALSE);
 454     // v->disable();
 455     vectors[i++] = v;
 456 
 457 
 458     v = new Vector(argv[0], "\"\"\"a b c\"\"\"");
 459     v->add("\"a b c\"", FALSE);
 460     // v->disable();
 461     vectors[i++] = v;
 462 
 463 
 464     v = new Vector(argv[0], "\"\"\"\"a b c\"\"\"\"");
 465     v->add("\"a", FALSE);
 466     v->add("b", FALSE);
 467     v->add("c\"", FALSE);
 468     // v->disable();
 469     vectors[i++] = v;
 470 
 471 
 472     v = new Vector(argv[0], "\"\"\"\"\"a b c\"\"\"\"\"");
 473     v->add("\"\"a b c\"\"", FALSE);
 474     // v->disable();
 475     vectors[i++] = v;
 476 
 477 
 478     v = new Vector(argv[0], "\"C:\\TEST A\\\\\"");
 479     v->add("C:\\TEST A\\", FALSE);
 480     // v->disable();
 481     vectors[i++] = v;
 482 
 483 
 484     v = new Vector(argv[0], "\"\"C:\\TEST A\\\\\"\"");
 485     v->add("C:\\TEST", FALSE);
 486     v->add("A\\", FALSE);
 487     // v->disable();
 488     vectors[i++] = v;
 489 
 490 
 491     // test if a wildcard is present
 492     v = new Vector(argv[0], "abc*def");
 493     v->add("abc*def", TRUE);
 494     // v->disable();
 495     vectors[i++] = v;
 496 
 497 
 498     v = new Vector(argv[0], "\"abc*def\"");
 499     v->add("abc*def", FALSE);
 500     // v->disable();
 501     vectors[i++] = v;
 502 
 503 
 504     v = new Vector(argv[0], "*.abc");
 505     v->add("*.abc", TRUE);
 506     // v->disable();
 507     vectors[i++] = v;
 508 
 509 
 510     v = new Vector(argv[0], "\"*.abc\"");
 511     v->add("*.abc", FALSE);
 512     // v->disable();
 513     vectors[i++] = v;
 514 
 515 
 516     v = new Vector(argv[0], "x.???");
 517     v->add("x.???", TRUE);
 518     // v->disable();
 519     vectors[i++] = v;
 520 
 521 
 522     v = new Vector(argv[0], "\"x.???\"");
 523     v->add("x.???", FALSE);
 524     // v->disable();
 525     vectors[i++] = v;
 526 
 527 
 528     v = new Vector(argv[0], "Debug\\*");
 529     v->add("Debug\\*", TRUE);
 530     // v->disable();
 531     vectors[i++] = v;
 532 
 533 
 534     v = new Vector(argv[0], "Debug\\f?a");
 535     v->add("Debug\\f?a", TRUE);
 536     // v->disable();
 537     vectors[i++] = v;
 538 
 539 
 540     v = new Vector(argv[0], "Debug\\?a.java");
 541     v->add("Debug\\?a.java", TRUE);
 542     // v->disable();
 543     vectors[i++] = v;
 544 
 545 
 546     v = new Vector(argv[0], "foo *.noexts");
 547     v->add("foo", FALSE);
 548     v->add("*.noexts", TRUE);
 549     // v->disable();
 550     vectors[i++] = v;
 551 
 552 
 553     v = new Vector(argv[0], "X\\Y\\Z");
 554     v->add("X\\Y\\Z", FALSE);
 555     // v->disable();
 556     vectors[i++] = v;
 557 
 558 
 559     v = new Vector(argv[0], "\\X\\Y\\Z");
 560     v->add("\\X\\Y\\Z", FALSE);
 561     // v->disable();
 562     vectors[i++] = v;
 563 
 564 
 565     v = new Vector(argv[0], "a b");
 566     v->add("a", FALSE);
 567     v->add("b", FALSE);
 568     // v->disable();
 569     vectors[i++] = v;
 570 
 571 
 572     v = new Vector(argv[0], "a\tb");
 573     v->add("a", FALSE);
 574     v->add("b", FALSE);
 575     // v->disable();
 576     vectors[i++] = v;
 577 
 578 
 579     v = new Vector(argv[0], "a \t b");
 580     v->add("a", FALSE);
 581     v->add("b", FALSE);
 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("..\\..\\*", TRUE);
 617     // v->disable();
 618     vectors[i++] = v;
 619 
 620     v = new Vector(argv[0], "../../*");
 621     v->add("../../*", TRUE);
 622     // v->disable();
 623     vectors[i++] = v;
 624 
 625     v = new Vector(argv[0], "..\\..\\");
 626     v->add("..\\..\\", FALSE);
 627     // v->disable();
 628     vectors[i++] = v;
 629 
 630     v = new Vector(argv[0], "../../");
 631     v->add("../../", FALSE);
 632     // v->disable();
 633     vectors[i++] = v;
 634 
 635     v= new Vector(argv[0], "a b\\\\ d");
 636     v->add("a", FALSE);
 637     v->add("b\\\\", FALSE);
 638     v->add("d", FALSE);
 639     vectors[i++] = v;
 640 
 641     v= new Vector(argv[0], "\\\\?");
 642     v->add("\\\\?", TRUE);
 643     vectors[i++] = v;
 644 
 645     v= new Vector(argv[0], "\\\\*");
 646     v->add("\\\\*", TRUE);
 647     vectors[i++] = v;
 648 
 649     dotest(vectors);
 650     printf("All tests pass [%d]\n", i);
 651     doexit(0);
 652 }
 653 #endif /* IDE_STANDALONE */