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