فهرست منبع

2009-02-07 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Added OptionParser::parseArg() which internally uses getopt_long
	to parse command-line options. All command-line options are now
	configured by OptionHandler. No manual editing of struct option*
	is required any more.
	* src/NameMatchOptionHandler.h
	* src/OptionHandler.h
	* src/OptionHandlerFactory.cc
	* src/OptionHandlerImpl.h
	* src/OptionParser.cc
	* src/OptionParser.h
	* src/array_fun.h
	* src/main.cc
	* src/option_processing.cc
	* test/OptionHandlerTest.cc
	* test/OptionParserTest.cc
Tatsuhiro Tsujikawa 16 سال پیش
والد
کامیت
2881dbe025
12فایلهای تغییر یافته به همراه817 افزوده شده و 839 حذف شده
  1. 18 0
      ChangeLog
  2. 46 9
      src/NameMatchOptionHandler.h
  3. 18 2
      src/OptionHandler.h
  4. 185 95
      src/OptionHandlerFactory.cc
  5. 103 53
      src/OptionHandlerImpl.h
  6. 178 19
      src/OptionParser.cc
  7. 19 3
      src/OptionParser.h
  8. 37 0
      src/array_fun.h
  9. 27 26
      src/main.cc
  10. 41 526
      src/option_processing.cc
  11. 63 92
      test/OptionHandlerTest.cc
  12. 82 14
      test/OptionParserTest.cc

+ 18 - 0
ChangeLog

@@ -1,3 +1,21 @@
+2009-02-07  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Added OptionParser::parseArg() which internally uses getopt_long
+	to parse command-line options. All command-line options are now
+	configured by OptionHandler. No manual editing of struct option*
+	is required any more.
+	* src/NameMatchOptionHandler.h
+	* src/OptionHandler.h
+	* src/OptionHandlerFactory.cc
+	* src/OptionHandlerImpl.h
+	* src/OptionParser.cc
+	* src/OptionParser.h
+	* src/array_fun.h
+	* src/main.cc
+	* src/option_processing.cc
+	* test/OptionHandlerTest.cc
+	* test/OptionParserTest.cc
+	
 2009-02-07  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Fixed configure error with --disable-epoll

+ 46 - 9
src/NameMatchOptionHandler.h

@@ -36,14 +36,17 @@
 #define _D_NAME_MATCH_OPTION_HANDLER_H_
 
 #include "OptionHandler.h"
-#include "A2STR.h"
-#include "Util.h"
-#include "OptionHandlerException.h"
+
 #include <strings.h>
+
 #include <algorithm>
 #include <sstream>
 #include <iterator>
 
+#include "A2STR.h"
+#include "Util.h"
+#include "OptionHandlerException.h"
+
 #define NO_DESCRIPTION A2STR::NIL
 #define NO_DEFAULT_VALUE A2STR::NIL
 
@@ -59,20 +62,30 @@ protected:
 
   std::string _defaultValue;
 
-  bool _hidden;
-
   std::deque<std::string> _tags;
 
-  virtual void parseArg(Option* option, const std::string& arg) = 0;
+  int _id;
+
+  OptionHandler::ARG_TYPE _argType;
+
+  char _shortName;
+
+  bool _hidden;
+
+  virtual void parseArg(Option& option, const std::string& arg) = 0;
 public:
   NameMatchOptionHandler(const std::string& optName,
 			 const std::string& description = NO_DESCRIPTION,
 			 const std::string& defaultValue = NO_DEFAULT_VALUE,
-			 bool hidden = false):
+			 ARG_TYPE argType = REQ_ARG,
+			 char shortName = 0):
     _optName(optName),
     _description(description),
     _defaultValue(defaultValue),
-    _hidden(hidden) {}
+    _id(0),
+    _argType(argType),
+    _shortName(shortName),
+    _hidden(false) {}
 
   virtual ~NameMatchOptionHandler() {}
   
@@ -81,7 +94,7 @@ public:
     return strcasecmp(_optName.c_str(), optName.c_str()) == 0;
   }
 
-  virtual void parse(Option* option, const std::string& arg)
+  virtual void parse(Option& option, const std::string& arg)
   {
     try {
       parseArg(option, arg);
@@ -128,6 +141,30 @@ public:
     return _hidden;
   }
 
+  void hide()
+  {
+    _hidden = true;
+  }
+
+  virtual char getShortName() const
+  {
+    return _shortName;
+  }
+
+  virtual int getOptionID() const
+  {
+    return _id;
+  }
+
+  virtual void setOptionID(int id)
+  {
+    _id = id;
+  }
+
+  virtual OptionHandler::ARG_TYPE getArgType() const
+  {
+    return _argType;
+  }
 };
 
 typedef SharedHandle<NameMatchOptionHandler> NameMatchOptionHandlerHandle;

+ 18 - 2
src/OptionHandler.h

@@ -36,11 +36,13 @@
 #define _D_OPTION_HANDLER_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <string>
 #include <deque>
 #include <iosfwd>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 class Option;
@@ -50,7 +52,7 @@ public:
   virtual ~OptionHandler() {}
   
   virtual bool canHandle(const std::string& optName) = 0;
-  virtual void parse(Option* option, const std::string& arg) = 0;
+  virtual void parse(Option& option, const std::string& arg) = 0;
 
   virtual std::string createPossibleValuesString() const = 0;
 
@@ -67,6 +69,20 @@ public:
   virtual const std::string& getDefaultValue() const = 0;
 
   virtual bool isHidden() const = 0;
+
+  enum ARG_TYPE {
+    REQ_ARG,
+    OPT_ARG,
+    NO_ARG
+  };
+
+  virtual ARG_TYPE getArgType() const = 0;
+
+  virtual char getShortName() const = 0;
+
+  virtual int getOptionID() const = 0;
+
+  virtual void setOptionID(int id) = 0;
 };
 
 typedef SharedHandle<OptionHandler> OptionHandlerHandle;

+ 185 - 95
src/OptionHandlerFactory.cc

@@ -64,19 +64,23 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   } 
+#ifdef ENABLE_ASYNC_DNS
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ASYNC_DNS,
 				    TEXT_ASYNC_DNS,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+#endif // ENABLE_ASYNC_DNS
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_AUTO_FILE_RENAMING,
 				    TEXT_AUTO_FILE_RENAMING,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
@@ -89,16 +93,20 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+#ifdef ENABLE_MESSAGE_DIGEST
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_CHECK_INTEGRITY,
 				    TEXT_CHECK_INTEGRITY,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG,
+				    'V'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_BITTORRENT);
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
+#endif // ENABLE_MESSAGE_DIGEST
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_CONF_PATH,
@@ -111,7 +119,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_CONTINUE,
 				    TEXT_CONTINUE,
-				    V_FALSE)); // TODO ommit?
+				    V_FALSE, // TODO ommit?
+				    OptionHandler::NO_ARG,
+				    'c'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
@@ -121,7 +131,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_DAEMON,
 				    TEXT_DAEMON,
-				    V_FALSE)); // TODO ommit?
+				    V_FALSE,
+				    OptionHandler::NO_ARG,
+				    'D')); // TODO ommit?
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
@@ -129,32 +141,39 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_DIR,
 				    TEXT_DIR,
-				    "."));
+				    ".",
+				    A2STR::NIL,
+				    OptionHandler::REQ_ARG,
+				    'd'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_DNS_TIMEOUT,
-				    NO_DESCRIPTION,
-				    "30",
-				    1, 60,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_DNS_TIMEOUT,
+					  NO_DESCRIPTION,
+					  "30",
+					  1, 60));
+    op->hide();
     handlers.push_back(op);
   }
+#ifdef ENABLE_DIRECT_IO
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_DIRECT_IO,
 				    TEXT_ENABLE_DIRECT_IO,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+#endif // ENABLE_DIRECT_IO
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_HTTP_SERVER,
 				    TEXT_ENABLE_HTTP_SERVER,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_EXPERIMENTAL);
     handlers.push_back(op);
   }
@@ -183,7 +202,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_FILE_ALLOCATION,
 				    TEXT_FILE_ALLOCATION,
 				    V_PREALLOC,
-				    V_NONE, V_PREALLOC));
+				    V_NONE, V_PREALLOC,
+				    'a'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
@@ -191,7 +211,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_FORCE_SEQUENTIAL,
 				    TEXT_FORCE_SEQUENTIAL,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG,
+				    'Z'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
@@ -209,7 +231,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_INPUT_FILE,
 				    TEXT_INPUT_FILE,
 				    NO_DEFAULT_VALUE,
-				    "FILENAME,-"));
+				    "FILENAME,-",
+				    OptionHandler::REQ_ARG,
+				    'i'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
@@ -218,7 +242,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_LOG,
 				    TEXT_LOG,
 				    NO_DEFAULT_VALUE,
-				    "FILENAME,-"));
+				    "FILENAME,-",
+				    OptionHandler::REQ_ARG,
+				    'l'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
@@ -239,7 +265,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_MAX_CONCURRENT_DOWNLOADS,
 				    TEXT_MAX_CONCURRENT_DOWNLOADS,
 				    "5",
-				    1, 45));
+				    1, 45,
+				    'j'));
     op->addTag(TAG_BASIC);
     handlers.push_back(op);
   }
@@ -258,7 +285,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_NO_CONF,
 				    TEXT_NO_CONF,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::NO_ARG));
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
@@ -275,7 +303,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_PARAMETERIZED_URI,
 				    TEXT_PARAMETERIZED_URI,
-				    V_FALSE));  
+				    V_FALSE,
+				    OptionHandler::OPT_ARG,
+				    'P'));  
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
@@ -283,10 +313,13 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_QUIET,
 				    TEXT_QUIET,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG,
+				    'q'));
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
   }
+#ifdef ENABLE_MESSAGE_DIGEST
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_REALTIME_CHUNK_CHECKSUM,
@@ -295,6 +328,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
+#endif // ENABLE_MESSAGE_DIGEST
   {
     SharedHandle<OptionHandler> op(new NumberOptionHandler
 				   (PREF_STOP,
@@ -349,7 +383,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_MAX_TRIES,
 				    TEXT_MAX_TRIES,
 				    "5",
-				    0));
+				    0, -1,
+				    'm'));
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
@@ -359,7 +394,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_OUT,
 				    TEXT_OUT,
 				    NO_DEFAULT_VALUE,
-				    "FILENAME"));
+				    "FILENAME",
+				    OptionHandler::REQ_ARG,
+				    'o'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
@@ -369,7 +406,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_REMOTE_TIME,
 				    TEXT_REMOTE_TIME,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG,
+				    'R'));
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
@@ -385,12 +424,12 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new UnitNumberOptionHandler
-				   (PREF_SEGMENT_SIZE,
-				    NO_DESCRIPTION,
-				    "1M",
-				    1024, -1,
-				    true));
+    SharedHandle<UnitNumberOptionHandler> op(new UnitNumberOptionHandler
+					     (PREF_SEGMENT_SIZE,
+					      NO_DESCRIPTION,
+					      "1M",
+					      1024, -1));
+    op->hide();
     handlers.push_back(op);
   }
   {
@@ -428,19 +467,20 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_SPLIT,
 				    TEXT_SPLIT,
 				    "5",
-				    1));
+				    1, -1,
+				    's'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_STARTUP_IDLE_TIME,
-				    NO_DESCRIPTION,
-				    "10",
-				    1, 60,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_STARTUP_IDLE_TIME,
+					  NO_DESCRIPTION,
+					  "10",
+					  1, 60));
+    op->hide();
     handlers.push_back(op);
   }
   {
@@ -448,7 +488,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_TIMEOUT,
 				    TEXT_TIMEOUT,
 				    "60",
-				    1, 600));
+				    1, 600,
+				    't'));
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
@@ -487,7 +528,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_CHECK_CERTIFICATE,
 				    TEXT_CHECK_CERTIFICATE,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_HTTP);
     op->addTag(TAG_HTTPS);
     handlers.push_back(op);
@@ -496,7 +538,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_HTTP_KEEP_ALIVE,
 				    TEXT_ENABLE_HTTP_KEEP_ALIVE,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
@@ -504,7 +547,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_HTTP_PIPELINING,
 				    TEXT_ENABLE_HTTP_PIPELINING,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
@@ -553,12 +597,12 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_MAX_HTTP_PIPELINING,
-				    NO_DESCRIPTION,
-				    "2",
-				    1, 8,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_MAX_HTTP_PIPELINING,
+					  NO_DESCRIPTION,
+					  "2",
+					  1, 8));
+    op->hide();
     handlers.push_back(op);
   }
   {
@@ -577,10 +621,11 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new DefaultOptionHandler
+    SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_USE_HEAD,
 				    TEXT_USE_HEAD,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
@@ -588,7 +633,10 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_USER_AGENT,
 				    TEXT_USER_AGENT,
-				    "aria2"));
+				    "aria2",
+				    A2STR::NIL,
+				    OptionHandler::REQ_ARG,
+				    'U'));
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
   }
@@ -605,7 +653,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_FTP_PASV,
 				    TEXT_FTP_PASV,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG,
+				    'p'));
     op->addTag(TAG_FTP);
     handlers.push_back(op);
   }
@@ -613,7 +663,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_FTP_REUSE_CONNECTION,
 				    TEXT_FTP_REUSE_CONNECTION,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_FTP);
     handlers.push_back(op);
   }
@@ -635,19 +686,21 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new DefaultOptionHandler
-				   (PREF_NETRC_PATH,
-				    NO_DESCRIPTION,
-				    Util::getHomeDir()+"/.netrc",
-				    "/PATH/TO/NETRC",
-				    true));
+    SharedHandle<DefaultOptionHandler> op(new DefaultOptionHandler
+					  (PREF_NETRC_PATH,
+					   NO_DESCRIPTION,
+					   Util::getHomeDir()+"/.netrc",
+					   "/PATH/TO/NETRC"));
+    op->hide();
     handlers.push_back(op);
   }
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_NO_NETRC,
 				    TEXT_NO_NETRC,
-				    V_FALSE)); // TODO ommit?
+				    V_FALSE, // TODO ommit?
+				    OptionHandler::NO_ARG,
+				    'n'));
     op->addTag(TAG_FTP);
     op->addTag(TAG_HTTP);
     handlers.push_back(op);
@@ -705,6 +758,7 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   // BitTorrent/Metalink Options
+#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK
   {
     SharedHandle<OptionHandler> op(new IntegerRangeOptionHandler
 				   (PREF_SELECT_FILE,
@@ -719,13 +773,17 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_SHOW_FILES,
 				    TEXT_SHOW_FILES,
-				    V_FALSE)); // TODO ommit?
+				    V_FALSE, // TODO ommit?
+				    OptionHandler::NO_ARG,
+				    'S'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_BITTORRENT);
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
+#endif // ENABLE_BITTORRENT || ENABLE_METALINK
   // BitTorrent Specific Options
+#ifdef ENABLE_BITTORRENT
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_BT_EXTERNAL_IP,
@@ -736,19 +794,20 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_BT_KEEP_ALIVE_INTERVAL,
-				    NO_DESCRIPTION,
-				    "120",
-				    1, 120,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_BT_KEEP_ALIVE_INTERVAL,
+					  NO_DESCRIPTION,
+					  "120",
+					  1, 120));
+    op->hide();
     handlers.push_back(op);
   }
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_BT_HASH_CHECK_SEED,
 				    TEXT_BT_HASH_CHECK_SEED,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
   }
@@ -798,29 +857,30 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_BT_REQUEST_TIMEOUT,
-				    NO_DESCRIPTION,
-				    "60",
-				    1, 600,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_BT_REQUEST_TIMEOUT,
+					  NO_DESCRIPTION,
+					  "60",
+					  1, 600));
+    op->hide();
     handlers.push_back(op);
   }
   {
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_BT_SEED_UNVERIFIED,
 				    TEXT_BT_SEED_UNVERIFIED,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_BT_TIMEOUT,
-				    NO_DESCRIPTION,
-				    "180",
-				    1, 600,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_BT_TIMEOUT,
+					  NO_DESCRIPTION,
+					  "180",
+					  1, 600));
+    op->hide();
     handlers.push_back(op);
   }
   {
@@ -864,7 +924,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_DHT,
 				    TEXT_ENABLE_DHT,
-				    V_FALSE));
+				    V_FALSE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
@@ -873,7 +934,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_ENABLE_PEER_EXCHANGE,
 				    TEXT_ENABLE_PEER_EXCHANGE,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
   }
@@ -911,18 +973,19 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_MAX_UPLOAD_LIMIT,
 				    TEXT_MAX_UPLOAD_LIMIT,
 				    "0",
-				    0));
+				    0, -1,
+				    'u'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
   }
   {
-    SharedHandle<OptionHandler> op(new NumberOptionHandler
-				   (PREF_PEER_CONNECTION_TIMEOUT,
-				    NO_DESCRIPTION,
-				    "20",
-				    1, 600,
-				    true));
+    SharedHandle<NumberOptionHandler> op(new NumberOptionHandler
+					 (PREF_PEER_CONNECTION_TIMEOUT,
+					  NO_DESCRIPTION,
+					  "20",
+					  1, 600));
+    op->hide();
     handlers.push_back(op);
   }
   {
@@ -954,12 +1017,18 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_TORRENT_FILE,
-				    TEXT_TORRENT_FILE));
+				    TEXT_TORRENT_FILE,
+				    NO_DEFAULT_VALUE,
+				    A2STR::NIL,
+				    OptionHandler::REQ_ARG,
+				    'T'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_BITTORRENT);
     handlers.push_back(op);
   }
+#endif // ENABLE_BITTORRENT
   // Metalink Specific Options
+#ifdef ENABLE_METALINK
   {
     SharedHandle<OptionHandler> op(new ParameterOptionHandler
 				   (PREF_FOLLOW_METALINK,
@@ -973,14 +1042,19 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     SharedHandle<OptionHandler> op(new BooleanOptionHandler
 				   (PREF_METALINK_ENABLE_UNIQUE_PROTOCOL,
 				    TEXT_METALINK_ENABLE_UNIQUE_PROTOCOL,
-				    V_TRUE));
+				    V_TRUE,
+				    OptionHandler::OPT_ARG));
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
 				   (PREF_METALINK_FILE,
-				    TEXT_METALINK_FILE));
+				    TEXT_METALINK_FILE,
+				    NO_DEFAULT_VALUE,
+				    A2STR::NIL,
+				    OptionHandler::REQ_ARG,
+				    'M'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
@@ -1022,7 +1096,8 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 				   (PREF_METALINK_SERVERS,
 				    TEXT_METALINK_SERVERS,
 				    "5",
-				    1));
+				    1, -1,
+				    'C'));
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
@@ -1033,6 +1108,19 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_METALINK);
     handlers.push_back(op);
   }
+#endif // ENABLE_METALINK
+  // Version Option
+  {
+    SharedHandle<OptionHandler> op(new DefaultOptionHandler
+				   ("version",
+				    TEXT_VERSION,
+				    NO_DEFAULT_VALUE,
+				    A2STR::NIL,
+				    OptionHandler::NO_ARG,
+				    'v'));
+    op->addTag(TAG_BASIC);
+    handlers.push_back(op);
+  }
   // Help Option
   {
     SharedHandle<OptionHandler> op(new DefaultOptionHandler
@@ -1048,7 +1136,9 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers()
 						 TAG_METALINK,
 						 TAG_BITTORRENT,
 						 TAG_EXPERIMENTAL,
-						 TAG_HELP).str()));
+						 TAG_HELP).str(),
+				    OptionHandler::OPT_ARG,
+				    'h'));
     op->addTag(TAG_BASIC);
     op->addTag(TAG_HELP);
     handlers.push_back(op);

+ 103 - 53
src/OptionHandlerImpl.h

@@ -56,12 +56,14 @@
 namespace aria2 {
 
 class NullOptionHandler : public OptionHandler {
+private:
+  int _id;
 public:
   virtual ~NullOptionHandler() {}
 
   virtual bool canHandle(const std::string& optName) { return true; }
 
-  virtual void parse(Option* option, const std::string& arg) {}
+  virtual void parse(Option& option, const std::string& arg) {}
 
   virtual bool hasTag(const std::string& tag) const { return false; }
 
@@ -78,23 +80,47 @@ public:
   virtual std::string createPossibleValuesString() const { return A2STR::NIL; }
 
   virtual bool isHidden() const { return true; }
+
+  virtual OptionHandler::ARG_TYPE getArgType() const
+  {
+    return OptionHandler::NO_ARG;
+  }
+
+  virtual int getOptionID() const
+  {
+    return _id;
+  }
+
+  virtual void setOptionID(int id)
+  {
+    _id = id;
+  }
+
+  virtual char getShortName() const
+  {
+    return 0;
+  }
 };
 
 class BooleanOptionHandler : public NameMatchOptionHandler {
 public:
   BooleanOptionHandler(const std::string& optName,
 		       const std::string& description = NO_DESCRIPTION,
-		       const std::string& defaultValue = NO_DEFAULT_VALUE):
-    NameMatchOptionHandler(optName, description, defaultValue) {}
+		       const std::string& defaultValue = NO_DEFAULT_VALUE,
+		       OptionHandler::ARG_TYPE argType = OptionHandler::REQ_ARG,
+		       char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   argType, shortName) {}
 
   virtual ~BooleanOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
-    if(optarg == "true") {
-      option->put(_optName, V_TRUE);
+    if(optarg == "true" ||
+       (_argType == OptionHandler::OPT_ARG && optarg.empty())) {
+      option.put(_optName, V_TRUE);
     } else if(optarg == "false") {
-      option->put(_optName, V_FALSE);
+      option.put(_optName, V_FALSE);
     } else {
       std::string msg = _optName+" "+_("must be either 'true' or 'false'.");
       throw FatalException(msg);
@@ -115,13 +141,15 @@ public:
   IntegerRangeOptionHandler(const std::string& optName,
 			    const std::string& description,
 			    const std::string& defaultValue,
-			    int32_t min, int32_t max):
-    NameMatchOptionHandler(optName, description, defaultValue),
+			    int32_t min, int32_t max,
+			    char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName),
     _min(min), _max(max) {}
 
   virtual ~IntegerRangeOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     IntSequence seq = Util::parseIntRange(optarg);
     while(seq.hasNext()) {
@@ -132,7 +160,7 @@ public:
 	  (StringFormat(msg.c_str(), Util::itos(_min).c_str(),
 			Util::itos(_max).c_str()).str());
       }
-      option->put(_optName, optarg);
+      option.put(_optName, optarg);
     }
   }
 
@@ -152,22 +180,23 @@ public:
 		      const std::string& defaultValue = NO_DEFAULT_VALUE,
 		      int64_t min = -1,
 		      int64_t max = -1,
-		      bool hidden = false):
-    NameMatchOptionHandler(optName, description, defaultValue, hidden),
+		      char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName),
     _min(min), _max(max) {}
 
   virtual ~NumberOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     int64_t num = Util::parseLLInt(optarg);
     parseArg(option, num);
   }
 
-  void parseArg(Option* option, int64_t number)
+  void parseArg(Option& option, int64_t number)
   {
     if((_min == -1 || _min <= number) && (_max ==  -1 || number <= _max)) {
-      option->put(_optName, Util::itos(number));
+      option.put(_optName, Util::itos(number));
     } else {
       std::string msg = _optName+" ";
       if(_min == -1 && _max != -1) {
@@ -200,12 +229,13 @@ public:
 			  const std::string& defaultValue = NO_DEFAULT_VALUE,
 			  int64_t min = -1,
 			  int64_t max = -1,
-			  bool hidden = false):
-    NumberOptionHandler(optName, description, defaultValue, min, max, hidden) {}
+			  char shortName = 0):
+    NumberOptionHandler(optName, description, defaultValue, min, max,
+			shortName) {}
 
   virtual ~UnitNumberOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     int64_t num = Util::getRealSize(optarg);
     NumberOptionHandler::parseArg(option, num);
@@ -220,17 +250,19 @@ public:
   FloatNumberOptionHandler(const std::string& optName,
 			   const std::string& description = NO_DESCRIPTION,
 			   const std::string& defaultValue = NO_DEFAULT_VALUE,
-			   double min = -1, double max = -1):
-    NameMatchOptionHandler(optName, description, defaultValue),
+			   double min = -1, double max = -1,
+			   char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName),
     _min(min), _max(max) {}
 
   virtual ~FloatNumberOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     double number = strtod(optarg.c_str(), 0);
     if((_min < 0 || _min <= number) && (_max < 0 || number <= _max)) {
-      option->put(_optName, optarg);
+      option.put(_optName, optarg);
     } else {
       std::string msg = _optName+" ";
       if(_min < 0 && _max >= 0) {
@@ -279,15 +311,17 @@ public:
 		       const std::string& description = NO_DESCRIPTION,
 		       const std::string& defaultValue = NO_DEFAULT_VALUE,
 		       const std::string& possibleValuesString = A2STR::NIL,
-		       bool hidden = false):
-    NameMatchOptionHandler(optName, description, defaultValue, hidden),
+		       OptionHandler::ARG_TYPE argType = OptionHandler::REQ_ARG,
+		       char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue, argType,
+			   shortName),
     _possibleValuesString(possibleValuesString) {}
 
   virtual ~DefaultOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
-    option->put(_optName, optarg);
+    option.put(_optName, optarg);
   }
 
   virtual std::string createPossibleValuesString() const
@@ -306,18 +340,22 @@ public:
 			  const std::string& description,
 			  const std::string& defaultValue,
 			  const std::string& delim,
-			  const std::string& possibleValuesString = A2STR::NIL):
-    NameMatchOptionHandler(optName, description, defaultValue),
+			  const std::string& possibleValuesString = A2STR::NIL,
+			  OptionHandler::ARG_TYPE argType =
+			  OptionHandler::REQ_ARG,
+			  char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue, argType,
+			   shortName),
     _delim(delim),
     _possibleValuesString(possibleValuesString) {}
 
   virtual ~CumulativeOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
-    std::string value = option->get(_optName);
+    std::string value = option.get(_optName);
     value += optarg+_delim;
-    option->put(_optName, value);
+    option.put(_optName, value);
   }
 
   virtual std::string createPossibleValuesString() const
@@ -333,15 +371,19 @@ public:
   ParameterOptionHandler(const std::string& optName,
 			 const std::string& description,
 			 const std::string& defaultValue,
-			 const std::deque<std::string>& validParamValues):
-    NameMatchOptionHandler(optName, description, defaultValue),
+			 const std::deque<std::string>& validParamValues,
+			 char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName),
     _validParamValues(validParamValues) {}
 
   ParameterOptionHandler(const std::string& optName,
 			 const std::string& description,
 			 const std::string& defaultValue,
-			 const std::string& validParamValue):
-    NameMatchOptionHandler(optName, description, defaultValue)
+			 const std::string& validParamValue,
+			 char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName)
   {
     _validParamValues.push_back(validParamValue);
   }
@@ -350,8 +392,10 @@ public:
 			 const std::string& description,
 			 const std::string& defaultValue,
 			 const std::string& validParamValue1,
-			 const std::string& validParamValue2):
-    NameMatchOptionHandler(optName, description, defaultValue)
+			 const std::string& validParamValue2,
+			 char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName)
   {
     _validParamValues.push_back(validParamValue1);
     _validParamValues.push_back(validParamValue2);
@@ -362,8 +406,10 @@ public:
 			 const std::string& defaultValue,
 			 const std::string& validParamValue1,
 			 const std::string& validParamValue2,
-			 const std::string& validParamValue3):
-    NameMatchOptionHandler(optName, description, defaultValue)
+			 const std::string& validParamValue3,
+			 char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName)
   {
     _validParamValues.push_back(validParamValue1);
     _validParamValues.push_back(validParamValue2);
@@ -372,7 +418,7 @@ public:
    
   virtual ~ParameterOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     std::deque<std::string>::const_iterator itr =
       std::find(_validParamValues.begin(), _validParamValues.end(), optarg);
@@ -388,7 +434,7 @@ public:
       }
       throw FatalException(msg);
     } else {
-      option->put(_optName, optarg);
+      option.put(_optName, optarg);
     }
   }
 
@@ -411,14 +457,16 @@ public:
 			const std::string& description,
 			const std::string& defaultValue,
 			const std::string& hostOptionName,
-			const std::string& portOptionName):
-    NameMatchOptionHandler(optName, description, defaultValue),
+			const std::string& portOptionName,
+			char shortName = 0):
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName),
     _hostOptionName(hostOptionName),
     _portOptionName(portOptionName) {}
 
   virtual ~HostPortOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     std::pair<std::string, std::string> proxy = Util::split(optarg, ":");
     int32_t port = Util::parseInt(proxy.second);
@@ -426,14 +474,14 @@ public:
        port <= 0 || 65535 < port) {
       throw FatalException(_("unrecognized proxy format"));
     }
-    option->put(_optName, optarg);
+    option.put(_optName, optarg);
     setHostAndPort(option, proxy.first, port);
   }
 
-  void setHostAndPort(Option* option, const std::string& hostname, uint16_t port)
+  void setHostAndPort(Option& option, const std::string& hostname, uint16_t port)
   {
-    option->put(_hostOptionName, hostname);
-    option->put(_portOptionName, Util::uitos(port));
+    option.put(_hostOptionName, hostname);
+    option.put(_portOptionName, Util::uitos(port));
   }
 
   virtual std::string createPossibleValuesString() const
@@ -446,14 +494,16 @@ class HttpProxyOptionHandler : public NameMatchOptionHandler {
 public:
   HttpProxyOptionHandler(const std::string& optName,
 			 const std::string& description,
-			 const std::string& defaultValue)
+			 const std::string& defaultValue,
+			 char shortName = 0)
     :
-    NameMatchOptionHandler(optName, description, defaultValue)
+    NameMatchOptionHandler(optName, description, defaultValue,
+			   OptionHandler::REQ_ARG, shortName)
   {}
 
   virtual ~HttpProxyOptionHandler() {}
 
-  virtual void parseArg(Option* option, const std::string& optarg)
+  virtual void parseArg(Option& option, const std::string& optarg)
   {
     Request req;
     std::string url;
@@ -463,7 +513,7 @@ public:
       url = "http://"+optarg;
     }
     if(req.setUrl(url)) {
-      option->put(_optName, url);
+      option.put(_optName, url);
     } else {
       throw FatalException(_("unrecognized proxy format"));
     }

+ 178 - 19
src/OptionParser.cc

@@ -33,17 +33,126 @@
  */
 /* copyright --> */
 #include "OptionParser.h"
+
+#include <unistd.h>
+#include <getopt.h>
+
+#include <cstring>
+#include <istream>
+#include <utility>
+
 #include "Util.h"
 #include "OptionHandlerImpl.h"
 #include "Option.h"
 #include "A2STR.h"
 #include "a2functional.h"
-#include <istream>
-#include <utility>
+#include "array_fun.h"
 
 namespace aria2 {
 
-void OptionParser::parse(Option* option, std::istream& is)
+OptionParser::OptionParser():_idCounter(0) {}
+
+template<typename InputIterator>
+static size_t countPublicOption(InputIterator first, InputIterator last)
+{
+  size_t count = 0;
+  for(; first != last; ++first) {
+    if(!(*first)->isHidden()) {
+      ++count;
+    }
+  }
+  return count;
+}
+
+template<typename InputIterator>
+static void putOptions(struct option* longOpts, int* plopt,
+		       InputIterator first, InputIterator last)
+{
+  for(; first != last; ++first) {
+    if(!(*first)->isHidden()) {
+      (*longOpts).name = (*first)->getName().c_str();
+      switch((*first)->getArgType()) {
+      case OptionHandler::REQ_ARG:
+	(*longOpts).has_arg = required_argument;
+	break;
+      case OptionHandler::OPT_ARG:
+	(*longOpts).has_arg = optional_argument;
+	break;
+      case OptionHandler::NO_ARG:
+	(*longOpts).has_arg = no_argument;
+	break;
+      default:
+	abort();
+      }
+      if((*first)->getShortName() == 0) {
+	(*longOpts).flag = plopt;
+	(*longOpts).val = (*first)->getOptionID();
+      } else {
+	(*longOpts).flag = 0;
+	(*longOpts).val = (*first)->getShortName();
+      }
+      ++longOpts;
+    }
+  }
+  (*longOpts).name = 0;
+  (*longOpts).has_arg = 0;
+  (*longOpts).flag = 0;
+  (*longOpts).val = 0;
+}
+
+template<typename InputIterator>
+static std::string createOptstring(InputIterator first, InputIterator last)
+{
+  std::string str = "";
+  for(; first != last; ++first) {
+    if(!(*first)->isHidden()) {
+      if((*first)->getShortName() != 0) {
+	str += (*first)->getShortName();
+	if((*first)->getArgType() == OptionHandler::REQ_ARG) {
+	  str += ":";
+	} else if((*first)->getArgType() == OptionHandler::OPT_ARG) {
+	  str += "::";
+	}
+      }
+    }
+  }
+  return str;
+}
+
+void OptionParser::parseArg
+(std::ostream& out, std::deque<std::string>& nonopts, int argc, char* const argv[])
+{
+  size_t numPublicOption = countPublicOption(_optionHandlers.begin(),
+					     _optionHandlers.end());
+  int lopt;
+  array_ptr<struct option> longOpts(new struct option[numPublicOption+1]);
+  putOptions(&longOpts[0], &lopt,_optionHandlers.begin(),_optionHandlers.end());
+  std::string optstring = createOptstring(_optionHandlers.begin(),
+					  _optionHandlers.end());
+  while(1) {
+    int c = getopt_long(argc, argv, optstring.c_str(), &longOpts[0], 0);
+    if(c == -1) {
+      break;
+    }
+    SharedHandle<OptionHandler> op;
+    if(c == 0) {
+      op = findByID(lopt);
+    } else {
+      op = findByShortName(c);
+    }
+    if(op.isNull()) {
+      throw FatalException("Unknown option");
+    }
+    out << op->getName() << "=";
+    if(optarg) {
+      out << optarg;
+    }
+    out << "\n";
+  }
+  std::copy(argv+optind, argv+argc, std::back_inserter(nonopts));
+}
+
+void OptionParser::parse(Option& option, std::istream& is)
 {
   std::string line;
   int32_t linenum = 0;
@@ -72,15 +181,20 @@ OptionHandlerHandle OptionParser::getOptionHandlerByName(const std::string& optN
 void OptionParser::setOptionHandlers(const std::deque<SharedHandle<OptionHandler> >& optionHandlers)
 {
   _optionHandlers = optionHandlers;
+  for(std::deque<SharedHandle<OptionHandler> >::iterator i =
+	_optionHandlers.begin(); i != _optionHandlers.end(); ++i) {
+    (*i)->setOptionID(++_idCounter);
+  }
 }
 
 void OptionParser::addOptionHandler
 (const SharedHandle<OptionHandler>& optionHandler)
 {
+  optionHandler->setOptionID(++_idCounter);
   _optionHandlers.push_back(optionHandler);
 }
 
-void OptionParser::parseDefaultValues(Option* option) const
+void OptionParser::parseDefaultValues(Option& option) const
 {
   for(std::deque<SharedHandle<OptionHandler> >::const_iterator i =
 	_optionHandlers.begin(); i != _optionHandlers.end(); ++i) {
@@ -137,6 +251,27 @@ OptionParser::findByNameSubstring(const std::string& substring) const
   return result;  
 }
 
+std::deque<SharedHandle<OptionHandler> > OptionParser::findAll() const
+{
+  std::deque<SharedHandle<OptionHandler> > result;
+  std::remove_copy_if(_optionHandlers.begin(), _optionHandlers.end(),
+		      std::back_inserter(result),
+		      mem_fun_sh(&OptionHandler::isHidden));
+  return result;
+}
+
+template<typename InputIterator, typename Predicate>
+static SharedHandle<OptionHandler> findOptionHandler
+(InputIterator first, InputIterator last, Predicate pred)
+{
+  InputIterator i = std::find_if(first, last, pred);
+  if(i == last) {
+    return SharedHandle<OptionHandler>();
+  } else {
+    return *i;
+  }
+}
+
 class FindByName :
   public std::unary_function<SharedHandle<OptionHandler> , bool> {
 private:
@@ -150,28 +285,52 @@ public:
   }
 };
 
-std::deque<SharedHandle<OptionHandler> > OptionParser::findAll() const
+SharedHandle<OptionHandler>
+OptionParser::findByName(const std::string& name) const
 {
-  std::deque<SharedHandle<OptionHandler> > result;
-  std::remove_copy_if(_optionHandlers.begin(), _optionHandlers.end(),
-		      std::back_inserter(result),
-		      mem_fun_sh(&OptionHandler::isHidden));
-  return result;
+  return findOptionHandler(_optionHandlers.begin(), _optionHandlers.end(),
+			   FindByName(name));
 }
 
-SharedHandle<OptionHandler>
-OptionParser::findByName(const std::string& name) const
+class FindByID:public std::unary_function<SharedHandle<OptionHandler>, bool> {
+private:
+  int _id;
+public:
+  FindByID(int id):_id(id) {}
+
+  bool operator()(const SharedHandle<OptionHandler>& optionHandler) const
+  {
+    return !optionHandler->isHidden() && optionHandler->getOptionID() == _id;
+  }
+};
+
+SharedHandle<OptionHandler> OptionParser::findByID(int id) const
 {
-  std::deque<SharedHandle<OptionHandler> >::const_iterator i =
-    std::find_if(_optionHandlers.begin(), _optionHandlers.end(),
-		 FindByName(name));
-  if(i == _optionHandlers.end()) {
-    return SharedHandle<OptionHandler>();
-  } else {
-    return *i;
+  return findOptionHandler(_optionHandlers.begin(), _optionHandlers.end(),
+			   FindByID(id));
+}
+
+class FindByShortName:
+    public std::unary_function<SharedHandle<OptionHandler>, bool> {
+private:
+  char _shortName;
+public:
+  FindByShortName(char shortName):_shortName(shortName) {}
+
+  bool operator()(const SharedHandle<OptionHandler>& optionHandler) const
+  {
+    return !optionHandler->isHidden() &&
+      optionHandler->getShortName() == _shortName;
   }
+};
+
+SharedHandle<OptionHandler> OptionParser::findByShortName(char shortName) const
+{
+  return findOptionHandler(_optionHandlers.begin(), _optionHandlers.end(),
+			   FindByShortName(shortName));
 }
 
+
 const std::deque<SharedHandle<OptionHandler> >&
 OptionParser::getOptionHandlers() const
 {

+ 19 - 3
src/OptionParser.h

@@ -36,11 +36,13 @@
 #define _D_OPTION_PARSER_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <string>
 #include <deque>
 #include <iosfwd>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 class Option;
@@ -48,16 +50,26 @@ class OptionHandler;
 
 class OptionParser {
 private:
+  int _idCounter;
+
   std::deque<SharedHandle<OptionHandler> > _optionHandlers;
 
   SharedHandle<OptionHandler>
   getOptionHandlerByName(const std::string& optName);
 public:
+  OptionParser();
+
   ~OptionParser() {}
 
-  void parse(Option* option, std::istream& ios);
+  // Parses options in argv and writes option name and value to out in
+  // NAME=VALUE format. Non-option strings are stored in nonopts.
+  // Throws FatalException when an unrecognized option is found.
+  void parseArg(std::ostream& out, std::deque<std::string>& nonopts,
+		int argc, char* const argv[]);
+
+  void parse(Option& option, std::istream& ios);
 
-  void parseDefaultValues(Option* option) const;
+  void parseDefaultValues(Option& option) const;
 
   void setOptionHandlers
   (const std::deque<SharedHandle<OptionHandler> >& optionHandlers);
@@ -75,6 +87,10 @@ public:
   SharedHandle<OptionHandler>
   findByName(const std::string& name) const;
 
+  SharedHandle<OptionHandler> findByID(int id) const;
+
+  SharedHandle<OptionHandler> findByShortName(char shortName) const;
+
   const std::deque<SharedHandle<OptionHandler> >& getOptionHandlers() const;
 };
 

+ 37 - 0
src/array_fun.h

@@ -215,6 +215,43 @@ size_t arrayLength(T (&a)[0u])
   return 0;
 }
 
+template<typename T>
+class array_ptr {
+private:
+  T* _array;
+
+  // Copies are not allowed. Let's make them private.
+  array_ptr(const array_ptr& s);
+
+  template<typename S>
+  array_ptr(const array_ptr<S>& s);
+
+  array_ptr& operator=(const array_ptr& s);
+
+  template<typename S>
+  array_ptr& operator=(const array_ptr<S>& s);
+
+public:
+  array_ptr():_array(0) {}
+
+  explicit array_ptr(T* array):_array(array) {}
+
+  ~array_ptr()
+  {
+    delete [] _array;
+  }
+
+  T& operator[](size_t index)
+  {
+    return _array[index];
+  }
+
+  const T& operator[](size_t index) const
+  {
+    return _array[index];
+  }
+};
+
 } // namespace aria2
 
 #endif // _D_ARRAY_FUN_H_

+ 27 - 26
src/main.cc

@@ -157,32 +157,34 @@ static void showFiles(const std::deque<std::string>& uris, const Option* op)
 }
 #endif // ENABLE_BITTORRENT || ENABLE_METALINK
 
-extern Option* option_processing(int argc, char* const argv[]);
+extern void option_processing(Option& option, std::deque<std::string>& uris,
+			      int argc, char* const argv[]);
 
 DownloadResult::RESULT main(int argc, char* argv[])
 {
-  Option* op = option_processing(argc, argv);
-  std::deque<std::string> args(argv+optind, argv+argc);
+  std::deque<std::string> args;
+  Option op;
+  option_processing(op, args, argc, argv);
 
   SimpleRandomizer::init();
   BitfieldManFactory::setDefaultRandomizer(SimpleRandomizer::getInstance());
-  if(op->get(PREF_LOG) == "-") {
+  if(op.get(PREF_LOG) == "-") {
     LogFactory::setLogFile(DEV_STDOUT);
-  } else if(!op->get(PREF_LOG).empty()) {
-    LogFactory::setLogFile(op->get(PREF_LOG));
+  } else if(!op.get(PREF_LOG).empty()) {
+    LogFactory::setLogFile(op.get(PREF_LOG));
   } else {
     LogFactory::setLogFile(DEV_NULL);
   }
-  LogFactory::setLogLevel(op->get(PREF_LOG_LEVEL));
-  if(op->getAsBool(PREF_QUIET)) {
+  LogFactory::setLogLevel(op.get(PREF_LOG_LEVEL));
+  if(op.getAsBool(PREF_QUIET)) {
     LogFactory::setConsoleOutput(false);
   }
 #ifdef HAVE_EPOLL
-  if(op->get(PREF_EVENT_POLL) == V_EPOLL) {
+  if(op.get(PREF_EVENT_POLL) == V_EPOLL) {
     SocketCore::useEpoll();
   } else
 #endif // HAVE_EPOLL
-    if(op->get(PREF_EVENT_POLL) == V_SELECT) {
+    if(op.get(PREF_EVENT_POLL) == V_SELECT) {
       SocketCore::useSelect();
     }
   DownloadResult::RESULT exitStatus = DownloadResult::FINISHED;
@@ -203,48 +205,47 @@ DownloadResult::RESULT main(int argc, char* argv[])
 #endif
     std::deque<SharedHandle<RequestGroup> > requestGroups;
 #ifdef ENABLE_BITTORRENT
-    if(!op->blank(PREF_TORRENT_FILE)) {
-      if(op->get(PREF_SHOW_FILES) == V_TRUE) {
-	showTorrentFile(op->get(PREF_TORRENT_FILE));
+    if(!op.blank(PREF_TORRENT_FILE)) {
+      if(op.get(PREF_SHOW_FILES) == V_TRUE) {
+	showTorrentFile(op.get(PREF_TORRENT_FILE));
 	return exitStatus;
       } else {
-	createRequestGroupForBitTorrent(requestGroups, op, args);
+	createRequestGroupForBitTorrent(requestGroups, &op, args);
       }
     }
     else
 #endif // ENABLE_BITTORRENT
 #ifdef ENABLE_METALINK
-      if(!op->blank(PREF_METALINK_FILE)) {
-	if(op->get(PREF_SHOW_FILES) == V_TRUE) {
-	  showMetalinkFile(op->get(PREF_METALINK_FILE), op);
+      if(!op.blank(PREF_METALINK_FILE)) {
+	if(op.get(PREF_SHOW_FILES) == V_TRUE) {
+	  showMetalinkFile(op.get(PREF_METALINK_FILE), &op);
 	  return exitStatus;
 	} else {
-	  createRequestGroupForMetalink(requestGroups, op);
+	  createRequestGroupForMetalink(requestGroups, &op);
 	}
       }
       else
 #endif // ENABLE_METALINK
-	if(!op->blank(PREF_INPUT_FILE)) {
-	  createRequestGroupForUriList(requestGroups, op);
+	if(!op.blank(PREF_INPUT_FILE)) {
+	  createRequestGroupForUriList(requestGroups, &op);
 #if defined ENABLE_BITTORRENT || defined ENABLE_METALINK
-	} else if(op->get(PREF_SHOW_FILES) == V_TRUE) {
-	  showFiles(args, op);
+	} else if(op.get(PREF_SHOW_FILES) == V_TRUE) {
+	  showFiles(args, &op);
 #endif // ENABLE_METALINK || ENABLE_METALINK
 	} else {
-	  createRequestGroupForUri(requestGroups, op, args);
+	  createRequestGroupForUri(requestGroups, &op, args);
 	}
 
     if(requestGroups.empty()) {
       std::cout << MSG_NO_FILES_TO_DOWNLOAD << std::endl;
     } else {
-      exitStatus = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op),
-				       getSummaryOut(op)).execute();
+      exitStatus = MultiUrlRequestInfo(requestGroups, &op, getStatCalc(&op),
+				       getSummaryOut(&op)).execute();
     }
   } catch(Exception& ex) {
     std::cerr << EX_EXCEPTION_CAUGHT << "\n" << ex.stackTrace() << std::endl;
     exitStatus = DownloadResult::UNKNOWN_ERROR;
   }
-  delete op;
   LogFactory::release();
   return exitStatus;
 }

+ 41 - 526
src/option_processing.cc

@@ -55,27 +55,12 @@
 #include "OptionHandlerException.h"
 #include "DownloadResult.h"
 
-extern char* optarg;
-extern int optind, opterr, optopt;
-#include <getopt.h>
-
 namespace aria2 {
 
 extern void showVersion();
 extern void showUsage(const std::string& keyword, const OptionParser& oparser);
 
-static std::string toBoolArg(const char* optarg)
-{
-  std::string arg;
-  if(!optarg || strlen(optarg) == 0) {
-    arg = V_TRUE;
-  } else {
-    arg = optarg;
-  }
-  return arg;
-}
-
-static void overrideWithEnv(Option* op, const OptionParser& optionParser,
+static void overrideWithEnv(Option& op, const OptionParser& optionParser,
 			    const std::string& pref,
 			    const std::string& envName)
 {
@@ -92,501 +77,33 @@ static void overrideWithEnv(Option* op, const OptionParser& optionParser,
   }
 }
 
-Option* option_processing(int argc, char* const argv[])
+void option_processing(Option& op, std::deque<std::string>& uris,
+		       int argc, char* const argv[])
 {
-  std::stringstream cmdstream;
-  int32_t c;
-  Option* op = new Option();
-
-  // following options are not parsed by OptionHandler and not stored in Option.
-  bool noConf = false;
-  std::string ucfname;
-
   OptionParser oparser;
   oparser.setOptionHandlers(OptionHandlerFactory::createOptionHandlers());
   try {
-    oparser.parseDefaultValues(op);
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace();
-    exit(DownloadResult::UNKNOWN_ERROR);
-  }
+    bool noConf = false;
+    std::string ucfname;
+    std::stringstream cmdstream;
+    oparser.parseArg(cmdstream, uris, argc, argv);
+    {
+      // first evaluate --no-conf and --conf-path options.
+      Option op;
+      oparser.parse(op, cmdstream);
+      noConf = op.getAsBool(PREF_NO_CONF);
+      ucfname = op.get(PREF_CONF_PATH);
 
-  while(1) {
-    int optIndex = 0;
-    int lopt;
-    static struct option longOpts[] = {
-#ifdef HAVE_DAEMON
-      { PREF_DAEMON.c_str(), no_argument, NULL, 'D' },
-#endif // HAVE_DAEMON
-      { PREF_DIR.c_str(), required_argument, NULL, 'd' },
-      { PREF_OUT.c_str(), required_argument, NULL, 'o' },
-      { PREF_LOG.c_str(), required_argument, NULL, 'l' },
-      { PREF_SPLIT.c_str(), required_argument, NULL, 's' },
-      { PREF_TIMEOUT.c_str(), required_argument, NULL, 't' },
-      { PREF_MAX_TRIES.c_str(), required_argument, NULL, 'm' },
-      { PREF_HTTP_PROXY.c_str(), required_argument, &lopt, 1 },
-      { PREF_HTTP_USER.c_str(), required_argument, &lopt, 2 },
-      { PREF_HTTP_PASSWD.c_str(), required_argument, &lopt, 3 },
-      { "http-proxy-user", required_argument, &lopt, 4 },
-      { "http-proxy-passwd", required_argument, &lopt, 5 },
-      { PREF_HTTP_AUTH_SCHEME.c_str(), required_argument, &lopt, 6 },
-      { PREF_REFERER.c_str(), required_argument, &lopt, 7 },
-      { PREF_RETRY_WAIT.c_str(), required_argument, &lopt, 8 },
-      { PREF_FTP_USER.c_str(), required_argument, &lopt, 9 },
-      { PREF_FTP_PASSWD.c_str(), required_argument, &lopt, 10 },
-      { PREF_FTP_TYPE.c_str(), required_argument, &lopt, 11 },
-      { PREF_FTP_PASV.c_str(), optional_argument, 0, 'p' },
-      { "ftp-via-http-proxy", required_argument, &lopt, 12 },
-      { "http-proxy-method", required_argument, &lopt, 14 },
-      { PREF_LOWEST_SPEED_LIMIT.c_str(), required_argument, &lopt, 200 },
-      { PREF_MAX_DOWNLOAD_LIMIT.c_str(), required_argument, &lopt, 201 },
-      { PREF_FILE_ALLOCATION.c_str(), required_argument, 0, 'a' },
-      { PREF_ALLOW_OVERWRITE.c_str(), required_argument, &lopt, 202 },
-#ifdef ENABLE_MESSAGE_DIGEST
-      { PREF_CHECK_INTEGRITY.c_str(), optional_argument, 0, 'V' },
-      { PREF_REALTIME_CHUNK_CHECKSUM.c_str(), required_argument, &lopt, 204 },
-#endif // ENABLE_MESSAGE_DIGEST
-      { PREF_CONTINUE.c_str(), no_argument, 0, 'c' },
-      { PREF_USER_AGENT.c_str(), required_argument, 0, 'U' },
-      { PREF_NO_NETRC.c_str(), no_argument, 0, 'n' },
-      { PREF_INPUT_FILE.c_str(), required_argument, 0, 'i' },
-      { PREF_MAX_CONCURRENT_DOWNLOADS.c_str(), required_argument, 0, 'j' },
-      { PREF_LOAD_COOKIES.c_str(), required_argument, &lopt, 205 },
-      { PREF_FORCE_SEQUENTIAL.c_str(), optional_argument, 0, 'Z' },
-      { PREF_AUTO_FILE_RENAMING.c_str(), optional_argument, &lopt, 206 },
-      { PREF_PARAMETERIZED_URI.c_str(), optional_argument, 0, 'P' },
-      { PREF_ENABLE_HTTP_KEEP_ALIVE.c_str(), optional_argument, &lopt, 207 },
-      { PREF_ENABLE_HTTP_PIPELINING.c_str(), optional_argument, &lopt, 208 },
-      { PREF_NO_FILE_ALLOCATION_LIMIT.c_str(), required_argument, &lopt, 209 },
-#ifdef ENABLE_DIRECT_IO
-      { PREF_ENABLE_DIRECT_IO.c_str(), optional_argument, &lopt, 210 },
-#endif // ENABLE_DIRECT_IO
-      { PREF_ALLOW_PIECE_LENGTH_CHANGE.c_str(), required_argument, &lopt, 211 },
-      { PREF_NO_CONF.c_str(), no_argument, &lopt, 212 },
-      { PREF_CONF_PATH.c_str(), required_argument, &lopt, 213 },
-      { PREF_STOP.c_str(), required_argument, &lopt, 214 },
-      { PREF_HEADER.c_str(), required_argument, &lopt, 215 },
-      { PREF_QUIET.c_str(), optional_argument, 0, 'q' },
-#ifdef ENABLE_ASYNC_DNS
-      { PREF_ASYNC_DNS.c_str(), optional_argument, &lopt, 216 },
-#endif // ENABLE_ASYNC_DNS
-      { PREF_FTP_REUSE_CONNECTION.c_str(), optional_argument, &lopt, 217 },
-      { PREF_SUMMARY_INTERVAL.c_str(), required_argument, &lopt, 218 },
-      { PREF_LOG_LEVEL.c_str(), required_argument, &lopt, 219 },
-      { PREF_URI_SELECTOR.c_str(), required_argument, &lopt, 220 },
-      { PREF_SERVER_STAT_IF.c_str(), required_argument, &lopt, 221 },
-      { PREF_SERVER_STAT_OF.c_str(), required_argument, &lopt, 222 },
-      { PREF_SERVER_STAT_TIMEOUT.c_str(), required_argument, &lopt, 223 },
-      { PREF_REMOTE_TIME.c_str(), optional_argument, 0, 'R' },
-      { PREF_CONNECT_TIMEOUT.c_str(), required_argument, &lopt, 224 },
-      { PREF_MAX_FILE_NOT_FOUND.c_str(), required_argument, &lopt, 225 },
-      { PREF_AUTO_SAVE_INTERVAL.c_str(), required_argument, &lopt, 226 },
-      { PREF_HTTPS_PROXY.c_str(), required_argument, &lopt, 227 },
-      { PREF_FTP_PROXY.c_str(), required_argument, &lopt, 228 },
-      { PREF_ALL_PROXY.c_str(), required_argument, &lopt, 229 },
-      { PREF_PROXY_METHOD.c_str(), required_argument, &lopt, 230 },
-      { PREF_CERTIFICATE.c_str(), required_argument, &lopt, 231 },
-      { PREF_PRIVATE_KEY.c_str(), required_argument, &lopt, 232 },
-      { PREF_CA_CERTIFICATE.c_str(), optional_argument, &lopt, 233 },
-      { PREF_CHECK_CERTIFICATE.c_str(), optional_argument, &lopt, 234 },
-      { PREF_NO_PROXY.c_str(), required_argument, &lopt, 235 },
-      { PREF_USE_HEAD.c_str(), optional_argument, &lopt, 236 },
-      { PREF_EVENT_POLL.c_str(), required_argument, &lopt, 237 },
-      { PREF_HTTP_SERVER_LISTEN_PORT.c_str(), required_argument, &lopt, 238 },
-      { PREF_ENABLE_HTTP_SERVER.c_str(), optional_argument, &lopt, 239 },
-#if defined ENABLE_BITTORRENT || defined ENABLE_METALINK
-      { PREF_SHOW_FILES.c_str(), no_argument, NULL, 'S' },
-      { PREF_SELECT_FILE.c_str(), required_argument, &lopt, 21 },
-#endif // ENABLE_BITTORRENT || ENABLE_METALINK
-#ifdef ENABLE_BITTORRENT
-      { PREF_TORRENT_FILE.c_str(), required_argument, NULL, 'T' },
-      { PREF_LISTEN_PORT.c_str(), required_argument, &lopt, 15 },
-      { PREF_FOLLOW_TORRENT.c_str(), required_argument, &lopt, 16 },
-      { PREF_DIRECT_FILE_MAPPING.c_str(), required_argument, &lopt, 19 },
-      // TODO remove upload-limit.
-      //{ "upload-limit".c_str(), required_argument, &lopt, 20 },
-      { PREF_SEED_TIME.c_str(), required_argument, &lopt, 22 },
-      { PREF_SEED_RATIO.c_str(), required_argument, &lopt, 23 },
-      { PREF_MAX_UPLOAD_LIMIT.c_str(), required_argument, 0, 'u' },
-      { PREF_PEER_ID_PREFIX.c_str(), required_argument, &lopt, 25 },
-      { PREF_ENABLE_PEER_EXCHANGE.c_str(), optional_argument, &lopt, 26 },
-      { PREF_ENABLE_DHT.c_str(), optional_argument, &lopt, 27 },
-      { PREF_DHT_LISTEN_PORT.c_str(), required_argument, &lopt, 28 },
-      { PREF_DHT_ENTRY_POINT.c_str(), required_argument, &lopt, 29 },
-      { PREF_BT_MIN_CRYPTO_LEVEL.c_str(), required_argument, &lopt, 30 },
-      { PREF_BT_REQUIRE_CRYPTO.c_str(), required_argument, &lopt, 31 },
-      { PREF_BT_REQUEST_PEER_SPEED_LIMIT.c_str(), required_argument, &lopt, 32 },
-      { PREF_BT_MAX_OPEN_FILES.c_str(), required_argument, &lopt, 33 },
-      { PREF_BT_SEED_UNVERIFIED.c_str(), optional_argument, &lopt, 34 },
-      { PREF_DHT_FILE_PATH.c_str(), required_argument, &lopt, 35 },
-      { PREF_MAX_OVERALL_UPLOAD_LIMIT.c_str(), required_argument, &lopt, 36 },
-      { PREF_BT_HASH_CHECK_SEED.c_str(), optional_argument, &lopt, 37 },
-      { PREF_BT_MAX_PEERS.c_str(), required_argument, &lopt, 38 },
-      { PREF_BT_EXTERNAL_IP.c_str(), required_argument, &lopt, 39 },
-#endif // ENABLE_BITTORRENT
-#ifdef ENABLE_METALINK
-      { PREF_METALINK_FILE.c_str(), required_argument, NULL, 'M' },
-      { PREF_METALINK_SERVERS.c_str(), required_argument, NULL, 'C' },
-      { PREF_METALINK_VERSION.c_str(), required_argument, &lopt, 100 },
-      { PREF_METALINK_LANGUAGE.c_str(), required_argument, &lopt, 101 },
-      { PREF_METALINK_OS.c_str(), required_argument, &lopt, 102 },
-      { PREF_FOLLOW_METALINK.c_str(), required_argument, &lopt, 103 },
-      { PREF_METALINK_LOCATION.c_str(), required_argument, &lopt, 104 },
-      { PREF_METALINK_PREFERRED_PROTOCOL.c_str(), required_argument, &lopt, 105 },
-      { PREF_METALINK_ENABLE_UNIQUE_PROTOCOL.c_str(), optional_argument, &lopt, 106 },
-#endif // ENABLE_METALINK
-      { "version", no_argument, NULL, 'v' },
-      { "help", optional_argument, NULL, 'h' },
-      { 0, 0, 0, 0 }
-    };
-    c = getopt_long(argc, argv, 
-		    "Dd:o:l:s:p::t:m:vh::ST:M:C:a:cU:ni:j:Z::P::q::R::V::u:",
-		    longOpts, &optIndex);
-    if(c == -1) {
-      break;
-    }
-    switch(c) {
-    case 0:{
-      switch(lopt) {
-      case 1:
-	cmdstream << PREF_HTTP_PROXY << "=" << optarg << "\n";
-	break;
-      case 2:
-	cmdstream << PREF_HTTP_USER << "=" << optarg << "\n";
-	break;
-      case 3:
-	cmdstream << PREF_HTTP_PASSWD << "=" << optarg << "\n";
-	break;
-      case 4:
-	std::cout << "--http-proxy-user was deprecated. See --http-proxy,"
-		  << " --https-proxy, --ftp-proxy, --all-proxy options."
-		  << std::endl;
-	exit(DownloadResult::UNKNOWN_ERROR);
-      case 5: 
-	std::cout << "--http-proxy-passwd was deprecated. See --http-proxy,"
-		  << " --https-proxy, --ftp-proxy, --all-proxy options."
-		  << std::endl;
-	exit(DownloadResult::UNKNOWN_ERROR);
-      case 6:
-	cmdstream << PREF_HTTP_AUTH_SCHEME << "=" << optarg << "\n";
-	break;
-      case 7:
-	cmdstream << PREF_REFERER << "=" << optarg << "\n";
-	break;
-      case 8:
-	cmdstream << PREF_RETRY_WAIT << "=" << optarg << "\n";
-	break;
-      case 9:
-	cmdstream << PREF_FTP_USER << "=" << optarg << "\n";
-	break;
-      case 10:
-	cmdstream << PREF_FTP_PASSWD << "=" << optarg << "\n";
-	break;
-      case 11:
-	cmdstream << PREF_FTP_TYPE << "=" << optarg << "\n";
-	break;
-      case 12:
-	std::cout << "--ftp-via-http-proxy was deprecated."
-		  << " Use --http-proxy-method option instead."
-		  << std::endl;
-	exit(DownloadResult::UNKNOWN_ERROR);
-      case 14:
-	std::cout << "--http-proxy-method was deprecated."
-		  << " Use --proxy-method option instead."
-		  << std::endl;
-	exit(DownloadResult::UNKNOWN_ERROR);
-      case 15:
-	cmdstream << PREF_LISTEN_PORT << "=" << optarg << "\n";
-	break;
-      case 16:
-	cmdstream << PREF_FOLLOW_TORRENT << "=" << optarg << "\n";
-	break;
-      case 19:
-	cmdstream << PREF_DIRECT_FILE_MAPPING << "=" << optarg << "\n";
-	break;
-      case 21:
-	cmdstream << PREF_SELECT_FILE << "=" << optarg << "\n";
-	break;
-      case 22:
-	cmdstream << PREF_SEED_TIME << "=" << optarg << "\n";
-	break;
-      case 23:
-	cmdstream << PREF_SEED_RATIO << "=" << optarg << "\n";
-	break;
-      case 25:
-	cmdstream << PREF_PEER_ID_PREFIX << "=" << optarg << "\n";
-	break;
-      case 26:
-	cmdstream << PREF_ENABLE_PEER_EXCHANGE << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 27:
-	cmdstream << PREF_ENABLE_DHT << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 28:
-	cmdstream << PREF_DHT_LISTEN_PORT << "=" << optarg << "\n";
-	break;
-      case 29:
-	cmdstream << PREF_DHT_ENTRY_POINT << "=" << optarg << "\n";
-	break;
-      case 30:
-	cmdstream << PREF_BT_MIN_CRYPTO_LEVEL << "=" << optarg << "\n";
-	break;
-      case 31:
-	cmdstream << PREF_BT_REQUIRE_CRYPTO << "=" << optarg << "\n";
-	break;
-      case 32:
-	cmdstream << PREF_BT_REQUEST_PEER_SPEED_LIMIT << "=" << optarg << "\n";
-	break;
-      case 33:
-	cmdstream << PREF_BT_MAX_OPEN_FILES << "=" << optarg << "\n";
-	break;
-      case 34:
-	cmdstream << PREF_BT_SEED_UNVERIFIED << "=" << toBoolArg(optarg)
-		  << "\n";
-	break;
-      case 35:
-	cmdstream << PREF_DHT_FILE_PATH << "=" << optarg << "\n";
-	break;
-      case 36:
-	cmdstream << PREF_MAX_OVERALL_UPLOAD_LIMIT << "=" << optarg << "\n";
-	break;
-      case 37:
-	cmdstream << PREF_BT_HASH_CHECK_SEED << "=" << optarg << "\n";
-	break;
-      case 38:
-	cmdstream << PREF_BT_MAX_PEERS << "=" << optarg << "\n";
-	break;
-      case 39:
-	cmdstream << PREF_BT_EXTERNAL_IP << "=" << optarg << "\n";
-	break;
-      case 100:
-	cmdstream << PREF_METALINK_VERSION << "=" << optarg << "\n";
-	break;
-      case 101:
-	cmdstream << PREF_METALINK_LANGUAGE << "=" << optarg << "\n";
-	break;
-      case 102:
-	cmdstream << PREF_METALINK_OS << "=" << optarg << "\n";
-	break;
-      case 103:
-	cmdstream << PREF_FOLLOW_METALINK << "=" << optarg << "\n";
-	break;
-      case 104:
-	cmdstream << PREF_METALINK_LOCATION << "=" << optarg << "\n";
-	break;
-      case 105:
-	cmdstream << PREF_METALINK_PREFERRED_PROTOCOL << "=" << optarg << "\n";
-	break;
-      case 106:
-	cmdstream << PREF_METALINK_ENABLE_UNIQUE_PROTOCOL << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 200:
-	cmdstream << PREF_LOWEST_SPEED_LIMIT << "=" << optarg << "\n";
-	break;
-      case 201:
-	cmdstream << PREF_MAX_DOWNLOAD_LIMIT << "=" << optarg << "\n";
-	break;
-      case 202:
-	cmdstream << PREF_ALLOW_OVERWRITE << "=" << optarg << "\n";
-	break;
-      case 204:
-	cmdstream << PREF_REALTIME_CHUNK_CHECKSUM << "=" << optarg << "\n";
-	break;
-      case 205:
-	cmdstream << PREF_LOAD_COOKIES << "=" << optarg << "\n";
-	break;
-      case 206:
-	cmdstream << PREF_AUTO_FILE_RENAMING << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 207:
-	cmdstream << PREF_ENABLE_HTTP_KEEP_ALIVE << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 208:
-	cmdstream << PREF_ENABLE_HTTP_PIPELINING << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 209:
-	cmdstream << PREF_NO_FILE_ALLOCATION_LIMIT << "=" << optarg << "\n";
-	break;
-      case 210:
-	cmdstream << PREF_ENABLE_DIRECT_IO << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 211:
-	cmdstream << PREF_ALLOW_PIECE_LENGTH_CHANGE << "=" << optarg << "\n";
-	break;
-      case 212:
-	noConf = true;
-	break;
-      case 213:
-	ucfname = optarg;
-	break;
-      case 214:
-	cmdstream << PREF_STOP << "=" << optarg << "\n";
-	break;
-      case 215:
-	cmdstream << PREF_HEADER << "=" << optarg << "\n";
-	break;
-#ifdef ENABLE_ASYNC_DNS
-      case 216:
-	cmdstream << PREF_ASYNC_DNS << "=" << toBoolArg(optarg) << "\n";
-	break;
-#endif // ENABLE_ASYNC_DNS
-      case 217:
-	cmdstream << PREF_FTP_REUSE_CONNECTION << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 218:
-	cmdstream << PREF_SUMMARY_INTERVAL << "=" << optarg << "\n";
-	break;
-      case 219:
-	cmdstream << PREF_LOG_LEVEL << "=" << optarg << "\n";
-	break;
-      case 220:
-	cmdstream << PREF_URI_SELECTOR << "=" << optarg << "\n";
-	break;
-      case 221:
-	cmdstream << PREF_SERVER_STAT_IF << "=" << optarg << "\n";
-	break;
-      case 222:
-	cmdstream << PREF_SERVER_STAT_OF << "=" << optarg << "\n";
-	break;
-      case 223:
-	cmdstream << PREF_SERVER_STAT_TIMEOUT << "=" << optarg << "\n";
-	break;
-      case 224:
-	cmdstream << PREF_CONNECT_TIMEOUT << "=" << optarg << "\n";
-	break;
-      case 225:
-	cmdstream << PREF_MAX_FILE_NOT_FOUND << "=" << optarg << "\n";
-	break;
-      case 226:
-	cmdstream << PREF_AUTO_SAVE_INTERVAL << "=" << optarg << "\n";
-	break;
-      case 227:
-	cmdstream << PREF_HTTPS_PROXY << "=" << optarg << "\n";
-	break;
-      case 228:
-	cmdstream << PREF_FTP_PROXY << "=" << optarg << "\n";
-	break;
-      case 229:
-	cmdstream << PREF_ALL_PROXY << "=" << optarg << "\n";
-	break;
-      case 230:
-	cmdstream << PREF_PROXY_METHOD << "=" << optarg << "\n";
-	break;
-      case 231:
-	cmdstream << PREF_CERTIFICATE << "=" << optarg << "\n";
-	break;
-      case 232:
-	cmdstream << PREF_PRIVATE_KEY << "=" << optarg << "\n";
-	break;
-      case 233:
-	cmdstream << PREF_CA_CERTIFICATE << "=" << optarg << "\n";
-	break;
-      case 234:
-	cmdstream << PREF_CHECK_CERTIFICATE << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 235:
-	cmdstream << PREF_NO_PROXY << "=" << optarg << "\n";
-	break;
-      case 236:
-	cmdstream << PREF_USE_HEAD << "=" << toBoolArg(optarg) << "\n";
-	break;
-      case 237:
-	cmdstream << PREF_EVENT_POLL << "=" << optarg << "\n";
-	break;
-      case 238:
-	cmdstream << PREF_HTTP_SERVER_LISTEN_PORT << "=" << optarg << "\n";
-	break;
-      case 239:
-	cmdstream << PREF_ENABLE_HTTP_SERVER << "=" << toBoolArg(optarg)
-		  << "\n";
-	break;
+      if(op.defined("version")) {
+	showVersion();
+	exit(DownloadResult::FINISHED);
       }
-      break;
-    }
-#ifdef HAVE_DAEMON
-    case 'D':
-      cmdstream << PREF_DAEMON << "=" << V_TRUE << "\n";
-      break;
-#endif // HAVE_DAEMON
-    case 'd':
-      cmdstream << PREF_DIR << "=" << optarg << "\n";
-      break;
-    case 'o':
-      cmdstream << PREF_OUT << "=" << optarg << "\n";
-      break;
-    case 'l':
-      cmdstream << PREF_LOG << "=" << optarg << "\n";
-      break;
-    case 's':
-      cmdstream << PREF_SPLIT << "=" << optarg << "\n";
-      break;
-    case 't':
-      cmdstream << PREF_TIMEOUT << "=" << optarg << "\n";
-      break;
-    case 'm':
-      cmdstream << PREF_MAX_TRIES << "=" << optarg << "\n";
-      break;
-    case 'p':
-      cmdstream << PREF_FTP_PASV << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'S':
-      cmdstream << PREF_SHOW_FILES << "=" << V_TRUE << "\n";
-      break;
-    case 'T':
-      cmdstream << PREF_TORRENT_FILE << "=" << optarg << "\n";
-      break;
-    case 'M':
-      cmdstream << PREF_METALINK_FILE << "=" << optarg << "\n";
-      break;
-    case 'C':
-      cmdstream << PREF_METALINK_SERVERS << "=" << optarg << "\n";
-      break;
-    case 'a':
-      cmdstream << PREF_FILE_ALLOCATION << "=" << optarg << "\n";
-      break;
-    case 'c':
-      cmdstream << PREF_CONTINUE << "=" << V_TRUE << "\n";
-      break;
-    case 'U':
-      cmdstream << PREF_USER_AGENT << "=" << optarg << "\n";
-      break;
-    case 'n':
-      cmdstream << PREF_NO_NETRC << "=" << V_TRUE << "\n";
-      break;
-    case 'i':
-      cmdstream << PREF_INPUT_FILE << "=" << optarg << "\n";
-      break;
-    case 'j':
-      cmdstream << PREF_MAX_CONCURRENT_DOWNLOADS << "=" << optarg << "\n";
-      break;
-    case 'Z':
-      cmdstream << PREF_FORCE_SEQUENTIAL << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'P':
-      cmdstream << PREF_PARAMETERIZED_URI << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'q':
-      cmdstream << PREF_QUIET << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'R':
-      cmdstream << PREF_REMOTE_TIME << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'V':
-      cmdstream << PREF_CHECK_INTEGRITY << "=" << toBoolArg(optarg) << "\n";
-      break;
-    case 'u':
-      cmdstream << PREF_MAX_UPLOAD_LIMIT << "=" << optarg << "\n";
-      break;
-    case 'v':
-      showVersion();
-      exit(DownloadResult::FINISHED);
-    case 'h':
-      {
+      if(op.defined("help")) {
 	std::string keyword;
-	if(optarg == 0 || strlen(optarg) == 0) {
+	if(op.get("help").empty()) {
 	  keyword = TAG_BASIC;
 	} else {
-	  keyword = optarg;
+	  keyword = op.get("help");
 	  if(Util::startsWith(keyword, "--")) {
 	    keyword = keyword.substr(2);
 	  }
@@ -598,13 +115,10 @@ Option* option_processing(int argc, char* const argv[])
 	showUsage(keyword, oparser);
 	exit(DownloadResult::FINISHED);
       }
-    default:
-      showUsage(TAG_HELP, oparser);
-      exit(DownloadResult::UNKNOWN_ERROR);
     }
-  }
 
-  {
+    oparser.parseDefaultValues(op);
+
     if(!noConf) {
       std::string cfname = 
 	ucfname.empty() ?
@@ -642,43 +156,44 @@ Option* option_processing(int argc, char* const argv[])
     overrideWithEnv(op, oparser, PREF_ALL_PROXY, "all_proxy");
     overrideWithEnv(op, oparser, PREF_NO_PROXY, "no_proxy");
 
-    try {
-      oparser.parse(op, cmdstream);
-    } catch(OptionHandlerException& e) {
-      std::cerr << e.stackTrace() << "\n"
-		<< "Usage:" << "\n"
-		<< oparser.findByName(e.getOptionName())->getDescription()
-		<< std::endl;
-      exit(DownloadResult::UNKNOWN_ERROR);
-    } catch(Exception& e) {
-      std::cerr << e.stackTrace() << std::endl;
-      showUsage(TAG_HELP, oparser);
-      exit(DownloadResult::UNKNOWN_ERROR);
-    }
+    // we must clear eof bit and seek to the beginning of the buffer.
+    cmdstream.clear();
+    cmdstream.seekg(0, std::ios::beg);
+    // finaly let's parse and store command-iine options.
+    oparser.parse(op, cmdstream);
+  } catch(OptionHandlerException& e) {
+    std::cerr << e.stackTrace() << "\n"
+	      << "Usage:" << "\n"
+	      << oparser.findByName(e.getOptionName())->getDescription()
+	      << std::endl;
+    exit(DownloadResult::UNKNOWN_ERROR);
+  } catch(Exception& e) {
+    std::cerr << e.stackTrace() << std::endl;
+    showUsage(TAG_HELP, oparser);
+    exit(DownloadResult::UNKNOWN_ERROR);
   }
   if(
 #ifdef ENABLE_BITTORRENT
-     op->blank(PREF_TORRENT_FILE) &&
+     op.blank(PREF_TORRENT_FILE) &&
 #endif // ENABLE_BITTORRENT
 #ifdef ENABLE_METALINK
-     op->blank(PREF_METALINK_FILE) &&
+     op.blank(PREF_METALINK_FILE) &&
 #endif // ENABLE_METALINK
-     op->blank(PREF_INPUT_FILE)) {
-    if(optind == argc) {
+     op.blank(PREF_INPUT_FILE)) {
+    if(uris.empty()) {
       std::cerr << MSG_URI_REQUIRED << std::endl;
       showUsage(TAG_HELP, oparser);
       exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
 #ifdef HAVE_DAEMON
-  if(op->getAsBool(PREF_DAEMON)) {
+  if(op.getAsBool(PREF_DAEMON)) {
     if(daemon(1, 1) < 0) {
       perror(MSG_DAEMON_FAILED);
       exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
 #endif // HAVE_DAEMON
-  return op;
 }
 
 } // namespace aria2

+ 63 - 92
test/OptionHandlerTest.cc

@@ -1,8 +1,9 @@
 #include "OptionHandlerImpl.h"
+
+#include <cppunit/extensions/HelperMacros.h>
+
 #include "prefs.h"
 #include "Exception.h"
-#include <iostream>
-#include <cppunit/extensions/HelperMacros.h>
 
 namespace aria2 {
 
@@ -53,7 +54,9 @@ void OptionHandlerTest::testNullOptionHandler()
 {
   NullOptionHandler handler;
   CPPUNIT_ASSERT(handler.canHandle("foo"));
-  handler.parse(0, "bar");
+  Option option;
+  handler.parse(option, "bar");
+  CPPUNIT_ASSERT(!option.defined("bar"));
 }
 
 void OptionHandlerTest::testBooleanOptionHandler()
@@ -62,16 +65,14 @@ void OptionHandlerTest::testBooleanOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, V_TRUE);
+  handler.parse(option, V_TRUE);
   CPPUNIT_ASSERT_EQUAL(std::string(V_TRUE), option.get("foo"));
-  handler.parse(&option, V_FALSE);
+  handler.parse(option, V_FALSE);
   CPPUNIT_ASSERT_EQUAL(std::string(V_FALSE), option.get("foo"));
   try {
-    handler.parse(&option, "hello");
+    handler.parse(option, "hello");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("true,false"),
 		       handler.createPossibleValuesString());
 }
@@ -82,7 +83,7 @@ void OptionHandlerTest::testNumberOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "0");
+  handler.parse(option, "0");
   CPPUNIT_ASSERT_EQUAL(std::string("0"), option.get("foo"));
   CPPUNIT_ASSERT_EQUAL(std::string("*-*"),
 		       handler.createPossibleValuesString());
@@ -92,14 +93,12 @@ void OptionHandlerTest::testNumberOptionHandler_min()
 {
   NumberOptionHandler handler("foo", "", "", 1);
   Option option;
-  handler.parse(&option, "1");
+  handler.parse(option, "1");
   CPPUNIT_ASSERT_EQUAL(std::string("1"), option.get("foo"));
   try {
-    handler.parse(&option, "0");
+    handler.parse(option, "0");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("1-*"),
 		       handler.createPossibleValuesString());
 }
@@ -108,14 +107,12 @@ void OptionHandlerTest::testNumberOptionHandler_max()
 {
   NumberOptionHandler handler("foo", "", "", -1, 100);
   Option option;
-  handler.parse(&option, "100");
+  handler.parse(option, "100");
   CPPUNIT_ASSERT_EQUAL(std::string("100"), option.get("foo"));
   try {
-    handler.parse(&option, "101");
+    handler.parse(option, "101");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("*-100"),
 		       handler.createPossibleValuesString());
 }
@@ -124,22 +121,18 @@ void OptionHandlerTest::testNumberOptionHandler_min_max()
 {
   NumberOptionHandler handler("foo", "", "", 1, 100);
   Option option;
-  handler.parse(&option, "1");
+  handler.parse(option, "1");
   CPPUNIT_ASSERT_EQUAL(std::string("1"), option.get("foo"));
-  handler.parse(&option, "100");
+  handler.parse(option, "100");
   CPPUNIT_ASSERT_EQUAL(std::string("100"), option.get("foo"));
   try {
-    handler.parse(&option, "0");
+    handler.parse(option, "0");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   try {
-    handler.parse(&option, "101");
+    handler.parse(option, "101");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("1-100"),
 		       handler.createPossibleValuesString());
 }
@@ -150,29 +143,23 @@ void OptionHandlerTest::testUnitNumberOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "4294967296");
+  handler.parse(option, "4294967296");
   CPPUNIT_ASSERT_EQUAL(std::string("4294967296"), option.get("foo"));
-  handler.parse(&option, "4096M");
+  handler.parse(option, "4096M");
   CPPUNIT_ASSERT_EQUAL(std::string("4294967296"), option.get("foo"));
-  handler.parse(&option, "4096K");
+  handler.parse(option, "4096K");
   CPPUNIT_ASSERT_EQUAL(std::string("4194304"), option.get("foo"));
   try {
-    handler.parse(&option, "K");
+    handler.parse(option, "K");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace();
-  }
+  } catch(Exception& e) {}
   try {
-    handler.parse(&option, "M");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace();
-  }
+    handler.parse(option, "M");
+  } catch(Exception& e) {}
   try {
-    handler.parse(&option, "");
+    handler.parse(option, "");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace();
-  }
+  } catch(Exception& e) {}
 }
 
 void OptionHandlerTest::testParameterOptionHandler_1argInit()
@@ -181,14 +168,12 @@ void OptionHandlerTest::testParameterOptionHandler_1argInit()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "value1");
+  handler.parse(option, "value1");
   CPPUNIT_ASSERT_EQUAL(std::string("value1"), option.get("foo"));
   try {
-    handler.parse(&option, "value3");
+    handler.parse(option, "value3");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("value1"),
 		       handler.createPossibleValuesString());
 }
@@ -199,16 +184,14 @@ void OptionHandlerTest::testParameterOptionHandler_2argsInit()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "value1");
+  handler.parse(option, "value1");
   CPPUNIT_ASSERT_EQUAL(std::string("value1"), option.get("foo"));
-  handler.parse(&option, "value2");
+  handler.parse(option, "value2");
   CPPUNIT_ASSERT_EQUAL(std::string("value2"), option.get("foo"));
   try {
-    handler.parse(&option, "value3");
+    handler.parse(option, "value3");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("value1,value2"),
 		       handler.createPossibleValuesString());
 }
@@ -223,16 +206,14 @@ void OptionHandlerTest::testParameterOptionHandler_listInit()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "value1");
+  handler.parse(option, "value1");
   CPPUNIT_ASSERT_EQUAL(std::string("value1"), option.get("foo"));
-  handler.parse(&option, "value2");
+  handler.parse(option, "value2");
   CPPUNIT_ASSERT_EQUAL(std::string("value2"), option.get("foo"));
   try {
-    handler.parse(&option, "value3");
+    handler.parse(option, "value3");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("value1,value2"),
 		       handler.createPossibleValuesString());
 }
@@ -243,9 +224,9 @@ void OptionHandlerTest::testDefaultOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "bar");
+  handler.parse(option, "bar");
   CPPUNIT_ASSERT_EQUAL(std::string("bar"), option.get("foo"));
-  handler.parse(&option, "");
+  handler.parse(option, "");
   CPPUNIT_ASSERT_EQUAL(std::string(""), option.get("foo"));
   CPPUNIT_ASSERT_EQUAL(std::string(""), handler.createPossibleValuesString());
 
@@ -264,7 +245,7 @@ void OptionHandlerTest::testFloatNumberOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle("foo"));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "1.0");
+  handler.parse(option, "1.0");
   CPPUNIT_ASSERT_EQUAL(std::string("1.0"), option.get("foo"));
   CPPUNIT_ASSERT_EQUAL(std::string("*-*"),
 		       handler.createPossibleValuesString());
@@ -274,14 +255,12 @@ void OptionHandlerTest::testFloatNumberOptionHandler_min()
 {
   FloatNumberOptionHandler handler("foo", "", "", 0.0);
   Option option;
-  handler.parse(&option, "0.0");
+  handler.parse(option, "0.0");
   CPPUNIT_ASSERT_EQUAL(std::string("0.0"), option.get("foo"));
   try {
-    handler.parse(&option, "-0.1");
+    handler.parse(option, "-0.1");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("0.0-*"),
 		       handler.createPossibleValuesString());
 }
@@ -290,14 +269,12 @@ void OptionHandlerTest::testFloatNumberOptionHandler_max()
 {
   FloatNumberOptionHandler handler("foo", "", "", -1, 10.0);
   Option option;
-  handler.parse(&option, "10.0");
+  handler.parse(option, "10.0");
   CPPUNIT_ASSERT_EQUAL(std::string("10.0"), option.get("foo"));
   try {
-    handler.parse(&option, "10.1");
+    handler.parse(option, "10.1");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("*-10.0"),
 		       handler.createPossibleValuesString());
 }
@@ -306,22 +283,18 @@ void OptionHandlerTest::testFloatNumberOptionHandler_min_max()
 {
   FloatNumberOptionHandler handler("foo", "", "", 0.0, 10.0);
   Option option;
-  handler.parse(&option, "0.0");
+  handler.parse(option, "0.0");
   CPPUNIT_ASSERT_EQUAL(std::string("0.0"), option.get("foo"));
-  handler.parse(&option, "10.0");
+  handler.parse(option, "10.0");
   CPPUNIT_ASSERT_EQUAL(std::string("10.0"), option.get("foo"));
   try {
-    handler.parse(&option, "-0.1");
+    handler.parse(option, "-0.1");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   try {
-    handler.parse(&option, "10.1");
+    handler.parse(option, "10.1");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("0.0-10.0"),
 		       handler.createPossibleValuesString());
 }
@@ -332,24 +305,22 @@ void OptionHandlerTest::testHttpProxyOptionHandler()
   CPPUNIT_ASSERT(handler.canHandle(PREF_HTTP_PROXY));
   CPPUNIT_ASSERT(!handler.canHandle("foobar"));
   Option option;
-  handler.parse(&option, "proxy:65535");
+  handler.parse(option, "proxy:65535");
   CPPUNIT_ASSERT_EQUAL(std::string("http://proxy:65535"),
 		       option.get(PREF_HTTP_PROXY));
 
-  handler.parse(&option, "http://proxy:8080");
+  handler.parse(option, "http://proxy:8080");
   CPPUNIT_ASSERT_EQUAL(std::string("http://proxy:8080"),
 		       option.get(PREF_HTTP_PROXY));
 
-  handler.parse(&option, "ftp://proxy:8080");
+  handler.parse(option, "ftp://proxy:8080");
   CPPUNIT_ASSERT_EQUAL(std::string("http://ftp://proxy:8080"),
 		       option.get(PREF_HTTP_PROXY));
 
   try {
-    handler.parse(&option, "http://bar:65536");
+    handler.parse(option, "http://bar:65536");
     CPPUNIT_FAIL("exception must be thrown.");
-  } catch(Exception& e) {
-    std::cerr << e.stackTrace() << std::endl;
-  }
+  } catch(Exception& e) {}
   CPPUNIT_ASSERT_EQUAL(std::string("[http://][USER:PASSWORD@]HOST[:PORT]"),
 		       handler.createPossibleValuesString());
 }

+ 82 - 14
test/OptionParserTest.cc

@@ -1,10 +1,16 @@
 #include "OptionParser.h"
+
+#include <cstring>
+#include <sstream>
+#include <deque>
+
+#include <cppunit/extensions/HelperMacros.h>
+
 #include "OptionHandlerImpl.h"
 #include "Exception.h"
 #include "Util.h"
 #include "Option.h"
-#include <iostream>
-#include <cppunit/extensions/HelperMacros.h>
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -15,7 +21,10 @@ class OptionParserTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testFindByNameSubstring);
   CPPUNIT_TEST(testFindByTag);
   CPPUNIT_TEST(testFindByName);
+  CPPUNIT_TEST(testFindByShortName);
+  CPPUNIT_TEST(testFindByID);
   CPPUNIT_TEST(testParseDefaultValues);
+  CPPUNIT_TEST(testParseArg);
   CPPUNIT_TEST_SUITE_END();
 private:
   SharedHandle<OptionParser> _oparser;
@@ -24,26 +33,27 @@ public:
   {
     _oparser.reset(new OptionParser());
 
-    SharedHandle<OptionHandler> alpha(new DefaultOptionHandler("alpha",
-							       "",
-							       "ALPHA"));
+    SharedHandle<OptionHandler> alpha
+      (new DefaultOptionHandler("alpha", NO_DESCRIPTION, "ALPHA", "",
+				OptionHandler::REQ_ARG, 'A'));
     alpha->addTag("apple");
     _oparser->addOptionHandler(alpha);
+
     SharedHandle<OptionHandler> bravo(new DefaultOptionHandler("bravo"));
     bravo->addTag("apple");
     bravo->addTag("orange");
     bravo->addTag("pineapple");
     _oparser->addOptionHandler(bravo);
-    SharedHandle<OptionHandler> charlie(new DefaultOptionHandler("charlie",
-								 "",
-								 "CHARLIE",
-								 "",
-								 true));
+
+    SharedHandle<DefaultOptionHandler> charlie
+      (new DefaultOptionHandler("charlie", NO_DESCRIPTION, "CHARLIE", "",
+				OptionHandler::REQ_ARG, 'C'));
+    charlie->hide();
     charlie->addTag("pineapple");
     _oparser->addOptionHandler(charlie);
-    SharedHandle<OptionHandler> delta(new UnitNumberOptionHandler("delta",
-								  "",
-								  "1M"));
+
+    SharedHandle<OptionHandler> delta
+      (new UnitNumberOptionHandler("delta", NO_DESCRIPTION, "1M", -1, -1, 'D'));
     delta->addTag("pineapple");
     _oparser->addOptionHandler(delta);    
   }
@@ -54,7 +64,10 @@ public:
   void testFindByNameSubstring();
   void testFindByTag();
   void testFindByName();
+  void testFindByShortName();
+  void testFindByID();
   void testParseDefaultValues();
+  void testParseArg();
 };
 
 
@@ -97,14 +110,69 @@ void OptionParserTest::testFindByName()
   CPPUNIT_ASSERT(charlie.isNull());
 }
 
+void OptionParserTest::testFindByShortName()
+{
+  SharedHandle<OptionHandler> alpha = _oparser->findByShortName('A');
+  CPPUNIT_ASSERT(!alpha.isNull());
+  CPPUNIT_ASSERT_EQUAL(std::string("alpha"), alpha->getName());
+
+  CPPUNIT_ASSERT(_oparser->findByShortName('C').isNull());
+}
+
+void OptionParserTest::testFindByID()
+{
+  SharedHandle<OptionHandler> alpha = _oparser->findByID(1);
+  CPPUNIT_ASSERT(!alpha.isNull());
+  CPPUNIT_ASSERT_EQUAL(std::string("alpha"), alpha->getName());
+
+  CPPUNIT_ASSERT(_oparser->findByID(3).isNull());
+}
+
 void OptionParserTest::testParseDefaultValues()
 {
   Option option;
-  _oparser->parseDefaultValues(&option);
+  _oparser->parseDefaultValues(option);
   CPPUNIT_ASSERT_EQUAL(std::string("ALPHA"), option.get("alpha"));
   CPPUNIT_ASSERT_EQUAL(std::string("1048576"), option.get("delta"));
   CPPUNIT_ASSERT_EQUAL(std::string("CHARLIE"), option.get("charlie"));
   CPPUNIT_ASSERT(!option.defined("bravo"));
 }
 
+void OptionParserTest::testParseArg()
+{
+  Option option;
+  char prog[7];
+  strncpy(prog, "aria2c", sizeof(prog));
+
+  char optionAlpha[3];
+  strncpy(optionAlpha, "-A", sizeof(optionAlpha));
+  char argAlpha[6];
+  strncpy(argAlpha, "ALPHA", sizeof(argAlpha));
+  char optionBravo[8];
+  strncpy(optionBravo, "--bravo", sizeof(optionBravo));
+  char argBravo[6];
+  strncpy(argBravo, "BRAVO", sizeof(argBravo));
+
+  char nonopt1[8];
+  strncpy(nonopt1, "nonopt1", sizeof(nonopt1));
+  char nonopt2[8];
+  strncpy(nonopt2, "nonopt2", sizeof(nonopt2));
+
+  char* const argv[] = { prog, optionAlpha, argAlpha, optionBravo, argBravo,
+			 nonopt1, nonopt2 };
+  int argc = arrayLength(argv);
+
+  std::stringstream s;
+  std::deque<std::string> nonopts;
+
+  _oparser->parseArg(s, nonopts, argc, argv);
+
+  CPPUNIT_ASSERT_EQUAL(std::string("alpha=ALPHA\n"
+				   "bravo=BRAVO\n"), s.str());
+
+  CPPUNIT_ASSERT_EQUAL((size_t)2, nonopts.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("nonopt1"), nonopts[0]);
+  CPPUNIT_ASSERT_EQUAL(std::string("nonopt2"), nonopts[1]);
+}
+
 } // namespace aria2