19fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann/*******************************************************************************
2b9d1b54e300318b470d9fedccc69d75187016444Evgeny Mandrikov * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors
39fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * All rights reserved. This program and the accompanying materials
49fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * are made available under the terms of the Eclipse Public License v1.0
59fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * which accompanies this distribution, and is available at
69fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * http://www.eclipse.org/legal/epl-v10.html
79fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann *
89fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * Contributors:
99fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann *    Marc R. Hoffmann - initial API and implementation
109fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann *
119fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann *******************************************************************************/
129fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmannpackage org.jacoco.core.runtime;
139fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
149fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmannimport java.util.ArrayList;
159fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmannimport java.util.List;
169fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
179fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann/**
189fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann * Internal utility to parse and create command lines arguments.
199fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann */
209fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmannfinal class CommandLineSupport {
219fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
229fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final char BLANK = ' ';
239fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final char QUOTE = '"';
249fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final char SLASH = '\\';
259fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
269fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	/**
279fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * Quotes a single command line argument if necessary.
289fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *
299fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @param arg
309fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *            command line argument
319fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @return quoted argument
329fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 */
339fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	static String quote(final String arg) {
349fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		final StringBuilder escaped = new StringBuilder();
359fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		for (final char c : arg.toCharArray()) {
369fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			if (c == QUOTE || c == SLASH) {
379fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				escaped.append(SLASH);
389fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			}
399fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			escaped.append(c);
409fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
419fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		if (arg.indexOf(BLANK) != -1 || arg.indexOf(QUOTE) != -1) {
429fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			escaped.insert(0, QUOTE).append(QUOTE);
439fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
449fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		return escaped.toString();
459fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	}
469fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
479fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	/**
489fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * Builds a single command line string from the given argument list.
499fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * Arguments are quoted when necessary.
509fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *
519fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @param args
529fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *            command line arguments
539fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @return combined command line
549fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 */
559fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	static String quote(final List<String> args) {
569fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		final StringBuilder result = new StringBuilder();
579fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		boolean seperate = false;
589fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		for (final String arg : args) {
599fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			if (seperate) {
609fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				result.append(BLANK);
619fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			}
629fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			result.append(quote(arg));
639fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			seperate = true;
649fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
659fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		return result.toString();
669fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	}
679fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
689fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	/**
699fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * Splits a command line into single arguments and removes quotes if
709fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * present.
719fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *
729fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @param commandline
739fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 *            combinded command line
749fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 * @return list of arguments
759fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	 */
769fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	static List<String> split(final String commandline) {
779fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		if (commandline == null || commandline.length() == 0) {
789fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			return new ArrayList<String>();
799fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
809fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		final List<String> args = new ArrayList<String>();
819fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		final StringBuilder current = new StringBuilder();
829fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		int mode = M_STRIPWHITESPACE;
839fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		int endChar = BLANK;
849fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		for (final char c : commandline.toCharArray()) {
859fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			switch (mode) {
869fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			case M_STRIPWHITESPACE:
879fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				if (!Character.isWhitespace(c)) {
889fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					if (c == QUOTE) {
899fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann						endChar = QUOTE;
909fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					} else {
919fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann						current.append(c);
929fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann						endChar = BLANK;
939fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					}
949fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					mode = M_PARSEARGUMENT;
959fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				}
969fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				break;
979fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			case M_PARSEARGUMENT:
989fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				if (c == endChar) {
999fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					addArgument(args, current);
1009fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					mode = M_STRIPWHITESPACE;
1019fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				} else if (c == SLASH) {
1029fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					current.append(SLASH);
1039fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					mode = M_ESCAPED;
1049fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				} else {
1059fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					current.append(c);
1069fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				}
1079fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				break;
1089fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			case M_ESCAPED:
1099fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				if (c == QUOTE || c == SLASH) {
1109fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					current.setCharAt(current.length() - 1, c);
1119fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				} else if (c == endChar) {
1129fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					addArgument(args, current);
1139fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					mode = M_STRIPWHITESPACE;
1149fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				} else {
1159fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann					current.append(c);
1169fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				}
1179fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann				mode = M_PARSEARGUMENT;
118e35a34adcc3a47eac6723533e811e52c288d4dd5Mirko Friedenhagen				break;
1199fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			}
1209fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
1219fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		addArgument(args, current);
1229fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		return args;
1239fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	}
1249fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
1259fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static void addArgument(final List<String> args,
1269fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			final StringBuilder current) {
1279fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		if (current.length() > 0) {
1289fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			args.add(current.toString());
1299fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann			current.setLength(0);
1309fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		}
1319fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	}
1329fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
1339fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final int M_STRIPWHITESPACE = 0;
1349fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final int M_PARSEARGUMENT = 1;
1359fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private static final int M_ESCAPED = 2;
1369fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann
1379fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	private CommandLineSupport() {
1389fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann		// no instances
1399fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann	}
1409fdd14bd5cf0ad765135c8466dcaa9921c72c74bMarc R. Hoffmann}
141