blob: 3f351b9a573e452db6f0c4ce5b08a72bef8d967e [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.execution.configurations;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* Splits input String to tokens being aware of quoted tokens ("foo bar") and escaped spaces & quotes (\"foo\ bar\"),
* usually used for splitting command line to separate arguments that may contain space symbols.
* Space and quote are the only symbols that can be escaped
*/
public class CommandLineTokenizer extends StringTokenizer {
private static final String DEFAULT_DELIMITERS = " \t\n\r\f";
// keep source level 1.4
private List myTokens = new ArrayList();
private int myCurrentToken = 0;
private boolean myHandleEscapedWhitespaces = false;
public CommandLineTokenizer(String str) {
this(str, false);
}
public CommandLineTokenizer(String str, boolean handleEscapedWhitespaces) {
super(str, DEFAULT_DELIMITERS, true);
myHandleEscapedWhitespaces = handleEscapedWhitespaces;
parseTokens();
}
/**
* @deprecated Do not pass custom delimiters to the CommandLineTokenizer as it may break its logic
*/
@Deprecated()
public CommandLineTokenizer(String str, String delim) {
super(str, delim, true);
parseTokens();
}
@Override
public boolean hasMoreTokens() {
return myCurrentToken < myTokens.size();
}
@Override
public String nextToken() {
return (String) myTokens.get(myCurrentToken++);
}
public String peekNextToken() {
return (String) myTokens.get(myCurrentToken);
}
@Override
public int countTokens() {
return myTokens.size() - myCurrentToken;
}
@Override
public String nextToken(String delim) {
throw new UnsupportedOperationException();
}
private void parseTokens() {
String token;
while ((token = nextTokenInternal()) != null) {
myTokens.add(token);
}
}
private String nextTokenInternal() {
String nextToken;
do {
if (super.hasMoreTokens()) {
nextToken = super.nextToken();
} else {
nextToken = null;
}
} while (nextToken != null && nextToken.length() == 1 && DEFAULT_DELIMITERS.indexOf(nextToken.charAt(0)) >= 0);
if (nextToken == null) {
return null;
}
int i;
int quotationMarks = 0;
final StringBuffer buffer = new StringBuffer();
do {
while ((i = nextToken.indexOf('"')) >= 0) {
boolean isEscapedQuote = i > 0 && nextToken.charAt(i - 1) == '\\';
if (!isEscapedQuote) quotationMarks++;
buffer.append(nextToken.substring(0, isEscapedQuote ? i - 1 : i));
if (isEscapedQuote) buffer.append('"');
nextToken = nextToken.substring(i + 1);
}
boolean isEscapedWhitespace = false;
if (myHandleEscapedWhitespaces && quotationMarks == 0 && nextToken.endsWith("\\") && super.hasMoreTokens()) {
isEscapedWhitespace = true;
buffer.append(nextToken.substring(0, nextToken.length() - 1));
buffer.append(super.nextToken());
}
else {
buffer.append(nextToken);
}
if ((isEscapedWhitespace || quotationMarks % 2 == 1) && super.hasMoreTokens()) {
nextToken = super.nextToken();
} else {
nextToken = null;
}
} while (nextToken != null);
return buffer.toString();
}
}