franta-hg@54: /** franta-hg@54: * Alt2XML franta-hg@54: * Copyright © 2014 František Kučera (frantovo.cz) franta-hg@54: * franta-hg@54: * This program is free software: you can redistribute it and/or modify franta-hg@54: * it under the terms of the GNU General Public License as published by franta-hg@54: * the Free Software Foundation, either version 3 of the License, or franta-hg@54: * (at your option) any later version. franta-hg@54: * franta-hg@54: * This program is distributed in the hope that it will be useful, franta-hg@54: * but WITHOUT ANY WARRANTY; without even the implied warranty of franta-hg@54: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the franta-hg@54: * GNU General Public License for more details. franta-hg@54: * franta-hg@54: * You should have received a copy of the GNU General Public License franta-hg@54: * along with this program. If not, see . franta-hg@54: */ franta-hg@54: package cz.frantovo.alt2xml.cli; franta-hg@54: franta-hg@54: import java.io.File; franta-hg@67: import java.util.Arrays; franta-hg@67: import java.util.Collection; franta-hg@54: franta-hg@54: /** franta-hg@54: * Converts command line arguments from String array to object. franta-hg@54: * Checks basic constraints (if only supported options are used and if they have correct number of franta-hg@54: * parameters) franta-hg@54: * franta-hg@54: * @author Ing. František Kučera (frantovo.cz) franta-hg@54: */ franta-hg@54: public class CLIParser { franta-hg@54: franta-hg@55: public CLIOptions parseOptions(String[] args) throws CLIParserException { franta-hg@54: CLIOptions options = new CLIOptions(); franta-hg@54: franta-hg@54: for (int i = 0; i < args.length; i++) { franta-hg@54: String arg = args[i]; franta-hg@54: franta-hg@55: boolean matches = false; franta-hg@55: franta-hg@54: for (Token t : Token.values()) { franta-hg@54: if (t.matches(arg)) { franta-hg@55: int parsedArgs = t.parse(args, i, options); franta-hg@55: i = i + parsedArgs; franta-hg@55: matches = true; franta-hg@54: } franta-hg@54: } franta-hg@54: franta-hg@55: if (!matches) { franta-hg@55: throw new CLIParserException("Unknown option: " + arg); franta-hg@55: } franta-hg@54: } franta-hg@54: franta-hg@55: // Default output: franta-hg@54: options.setOutputStream(System.out); franta-hg@54: franta-hg@54: return options; franta-hg@54: } franta-hg@54: franta-hg@54: private static String fetchNext(String[] args, int index) throws CLIParserException { franta-hg@54: if (index < args.length) { franta-hg@54: return args[index]; franta-hg@54: } else { franta-hg@54: throw new CLIParserException("Expecting value for option: " + args[index - 1]); franta-hg@54: } franta-hg@54: } franta-hg@54: franta-hg@54: private static enum Token { franta-hg@54: franta-hg@54: INPUT_FILE("--input-file") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: options.setInputFile(new File(fetchNext(args, ++index))); franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }, franta-hg@54: INPUT_STDIN("--input-stdin") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: options.setInputStream(System.in); franta-hg@54: return 0; franta-hg@54: } franta-hg@54: }, franta-hg@67: SYSTEM_ID("--system-id", "--input-url") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: options.setSystemId(fetchNext(args, ++index)); franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }, franta-hg@54: READER_PROPERTY("--reader-property") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: String name = fetchNext(args, ++index); franta-hg@54: String value = fetchNext(args, ++index); franta-hg@54: options.addReaderProperty(name, value); franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }, franta-hg@98: READER_FEATURE("--reader-feature") { franta-hg@98: @Override franta-hg@98: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@98: int originalIndex = index; franta-hg@98: String name = fetchNext(args, ++index); franta-hg@98: String value = fetchNext(args, ++index); franta-hg@98: options.addReaderFeature(name, Boolean.valueOf(value)); franta-hg@98: return index - originalIndex; franta-hg@98: } franta-hg@98: }, franta-hg@54: ACTION("--action") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: options.setAction(fetchNext(args, ++index)); franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }, franta-hg@54: ACTION_PROPERTY("--action-property") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: String name = fetchNext(args, ++index); franta-hg@54: String value = fetchNext(args, ++index); franta-hg@54: options.addActionProperty(name, value); franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }, franta-hg@54: ACTION_DATA("--") { franta-hg@54: @Override franta-hg@54: public int parse(String[] args, int index, CLIOptions options) throws CLIParserException { franta-hg@54: int originalIndex = index; franta-hg@54: for (index++; index < args.length; index++) { franta-hg@54: options.addActionData(args[index]); franta-hg@54: } franta-hg@54: return index - originalIndex; franta-hg@54: } franta-hg@54: }; franta-hg@54: franta-hg@67: private final Collection options; franta-hg@54: franta-hg@67: private Token(String... options) { franta-hg@67: this.options = Arrays.asList(options); franta-hg@54: } franta-hg@54: franta-hg@54: /** franta-hg@54: * @param option e.g. „--input-file“ franta-hg@54: * @return whether option is this token franta-hg@54: */ franta-hg@54: public boolean matches(String option) { franta-hg@67: return options.contains(option); franta-hg@54: } franta-hg@54: franta-hg@54: /** franta-hg@54: * Parse String arguments and fill values into the options object. franta-hg@54: * franta-hg@54: * @param args CLI arguments franta-hg@54: * @param index index of the option matched by this token, like „--input-file“ franta-hg@54: * @param options object to be filled franta-hg@54: * @return number of parsed arguments – if option has no arguments (just boolean flag), franta-hg@54: * return 0, otherwise return positive integer: number of eaten arguments. franta-hg@54: * @throws CLIParserException franta-hg@54: */ franta-hg@54: public abstract int parse(String[] args, int index, CLIOptions options) throws CLIParserException; franta-hg@54: } franta-hg@54: }