Merge branch 'master' of github.com:qwc/cmdlineoptions into cpp14

This commit is contained in:
Marcel M. Otte 2015-10-27 21:57:27 +01:00
commit b23249d5b9
5 changed files with 411 additions and 78 deletions

View File

@ -7,7 +7,12 @@ Why not using a small and easy library, which does exactly THAT task? Which give
This is the goal of this project. This is a goal of this project.
The main goals of this project are a personal ones:
- to have fun programming similiar behaving code in different languages
- learning new programming languages through adding them to this repository
cmdlineoptions cmdlineoptions
@ -34,12 +39,16 @@ Current work and future plans
=============== ===============
Working on: Working on:
- JUnit tests - ~~JUnit tests~~
- Java: better errorhandling - ~~Java: better errorhandling~~
- Java: Examples - ~~Java: Examples~~
- C version [done] - ~~C version~~
- Getting started - Getting started
- Unit tests
- ~~Some java improvements~~
- get the improvments into the C version
Future plans: Future plans:
- C++ class version - C++ class version
- haskell
- ... - ...

View File

@ -2,5 +2,6 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
/** /**
* Written by Marcel M. Otte, (c) 2013 For use under the BSD 2-clause License, * Written by Marcel M. Otte, (c) 2013 For use under the BSD 2-clause License,
@ -16,15 +17,26 @@ public class CmdOptions {
private static CmdOptions instance; private static CmdOptions instance;
private static String optionChar;
private HashMap<String, Option> options;
private boolean showOptions;
private boolean combineSwitches;
private boolean dontQuitOnError;
public static class Option { public static class Option {
private String name; private String name;
private ArrayList<String> cmd; private ArrayList<String> cmd;
private ArrayList<String> cmdLong;
private String description; private String description;
private ArrayList<String> defaultParameter; private ArrayList<String> defaultParameter;
private ArrayList<String> possibleParams; private ArrayList<String> possibleParams;
private boolean set; private boolean set;
private boolean required;
private ArrayList<String> values; private ArrayList<String> values;
private int maxParameters, minParameters;
private ArrayList<String> examples;
private int stepSizeParameters;
public ArrayList<String> getValues() { public ArrayList<String> getValues() {
return values; return values;
@ -37,15 +49,31 @@ public class CmdOptions {
public Option() { public Option() {
values = new ArrayList<String>(); values = new ArrayList<String>();
cmd = new ArrayList<String>(); cmd = new ArrayList<String>();
cmdLong = new ArrayList<String>();
defaultParameter = new ArrayList<String>(); defaultParameter = new ArrayList<String>();
possibleParams = new ArrayList<String>(); possibleParams = new ArrayList<String>();
examples = new ArrayList<String>();
} }
public Option addCommand(String cmd) { public Option addCommand(String cmd) {
if (cmd.contains(optionChar)) {
cmd = cmd.replace(optionChar, "");
}
if (cmd.length() > 1) {
throw new IllegalArgumentException(
"Command longer than 1 character, which is not allowed. Use 'addLongCommand()' instead!");
}
this.cmd.add(cmd); this.cmd.add(cmd);
return this; return this;
} }
public Option addLongCommand(String cmd) {
if (cmd.contains(optionChar))
cmd = cmd.replace(optionChar, "");
this.cmdLong.add(cmd);
return this;
}
public Option addDefaultParameter(String d) { public Option addDefaultParameter(String d) {
this.defaultParameter.add(d); this.defaultParameter.add(d);
return this; return this;
@ -70,6 +98,17 @@ public class CmdOptions {
return this; return this;
} }
public Option setParameterCount(int min, int max) {
return this.setParameterCount(min, max, 0);
}
public Option setParameterCount(int min, int max, int step) {
this.minParameters = min;
this.maxParameters = max;
this.stepSizeParameters = step;
return this;
}
public String getDescription() { public String getDescription() {
return description; return description;
} }
@ -79,25 +118,55 @@ public class CmdOptions {
return this; return this;
} }
public Option setRequired(boolean required) {
this.required = true;
return this;
}
public boolean isSet() { public boolean isSet() {
return set; return set;
} }
public boolean valuesContains(String value) {
return values.contains(value);
}
public int getIndexOf(String value) {
return values.indexOf(value);
}
public Option setSet(boolean set) { public Option setSet(boolean set) {
this.set = set; this.set = set;
return this; return this;
} }
public Option addExample(String example) {
this.examples.add(example);
return this;
}
public String toString() { public String toString() {
String ret = name + " ("; return toString(false);
}
public String toString(boolean help) {
String ret = name;
ret += " (";
for (String s : cmd) { for (String s : cmd) {
ret += optionChar + s + ", ";
}
for (String s : cmdLong) {
ret += optionChar + optionChar + s + ", ";
}
ret += ")";
if (help && defaultParameter.size() > 0) {
ret += ": default=";
for (String s : defaultParameter) {
ret += s + ","; ret += s + ",";
} }
ret += ")" }
+ (defaultParameter != null ? ": default=" ret += (help && description != null ? "\n\t\t" + description : "");
+ defaultParameter : "") if (help && possibleParams.size() > 0) {
+ (description != null ? "\n\t\t" + description : "");
if (possibleParams != null) {
boolean start = true; boolean start = true;
ret += "\n\t\t(Possible parameters: "; ret += "\n\t\t(Possible parameters: ";
for (String s : possibleParams) { for (String s : possibleParams) {
@ -123,14 +192,16 @@ public class CmdOptions {
} }
} }
private HashMap<String, Option> options;
private CmdOptions() { private CmdOptions() {
optionChar = "-";
this.setSwitchCombination(false);
this.setShowOptions(false);
this.setDontQuitOnError(false);
options = new HashMap<String, Option>(); options = new HashMap<String, Option>();
this.createOption("help") this.createOption("help")
.setDescription( .setDescription(
"Show all possible options and their parameters.") "Show all possible options and their parameters.")
.addCommand("--help").addCommand("-h").addCommand("-?"); .addLongCommand("--help").addCommand("-h").addCommand("-?");
} }
public static CmdOptions i() { public static CmdOptions i() {
@ -140,6 +211,28 @@ public class CmdOptions {
return instance; return instance;
} }
public void setSwitchCombination(boolean on) {
this.combineSwitches = on;
}
public void setOptionCharacter(String c) {
this.optionChar = c;
}
public void setDontQuitOnError(boolean set) {
this.dontQuitOnError = set;
}
public void setShowOptions(boolean show) {
this.showOptions = show;
}
public void setHelpGeneration(boolean on) {
if (!on) {
options.remove("help");
}
}
public Option createOption(String name) { public Option createOption(String name) {
Option o = new Option(); Option o = new Option();
o.setName(name); o.setName(name);
@ -147,6 +240,22 @@ public class CmdOptions {
return o; return o;
} }
public Option getBareOption(String name) {
return options.get(name);
}
public String[] get(String name) {
return getOption(name);
}
public String get(String name, int index) {
String[] values = getOption(name);
if (values.length > index && index > 0) {
return values[index];
}
return null;
}
public String[] getOption(String name) { public String[] getOption(String name) {
if (options.get(name).values.size() > 0) if (options.get(name).values.size() > 0)
return options.get(name).values.toArray(new String[0]); return options.get(name).values.toArray(new String[0]);
@ -155,6 +264,13 @@ public class CmdOptions {
return null; return null;
} }
public List<String> getValuesAsList(String name) {
if (options.get(name).getValues().size() > 0) {
return options.get(name).getValues();
}
return null;
}
public Integer[] getOptionAsInt(String name) { public Integer[] getOptionAsInt(String name) {
if (options.get(name).values.size() > 0) { if (options.get(name).values.size() > 0) {
ArrayList<Integer> list = new ArrayList<Integer>(); ArrayList<Integer> list = new ArrayList<Integer>();
@ -172,6 +288,14 @@ public class CmdOptions {
return null; return null;
} }
public Integer getOptionAsInt(String name, int index) {
Integer[] array = getOptionAsInt(name);
if (index >= 0 && index < array.length) {
return array[index];
}
return null;
}
public Double[] getOptionAsDouble(String name) { public Double[] getOptionAsDouble(String name) {
if (options.get(name).values.size() > 0) { if (options.get(name).values.size() > 0) {
ArrayList<Double> list = new ArrayList<Double>(); ArrayList<Double> list = new ArrayList<Double>();
@ -189,17 +313,30 @@ public class CmdOptions {
return null; return null;
} }
public Double getOptionAsDouble(String name, int index) {
Double[] array = getOptionAsDouble(name);
if (index >= 0 && index < array.length) {
return array[index];
}
return null;
}
public boolean isSet(String option) { public boolean isSet(String option) {
return options.get(option).set; return options.get(option).set;
} }
public boolean isSet(String option, String parameter) { public boolean isSet(String option, String parameter) {
for (String o : options.get(option).values) { return this.getValuesAsList(option).contains(parameter);
if (o.equals(parameter)) { }
return true;
public void resetValues() {
for (Option o : options.values()) {
o.values.clear();
} }
} }
return false;
public void reset() {
options.clear();
} }
public String toString(boolean help) { public String toString(boolean help) {
@ -216,72 +353,173 @@ public class CmdOptions {
} }
}); });
for (Option o : vars) { for (Option o : vars) {
b.append("\t").append(o.toString()).append("\n"); b.append("\t").append(o.toString(help)).append("\n");
} }
b.append("/options\n"); b.append("/options\n");
return b.toString(); return b.toString();
} }
public void parse(String[] args) { private Integer[] getIndices(String[] args) {
List<Integer> indices = new ArrayList<Integer>();
for (int i = 0; i < args.length; ++i) {
if (args[i].startsWith(optionChar)) {
indices.add(i);
}
}
return indices.toArray(new Integer[0]);
}
private Option getOptionByCommand(String cmd) {
for (Option o : this.options.values()) {
for (String s : o.cmd) {
if (cmd.equals(s)) {
return o;
}
}
for (String s : o.cmdLong) {
if (cmd.equals(s)) {
return o;
}
}
}
return null;
}
private boolean cmdExists(String cmd) {
return getOptionByCommand(cmd) != null;
}
private boolean switchExists(char c) {
for (Option op : this.options.values()) {
for (String s : op.cmd) {
if (s.toCharArray()[0] == c) {
return true;
}
}
}
return false;
}
private Option[] getOptionBySwitches(String switches) {
List<Option> o = new ArrayList<CmdOptions.Option>();
for (Option op : this.options.values()) {
for (String s : op.cmd) {
for (char c : switches.toCharArray()) {
if (s.toCharArray()[0] == c) {
o.add(op);
}
}
}
}
return o.toArray(new Option[0]);
}
public int parse(String[] args) {
int exit = 0;
// get indices
Integer[] indices = getIndices(args);
// check for correct options
boolean ok = true;
for (Integer i : indices) {
String o = args[i].replace(optionChar, "");
if (!cmdExists(o)) {
if (this.combineSwitches) {
for (char c : o.toCharArray()) {
if (!switchExists(c)) {
System.err.println("Unrecognized switch '" + c
+ "'");
ok = false;
}
}
} else {
System.err.println("Unrecognized option '" + o + "'");
ok = false;
}
}
}
// quit if there are unknown options
if (!ok && exit == 0) {
exit = 1;
}
// now parse // now parse
if (args.length > 0) { Option op;
int i = 0; for (int a = 0; a < indices.length; ++a) {
String arg = null; String o = args[indices[a]].replace(optionChar, "");
// iterate through all options op = this.getOptionByCommand(o);
for (; i < args.length; ++i) { if (op == null) {
arg = args[i]; if (this.combineSwitches) {
Option o = null; Option[] mop = getOptionBySwitches(o);
// search for correct option for (Option opt : mop) {
for (Option op : options.values()) { opt.setSet(true);
for (String s : op.cmd)
if (arg.equals(s)) {
o = op;
break;
} }
} }
// if it is unknown
if (o == null) {
System.err.println("Unrecognized option '" + arg + "'");
continue; continue;
} }
o.set = true; // the option is set!
// now iterate through the parameters op.setSet(true);
int j = i + 1; // are there parameters?
while (args.length > j && !args[j].startsWith("-")) { if (indices[a] < args.length - 1 && a < indices.length - 1
if (o.possibleParams.size() > 0) { && indices[a + 1] - indices[a] > 1) {
if (o.possibleParams.contains(args[j])) // parameters between options
o.values.add(args[j]); for (int b = indices[a] + 1; b < indices[a + 1]; ++b) {
else op.getValues().add(args[b]);
System.err.println("Parameter \"" + args[j]
+ "\" for Option \"" + o.name
+ "\" not allowed!");
} else {
o.values.add(args[j]);
} }
++j; } else if (a == indices.length - 1 && args.length - 1 > indices[a]) {
} // parameters at the last option
i = j - 1; for (int b = indices[a] + 1; b < args.length; ++b) {
op.getValues().add(args[b]);
} }
} }
if (options.get("help").set) { }
System.out.println(this.toString(true));
System.exit(0); // check for possible parameters
for (Option o : options.values()) {
for (String s : o.getValues()) {
if (o.possibleParams.size() > 0
&& !o.possibleParams.contains(s)) {
System.err.println("Parameter \"" + s + "\" for Option \""
+ o.name + "\" not allowed!");
ok = false;
}
}
}
if (!ok && exit == 0) {
exit = 2;
}
// check parameter counts
for (Option o : options.values()) {
if (o.getValues().size() < o.minParameters && o.minParameters != 0
|| o.getValues().size() > o.maxParameters
&& o.maxParameters != 0 || o.stepSizeParameters != 0
&& o.getValues().size() % o.stepSizeParameters != 0) {
System.err.println(o.name
+ ": Parameter count not correct! Check help.");
exit = 3;
}
} }
// set default for that options that aren't set // set default for that options that aren't set
for (Option o : options.values()) { for (Option o : options.values()) {
if (!o.set && o.defaultParameter != null if (!o.set && o.required) {
&& o.defaultParameter.equals("")) {
System.err System.err
.println(o.name .println(o.name
+ " (" + " ("
+ o.getName() + o.getName()
+ "): has no default parameter and has to be set on commandline!"); + "): has no default parameter and has to be set on commandline!");
System.exit(1); exit = 4;
} }
if (!o.set && o.defaultParameter != null) if (!o.set && o.defaultParameter.size() != 0)
o.values.addAll(o.defaultParameter); o.values.addAll(o.defaultParameter);
} }
if (options.get("help").set || exit > 0) {
System.out.println(this.toString(true));
if (!this.dontQuitOnError)
System.exit(exit);
}
if (this.showOptions) {
System.out.println(this.toString(false)); System.out.println(this.toString(false));
} }
return exit;
}
} }

View File

@ -8,26 +8,27 @@ public class Example {
CmdOptions.i().createOption("name").// give the option a name which you CmdOptions.i().createOption("name").// give the option a name which you
// can // can
// remember within your project // remember within your project
addCommand("--name") // it's always good to define a long addLongCommand("--name"). // it's always good to define a
// long
// commandline parameter with a // commandline parameter with a
// describing name // describing name
.addCommand("-n") // of course, programmer are always lazy so addCommand("-n"). // of course, programmer are always lazy so
// give them an possibility to shortcut your // give them an possibility to shortcut your
// option // option
.addDefaultParameter("whatever")// a default parameter is good addDefaultParameter("whatever").// a default parameter is good
// if you need the option within // if you need the option within
// your program, but don't care // your program, but don't care
// when it's omitted on // when it's omitted on
// execution // execution
.setDescription("an example option.");// And of course a setDescription("an example option.");// And of course a
// description... for // description... for
// the help readers, the // the help readers, the
// few among us... // few among us...
CmdOptions CmdOptions
.i() .i()
.createOption("complex") .createOption("complex")
.addCommand("--complex") .addLongCommand("--complex")
// see above // see above
// yes you can omit a default parameter, but you have to // yes you can omit a default parameter, but you have to
// check later in your project if that option is set. // check later in your project if that option is set.
@ -42,7 +43,7 @@ public class Example {
// here you are able to add some more alternatives for that // here you are able to add some more alternatives for that
// option, so here you can use "--complex", "-c", "-i" and // option, so here you can use "--complex", "-c", "-i" and
// "--ccp" to trigger this option. // "--ccp" to trigger this option.
.addCommand("-i").addCommand("--ccp"); .addCommand("-i").addLongCommand("--ccp");
} }

View File

@ -0,0 +1,84 @@
package to.mmo.cmdlineoptions.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import to.mmo.cmdlineoptions.CmdOptions;
public class Tests {
@Before
public void setupCmdOptions() {
CmdOptions.i().createOption("test").addCommand("t")
.addLongCommand("test").setParameterCount(0, 1);
CmdOptions.i().createOption("test2").addCommand("f");
CmdOptions.i().createOption("complex").addCommand("c")
.addLongCommand("complex").addDefaultParameter("wtf")
.addPossibleParameter("wtf").addPossibleParameter("wth");
}
@Test
public void testSingle() {
CmdOptions.i().setShowOptions(false);
String argstr = "-t";
String[] args = argstr.split(" ");
CmdOptions.i().parse(args);
assertTrue(CmdOptions.i().isSet("test"));
// assertEquals("test", CmdOptions.i().get("test")[0]);
}
@Test
public void testSingle2() {
CmdOptions.i().setShowOptions(false);
String argstr = "-t test";
String[] args = argstr.split(" ");
CmdOptions.i().parse(args);
assertTrue(CmdOptions.i().isSet("test"));
assertEquals("test", CmdOptions.i().get("test")[0]);
}
@Test
public void testMore() {
CmdOptions.i().setSwitchCombination(true);
CmdOptions.i().setShowOptions(false);
String argstr = "-tf";
String[] args = argstr.split(" ");
CmdOptions.i().parse(args);
assertTrue(CmdOptions.i().isSet("test"));
assertTrue(CmdOptions.i().isSet("test2"));
}
@Test
public void testMoreSwitches() {
CmdOptions.i().setSwitchCombination(true);
CmdOptions.i().setShowOptions(true);
CmdOptions.i().setDontQuitOnError(true);
String argstr = "-tsf";
String[] args = argstr.split(" ");
int e = CmdOptions.i().parse(args);
assertEquals(1, e);
}
@Test
public void testComplex() {
CmdOptions.i().setSwitchCombination(true);
CmdOptions.i().setShowOptions(true);
String argstr = "-tf -c wth";
String[] args = argstr.split(" ");
CmdOptions.i().parse(args);
}
@After
public void reset() {
CmdOptions.i().resetValues();
}
}