Index: trunk/source/Lib/TAppCommon/program_options_lite.cpp
===================================================================
--- trunk/source/Lib/TAppCommon/program_options_lite.cpp	(revision 1179)
+++ trunk/source/Lib/TAppCommon/program_options_lite.cpp	(revision 1313)
@@ -2,7 +2,7 @@
  * License, included below. This software may be subject to other third party
  * and contributor rights, including patent rights, and no such rights are
- * granted under this license.  
+ * granted under this license.
  *
-* Copyright (c) 2010-2015, ITU/ISO/IEC
+ * Copyright (c) 2010-2015, ITU/ISO/IEC
  * All rights reserved.
  *
@@ -40,5 +40,5 @@
 #include <algorithm>
 #include "program_options_lite.h"
-#include  "../TLibCommon/TypeDef.h"
+#include  "../TLibCommon/CommonDef.h"
 using namespace std;
 
@@ -50,5 +50,19 @@
   namespace program_options_lite
   {
-    
+    ErrorReporter default_error_reporter;
+
+    ostream& ErrorReporter::error(const string& where)
+    {
+      is_errored = 1;
+      cerr << where << " error: ";
+      return cerr;
+    }
+
+    ostream& ErrorReporter::warn(const string& where)
+    {
+      cerr << where << " warning: ";
+      return cerr;
+    }
+
     Options::~Options()
     {
@@ -58,5 +72,5 @@
       }
     }
-    
+
     void Options::addOption(OptionBase *opt)
     {
@@ -64,5 +78,5 @@
       names->opt = opt;
       string& opt_string = opt->opt_string;
-      
+
       size_t opt_start = 0;
       for (size_t opt_end = 0; opt_end != string::npos;)
@@ -96,6 +110,6 @@
       return OptionSpecific(*this);
     }
-    
-    static void setOptions(Options::NamesPtrList& opt_list, const string& value)
+
+    static void setOptions(Options::NamesPtrList& opt_list, const string& value, ErrorReporter& error_reporter)
     {
       /* multiple options may be registered for the same name:
@@ -103,10 +117,10 @@
       for (Options::NamesPtrList::iterator it = opt_list.begin(); it != opt_list.end(); ++it)
       {
-        (*it)->opt->parse(value);
+        (*it)->opt->parse(value, error_reporter);
       }
     }
 
     static const char spaces[41] = "                                        ";
-    
+
     /* format help text for a single option:
      * using the formatting: "-x, --long",
@@ -138,5 +152,5 @@
       }
     }
-    
+
     /* format the help text */
     void doHelp(ostream& out, Options& opts, unsigned columns)
@@ -147,5 +161,5 @@
       for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++)
       {
-#if H_MV
+#if NH_MV
         if  ( (*it)->opt->opt_duplicate ) continue; 
 #endif
@@ -157,5 +171,5 @@
       unsigned opt_width = min(max_width+2, 28u + pad_short) + 2;
       unsigned desc_width = columns - opt_width;
-      
+
       /* second pass: write out formatted option and help text.
        *  - align start of help text to start at opt_width
@@ -165,5 +179,5 @@
       for(Options::NamesPtrList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++)
       {
-#if H_MV
+#if NH_MV
         if  ( (*it)->opt->opt_duplicate ) continue; 
 #endif
@@ -215,5 +229,5 @@
             split_pos = opt_desc.find_last_not_of(' ', split_pos) + 1;
           }
-          
+
           /* bad split if no suitable space to split at.  fall back to width */
           bool bad_split = split_pos == string::npos || split_pos <= cur_pos;
@@ -223,5 +237,5 @@
           }
           line << opt_desc.substr(cur_pos, split_pos - cur_pos);
-          
+
           /* eat up any space for the start of the next line */
           if (!bad_split)
@@ -230,5 +244,5 @@
           }
           cur_pos = newline_pos = split_pos;
-          
+
           if (cur_pos >= opt_desc.size())
           {
@@ -241,6 +255,25 @@
       }
     }
-    
-    bool storePair(Options& opts, bool allow_long, bool allow_short, const string& name, const string& value)
+
+    struct OptionWriter
+    {
+      OptionWriter(Options& rOpts, ErrorReporter& err)
+      : opts(rOpts), error_reporter(err)
+      {}
+      virtual ~OptionWriter() {}
+
+      virtual const string where() = 0;
+
+      bool storePair(bool allow_long, bool allow_short, const string& name, const string& value);
+      bool storePair(const string& name, const string& value)
+      {
+        return storePair(true, true, name, value);
+      }
+
+      Options& opts;
+      ErrorReporter& error_reporter;
+    };
+
+    bool OptionWriter::storePair(bool allow_long, bool allow_short, const string& name, const string& value)
     {
       bool found = false;
@@ -254,5 +287,5 @@
         }
       }
-      
+
       /* check for the short list */
       if (allow_short && !(found && allow_long))
@@ -267,22 +300,29 @@
       if (!found)
       {
-        /* not found */
-        cerr << "Unknown option: `" << name << "' (value:`" << value << "')" << endl;
+        error_reporter.error(where())
+          << "Unknown option `" << name << "' (value:`" << value << "')\n";
         return false;
       }
 
-      setOptions((*opt_it).second, value);
+      setOptions((*opt_it).second, value, error_reporter);
       return true;
     }
-    
-    bool storePair(Options& opts, const string& name, const string& value)
-    {
-      return storePair(opts, true, true, name, value);
-    }
-    
+
+    struct ArgvParser : public OptionWriter
+    {
+      ArgvParser(Options& rOpts, ErrorReporter& rError_reporter)
+      : OptionWriter(rOpts, rError_reporter)
+      {}
+
+      const string where() { return "command line"; }
+
+      unsigned parseGNU(unsigned argc, const char* argv[]);
+      unsigned parseSHORT(unsigned argc, const char* argv[]);
+    };
+
     /**
      * returns number of extra arguments consumed
      */
-    unsigned parseGNU(Options& opts, unsigned argc, const char* argv[])
+    unsigned ArgvParser::parseGNU(unsigned argc, const char* argv[])
     {
       /* gnu style long options can take the forms:
@@ -294,5 +334,5 @@
       size_t arg_opt_sep = arg.find_first_of('=');
       string option = arg.substr(arg_opt_start, arg_opt_sep - arg_opt_start);
-      
+
       unsigned extra_argc_consumed = 0;
       if (arg_opt_sep == string::npos)
@@ -305,8 +345,10 @@
         * booleans */
         if (argc == 1)
+        {
           return 0; /* run out of argv for argument */
+        }
         extra_argc_consumed = 1;
 #endif
-        if(!storePair(opts, true, false, option, "1"))
+        if(!storePair(true, false, option, "1"))
         {
           return 0;
@@ -317,5 +359,5 @@
         /* argument occurs after option_sep */
         string val = arg.substr(arg_opt_sep + 1);
-        storePair(opts, true, false, option, val);
+        storePair(true, false, option, val);
       }
 
@@ -323,5 +365,5 @@
     }
 
-    unsigned parseSHORT(Options& opts, unsigned argc, const char* argv[])
+    unsigned ArgvParser::parseSHORT(unsigned argc, const char* argv[])
     {
       /* short options can take the forms:
@@ -338,15 +380,18 @@
       if (argc == 1)
       {
-        cerr << "Not processing option without argument `" << option << "'" << endl;
+        error_reporter.error(where())
+          << "Not processing option `" << option << "' without argument\n";
         return 0; /* run out of argv for argument */
       }
-      storePair(opts, false, true, option, string(argv[1]));
+      storePair(false, true, option, string(argv[1]));
 
       return 1;
     }
-    
+
     list<const char*>
-    scanArgv(Options& opts, unsigned argc, const char* argv[])
-    {
+    scanArgv(Options& opts, unsigned argc, const char* argv[], ErrorReporter& error_reporter)
+    {
+      ArgvParser avp(opts, error_reporter);
+
       /* a list for anything that didn't get handled as an option */
       list<const char*> non_option_arguments;
@@ -370,9 +415,5 @@
         {
           /* handle short (single dash) options */
-#if 0
-          i += parsePOSIX(opts, argc - i, &argv[i]);
-#else
-          i += parseSHORT(opts, argc - i, &argv[i]);
-#endif
+          i += avp.parseSHORT(argc - i, &argv[i]);
           continue;
         }
@@ -382,16 +423,39 @@
           /* a lone double dash ends option processing */
           while (++i < argc)
+          {
             non_option_arguments.push_back(argv[i]);
+          }
           break;
         }
 
         /* handle long (double dash) options */
-        i += parseGNU(opts, argc - i, &argv[i]);
+        i += avp.parseGNU(argc - i, &argv[i]);
       }
 
       return non_option_arguments;
     }
-    
-    void scanLine(Options& opts, string& line)
+
+    struct CfgStreamParser : public OptionWriter
+    {
+      CfgStreamParser(const string& rName, Options& rOpts, ErrorReporter& rError_reporter)
+      : OptionWriter(rOpts, rError_reporter)
+      , name(rName)
+      , linenum(0)
+      {}
+
+      const string name;
+      int linenum;
+      const string where()
+      {
+        ostringstream os;
+        os << name << ":" << linenum;
+        return os.str();
+      }
+
+      void scanLine(string& line);
+      void scanStream(istream& in);
+    };
+
+    void CfgStreamParser::scanLine(string& line)
     {
       /* strip any leading whitespace */
@@ -416,4 +480,5 @@
       {
         /* error: badly formatted line */
+        error_reporter.warn(where()) << "line formatting error\n";
         return;
       }
@@ -421,4 +486,5 @@
       {
         /* error: badly formatted line */
+        error_reporter.warn(where()) << "line formatting error\n";
         return;
       }
@@ -429,4 +495,9 @@
       {
         /* error: badly formatted line */
+#if !NH_MV
+        error_reporter.warn(where()) << "line formatting error\n";
+#else
+        // HTM also allows empty parameters.
+#endif
         return;
       }
@@ -447,6 +518,5 @@
          * any trailing whitespace will be removed shortly */
         value_end = line.find_first_not_of(" \t\n\r", value_end);
-      }
-      while (value_end != string::npos);
+      } while (value_end != string::npos);
       /* strip any trailing space from value*/
       value_end = line.find_last_not_of(" \t\n\r", value_end);
@@ -460,20 +530,25 @@
       {
         /* error: no value */
+#if !NH_MV
+        error_reporter.warn(where()) << "no value found\n";
+#else
+        // This is ok for HTM.
+#endif
         return;
       }
 
       /* store the value in option */
-      storePair(opts, true, false, option, value);
-    }
-
-    void scanFile(Options& opts, istream& in)
+      storePair(true, false, option, value);
+    }
+
+    void CfgStreamParser::scanStream(istream& in)
     {
       do
       {
+        linenum++;
         string line;
         getline(in, line);
-        scanLine(opts, line);
-      }
-      while(!!in);
+        scanLine(line);
+      } while(!!in);
     }
 
@@ -488,17 +563,18 @@
     }
 
-    void parseConfigFile(Options& opts, const string& filename)
+    void parseConfigFile(Options& opts, const string& filename, ErrorReporter& error_reporter)
     {
       ifstream cfgstream(filename.c_str(), ifstream::in);
       if (!cfgstream)
       {
-        cerr << "Failed to open config file: `" << filename << "'" << endl;
-        exit(EXIT_FAILURE);
-      }
-      scanFile(opts, cfgstream);
-    }
-
-  };
-};
+        error_reporter.error(filename) << "Failed to open config file\n";
+        return;
+      }
+      CfgStreamParser csp(filename, opts, error_reporter);
+      csp.scanStream(cfgstream);
+    }
+
+  }
+}
 
 //! \}
