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
50typedef struct  {
51    char* arg;
52    boolean has_wildcard;
53} StdArg ;
54#endif
55static StdArg *stdargs;
56static int    stdargc;
57
58static 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
68static 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
191int JLI_GetStdArgc() {
192    return stdargc;
193}
194
195StdArg* JLI_GetStdArgs() {
196    return stdargs;
197}
198
199void 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, JDK_JAVA_OPTIONS)) {
209        // JLI_SetTraceLauncher is not called yet
210        // Show _JAVA_OPTIONS content along with JDK_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
277void doexit(int rv) {
278    printf("Hit any key to quit\n");
279    int c = getchar();
280    exit(rv);
281}
282
283void doabort() {
284    doexit(1);
285}
286
287class Vector {
288public:
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
369void 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
380int 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 */
699