Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.freeutils.util.Arguments Maven / Gradle / Ivy
/*
* Copyright © 2003-2024 Amichai Rothman
*
* This file is part of JElementary - the Java Elementary Utilities package.
*
* JElementary is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* JElementary is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JElementary. If not, see .
*
* For additional info see https://www.freeutils.net/source/jelementary/
*/
package net.freeutils.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Parses command-line arguments and options.
*/
public class Arguments {
/**
* A supported command-line option's configuration.
*
* @param the option value type (if it has a value)
*/
protected class Option {
protected final String name;
protected final String abbrev;
protected final Class type;
protected final boolean required;
protected final T def;
/**
* Constructs an option with the given configuration details.
*
* @param name the full name (long option form)
* @param abbrev the abbreviation (short name or letter, i.e. short option form)
* @param type the option value type (if it has a value)
* @param required whether the option is required or not
* @param def a default value if the option is not specified
*/
public Option(String name, String abbrev, Class type, boolean required, T def) {
this.name = name;
this.abbrev = abbrev;
this.type = type;
this.required = required;
this.def = def;
}
/**
* Returns whether this option has the given name or abbreviation.
*
* @param name an option name, or null
* @param abbrev an option abbreviation, or null
* @return true if this option has the given name or abbreviation
*/
public boolean is(String name, String abbrev) {
return name != null && name.equals(this.name)
|| abbrev != null && abbrev.equals(this.abbrev);
}
/**
* Parses a value for this option.
*
* @param value the option value string
* @return the parsed option value, or the default value if the value is null
* and the option is not required
* @throws IllegalArgumentException if value is null and the option is required
*/
public T parse(String value) {
if (value != null)
return Reflect.convert(value, type);
if (!required)
return def;
throw new IllegalArgumentException(
"missing required option --" + name + " or -" + abbrev);
}
}
protected List> options = new ArrayList<>();
protected Map , String> values;
protected List positionals;
/**
* Constructs a new Arguments instance.
*/
public Arguments() {}
/**
* Finds a supported option with the given name or abbreviation.
*
* @param name an option name, or null
* @param abbrev an option abbreviation, or null
* @param throwIfNotFound specifies whether to throw an exception if the option is not found,
* or simply return null
* @param the option value type
* @return the supported option with the given name or abbreviation,
* or null if the option was not found and throwIfNotFound is false
* @throws IllegalArgumentException if throwIfNotFound is true and
* there is no option with the given name or abbreviation
*/
@SuppressWarnings("unchecked")
protected Option find(String name, String abbrev, boolean throwIfNotFound) {
for (Option> opt : options)
if (opt.is(name, abbrev))
return (Option)opt;
if (throwIfNotFound)
throw new IllegalArgumentException("unknown option: " + (name != null ? name : abbrev));
return null;
}
/**
* Finds the supported option specified by the given command-line argument.
*
* @param arg the command-line argument (including prefix dashes)
* @param the option value type
* @return the supported option specified by the given argument,
* or null if the given argument is a positional argument
* and does not reference an option (i.e. it does not start with a dash)
* @throws IllegalArgumentException if there is no supported option matching
* the given argument
*/
protected Option find(String arg) {
if (arg.startsWith("--"))
return find(arg.substring(2), null, true);
if (arg.startsWith("-"))
return find(null, arg.substring(1), true);
return null;
}
/**
* Adds a command-line option to support.
*
* @param option the option to add
* @return this Arguments instance
* @throws IllegalStateException if arguments have already been parsed
* @throws IllegalArgumentException if an option with the same name or abbreviation already exists
*/
protected Arguments add(Option> option) {
if (values != null || positionals != null)
throw new IllegalStateException("cannot add options after arguments were parsed");
if (find(option.name, option.abbrev, false) != null)
throw new IllegalArgumentException("an option with the given name or abbreviation already exists");
options.add(option);
return this;
}
/**
* Adds a command-line option to support.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @param type the option's value type
* @param required whether the option is required or optional
* @param def a default value to use if the option is not specified
* @param the option value type
* @return this Arguments instance
*/
protected Arguments add(String name, String abbrev, Class type, boolean required, T def) {
return add(new Option<>(name, abbrev, type, required, def));
}
/**
* Adds a command-line option to support.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @param type the option's value type
* @param required whether the option is required or optional
* @param the option value type
* @return this Arguments instance
*/
public Arguments add(String name, String abbrev, Class type, boolean required) {
return add(name, abbrev, type, required, null);
}
/**
* Adds a command-line option to support.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @param type the option's value type
* @param def a default value to use if the option is not specified
* @param the option value type
* @return this Arguments instance
*/
public Arguments add(String name, String abbrev, Class type, T def) {
return add(name, abbrev, type, false, def);
}
/**
* Adds a command-line option to support.
* The option is optional and has no default value.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @param type the option's value type
* @param the option value type
* @return this Arguments instance
*/
public Arguments add(String name, String abbrev, Class type) {
return add(name, abbrev, type, null);
}
/**
* Adds a command-line option to support.
* The option is optional, and its value is of type String.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @param def a default value to use if the option is not specified
* @return this Arguments instance
*/
public Arguments add(String name, String abbrev, String def) {
return add(name, abbrev, String.class, def);
}
/**
* Adds a command-line option to support.
* The option is optional, and its value is of type String.
*
* @param name the option full name
* @param abbrev the option abbreviated name (short name or letter)
* @return this Arguments instance
*/
public Arguments add(String name, String abbrev) {
return add(name, abbrev, String.class);
}
/**
* Parses the given command line arguments according to the configured options.
*
* @param args the command-line arguments
* @return this Arguments instance
* @throws IllegalArgumentException if any of the arguments are invalid,
* such as unsupported options or wrong value types
*/
public Arguments parse(String... args) throws IllegalArgumentException {
values = new LinkedHashMap<>();
positionals = new ArrayList<>();
for (int i = 0; i < args.length; i++) {
String arg = args[i];
Option> opt = find(arg);
if (opt == null) {
positionals.add(arg);
} else if (opt.type == boolean.class) {
values.put(opt, "true");
} else if (i == args.length - 1) {
throw new IllegalArgumentException("missing value for option " + arg);
} else {
values.put(opt, args[++i]);
}
}
return this;
}
/**
* Ensures that arguments were parsed.
*
* @throws IllegalStateException if no arguments were parsed
*/
protected void ensureParsed() {
if (values == null || positionals == null)
throw new IllegalStateException("no arguments were parsed");
}
/**
* Returns the number of positional (non-option) arguments.
*
* @return the number of positional (non-option) arguments
*/
public int count() {
return positionals.size();
}
/**
* Returns the value of the named option.
*
* @param name the name of the option
* @param the type of the value
* @return the value of the option
* @throws IllegalStateException if no arguments were parsed
* @throws IllegalArgumentException if there is no supported option with the given name
*/
public T get(String name) {
ensureParsed();
Option opt = find(name, null, true);
return opt.parse(values.get(opt));
}
/**
* Returns the i-th positional argument.
*
* @param i the zero-based index of the positional argument
* @return the i-th positional argument
* @throws IllegalStateException if no arguments were parsed
* @throws IllegalArgumentException if no i-th positional argument was provided
*/
public String get(int i) {
ensureParsed();
if (i >= positionals.size())
throw new IllegalArgumentException("missing argument #" + i
+ ", only " + positionals.size() + " arguments provided");
return positionals.get(i);
}
}