CommandLineSupport.java revision 398ee59bebad6835dab57b60157eff16d511709e
1/*******************************************************************************
2 * Copyright (c) 2009, 2015 Mountainminds GmbH & Co. KG and Contributors
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 *    Marc R. Hoffmann - initial API and implementation
10 *
11 *******************************************************************************/
12package org.jacoco.core.runtime;
13
14import java.util.ArrayList;
15import java.util.List;
16
17/**
18 * Internal utility to parse and create command lines arguments.
19 */
20final class CommandLineSupport {
21
22	private static final char BLANK = ' ';
23	private static final char QUOTE = '"';
24	private static final char SLASH = '\\';
25
26	/**
27	 * Quotes a single command line argument if necessary.
28	 *
29	 * @param arg
30	 *            command line argument
31	 * @return quoted argument
32	 */
33	static String quote(final String arg) {
34		final StringBuilder escaped = new StringBuilder();
35		for (final char c : arg.toCharArray()) {
36			if (c == QUOTE || c == SLASH) {
37				escaped.append(SLASH);
38			}
39			escaped.append(c);
40		}
41		if (arg.indexOf(BLANK) != -1 || arg.indexOf(QUOTE) != -1) {
42			escaped.insert(0, QUOTE).append(QUOTE);
43		}
44		return escaped.toString();
45	}
46
47	/**
48	 * Builds a single command line string from the given argument list.
49	 * Arguments are quoted when necessary.
50	 *
51	 * @param args
52	 *            command line arguments
53	 * @return combined command line
54	 */
55	static String quote(final List<String> args) {
56		final StringBuilder result = new StringBuilder();
57		boolean seperate = false;
58		for (final String arg : args) {
59			if (seperate) {
60				result.append(BLANK);
61			}
62			result.append(quote(arg));
63			seperate = true;
64		}
65		return result.toString();
66	}
67
68	/**
69	 * Splits a command line into single arguments and removes quotes if
70	 * present.
71	 *
72	 * @param commandline
73	 *            combinded command line
74	 * @return list of arguments
75	 */
76	static List<String> split(final String commandline) {
77		if (commandline == null || commandline.length() == 0) {
78			return new ArrayList<String>();
79		}
80		final List<String> args = new ArrayList<String>();
81		final StringBuilder current = new StringBuilder();
82		int mode = M_STRIPWHITESPACE;
83		int endChar = BLANK;
84		for (final char c : commandline.toCharArray()) {
85			switch (mode) {
86			case M_STRIPWHITESPACE:
87				if (!Character.isWhitespace(c)) {
88					if (c == QUOTE) {
89						endChar = QUOTE;
90					} else {
91						current.append(c);
92						endChar = BLANK;
93					}
94					mode = M_PARSEARGUMENT;
95				}
96				break;
97			case M_PARSEARGUMENT:
98				if (c == endChar) {
99					addArgument(args, current);
100					mode = M_STRIPWHITESPACE;
101				} else if (c == SLASH) {
102					current.append(SLASH);
103					mode = M_ESCAPED;
104				} else {
105					current.append(c);
106				}
107				break;
108			case M_ESCAPED:
109				if (c == QUOTE || c == SLASH) {
110					current.setCharAt(current.length() - 1, c);
111				} else if (c == endChar) {
112					addArgument(args, current);
113					mode = M_STRIPWHITESPACE;
114				} else {
115					current.append(c);
116				}
117				mode = M_PARSEARGUMENT;
118				break;
119			}
120		}
121		addArgument(args, current);
122		return args;
123	}
124
125	private static void addArgument(final List<String> args,
126			final StringBuilder current) {
127		if (current.length() > 0) {
128			args.add(current.toString());
129			current.setLength(0);
130		}
131	}
132
133	private static final int M_STRIPWHITESPACE = 0;
134	private static final int M_PARSEARGUMENT = 1;
135	private static final int M_ESCAPED = 2;
136
137	private CommandLineSupport() {
138		// no instances
139	}
140}
141