summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Keller2012-09-05 11:59:51 (EDT)
committer Mike Rennie2012-09-05 11:59:51 (EDT)
commit37978528c6f546dbacda8aaa7c9b284e602b5b44 (patch)
treecee56b51c5b3edecff7ec849a07e50974cc6243b
parent176d9f36b174c79199db39afe242047fc5d6290d (diff)
downloadeclipse.platform.debug-37978528c6f546dbacda8aaa7c9b284e602b5b44.zip
eclipse.platform.debug-37978528c6f546dbacda8aaa7c9b284e602b5b44.tar.gz
eclipse.platform.debug-37978528c6f546dbacda8aaa7c9b284e602b5b44.tar.bz2
Bug 387504 - Bugs in program argument parsing (compared to command line)v20120905-155951
-rw-r--r--org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java355
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentParsingTests.java255
-rw-r--r--org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentsPrinter.java23
-rw-r--r--org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java2
-rw-r--r--org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/preferences/ProcessPropertyPage.java43
5 files changed, 553 insertions, 125 deletions
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java
index 463920b..13b6029 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/DebugPlugin.java
@@ -853,6 +853,13 @@ public class DebugPlugin extends Plugin {
* @since 3.0
*/
public static Process exec(String[] cmdLine, File workingDirectory, String[] envp) throws CoreException {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ String[] winCmdLine= new String[cmdLine.length];
+ for (int i= 0; i < cmdLine.length; i++) {
+ winCmdLine[i]= winQuote(cmdLine[i]);
+ }
+ cmdLine= winCmdLine;
+ }
Process p= null;
try {
if (workingDirectory == null) {
@@ -876,7 +883,28 @@ public class DebugPlugin extends Plugin {
}
}
return p;
- }
+ }
+
+ private static boolean needsQuoting(String s) {
+ int len = s.length();
+ if (len == 0) // empty string has to be quoted
+ return true;
+ for (int i = 0; i < len; i++) {
+ switch (s.charAt(i)) {
+ case ' ': case '\t': case '\\': case '"':
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String winQuote(String s) {
+ if (! needsQuoting(s))
+ return s;
+ s = s.replaceAll("([\\\\]*)\"", "$1$1\\\\\""); //$NON-NLS-1$ //$NON-NLS-2$
+ s = s.replaceAll("([\\\\]*)\\z", "$1$1"); //$NON-NLS-1$ //$NON-NLS-2$
+ return "\"" + s + "\""; //$NON-NLS-1$ //$NON-NLS-2$
+ }
/**
* Returns whether this plug-in is in the process of
@@ -1256,115 +1284,168 @@ public class DebugPlugin extends Plugin {
throw new CoreException(status);
}
- /**
- * Utility class to parse command line arguments.
- *
- * @since 3.1
- */
- private static class ArgumentParser {
- private String fArgs;
- private int fIndex= 0;
- private int ch= -1;
-
- public ArgumentParser(String args) {
- fArgs= args;
- }
-
- public String[] parseArguments() {
- List v= new ArrayList();
-
- ch= getNext();
- while (ch > 0) {
- if (Character.isWhitespace((char)ch)) {
- ch= getNext();
+ private static String[] parseArgumentsWindows(String args) {
+ // see http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
+ List result= new ArrayList();
+
+ final int DEFAULT= 0;
+ final int ARG= 1;
+ final int IN_DOUBLE_QUOTE= 2;
+
+ int state= DEFAULT;
+ int backslashes= 0;
+ StringBuffer buf= new StringBuffer();
+ 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 {
- if (ch == '"') {
- StringBuffer buf = new StringBuffer();
- buf.append(parseString());
- if (buf.length() == 0 && Platform.getOS().equals(Constants.OS_WIN32)) {
- // empty string on windows platform
- buf.append("\"\""); //$NON-NLS-1$
- }
- v.add(buf.toString());
- } else {
- v.add(parseToken());
+ // false alarm, treat passed backslashes literally...
+ if (state == DEFAULT)
+ state= ARG;
+ for (; backslashes > 0; backslashes--) {
+ buf.append('\\');
}
+ // fall through to switch
}
}
-
- String[] result= new String[v.size()];
- v.toArray(result);
- return result;
- }
-
- private int getNext() {
- if (fIndex < fArgs.length())
- return fArgs.charAt(fIndex++);
- return -1;
- }
-
- private String parseString() {
- ch= getNext();
- if (ch == '"') {
- ch= getNext();
- return ""; //$NON-NLS-1$
+ if (Character.isWhitespace(ch)) {
+ if (state == DEFAULT) {
+ // skip
+ continue;
+ } else if (state == ARG) {
+ state= DEFAULT;
+ result.add(buf.toString());
+ buf.setLength(0);
+ continue;
+ }
}
- StringBuffer buf= new StringBuffer();
- while (ch > 0 && ch != '"') {
- if (ch == '\\') {
- ch= getNext();
- if (ch != '"') { // Only escape double quotes
- buf.append('\\');
+ switch (state) {
+ case DEFAULT:
+ case ARG:
+ if (ch == '"') {
+ state= IN_DOUBLE_QUOTE;
} else {
- if (Platform.getOS().equals(Constants.OS_WIN32)) {
- // @see Bug 26870. Windows requires an extra escape for embedded strings
- buf.append('\\');
+ 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);
}
- }
- if (ch > 0) {
- buf.append((char)ch);
- ch= getNext();
- }
+ break;
+
+ default:
+ throw new IllegalStateException();
}
- ch= getNext();
- return buf.toString();
}
-
- private String parseToken() {
- StringBuffer buf= new StringBuffer();
-
- while (ch > 0 && !Character.isWhitespace((char)ch)) {
- if (ch == '\\') {
- ch= getNext();
- if (Character.isWhitespace((char)ch)) {
- // end of token, don't lose trailing backslash
- buf.append('\\');
- return buf.toString();
+ if (buf.length() > 0)
+ result.add(buf.toString());
+
+ return (String[]) result.toArray(new String[result.size()]);
+ }
+
+ private static String[] parseArgumentsImpl(String args) {
+ // man sh, see topic QUOTING
+ List 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;
+ StringBuffer buf= new StringBuffer();
+ 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);
}
- if (ch > 0) {
- if (ch != '"') { // Only escape double quotes
- buf.append('\\');
- } else {
- if (Platform.getOS().equals(Constants.OS_WIN32)) {
- // @see Bug 26870. Windows requires an extra escape for embedded strings
- buf.append('\\');
- }
- }
- buf.append((char)ch);
- ch= getNext();
- } else if (ch == -1) { // Don't lose a trailing backslash
- buf.append('\\');
+ 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);
}
- } else if (ch == '"') {
- buf.append(parseString());
- } else {
- buf.append((char)ch);
- ch= getNext();
- }
+ break;
+
+ case IN_SINGLE_QUOTE:
+ if (ch == '\'') {
+ state= ARG;
+ } else {
+ buf.append(ch);
+ }
+ break;
+
+ default:
+ throw new IllegalStateException();
}
- return buf.toString();
}
+ if (buf.length() > 0)
+ result.add(buf.toString());
+
+ return (String[]) result.toArray(new String[result.size()]);
}
/**
@@ -1379,13 +1460,89 @@ public class DebugPlugin extends Plugin {
public static String[] parseArguments(String args) {
if (args == null)
return new String[0];
- ArgumentParser parser= new ArgumentParser(args);
- String[] res= parser.parseArguments();
- return res;
+ if (Constants.OS_WIN32.equals(Platform.getOS()))
+ return parseArgumentsWindows(args);
+
+ return parseArgumentsImpl(args);
}
/**
+ * Renders the given array of strings into a single command line.
+ * <p>
+ * If <code>segments</code> is not <code>null</code>, the array is filled
+ * with the offsets of the start positions of arguments 1 to
+ * <code>arguments.length - 1</code>, as rendered in the resulting string.
+ * </p>
+ *
+ * @param arguments
+ * the command line arguments
+ * @param segments
+ * an array of size <code>arguments.length - 1</code> or
+ * <code>null</code>
+ * @return the command line
+ * @since 3.8
+ */
+ public static String renderArguments(String[] arguments, int[] segments) {
+ boolean isWin32= Platform.getOS().equals(Constants.OS_WIN32);
+ StringBuffer buf = new StringBuffer();
+ int count = arguments.length;
+ for (int i = 0; i < count; i++) {
+ if (i > 0)
+ buf.append(' ');
+
+ boolean containsSpace = false;
+ char[] characters = arguments[i].toCharArray();
+ for (int j = 0; j < characters.length; j++) {
+ char ch = characters[j];
+ if (ch == ' ' || ch == '\t') {
+ containsSpace = true;
+ buf.append('"');
+ break;
+ }
+ }
+
+ int backslashes = 0;
+ for (int j = 0; j < characters.length; j++) {
+ char ch = characters[j];
+ if (ch == '"') {
+ if (isWin32) {
+ if (j == 0 && characters.length == 2 && characters[1] == '"') {
+ // empty string on windows platform, see bug 130767. Bug in constructor of JDK's java.lang.ProcessImpl.
+ buf.append("\"\""); //$NON-NLS-1$
+ break;
+ }
+ if (backslashes > 0) {
+ // Feature in Windows: need to double-escape backslashes in front of double quote.
+ for (; backslashes > 0; backslashes--) {
+ buf.append('\\');
+ }
+ }
+ }
+ buf.append('\\');
+ } else if (ch == '\\') {
+ if (isWin32) {
+ backslashes++;
+ } else {
+ buf.append('\\');
+ }
+ }
+ buf.append(ch);
+ }
+ if (containsSpace) {
+ buf.append('"');
+ } else if (characters.length == 0) {
+ buf.append("\"\""); //$NON-NLS-1$
+ }
+
+ if (segments != null && i < count - 1) {
+ segments[i] = buf.length() + 1;
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
* Sets whether step filters should be applied to step commands. This
* setting is a global option applied to all registered debug targets.
*
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentParsingTests.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentParsingTests.java
new file mode 100644
index 0000000..33647b7
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentParsingTests.java
@@ -0,0 +1,255 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipe.debug.tests.launching;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.URIUtil;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.tests.TestsPlugin;
+import org.eclipse.osgi.service.environment.Constants;
+
+/**
+ * Tests {@link org.eclipse.debug.core.DebugPlugin#parseArguments(String)} and
+ * {@link org.eclipse.debug.core.DebugPlugin#renderCommandLine(String[], int[])}.
+ */
+public class ArgumentParsingTests extends TestCase {
+
+ private void execute1Arg(String cmdLine) throws Exception {
+ execute1Arg(cmdLine, cmdLine);
+ }
+
+ private void execute1Arg(String cmdLine, String argParsed) throws Exception {
+ execute1Arg(cmdLine, argParsed, cmdLine);
+ }
+
+ private void execute1Arg(String cmdLine, String argParsed, String rendered) throws Exception {
+ execute("a " + cmdLine + " b", new String[] { "a", argParsed, "b" }, "a " + rendered + " b");
+ }
+
+ private static void execute(String commandLine, String[] expectedArgs) throws Exception {
+ execute(commandLine, expectedArgs, commandLine);
+ }
+
+ private static void execute(String commandLine, String[] expectedArgs, String expectedRendered) throws Exception {
+ String[] arguments = DebugPlugin.parseArguments(commandLine);
+ assertEquals("unexpected parseArguments result;",
+ Arrays.asList(expectedArgs).toString(),
+ Arrays.asList(arguments).toString());
+
+ runCommandLine(commandLine, arguments);
+
+ String rendered = DebugPlugin.renderArguments(arguments, null);
+ assertEquals("unexpected renderArguments result;", expectedRendered, rendered);
+
+ if (!commandLine.equals(rendered)) {
+ String[] arguments2 = DebugPlugin.parseArguments(rendered);
+ assertEquals("parsing rendered command line doesn't yield original arguments;",
+ Arrays.asList(expectedArgs).toString(),
+ Arrays.asList(arguments2).toString());
+ }
+
+ }
+
+ private static void runCommandLine(String commandLine, String[] arguments) throws IOException,
+ URISyntaxException, CoreException {
+ URL classFolderUrl = FileLocator.find(TestsPlugin.getDefault().getBundle(), new Path("bin/"), null);
+ classFolderUrl= FileLocator.toFileURL(classFolderUrl);
+ File classFolderFile = URIUtil.toFile(URIUtil.toURI(classFolderUrl));
+
+ String[] execArgs= new String[arguments.length + 2];
+ execArgs[0]= new Path(System.getProperty("java.home")).append("bin/java").toOSString();
+ execArgs[1]= ArgumentsPrinter.class.getName();
+ System.arraycopy(arguments, 0, execArgs, 2, arguments.length);
+
+ ArrayList resultArgs = runCommandLine(execArgs, classFolderFile);
+
+ assertEquals("unexpected exec result;",
+ Arrays.asList(arguments).toString(),
+ resultArgs.toString());
+
+ if (! Platform.getOS().equals(Constants.OS_WIN32)) {
+ execArgs= new String[] { "sh", "-c", execArgs[0] + " " + execArgs[1] + " " + commandLine};
+ resultArgs = runCommandLine(execArgs, classFolderFile);
+ assertEquals("unexpected sh exec result;",
+ Arrays.asList(arguments).toString(),
+ resultArgs.toString());
+
+ }
+ }
+
+ private static ArrayList runCommandLine(String[] execArgs, File workingDir)
+ throws CoreException, IOException {
+ Process process = DebugPlugin.exec(execArgs, workingDir);
+ BufferedReader procOut = new BufferedReader(new InputStreamReader(process.getInputStream()));
+
+ ArrayList procArgs= new ArrayList();
+ String procArg;
+ while ((procArg = procOut.readLine()) != null) {
+ procArgs.add(procArg);
+ }
+ return procArgs;
+ }
+
+ // -- tests:
+
+ public void testEmpty() throws Exception {
+ execute("", new String[0]);
+ }
+
+ public void test1arg() throws Exception {
+ execute("a", new String[] { "a" });
+ }
+
+ public void test2arg() throws Exception {
+ execute("a b", new String[] { "a", "b" });
+ }
+
+ public void test100arg() throws Exception {
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < 100; i++)
+ buf.append("a ");
+ String[] args = new String[100];
+ Arrays.fill(args, "a");
+ execute(buf.toString(), args, buf.toString().trim());
+ }
+
+ public void testEscape() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute1Arg("\\1");
+ } else {
+ execute1Arg("\\1", "1", "1");
+ }
+ }
+
+ public void testEscapeDoubleQuote1() throws Exception {
+ execute1Arg("\\\"", "\"", "\\\"");
+ }
+
+ public void testEscapeDoubleQuote2() throws Exception {
+ execute1Arg("arg=\\\"bla\\\"", "arg=\"bla\"", "arg=\\\"bla\\\"");
+ }
+
+ public void testDoubleQuoted1() throws Exception {
+ execute1Arg("\"1 2\"", "1 2");
+ }
+
+ public void testDoubleQuoted2() throws Exception {
+ execute1Arg("\"1\"", "1", "1");
+ }
+
+ public void testDoubleQuoted3() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+// execute1Arg("\"\"", "", "\"\""); // would be correct, but ProcessImpl is buggy on Windows JDKs
+ execute1Arg("\"\"");
+ } else {
+ execute1Arg("\"\"", "", "\"\"");
+ }
+ }
+
+ public void testDoubleQuoted4() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute1Arg("\"\"\"\"", "\"", "\\\"");
+ } else {
+ execute1Arg("\"\"\"\"", "", "\"\"");
+ }
+ }
+
+ public void testDoubleQuoted5() throws Exception {
+ execute1Arg("ab\"cd\"ef\"gh\"", "abcdefgh", "abcdefgh");
+ }
+
+ public void testDoubleQuotedWithSpace1() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute1Arg("\"\"\"1\"\" 2\"", "\"1\" 2", "\"\\\"1\\\" 2\"");
+ } else {
+ execute1Arg("\"\"\"1\"\" 2\"", "1 2", "\"1 2\"");
+ }
+ }
+
+ public void testDoubleQuotedWithSpace2() throws Exception {
+ execute1Arg("\"\\\"1\\\" 2\"", "\"1\" 2");
+ }
+
+ public void testSingleQuoted1() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute("'1 2'", new String[] { "'1", "2'" });
+ } else {
+ execute("'1 2'", new String[] { "1 2" }, "\"1 2\"");
+ }
+ }
+
+ public void testSingleQuoted2() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute1Arg("'1'", "'1'", "'1'");
+ } else {
+ execute1Arg("'1'", "1", "1");
+ }
+ }
+
+ public void testWindows1() throws Exception {
+ execute("\"a b c\" d e", new String[] { "a b c", "d", "e" });
+ }
+
+ public void testWindows2() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute("\"ab\\\"c\" \"\\\\\" d", new String[] { "ab\"c", "\\", "d" }, "ab\\\"c \\ d");
+ } else {
+ execute("\"ab\\\"c\" \"\\\\\" d", new String[] { "ab\"c", "\\", "d" }, "ab\\\"c \\\\ d");
+ }
+ }
+
+ public void testWindows3() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute("a\\\\\\b d\"e f\"g h", new String[] { "a\\\\\\b", "de fg", "h" }, "a\\\\\\b \"de fg\" h");
+ } else {
+ execute("a\\\\\\b d\"e f\"g h", new String[] { "a\\b", "de fg", "h" }, "a\\\\b \"de fg\" h");
+ }
+ }
+
+ public void testWindows4() throws Exception {
+ execute("a\\\\\\\"b c d", new String[] { "a\\\"b", "c", "d" });
+ }
+
+ public void testWindows5() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute("a\\\\\\\\\"b c\" d e", new String[] { "a\\\\b c", "d", "e" }, "\"a\\\\b c\" d e");
+ } else {
+ execute("a\\\\\\\\\"b c\" d e", new String[] { "a\\\\b c", "d", "e" }, "\"a\\\\\\\\b c\" d e");
+ }
+ }
+
+ public void testAllInOne() throws Exception {
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ execute("1 \"\" 2 \" \" 3 \\\" 4 \"a b\" 5 \\\"bla\\\" 6 \"ab\"cd 7 ef\"gh\" 8 i\"\"j 9 \"x\\\"y\\\\\" 10 z\\\\z 11 \"two-quotes:\"\"\"\"\" 12 \"g\"\"h\" 13 \"\"\"a\"\" b\"",
+ new String[] { "1", "\"\"", "2", " ", "3", "\"", "4", "a b", "5", "\"bla\"", "6", "abcd", "7", "efgh", "8", "ij", "9", "x\"y\\", "10", "z\\\\z", "11", "two-quotes:\"\"", "12", "g\"h", "13", "\"a\" b" },
+ "1 \"\" 2 \" \" 3 \\\" 4 \"a b\" 5 \\\"bla\\\" 6 abcd 7 efgh 8 ij 9 x\\\"y\\ 10 z\\\\z 11 two-quotes:\\\"\\\" 12 g\\\"h 13 \"\\\"a\\\" b\"");
+ } else {
+ execute("1 \"\" 2 \" \" 3 \\\" 4 \"a b\" 5 \\\"bla\\\" 6 \"ab\"cd 7 ef\"gh\" 8 i\"\"j 9 \"x\\\"y\\\\\" 10 z\\\\z 11 \"two-quotes:\"\"\"\"\" 12 \"g\"\"h\" 13 \"\"\"a\"\" b\"",
+ new String[] { "1", "", "2", " ", "3", "\"", "4", "a b", "5", "\"bla\"", "6", "abcd", "7", "efgh", "8", "ij", "9", "x\"y\\", "10", "z\\z", "11", "two-quotes:", "12", "gh", "13", "a b" },
+ "1 \"\" 2 \" \" 3 \\\" 4 \"a b\" 5 \\\"bla\\\" 6 abcd 7 efgh 8 ij 9 x\\\"y\\\\ 10 z\\\\z 11 two-quotes: 12 gh 13 \"a b\"");
+ }
+ }
+
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentsPrinter.java b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentsPrinter.java
new file mode 100644
index 0000000..9651de2
--- /dev/null
+++ b/org.eclipse.debug.tests/src/org/eclipe/debug/tests/launching/ArgumentsPrinter.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2012 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipe.debug.tests.launching;
+
+/**
+ * Used by {@link ArgumentParsingTests}.
+ */
+public class ArgumentsPrinter {
+ public static void main(String[] args) {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ System.out.println(arg);
+ }
+ }
+}
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
index 87fbb05..7fb3eac 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/AutomatedSuite.java
@@ -15,6 +15,7 @@ import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipe.debug.tests.launching.AcceleratorSubstitutionTests;
+import org.eclipe.debug.tests.launching.ArgumentParsingTests;
import org.eclipe.debug.tests.launching.LaunchConfigurationTests;
import org.eclipe.debug.tests.launching.LaunchFavoriteTests;
import org.eclipe.debug.tests.launching.LaunchHistoryTests;
@@ -83,6 +84,7 @@ public class AutomatedSuite extends TestSuite {
addTest(new TestSuite(LaunchFavoriteTests.class));
addTest(new TestSuite(LaunchManagerTests.class));
addTest(new TestSuite(RefreshTabTests.class));
+ addTest(new TestSuite(ArgumentParsingTests.class));
// Status handlers
addTest(new TestSuite(StatusHandlerTests.class));
diff --git a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/preferences/ProcessPropertyPage.java b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/preferences/ProcessPropertyPage.java
index 129b493..4e42fc0 100644
--- a/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/preferences/ProcessPropertyPage.java
+++ b/org.eclipse.debug.ui/ui/org/eclipse/debug/internal/ui/preferences/ProcessPropertyPage.java
@@ -93,33 +93,24 @@ public class ProcessPropertyPage extends PropertyPage {
((GridData)text.getLayoutData()).horizontalIndent = 10;
String commandLineText = getCommandLineText(proc);
if (commandLineText != null) {
- final String[] arguments = DebugPlugin.parseArguments(commandLineText);
- StringBuffer renderedCommandLine = new StringBuffer(commandLineText.length());
- for (int i = 0; i < arguments.length; i++) {
- if (i > 0)
- renderedCommandLine.append(' ');
- renderedCommandLine.append(arguments[i]);
- }
- text.addSegmentListener(new SegmentListener() {
- public void getSegments(SegmentEvent event) {
- int count = arguments.length;
- if (count < 2)
- return;
-
- int[] segments = new int[count - 1];
- int nextStart = arguments[0].length() + 1;
- for (int i = 1; i < count; i++) {
- segments[i - 1] = nextStart;
- nextStart = nextStart + arguments[i].length() + 1;
+ String[] arguments = DebugPlugin.parseArguments(commandLineText);
+ int count = arguments.length;
+ if (count > 1) {
+ // render as one argument per line, but don't copy line delimiters to clipboard:
+ final int[] segments = new int[count - 1];
+ final char[] chars = new char[count - 1];
+ Arrays.fill(chars, '\n');
+
+ commandLineText = DebugPlugin.renderArguments(arguments, segments);
+
+ text.addSegmentListener(new SegmentListener() {
+ public void getSegments(SegmentEvent event) {
+ event.segments = segments;
+ event.segmentsChars = chars;
}
- event.segments = segments;
-
- char[] chars = new char[count - 1];
- Arrays.fill(chars, '\n');
- event.segmentsChars = chars;
- }
- });
- text.setText(renderedCommandLine.toString());
+ });
+ }
+ text.setText(commandLineText);
}
//create environment section