| /******************************************************************************* |
| * Copyright (c) 2007 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ptp.utils.core.linux; |
| |
| import java.text.CharacterIterator; |
| import java.text.StringCharacterIterator; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| |
| public class ArgumentParser { |
| List<String> tokens; |
| |
| /** |
| * Create a command line representation from the string with a shell command line. |
| * The command line is parsed and split on spaces. Quoted or escaped spaces are preserved.. |
| */ |
| public ArgumentParser(String commandline) { |
| this.tokens = parseCommandline(commandline); |
| } |
| |
| /** |
| * Create a command line representation from an array of strings. |
| * The first element of the array is assumed to be the command, the remaining, the arguments. |
| * The elements are not parsed not (un)escaped., but taked as the are. |
| */ |
| public ArgumentParser(String tokenArray[]) { |
| this(Arrays.asList(tokenArray)); |
| } |
| |
| /** |
| * Create a command line representation from an array of strings. |
| * The first element of the list is assumed to be the command, the remaining, the arguments. |
| * The elements are not parsed not (un)escaped., but taked as the are. |
| */ |
| public ArgumentParser(List tokenList) { |
| this.tokens = new ArrayList(tokenList); |
| } |
| |
| /** |
| * Create a command line representation from the command and an array of parameters. |
| * The elements are not parsed not (un)escaped., but taked as the are. |
| */ |
| public ArgumentParser(String command, String parameterArray[]) { |
| this(command, Arrays.asList(parameterArray)); |
| } |
| |
| /** |
| * Create a command line representation from the command and an list of parameters. |
| * The elements are not parsed not (un)escaped., but taked as the are. |
| */ |
| public ArgumentParser(String command, List<String> parameterList) { |
| this.tokens = new ArrayList<String>(); |
| this.tokens.add(command); |
| this.tokens.addAll(parameterList); |
| } |
| |
| private static List<String> parseCommandline(String commandline) { |
| ArrayList<String> result = new ArrayList<String>(); |
| StringCharacterIterator iterator = new StringCharacterIterator(commandline); |
| |
| for (iterator.first(); iterator.current() != CharacterIterator.DONE; iterator.next()) { |
| |
| // Restart to skip white space |
| if (Character.isWhitespace(iterator.current())) { |
| continue; |
| } |
| |
| // Read token |
| StringBuffer buffer = new StringBuffer(); |
| token_reader: for (; iterator.current() != CharacterIterator.DONE; iterator.next()) { |
| char tokenChar = iterator.current(); |
| |
| // A white space terminates the token |
| if (Character.isWhitespace(tokenChar)) { |
| break token_reader; |
| } |
| |
| // Handle character that composes the token |
| switch (tokenChar) { |
| case '"': |
| { |
| /* |
| * Read all text within double quotes or until end of string. Allows escaping. |
| */ |
| iterator.next(); // Skip quote |
| quoted_reader: while ((iterator.current() != CharacterIterator.DONE) && (iterator.current() != '"')) { |
| char innerChar = iterator.current(); |
| switch (innerChar) { |
| case '\\': |
| char nextChar = iterator.next(); |
| switch (nextChar) { |
| case CharacterIterator.DONE: |
| break quoted_reader; |
| case '"': |
| // Add the character, but remove the escape |
| buffer.append(nextChar); |
| iterator.next(); |
| continue quoted_reader; |
| default: |
| // Add the character and keep escape |
| buffer.append(innerChar); |
| buffer.append(nextChar); |
| iterator.next(); |
| continue quoted_reader; |
| } |
| default: |
| buffer.append(innerChar); |
| iterator.next(); |
| continue quoted_reader; |
| } |
| } |
| continue token_reader; |
| } |
| case '\'': |
| { |
| /* |
| * Read all text within single quotes or until end of string. No escaping. |
| */ |
| iterator.next(); // Skip the quote |
| while ((iterator.current() != CharacterIterator.DONE) && (iterator.current() != '\'')) { |
| buffer.append(iterator.current()); |
| iterator.next(); |
| } |
| continue token_reader; |
| } |
| case '\\': |
| { |
| /* |
| * Read escaped char. |
| */ |
| char nextChar = iterator.next(); |
| switch (nextChar) { |
| case CharacterIterator.DONE: |
| break token_reader; |
| case '\n': |
| // Ignore newline. Both lines are concatenated. |
| continue token_reader; |
| default: |
| // Add the character, but remove the escape |
| buffer.append(nextChar); |
| continue token_reader; |
| } |
| } |
| default: |
| /* |
| * Any other char, add to the buffer. |
| */ |
| buffer.append(tokenChar); |
| continue token_reader; |
| } |
| } |
| result.add(buffer.toString()); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Convert all tokens in a full command line that can be executed in a shell. |
| * @param fullEscape If every special character shall be escaped. If false, only white spaces |
| * are escaped and the shell will interpret the special chars. If true, then all special chars are |
| * quoted. |
| * @return |
| */ |
| public String getCommandLine(boolean fullEscape) { |
| StringBuffer buffer = new StringBuffer(); |
| Iterator<String> iterator = this.tokens.iterator(); |
| boolean first = true; |
| while (iterator.hasNext()) { |
| String token = (String) iterator.next(); |
| if (! first) { |
| buffer.append(' '); |
| } else { |
| first = false; |
| } |
| buffer.append(escapeToken(token, fullEscape)); |
| } |
| return buffer.toString(); |
| } |
| |
| private StringBuffer escapeToken(String token, boolean fullEscape) { |
| StringBuffer buffer = new StringBuffer(); |
| StringCharacterIterator iter = new StringCharacterIterator(token); |
| for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { |
| if (Character.isWhitespace(c)) { |
| buffer.append('\\'); |
| buffer.append(c); |
| continue; |
| } |
| switch (c) { |
| case '(': |
| case ')': |
| case '[': |
| case ']': |
| case '{': |
| case '}': |
| case '|': |
| case '\\': |
| case '*': |
| case '&': |
| case '^': |
| case '%': |
| case '$': |
| case '#': |
| case '@': |
| case '!': |
| case '~': |
| case '`': |
| case '\'': |
| case '"': |
| case ':': |
| case ';': |
| case '?': |
| case '>': |
| case '<': |
| case '\n': |
| if (fullEscape) { |
| buffer.append('\\'); |
| } |
| buffer.append(c); |
| continue; |
| case ' ': |
| buffer.append('\\'); |
| buffer.append(c); |
| continue; |
| default: |
| buffer.append(c); |
| continue; |
| } |
| } |
| return buffer; |
| } |
| |
| /** |
| * Returns a List of all entries of the command line. |
| * @return The Array |
| */ |
| public String[] getTokenArray() { |
| return (String[]) this.tokens.toArray(new String[this.tokens.size()]); |
| } |
| |
| /** |
| * Returns a List of all entries of the command line. |
| * @return The List |
| */ |
| public List<String> getTokenList() { |
| return new ArrayList(this.tokens); |
| } |
| |
| /** |
| * Returns the command of the command line, assuming that the first entry is always the command. |
| * @return The command or null if the command lines has no command nor arguments. |
| * @return |
| */ |
| public String getCommand() { |
| if (this.tokens.size() == 0) { |
| return null; |
| } |
| return (String) this.tokens.get(0); |
| } |
| |
| /** |
| * Returns the command of the command line, assuming that the first entry is always the command. |
| * @return The command or null if the command lines has no command nor arguments. |
| * @param fullEscape If every special character shall be escaped. If false, only white spaces |
| * are escaped and the shell will interpret the special chars. If true, then all special chars are |
| * quoted. |
| * @return |
| */ |
| public String getEscapedCommand(boolean fullEscalpe) { |
| if (this.tokens.size() == 0) { |
| return null; |
| } |
| return escapeToken((String) this.tokens.get(0), fullEscalpe).toString(); |
| } |
| |
| /** |
| * Returns a list of all arguments, assuming that the first entry is the command name. |
| * @return The Array or null if the command lines has no command nor arguments. |
| */ |
| public String[] getParameterArray() { |
| if (this.tokens.size() == 0) { |
| return null; |
| } |
| return (String[]) this.tokens.subList(1, this.tokens.size()).toArray(new String[this.tokens.size()-1]); |
| } |
| |
| /** |
| * Returns a list of all arguments, assuming that the first entry is the command name. |
| * @return The List or null if the command lines has no command nor arguments. |
| */ |
| public List getParameterList() { |
| if (this.tokens.size() == 0) { |
| return null; |
| } |
| return new ArrayList(this.tokens.subList(1, this.tokens.size())); |
| } |
| |
| /** |
| * Returns the total number of entries. |
| * @return |
| */ |
| public int getSize() { |
| return this.tokens.size(); |
| } |
| |
| /** |
| * Returns a representation of the command line for debug purposes. |
| */ |
| public String toString() { |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append("<"); //$NON-NLS-1$ |
| Iterator iterator = this.tokens.iterator(); |
| boolean first = true; |
| while (iterator.hasNext()) { |
| String token = (String) iterator.next(); |
| if (! first) { |
| buffer.append('\n'); |
| } else { |
| first = false; |
| } |
| buffer.append(token); |
| } |
| buffer.append(">"); //$NON-NLS-1$ |
| return buffer.toString(); |
| } |
| |
| public static void main(String[] args) { |
| ArgumentParser parser = new ArgumentParser("foobar", new String[] {"arg1", "arg2", "arg\\3", "arg\"4", "arg'5", "more arguments"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ |
| System.out.println(parser.getCommandLine(false)); |
| System.out.println(parser.getCommandLine(true)); |
| |
| parser = new ArgumentParser(" foo"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a "); System.out.println(parser); //$NON-NLS-1$ |
| System.out.println(); |
| parser = new ArgumentParser(" foo a"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser(" foo a "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser(" foo a "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a "); System.out.println(parser); //$NON-NLS-1$ |
| System.out.println(); |
| parser = new ArgumentParser("foo a b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a b "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a b c "); System.out.println(parser); //$NON-NLS-1$ |
| System.out.println(); |
| parser = new ArgumentParser("foo\\ a b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo \\ab"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a\\ b\\ c "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("\\foo a b c "); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a b c\\"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \\b c"); System.out.println(parser); //$NON-NLS-1$ |
| System.out.println(); |
| parser = new ArgumentParser("foo a\\'c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a\\\"c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \\'c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \\\"c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a\\' c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a\\\" c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \\' c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \\\" c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a c b\\'"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a c b\\\""); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a c b \\'"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a c b \\\""); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("\\'foo a c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("\\\"foo a c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("\\' foo a c b"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("\\\" foo a c b"); System.out.println(parser); //$NON-NLS-1$ |
| System.out.println(); |
| parser = new ArgumentParser("'foo a' b c d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a b 'c d'"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b c' d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b\\e' d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b\\e\" d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b c d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b c d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b c\" d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b c\"d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b c' d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b c'd"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b \" c' d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b ' c\" d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a 'b \\\" c' d"); System.out.println(parser); //$NON-NLS-1$ |
| parser = new ArgumentParser("foo a \"b \' c\" d"); System.out.println(parser); //$NON-NLS-1$ |
| |
| System.out.println(); |
| parser = new ArgumentParser(new String[] {}); System.out.println(parser.getCommandLine(true)); |
| parser = new ArgumentParser(new String[] {"a"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ |
| parser = new ArgumentParser(new String[] {"av"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ |
| parser = new ArgumentParser(new String[] {"a d"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ |
| parser = new ArgumentParser(new String[] {"a", "a"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| parser = new ArgumentParser(new String[] {"av", "a"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| parser = new ArgumentParser(new String[] {"a d", "a"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| parser = new ArgumentParser(new String[] {"a", "b b"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| parser = new ArgumentParser(new String[] {"av", "b b"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| parser = new ArgumentParser(new String[] {"a d", "b b"}); System.out.println(parser.getCommandLine(true)); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| } |
| |
| } |