diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md
index 6db6daed42..5787f9dd1f 100644
--- a/doc/CHANGELOG.md
+++ b/doc/CHANGELOG.md
@@ -21,6 +21,12 @@ Further documentation can be found in:
`make -C $DAIKONDIR/java javadoc`
It is also available at .
+## Version 5.9.1 (???, 2026)
+
+* Daikon and its tools now reject a malformed command-line option.
+* `daikon.diff.Diff` no longer accepts the `-u` and `-z` options, which had
+ no effect.
+
## Version 5.9.0 (September 1, 2026)
* All Daikon tools now work with Java 8-26.
diff --git a/doc/daikon.texinfo b/doc/daikon.texinfo
index 2c7d2f72e6..63824ae74e 100644
--- a/doc/daikon.texinfo
+++ b/doc/daikon.texinfo
@@ -6749,9 +6749,6 @@ invariants must be justified. Does not print ``uninteresting'' invariants
Display the tree of all invariants. Includes invariants that are the
same in @var{file1} and @var{file2}, and unjustified invariants.
-@item -u
-Include ``uninteresting'' invariants in the tree of differing invariants.
-
@item -y
@itemx --ignore_unjustified
Include (statistically) unjustified invariants.
diff --git a/java/Makefile b/java/Makefile
index ce436e5d69..886b00683b 100644
--- a/java/Makefile
+++ b/java/Makefile
@@ -181,7 +181,7 @@ JAVADOC_COMMAND := ${JAVADOC} -cp ${DAIKON_CLASSPATH}
JAVAC_COMMAND := ${JAVAC} -cp ${DAIKON_CLASSPATH} -Xlint -J-Xmx7g ${JAVAC_ARGS}
JAVA_COMMAND := ${JAVA} -cp ${DAIKON_CLASSPATH}
-DOCLETPATH := ${DAIKONDIR}/java:$(wildcard ${DAIKONDIR}/java/lib/bcel-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/plume-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/reflection-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/hashmap-util-*.jar):${DAIKONDIR}/java/lib/daikon-plumelib.jar
+DOCLETPATH := ${DAIKONDIR}/java:$(wildcard ${DAIKONDIR}/java/lib/java-getopt-*.jar):$(wildcard ${DAIKONDIR}/java/lib/bcel-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/plume-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/reflection-util-*.jar):$(wildcard ${DAIKONDIR}/java/lib/hashmap-util-*.jar):${DAIKONDIR}/java/lib/daikon-plumelib.jar
DOCLET_FLAGS :=
LINKOFFLINE := https://docs.oracle.com/javase/8/docs/api/
diff --git a/java/daikon/Daikon.java b/java/daikon/Daikon.java
index 1e7c1e1b73..aaa2b3f3d6 100644
--- a/java/daikon/Daikon.java
+++ b/java/daikon/Daikon.java
@@ -1022,7 +1022,6 @@ static FileOptions read_options(String[] args, String usage) {
LongOpt[] longopts =
new LongOpt[] {
// Control output
- new LongOpt(help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(no_text_output_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(show_progress_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
@@ -1055,7 +1054,7 @@ static FileOptions read_options(String[] args, String usage) {
new LongOpt(disc_reason_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(mem_stat_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.Daikon", args, "ho:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
@@ -1065,10 +1064,7 @@ static FileOptions read_options(String[] args, String usage) {
String option_name = longopts[g.getLongind()].getName();
// Control output
- if (help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (no_text_output_SWITCH.equals(option_name)) {
+ if (no_text_output_SWITCH.equals(option_name)) {
no_text_output = true;
} else if (format_SWITCH.equals(option_name)) {
String format_name = getOptarg(g);
@@ -1367,12 +1363,9 @@ else if (ppt_regexp_SWITCH.equals(option_name)) {
} else if (mem_stat_SWITCH.equals(option_name)) {
use_mem_monitor = true;
} else {
- throw new Daikon.UserError("Unknown option " + option_name + " on command line");
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
case 'o':
String inv_filename = getOptarg(g);
@@ -1391,11 +1384,6 @@ else if (ppt_regexp_SWITCH.equals(option_name)) {
}
break;
//
- case '?':
- // break; // getopt() already printed an error
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- //
default:
throw new Daikon.BugInDaikon("getopt() returned " + c);
}
diff --git a/java/daikon/DaikonGetopt.java b/java/daikon/DaikonGetopt.java
new file mode 100644
index 0000000000..26bf668530
--- /dev/null
+++ b/java/daikon/DaikonGetopt.java
@@ -0,0 +1,125 @@
+package daikon;
+
+import static daikon.tools.nullness.NullnessUtil.castNonNull;
+
+import gnu.getopt.Getopt;
+import gnu.getopt.LongOpt;
+import org.plumelib.util.ArraysPlume;
+
+/**
+ * A command-line option processor that throws a {@link Daikon.UserError} that describes a bad
+ * command-line option, instead of printing a message and returning {@code '?'} or {@code ':'}. It
+ * also handles {@code -h} and {@code --help}: it prints the usage message and throws {@link
+ * Daikon.NormalTermination}.
+ */
+public class DaikonGetopt extends Getopt {
+
+ /**
+ * The name passed to {@link Getopt}, which uses it only in messages that DaikonGetopt suppresses.
+ */
+ private static final String PROGNAME = "DaikonGetopt";
+
+ /** The usage message printed for {@code -h} and {@code --help}. */
+ private final String usage;
+
+ /**
+ * Creates a command-line option processor that recognizes short and long options, plus {@code -h}
+ * and {@code --help}, which print the usage message and throw {@link Daikon.NormalTermination}.
+ *
+ * @param argv the command-line arguments
+ * @param optstring the short options, in the format of {@link Getopt}; must not contain {@code h}
+ * @param longopts the long options; must not contain {@code help}
+ * @param usage the usage message to print for {@code -h} and {@code --help}
+ */
+ public DaikonGetopt(String[] argv, String optstring, LongOpt[] longopts, String usage) {
+ super(
+ PROGNAME,
+ argv,
+ optstring + "h",
+ ArraysPlume.append(
+ longopts, new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 'h')));
+ this.usage = usage;
+ opterr = false;
+ }
+
+ /**
+ * Like {@link Getopt#getopt()}, but never returns {@code '?'}, {@code ':'}, or {@code 'h'}.
+ * Getopt returns {@code ':'} for a missing argument if the optstring starts with {@code ':'}.
+ *
+ * @return the next option, as described in {@link Getopt#getopt()}
+ * @throws Daikon.UserError if the next option is unrecognized, ambiguous, or malformed
+ * @throws Daikon.NormalTermination after printing the usage message, if the next option is {@code
+ * -h} or {@code --help}
+ */
+ @Override
+ public int getopt() {
+ int c = super.getopt();
+ if (c == '?' || c == ':') {
+ throw new Daikon.UserError(badOptionMessage() + "; run with -h for usage");
+ }
+ if (c == 'h') {
+ System.out.println(usage);
+ throw new Daikon.NormalTermination();
+ }
+ return c;
+ }
+
+ /**
+ * Returns a description of the bad command-line option that {@link Getopt#getopt()} just
+ * rejected.
+ *
+ * @return a description of the bad command-line option
+ */
+ private String badOptionMessage() {
+ // For every bad long option, Getopt clears nextchar and advances optind past the option. A
+ // bad short option has no such guarantee, because it may be followed by other short options in
+ // the same argument, as in "-xh".
+ if ("".equals(nextchar) && argv[optind - 1].startsWith("--")) {
+ return longOptionMessage(argv[optind - 1]);
+ }
+ char c = (char) optopt;
+ if (c == ':' || optstring.indexOf(c) == -1) {
+ return "Unrecognized command-line option -" + c;
+ } else {
+ return "Command-line option -" + c + " requires an argument";
+ }
+ }
+
+ /**
+ * Returns a description of a bad long command-line option. Uses {@code longind}, which Getopt
+ * sets to the index of the long option that matched the argument, or to -1 if none matched.
+ *
+ * @param arg the bad command-line argument, which starts with "--"
+ * @return a description of the bad command-line option
+ */
+ private String longOptionMessage(String arg) {
+ int equalsPos = arg.indexOf('=');
+ String name = (equalsPos == -1) ? arg.substring(2) : arg.substring(2, equalsPos);
+ // Getopt treats an empty name, as in "--=foo", as a prefix of every long option.
+ if (name.isEmpty()) {
+ return "Unrecognized command-line option " + arg;
+ }
+ if (longind == -1) {
+ return "Unrecognized command-line option --" + name;
+ }
+ // Every constructor passes long options to Getopt.
+ LongOpt[] longopts = castNonNull(long_options);
+ LongOpt match = longopts[longind];
+ // For an inexact match, Getopt sets longind to the first long option that has the given
+ // prefix. The match is ambiguous if a later long option also has the prefix.
+ if (!match.getName().equals(name)) {
+ for (int i = longind + 1; i < longopts.length; i++) {
+ if (longopts[i].getName().startsWith(name)) {
+ return "Ambiguous command-line option --" + name;
+ }
+ }
+ }
+ if (equalsPos != -1 && match.getHasArg() == LongOpt.NO_ARGUMENT) {
+ return "Command-line option --" + match.getName() + " does not take an argument";
+ } else if (equalsPos == -1 && match.getHasArg() == LongOpt.REQUIRED_ARGUMENT) {
+ return "Command-line option --" + match.getName() + " requires an argument";
+ } else {
+ throw new Daikon.BugInDaikon("Getopt rejected " + arg + " for no known reason");
+ }
+ }
+}
diff --git a/java/daikon/MergeInvariants.java b/java/daikon/MergeInvariants.java
index bc2009da5d..8a814a80fb 100644
--- a/java/daikon/MergeInvariants.java
+++ b/java/daikon/MergeInvariants.java
@@ -5,7 +5,6 @@
import daikon.split.PptSplitter;
import daikon.suppress.NIS;
-import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import java.io.FileNotFoundException;
@@ -97,14 +96,13 @@ public static void mainHelper(String[] args)
LongOpt[] longopts =
new LongOpt[] {
- new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.MergeInvariants", args, "ho:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
@@ -112,10 +110,7 @@ public static void mainHelper(String[] args)
// long option
case 0:
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.config_option_SWITCH.equals(option_name)) {
+ if (Daikon.config_option_SWITCH.equals(option_name)) {
String item = Daikon.getOptarg(g);
daikon.config.Configuration.getInstance().apply(item);
break;
@@ -133,14 +128,10 @@ public static void mainHelper(String[] args)
"Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error);
}
} else {
- throw new Daikon.UserError("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
-
case 'o':
String output_inv_filename = Daikon.getOptarg(g);
@@ -160,12 +151,8 @@ public static void mainHelper(String[] args)
}
break;
- case '?':
- break; // getopt() already printed an error
-
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/PrintInvariants.java b/java/daikon/PrintInvariants.java
index f7bc9121c3..57f483661d 100644
--- a/java/daikon/PrintInvariants.java
+++ b/java/daikon/PrintInvariants.java
@@ -24,7 +24,6 @@
import daikon.split.PptSplitter;
import daikon.suppress.NIS;
import daikon.suppress.NISuppressionSet;
-import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.BufferedWriter;
import java.io.File;
@@ -329,7 +328,6 @@ public static void mainHelper(String[] args)
LongOpt[] longopts =
new LongOpt[] {
- new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(Daikon.suppress_redundant_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.output_num_samples_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
@@ -344,17 +342,14 @@ public static void mainHelper(String[] args)
new LongOpt(
PrintInvariants.print_csharp_metadata_SWITCH, LongOpt.OPTIONAL_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.PrintInvariants", args, "h", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.ppt_regexp_SWITCH.equals(option_name)) {
+ if (Daikon.ppt_regexp_SWITCH.equals(option_name)) {
if (ppt_regexp != null) {
throw new Error(
"multiple --"
@@ -430,17 +425,11 @@ public static void mainHelper(String[] args)
} else if (Daikon.wrap_xml_SWITCH.equals(option_name)) {
wrap_xml = true;
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/UnionInvariants.java b/java/daikon/UnionInvariants.java
index ea34b0f075..c07e19d7ce 100644
--- a/java/daikon/UnionInvariants.java
+++ b/java/daikon/UnionInvariants.java
@@ -1,6 +1,5 @@
package daikon;
-import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import org.plumelib.util.FilesPlume;
@@ -52,25 +51,19 @@ public static void mainHelper(String[] args) throws Exception {
new LongOpt[] {
new LongOpt(Daikon.suppress_redundant_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.UnionInvariants", args, "ho:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.suppress_redundant_SWITCH.equals(option_name)) {
+ if (Daikon.suppress_redundant_SWITCH.equals(option_name)) {
Daikon.suppress_redundant_invariants_with_simplify = true;
} else {
- throw new Daikon.UserError("Unknown option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
case 'o':
String inv_filename = Daikon.getOptarg(g);
@@ -90,11 +83,8 @@ public static void mainHelper(String[] args) throws Exception {
}
break;
//
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/diff/Diff.java b/java/daikon/diff/Diff.java
index 0019d1e935..324406bafb 100644
--- a/java/daikon/diff/Diff.java
+++ b/java/daikon/diff/Diff.java
@@ -4,13 +4,13 @@
import static java.util.logging.Level.INFO;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.FileIO;
import daikon.Ppt;
import daikon.PptConditional;
import daikon.PptMap;
import daikon.PptTopLevel;
import daikon.inv.Invariant;
-import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import java.io.FileNotFoundException;
@@ -68,13 +68,19 @@ public final class Diff {
" For a list of flags, see the Daikon manual, which appears in the ",
" Daikon distribution and also at http://plse.cs.washington.edu/daikon/.");
- /** The long command line options. */
- private static final String HELP_SWITCH = "help";
-
+ /** The long command-line option that specifies the comparator to sort the first set of invs. */
private static final String INV_SORT_COMPARATOR1_SWITCH = "invSortComparator1";
+
+ /** The long command-line option that specifies the comparator to sort the second set of invs. */
private static final String INV_SORT_COMPARATOR2_SWITCH = "invSortComparator2";
+
+ /** The long command-line option that specifies the comparator to pair up invs. */
private static final String INV_PAIR_COMPARATOR_SWITCH = "invPairComparator";
+
+ /** The long command-line option that is a synonym for -y. */
private static final String IGNORE_UNJUSTIFIED_SWITCH = "ignore_unjustified";
+
+ /** The long command-line option that ignores numbered exit points. */
private static final String IGNORE_NUMBERED_EXITS_SWITCH = "ignore_exitNN";
/** Determine which ppts should be paired together in the tree. */
@@ -193,7 +199,6 @@ public static void mainHelper(final String[] args)
LongOpt[] longOpts =
new LongOpt[] {
- new LongOpt(HELP_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(INV_SORT_COMPARATOR1_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(INV_SORT_COMPARATOR2_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(INV_PAIR_COMPARATOR_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
@@ -201,20 +206,14 @@ public static void mainHelper(final String[] args)
new LongOpt(IGNORE_NUMBERED_EXITS_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
};
- Getopt g =
- new Getopt(
- "daikon.diff.Diff", args,
- "Hhyduastmxno:jzpevl", longOpts);
+ DaikonGetopt g = new DaikonGetopt(args, "Hydastmxno:jpevl", longOpts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String optionName = longOpts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(optionName)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (INV_SORT_COMPARATOR1_SWITCH.equals(optionName)) {
+ if (INV_SORT_COMPARATOR1_SWITCH.equals(optionName)) {
if (invSortComparator1Classname != null) {
throw new Error(
"multiple --"
@@ -252,12 +251,9 @@ public static void mainHelper(final String[] args)
ignoreNumberedExits = true;
break;
} else {
- throw new RuntimeException("Unknown long option received: " + optionName);
+ throw new Daikon.BugInDaikon("Unhandled long option " + optionName);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
case 'H':
PrintAllVisitor.HUMAN_OUTPUT = true;
break;
@@ -318,13 +314,8 @@ public static void mainHelper(final String[] args)
case 'l':
logging = true;
break;
- case '?':
- // getopt() already printed an error
- System.out.println(usage);
- throw new Daikon.UserError("Bad argument");
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
@@ -422,8 +413,7 @@ public static void mainHelper(final String[] args)
v1.printAll();
return;
} else {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
+ throw new Daikon.UserError("No invariant files specified; run with -h for usage");
}
if (logging) {
diff --git a/java/daikon/test/AllTestsSuite.java b/java/daikon/test/AllTestsSuite.java
index 7d74e7e7ac..9a817b266f 100644
--- a/java/daikon/test/AllTestsSuite.java
+++ b/java/daikon/test/AllTestsSuite.java
@@ -7,6 +7,7 @@
@RunWith(Suite.class)
@Suite.SuiteClasses({
daikon.chicory.RuntimeTest.class,
+ daikon.test.BadOptionTest.class,
daikon.test.TestClassOrInterfaceTypeDecorateVisitor.class,
daikon.test.TestAst.class,
daikon.test.config.ConfigurationTest.class,
diff --git a/java/daikon/test/BadOptionTest.java b/java/daikon/test/BadOptionTest.java
new file mode 100644
index 0000000000..0f50ea31e2
--- /dev/null
+++ b/java/daikon/test/BadOptionTest.java
@@ -0,0 +1,176 @@
+package daikon.test;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import daikon.Daikon;
+import daikon.DaikonGetopt;
+import daikon.PrintInvariants;
+import daikon.UnionInvariants;
+import daikon.tools.DtraceDiff;
+import gnu.getopt.LongOpt;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
+
+/**
+ * Tests that Daikon tools reject bad command-line options with a UserError.
+ *
+ *
These tests do not call {@code Daikon.mainHelper}, because it resets Daikon's global state,
+ * which other tests in the same JVM depend on.
+ */
+public class BadOptionTest {
+
+ /** The long options used by {@link #parse}. DaikonGetopt adds {@code --help}. */
+ private static final LongOpt[] longopts =
+ new LongOpt[] {
+ new LongOpt("config", LongOpt.REQUIRED_ARGUMENT, null, 0),
+ new LongOpt("config_option", LongOpt.REQUIRED_ARGUMENT, null, 0),
+ new LongOpt("debug", LongOpt.REQUIRED_ARGUMENT, null, 'd'),
+ new LongOpt("verbose", LongOpt.NO_ARGUMENT, null, 'v'),
+ };
+
+ /** The suffix of every description of a bad command-line option. */
+ private static final String USAGE_HINT = "; run with -h for usage";
+
+ /**
+ * Parses the given command-line arguments, which must contain a bad option, and returns the
+ * resulting error message, without its suffix that suggests running with -h.
+ *
+ * @param optstring the short options, in the format of Getopt
+ * @param args command-line arguments
+ * @return the message of the UserError for the bad option, without {@link #USAGE_HINT}
+ */
+ private static String parseWith(String optstring, String... args) {
+ DaikonGetopt g = new DaikonGetopt(args, optstring, longopts, "usage");
+ Daikon.UserError e = assertThrows(Daikon.UserError.class, () -> consumeAll(g));
+ String message = String.valueOf(e.getMessage());
+ assertTrue(message, message.endsWith(USAGE_HINT));
+ return message.substring(0, message.length() - USAGE_HINT.length());
+ }
+
+ /**
+ * Parses the given command-line arguments, which must contain a bad option, and returns the
+ * resulting error message, without its suffix that suggests running with -h.
+ *
+ * @param args command-line arguments
+ * @return the message of the UserError for the bad option, without {@link #USAGE_HINT}
+ */
+ private static String parse(String... args) {
+ return parseWith("vo:", args);
+ }
+
+ /**
+ * Calls {@code getopt()} until all command-line arguments have been processed.
+ *
+ * @param g the command-line parser
+ */
+ private static void consumeAll(DaikonGetopt g) {
+ while (g.getopt() != -1) {}
+ }
+
+ /** Tests an unrecognized long option. */
+ @Test
+ public void testUnrecognizedLongOption() {
+ assertEquals("Unrecognized command-line option --bogus", parse("--bogus"));
+ assertEquals("Unrecognized command-line option --bogus", parse("--bogus=3"));
+ assertEquals("Unrecognized command-line option --=3", parse("--=3"));
+ assertEquals("Unrecognized command-line option --bogus", parse("-v", "--bogus", "file"));
+ }
+
+ /** Tests an unrecognized short option, alone and combined with a valid one. */
+ @Test
+ public void testUnrecognizedShortOption() {
+ assertEquals("Unrecognized command-line option -x", parse("-x"));
+ assertEquals("Unrecognized command-line option -x", parse("-xv"));
+ assertEquals("Unrecognized command-line option -x", parse("-vx"));
+ assertEquals("Unrecognized command-line option -:", parse("-:"));
+ }
+
+ /** Tests an unrecognized short option when there are no short options. */
+ @Test
+ public void testNoShortOptions() {
+ for (String arg : new String[] {"- ", "-x", "-:"}) {
+ assertEquals("Unrecognized command-line option " + arg, parseWith("", arg));
+ }
+ }
+
+ /** Tests an ambiguous abbreviation of a long option. */
+ @Test
+ public void testAmbiguousLongOption() {
+ assertEquals("Ambiguous command-line option --conf", parse("--conf=x"));
+ assertEquals("Ambiguous command-line option --conf", parse("--conf"));
+ }
+
+ /** Tests options that are missing their required argument. */
+ @Test
+ public void testMissingArgument() {
+ assertEquals("Command-line option --config requires an argument", parse("--config"));
+ assertEquals("Command-line option --debug requires an argument", parse("--deb"));
+ assertEquals("Command-line option -o requires an argument", parse("-o"));
+ assertEquals("Command-line option -o requires an argument", parse("-vo"));
+ }
+
+ /** Tests options that are missing their required argument, when the optstring starts with ':'. */
+ @Test
+ public void testMissingArgumentLeadingColon() {
+ assertEquals("Command-line option -o requires an argument", parseWith(":o:", "-o"));
+ assertEquals("Command-line option --config requires an argument", parseWith(":o:", "--config"));
+ }
+
+ /** Tests long options that are given an argument they do not take. */
+ @Test
+ public void testUnexpectedArgument() {
+ assertEquals("Command-line option --help does not take an argument", parse("--help=x"));
+ assertEquals("Command-line option --verbose does not take an argument", parse("--verb=x"));
+ }
+
+ /**
+ * Asserts that running {@code mainCall} throws a UserError with the given message.
+ *
+ * @param description a description of the bad option
+ * @param mainCall a call to a tool's {@code mainHelper} method
+ */
+ private static void assertBadOption(String description, ThrowingRunnable mainCall) {
+ Daikon.UserError e = assertThrows(Daikon.UserError.class, mainCall);
+ assertEquals(description + USAGE_HINT, String.valueOf(e.getMessage()));
+ }
+
+ /** Tests an unrecognized long option in a tool. */
+ @Test
+ public void testPrintInvariantsUnrecognizedOption() {
+ assertBadOption(
+ "Unrecognized command-line option --bogus",
+ () -> PrintInvariants.mainHelper(new String[] {"--bogus", "foo.inv.gz"}));
+ }
+
+ /** Tests that tools accept the {@code --help} option that their usage messages document. */
+ @Test
+ public void testHelpOption() {
+ assertPrintsUsage(() -> DtraceDiff.mainHelper(new String[] {"--help"}));
+ assertPrintsUsage(() -> UnionInvariants.mainHelper(new String[] {"--help"}));
+ }
+
+ /**
+ * Asserts that the given code prints a usage message to standard output and throws {@link
+ * Daikon.NormalTermination}. Captures the usage message so that it does not clutter the test
+ * output.
+ *
+ * @param code the code to run
+ */
+ private static void assertPrintsUsage(ThrowingRunnable code) {
+ PrintStream oldOut = System.out;
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(bytes, true, UTF_8));
+ try {
+ assertThrows(Daikon.NormalTermination.class, code);
+ } finally {
+ System.setOut(oldOut);
+ }
+ assertNotEquals("", bytes.toString(UTF_8).trim());
+ }
+}
diff --git a/java/daikon/test/SampleTester.java b/java/daikon/test/SampleTester.java
index 40919edb6b..ee6c5eda2e 100644
--- a/java/daikon/test/SampleTester.java
+++ b/java/daikon/test/SampleTester.java
@@ -8,6 +8,7 @@
import static org.junit.Assert.fail;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.Debug;
import daikon.FileIO;
import daikon.Global;
@@ -18,7 +19,6 @@
import daikon.ValueTuple;
import daikon.VarInfo;
import daikon.inv.Invariant;
-import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import java.io.IOException;
@@ -78,8 +78,29 @@ public class SampleTester {
" Specify a class, varinfos, and ppt to debug track.",
" Format is class@ppt");
- @SuppressWarnings("JUnitMethodInvoked") // main() runs the tests without JUnit
+ /**
+ * Runs the sample tests.
+ *
+ * @param args command-line arguments
+ * @throws IOException if there is trouble reading a file
+ */
public static void main(String[] args) throws IOException {
+ try {
+ mainHelper(args);
+ } catch (Daikon.DaikonTerminationException e) {
+ Daikon.handleDaikonTerminationException(e);
+ }
+ }
+
+ /**
+ * Does the work of {@link #main}, but throws an exception rather than calling {@code
+ * System.exit}.
+ *
+ * @param args command-line arguments
+ * @throws IOException if there is trouble reading a file
+ */
+ @SuppressWarnings("JUnitMethodInvoked") // mainHelper() runs the tests without JUnit
+ public static void mainHelper(String[] args) throws IOException {
LongOpt[] longopts =
new LongOpt[] {
@@ -89,7 +110,7 @@ public static void main(String[] args) throws IOException {
new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.test.SampleTester", args, "h:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
@@ -97,11 +118,7 @@ public static void main(String[] args) throws IOException {
// long option
case 0:
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
-
- } else if (Daikon.config_option_SWITCH.equals(option_name)) {
+ if (Daikon.config_option_SWITCH.equals(option_name)) {
String item = Daikon.getOptarg(g);
daikon.config.Configuration.getInstance().apply(item);
break;
@@ -119,20 +136,12 @@ public static void main(String[] args) throws IOException {
"Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error);
}
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
-
- case '?':
- break; // getopt() already printed an error
-
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/test/split/SplitterFactoryTestUpdater.java b/java/daikon/test/split/SplitterFactoryTestUpdater.java
index 0c806f6071..5391293804 100644
--- a/java/daikon/test/split/SplitterFactoryTestUpdater.java
+++ b/java/daikon/test/split/SplitterFactoryTestUpdater.java
@@ -247,24 +247,36 @@ private static String getTestClassText() {
" \" -s Save (do not delete) the splitter java files in the temp directory\",");
ps.println(" \" -h Display this usage message\");");
ps.println();
+ ps.println(" /**");
+ ps.println(" * Processes command-line options.");
+ ps.println(" *");
+ ps.println(" * @param args command-line arguments");
+ ps.println(" */");
ps.println(" public static void main(String[] args) {");
+ ps.println(" try {");
+ ps.println(" mainHelper(args);");
+ ps.println(" } catch (Daikon.DaikonTerminationException e) {");
+ ps.println(" Daikon.handleDaikonTerminationException(e);");
+ ps.println(" }");
+ ps.println(" }");
+ ps.println();
+ ps.println(" /**");
ps.println(
- " Getopt g = new Getopt(\"daikon.test.split.SplitterFactoryTest\", args, \"hs\");");
+ " * Does the work of {@link #main}, but throws an exception rather than calling {@code");
+ ps.println(" * System.exit}.");
+ ps.println(" *");
+ ps.println(" * @param args command-line arguments");
+ ps.println(" */");
+ ps.println(" public static void mainHelper(String[] args) {");
+ ps.println(" DaikonGetopt g = new DaikonGetopt(args, \"s\", new LongOpt[0], usage);");
ps.println(" int c;");
ps.println(" while ((c = g.getopt()) != -1) {");
ps.println(" switch (c) {");
ps.println(" case 's':");
ps.println(" saveFiles = true;");
ps.println(" break;");
- ps.println(" case 'h':");
- ps.println(" System.out.println(usage);");
- ps.println(" System.exit(1);");
- ps.println(" break;");
- ps.println(" case '?':");
- ps.println(" break;");
ps.println(" default:");
- ps.println(" System.out.println(\"getopt() returned \" + c);");
- ps.println(" break;");
+ ps.println(" throw new Daikon.BugInDaikon(\"getopt() returned \" + c);");
ps.println(" }");
ps.println(" }");
ps.println(" }");
diff --git a/java/daikon/tools/DtraceDiff.java b/java/daikon/tools/DtraceDiff.java
index 7d158ccc29..0fe001621e 100644
--- a/java/daikon/tools/DtraceDiff.java
+++ b/java/daikon/tools/DtraceDiff.java
@@ -6,6 +6,7 @@
import static daikon.tools.nullness.NullnessUtil.*;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.FileIO;
import daikon.Global;
import daikon.PptMap;
@@ -124,7 +125,7 @@ public static void mainHelper(final String[] args) {
new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.tools.DtraceDiff", args, "h:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
@@ -132,10 +133,7 @@ public static void mainHelper(final String[] args) {
// long option
case 0:
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.ppt_regexp_SWITCH.equals(option_name)) {
+ if (Daikon.ppt_regexp_SWITCH.equals(option_name)) {
if (Daikon.ppt_regexp != null) {
throw new Error(
"multiple --"
@@ -224,20 +222,11 @@ public static void mainHelper(final String[] args) {
Configuration.getInstance().apply(item);
break;
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
- // short options
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
-
- case '?':
- break; // getopt() already printed an error
-
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/tools/ExtractConsequent.java b/java/daikon/tools/ExtractConsequent.java
index f2ecf3caf3..d4f94d9f49 100644
--- a/java/daikon/tools/ExtractConsequent.java
+++ b/java/daikon/tools/ExtractConsequent.java
@@ -5,6 +5,7 @@
import static java.util.logging.Level.INFO;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.FileIO;
import daikon.Global;
import daikon.Ppt;
@@ -118,17 +119,14 @@ public static void mainHelper(final String[] args) throws IOException {
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.ExtractConsequent", args, "h", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.suppress_redundant_SWITCH.equals(option_name)) {
+ if (Daikon.suppress_redundant_SWITCH.equals(option_name)) {
Daikon.suppress_redundant_invariants_with_simplify = true;
} else if (Daikon.config_option_SWITCH.equals(option_name)) {
String item = Daikon.getOptarg(g);
@@ -139,17 +137,11 @@ public static void mainHelper(final String[] args) throws IOException {
} else if (Daikon.debug_SWITCH.equals(option_name)) {
daikon.LogHelper.setLevel(Daikon.getOptarg(g), FINE);
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
// The index of the first non-option argument -- the name of the file
diff --git a/java/daikon/tools/InvariantChecker.java b/java/daikon/tools/InvariantChecker.java
index 70a3c804d1..3f8c7c56b7 100644
--- a/java/daikon/tools/InvariantChecker.java
+++ b/java/daikon/tools/InvariantChecker.java
@@ -4,6 +4,7 @@
import static java.util.logging.Level.INFO;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.Debug;
import daikon.FileIO;
import daikon.Global;
@@ -135,20 +136,16 @@ public static void mainHelper(final String[] args)
new LongOpt(verbose_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
- new LongOpt(Daikon.ppt_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.tools.InvariantChecker", args, "h", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (conf_SWITCH.equals(option_name)) {
+ if (conf_SWITCH.equals(option_name)) {
doConf = true;
} else if (filter_SWITCH.equals(option_name)) {
doFilter = true;
@@ -179,17 +176,11 @@ public static void mainHelper(final String[] args)
"Error parsing track argument '" + Daikon.getOptarg(g) + "' - " + error);
}
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/tools/compare/LogicalCompare.java b/java/daikon/tools/compare/LogicalCompare.java
index bbbc6df993..371d26ea25 100644
--- a/java/daikon/tools/compare/LogicalCompare.java
+++ b/java/daikon/tools/compare/LogicalCompare.java
@@ -5,6 +5,7 @@
import static java.util.logging.Level.INFO;
import daikon.Daikon;
+import daikon.DaikonGetopt;
import daikon.FileIO;
import daikon.Global;
import daikon.PptMap;
@@ -658,7 +659,6 @@ public static void mainHelper(final String[] args)
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt("filters", LongOpt.REQUIRED_ARGUMENT, null, 0),
- new LongOpt("help", LongOpt.NO_ARGUMENT, null, 0),
new LongOpt("minimize-classes", LongOpt.NO_ARGUMENT, null, 0),
new LongOpt("no-post-after-pre-failure", LongOpt.NO_ARGUMENT, null, 0),
new LongOpt("post-after-pre-failure", LongOpt.NO_ARGUMENT, null, 0),
@@ -675,7 +675,7 @@ public static void mainHelper(final String[] args)
extra_assumptions = new LinkedHashMap<>();
- Getopt g = new Getopt("daikon.tools.compare.LogicalCompare", args, "h", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "", longopts, usage);
int c;
boolean user_filters = false;
while ((c = g.getopt()) != -1) {
@@ -683,10 +683,7 @@ public static void mainHelper(final String[] args)
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (option_name.equals("config-file")) {
+ if (option_name.equals("config-file")) {
String config_file = Daikon.getOptarg(g);
try (InputStream stream = new FileInputStream(config_file)) {
Configuration.getInstance().apply(stream);
@@ -727,15 +724,11 @@ public static void mainHelper(final String[] args)
} else if (option_name.equals("minimize-classes")) {
opt_minimize_classes = true;
} else {
- throw new Error();
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- case '?':
- // getopt() already printed an error
- throw new Daikon.UserError("Bad argument");
+ default:
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/tools/jtb/Annotate.java b/java/daikon/tools/jtb/Annotate.java
index 9635cc5912..b76c70ef97 100644
--- a/java/daikon/tools/jtb/Annotate.java
+++ b/java/daikon/tools/jtb/Annotate.java
@@ -24,8 +24,7 @@
*
* The first argument is a Daikon {@code .inv} file -- a serialized file of Invariant objects.
* All subsequent arguments are {@code Foo.java} files that are rewritten into {@code
- * Foo.java-jmlannotated} versions; alternately, use the {@code -r} flag to process every {@code
- * .java} file under the current directory.
+ * Foo.java-jmlannotated} versions.
*/
public class Annotate {
@@ -88,11 +87,10 @@ private Annotate() {
private static String usage =
StringsPlume.joinLines(
"Usage: java daikon.tools.Annotate FILE.inv FILE.java ...",
- " -h Display this usage message",
- " -i Insert invariants not supported by ESC with \"!\" instead of \"@\";",
- " by default these \"inexpressible\" invariants are simply omitted",
- " -r Use all .java files under the current directory as arguments",
- " -s Use // comments rather than /* comments",
+ " -h, --help Display this usage message",
+ " -i Insert invariants not supported by ESC with \"!\" instead of \"@\";",
+ " by default these \"inexpressible\" invariants are simply omitted",
+ " -s Use // comments rather than /* comments",
" --format name Insert specifications in the given format: DBC, ESC, JML, Java",
" --wrap_xml Wrap each annotation and auxiliary information in XML tags",
" --max_invariants_pp N",
@@ -132,7 +130,6 @@ public static void mainHelper(final String[] args) throws Exception {
Daikon.output_format = OutputFormat.ESCJAVA;
LongOpt[] longopts =
new LongOpt[] {
- new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(Daikon.format_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
@@ -140,7 +137,7 @@ public static void mainHelper(final String[] args) throws Exception {
new LongOpt(max_invariants_pp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
new LongOpt(no_reflection_SWITCH, LongOpt.NO_ARGUMENT, null, 0)
};
- Getopt g = new Getopt("daikon.tools.jtb.Annotate", args, "hs", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "is", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
@@ -148,10 +145,7 @@ public static void mainHelper(final String[] args) throws Exception {
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (no_reflection_SWITCH.equals(option_name)) {
+ if (no_reflection_SWITCH.equals(option_name)) {
useReflection = false;
} else if (max_invariants_pp_SWITCH.equals(option_name)) {
try {
@@ -181,12 +175,9 @@ public static void mainHelper(final String[] args) throws Exception {
setLightweight = true;
}
} else {
- throw new Daikon.UserError("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
case 'i':
insert_inexpressible = true;
break;
@@ -200,11 +191,8 @@ public static void mainHelper(final String[] args) throws Exception {
case 's':
slashslash = true;
break;
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/java/daikon/tools/jtb/CreateSpinfo.java b/java/daikon/tools/jtb/CreateSpinfo.java
index 56f1b154e2..76d4b23b05 100644
--- a/java/daikon/tools/jtb/CreateSpinfo.java
+++ b/java/daikon/tools/jtb/CreateSpinfo.java
@@ -83,40 +83,30 @@ public static void mainHelper(final String[] args) throws IOException {
daikon.LogHelper.setupLogs(INFO);
LongOpt[] longopts =
new LongOpt[] {
- new LongOpt(Daikon.help_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0),
new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0),
};
- Getopt g = new Getopt("daikon.tools.jtb.CreateSpinfo", args, "ho:", longopts);
+ DaikonGetopt g = new DaikonGetopt(args, "o:", longopts, usage);
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 0:
// got a long option
String option_name = longopts[g.getLongind()].getName();
- if (Daikon.help_SWITCH.equals(option_name)) {
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- } else if (Daikon.debugAll_SWITCH.equals(option_name)) {
+ if (Daikon.debugAll_SWITCH.equals(option_name)) {
Global.debugAll = true;
} else if (Daikon.debug_SWITCH.equals(option_name)) {
daikon.LogHelper.setLevel(Daikon.getOptarg(g), FINE);
} else {
- throw new RuntimeException("Unknown long option received: " + option_name);
+ throw new Daikon.BugInDaikon("Unhandled long option " + option_name);
}
break;
case 'o':
outputfilename = Daikon.getOptarg(g);
break;
- case 'h':
- System.out.println(usage);
- throw new Daikon.NormalTermination();
- case '?':
- break; // getopt() already printed an error
default:
- System.out.println("getopt() returned " + c);
- break;
+ throw new Daikon.BugInDaikon("getopt() returned " + c);
}
}
diff --git a/tests/diff-tests/Makefile.common b/tests/diff-tests/Makefile.common
index 7a22461dfd..014605b8b4 100644
--- a/tests/diff-tests/Makefile.common
+++ b/tests/diff-tests/Makefile.common
@@ -20,10 +20,10 @@ INV_FILES := $(PROGRAM)-1.inv.gz $(PROGRAM)-2.inv.gz
# An output file must satisfy the pattern program%.txt, where the % is
# the options passed to Diff
## Must reinstate -a and -ap and -p in V3 as soon as possible. -MDE 6/10/2003
-# OUTPUT := $(PROGRAM).txt $(PROGRAM)-u.txt $(PROGRAM)-a.txt $(PROGRAM)-p.txt \
+# OUTPUT := $(PROGRAM).txt $(PROGRAM)-a.txt $(PROGRAM)-p.txt \
# $(PROGRAM)-e.txt $(PROGRAM)-ap.txt $(PROGRAM)-t.txt \
# $(PROGRAM)-jt.txt
-OUTPUT := $(PROGRAM).txt $(PROGRAM)-u.txt \
+OUTPUT := $(PROGRAM).txt \
$(PROGRAM)-e.txt $(PROGRAM)-t.txt \
$(PROGRAM)-jt.txt
# Must be handled differently than OUTPUT, because map files are
diff --git a/tests/diff-tests/StackAr/StackAr-u.txt.goal b/tests/diff-tests/StackAr/StackAr-u.txt.goal
deleted file mode 100644
index f3164de375..0000000000
--- a/tests/diff-tests/StackAr/StackAr-u.txt.goal
+++ /dev/null
@@ -1,105 +0,0 @@
-(I)V:::ENTER>
- = 0 {0+}, capacity >= 2 {1-}> (UInt,DJU)
- (U!Int,DUU)
-(I)V:::EXIT>
- (Bin,MJ)
- (Bin,MJ)
- = -1 {0.8136-}, this.topOfStack >= -1 {0.8333-}> (U!Int,SUU)
- (UInt,SJU)
- (U!Int,DUU)
- (U!Int,SUU)
- (UInt,SJU)
- (UInt,MJ)
-
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DJU)
- (U!Int,DUU)
- (UInt,MJ)
-
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DJU)
- (U!Int,DJU)
- (U!Int,DUU)
- (UInt,MJ)
-
- (Bin,MJ)
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- (Bin,MJ)
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (UInt,MJ)
- (U!Int,DJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- (Bin,JM)
- = -1 {0+}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,DJU)
- (U!Int,UM)
- (U!Int,DUU)
- (UInt,JM)
- (UInt,JM)
- (UInt,DJU)
-
- (Bin,JM)
- (Bin,JM)
- (Bin,JM)
- (Bin,JM)
- (Bin,JM)
- = -1 {0+}, null> (U!Int,JM)
- = -1 {0.8205-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,DUU)
- (UInt,DJU)
- (U!Int,UM)
- (U!Int,UM)
- (U!Int,UM)
- (U!Int,DUU)
- (UInt,DJU)
- (UInt,JM)
- (UInt,JM)
- (UInt,DJU)
- (UInt,DJU)
-
- = 9223372036854775807 {1-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,SUU)
- (U!Int,SUU)
-
- = 9223372036854775807 {1-}, this.topOfStack >= 9223372036854775807 {1-}> (U!Int,SUU)
- (U!Int,SUU)
-
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- = -1 {0+}, orig(this.topOfStack) >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DUU)
- (U!Int,DJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- = -1 {0+}, this.topOfStack >= 0 {0+}> (UInt,DJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- (Bin,MJ)
- (Bin,MJ)
- (Bin,MJ)
- (Bin,MJ)
- = -1 {0+}, this.topOfStack >= 0 {0+}> (UInt,DJJ)
- (UInt,MJ)
- (U!Int,DJJ)
- (U!Int,DJJ)
- (U!Int,DUU)
-
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DJU)
- (U!Int,DUU)
-
- (Bin,MJ)
- (Bin,MJ)
- (Bin,MJ)
- = -1 {0+}, orig(this.topOfStack) >= -1 {0+}> (U!Int,SJJ)
- = -1 {0+}, this.topOfStack >= -1 {0+}> (U!Int,SJJ)
- (U!Int,DUU)
- (U!Int,DJU)
- (U!Int,DJU)
- (U!Int,DUU)
diff --git a/tests/diff-tests/schedule2/schedule2-u.txt.goal b/tests/diff-tests/schedule2/schedule2-u.txt.goal
deleted file mode 100644
index ef71a1c0d9..0000000000
--- a/tests/diff-tests/schedule2/schedule2-u.txt.goal
+++ /dev/null
@@ -1,77 +0,0 @@
-getopt() returned 117
-
- <::next_pid >= 0 {0-}, ::next_pid >= 0 {1+}> (Una,SUJ)
-
- <::next_pid >= 0 {0-}, ::next_pid >= 0 {1+}> (Una,SUJ)
-
- = 0 {1+}, prio >= -1 {1+}> (Una,DJJ)
-
- (return is a pointer) {1+}> (Nul,MJ)
- (prio >= -1) {1+}> (Nul,MJ)
- (prio >= 0) {1+}> (Nul,MJ)
- (prio != 0) {0.9999+}> (Nul,MJ)
- = 0 {1+}, prio >= -1 {1+}> (Una,DJJ)
- (Una,DJJ)
-
- <*prio >= -1 {1+}, *prio >= -2 {0-}> (Una,DJU)
- <*command != 0 {1+}, null> (Una,JM)
-
- (*prio >= -1) {1+}> (Nul,MJ)
- (orig(*prio) >= -1) {1+}> (Nul,MJ)
- <(return == 1) ==> (*prio != 0) {1+}, null> (Nul,JM)
- (*command == 0) {1+}> (Bin,MJ)
- <(*prio == 0) ==> (orig(*prio) == 0) {1+}, null> (Bin,JM)
- <*prio >= -1 {1+}, *prio >= -2 {0-}> (Una,DJU)
- <*command != 0 {1+}, null> (Una,JM)
-
- <::next_pid >= 0 {0.4444-}, ::next_pid >= 0 {1+}> (Una,SUJ)
-
- <::next_pid >= 0 {0.4444-}, ::next_pid >= 0 {1+}> (Una,SUJ)
-
- = 0.0 {1+}, ratio >= -1.0 {0.0721-}> (Una,DJU)
-
- = 0.0 {1+}, ratio >= -1.0 {0.0721-}> (Una,DJU)
- (Una,DJJ)
-
- (Una,JM)
-
- = orig(::next_pid) {1+}> (Bin,MJ)
- <::next_pid - orig(::next_pid) - 1 == 0 {1+}, null> (Bin,JM)
- (orig(::next_pid) == 0) {1+}> (Bin,MJ)
- <::next_pid >= 1 {1+}, ::next_pid >= 0 {0.3333-}> (Una,DJU)
- (Una,DUJ)
- (Una,JM)
- (Una,DJJ)
-
- = 0 {1+}, prio >= -1 {1+}> (Una,DJJ)
-
- (return is a pointer) {1+}> (Nul,MJ)
- (prio >= -1) {1+}> (Nul,MJ)
- (prio >= 0) {1+}> (Nul,MJ)
- (prio != 0) {0.9999+}> (Nul,MJ)
- = 0 {1+}, prio >= -1 {1+}> (Una,DJJ)
- (Una,DJJ)
-
- = -1 {1+}, prio >= -2 {0-}> (Una,DJU)
- (Una,JM)
- (Una,JM)
-
- = -1 {1+}, prio >= -2 {0-}> (Una,DJU)
- (Una,JM)
- (Una,JM)
- (Una,JM)
- (Una,JM)
-
- (Una,SUJ)
-
- (Una,SUJ)
- (Una,DJJ)
-
- <::next_pid >= 0 {1+}, ::next_pid >= 0 {0.7779-}> (Una,SJU)
- (Una,SUJ)
- (Una,JM)
-
- <::next_pid >= 0 {1+}, ::next_pid >= 0 {0.7779-}> (Una,SJU)
- (Una,SUJ)
- (Una,JM)
- (Una,DJJ)