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.ExternalToolsModelMessages;
 
  15 import net.sourceforge.phpdt.externaltools.internal.registry.ArgumentVariable;
 
  16 import net.sourceforge.phpdt.externaltools.internal.registry.ArgumentVariableRegistry;
 
  17 import net.sourceforge.phpdt.externaltools.internal.registry.PathLocationVariable;
 
  18 import net.sourceforge.phpdt.externaltools.internal.registry.PathLocationVariableRegistry;
 
  19 import net.sourceforge.phpdt.externaltools.variable.ExpandVariableContext;
 
  20 import net.sourceforge.phpeclipse.externaltools.ExternalToolsPlugin;
 
  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$
 
  34         private static final char ARG_DBL_QUOTE = '"'; //$NON-NLS-1$
 
  37          * Variable tag indentifiers
 
  39         private static final char VAR_TAG_START_CHAR1 = '$'; //$NON-NLS-1$
 
  41         private static final char VAR_TAG_START_CHAR2 = '{'; //$NON-NLS-1$
 
  43         private static final char VAR_TAG_END_CHAR1 = '}'; //$NON-NLS-1$
 
  45         private static final String VAR_TAG_START = "${"; //$NON-NLS-1$
 
  47         private static final String VAR_TAG_END = "}"; //$NON-NLS-1$
 
  49         private static final String VAR_TAG_SEP = ":"; //$NON-NLS-1$
 
  52          * No instances allowed
 
  59          * Builds a variable tag that will be auto-expanded before the tool is run.
 
  62          *            the name of a known variable (one of the VAR_* constants for
 
  65          *            an optional argument for the variable, <code>null</code> if
 
  68         public static String buildVariableTag(String varName, String varArgument) {
 
  69                 StringBuffer buf = new StringBuffer();
 
  70                 buildVariableTag(varName, varArgument, buf);
 
  71                 return buf.toString();
 
  75          * Builds a variable tag that will be auto-expanded before the tool is run.
 
  78          *            the name of a known variable (one of the VAR_* constants for
 
  81          *            an optional argument for the variable, <code>null</code> if
 
  84          *            the buffer to write the constructed variable tag
 
  86         public static void buildVariableTag(String varName, String varArgument,
 
  87                         StringBuffer buffer) {
 
  88                 buffer.append(VAR_TAG_START);
 
  89                 buffer.append(varName);
 
  90                 if (varArgument != null && varArgument.length() > 0) {
 
  91                         buffer.append(VAR_TAG_SEP);
 
  92                         buffer.append(varArgument);
 
  94                 buffer.append(VAR_TAG_END);
 
  98          * Expands all the variables found in an individual argument text.
 
 101          *            one of the argument text in the list of arguments
 
 103          *            the context to use for expanding variables
 
 105          *            multi status to report any problems expanding variables
 
 106          * @return the argument text with all variables expanded, or
 
 107          *         <code>null</code> if not possible
 
 109         public static String expandArgument(String argument,
 
 110                         ExpandVariableContext context, MultiStatus status) {
 
 111                 StringBuffer buffer = new StringBuffer();
 
 115                         VariableDefinition varDef = extractVariableTag(argument, start);
 
 117                         // No more variables found...
 
 118                         if (varDef.start == -1) {
 
 120                                         buffer.append(argument);
 
 122                                         buffer.append(argument.substring(start));
 
 126                         // Invalid variable format
 
 127                         if (varDef.end == -1 || varDef.name == null
 
 128                                         || varDef.name.length() == 0) {
 
 129                                 String msg = ExternalToolsModelMessages
 
 130                                                 .getString("ToolUtil.argumentVarFormatWrong"); //$NON-NLS-1$
 
 131                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 135                         // Copy text between start and variable.
 
 136                         if (varDef.start > start)
 
 137                                 buffer.append(argument.substring(start, varDef.start));
 
 140                         // Lookup the variable if it exist
 
 141                         ArgumentVariableRegistry registry;
 
 142                         registry = ExternalToolsPlugin.getDefault()
 
 143                                         .getArgumentVariableRegistry();
 
 144                         ArgumentVariable variable = registry
 
 145                                         .getArgumentVariable(varDef.name);
 
 146                         if (variable == null) {
 
 147                                 String msg = ExternalToolsModelMessages
 
 149                                                                 "ToolUtil.argumentVarMissing", new Object[] { varDef.name }); //$NON-NLS-1$
 
 150                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 154                         // Expand the variable as text if possible
 
 155                         String text = variable.getExpander().getText(varDef.name,
 
 156                                         varDef.argument, context);
 
 158                                 String msg = ExternalToolsModelMessages
 
 160                                                                 "ToolUtil.argumentVarExpandFailed", new Object[] { varDef.name }); //$NON-NLS-1$
 
 161                                 status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 167                 return buffer.toString();
 
 171          * Returns a list of individual arguments where all variables have been
 
 175          *            the arguments with leading and trailing spaces already
 
 178          *            the context used to expand the variable(s)
 
 180          *            multi status to report any problems expanding variables
 
 181          * @return the list of individual arguments where some elements in the list
 
 182          *         maybe <code>null</code> if problems expanding variable(s).
 
 184         public static String[] expandArguments(String arguments,
 
 185                         ExpandVariableContext context, MultiStatus status) {
 
 186                 if (arguments == null || arguments.length() == 0)
 
 187                         return new String[0];
 
 189                 String[] argList = parseArgumentsIntoList(arguments);
 
 190                 for (int i = 0; i < argList.length; i++)
 
 191                         argList[i] = expandArgument(argList[i], context, status);
 
 197          * Returns the expanded directory location if represented by a directory
 
 198          * variable. Otherwise, the directory location given is return unless an
 
 199          * unknown variable was detected.
 
 202          *            a directory location either as a path or a variable with
 
 203          *            leading and trailing spaces already removed.
 
 205          *            the context used to expand the variable
 
 207          *            multi status to report any problems expanding variables
 
 208          * @return the directory location as a string or <code>null</code> if not
 
 211         public static String expandDirectoryLocation(String dirLocation,
 
 212                         ExpandVariableContext context, MultiStatus status) {
 
 213                 if (dirLocation == null || dirLocation.length() == 0)
 
 214                         return ""; //$NON-NLS-1$
 
 216                 VariableDefinition varDef = extractVariableTag(dirLocation, 0);
 
 217                 // Return if no variable found
 
 218                 if (varDef.start < 0)
 
 221                 // Disallow text before/after variable
 
 222                 if (varDef.start != 0
 
 223                                 || (varDef.end < dirLocation.length() && varDef.end != -1)) {
 
 224                         String msg = ExternalToolsModelMessages
 
 225                                         .getString("ToolUtil.dirLocVarBetweenText"); //$NON-NLS-1$
 
 226                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 230                 // Invalid variable format
 
 231                 if (varDef.name == null || varDef.name.length() == 0
 
 232                                 || varDef.end == -1) {
 
 233                         String msg = ExternalToolsModelMessages
 
 234                                         .getString("ToolUtil.dirLocVarFormatWrong"); //$NON-NLS-1$
 
 235                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 239                 // Lookup the variable if it exist
 
 240                 PathLocationVariableRegistry registry;
 
 241                 registry = ExternalToolsPlugin.getDefault()
 
 242                                 .getDirectoryLocationVariableRegistry();
 
 243                 PathLocationVariable variable = registry
 
 244                                 .getPathLocationVariable(varDef.name);
 
 245                 if (variable == null) {
 
 246                         String msg = ExternalToolsModelMessages.format(
 
 247                                         "ToolUtil.dirLocVarMissing", new Object[] { varDef.name }); //$NON-NLS-1$
 
 248                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 252                 // Expand the variable into a IPath if possible
 
 253                 IPath path = variable.getExpander().getPath(varDef.name,
 
 254                                 varDef.argument, context);
 
 256                         String msg = ExternalToolsModelMessages
 
 258                                                         "ToolUtil.dirLocVarExpandFailed", new Object[] { varDef.name }); //$NON-NLS-1$
 
 259                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 263                 return path.toOSString();
 
 267          * Returns the expanded file location if represented by a file variable.
 
 268          * Otherwise, the file location given is return unless an unknown variable
 
 271          * @param fileLocation
 
 272          *            a file location either as a path or a variable with leading
 
 273          *            and trailing spaces already removed.
 
 275          *            the context used to expand the variable
 
 277          *            multi status to report any problems expanding variables
 
 278          * @return the file location as a string or <code>null</code> if not
 
 281         public static String expandFileLocation(String fileLocation,
 
 282                         ExpandVariableContext context, MultiStatus status) {
 
 283                 if (fileLocation == null || fileLocation.length() == 0)
 
 284                         return ""; //$NON-NLS-1$
 
 286                 VariableDefinition varDef = extractVariableTag(fileLocation, 0);
 
 287                 // Return if no variable found
 
 288                 if (varDef.start < 0)
 
 291                 // Disallow text before/after variable
 
 292                 if (varDef.start != 0
 
 293                                 || (varDef.end < fileLocation.length() && varDef.end != -1)) {
 
 294                         String msg = ExternalToolsModelMessages
 
 295                                         .getString("ToolUtil.fileLocVarBetweenText"); //$NON-NLS-1$
 
 296                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 300                 // Invalid variable format
 
 301                 if (varDef.name == null || varDef.name.length() == 0
 
 302                                 || varDef.end == -1) {
 
 303                         String msg = ExternalToolsModelMessages
 
 304                                         .getString("ToolUtil.fileLocVarFormatWrong"); //$NON-NLS-1$
 
 305                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 309                 // Lookup the variable if it exist
 
 310                 PathLocationVariableRegistry registry;
 
 311                 registry = ExternalToolsPlugin.getDefault()
 
 312                                 .getFileLocationVariableRegistry();
 
 313                 PathLocationVariable variable = registry
 
 314                                 .getPathLocationVariable(varDef.name);
 
 315                 if (variable == null) {
 
 316                         String msg = ExternalToolsModelMessages.format(
 
 317                                         "ToolUtil.fileLocVarMissing", new Object[] { varDef.name }); //$NON-NLS-1$
 
 318                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 322                 // Expand the variable into a IPath if possible
 
 323                 IPath path = variable.getExpander().getPath(varDef.name,
 
 324                                 varDef.argument, context);
 
 326                         String msg = ExternalToolsModelMessages
 
 328                                                         "The variable {0} with argument {1} could not be expanded to a valid path.",
 
 329                                                         new Object[] { varDef.name, varDef.argument });
 
 330                         status.merge(ExternalToolsPlugin.newErrorStatus(msg, null));
 
 334                 return path.toString();
 
 338          * Extracts from the source text the variable tag's name and argument.
 
 341          *            the source text to parse for a variable tag
 
 343          *            the index in the string to start the search
 
 344          * @return the variable definition
 
 346         public static VariableDefinition extractVariableTag(String text, int start) {
 
 347                 VariableDefinition varDef = new VariableDefinition();
 
 349                 varDef.start = text.indexOf(VAR_TAG_START, start);
 
 350                 if (varDef.start < 0)
 
 352                 start = varDef.start + VAR_TAG_START.length();
 
 354                 int end = text.indexOf(VAR_TAG_END, start);
 
 357                 varDef.end = end + VAR_TAG_END.length();
 
 361                 int mid = text.indexOf(VAR_TAG_SEP, start);
 
 362                 if (mid < 0 || mid > end) {
 
 363                         varDef.name = text.substring(start, end);
 
 366                                 varDef.name = text.substring(start, mid);
 
 367                         mid = mid + VAR_TAG_SEP.length();
 
 369                                 varDef.argument = text.substring(mid, end);
 
 376          * Parses the argument text into an array of individual arguments using the
 
 377          * space character as the delimiter. An individual argument containing
 
 378          * spaces must have a double quote (") at the start and end. Two double
 
 379          * quotes together is taken to mean an embedded double quote in the argument
 
 380          * text. Variables are treated as a single unit and therefore spaces and
 
 381          * double quotes inside a variable are copied as is and not parsed.
 
 384          *            the arguments as one string
 
 385          * @return the array of arguments
 
 387         public static String[] parseArgumentsIntoList(String arguments) {
 
 388                 if (arguments == null || arguments.length() == 0)
 
 389                         return new String[0];
 
 391                 ArrayList list = new ArrayList(10);
 
 392                 boolean inQuotes = false;
 
 393                 boolean inVar = false;
 
 395                 int end = arguments.length();
 
 396                 StringBuffer buffer = new StringBuffer(end);
 
 398                 while (start < end) {
 
 399                         char ch = arguments.charAt(start);
 
 404                                 if (inQuotes || inVar) {
 
 407                                         if (buffer.length() > 0) {
 
 408                                                 list.add(buffer.toString());
 
 419                                                 if (arguments.charAt(start) == ARG_DBL_QUOTE) {
 
 420                                                         // Two quotes together represents one quote
 
 424                                                         inQuotes = !inQuotes;
 
 427                                                 // A lone quote at the end, just drop it.
 
 433                         case VAR_TAG_START_CHAR1:
 
 435                                 if (!inVar && start < end) {
 
 436                                         if (arguments.charAt(start) == VAR_TAG_START_CHAR2) {
 
 437                                                 buffer.append(VAR_TAG_START_CHAR2);
 
 444                         case VAR_TAG_END_CHAR1:
 
 456                 if (buffer.length() > 0)
 
 457                         list.add(buffer.toString());
 
 459                 String[] results = new String[list.size()];
 
 460                 list.toArray(results);
 
 465          * Structure to represent a variable definition within a source string.
 
 467         public static final class VariableDefinition {
 
 469                  * Index in the source text where the variable started or
 
 470                  * <code>-1</code> if no valid variable start tag identifier found.
 
 472                 public int start = -1;
 
 475                  * Index in the source text of the character following the end of the
 
 476                  * variable or <code>-1</code> if no valid variable end tag found.
 
 481                  * The variable's name found in the source text, or <code>null</code>
 
 482                  * if no valid variable found.
 
 484                 public String name = null;
 
 487                  * The variable's argument found in the source text, or
 
 488                  * <code>null</code> if no valid variable found or if the variable did
 
 489                  * not specify an argument
 
 491                 public String argument = null;
 
 494                  * Create an initialized variable definition.
 
 496                 private VariableDefinition() {
 
 501                  * Create an initialized variable definition.
 
 503                 private VariableDefinition(int start, int end) {