From 07647b57a3b66596a44bf99bed8d7cfb3d555e87 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Thu, 28 Feb 2008 16:08:09 +0000 Subject: [PATCH] [219920] Added mechanism for adjusting command parameter formatting. --- .../service/command/commands/Adjustable.java | 26 ++ .../command/commands/MIBreakInsert.java | 24 +- .../service/command/commands/MICommand.java | 231 ++++++++++++------ .../mi/service/command/commands/AllTests.java | 31 +++ .../commands/TestMIBreakInsertCommand.java | 62 +++++ .../TestMICommandConstructCommand.java | 64 +++++ 6 files changed, 360 insertions(+), 78 deletions(-) create mode 100644 plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/Adjustable.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/AllTests.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMIBreakInsertCommand.java create mode 100644 plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMICommandConstructCommand.java diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/Adjustable.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/Adjustable.java new file mode 100644 index 00000000000..47536a612cc --- /dev/null +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/Adjustable.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson. + * 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: + * Ericsson - initial API and implementation for bug 219920 + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +/** + * The implementor of this interface may adjust its output. + * + * This is used for MICommands where the output of each option and/or parameter + * may be adjusted independently to conform to the current version of the MI + * interface. + * + */ +public interface Adjustable { + + String getValue(); + + String getAdjustedValue(); +} diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java index 79446d9b165..228b32ad613 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MIBreakInsert.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -8,6 +8,7 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Wind River Systems - Modified for new DSF Reference Implementation + * Ericsson - Modified for bug 219920 *******************************************************************************/ package org.eclipse.dd.mi.service.command.commands; @@ -110,11 +111,30 @@ public class MIBreakInsert extends MICommand if (opts.length > 0) { setOptions(opts); } - setParameters(new String[]{line}); + setParameters(new Adjustable[]{ new PathAdjustable(line)}); } @Override public MIBreakInsertInfo getResult(MIOutput output) { return new MIBreakInsertInfo(output); } + + /** + * This adjustable makes sure that the path parameter will not get the + * backslashes substituted with double backslashes. + */ + private class PathAdjustable + extends + org.eclipse.dd.mi.service.command.commands.MICommand.MIStandardParameterAdjustable { + + public PathAdjustable(String path) { + super(path); + } + + @Override + public String getAdjustedValue() { + String adjustedValue = super.getAdjustedValue(); + return adjustedValue.replace("\\\\", "\\"); //$NON-NLS-1$//$NON-NLS-2$ + } + } } diff --git a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java index bc85b408536..91c8e41dd45 100644 --- a/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java +++ b/plugins/org.eclipse.dd.mi/src/org/eclipse/dd/mi/service/command/commands/MICommand.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2000, 2007 QNX Software Systems and others. + * Copyright (c) 2000, 2008 QNX Software Systems 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 @@ -8,11 +8,15 @@ * Contributors: * QNX Software Systems - Initial API and implementation * Wind River Systems - Modified for new DSF Reference Implementation - * Ericsson - Modified for additional features in DSF Reference implementation + * Ericsson - Modified for additional features in DSF Reference implementation and bug 219920 *******************************************************************************/ package org.eclipse.dd.mi.service.command.commands; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.eclipse.dd.dsf.datamodel.DMContexts; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.debug.service.command.ICommand; @@ -31,8 +35,8 @@ public class MICommand implements ICommand { */ final static String[] empty = new String[0]; - String[] fOptions = empty; - String[] fParameters = empty; + List fOptions = new ArrayList(); + List fParameters = new ArrayList(); String fOperation = new String(); IDMContext fCtx; @@ -60,10 +64,30 @@ public class MICommand implements ICommand { assert(ctx != null && DMContexts.getAncestorOfType(ctx, MIControlDMContext.class) != null); fCtx = ctx; fOperation = operation; - fOptions = options; - fParameters = params; + fOptions = optionsToAdjustables(options); + fParameters = parametersToAdjustables(params); } + + private final List optionsToAdjustables(String[] options) { + List result = new ArrayList(); + if (options != null) { + for (String option : options) { + result.add(new MIStandardOptionAdjustable(option)); + } + } + return result; + } + private final List parametersToAdjustables(String[] parameters) { + List result = new ArrayList(); + if (parameters != null) { + for (String parameter : parameters) { + result.add(new MIStandardParameterAdjustable(parameter)); + } + } + return result; + } + public String getCommandControlFilter() { MIControlDMContext controlDmc = DMContexts.getAncestorOfType(getContext(), MIControlDMContext.class); return controlDmc.getCommandControlFilter(); @@ -81,11 +105,15 @@ public class MICommand implements ICommand { * returned if there are no options. */ public String[] getOptions() { - return fOptions; + List result = new ArrayList(); + for (Adjustable option : fOptions) { + result.add(option.getValue()); + } + return result.toArray(new String[fOptions.size()]); } public void setOptions(String[] options) { - fOptions = options; + fOptions = optionsToAdjustables(options); } /* @@ -93,13 +121,21 @@ public class MICommand implements ICommand { * returned if there are no parameters. */ public String[] getParameters() { - return fParameters; + List result = new ArrayList(); + for (Adjustable parameter : fParameters) { + result.add(parameter.getValue()); + } + return result.toArray(new String[fParameters.size()]); } public void setParameters(String[] params) { - fParameters = params; + fParameters = parametersToAdjustables(params); } + public void setParameters(Adjustable... params) { + fParameters = Arrays.asList(params); + } + /* * Returns the constructed command. */ @@ -149,78 +185,38 @@ public class MICommand implements ICommand { } protected String optionsToString() { - String[] options = getOptions(); - StringBuffer sb = new StringBuffer(); - if (options != null && options.length > 0) { - for (int i = 0; i < options.length; i++) { - String option = options[i]; - // If the option argument contains " or \ it must be escaped - if (option.indexOf('"') != -1 || option.indexOf('\\') != -1) { - StringBuffer buf = new StringBuffer(); - for (int j = 0; j < option.length(); j++) { - char c = option.charAt(j); - if (c == '"' || c == '\\') { - buf.append('\\'); - } - buf.append(c); - } - option = buf.toString(); - } - - // If the option contains a space according to - // GDB/MI spec we must surround it with double quotes. - if (option.indexOf('\t') != -1 || option.indexOf(' ') != -1) { - sb.append(' ').append('"').append(option).append('"'); - } else { - sb.append(' ').append(option); - } - } - } - return sb.toString().trim(); + StringBuffer sb = new StringBuffer(); + if (fOptions != null && fOptions.size() > 0) { + for (Adjustable option : fOptions) { + sb.append(option.getAdjustedValue()); + } + } + return sb.toString().trim(); } protected String parametersToString() { - String[] parameters = getParameters(); - String[] options = getOptions(); - StringBuffer buffer = new StringBuffer(); - if (parameters != null && parameters.length > 0) { - // According to GDB/MI spec - // Add a "--" separator if any parameters start with "-" - if (options != null && options.length > 0) { - for (int i = 0; i < parameters.length; i++) { - if (parameters[i].startsWith("-")) { //$NON-NLS-1$ - buffer.append('-').append('-'); - break; - } - } - } + String[] options = getOptions(); + StringBuffer buffer = new StringBuffer(); + if (fParameters != null && fParameters.size() > 0) { + // According to GDB/MI spec + // Add a "--" separator if any parameters start with "-" + if (options != null && options.length > 0) { + for (Adjustable parameter : fParameters) { + if (parameter.getValue().startsWith("-")) {//$NON-NLS-1$ + buffer.append('-').append('-'); + break; + } + } + } - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < parameters.length; i++) { - // We need to escape the double quotes and the backslash. - sb.setLength(0); - String param = parameters[i]; - for (int j = 0; j < param.length(); j++) { - char c = param.charAt(j); - if (c == '"' || c == '\\') { - sb.append('\\'); - } - sb.append(c); - } - - // If the string contains spaces instead of escaping - // surround the parameter with double quotes. - if (containsWhitespace(param)) { - sb.insert(0, '"'); - sb.append('"'); - } - buffer.append(' ').append(sb); - } - } - return buffer.toString().trim(); + for (Adjustable parameter : fParameters) { + buffer.append(' ').append(parameter.getAdjustedValue()); + } + } + return buffer.toString().trim(); } - protected boolean containsWhitespace(String s) { + protected static boolean containsWhitespace(String s) { for (int i = 0; i < s.length(); i++) { if (Character.isWhitespace(s.charAt(i))) { return true; @@ -253,4 +249,87 @@ public class MICommand implements ICommand { public String toString() { return constructCommand(); } + + public static class MIStandardOptionAdjustable extends MICommandAdjustable { + + public MIStandardOptionAdjustable(String option) { + super(option); + } + + public String getAdjustedValue() { + StringBuilder builder = new StringBuilder(); + String option = value; + // If the option argument contains " or \ it must be escaped + if (option.indexOf('"') != -1 || option.indexOf('\\') != -1) { + StringBuilder buf = new StringBuilder(); + for (int j = 0; j < option.length(); j++) { + char c = option.charAt(j); + if (c == '"' || c == '\\') { + buf.append('\\'); + } + buf.append(c); + } + option = buf.toString(); + } + + // If the option contains a space according to + // GDB/MI spec we must surround it with double quotes. + if (option.indexOf('\t') != -1 || option.indexOf(' ') != -1) { + builder.append(' ').append('"').append(option).append('"'); + } else { + builder.append(' ').append(option); + } + return builder.toString(); + } + } + + public static class MIStandardParameterAdjustable extends + MICommandAdjustable { + public MIStandardParameterAdjustable(String parameter) { + super(parameter); + } + + public String getAdjustedValue() { + StringBuilder builder = new StringBuilder(); + for (int j = 0; j < value.length(); j++) { + char c = value.charAt(j); + if (c == '"' || c == '\\') { + builder.append('\\'); + } + builder.append(c); + } + + // If the string contains spaces instead of escaping + // surround the parameter with double quotes. + if (containsWhitespace(value)) { + builder.insert(0, '"'); + builder.append('"'); + } + + return builder.toString(); + } + } + + public static abstract class MICommandAdjustable implements Adjustable { + + protected final String value; + + /** + * Creates a new instance. + * + * @param builder + * The string builder is an optimization option, if two + * commands are not processed at the same time a shared + * builder can be used to save memory. + * @param value + * The value that should be adjusted. + */ + public MICommandAdjustable(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + } } diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/AllTests.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/AllTests.java new file mode 100644 index 00000000000..a1f34c313a4 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/AllTests.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/* + * This class is meant to be empty. It enables us to define + * the annotations which list all the different JUnit class we + * want to run. When creating a new test class, it should be + * added to the list below. + */ + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + TestMIBreakInsertCommand.class, + TestMICommandConstructCommand.class, + + /* Add your test class here */ + }) + +public class AllTests {} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMIBreakInsertCommand.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMIBreakInsertCommand.java new file mode 100644 index 00000000000..975573edf0c --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMIBreakInsertCommand.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; +import org.junit.Test; + +/** + * Verifies that the break insert MI command have the correct path substitution. + * + * @author qtobsod + * + */ +public class TestMIBreakInsertCommand { + + @Test + public void pathShouldNotContainDoubleBackSlashes() { + MIBreakInsert target = new MIBreakInsert(new TestContext(), false, + false, null, 1, "c:\\test\\this\\path:14", 4); + + assertEquals("Wrong syntax for command", + "-break-insert -i 1 -p 4 c:\\test\\this\\path:14\n", target + .constructCommand()); + } + + @Test + public void pathWithSlashesShouldNotBeSubstituted() { + MIBreakInsert target = new MIBreakInsert(new TestContext(), false, + false, null, 1, "/test/this/path:14", 4); + + assertEquals("Wrong syntax for command", + "-break-insert -i 1 -p 4 /test/this/path:14\n", target + .constructCommand()); + } + + private class TestContext implements IBreakpointsTargetDMContext { + + public IDMContext[] getParents() { + return null; + } + + public String getSessionId() { + return null; + } + + public Object getAdapter(Class adapter) { + return null; + } + } + +} diff --git a/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMICommandConstructCommand.java b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMICommandConstructCommand.java new file mode 100644 index 00000000000..fde6ae28562 --- /dev/null +++ b/plugins/org.eclipse.dd.tests.gdb/src/org/eclipse/dd/mi/service/command/commands/TestMICommandConstructCommand.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2008 Ericsson 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: + * Ericsson - Initial Implementation + *******************************************************************************/ +package org.eclipse.dd.mi.service.command.commands; + +import static org.junit.Assert.assertEquals; + +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.mi.service.command.output.MIInfo; +import org.junit.Test; + +/** + * Test verifying that the construct command method handles separators and + * escaping correctly + * + * @author qtobsod + * + */ +public class TestMICommandConstructCommand { + + @Test + public void multipleParametersShouldHaveCorrectSeparators() { + // Setup + MICommand target = new MICommand(new TestContext(), + "-test-operation"); + target.setOptions(new String[] { "-a a_test\\with slashes", + "-b \"hello\"", "-c c_test" }); + target.setParameters(new String[] { "-param1 param", "param2", + "-param3" }); + + // Act + String result = target.constructCommand(); + + // Assert + assertEquals( + "Wrong syntax for command", + "-test-operation \"-a a_test\\\\with slashes\" \"-b \\\"hello\\\"\" \"-c c_test\" -- \"-param1 param\" param2 -param3\n", + result); + } + + private class TestContext implements IDMContext { + + public IDMContext[] getParents() { + return null; + } + + public String getSessionId() { + return null; + } + + public Object getAdapter(Class adapter) { + return null; + } + + } + +}