java/alt2xml-cli/src/cz/frantovo/alt2xml/cli/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Thu, 03 Jul 2014 00:18:35 +0200
changeset 54 3d5cc308e268
child 55 c703fb7f088f
permissions -rw-r--r--
CLIOptions, CLIParser – basics
     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.io.InputStream;
    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, InputStream in) throws CLIParserException {
    33 		CLIOptions options = new CLIOptions();
    34 
    35 		for (int i = 0; i < args.length; i++) {
    36 			String arg = args[i];
    37 
    38 			for (Token t : Token.values()) {
    39 				if (t.matches(arg)) {
    40 					t.parse(args, i, options);
    41 				}
    42 			}
    43 
    44 			throw new CLIParserException("Unknown option: " + arg);
    45 		}
    46 
    47 		// Default output: STDOUT
    48 		options.setOutputStream(System.out);
    49 
    50 		return options;
    51 	}
    52 
    53 	private static String fetchNext(String[] args, int index) throws CLIParserException {
    54 		if (index < args.length) {
    55 			return args[index];
    56 		} else {
    57 			throw new CLIParserException("Expecting value for option: " + args[index - 1]);
    58 		}
    59 	}
    60 
    61 	private static enum Token {
    62 
    63 		INPUT_FILE("--input-file") {
    64 					@Override
    65 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    66 						int originalIndex = index;
    67 						options.setInputFile(new File(fetchNext(args, ++index)));
    68 						return index - originalIndex;
    69 					}
    70 				},
    71 		INPUT_STDIN("--input-stdin") {
    72 					@Override
    73 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    74 						options.setInputStream(System.in);
    75 						return 0;
    76 					}
    77 				},
    78 		INPUT_URL("--input-url") {
    79 					@Override
    80 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    81 						int originalIndex = index;
    82 						options.setInputUrl(fetchNext(args, ++index));
    83 						return index - originalIndex;
    84 					}
    85 				},
    86 		SYSTEM_ID("--system-id") {
    87 					@Override
    88 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    89 						int originalIndex = index;
    90 						options.setSystemId(fetchNext(args, ++index));
    91 						return index - originalIndex;
    92 					}
    93 				},
    94 		READER_PROPERTY("--reader-property") {
    95 					@Override
    96 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
    97 						int originalIndex = index;
    98 						String name = fetchNext(args, ++index);
    99 						String value = fetchNext(args, ++index);
   100 						options.addReaderProperty(name, value);
   101 						return index - originalIndex;
   102 					}
   103 				},
   104 		ACTION("--action") {
   105 					@Override
   106 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   107 						int originalIndex = index;
   108 						options.setAction(fetchNext(args, ++index));
   109 						return index - originalIndex;
   110 					}
   111 				},
   112 		ACTION_PROPERTY("--action-property") {
   113 					@Override
   114 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   115 						int originalIndex = index;
   116 						String name = fetchNext(args, ++index);
   117 						String value = fetchNext(args, ++index);
   118 						options.addActionProperty(name, value);
   119 						return index - originalIndex;
   120 					}
   121 				},
   122 		ACTION_DATA("--") {
   123 					@Override
   124 					public int parse(String[] args, int index, CLIOptions options) throws CLIParserException {
   125 						int originalIndex = index;
   126 						for (index++; index < args.length; index++) {
   127 							options.addActionData(args[index]);
   128 						}
   129 						return index - originalIndex;
   130 					}
   131 				};
   132 
   133 		private final String option;
   134 
   135 		private Token(String option) {
   136 			this.option = option;
   137 		}
   138 
   139 		/**
   140 		 * @param option e.g. „--input-file“
   141 		 * @return whether option is this token
   142 		 */
   143 		public boolean matches(String option) {
   144 			return this.option.equals(option);
   145 		}
   146 
   147 		/**
   148 		 * Parse String arguments and fill values into the options object.
   149 		 *
   150 		 * @param args CLI arguments
   151 		 * @param index index of the option matched by this token, like „--input-file“
   152 		 * @param options object to be filled
   153 		 * @return number of parsed arguments – if option has no arguments (just boolean flag),
   154 		 * return 0, otherwise return positive integer: number of eaten arguments.
   155 		 * @throws CLIParserException
   156 		 */
   157 		public abstract int parse(String[] args, int index, CLIOptions options) throws CLIParserException;
   158 	}
   159 }