Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.apache.commons.lang3.StringUtils;

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

return result.toArray(new String[0]);
}

/**
* Parses the given command line into separate arguments that can be passed
* to <code>Runtime.getRuntime().exec(cmdArray)</code>.
*
* @param cmdStr command line as a single string.
* @return the individual arguments.
*/
public static List<String> parseArguments(String cmdStr) {
if (cmdStr == null) {
return new ArrayList<>();
}

return AdapterUtils.isWindows() ? parseArgumentsWindows(cmdStr) : parseArgumentsNonWindows(cmdStr);
}


/**
* Parses the given command line into separate arguments for mac/linux platform.
* This piece of code is mainly copied from
* https://github.com/eclipse/eclipse.platform.debug/blob/master/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java#L1374
*
* @param args
* the command line arguments as a single string.
* @return the individual arguments
*/
private static List<String> parseArgumentsNonWindows(String args) {
// man sh, see topic QUOTING
List<String> result = new ArrayList<>();

final int DEFAULT = 0;
final int ARG = 1;
final int IN_DOUBLE_QUOTE = 2;
final int IN_SINGLE_QUOTE = 3;

int state = DEFAULT;
StringBuilder buf = new StringBuilder();
int len = args.length();
for (int i = 0; i < len; i++) {
char ch = args.charAt(i);
if (Character.isWhitespace(ch)) {
if (state == DEFAULT) {
// skip
continue;
} else if (state == ARG) {
state = DEFAULT;
result.add(buf.toString());
buf.setLength(0);
continue;
}
}
switch (state) {
case DEFAULT:
case ARG:
if (ch == '"') {
state = IN_DOUBLE_QUOTE;
} else if (ch == '\'') {
state = IN_SINGLE_QUOTE;
} else if (ch == '\\' && i + 1 < len) {
state = ARG;
ch = args.charAt(++i);
buf.append(ch);
} else {
state = ARG;
buf.append(ch);
}
break;

case IN_DOUBLE_QUOTE:
if (ch == '"') {
state = ARG;
} else if (ch == '\\' && i + 1 < len && (args.charAt(i + 1) == '\\' || args.charAt(i + 1) == '"')) {
ch = args.charAt(++i);
buf.append(ch);
} else {
buf.append(ch);
}
break;

case IN_SINGLE_QUOTE:
if (ch == '\'') {
state = ARG;
} else {
buf.append(ch);
}
break;

default:
throw new IllegalStateException();
}
}
if (buf.length() > 0 || state != DEFAULT) {
result.add(buf.toString());
}

return result;
}


/**
* Parses the given command line into separate arguments for windows platform.
* This piece of code is mainly copied from
* https://github.com/eclipse/eclipse.platform.debug/blob/master/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java#L1264
*
* @param args
* the command line arguments as a single string.
* @return the individual arguments
*/
private static List<String> parseArgumentsWindows(String args) {
// see http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
List<String> result = new ArrayList<>();
final int DEFAULT = 0;
final int ARG = 1;
final int IN_DOUBLE_QUOTE = 2;

int state = DEFAULT;
int backslashes = 0;
StringBuilder buf = new StringBuilder();
int len = args.length();
for (int i = 0; i < len; i++) {
char ch = args.charAt(i);
if (ch == '\\') {
backslashes++;
continue;
} else if (backslashes != 0) {
if (ch == '"') {
for (; backslashes >= 2; backslashes -= 2) {
buf.append('\\');
}
if (backslashes == 1) {
if (state == DEFAULT) {
state = ARG;
}
buf.append('"');
backslashes = 0;
continue;
} // else fall through to switch
} else {
// false alarm, treat passed backslashes literally...
if (state == DEFAULT) {
state = ARG;
}
for (; backslashes > 0; backslashes--) {
buf.append('\\');
}
// fall through to switch
}
}
if (Character.isWhitespace(ch)) {
if (state == DEFAULT) {
// skip
continue;
} else if (state == ARG) {
state = DEFAULT;
result.add(buf.toString());
buf.setLength(0);
continue;
}
}
switch (state) {
case DEFAULT:
case ARG:
if (ch == '"') {
state = IN_DOUBLE_QUOTE;
} else {
state = ARG;
buf.append(ch);
}
break;

case IN_DOUBLE_QUOTE:
if (ch == '"') {
if (i + 1 < len && args.charAt(i + 1) == '"') {
/* Undocumented feature in Windows:
* Two consecutive double quotes inside a double-quoted argument are interpreted as
* a single double quote.
*/
buf.append('"');
i++;
} else if (buf.length() == 0) {
// empty string on Windows platform. Account for bug in constructor of JDK's java.lang.ProcessImpl.
result.add("\"\""); //$NON-NLS-1$
state = DEFAULT;
} else {
state = ARG;
}
} else {
buf.append(ch);
}
break;

default:
throw new IllegalStateException();
}
}
if (buf.length() > 0 || state != DEFAULT) {
result.add(buf.toString());
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@
import java.util.Map.Entry;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import com.microsoft.java.debug.core.Configuration;
import com.microsoft.java.debug.core.DebugSettings;
import com.microsoft.java.debug.core.DebugUtility;
import com.microsoft.java.debug.core.adapter.AdapterUtils;
import com.microsoft.java.debug.core.adapter.ErrorCode;
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
Expand Down Expand Up @@ -107,7 +106,7 @@ protected static String[] constructLaunchCommands(LaunchArguments launchArgument
launchCmds.add(String.format("-agentlib:jdwp=transport=dt_socket,server=%s,suspend=y,address=%s", serverMode ? "y" : "n", address));
}
if (StringUtils.isNotBlank(launchArguments.vmArgs)) {
launchCmds.addAll(parseArguments(launchArguments.vmArgs));
launchCmds.addAll(DebugUtility.parseArguments(launchArguments.vmArgs));
}
if (ArrayUtils.isNotEmpty(launchArguments.modulePaths)) {
launchCmds.add("--module-path");
Expand All @@ -124,7 +123,7 @@ protected static String[] constructLaunchCommands(LaunchArguments launchArgument
}
launchCmds.add(launchArguments.mainClass);
if (StringUtils.isNotBlank(launchArguments.args)) {
launchCmds.addAll(parseArguments(launchArguments.args));
launchCmds.addAll(DebugUtility.parseArguments(launchArguments.args));
}
return launchCmds.toArray(new String[0]);
}
Expand Down Expand Up @@ -170,26 +169,6 @@ protected static String[] constructEnvironmentVariables(LaunchArguments launchAr
return envVars;
}

/**
* Parses the given command line into separate arguments that can be passed
* to <code>Runtime.getRuntime().exec(cmdArray)</code>.
*
* @param cmdStr command line as a single string.
* @return the arguments array.
*/
protected static List<String> parseArguments(String cmdStr) {
List<String> list = new ArrayList<String>();
// The legal arguments are
// 1. token starting with something other than quote " and followed by zero or more non-space characters
// 2. a quote " followed by whatever, until another quote "
Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(cmdStr);
while (m.find()) {
String arg = m.group(1).replaceAll("^\"|\"$", ""); // Remove surrounding quotes.
list.add(arg);
}
return list;
}

public static String parseMainClassWithoutModuleName(String mainClass) {
int index = mainClass.indexOf('/');
return mainClass.substring(index + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import java.nio.file.Paths;
import java.util.Map;

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

return DebugPlugin.parseArguments(execString.toString());
return DebugUtility.parseArguments(execString.toString()).toArray(new String[0]);
}

class AdvancedStringArgumentImpl extends StringArgumentImpl implements StringArgument {
Expand Down