java/alt2xml-cli/src/cz/frantovo/alt2xml/cli/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Thu, 24 Oct 2019 21:56:03 +0200
changeset 111 e4900596abdb
parent 100 b50e77d23d13
permissions -rw-r--r--
fix license version: GNU GPLv3
     1 /**
     2  * Alt2XML
     3  * Copyright © 2014 František Kučera (frantovo.cz)
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 3 of the License.
     8  *
     9  * This program is distributed in the hope that it will be useful,
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  * GNU General Public License for more details.
    13  *
    14  * You should have received a copy of the GNU General Public License
    15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
    16  */
    17 package cz.frantovo.alt2xml.cli;
    18 
    19 import java.io.File;
    20 import java.util.Arrays;
    21 import java.util.Collection;
    22 
    23 /**
    24  * Converts command line arguments from String array to object.
    25  * Checks basic constraints (if only supported options are used and if they have correct number of
    26  * parameters)
    27  *
    28  * @author Ing. František Kučera (frantovo.cz)
    29  */
    30 public class CLIParser {
    31 
    32 	public CLIOptions parseOptions(String[] args) throws CLIParserException {
    33 		CLIOptions options = new CLIOptions();
    34 
    35 		for (int i = 0; i < args.length; i++) {
    36 			String arg = args[i];
    37 
    38 			boolean matches = false;
    39 
    40 			for (Token t : Token.values()) {
    41 				if (t.matches(arg)) {
    42 					int parsedArgs = t.parse(args, i, options);
    43 					i = i + parsedArgs;
    44 					matches = true;
    45 				}
    46 			}
    47 
    48 			if (!matches) {
    49 				throw new CLIParserException("Unknown option: " + arg);
    50 			}
    51 		}
    52 
    53 		// Default output:
    54 		options.setOutputStream(System.out);
    55 
    56 		return options;
    57 	}
    58 
    59 	private static String fetchNext(String[] args, int index) throws CLIParserException {
    60 		if (index < args.length) {
    61 			return args[index];
    62 		} else {
    63 			throw new CLIParserException("Expecting value for option: " + args[index - 1]);
    64 		}
    65 	}
    66 
    67 	private static enum Token {
    68 
    69 		INPUT_FILE("--input-file") {
    70 					@Override
    71 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    72 						int originalIndex = index;
    73 						options.setInputFile(new File(fetchNext(args, ++index)));
    74 						return index - originalIndex;
    75 					}
    76 				},
    77 		INPUT_STDIN("--input-stdin") {
    78 					@Override
    79 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    80 						options.setInputStream(System.in);
    81 						return 0;
    82 					}
    83 				},
    84 		SYSTEM_ID("--system-id", "--input-url") {
    85 					@Override
    86 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    87 						int originalIndex = index;
    88 						options.setSystemId(fetchNext(args, ++index));
    89 						return index - originalIndex;
    90 					}
    91 				},
    92 		READER_PROPERTY("--reader-property") {
    93 					@Override
    94 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    95 						int originalIndex = index;
    96 						String name = fetchNext(args, ++index);
    97 						String value = fetchNext(args, ++index);
    98 						options.addReaderProperty(name, value);
    99 						return index - originalIndex;
   100 					}
   101 				},
   102 		READER_FEATURE("--reader-feature") {
   103 					@Override
   104 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   105 						int originalIndex = index;
   106 						String name = fetchNext(args, ++index);
   107 						String value = fetchNext(args, ++index);
   108 						options.addReaderFeature(name, Boolean.valueOf(value));
   109 						return index - originalIndex;
   110 					}
   111 				},
   112 		READER_NAMESPACE_AWARE("--reader-namespace-aware") {
   113 					@Override
   114 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   115 						int originalIndex = index;
   116 						String value = fetchNext(args, ++index);
   117 						options.addReaderFeature(Constants.SAX_PARSER_NAMESPACE_AWARE, Boolean.valueOf(value));
   118 						return index - originalIndex;
   119 					}
   120 				},
   121 		ACTION("--action") {
   122 					@Override
   123 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   124 						int originalIndex = index;
   125 						options.setAction(fetchNext(args, ++index));
   126 						return index - originalIndex;
   127 					}
   128 				},
   129 		ACTION_PROPERTY("--action-property") {
   130 					@Override
   131 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   132 						int originalIndex = index;
   133 						String name = fetchNext(args, ++index);
   134 						String value = fetchNext(args, ++index);
   135 						options.addActionProperty(name, value);
   136 						return index - originalIndex;
   137 					}
   138 				},
   139 		ACTION_DATA("--") {
   140 					@Override
   141 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   142 						int originalIndex = index;
   143 						for (index++; index < args.length; index++) {
   144 							options.addActionData(args[index]);
   145 						}
   146 						return index - originalIndex;
   147 					}
   148 				};
   149 
   150 		private final Collection<String> options;
   151 
   152 		private Token(String... options) {
   153 			this.options = Arrays.asList(options);
   154 		}
   155 
   156 		/**
   157 		 * @param option e.g. „--input-file“
   158 		 * @return whether option is this token
   159 		 */
   160 		public boolean matches(String option) {
   161 			return options.contains(option);
   162 		}
   163 
   164 		/**
   165 		 * Parse String arguments and fill values into the options object.
   166 		 *
   167 		 * @param args CLI arguments
   168 		 * @param index index of the option matched by this token, like „--input-file“
   169 		 * @param options object to be filled
   170 		 * @return number of parsed arguments – if option has no arguments (just boolean flag),
   171 		 * return 0, otherwise return positive integer: number of eaten arguments.
   172 		 * @throws CLIParserException
   173 		 */
   174 		public abstract int parse(String[] args, int index, CLIOptions options) throws CLIParserException;
   175 	}
   176 }