CommandLineSupport.java
/*******************************************************************************
* Copyright (c) 2009, 2024 Mountainminds GmbH & Co. KG and Contributors
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Marc R. Hoffmann - initial API and implementation
*
*******************************************************************************/
package org.jacoco.core.runtime;
import java.util.ArrayList;
import java.util.List;
/**
* Internal utility to parse and create command lines arguments.
*/
final class CommandLineSupport {
private static final char BLANK = ' ';
private static final char QUOTE = '"';
private static final char SLASH = '\\';
/**
* Quotes a single command line argument if necessary.
*
* @param arg
* command line argument
* @return quoted argument
*/
static String quote(final String arg) {
final StringBuilder escaped = new StringBuilder();
for (final char c : arg.toCharArray()) {
if (c == QUOTE || c == SLASH) {
escaped.append(SLASH);
}
escaped.append(c);
}
if (arg.indexOf(BLANK) != -1 || arg.indexOf(QUOTE) != -1) {
escaped.insert(0, QUOTE).append(QUOTE);
}
return escaped.toString();
}
/**
* Builds a single command line string from the given argument list.
* Arguments are quoted when necessary.
*
* @param args
* command line arguments
* @return combined command line
*/
static String quote(final List<String> args) {
final StringBuilder result = new StringBuilder();
boolean separate = false;
for (final String arg : args) {
if (separate) {
result.append(BLANK);
}
result.append(quote(arg));
separate = true;
}
return result.toString();
}
/**
* Splits a command line into single arguments and removes quotes if
* present.
*
* @param commandline
* combined command line
* @return list of arguments
*/
static List<String> split(final String commandline) {
if (commandline == null || commandline.length() == 0) {
return new ArrayList<String>();
}
final List<String> args = new ArrayList<String>();
final StringBuilder current = new StringBuilder();
int mode = M_STRIP_WHITESPACE;
int endChar = BLANK;
for (final char c : commandline.toCharArray()) {
switch (mode) {
case M_STRIP_WHITESPACE:
if (!Character.isWhitespace(c)) {
if (c == QUOTE) {
endChar = QUOTE;
} else {
current.append(c);
endChar = BLANK;
}
mode = M_PARSE_ARGUMENT;
}
break;
case M_PARSE_ARGUMENT:
if (c == endChar) {
addArgument(args, current);
mode = M_STRIP_WHITESPACE;
} else if (c == SLASH) {
current.append(SLASH);
mode = M_ESCAPED;
} else {
current.append(c);
}
break;
case M_ESCAPED:
if (c == QUOTE || c == SLASH) {
current.setCharAt(current.length() - 1, c);
} else if (c == endChar) {
addArgument(args, current);
mode = M_STRIP_WHITESPACE;
} else {
current.append(c);
}
mode = M_PARSE_ARGUMENT;
break;
}
}
addArgument(args, current);
return args;
}
private static void addArgument(final List<String> args,
final StringBuilder current) {
if (current.length() > 0) {
args.add(current.toString());
current.setLength(0);
}
}
private static final int M_STRIP_WHITESPACE = 0;
private static final int M_PARSE_ARGUMENT = 1;
private static final int M_ESCAPED = 2;
private CommandLineSupport() {
// no instances
}
}