1 package net.sourceforge.phpdt.externaltools.model;
 
   3 /**********************************************************************
 
   4 Copyright (c) 2002 IBM Corp. and others. All rights reserved.
 
   5 This file is made available under the terms of the Common Public License v1.0
 
   6 which accompanies this distribution, and is available at
 
   7 http://www.eclipse.org/legal/cpl-v10.html
 
  10 **********************************************************************/
 
  12 import java.util.ArrayList;
 
  14 import net.sourceforge.phpdt.externaltools.internal.model.ExternalToolsPlugin;
 
  15 import net.sourceforge.phpdt.externaltools.internal.model.ToolMessages;
 
  16 import net.sourceforge.phpdt.externaltools.internal.registry.ArgumentVariable;
 
  17 import net.sourceforge.phpdt.externaltools.internal.registry.ArgumentVariableRegistry;
 
  18 import net.sourceforge.phpdt.externaltools.internal.registry.PathLocationVariable;
 
  19 import net.sourceforge.phpdt.externaltools.internal.registry.PathLocationVariableRegistry;
 
  20 import net.sourceforge.phpdt.externaltools.variable.ExpandVariableContext;
 
  22 import org.eclipse.core.runtime.IPath;
 
  23 import org.eclipse.core.runtime.MultiStatus;
 
  26  * General utility class dealing with external tools
 
  28 public final class ToolUtil {
 
  30          * Argument parsing constants
 
  32         private static final char ARG_DELIMITER = ' '; //$NON-NLS-1$
 
  33         private static final char ARG_DBL_QUOTE = '"'; //$NON-NLS-1$
 
  36          * Variable tag indentifiers
 
  38         private static final char VAR_TAG_START_CHAR1 = '$'; //$NON-NLS-1$
 
  39         private static final char VAR_TAG_START_CHAR2 = '{'; //$NON-NLS-1$
 
  40         private static final char VAR_TAG_END_CHAR1 = '}'; //$NON-NLS-1$
 
  41         private static final String VAR_TAG_START = "${"; //$NON-NLS-1$
 
  42         private static final String VAR_TAG_END = "}"; //$NON-NLS-1$
 
  43         private static final String VAR_TAG_SEP = ":"; //$NON-NLS-1$
 
  46          * No instances allowed
 
  53          * Builds a variable tag that will be auto-expanded before
 
  56          * @param varName the name of a known variable (one of the VAR_* constants for instance)
 
  57          * @param varArgument an optional argument for the variable, <code>null</code> if none
 
  59         public static String buildVariableTag(String varName, String varArgument) {
 
  60                 StringBuffer buf = new StringBuffer();
 
  61                 buildVariableTag(varName,varArgument, buf);
 
  62                 return buf.toString();
 
  66          * Builds a variable tag that will be auto-expanded before
 
  69          * @param varName the name of a known variable (one of the VAR_* constants for instance)
 
  70          * @param varArgument an optional argument for the variable, <code>null</code> if none
 
  71          * @param buffer the buffer to write the constructed variable tag
 
  73         public static void buildVariableTag(String varName, String varArgument, StringBuffer buffer) {
 
  74                 buffer.append(VAR_TAG_START);
 
  75                 buffer.append(varName);
 
  76                 if (varArgument != null && varArgument.length() > 0) {
 
  77                         buffer.append(VAR_TAG_SEP);
 
  78                         buffer.append(varArgument);
 
  80                 buffer.append(VAR_TAG_END);
 
  84          * Expands all the variables found in an individual
 
  87          * @param argument one of the argument text in the list of arguments
 
  88          * @param context the context to use for expanding variables
 
  89          * @param status multi status to report any problems expanding variables
 
  90          * @return the argument text with all variables expanded, or <code>null</code> if not possible
 
  92         public static String expandArgument(String argument, ExpandVariableContext context, MultiStatus status) {
 
  93                 StringBuffer buffer = new StringBuffer();
 
  97                         VariableDefinition varDef = extractVariableTag(argument, start);
 
  99                         // No more variables found...
 
 100                         if (varDef.start == -1) {
 
 102                                         buffer.append(argument);
 
 104                                         buffer.append(argument.substring(start));
 
 108                         // Invalid variable format
 
 109                         if (varDef.end == -1 || varDef.name == null || varDef.name.length() == 0) {
 
 110                                 String msg = ToolMessages.getString("ToolUtil.argumentVarFormatWrong"); //$NON-NLS-1$
 
 111                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 115                         // Copy text between start and variable.                        
 
 116                         if (varDef.start > start)
 
 117                                 buffer.append(argument.substring(start, varDef.start));
 
 120                         // Lookup the variable if it exist
 
 121                         ArgumentVariableRegistry registry;
 
 122                         registry = ExternalToolsPlugin.getDefault().getArgumentVariableRegistry();
 
 123                         ArgumentVariable variable = registry.getArgumentVariable(varDef.name);
 
 124                         if (variable == null) {
 
 125                                 String msg = ToolMessages.format("ToolUtil.argumentVarMissing", new Object[] {varDef.name}); //$NON-NLS-1$
 
 126                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 130                         // Expand the variable as text if possible
 
 131                         String text = variable.getExpander().getText(varDef.name, varDef.argument, context);
 
 133                                 String msg = ToolMessages.format("ToolUtil.argumentVarExpandFailed", new Object[] {varDef.name}); //$NON-NLS-1$
 
 134                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 140                 return buffer.toString();
 
 144          * Returns a list of individual arguments where all
 
 145          * variables have been expanded.
 
 147          * @param arguments the arguments with leading and trailing
 
 148          *              spaces already removed.
 
 149          * @param context the context used to expand the variable(s)
 
 150          * @param status multi status to report any problems expanding variables
 
 151          * @return the list of individual arguments where some elements in the
 
 152          *              list maybe <code>null</code> if problems expanding variable(s).
 
 154         public static String[] expandArguments(String arguments, ExpandVariableContext context, MultiStatus status) {
 
 155                 if (arguments == null || arguments.length() == 0)
 
 156                         return new String[0];
 
 158                 String[] argList = parseArgumentsIntoList(arguments);
 
 159                 for (int i = 0; i < argList.length; i++)
 
 160                         argList[i] = expandArgument(argList[i], context, status);
 
 166          * Returns the expanded directory location if represented by a
 
 167          * directory variable. Otherwise, the directory location given is
 
 168          * return unless an unknown variable was detected.
 
 170          * @param dirLocation a directory location either as a path or a variable
 
 171          *              with leading and trailing spaces already removed.
 
 172          * @param context the context used to expand the variable
 
 173          * @param status multi status to report any problems expanding variables
 
 174          * @return the directory location as a string or <code>null</code> if not possible
 
 176         public static String expandDirectoryLocation(String dirLocation, ExpandVariableContext context, MultiStatus status) {
 
 177                 if (dirLocation == null || dirLocation.length() == 0)
 
 178                         return ""; //$NON-NLS-1$
 
 180                 VariableDefinition varDef = extractVariableTag(dirLocation, 0);
 
 181                 // Return if no variable found
 
 182                 if (varDef.start < 0)
 
 185                 // Disallow text before/after variable
 
 186                 if (varDef.start != 0 || (varDef.end < dirLocation.length() && varDef.end != -1)) {
 
 187                         String msg = ToolMessages.getString("ToolUtil.dirLocVarBetweenText"); //$NON-NLS-1$
 
 188                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 192                 // Invalid variable format
 
 193                 if (varDef.name == null || varDef.name.length() == 0 || varDef.end == -1) {
 
 194                         String msg = ToolMessages.getString("ToolUtil.dirLocVarFormatWrong"); //$NON-NLS-1$
 
 195                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 199                 // Lookup the variable if it exist
 
 200                 PathLocationVariableRegistry registry;
 
 201                 registry = ExternalToolsPlugin.getDefault().getDirectoryLocationVariableRegistry();
 
 202                 PathLocationVariable variable = registry.getPathLocationVariable(varDef.name);
 
 203                 if (variable == null) {
 
 204                         String msg = ToolMessages.format("ToolUtil.dirLocVarMissing", new Object[] {varDef.name}); //$NON-NLS-1$
 
 205                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 209                 // Expand the variable into a IPath if possible
 
 210                 IPath path = variable.getExpander().getPath(varDef.name, varDef.argument, context);
 
 212                         String msg = ToolMessages.format("ToolUtil.dirLocVarExpandFailed", new Object[] {varDef.name}); //$NON-NLS-1$
 
 213                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 217                 return path.toOSString();
 
 221          * Returns the expanded file location if represented by a
 
 222          * file variable. Otherwise, the file location given is
 
 223          * return unless an unknown variable was detected.
 
 225          * @param fileLocation a file location either as a path or a variable
 
 226          *              with leading and trailing spaces already removed.
 
 227          * @param context the context used to expand the variable
 
 228          * @param status multi status to report any problems expanding variables
 
 229          * @return the file location as a string or <code>null</code> if not possible
 
 231         public static String expandFileLocation(String fileLocation, ExpandVariableContext context, MultiStatus status) {
 
 232                 if (fileLocation == null || fileLocation.length() == 0)
 
 233                         return ""; //$NON-NLS-1$
 
 235                 VariableDefinition varDef = extractVariableTag(fileLocation, 0);
 
 236                 // Return if no variable found
 
 237                 if (varDef.start < 0)
 
 240                 // Disallow text before/after variable
 
 241                 if (varDef.start != 0 || (varDef.end < fileLocation.length() && varDef.end != -1)) {
 
 242                         String msg = ToolMessages.getString("ToolUtil.fileLocVarBetweenText"); //$NON-NLS-1$
 
 243                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 247                 // Invalid variable format
 
 248                 if (varDef.name == null || varDef.name.length() == 0 || varDef.end == -1) {
 
 249                         String msg = ToolMessages.getString("ToolUtil.fileLocVarFormatWrong"); //$NON-NLS-1$
 
 250                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 254                 // Lookup the variable if it exist
 
 255                 PathLocationVariableRegistry registry;
 
 256                 registry = ExternalToolsPlugin.getDefault().getFileLocationVariableRegistry();
 
 257                 PathLocationVariable variable = registry.getPathLocationVariable(varDef.name);
 
 258                 if (variable == null) {
 
 259                         String msg = ToolMessages.format("ToolUtil.fileLocVarMissing", new Object[] {varDef.name}); //$NON-NLS-1$
 
 260                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 264                 // Expand the variable into a IPath if possible
 
 265                 IPath path = variable.getExpander().getPath(varDef.name, varDef.argument, context);
 
 267                         String msg = ToolMessages.format("The variable {0} with argument {1} could not be expanded to a valid path.", new Object[] {varDef.name, varDef.argument});
 
 268                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 272                 return path.toString();
 
 276          * Extracts from the source text the variable tag's name
 
 279          * @param text the source text to parse for a variable tag
 
 280          * @param start the index in the string to start the search
 
 281          * @return the variable definition
 
 283         public static VariableDefinition extractVariableTag(String text, int start) {
 
 284                 VariableDefinition varDef = new VariableDefinition();
 
 286                 varDef.start = text.indexOf(VAR_TAG_START, start);
 
 287                 if (varDef.start < 0)
 
 289                 start = varDef.start + VAR_TAG_START.length();
 
 291                 int end = text.indexOf(VAR_TAG_END, start);
 
 294                 varDef.end = end + VAR_TAG_END.length();
 
 298                 int mid = text.indexOf(VAR_TAG_SEP, start);
 
 299                 if (mid < 0 || mid > end) {
 
 300                         varDef.name = text.substring(start, end);
 
 303                                 varDef.name = text.substring(start, mid);
 
 304                         mid = mid + VAR_TAG_SEP.length();
 
 306                                 varDef.argument = text.substring(mid, end);
 
 313          * Parses the argument text into an array of individual
 
 314          * arguments using the space character as the delimiter.
 
 315          * An individual argument containing spaces must have a
 
 316          * double quote (") at the start and end. Two double 
 
 317          * quotes together is taken to mean an embedded double
 
 318          * quote in the argument text. Variables are treated as
 
 319          * a single unit and therefore spaces and double quotes
 
 320          * inside a variable are copied as is and not parsed.
 
 322          * @param arguments the arguments as one string
 
 323          * @return the array of arguments
 
 325         public static String[] parseArgumentsIntoList(String arguments) {
 
 326                 if (arguments == null || arguments.length() == 0)
 
 327                         return new String[0];
 
 329                 ArrayList list = new ArrayList(10);
 
 330                 boolean inQuotes = false;
 
 331                 boolean inVar = false;
 
 333                 int end = arguments.length();
 
 334                 StringBuffer buffer = new StringBuffer(end);
 
 336                 while (start < end) {
 
 337                         char ch = arguments.charAt(start);
 
 342                                         if (inQuotes || inVar) {
 
 345                                                 if (buffer.length() > 0) {
 
 346                                                         list.add(buffer.toString());
 
 357                                                         if (arguments.charAt(start) == ARG_DBL_QUOTE) {
 
 358                                                                 // Two quotes together represents one quote
 
 362                                                                 inQuotes = !inQuotes;
 
 365                                                         // A lone quote at the end, just drop it.
 
 371                                 case VAR_TAG_START_CHAR1 :
 
 373                                         if (!inVar && start < end) {
 
 374                                                 if (arguments.charAt(start) == VAR_TAG_START_CHAR2) {
 
 375                                                         buffer.append(VAR_TAG_START_CHAR2);
 
 382                                 case VAR_TAG_END_CHAR1 :
 
 394                 if (buffer.length() > 0)
 
 395                         list.add(buffer.toString());
 
 397                 String[] results = new String[list.size()];
 
 398                 list.toArray(results);
 
 404          * Structure to represent a variable definition within a
 
 407         public static final class VariableDefinition {
 
 409                  * Index in the source text where the variable started
 
 410                  * or <code>-1</code> if no valid variable start tag 
 
 413                 public int start = -1;
 
 416                  * Index in the source text of the character following
 
 417                  * the end of the variable or <code>-1</code> if no 
 
 418                  * valid variable end tag found.
 
 423                  * The variable's name found in the source text, or
 
 424                  * <code>null</code> if no valid variable found.
 
 426                 public String name = null;
 
 429                  * The variable's argument found in the source text, or
 
 430                  * <code>null</code> if no valid variable found or if
 
 431                  * the variable did not specify an argument
 
 433                 public String argument = null;
 
 436                  * Create an initialized variable definition.
 
 438                 private VariableDefinition() {
 
 443                  * Create an initialized variable definition.
 
 445                 private VariableDefinition(int start, int end) {