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