1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-01 06:05:24 +02:00

[219920] Added mechanism for adjusting command parameter formatting.

This commit is contained in:
Pawel Piech 2008-02-28 16:08:09 +00:00
parent 822accd4bb
commit 07647b57a3
6 changed files with 360 additions and 78 deletions

View file

@ -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();
}

View file

@ -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<MIBreakInsertInfo>
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$
}
}
}

View file

@ -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<V extends MIInfo> implements ICommand<V> {
*/
final static String[] empty = new String[0];
String[] fOptions = empty;
String[] fParameters = empty;
List<Adjustable> fOptions = new ArrayList<Adjustable>();
List<Adjustable> fParameters = new ArrayList<Adjustable>();
String fOperation = new String();
IDMContext fCtx;
@ -60,10 +64,30 @@ public class MICommand<V extends MIInfo> implements ICommand<V> {
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<Adjustable> optionsToAdjustables(String[] options) {
List<Adjustable> result = new ArrayList<Adjustable>();
if (options != null) {
for (String option : options) {
result.add(new MIStandardOptionAdjustable(option));
}
}
return result;
}
private final List<Adjustable> parametersToAdjustables(String[] parameters) {
List<Adjustable> result = new ArrayList<Adjustable>();
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<V extends MIInfo> implements ICommand<V> {
* returned if there are no options.
*/
public String[] getOptions() {
return fOptions;
List<String> result = new ArrayList<String>();
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<V extends MIInfo> implements ICommand<V> {
* returned if there are no parameters.
*/
public String[] getParameters() {
return fParameters;
List<String> result = new ArrayList<String>();
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<V extends MIInfo> implements ICommand<V> {
}
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<V extends MIInfo> implements ICommand<V> {
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;
}
}
}

View file

@ -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 {}

View file

@ -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;
}
}
}

View file

@ -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<MIInfo> target = new MICommand<MIInfo>(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;
}
}
}