/*******************************************************************************
* Copyright (c) 2012, 2013 Google, Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alex Ruiz (Google) - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.codan.core.cxx.externaltool;
import java.util.ArrayList;
import java.util.List;
/**
* Separates the arguments, stored as a single {@code String}, to pass to an external tool. It uses
* an empty space as the delimiter and supports quoted arguments.
*
* @since 2.1
*/
public class ArgsSeparator {
private static final char BACKSLASH = '\\';
private static final char DOUBLE_QUOTE = '"';
private static final char SINGLE_QUOTE = '\'';
private static final char SPACE = ' ';
private static final String[] NO_ARGS = {};
public String[] splitArguments(String s) {
if (s == null || s.isEmpty()) {
return NO_ARGS;
}
ParserState state = ParserState.NORMAL;
StringBuilder current = new StringBuilder();
List<String> args = new ArrayList<String>();
boolean lastTokenInQuotes = false;
char previous = 0;
for (char c : s.toCharArray()) {
switch (state) {
case IN_SINGLE_QUOTE:
if (previous != BACKSLASH && c == SINGLE_QUOTE) {
lastTokenInQuotes = true;
state = ParserState.NORMAL;
} else {
previous = c;
current.append(c);
}
break;
case IN_DOUBLE_QUOTE:
if (previous != BACKSLASH && c == DOUBLE_QUOTE) {
lastTokenInQuotes = true;
state = ParserState.NORMAL;
} else {
previous = c;
current.append(c);
}
break;
default:
switch (c) {
case SINGLE_QUOTE:
if (previous != BACKSLASH) {
state = ParserState.IN_SINGLE_QUOTE;
}
break;
case DOUBLE_QUOTE:
if (previous != BACKSLASH) {
state = ParserState.IN_DOUBLE_QUOTE;
}
break;
case SPACE:
if (lastTokenInQuotes || current.length() != 0) {
args.add(current.toString());
current.setLength(0);
}
break;
default:
previous = c;
current.append(c);
}
lastTokenInQuotes = false;
break;
}
}
if (lastTokenInQuotes || current.length() != 0) {
args.add(current.toString());
}
if (state != ParserState.NORMAL) {
throw new IllegalArgumentException("Unbalanced quotes in " + s); //$NON-NLS-1$
}
return args.toArray(new String[args.size()]);
}
private static enum ParserState {
NORMAL, IN_SINGLE_QUOTE, IN_DOUBLE_QUOTE;
}
}