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
franta-hg@3
     1
/**
franta-hg@3
     2
 * copy-image-resizer
franta-hg@3
     3
 * Copyright © 2014 František Kučera (frantovo.cz)
franta-hg@3
     4
 *
franta-hg@3
     5
 * This program is free software: you can redistribute it and/or modify
franta-hg@3
     6
 * it under the terms of the GNU General Public License as published by
franta-hg@3
     7
 * the Free Software Foundation, either version 3 of the License, or
franta-hg@3
     8
 * (at your option) any later version.
franta-hg@3
     9
 *
franta-hg@3
    10
 * This program is distributed in the hope that it will be useful,
franta-hg@3
    11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
franta-hg@3
    12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
franta-hg@3
    13
 * GNU General Public License for more details.
franta-hg@3
    14
 *
franta-hg@3
    15
 * You should have received a copy of the GNU General Public License
franta-hg@3
    16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
franta-hg@3
    17
 */
franta-hg@4
    18
package cz.frantovo.copyImageResizer.cli;
franta-hg@3
    19
franta-hg@5
    20
import cz.frantovo.copyImageResizer.RecursiveOptions;
franta-hg@7
    21
import cz.frantovo.copyImageResizer.SizeSpecification;
franta-hg@3
    22
import java.io.File;
franta-hg@3
    23
import java.util.Arrays;
franta-hg@3
    24
import java.util.Collection;
franta-hg@3
    25
franta-hg@3
    26
/**
franta-hg@3
    27
 *
franta-hg@3
    28
 * @author Ing. František Kučera (frantovo.cz)
franta-hg@3
    29
 */
franta-hg@3
    30
public class CLIParser {
franta-hg@3
    31
franta-hg@5
    32
	public RecursiveOptions parseOptions(String[] args) throws CLIParserException {
franta-hg@5
    33
		RecursiveOptions options = new RecursiveOptions();
franta-hg@3
    34
franta-hg@3
    35
		for (int i = 0; i < args.length; i++) {
franta-hg@3
    36
			String arg = args[i];
franta-hg@3
    37
franta-hg@3
    38
			boolean matches = false;
franta-hg@3
    39
franta-hg@3
    40
			for (Token t : Token.values()) {
franta-hg@3
    41
				if (t.matches(arg)) {
franta-hg@3
    42
					int parsedArgs = t.parse(args, i, options);
franta-hg@3
    43
					i = i + parsedArgs;
franta-hg@3
    44
					matches = true;
franta-hg@3
    45
				}
franta-hg@3
    46
			}
franta-hg@3
    47
franta-hg@3
    48
			if (!matches) {
franta-hg@3
    49
				throw new CLIParserException("Unknown option: " + arg);
franta-hg@3
    50
			}
franta-hg@3
    51
		}
franta-hg@3
    52
franta-hg@3
    53
		return options;
franta-hg@3
    54
	}
franta-hg@3
    55
franta-hg@7
    56
	/**
franta-hg@7
    57
	 *
franta-hg@7
    58
	 * @param args
franta-hg@7
    59
	 * @param index
franta-hg@7
    60
	 * @param option name of the option for error messages | if null, the previous argument is used
franta-hg@7
    61
	 * as option name
franta-hg@7
    62
	 * @return
franta-hg@7
    63
	 * @throws CLIParserException
franta-hg@7
    64
	 */
franta-hg@7
    65
	private static String fetchNext(String[] args, int index, String option) throws CLIParserException {
franta-hg@3
    66
		if (index < args.length) {
franta-hg@3
    67
			return args[index];
franta-hg@3
    68
		} else {
franta-hg@7
    69
			option = option == null ? args[index - 1] : option;
franta-hg@7
    70
			throw new CLIParserException("Expecting value for option: " + option);
franta-hg@3
    71
		}
franta-hg@3
    72
	}
franta-hg@3
    73
franta-hg@3
    74
	private static enum Token {
franta-hg@3
    75
franta-hg@3
    76
		INPUT_DIR("--input-dir") { // bash-completion: option
franta-hg@3
    77
					@Override
franta-hg@5
    78
					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
franta-hg@3
    79
						int originalIndex = index;
franta-hg@7
    80
						String name = fetchNext(args, ++index, args[originalIndex]);
franta-hg@3
    81
						options.setInput(new File(name));
franta-hg@3
    82
						return index - originalIndex;
franta-hg@3
    83
					}
franta-hg@3
    84
				},
franta-hg@3
    85
		OUTPUT_DIR("--output-dir") { // bash-completion: option
franta-hg@3
    86
					@Override
franta-hg@5
    87
					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
franta-hg@3
    88
						int originalIndex = index;
franta-hg@7
    89
						String name = fetchNext(args, ++index, args[originalIndex]);
franta-hg@3
    90
						options.setOutput(new File(name));
franta-hg@3
    91
						return index - originalIndex;
franta-hg@3
    92
					}
franta-hg@3
    93
				},
franta-hg@3
    94
		SIZE("--size") { // bash-completion: option
franta-hg@3
    95
					@Override
franta-hg@5
    96
					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
franta-hg@3
    97
						int originalIndex = index;
franta-hg@7
    98
						int width = parseInt(fetchNext(args, ++index, args[originalIndex]));
franta-hg@7
    99
						int height = parseInt(fetchNext(args, ++index, args[originalIndex]));
franta-hg@7
   100
						boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex]));
franta-hg@3
   101
						String directory = width + "x" + height;
franta-hg@7
   102
						options.addSize(new SizeSpecification(width, height, directory, resizeSmaller));
franta-hg@3
   103
						return index - originalIndex;
franta-hg@3
   104
					}
franta-hg@3
   105
				},
franta-hg@3
   106
		SIZE_NAMED("--size-named") { // bash-completion: option
franta-hg@3
   107
					@Override
franta-hg@5
   108
					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
franta-hg@3
   109
						int originalIndex = index;
franta-hg@7
   110
						int width = parseInt(fetchNext(args, ++index, args[originalIndex]));
franta-hg@7
   111
						int height = parseInt(fetchNext(args, ++index, args[originalIndex]));
franta-hg@7
   112
						boolean resizeSmaller = parseBoolean(fetchNext(args, ++index, args[originalIndex]));
franta-hg@7
   113
						String directory = fetchNext(args, ++index, args[originalIndex]);
franta-hg@7
   114
						options.addSize(new SizeSpecification(width, height, directory, resizeSmaller));
franta-hg@3
   115
						return index - originalIndex;
franta-hg@3
   116
					}
franta-hg@14
   117
				},
franta-hg@14
   118
		SKIP_ERRORS("--skip-errors") { // bash-completion: option
franta-hg@14
   119
franta-hg@14
   120
					@Override
franta-hg@14
   121
					public int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException {
franta-hg@14
   122
						options.setSkipErrors(true);
franta-hg@14
   123
						return 0;
franta-hg@14
   124
					}
franta-hg@14
   125
franta-hg@3
   126
				};
franta-hg@3
   127
franta-hg@3
   128
		private final Collection<String> options;
franta-hg@3
   129
franta-hg@3
   130
		private Token(String... options) {
franta-hg@3
   131
			this.options = Arrays.asList(options);
franta-hg@3
   132
		}
franta-hg@3
   133
franta-hg@3
   134
		/**
franta-hg@3
   135
		 * @param option e.g. „--input-file“
franta-hg@3
   136
		 * @return whether option is this token
franta-hg@3
   137
		 */
franta-hg@3
   138
		public boolean matches(String option) {
franta-hg@3
   139
			return options.contains(option);
franta-hg@3
   140
		}
franta-hg@3
   141
franta-hg@3
   142
		private static int parseInt(String number) throws CLIParserException {
franta-hg@3
   143
			try {
franta-hg@3
   144
				return Integer.parseInt(number);
franta-hg@3
   145
			} catch (Exception e) {
franta-hg@3
   146
				throw new CLIParserException("Unable to parse integer: " + number, e);
franta-hg@3
   147
			}
franta-hg@3
   148
		}
franta-hg@3
   149
franta-hg@7
   150
		private static boolean parseBoolean(String value) throws CLIParserException {
franta-hg@7
   151
			switch (value) {
franta-hg@7
   152
				case "true":
franta-hg@7
   153
					return true;
franta-hg@7
   154
				case "false":
franta-hg@7
   155
					return false;
franta-hg@7
   156
				default:
franta-hg@7
   157
					throw new CLIParserException("Value „" + value + "“ is not a valid boolean. Expecting „true“ or „false“.");
franta-hg@7
   158
			}
franta-hg@7
   159
		}
franta-hg@7
   160
franta-hg@3
   161
		/**
franta-hg@3
   162
		 * Parse String arguments and fill values into the options object.
franta-hg@3
   163
		 *
franta-hg@3
   164
		 * @param args CLI arguments
franta-hg@3
   165
		 * @param index index of the option matched by this token, like „--input-file“
franta-hg@3
   166
		 * @param options object to be filled
franta-hg@3
   167
		 * @return number of parsed arguments – if option has no arguments (just boolean flag),
franta-hg@3
   168
		 * return 0, otherwise return positive integer: number of eaten arguments.
franta-hg@3
   169
		 * @throws CLIParserException
franta-hg@3
   170
		 */
franta-hg@5
   171
		public abstract int parse(String[] args, int index, RecursiveOptions options) throws CLIParserException;
franta-hg@3
   172
	}
franta-hg@3
   173
}