/* Schmant, the build tool, http://www.schmant.org
* Copyright (C) 2007-2009 Karl Gustafsson
*
* This file is a part of Schmant.
*
* Schmant is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Schmant is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.schmant.support.io;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Objects of this class is used for building an command and argument list that
* is used for running an external command. The {@link #add(java.lang.String)}
* method is responsible for quoting and escaping the contents of the string as
* necessary.
* @author Karl Gustafsson
* @since 0.5
*/
public class ArgumentList
{
private static final Pattern BACKSLASH_PATTERN = Pattern.compile("\\", Pattern.LITERAL);
private final List<String> m_argumentList = new ArrayList<String>();
// Should strings containing spaces be quoted?
private final boolean m_quoteStringsWSpaces;
/**
* Create the argument list.
* @param quoteStringsWSpaces Should an added string containing spaces be
* quoted?
*/
public ArgumentList(boolean quoteStringsWSpaces)
{
m_quoteStringsWSpaces = quoteStringsWSpaces;
}
/**
* Check if the argument is already quoted. Declared package private so that
* it can be unit tested.
* @param arg The argument to check
* @return {@code true} if already quoted
*/
boolean isAlreadyQuoted(String arg)
{
return ((arg.startsWith("\"") && arg.endsWith("\"")) || (arg.startsWith("'") && arg.endsWith("'")));
}
/**
* Add one argument to the list. If there are characters that need to be
* escaped in the argument, this method takes care of that.
* @param arg The argument. {@code null} arguments are allowed.
* @return {@code this}
*/
public ArgumentList add(String arg)
{
if (arg != null)
{
// This must be used instead of String.replaceAll since the
// replacement string contains back slashes.
arg = BACKSLASH_PATTERN.matcher(arg).replaceAll(Matcher.quoteReplacement("\\\\"));
if (m_quoteStringsWSpaces && arg.contains(" ") && !isAlreadyQuoted(arg))
{
arg = "\"" + arg + "\"";
}
}
m_argumentList.add(arg);
return this;
}
/**
* Add a collection of arguments to the list. The arguments are added in the
* order that they are returned when iterating over the collection. If there
* are characters that need to be escaped in the arguments, this method
* takes care of that.
* @param c The argument collection.
* @return {@code this}
*/
public ArgumentList addAll(Collection<String> c)
{
for (String s : c)
{
add(s);
}
return this;
}
/**
* Add all arguments in the supplied argument list. The arguments are
* assumed to be processed already, and are added as-is.
* @param al The argument list to add arguments from.
* @return {@code this}
*/
public ArgumentList addAll(ArgumentList al)
{
for (String s : al.getArgumentList())
{
m_argumentList.add(s);
}
return this;
}
/**
* Get the argument list.
* @return The argument list.
*/
public List<String> getArgumentList()
{
return m_argumentList;
}
@Override
public String toString()
{
StringBuilder res = new StringBuilder();
boolean first = true;
for (String arg : m_argumentList)
{
if (!first)
{
res.append(' ');
}
res.append(arg);
first = false;
}
return res.toString();
}
}