// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package common.opt; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * Simple parser of GNU-like options. */ public class OptionParser { public static Option helpOption() { return new Option() { { name = "--help"; alias = "-h"; } }; } /** * Parse options, capture values and return rest of arguments. * * @param args * command line arguments to parse * @param startFrom * number of first argument to start parsing from * @param options * options to fill with values * @return rest of command line after first non-option or "--" separator */ public static String[] parseOptions(String args[], int startFrom, Option options[]) { // Convert array of options into map, where key is option name or alias Map<String, Option> optionMap = new HashMap<String, Option>(options.length); for (Option option : options) { optionMap.put(option.name, option); if (option.alias != null) optionMap.put(option.alias, option); if (option.aliases != null) { for (String alias : option.aliases) optionMap.put(alias, option); } } // Parse arguments int position = startFrom; while (position < args.length) { // Double dash means end of options String optionName = args[position]; if (optionName.equals("--")) { position++; break; } Option option = optionMap.get(optionName); // If option is not found, then this is argument, unless is starts with // dash if (option == null) if (!optionName.startsWith("-")) break; else throw new UnknownOptionException("Option \"" + optionName + "\" is unknown. If this is not an option, then use \"--\" to separate options and arguments. Known options: " + optionMap.keySet().toString()); position += option.parse(position, args); } // Check is required options are used on command line for (Option option : options) { if (option.required && !option.used) throw new OptionRequiredException("Option \"" + option.name + "\" is required."); } // Return rest of arguments, which are left after options return (position < args.length) ? Arrays.copyOfRange(args, position, args.length) : new String[] {}; } /* Example. */ public static void main(String args[]) { if (args.length == 0) args = new String[] {"--help", "--foo", "fooval", "--bar", "123", "-v", "--verbose", "-v", "-a", "a1", "-aa", "a2", "-aaa", "a3", "rest", "of", "arguments"}; StringOption foo = new StringOption() { { name = "--foo"; alias = "-f"; value = "fooDefault"; } }; IntOption bar = new IntOption() { { name = "--bar"; alias = "-b"; value = 123; } }; IncrementalOption verbose = new IncrementalOption() { { name = "--verbose"; alias = "-v"; } }; StringArrayOption array = new StringArrayOption() { { name = "--array"; alias = "-a"; aliases = new String[] {"-aa", "-aaa"}; } }; String arguments[] = OptionParser.parseOptions(args, 0, new Option[] {helpOption(), foo, bar, verbose, array}); assertTrue(foo.value.equals("fooval")); assertTrue(bar.value == 123); assertTrue(verbose.value == 3); assertTrue(Arrays.equals(array.value, new String[] {"a1", "a2", "a3"})); assertTrue(Arrays.equals(arguments, new String[] {"rest", "of", "arguments"})); } public static void assertTrue(boolean result) { if (!result) throw new AssertionError(); } }