franta-hg@3: /** franta-hg@3: * copy-image-resizer franta-hg@3: * Copyright © 2014 František Kučera (frantovo.cz) franta-hg@3: * franta-hg@3: * This program is free software: you can redistribute it and/or modify franta-hg@3: * it under the terms of the GNU General Public License as published by franta-hg@3: * the Free Software Foundation, either version 3 of the License, or franta-hg@3: * (at your option) any later version. franta-hg@3: * franta-hg@3: * This program is distributed in the hope that it will be useful, franta-hg@3: * but WITHOUT ANY WARRANTY; without even the implied warranty of franta-hg@3: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the franta-hg@3: * GNU General Public License for more details. franta-hg@3: * franta-hg@3: * You should have received a copy of the GNU General Public License franta-hg@3: * along with this program. If not, see . franta-hg@3: */ franta-hg@4: package cz.frantovo.copyImageResizer.cli; franta-hg@3: franta-hg@5: import cz.frantovo.copyImageResizer.RecursiveOptions; franta-hg@7: import cz.frantovo.copyImageResizer.SizeSpecification; franta-hg@3: import java.io.File; franta-hg@3: import java.util.Arrays; franta-hg@3: import java.util.Collection; franta-hg@3: franta-hg@3: /** franta-hg@3: * franta-hg@3: * @author Ing. František Kučera (frantovo.cz) franta-hg@3: */ franta-hg@3: public class CLIParser { franta-hg@3: franta-hg@5: public RecursiveOptions parseOptions(String[] args) throws CLIParserException { franta-hg@5: RecursiveOptions options = new RecursiveOptions(); franta-hg@3: franta-hg@3: for (int i = 0; i < args.length; i++) { franta-hg@3: String arg = args[i]; franta-hg@3: franta-hg@3: boolean matches = false; franta-hg@3: franta-hg@3: for (Token t : Token.values()) { franta-hg@3: if (t.matches(arg)) { franta-hg@3: int parsedArgs = t.parse(args, i, options); franta-hg@3: i = i + parsedArgs; franta-hg@3: matches = true; franta-hg@3: } franta-hg@3: } franta-hg@3: franta-hg@3: if (!matches) { franta-hg@3: throw new CLIParserException("Unknown option: " + arg); franta-hg@3: } franta-hg@3: } franta-hg@3: franta-hg@3: return options; franta-hg@3: } franta-hg@3: franta-hg@7: /** franta-hg@7: * franta-hg@7: * @param args franta-hg@7: * @param index franta-hg@7: * @param option name of the option for error messages | if null, the previous argument is used franta-hg@7: * as option name franta-hg@7: * @return franta-hg@7: * @throws CLIParserException franta-hg@7: */ franta-hg@7: private static String fetchNext(String[] args, int index, String option) throws CLIParserException { franta-hg@3: if (index < args.length) { franta-hg@3: return args[index]; franta-hg@3: } else { franta-hg@7: option = option == null ? args[index - 1] : option; franta-hg@7: throw new CLIParserException("Expecting value for option: " + option); franta-hg@3: } franta-hg@3: } franta-hg@3: franta-hg@3: private static enum Token { franta-hg@3: franta-hg@3: INPUT_DIR("--input-dir") { // bash-completion: option franta-hg@3: @Override franta-hg@5: public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException { franta-hg@3: int originalIndex = index; franta-hg@7: String name = fetchNext(args, ++index, args[originalIndex]); franta-hg@3: options.setInput(new File(name)); franta-hg@3: return index - originalIndex; franta-hg@3: } franta-hg@3: }, franta-hg@3: OUTPUT_DIR("--output-dir") { // bash-completion: option franta-hg@3: @Override franta-hg@5: public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException { franta-hg@3: int originalIndex = index; franta-hg@7: String name = fetchNext(args, ++index, args[originalIndex]); franta-hg@3: options.setOutput(new File(name)); franta-hg@3: return index - originalIndex; franta-hg@3: } franta-hg@3: }, franta-hg@3: SIZE("--size") { // bash-completion: option franta-hg@3: @Override franta-hg@5: public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException { franta-hg@3: int originalIndex = index; franta-hg@7: int width = parseInt(fetchNext(args, ++index, args[originalIndex])); franta-hg@7: int height = parseInt(fetchNext(args, ++index, args[originalIndex])); franta-hg@7: boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex])); franta-hg@3: String directory = width + "x" + height; franta-hg@7: options.addSize(new SizeSpecification(width, height, directory, resizeSmaller)); franta-hg@3: return index - originalIndex; franta-hg@3: } franta-hg@3: }, franta-hg@3: SIZE_NAMED("--size-named") { // bash-completion: option franta-hg@3: @Override franta-hg@5: public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException { franta-hg@3: int originalIndex = index; franta-hg@7: int width = parseInt(fetchNext(args, ++index, args[originalIndex])); franta-hg@7: int height = parseInt(fetchNext(args, ++index, args[originalIndex])); franta-hg@7: boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex])); franta-hg@7: String directory = fetchNext(args, ++index, args[originalIndex]); franta-hg@7: options.addSize(new SizeSpecification(width, height, directory, resizeSmaller)); franta-hg@3: return index - originalIndex; franta-hg@3: } franta-hg@14: }, franta-hg@14: SKIP_ERRORS("--skip-errors") { // bash-completion: option franta-hg@14: franta-hg@14: @Override franta-hg@14: public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException { franta-hg@14: options.setSkipErrors(true); franta-hg@14: return 0; franta-hg@14: } franta-hg@14: franta-hg@3: }; franta-hg@3: franta-hg@3: private final Collection options; franta-hg@3: franta-hg@3: private Token(String... options) { franta-hg@3: this.options = Arrays.asList(options); franta-hg@3: } franta-hg@3: franta-hg@3: /** franta-hg@3: * @param option e.g. „--input-file“ franta-hg@3: * @return whether option is this token franta-hg@3: */ franta-hg@3: public boolean matches(String option) { franta-hg@3: return options.contains(option); franta-hg@3: } franta-hg@3: franta-hg@3: private static int parseInt(String number) throws CLIParserException { franta-hg@3: try { franta-hg@3: return Integer.parseInt(number); franta-hg@3: } catch (Exception e) { franta-hg@3: throw new CLIParserException("Unable to parse integer: " + number, e); franta-hg@3: } franta-hg@3: } franta-hg@3: franta-hg@7: private static boolean parseBoolean(String value) throws CLIParserException { franta-hg@7: switch (value) { franta-hg@7: case "true": franta-hg@7: return true; franta-hg@7: case "false": franta-hg@7: return false; franta-hg@7: default: franta-hg@7: throw new CLIParserException("Value „" + value + "“ is not a valid boolean. Expecting „true“ or „false“."); franta-hg@7: } franta-hg@7: } franta-hg@7: franta-hg@3: /** franta-hg@3: * Parse String arguments and fill values into the options object. franta-hg@3: * franta-hg@3: * @param args CLI arguments franta-hg@3: * @param index index of the option matched by this token, like „--input-file“ franta-hg@3: * @param options object to be filled franta-hg@3: * @return number of parsed arguments – if option has no arguments (just boolean flag), franta-hg@3: * return 0, otherwise return positive integer: number of eaten arguments. franta-hg@3: * @throws CLIParserException franta-hg@3: */ franta-hg@5: public abstract int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException; franta-hg@3: } franta-hg@3: }