From 416f05e35758995eedd5a5a87d0a7326dbbbc4cb Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 21 May 2007 10:27:41 +0000
Subject: [PATCH] Add support for trailing arguments in sub-command argument parser (includes unit tests).

---
 opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java |  102 ++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 84 insertions(+), 18 deletions(-)

diff --git a/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java b/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
index f006681..72bcea9 100644
--- a/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
+++ b/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
@@ -31,9 +31,12 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Properties;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import org.opends.server.core.DirectoryServer;
 
@@ -61,6 +64,9 @@
   // The argument that will be used to trigger the display of usage information.
   private Argument usageArgument;
 
+  // The set of unnamed trailing arguments that were provided for this parser.
+  private ArrayList<String> trailingArguments;
+
   // Indicates whether subcommand and long argument names should be treated in a
   // case-sensitive manner.
   private boolean longArgumentsCaseSensitive;
@@ -82,7 +88,7 @@
 
   // The set of subcommands defined for this parser, referenced by subcommand
   // name.
-  private HashMap<String,SubCommand> subCommands;
+  private SortedMap<String,SubCommand> subCommands;
 
   // The total set of global arguments defined for this parser.
   private LinkedList<Argument> globalArgumentList;
@@ -128,11 +134,12 @@
     this.toolDescription            = toolDescription;
     this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
 
+    trailingArguments  = new ArrayList<String>();
     globalArgumentList = new LinkedList<Argument>();
     globalArgumentMap  = new HashMap<String,Argument>();
     globalShortIDMap   = new HashMap<Character,Argument>();
     globalLongIDMap    = new HashMap<String,Argument>();
-    subCommands        = new HashMap<String,SubCommand>();
+    subCommands        = new TreeMap<String,SubCommand>();
     usageDisplayed     = false;
     rawArguments       = null;
     subCommand         = null;
@@ -331,7 +338,7 @@
    * @return  The set of subcommands defined for this argument parser,
    *          referenced by subcommand name.
    */
-  public HashMap<String,SubCommand> getSubCommands()
+  public SortedMap<String,SubCommand> getSubCommands()
   {
     return subCommands;
   }
@@ -649,19 +656,35 @@
          throws ArgumentException
   {
     this.rawArguments = rawArguments;
+    this.subCommand = null;
+    this.trailingArguments = new ArrayList<String>();
+    this.usageDisplayed = false;
+
+    boolean inTrailingArgs = false;
 
     int numArguments = rawArguments.length;
     for (int i=0; i < numArguments; i++)
     {
       String arg = rawArguments[i];
 
+      if (inTrailingArgs)
+      {
+        trailingArguments.add(arg);
+        if ((subCommand.getMaxTrailingArguments() > 0) &&
+            (trailingArguments.size() > subCommand.getMaxTrailingArguments()))
+        {
+          int    msgID   = MSGID_ARGPARSER_TOO_MANY_TRAILING_ARGS;
+          String message = getMessage(msgID, subCommand
+              .getMaxTrailingArguments());
+          throw new ArgumentException(msgID, message);
+        }
+
+        continue;
+      }
+
       if (arg.equals("--"))
       {
-        // This is not legal because we don't allow unnamed trailing arguments
-        // in this parser.
-        int    msgID   = MSGID_SUBCMDPARSER_LONG_ARG_WITHOUT_NAME;
-        String message = getMessage(msgID, arg);
-        throw new ArgumentException(msgID, message);
+        inTrailingArgs = true;
       }
       else if (arg.startsWith("--"))
       {
@@ -1056,11 +1079,26 @@
           }
         }
       }
+      else if (subCommand != null)
+      {
+        // It's not a short or long identifier and the sub-command has
+        // already been specified, so it must be the first trailing argument.
+        if (subCommand.allowsTrailingArguments())
+        {
+          trailingArguments.add(arg);
+          inTrailingArgs = true;
+        }
+        else
+        {
+          // Trailing arguments are not allowed for this sub-command.
+          int    msgID   = MSGID_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT;
+          String message = getMessage(msgID, arg);
+          throw new ArgumentException(msgID, message);
+        }
+      }
       else
       {
-        // It's not a short or long identifier, so check to see if it is a
-        // subcommand name.  If not, then it's invalid.  If so, then make sure
-        // that it was the only subcommand provided.
+        // It must be the sub-command.
         String nameToCheck = arg;
         if (! longArgumentsCaseSensitive)
         {
@@ -1074,19 +1112,29 @@
           String message = getMessage(msgID, arg);
           throw new ArgumentException(msgID, message);
         }
-        else if (subCommand == null)
-        {
-          subCommand = sc;
-        }
         else
         {
-          int    msgID   = MSGID_SUBCMDPARSER_MULTIPLE_SUBCOMMANDS;
-          String message = getMessage(msgID, arg, subCommand.getName());
-          throw new ArgumentException(msgID, message);
+          subCommand = sc;
         }
       }
     }
 
+    // If we have a sub-command and it allows trailing arguments and
+    // there is a minimum number, then make sure at least that many
+    // were provided.
+    if (subCommand != null)
+    {
+      int minTrailingArguments = subCommand.getMinTrailingArguments();
+      if (subCommand.allowsTrailingArguments() && (minTrailingArguments > 0))
+      {
+        if (trailingArguments.size() < minTrailingArguments)
+        {
+          int msgID = MSGID_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS;
+          String message = getMessage(msgID, minTrailingArguments);
+          throw new ArgumentException(msgID, message);
+        }
+      }
+    }
 
     // Iterate through all the global arguments and make sure that they have
     // values or a suitable default is available.
@@ -1321,6 +1369,10 @@
     buffer.append(" ");
     buffer.append(subCommand.getName());
     buffer.append(" {options}");
+    if (subCommand.allowsTrailingArguments()) {
+      buffer.append(' ');
+      buffer.append(subCommand.getTrailingArgumentsDisplayName());
+    }
     buffer.append(EOL);
     buffer.append(subCommand.getDescription());
     buffer.append(EOL);
@@ -1479,6 +1531,20 @@
 
 
   /**
+   * Retrieves the set of unnamed trailing arguments that were provided on the
+   * command line.
+   *
+   * @return  The set of unnamed trailing arguments that were provided on the
+   *          command line.
+   */
+  public ArrayList<String> getTrailingArguments()
+  {
+    return trailingArguments;
+  }
+
+
+
+  /**
    * Indicates whether the usage information has been displayed to the end user
    * either by an explicit argument like "-H" or "--help", or by a built-in
    * argument like "-?".

--
Gitblit v1.10.0