blob: d9990a398676a208cdef47846dcbfee8e160763b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* Tomasz Stanczak - Fix for Bug 29504
*******************************************************************************/
package org.eclipse.ui.externaltools.internal.model;
import java.text.MessageFormat;
import java.util.ArrayList;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.ui.externaltools.internal.registry.ExternalToolVariable;
import org.eclipse.ui.externaltools.internal.registry.ExternalToolVariableRegistry;
import org.eclipse.ui.externaltools.internal.variable.ExpandVariableContext;
/**
* General utility class dealing with external tools
*/
public final class ToolUtil {
/**
* Argument parsing constants
*/
private static final char ARG_DELIMITER = ' '; //$NON-NLS-1$
private static final char ARG_DBL_QUOTE = '"'; //$NON-NLS-1$
/**
* Variable tag indentifiers
*/
private static final char VAR_TAG_START_CHAR1 = '$'; //$NON-NLS-1$
private static final char VAR_TAG_START_CHAR2 = '{'; //$NON-NLS-1$
private static final char VAR_TAG_END_CHAR1 = '}'; //$NON-NLS-1$
private static final String VAR_TAG_START = "${"; //$NON-NLS-1$
private static final String VAR_TAG_END = "}"; //$NON-NLS-1$
private static final String VAR_TAG_SEP = ":"; //$NON-NLS-1$
/**
* No instances allowed
*/
private ToolUtil() {
super();
}
/**
* Builds a variable tag that will be auto-expanded before
* the tool is run.
*
* @param varName the name of a known variable (one of the VAR_* constants for instance)
* @param varArgument an optional argument for the variable, <code>null</code> if none
*/
public static String buildVariableTag(String varName, String varArgument) {
StringBuffer buf = new StringBuffer();
buildVariableTag(varName,varArgument, buf);
return buf.toString();
}
/**
* Builds a variable tag that will be auto-expanded before
* the tool is run.
*
* @param varName the name of a known variable (one of the VAR_* constants for instance)
* @param varArgument an optional argument for the variable, <code>null</code> if none
* @param buffer the buffer to write the constructed variable tag
*/
public static void buildVariableTag(String varName, String varArgument, StringBuffer buffer) {
buffer.append(VAR_TAG_START);
buffer.append(varName);
if (varArgument != null && varArgument.length() > 0) {
buffer.append(VAR_TAG_SEP);
buffer.append(varArgument);
}
buffer.append(VAR_TAG_END);
}
/**
* Expands all the variables found in an individual
* argument text.
*
* @param argument one of the argument text in the list of arguments
* @param context the context to use for expanding variables
* @param status multi status to report any problems expanding variables
* @return the argument text with all variables expanded, or <code>null</code> if not possible
*/
public static String expandArgument(String argument, ExpandVariableContext context, MultiStatus status) {
StringBuffer buffer = new StringBuffer();
int start = 0;
while (true) {
VariableDefinition varDef = extractVariableTag(argument, start);
// No more variables found...
if (varDef.start == -1) {
if (start == 0)
buffer.append(argument);
else
buffer.append(argument.substring(start));
break;
}
// Invalid variable format
if (varDef.end == -1 || varDef.name == null || varDef.name.length() == 0) {
String msg = ExternalToolsModelMessages.getString("ToolUtil.argumentVarFormatWrong"); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Copy text between start and variable.
if (varDef.start > start)
buffer.append(argument.substring(start, varDef.start));
start = varDef.end;
// Lookup the variable if it exist
ExternalToolVariableRegistry registry;
registry = ExternalToolsPlugin.getDefault().getToolVariableRegistry();
ExternalToolVariable variable = registry.getVariable(varDef.name);
if (variable == null) {
String msg = MessageFormat.format(ExternalToolsModelMessages.getString("ToolUtil.argumentVarMissing"), new Object[] {varDef.name}); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Expand the variable as text if possible
String text = null;
try {
text= variable.getExpander().getText(varDef.name, varDef.argument, context);
} catch (CoreException exception) {
status.merge(exception.getStatus());
return null;
}
buffer.append(text);
}
return buffer.toString();
}
/**
* Returns a list of individual arguments where all
* variables have been expanded.
*
* @param arguments the arguments with leading and trailing
* spaces already removed.
* @param context the context used to expand the variable(s)
* @param status multi status to report any problems expanding variables
* @return the list of individual arguments where some elements in the
* list maybe <code>null</code> if problems expanding variable(s).
*/
public static String[] expandArguments(String arguments, ExpandVariableContext context, MultiStatus status) {
if (arguments == null || arguments.length() == 0)
return new String[0];
String[] argList = parseArgumentsIntoList(arguments);
for (int i = 0; i < argList.length; i++)
argList[i] = expandArgument(argList[i], context, status);
return argList;
}
/**
* Returns the expanded directory location if represented by a
* directory variable. Otherwise, the directory location given is
* return unless an unknown variable was detected.
*
* @param dirLocation a directory location either as a path or a variable
* with leading and trailing spaces already removed.
* @param context the context used to expand the variable
* @param status multi status to report any problems expanding variables
* @return the directory location as a string or <code>null</code> if not possible
*/
public static String expandDirectoryLocation(String dirLocation, ExpandVariableContext context, MultiStatus status) {
if (dirLocation == null || dirLocation.length() == 0)
return ""; //$NON-NLS-1$
VariableDefinition varDef = extractVariableTag(dirLocation, 0);
// Return if no variable found
if (varDef.start < 0) {
return dirLocation;
}
StringBuffer buffer= new StringBuffer();
int start= 0;
while (varDef.start >= 0) {
// Invalid variable format
if (varDef.name == null || varDef.name.length() == 0 || varDef.end == -1) {
String msg = ExternalToolsModelMessages.getString("ToolUtil.dirLocVarFormatWrong"); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Append text before the variable
buffer.append(dirLocation.substring(start, varDef.start));
// Lookup the variable if it exist
ExternalToolVariableRegistry registry;
registry = ExternalToolsPlugin.getDefault().getToolVariableRegistry();
ExternalToolVariable variable = registry.getVariable(varDef.name);
if (variable == null) {
String msg = MessageFormat.format(ExternalToolsModelMessages.getString("ToolUtil.dirLocVarMissing"), new Object[] {varDef.name}); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Expand the variable into a IPath if possible
IPath path= null;
try {
path= variable.getExpander().getPath(varDef.name, varDef.argument, context);
} catch (CoreException exception) {
status.merge(exception.getStatus());
return null;
}
buffer.append(path.toOSString());
start= varDef.end;
varDef= extractVariableTag(dirLocation, start);
}
// Append text remaining after the variables
buffer.append(dirLocation.substring(start));
return buffer.toString();
}
/**
* Returns the expanded file location if represented by a
* file variable. Otherwise, the file location given is
* return unless an unknown variable was detected.
*
* @param fileLocation a file location either as a path or a variable
* with leading and trailing spaces already removed.
* @param context the context used to expand the variable
* @param status multi status to report any problems expanding variables
* @return the file location as a string or <code>null</code> if not possible
*/
public static String expandFileLocation(String fileLocation, ExpandVariableContext context, MultiStatus status) {
if (fileLocation == null || fileLocation.length() == 0)
return ""; //$NON-NLS-1$
VariableDefinition varDef = extractVariableTag(fileLocation, 0);
// Return if no variable found
if (varDef.start < 0) {
return fileLocation;
}
StringBuffer buffer= new StringBuffer();
int start= 0;
while (varDef.start >= 0) {
// Invalid variable format
if (varDef.name == null || varDef.name.length() == 0 || varDef.end == -1) {
String msg = ExternalToolsModelMessages.getString("ToolUtil.fileLocVarFormatWrong"); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Append text before the variable
buffer.append(fileLocation.substring(start, varDef.start));
// Lookup the variable if it exist
ExternalToolVariableRegistry registry;
registry = ExternalToolsPlugin.getDefault().getToolVariableRegistry();
ExternalToolVariable variable = registry.getVariable(varDef.name);
if (variable == null) {
String msg = MessageFormat.format(ExternalToolsModelMessages.getString("ToolUtil.fileLocVarMissing"), new Object[] {varDef.name}); //$NON-NLS-1$
status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
return null;
}
// Expand the variable into a IPath if possible
IPath path = null;
try {
path= variable.getExpander().getPath(varDef.name, varDef.argument, context);
} catch (CoreException exception) {
status.merge(exception.getStatus());
return null;
}
buffer.append(path.toOSString());
start= varDef.end;
varDef= extractVariableTag(fileLocation, start);
}
// Append text remaining after the variables
buffer.append(fileLocation.substring(start));
return buffer.toString();
}
/**
* Extracts from the source text the variable tag's name
* and argument.
*
* @param text the source text to parse for a variable tag
* @param start the index in the string to start the search
* @return the variable definition
*/
public static VariableDefinition extractVariableTag(String text, int start) {
VariableDefinition varDef = new VariableDefinition();
varDef.start = text.indexOf(VAR_TAG_START, start);
if (varDef.start < 0)
return varDef;
start = varDef.start + VAR_TAG_START.length();
int end = text.indexOf(VAR_TAG_END, start);
if (end < 0)
return varDef;
varDef.end = end + VAR_TAG_END.length();
if (end == start)
return varDef;
int mid = text.indexOf(VAR_TAG_SEP, start);
if (mid < 0 || mid > end) {
varDef.name = text.substring(start, end);
} else {
if (mid > start)
varDef.name = text.substring(start, mid);
mid = mid + VAR_TAG_SEP.length();
if (mid < end)
varDef.argument = text.substring(mid, end);
}
return varDef;
}
/**
* Parses the argument text into an array of individual
* arguments using the space character as the delimiter.
* An individual argument containing spaces must have a
* double quote (") at the start and end. Two double
* quotes together is taken to mean an embedded double
* quote in the argument text. Variables are treated as
* a single unit and therefore spaces and double quotes
* inside a variable are copied as is and not parsed.
*
* @param arguments the arguments as one string
* @return the array of arguments
*/
public static String[] parseArgumentsIntoList(String arguments) {
if (arguments == null || arguments.length() == 0)
return new String[0];
ArrayList list = new ArrayList(10);
boolean inQuotes = false;
boolean inVar = false;
int start = 0;
int end = arguments.length();
StringBuffer buffer = new StringBuffer(end);
while (start < end) {
char ch = arguments.charAt(start);
start++;
switch (ch) {
case ARG_DELIMITER :
if (inQuotes || inVar) {
buffer.append(ch);
} else {
if (buffer.length() > 0) {
list.add(buffer.toString());
buffer.setLength(0);
}
}
break;
case ARG_DBL_QUOTE :
if (inVar) {
buffer.append(ch);
} else {
if (start < end) {
if (arguments.charAt(start) == ARG_DBL_QUOTE) {
// Two quotes together represents one quote
buffer.append(ch);
start++;
} else {
inQuotes = !inQuotes;
}
} else {
// A lone quote at the end, just drop it.
inQuotes = false;
}
}
break;
case VAR_TAG_START_CHAR1 :
buffer.append(ch);
if (!inVar && start < end) {
if (arguments.charAt(start) == VAR_TAG_START_CHAR2) {
buffer.append(VAR_TAG_START_CHAR2);
inVar = true;
start++;
}
}
break;
case VAR_TAG_END_CHAR1 :
buffer.append(ch);
inVar = false;
break;
default :
buffer.append(ch);
break;
}
}
if (buffer.length() > 0)
list.add(buffer.toString());
String[] results = new String[list.size()];
list.toArray(results);
return results;
}
/**
* Structure to represent a variable definition within a
* source string.
*/
public static final class VariableDefinition {
/**
* Index in the source text where the variable started
* or <code>-1</code> if no valid variable start tag
* identifier found.
*/
public int start = -1;
/**
* Index in the source text of the character following
* the end of the variable or <code>-1</code> if no
* valid variable end tag found.
*/
public int end = -1;
/**
* The variable's name found in the source text, or
* <code>null</code> if no valid variable found.
*/
public String name = null;
/**
* The variable's argument found in the source text, or
* <code>null</code> if no valid variable found or if
* the variable did not specify an argument
*/
public String argument = null;
/**
* Create an initialized variable definition.
*/
private VariableDefinition() {
super();
}
}
}