java/copy-image-resizer/src/cz/frantovo/copyImageResizer/cli/CLIParser.java
author František Kučera <franta-hg@frantovo.cz>
Mon, 17 Nov 2014 20:23:58 +0100
changeset 14 dec0dd934a64
parent 7 8e9983260624
child 18 a5a36526ff71
permissions -rw-r--r--
option: --skip-errors
     1 /**
     2  * copy-image-resizer
     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.copyImageResizer.cli;
    19 
    20 import cz.frantovo.copyImageResizer.RecursiveOptions;
    21 import cz.frantovo.copyImageResizer.SizeSpecification;
    22 import java.io.File;
    23 import java.util.Arrays;
    24 import java.util.Collection;
    25 
    26 /**
    27  *
    28  * @author Ing. František Kučera (frantovo.cz)
    29  */
    30 public class CLIParser {
    31 
    32 	public RecursiveOptions parseOptions(String[] args) throws CLIParserException {
    33 		RecursiveOptions options = new RecursiveOptions();
    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 		return options;
    54 	}
    55 
    56 	/**
    57 	 *
    58 	 * @param args
    59 	 * @param index
    60 	 * @param option name of the option for error messages | if null, the previous argument is used
    61 	 * as option name
    62 	 * @return
    63 	 * @throws CLIParserException
    64 	 */
    65 	private static String fetchNext(String[] args, int index, String option) throws CLIParserException {
    66 		if (index < args.length) {
    67 			return args[index];
    68 		} else {
    69 			option = option == null ? args[index - 1] : option;
    70 			throw new CLIParserException("Expecting value for option: " + option);
    71 		}
    72 	}
    73 
    74 	private static enum Token {
    75 
    76 		INPUT_DIR("--input-dir") { // bash-completion: option
    77 					@Override
    78 					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
    79 						int originalIndex = index;
    80 						String name = fetchNext(args, ++index, args[originalIndex]);
    81 						options.setInput(new File(name));
    82 						return index - originalIndex;
    83 					}
    84 				},
    85 		OUTPUT_DIR("--output-dir") { // bash-completion: option
    86 					@Override
    87 					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
    88 						int originalIndex = index;
    89 						String name = fetchNext(args, ++index, args[originalIndex]);
    90 						options.setOutput(new File(name));
    91 						return index - originalIndex;
    92 					}
    93 				},
    94 		SIZE("--size") { // bash-completion: option
    95 					@Override
    96 					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
    97 						int originalIndex = index;
    98 						int width = parseInt(fetchNext(args, ++index, args[originalIndex]));
    99 						int height = parseInt(fetchNext(args, ++index, args[originalIndex]));
   100 						boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex]));
   101 						String directory = width + "x" + height;
   102 						options.addSize(new SizeSpecification(width, height, directory, resizeSmaller));
   103 						return index - originalIndex;
   104 					}
   105 				},
   106 		SIZE_NAMED("--size-named") { // bash-completion: option
   107 					@Override
   108 					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
   109 						int originalIndex = index;
   110 						int width = parseInt(fetchNext(args, ++index, args[originalIndex]));
   111 						int height = parseInt(fetchNext(args, ++index, args[originalIndex]));
   112 						boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex]));
   113 						String directory = fetchNext(args, ++index, args[originalIndex]);
   114 						options.addSize(new SizeSpecification(width, height, directory, resizeSmaller));
   115 						return index - originalIndex;
   116 					}
   117 				},
   118 		SKIP_ERRORS("--skip-errors") { // bash-completion: option
   119 
   120 					@Override
   121 					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
   122 						options.setSkipErrors(true);
   123 						return 0;
   124 					}
   125 
   126 				};
   127 
   128 		private final Collection<String> options;
   129 
   130 		private Token(String... options) {
   131 			this.options = Arrays.asList(options);
   132 		}
   133 
   134 		/**
   135 		 * @param option e.g. „--input-file“
   136 		 * @return whether option is this token
   137 		 */
   138 		public boolean matches(String option) {
   139 			return options.contains(option);
   140 		}
   141 
   142 		private static int parseInt(String number) throws CLIParserException {
   143 			try {
   144 				return Integer.parseInt(number);
   145 			} catch (Exception e) {
   146 				throw new CLIParserException("Unable to parse integer: " + number, e);
   147 			}
   148 		}
   149 
   150 		private static boolean parseBoolean(String value) throws CLIParserException {
   151 			switch (value) {
   152 				case "true":
   153 					return true;
   154 				case "false":
   155 					return false;
   156 				default:
   157 					throw new CLIParserException("Value „" + value + "“ is not a valid boolean. Expecting „true“ or „false“.");
   158 			}
   159 		}
   160 
   161 		/**
   162 		 * Parse String arguments and fill values into the options object.
   163 		 *
   164 		 * @param args CLI arguments
   165 		 * @param index index of the option matched by this token, like „--input-file“
   166 		 * @param options object to be filled
   167 		 * @return number of parsed arguments – if option has no arguments (just boolean flag),
   168 		 * return 0, otherwise return positive integer: number of eaten arguments.
   169 		 * @throws CLIParserException
   170 		 */
   171 		public abstract int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException;
   172 	}
   173 }