Skip to content

Commit b9a0f75

Browse files
authored
fix #440: The startup command arguments for internalConsole are different from integratedTerminal (#237)
* fix bug #440: The startup command for internalConsole is different from integratedTerminal
1 parent 2d479e6 commit b9a0f75

File tree

3 files changed

+205
-26
lines changed

3 files changed

+205
-26
lines changed

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/DebugUtility.java

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.apache.commons.lang3.StringUtils;
2626

27+
import com.microsoft.java.debug.core.adapter.AdapterUtils;
2728
import com.sun.jdi.Method;
2829
import com.sun.jdi.ObjectCollectedException;
2930
import com.sun.jdi.ThreadReference;
@@ -438,4 +439,204 @@ public static String[] decodeArrayArgument(String argument) {
438439

439440
return result.toArray(new String[0]);
440441
}
442+
443+
/**
444+
* Parses the given command line into separate arguments that can be passed
445+
* to <code>Runtime.getRuntime().exec(cmdArray)</code>.
446+
*
447+
* @param cmdStr command line as a single string.
448+
* @return the individual arguments.
449+
*/
450+
public static List<String> parseArguments(String cmdStr) {
451+
if (cmdStr == null) {
452+
return new ArrayList<>();
453+
}
454+
455+
return AdapterUtils.isWindows() ? parseArgumentsWindows(cmdStr) : parseArgumentsNonWindows(cmdStr);
456+
}
457+
458+
459+
/**
460+
* Parses the given command line into separate arguments for mac/linux platform.
461+
* This piece of code is mainly copied from
462+
* https://github.com/eclipse/eclipse.platform.debug/blob/master/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java#L1374
463+
*
464+
* @param args
465+
* the command line arguments as a single string.
466+
* @return the individual arguments
467+
*/
468+
private static List<String> parseArgumentsNonWindows(String args) {
469+
// man sh, see topic QUOTING
470+
List<String> result = new ArrayList<>();
471+
472+
final int DEFAULT = 0;
473+
final int ARG = 1;
474+
final int IN_DOUBLE_QUOTE = 2;
475+
final int IN_SINGLE_QUOTE = 3;
476+
477+
int state = DEFAULT;
478+
StringBuilder buf = new StringBuilder();
479+
int len = args.length();
480+
for (int i = 0; i < len; i++) {
481+
char ch = args.charAt(i);
482+
if (Character.isWhitespace(ch)) {
483+
if (state == DEFAULT) {
484+
// skip
485+
continue;
486+
} else if (state == ARG) {
487+
state = DEFAULT;
488+
result.add(buf.toString());
489+
buf.setLength(0);
490+
continue;
491+
}
492+
}
493+
switch (state) {
494+
case DEFAULT:
495+
case ARG:
496+
if (ch == '"') {
497+
state = IN_DOUBLE_QUOTE;
498+
} else if (ch == '\'') {
499+
state = IN_SINGLE_QUOTE;
500+
} else if (ch == '\\' && i + 1 < len) {
501+
state = ARG;
502+
ch = args.charAt(++i);
503+
buf.append(ch);
504+
} else {
505+
state = ARG;
506+
buf.append(ch);
507+
}
508+
break;
509+
510+
case IN_DOUBLE_QUOTE:
511+
if (ch == '"') {
512+
state = ARG;
513+
} else if (ch == '\\' && i + 1 < len && (args.charAt(i + 1) == '\\' || args.charAt(i + 1) == '"')) {
514+
ch = args.charAt(++i);
515+
buf.append(ch);
516+
} else {
517+
buf.append(ch);
518+
}
519+
break;
520+
521+
case IN_SINGLE_QUOTE:
522+
if (ch == '\'') {
523+
state = ARG;
524+
} else {
525+
buf.append(ch);
526+
}
527+
break;
528+
529+
default:
530+
throw new IllegalStateException();
531+
}
532+
}
533+
if (buf.length() > 0 || state != DEFAULT) {
534+
result.add(buf.toString());
535+
}
536+
537+
return result;
538+
}
539+
540+
541+
/**
542+
* Parses the given command line into separate arguments for windows platform.
543+
* This piece of code is mainly copied from
544+
* https://github.com/eclipse/eclipse.platform.debug/blob/master/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java#L1264
545+
*
546+
* @param args
547+
* the command line arguments as a single string.
548+
* @return the individual arguments
549+
*/
550+
private static List<String> parseArgumentsWindows(String args) {
551+
// see http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
552+
List<String> result = new ArrayList<>();
553+
final int DEFAULT = 0;
554+
final int ARG = 1;
555+
final int IN_DOUBLE_QUOTE = 2;
556+
557+
int state = DEFAULT;
558+
int backslashes = 0;
559+
StringBuilder buf = new StringBuilder();
560+
int len = args.length();
561+
for (int i = 0; i < len; i++) {
562+
char ch = args.charAt(i);
563+
if (ch == '\\') {
564+
backslashes++;
565+
continue;
566+
} else if (backslashes != 0) {
567+
if (ch == '"') {
568+
for (; backslashes >= 2; backslashes -= 2) {
569+
buf.append('\\');
570+
}
571+
if (backslashes == 1) {
572+
if (state == DEFAULT) {
573+
state = ARG;
574+
}
575+
buf.append('"');
576+
backslashes = 0;
577+
continue;
578+
} // else fall through to switch
579+
} else {
580+
// false alarm, treat passed backslashes literally...
581+
if (state == DEFAULT) {
582+
state = ARG;
583+
}
584+
for (; backslashes > 0; backslashes--) {
585+
buf.append('\\');
586+
}
587+
// fall through to switch
588+
}
589+
}
590+
if (Character.isWhitespace(ch)) {
591+
if (state == DEFAULT) {
592+
// skip
593+
continue;
594+
} else if (state == ARG) {
595+
state = DEFAULT;
596+
result.add(buf.toString());
597+
buf.setLength(0);
598+
continue;
599+
}
600+
}
601+
switch (state) {
602+
case DEFAULT:
603+
case ARG:
604+
if (ch == '"') {
605+
state = IN_DOUBLE_QUOTE;
606+
} else {
607+
state = ARG;
608+
buf.append(ch);
609+
}
610+
break;
611+
612+
case IN_DOUBLE_QUOTE:
613+
if (ch == '"') {
614+
if (i + 1 < len && args.charAt(i + 1) == '"') {
615+
/* Undocumented feature in Windows:
616+
* Two consecutive double quotes inside a double-quoted argument are interpreted as
617+
* a single double quote.
618+
*/
619+
buf.append('"');
620+
i++;
621+
} else if (buf.length() == 0) {
622+
// empty string on Windows platform. Account for bug in constructor of JDK's java.lang.ProcessImpl.
623+
result.add("\"\""); //$NON-NLS-1$
624+
state = DEFAULT;
625+
} else {
626+
state = ARG;
627+
}
628+
} else {
629+
buf.append(ch);
630+
}
631+
break;
632+
633+
default:
634+
throw new IllegalStateException();
635+
}
636+
}
637+
if (buf.length() > 0 || state != DEFAULT) {
638+
result.add(buf.toString());
639+
}
640+
return result;
641+
}
441642
}

com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/adapter/handler/LaunchRequestHandler.java

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,13 @@
2222
import java.util.Map.Entry;
2323
import java.util.concurrent.CompletableFuture;
2424
import java.util.logging.Logger;
25-
import java.util.regex.Matcher;
26-
import java.util.regex.Pattern;
2725

2826
import org.apache.commons.lang3.ArrayUtils;
2927
import org.apache.commons.lang3.StringUtils;
3028

3129
import com.microsoft.java.debug.core.Configuration;
3230
import com.microsoft.java.debug.core.DebugSettings;
31+
import com.microsoft.java.debug.core.DebugUtility;
3332
import com.microsoft.java.debug.core.adapter.AdapterUtils;
3433
import com.microsoft.java.debug.core.adapter.ErrorCode;
3534
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
@@ -107,7 +106,7 @@ protected static String[] constructLaunchCommands(LaunchArguments launchArgument
107106
launchCmds.add(String.format("-agentlib:jdwp=transport=dt_socket,server=%s,suspend=y,address=%s", serverMode ? "y" : "n", address));
108107
}
109108
if (StringUtils.isNotBlank(launchArguments.vmArgs)) {
110-
launchCmds.addAll(parseArguments(launchArguments.vmArgs));
109+
launchCmds.addAll(DebugUtility.parseArguments(launchArguments.vmArgs));
111110
}
112111
if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) {
113112
launchCmds.add("--module-path");
@@ -124,7 +123,7 @@ protected static String[] constructLaunchCommands(LaunchArguments launchArgument
124123
}
125124
launchCmds.add(launchArguments.mainClass);
126125
if (StringUtils.isNotBlank(launchArguments.args)) {
127-
launchCmds.addAll(parseArguments(launchArguments.args));
126+
launchCmds.addAll(DebugUtility.parseArguments(launchArguments.args));
128127
}
129128
return launchCmds.toArray(new String[0]);
130129
}
@@ -170,26 +169,6 @@ protected static String[] constructEnvironmentVariables(LaunchArguments launchAr
170169
return envVars;
171170
}
172171

173-
/**
174-
* Parses the given command line into separate arguments that can be passed
175-
* to <code>Runtime.getRuntime().exec(cmdArray)</code>.
176-
*
177-
* @param cmdStr command line as a single string.
178-
* @return the arguments array.
179-
*/
180-
protected static List<String> parseArguments(String cmdStr) {
181-
List<String> list = new ArrayList<String>();
182-
// The legal arguments are
183-
// 1. token starting with something other than quote " and followed by zero or more non-space characters
184-
// 2. a quote " followed by whatever, until another quote "
185-
Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(cmdStr);
186-
while (m.find()) {
187-
String arg = m.group(1).replaceAll("^\"|\"$", ""); // Remove surrounding quotes.
188-
list.add(arg);
189-
}
190-
return list;
191-
}
192-
193172
public static String parseMainClassWithoutModuleName(String mainClass) {
194173
int index = mainClass.indexOf('/');
195174
return mainClass.substring(index + 1);

com.microsoft.java.debug.plugin/src/main/java/com/microsoft/java/debug/plugin/internal/AdvancedLaunchingConnector.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import java.nio.file.Paths;
1818
import java.util.Map;
1919

20-
import org.eclipse.debug.core.DebugPlugin;
2120
import org.eclipse.jdi.internal.VirtualMachineImpl;
2221
import org.eclipse.jdi.internal.VirtualMachineManagerImpl;
2322
import org.eclipse.jdi.internal.connect.SocketLaunchingConnectorImpl;
@@ -115,7 +114,7 @@ private static String[] constructLaunchCommand(Map<String, ? extends Argument> l
115114
}
116115
execString.append(" " + main);
117116

118-
return DebugPlugin.parseArguments(execString.toString());
117+
return DebugUtility.parseArguments(execString.toString()).toArray(new String[0]);
119118
}
120119

121120
class AdvancedStringArgumentImpl extends StringArgumentImpl implements StringArgument {

0 commit comments

Comments
 (0)