aboutsummaryrefslogtreecommitdiffstats
path: root/src/ArgParser.java
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2013-06-18 00:41:25 +0200
committerMattias Andrée <maandree@operamail.com>2013-06-18 00:41:25 +0200
commitb4fa23dd22f91fc3f4387d0654a91ed0cf868236 (patch)
tree9b0487aa9ee94fea39c06471d9d089225a4f0702 /src/ArgParser.java
parentm (diff)
downloadargparser-b4fa23dd22f91fc3f4387d0654a91ed0cf868236.tar.gz
argparser-b4fa23dd22f91fc3f4387d0654a91ed0cf868236.tar.bz2
argparser-b4fa23dd22f91fc3f4387d0654a91ed0cf868236.tar.xz
add java version
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to '')
-rw-r--r--src/ArgParser.java1007
1 files changed, 1007 insertions, 0 deletions
diff --git a/src/ArgParser.java b/src/ArgParser.java
new file mode 100644
index 0000000..495e07c
--- /dev/null
+++ b/src/ArgParser.java
@@ -0,0 +1,1007 @@
+/**
+ * argparser – command line argument parser library
+ *
+ * Copyright © 2013 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This library 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+import java.util.*;
+import java.io.*;
+
+
+/**
+ * Simple argument parser
+ *
+ * @author Mattias Andrée, <a href="mailto:maandree@member.fsf.org">maandree@member.fsf.org</a>
+ */
+public class ArgParser
+{
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ */
+ public ArgParser(final String description, final String usage)
+ { this(description, usage, null, null, false);
+ }
+
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ * @param useStderr Whether to use stderr instead of stdout
+ */
+ public ArgParser(final String description, final String usage, final boolean useStderr)
+ { this(description, usage, null, null, useStderr);
+ }
+
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ * @param longDescription Long, multi-line, description of the program, may be {@code null}
+ */
+ public ArgParser(final String description, final String usage, final String longDescription)
+ { this(description, usage, longDescription, null, false);
+ }
+
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ * @param longDescription Long, multi-line, description of the program, may be {@code null}
+ * @param useStderr Whether to use stderr instead of stdout
+ */
+ public ArgParser(final String description, final String usage, final String longDescription, final boolean useStderr)
+ { this(description, usage, longDescription, null, useStderr);
+ }
+
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ * @param longDescription Long, multi-line, description of the program, may be {@code null}
+ * @param program The name of the program, {@code null} for automatic
+ */
+ public ArgParser(final String description, final String usage, final String longDescription, final String program)
+ { this(description, usage, longDescription, program, false);
+ }
+
+ /**
+ * <p>Constructor</p>
+ * <p>
+ * The short description is printed on same line as the program name
+ * </p>
+ *
+ * @param description Short, single-line, description of the program
+ * @param usage Formated, multi-line, usage text, may be {@code null}
+ * @param longDescription Long, multi-line, description of the program, may be {@code null}
+ * @param program The name of the program, {@code null} for automatic
+ * @param useStderr Whether to use stderr instead of stdout
+ */
+ public ArgParser(final String description, final String usage, final String longDescription, final String program, final boolean useStderr)
+ {
+ this.linuxvt = System.getenv("TERM") == null ? false : System.getenv("TERM").equals("linux");
+ String prog = program == null ? ArgParser.parentName(0, true) : program;
+ this.program = prog == null ? "?" : prog;
+ this.description = description;
+ this.usage = usage;
+ this.longDescription = longDescription;
+ this.out = useStderr ? System.err : System.out;
+ }
+
+
+
+ /**
+ * Whether the Linux VT is being used
+ */
+ public boolean linuxvt;
+
+ /**
+ * The name of the executed command
+ */
+ public final String program;
+
+ /**
+ * Short, single-line, description of the program
+ */
+ private final String description;
+
+ /**
+ * Formated, multi-line, usage text, {@code null} if none
+ */
+ private final String usage;
+
+ /**
+ * Long, multi-line, description of the program, {@code null} if none
+ */
+ private final String longDescription;
+
+ /**
+ * The error output stream
+ */
+ private final OutputStream out;
+
+ /**
+ * The passed arguments
+ */
+ public String[] arguments = null;
+
+ /**
+ * The number of unrecognised arguments
+ */
+ public int unrecognisedCount = 0;
+
+ /**
+ * Options, in order
+ */
+ private final ArrayList<Option> options = new ArrayList<Option>();
+
+ /**
+ * Option map
+ */
+ public final HashMap<String, Option> optmap = new HashMap<String, Option>();
+
+ /**
+ * The arguments passed that is not tied to an option
+ */
+ public final ArrayList<String> files = new ArrayList<String>();
+
+ /**
+ * Parsed arguments, a map from option to arguments, {@code null} if not used,
+ * add one {@code null} element per argumentless use.
+ */
+ public final HashMap<String, String[]> opts = new HashMap<String, String[]>();
+
+
+
+ /**
+ * Option class
+ */
+ public class Option
+ {
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param standard Standard option index
+ * @param argument Argument name, not for argumentless options
+ */
+ protected Option(final String[] alternatives, final int standard, final String argument)
+ {
+ this.alternatives = alternatives;
+ this.standard = alternatives[standard < 0 ? (alternatives.length + standard) : standard];
+ this.argument = argument == null ? "ARG" : argument;
+ }
+
+
+
+ /**
+ * Alterative option names
+ */
+ public final String[] alternatives;
+
+ /**
+ * Standard option name
+ */
+ public final String standard;
+
+ /**
+ * Argument name, not for argumentless options
+ */
+ public final String argument;
+
+ /**
+ * Help text, multi-line
+ */
+ public String help = null;
+ }
+
+
+ /**
+ * Option takes no arguments
+ */
+ public class Argumentless extends Option
+ {
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param standard Standard option index
+ */
+ public Argumentless(final String[] alternatives, final int standard)
+ { super(alternatives, standard, null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param standard Standard option index
+ * @param alternatives Alterative option names
+ */
+ public Argumentless(final int standard, final String... alternatives)
+ { super(alternatives, standard, null);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ */
+ public Argumentless(final String... alternatives)
+ { super(alternatives, 0, null);
+ }
+ }
+
+
+ /**
+ * Option takes one argument per instance
+ */
+ public class Argumented extends Option
+ {
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param standard Standard option index
+ * @param argument Argument name
+ */
+ public Argumented(final String[] alternatives, final int standard, final String argument)
+ { super(alternatives, standard, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param argument Argument name
+ * @param standard Standard option index
+ */
+ public Argumented(final String[] alternatives, final String argument, final int standard)
+ { super(alternatives, standard, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param argument Argument name
+ */
+ public Argumented(final String[] alternatives, final String argument)
+ { super(alternatives, 0, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param standard Standard option index
+ * @param argument Argument name
+ * @param alternatives Alterative option names
+ */
+ public Argumented(final int standard, final String argument, final String... alternatives)
+ { super(alternatives, standard, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param argument Argument name
+ * @param standard Standard option index
+ * @param alternatives Alterative option names
+ */
+ public Argumented(final String argument, final int standard, final String... alternatives)
+ { super(alternatives, standard, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param argument Argument name
+ * @param alternatives Alterative option names
+ */
+ public Argumented(final String argument, final String... alternatives)
+ { super(alternatives, 0, argument);
+ }
+ }
+
+
+ /**
+ * Option consumes all following arguments
+ */
+ public class Variadic extends Argumented
+ {
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param standard Standard option index
+ * @param argument Argument name
+ */
+ public Variadic(final String[] alternatives, final int standard, final String argument)
+ { super(alternatives, standard, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param argument Argument name
+ * @param standard Standard option index
+ */
+ public Variadic(final String[] alternatives, final String argument, final int standard)
+ { super(alternatives, argument, standard);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param alternatives Alterative option names
+ * @param argument Argument name
+ */
+ public Variadic(final String[] alternatives, final String argument)
+ { super(alternatives, argument);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param standard Standard option index
+ * @param argument Argument name
+ * @param alternatives Alterative option names
+ */
+ public Variadic(final int standard, final String argument, final String... alternatives)
+ { super(standard, argument, alternatives);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param argument Argument name
+ * @param standard Standard option index
+ * @param alternatives Alterative option names
+ */
+ public Variadic(final String argument, final int standard, final String... alternatives)
+ { super(argument, standard, alternatives);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param argument Argument name
+ * @param alternatives Alterative option names
+ */
+ public Variadic(final String argument, final String... alternatives)
+ { super(argument, alternatives);
+ }
+ }
+
+
+
+ /**
+ * Gets the name of the parent process
+ *
+ * @return The name of the parent process
+ */
+ public static String parentName()
+ {
+ return ArgParser.parentName(1, false);
+ }
+
+ /**
+ * Gets the name of the parent process
+ *
+ * @param levels The number of parents to walk, 0 for self, and 1 for direct parent
+ * @return The name of the parent process
+ */
+ public static String parentName(final int levels)
+ {
+ return ArgParser.parentName(levels, false);
+ }
+
+ /**
+ * Gets the name of the parent process
+ *
+ * @param hasInterpretor Whether the parent process is an interpretor
+ * @return The name of the parent process
+ */
+ public static String parentName(final boolean hasInterpretor)
+ {
+ return ArgParser.parentName(1, hasInterpretor);
+ }
+
+ /**
+ * Gets the name of the parent process
+ *
+ * @param levels The number of parents to walk, 0 for self, and 1 for direct parent
+ * @param hasInterpretor Whether the parent process is an interpretor
+ * @return The name of the parent process
+ */
+ public static String parentName(final int levels, final boolean hasInterpretor)
+ {
+ int pid;
+ try
+ { pid = Integer.parseInt((new File("/proc/self")).getCanonicalPath().substring(6));
+ }
+ catch (final Throwable err)
+ { return null;
+ }
+ int lvl = levels;
+ try
+ { outer:
+ while (lvl > 1)
+ {
+ InputStream is = null;
+ try
+ { is = new FileInputStream(new File("/proc/" + pid + "/status"));
+ byte[] data = new byte[is.available()];
+ int off = 0;
+ while (off != data.length)
+ off += is.read(data, off, data.length - off);
+ String[] lines = (new String(data, "UTF-8")).split("\n");
+ for (String line : lines)
+ { if (line.startsWith("PPid:"))
+ {
+ line = line.substring(5);
+ line = line.replace('\t', ' ').replace('\n', ' ').replace(" ", "");
+ pid = Integer.parseInt(line);
+ lvl -= 1;
+ continue outer;
+ } }
+ return null;
+ }
+ finally
+ { if (is != null)
+ try
+ { is.close();
+ }
+ catch (final Throwable ignore)
+ { /* ignore */
+ } }
+ }
+ InputStream is = null;
+ try
+ { is = new FileInputStream(new File("/proc/" + pid + "/cmdline"));
+ byte[] data = new byte[is.available()];
+ int off = 0;
+ while (off != data.length)
+ off += is.read(data, off, data.length - off);
+ String[] cmdline = new String(data, 0, off - 1, "UTF-8").split("\0");
+ if (hasInterpretor == false)
+ { String rc = cmdline[0];
+ return rc.length() == 0 ? null : rc;
+ }
+ boolean dashed = false;
+ for (int i = 1, n = cmdline.length; i < n; i++)
+ {
+ if (dashed)
+ return cmdline[i];
+ if (cmdline[i].equals("--"))
+ dashed = true;
+ else if (cmdline[i].equals("-cp") || cmdline[i].equals("-classpath"))
+ i++;
+ else if (cmdline[i].startsWith("-") == false)
+ return cmdline[i];
+ }
+ }
+ finally
+ { if (is != null)
+ try
+ { is.close();
+ }
+ catch (final Throwable ignore)
+ { /* ignore */
+ } }
+ return null;
+ }
+ catch (final Throwable err)
+ { return null;
+ }
+ }
+
+
+ /**
+ * Print an empty line to the selected error channel
+ */
+ private void println()
+ {
+ this.print("\n", true);
+ }
+
+ /**
+ * Print an empty line to the selected error channel
+ *
+ * @param flush Whether to flush the stream
+ */
+ private void println(final boolean flush)
+ {
+ this.print("\n", flush);
+ }
+
+ /**
+ * Print a text with an added line break to the selected error channel
+ */
+ private void println(final String text)
+ {
+ this.print(text + "\n", true);
+ }
+
+ /**
+ * Print a text with an added line break to the selected error channel
+ *
+ * @param flush Whether to flush the stream
+ */
+ private void println(final String text, final boolean flush)
+ {
+ this.print(text + "\n", flush);
+ }
+
+ /**
+ * Print a text to the selected error channel
+ */
+ private void print(final String text)
+ {
+ this.print(text, false);
+ }
+
+ /**
+ * Print a text to the selected error channel
+ *
+ * @param flush Whether to flush the stream
+ */
+ private void print(final String text, final boolean flush)
+ {
+ try
+ { if (text != null)
+ this.out.write(text.getBytes("UTF-8"));
+ if (flush)
+ this.out.flush();
+ }
+ catch (final Throwable ignore)
+ { /* ignore */
+ }
+ }
+
+
+ /**
+ * Add an option
+ *
+ * @param option The option
+ */
+ public void add(final Option option)
+ {
+ this.options.add(option);
+ for (final String alternative : option.alternatives)
+ this.optmap.put(alternative, option);
+ this.opts.put(option.standard, null);
+ }
+
+ /**
+ * Add an option
+ *
+ * @param option The option
+ * @param help Help text, multi-line
+ */
+ public void add(final Option option, final String help)
+ {
+ this.add(help, option);
+ }
+
+ /**
+ * Add an option
+ *
+ * @param help Help text, multi-line
+ * @param option The option
+ */
+ public void add(final String help, final Option option)
+ {
+ this.add(option);
+ option.help = help;
+ }
+
+
+ /**
+ * Maps up options that are alternatives to the first alternative for each option
+ */
+ public void supportAlternatives()
+ {
+ for (final String opt : this.optmap.keySet())
+ this.opts.put(opt, this.opts.get(this.optmap.get(opt).standard));
+ }
+
+
+ /**
+ * Checks for option conflicts
+ *
+ * @param exclusives Exclusive options
+ * @param exitValue The value to exit with on the check does not pass,
+ * @return Whether at most one exclusive option was used
+ */
+ public boolean testExclusiveness(final Set<String> exclusives, final int exitValue)
+ {
+ boolean rc = this.testExclusiveness(exclusives);
+ if (rc == false)
+ System.exit(exitValue);
+ return rc;
+ }
+
+ /**
+ * Checks for option conflicts
+ *
+ * @param exclusives Exclusive options
+ * @return Whether at most one exclusive option was used
+ */
+ public boolean testExclusiveness(final Set<String> exclusives)
+ {
+ final ArrayList<String> used = new ArrayList<String>();
+
+ for (final String opt : this.opts.keySet())
+ if ((this.opts.get(opt) != null) && exclusives.contains(opt))
+ used.add(opt);
+
+ if (used.size() > 1)
+ { String msg = this.program + ": conflicting options:";
+ for (final String opt : used)
+ if (this.optmap.get(opt).standard.equals(opt))
+ msg += " " + opt;
+ else
+ msg += " " + opt + "(" + this.optmap.get(opt).standard + ")";
+ this.println(msg, true);
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * Checks for out of context option usage
+ *
+ * @param allowed Allowed options
+ * @param exitValue The value to exit with on the check does not pass,
+ * @return Whether only allowed options was used
+ */
+ public boolean testAllowed(final Set<String> allowed, final int exitValue)
+ {
+ boolean rc = this.testAllowed(allowed);
+ if (rc == false)
+ System.exit(exitValue);
+ return rc;
+ }
+
+ /**
+ * Checks for out of context option usage
+ *
+ * @param allowed Allowed options
+ * @return Whether only allowed options was used
+ */
+ public boolean testAllowed(final Set<String> allowed)
+ {
+ boolean rc = true;
+ for (final String opt : this.opts.keySet())
+ if ((this.opts.get(opt) != null) && (allowed.contains(opt) == false))
+ { String msg = this.program + ": option used out of context: " + opt;
+ if (opt.equals(this.optmap.get(opt).standard) == false)
+ msg += "(" + this.optmap.get(opt).standard + ")";
+ this.println(msg, true);
+ rc = false;
+ }
+ return rc;
+ }
+
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param min The minimum number of files
+ * @param exitValue The value to exit with on the check does not pass
+ * @return Whether the usage was correct
+ */
+ public boolean testFilesMin(final int min, final int exitValue)
+ {
+ boolean rc = this.testFilesMin(min);
+ if (rc == false)
+ System.exit(exitValue);
+ return rc;
+ }
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param min The minimum number of files
+ * @return Whether the usage was correct
+ */
+ public boolean testFilesMin(final int min)
+ {
+ return min <= this.files.size();
+ }
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param max The maximum number of files
+ * @param exitValue The value to exit with on the check does not pass
+ * @return Whether the usage was correct
+ */
+ public boolean testFilesMax(final int max, final int exitValue)
+ {
+ boolean rc = this.testFilesMax(max);
+ if (rc == false)
+ System.exit(exitValue);
+ return rc;
+ }
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param max The maximum number of files
+ * @return Whether the usage was correct
+ */
+ public boolean testFilesMax(final int max)
+ {
+ return this.files.size() <= max;
+ }
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param min The minimum number of files
+ * @param max The maximum number of files
+ * @param exitValue The value to exit with on the check does not pass
+ * @return Whether the usage was correct
+ */
+ public boolean testFiles(final int min, final int max, final int exitValue)
+ {
+ boolean rc = this.testFiles(min, max);
+ if (rc == false)
+ System.exit(exitValue);
+ return rc;
+ }
+
+ /**
+ * Checks the correctness of the number of used non-option arguments
+ *
+ * @param min The minimum number of files
+ * @param max The maximum number of files
+ * @return Whether the usage was correct
+ */
+ public boolean testFiles(final int min, final int max)
+ {
+ return (min <= this.files.size()) && (this.files.size() <= max);
+ }
+
+
+ /**
+ * Prints a colourful help message
+ */
+ public void help()
+ {
+ final String dash = this.linuxvt ? "-" : "—";
+ this.println("\033[01m" + program + "\033[21m " + dash + " " + this.description + "\n", false);
+ if (this.longDescription != null)
+ this.println(longDescription, false);
+ this.println(false);
+
+ if (this.usage != null)
+ { this.print("\033[01mUSAGE:\033[21m");
+ boolean first = true;
+ for (final String line : this.usage.split("\n"))
+ { if (first)
+ first = false;
+ else
+ this.print(" or");
+ this.println("\t" + line, false);
+ }
+ this.println(false);
+ }
+
+ int maxfirstlen = 0;
+ for (final Option opt : this.options)
+ { if (opt.help == null)
+ continue;
+ if (opt.alternatives.length > 1)
+ if (maxfirstlen < opt.alternatives[0].length())
+ maxfirstlen = opt.alternatives[0].length();
+ }
+ String empty = " ";
+ while (empty.length() < maxfirstlen)
+ empty += empty;
+ empty = empty.substring(0, maxfirstlen);
+
+ this.println("\033[01mSYNOPSIS:\033[21m", false);
+ final ArrayList<String> lines = new ArrayList<String>();
+ final ArrayList<int[]> lens = new ArrayList<int[]>();
+ for (final Option opt : this.options)
+ { if (opt.help == null)
+ continue;
+ int l = 0;
+ String first = opt.alternatives[0];
+ String last = opt.alternatives[opt.alternatives.length - 1];
+ if (first == last)
+ first = empty;
+ else
+ first += empty.substring(first.length());
+ String line = " \033[02m" + first + "\033[22m %colour%" + last;
+ l += first.length() + 6 + last.length();
+ if (opt instanceof Variadic)
+ { line += " [\033[04m" + opt.argument + "\033[24m...]";
+ l += opt.argument.length() + 6;
+ }
+ else if (opt instanceof Argumented)
+ { line += " \033[04m" + opt.argument + "\033[24m";
+ l += opt.argument.length() + 1;
+ }
+ lines.add(line);
+ lens.add(new int[] { l });
+ }
+
+ int col = lens.size();
+ col += 8 - ((col - 4) & 7);
+ int index = 0;
+ while (empty.length() < col)
+ empty += empty;
+ empty = empty.substring(0, col);
+ for (final Option opt : this.options)
+ { if (opt.help == null)
+ continue;
+ boolean first = true;
+ final String colour = (index & 1) == 0 ? "36" : "34";
+ { String line = lines.get(index).replace("%colour%", "\033[" + colour + ";01m");
+ line += empty.substring(lens.get(index)[0]);
+ this.print(line, false);
+ }
+ for (final String line : opt.help.split("\n"))
+ if (first)
+ { first = false;
+ print(line + "\033[00m\n");
+ }
+ else
+ print(empty + "\033[" + colour + "m" + line + "\033[00m\n");
+ index++;
+ }
+
+ this.println(true);
+ }
+
+
+ /**
+ * Parse arguments
+ *
+ * @param args The command line arguments, however it should not include the execute file at index 0
+ * @return Whether no unrecognised option is used
+ */
+ public boolean parse(final String[] argv)
+ {
+ this.arguments = argv;
+
+ final ArrayList<String> argqueue = new ArrayList<String>();
+ final ArrayList<String> optqueue = new ArrayList<String>();
+ final ArrayList<String> queue = new ArrayList<String>();
+ for (final String arg : argv)
+ queue.add(arg);
+
+ boolean dashed = false, tmpdashed = false, rc = true;
+ int get = 0, dontget = 0;
+
+ while (queue.size() > 0)
+ { final String arg = queue.remove(0);
+ if ((get > 0) && (dontget == 0))
+ { get--;
+ argqueue.add(arg);
+ }
+ else if (tmpdashed)
+ { this.files.add(arg);
+ tmpdashed = false;
+ }
+ else if (dashed) this.files.add(arg);
+ else if (arg.equals("++")) tmpdashed = true;
+ else if (arg.equals("--")) dashed = true;
+ else if ((arg.length() > 1) && ((arg.charAt(0) == '-') || (arg.charAt(0) == '+')))
+ if ((arg.length() > 2) && (arg.charAt(1) == arg.charAt(0)))
+ { Option opt = this.optmap.get(arg);
+ if (dontget > 0)
+ dontget--;
+ else if ((opt != null) && (opt.getClass() == Argumentless.class))
+ { optqueue.add(arg);
+ argqueue.add(null);
+ }
+ else if (arg.contains("="))
+ { String arg_opt = arg.substring(0, arg.indexOf('='));
+ Option arg_opt_opt = this.optmap.get(arg_opt);
+ if ((arg_opt_opt != null) && (arg_opt_opt instanceof Argumented))
+ { optqueue.add(arg_opt);
+ argqueue.add(arg.substring(arg.indexOf('=') + 1));
+ if (arg_opt_opt instanceof Variadic)
+ dashed = true;
+ }
+ else
+ { if (++this.unrecognisedCount <= 5)
+ this.println(this.program + ": warning: unrecognised option " + arg, true);
+ rc = false;
+ }
+ }
+ else if ((opt != null) && (opt.getClass() == Argumented.class))
+ { optqueue.add(arg);
+ get++;
+ }
+ else if ((opt != null) && (opt.getClass() == Variadic.class))
+ { optqueue.add(arg);
+ argqueue.add(null);
+ dashed = true;
+ }
+ else
+ { if (++this.unrecognisedCount <= 5)
+ this.println(this.program + ": warning: unrecognised option " + arg, true);
+ rc = false;
+ }
+ }
+ else
+ { String sign = String.valueOf(arg.charAt(0)), narg;
+ int i = 1, n = arg.length();
+ while (i < n)
+ { Option opt = this.optmap.get(narg = sign + arg.charAt(i++));
+ if (opt != null)
+ if (opt.getClass() == Argumentless.class)
+ { optqueue.add(narg);
+ argqueue.add(null);
+ }
+ else if (opt.getClass() == Argumented.class)
+ { optqueue.add(narg);
+ String nargarg = arg.substring(i);
+ if (nargarg.length() == 0)
+ get++;
+ else
+ argqueue.add(nargarg);
+ break;
+ }
+ else
+ { optqueue.add(narg);
+ String nargarg = arg.substring(i);
+ argqueue.add(nargarg.length() > 0 ? nargarg : null);
+ dashed = true;
+ break;
+ }
+ else
+ { if (++this.unrecognisedCount <= 5)
+ this.println(this.program + ": warning: unrecognised option " + arg, true);
+ rc = false;
+ }
+ } }
+ else
+ this.files.add(arg);
+ }
+
+ return rc;
+ }
+
+}
+