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: }