$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r77829 - in branches/release: boost/program_options boost/program_options/detail libs/program_options libs/program_options/build libs/program_options/doc libs/program_options/example libs/program_options/src libs/program_options/test
From: ghost_at_[hidden]
Date: 2012-04-08 06:02:29
Author: vladimir_prus
Date: 2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
New Revision: 77829
URL: http://svn.boost.org/trac/boost/changeset/77829
Log:
Merge from trunk.
Added:
   branches/release/libs/program_options/test/exception_txt_test.cpp
      - copied unchanged from r77828, /trunk/libs/program_options/test/exception_txt_test.cpp
Properties modified: 
   branches/release/boost/program_options/   (props changed)
   branches/release/boost/program_options/detail/parsers.hpp   (contents, props changed)
   branches/release/boost/program_options/parsers.hpp   (contents, props changed)
   branches/release/libs/program_options/   (props changed)
   branches/release/libs/program_options/test/parsers_test.cpp   (props changed)
Text files modified: 
   branches/release/boost/program_options/detail/cmdline.hpp               |    12 +                                       
   branches/release/boost/program_options/detail/parsers.hpp               |     6                                         
   branches/release/boost/program_options/errors.hpp                       |   454 +++++++++++++++++++++++++++------------ 
   branches/release/boost/program_options/options_description.hpp          |    10                                         
   branches/release/boost/program_options/parsers.hpp                      |    30 ++                                      
   branches/release/boost/program_options/value_semantic.hpp               |    10                                         
   branches/release/boost/program_options/variables_map.hpp                |    13                                         
   branches/release/libs/program_options/build/Jamfile.v2                  |     2                                         
   branches/release/libs/program_options/doc/overview.xml                  |     2                                         
   branches/release/libs/program_options/example/first.cpp                 |     6                                         
   branches/release/libs/program_options/example/multiple_sources.cpp      |     2                                         
   branches/release/libs/program_options/example/options_description.cpp   |     2                                         
   branches/release/libs/program_options/src/cmdline.cpp                   |   324 ++++++++++++++++-----------             
   branches/release/libs/program_options/src/config_file.cpp               |     6                                         
   branches/release/libs/program_options/src/options_description.cpp       |    46 +++                                     
   branches/release/libs/program_options/src/parsers.cpp                   |    10                                         
   branches/release/libs/program_options/src/value_semantic.cpp            |   285 ++++++++++++++++--------                
   branches/release/libs/program_options/src/variables_map.cpp             |   130 ++++++----                              
   branches/release/libs/program_options/test/cmdline_test.cpp             |     9                                         
   branches/release/libs/program_options/test/exception_test.cpp           |    12                                         
   branches/release/libs/program_options/test/program_options_size_test.py |     4                                         
   branches/release/libs/program_options/test/required_test.cpp            |     1                                         
   22 files changed, 916 insertions(+), 460 deletions(-)
Modified: branches/release/boost/program_options/detail/cmdline.hpp
==============================================================================
--- branches/release/boost/program_options/detail/cmdline.hpp	(original)
+++ branches/release/boost/program_options/detail/cmdline.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -81,6 +81,18 @@
         cmdline(int argc, const char*const * argv);
 
         void style(int style);
+
+        /** returns the canonical option prefix associated with the command_line_style
+         *  In order of precedence:
+         *      allow_long           : allow_long
+         *      allow_long_disguise  : allow_long_disguise
+         *      allow_dash_for_short : allow_short | allow_dash_for_short
+         *      allow_slash_for_short: allow_short | allow_slash_for_short
+         *  
+         *      This is mainly used for the diagnostic messages in exceptions
+        */ 
+        int         get_canonical_option_prefix();
+
         void allow_unregistered();
 
         void set_options_description(const options_description& desc);
Modified: branches/release/boost/program_options/detail/parsers.hpp
==============================================================================
--- branches/release/boost/program_options/detail/parsers.hpp	(original)
+++ branches/release/boost/program_options/detail/parsers.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -100,7 +100,11 @@
     basic_parsed_options<charT>
     basic_command_line_parser<charT>::run()
     {
-        parsed_options result(m_desc);
+        // save the canonical prefixes which were used by this cmdline parser
+        //    eventually inside the parsed results
+        //    This will be handy to format recognisable options
+        //    for diagnostic messages if everything blows up much later on
+        parsed_options result(m_desc, detail::cmdline::get_canonical_option_prefix());
         result.options = detail::cmdline::run();
 
         // Presense of parsed_options -> wparsed_options conversion
Modified: branches/release/boost/program_options/errors.hpp
==============================================================================
--- branches/release/boost/program_options/errors.hpp	(original)
+++ branches/release/boost/program_options/errors.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -12,6 +12,8 @@
 #include <string>
 #include <stdexcept>
 #include <vector>
+#include <map>
+
 
 #if defined(BOOST_MSVC)
 #   pragma warning (push)
@@ -21,126 +23,338 @@
 
 namespace boost { namespace program_options {
 
+    inline std::string strip_prefixes(const std::string& text)
+    {
+        return text.substr(text.find_last_of("-/") + 1);
+    }
+
     /** Base class for all errors in the library. */
     class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error {
     public:
         error(const std::string& xwhat) : std::logic_error(xwhat) {}
     };
 
-    class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error {
+
+    /** Class thrown when there are too many positional options. 
+        This is a programming error.
+    */
+    class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
     public:
-        enum kind_t {
-            long_not_allowed = 30,
-            long_adjacent_not_allowed,
-            short_adjacent_not_allowed,
-            empty_adjacent_parameter,
-            missing_parameter,
-            extra_parameter,
-            unrecognized_line
-        };
-        
-        invalid_syntax(const std::string& tokens, kind_t kind);
+        too_many_positional_options_error() 
+         : error("too many positional arguments have been specified on the command line") 
+        {}
+    };
+
+    /** Class thrown when there are programming error related to style */
+    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
+    public:
+        invalid_command_line_style(const std::string& msg)
+        : error(msg)
+        {}
+    };
+
+    /** Class thrown if config file can not be read */
+    class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
+    public:
+        reading_file(const char* filename)
+         : error(std::string("can not read options configuration file '").append(filename).append("'"))
+        {}
+    };
+
+
+    /** Base class for most exceptions in the library.
+     *  
+     *  Substitutes the values for the parameter name
+     *      placeholders in the template to create the human
+     *      readable error message
+     *  
+     *  Placeholders are surrounded by % signs: %example%
+     *      Poor man's version of boost::format
+     *  
+     *  If a parameter name is absent, perform default substitutions
+     *      instead so ugly placeholders are never left in-place.
+     *  
+     *  Options are displayed in "canonical" form
+     *      This is the most unambiguous form of the
+     *      *parsed* option name and would correspond to
+     *      option_description::format_name()
+     *      i.e. what is shown by print_usage()
+     *  
+     *  The "canonical" form depends on whether the option is
+     *      specified in short or long form, using dashes or slashes
+     *      or without a prefix (from a configuration file)
+     *  
+     *   */
+    class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {
 
-        // gcc says that throw specification on dtor is loosened
-        // without this line
-        ~invalid_syntax() throw() {}
-        
-        kind_t kind() const;
-        
-        const std::string& tokens() const;
-        
     protected:
-        /** Used to convert kind_t to a related error text */
-        static std::string error_message(kind_t kind);
+        /** can be
+         *      0 = no prefix (config file options)
+         *      allow_long
+         *      allow_dash_for_short
+         *      allow_slash_for_short
+         *      allow_long_disguise */
+        int m_option_style;
+
+
+        /** substitutions
+         *  from placeholders to values */
+        std::map<std::string, std::string> m_substitutions;
+        typedef std::pair<std::string, std::string> string_pair;
+        std::map<std::string, string_pair > m_substitution_defaults;
+
+    public:
+		/** template with placeholders */
+		std::string m_error_template;
+
+		error_with_option_name(const std::string& template_,
+                              const std::string& option_name = "",
+                              const std::string& original_token = "",
+                              int option_style               = 0);
+
+        /** gcc says that throw specification on dtor is loosened 
+         *  without this line                                     
+         *  */ 
+        ~error_with_option_name() throw() {}
+
+
+        //void dump() const
+        //{
+        //  std::cerr << "m_substitution_defaults:\n";
+        //  for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
+        //        iter != m_substitution_defaults.end(); ++iter)
+        //      std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n";
+        //  std::cerr << "m_substitutions:\n";
+        //  for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin();
+        //        iter != m_substitutions.end(); ++iter)
+        //      std::cerr << "\t" << iter->first << "=" << iter->second << "\n";
+        //  std::cerr << "m_error_template:\n";
+        //  std::cerr << "\t" << m_error_template << "\n";
+        //  std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n";
+        //  std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n";
+        //  std::cerr << "what:[" << what() << "]\n";
+        //}
+
+        /** Substitute
+         *      parameter_name->value to create the error message from
+         *      the error template */
+        void set_substitute(const std::string& parameter_name,  const std::string& value)
+        {           m_substitutions[parameter_name] = value;    }
+
+        /** If the parameter is missing, then make the
+         *      from->to substitution instead */
+        void set_substitute_default(const std::string& parameter_name, 
+                                    const std::string& from,  
+                                    const std::string& to)
+        {           
+            m_substitution_defaults[parameter_name] = std::make_pair(from, to); 
+        }
+
+
+        /** Add context to an exception */
+        void add_context(const std::string& option_name,
+                         const std::string& original_token,
+                         int option_style)
+        {
+            set_option_name(option_name);
+            set_original_token(original_token);
+            set_prefix(option_style);
+        }
+
+        void set_prefix(int option_style)
+        {           m_option_style = option_style;}
+
+        /** Overridden in error_with_no_option_name */
+        virtual void set_option_name(const std::string& option_name)
+        {           set_substitute("option", option_name);}
+
+        std::string get_option_name() const throw()
+        {           return get_canonical_option_name();         }
+
+        void set_original_token(const std::string& original_token)
+        {           set_substitute("original_token", original_token);}
+
+
+        /** Creates the error_message on the fly
+         *      Currently a thin wrapper for substitute_placeholders() */
+        virtual const char* what() const throw();
 
-    private:
-        // TODO: copy ctor might throw
-        std::string m_tokens;
+    protected:
+        /** Used to hold the error text returned by what() */
+        mutable std::string m_message;  // For on-demand formatting in 'what'
 
-        kind_t m_kind;
+        /** Makes all substitutions using the template */
+        virtual void substitute_placeholders(const std::string& error_template) const;
+
+        // helper function for substitute_placeholders
+        void replace_token(const std::string& from, const std::string& to) const;
+
+        /** Construct option name in accordance with the appropriate
+         *  prefix style: i.e. long dash or short slash etc */
+        std::string get_canonical_option_name() const;
+        std::string get_canonical_option_prefix() const;
+    };
+
+
+    /** Class thrown when there are several option values, but
+        user called a method which cannot return them all. */
+    class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error_with_option_name {
+    public:
+        multiple_values() 
+         : error_with_option_name("option '%canonical_option%' only takes a single argument"){}
+
+        ~multiple_values() throw() {}
+    };
+
+    /** Class thrown when there are several occurrences of an
+        option, but user called a method which cannot return 
+        them all. */
+    class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error_with_option_name {
+    public:
+        multiple_occurrences() 
+         : error_with_option_name("option '%canonical_option%' cannot be specified more than once"){}
+
+        ~multiple_occurrences() throw() {}
+
+    };
+
+    /** Class thrown when a required/mandatory option is missing */
+    class BOOST_PROGRAM_OPTIONS_DECL required_option : public error_with_option_name {
+    public:
+       // option name is constructed by the option_descriptor and never on the fly
+       required_option(const std::string& option_name)
+       : error_with_option_name("the option '%canonical_option%' is required but missing", "", option_name)
+       {
+       }
+
+       ~required_option() throw() {}
+    };
+
+    /** Base class of unparsable options,
+     *  when the desired option cannot be identified.
+     *  
+     *  
+     *  It makes no sense to have an option name, when we can't match an option to the
+     *      parameter
+     *  
+     *  Having this a part of the error_with_option_name hierachy makes error handling
+     *      a lot easier, even if the name indicates some sort of conceptual dissonance!
+     *  
+     *   */
+    class BOOST_PROGRAM_OPTIONS_DECL error_with_no_option_name : public error_with_option_name {
+    public:
+        error_with_no_option_name(const std::string& template_,
+                              const std::string& original_token = "")
+        : error_with_option_name(template_, "", original_token)
+        {
+        }
+
+        /** Does NOT set option name, because no option name makes sense */
+        virtual void set_option_name(const std::string& option_name){}
+
+        ~error_with_no_option_name() throw() {}
     };
 
+
     /** Class thrown when option name is not recognized. */
-    class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error {
+    class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error_with_no_option_name {
     public:
-        unknown_option(const std::string& name)
-        : error(std::string("unknown option ").append(name)), 
-          m_option_name(name)
-        {}
+        unknown_option(const std::string& original_token = "")
+        : error_with_no_option_name("unrecognised option '%canonical_option%'", original_token)
+        {
+        }
 
-        // gcc says that throw specification on dtor is loosened
-        // without this line
         ~unknown_option() throw() {}
-        
-        const std::string& get_option_name() const throw();
-        
-    private:
-        std::string m_option_name;
     };
 
+
+
     /** Class thrown when there's ambiguity amoung several possible options. */
-    class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error {
+    class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error_with_no_option_name {
     public:
-        ambiguous_option(const std::string& name, 
-                         const std::vector<std::string>& xalternatives)
-        : error(std::string("ambiguous option ").append(name))
-        , m_alternatives(xalternatives)
-        , m_option_name(name)
+        ambiguous_option(const std::vector<std::string>& xalternatives)
+        : error_with_no_option_name("option '%canonical_option%' is ambiguous"),
+            m_alternatives(xalternatives)
         {}
 
         ~ambiguous_option() throw() {}
-        
-        const std::string& get_option_name() const throw();
-        
-        const std::vector<std::string>& alternatives() const throw();
 
+        const std::vector<std::string>& alternatives() const throw() {return m_alternatives;}
+
+    protected:
+        /** Makes all substitutions using the template */
+        virtual void substitute_placeholders(const std::string& error_template) const;
     private:
         // TODO: copy ctor might throw
         std::vector<std::string> m_alternatives;
-        std::string m_option_name;
     };
 
-    /** Class thrown when there are several option values, but
-        user called a method which cannot return them all. */
-    class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error {
+
+    /** Class thrown when there's syntax error either for command
+     *  line or config file options. See derived children for
+     *  concrete classes. */
+    class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error_with_option_name {
     public:
-        multiple_values() 
-         : error("multiple values")
-         , m_option_name() {}
-         
-        ~multiple_values() throw() {}
-        
-        void set_option_name(const std::string& option);
-        
-        const std::string& get_option_name() const throw();
-        
-    private:
-        std::string m_option_name; // The name of the option which
-                                   // caused the exception.        
+        enum kind_t {
+            long_not_allowed = 30,
+            long_adjacent_not_allowed,
+            short_adjacent_not_allowed,
+            empty_adjacent_parameter,
+            missing_parameter,
+            extra_parameter,
+            unrecognized_line
+        };
+
+        invalid_syntax(kind_t kind, 
+                       const std::string& option_name = "",
+                       const std::string& original_token = "",
+                       int option_style              = 0):
+            error_with_option_name(get_template(kind), option_name, original_token, option_style),
+            m_kind(kind)
+        {
+        }
+
+        ~invalid_syntax() throw() {}
+
+        kind_t kind() const {return m_kind;}
+
+        /** Convenience functions for backwards compatibility */
+        virtual std::string tokens() const {return get_option_name();   }
+    protected:
+        /** Used to convert kind_t to a related error text */
+        std::string get_template(kind_t kind);
+        kind_t m_kind;
     };
 
-    /** Class thrown when there are several occurrences of an
-        option, but user called a method which cannot return 
-        them all. */
-    class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error {
+    class BOOST_PROGRAM_OPTIONS_DECL invalid_config_file_syntax : public invalid_syntax {
     public:
-        multiple_occurrences() 
-         : error("multiple occurrences")
-         , m_option_name() {}
-         
-        ~multiple_occurrences() throw() {}
-        
-        void set_option_name(const std::string& option);
-        
-        const std::string& get_option_name() const throw();
+        invalid_config_file_syntax(const std::string& invalid_line, kind_t kind):
+            invalid_syntax(kind)
+        {
+            m_substitutions["invalid_line"] = invalid_line;
+        }
 
-    private:        
-        std::string m_option_name; // The name of the option which
-                                   // caused the exception.
+        ~invalid_config_file_syntax() throw() {}
+
+        /** Convenience functions for backwards compatibility */
+        virtual std::string tokens() const {return m_substitutions.find("invalid_line")->second;    }
     };
 
+
+    /** Class thrown when there are syntax errors in given command line */
+    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
+    public:
+        invalid_command_line_syntax(kind_t kind,
+                       const std::string& option_name = "",
+                       const std::string& original_token = "",
+                       int option_style              = 0):
+            invalid_syntax(kind, option_name, original_token, option_style) {}
+        ~invalid_command_line_syntax() throw() {}
+    };
+
+
     /** Class thrown when value of option is incorrect. */
-    class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
+    class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error_with_option_name {
     public:
         enum kind_t {
             multiple_values_not_allowed = 30,
@@ -150,32 +364,24 @@
             invalid_option
         };
         
+    public:
         validation_error(kind_t kind, 
-                         const std::string& option_value = "",
-                         const std::string& option_name = "");
-                         
+                   const std::string& option_name = "",
+                   const std::string& original_token = "",
+                   int option_style              = 0):
+        error_with_option_name(get_template(kind), option_name, original_token, option_style)
+        {
+        }
+
         ~validation_error() throw() {}
 
-        void set_option_name(const std::string& option);
-        
-        const std::string& get_option_name() const throw();
-        
-        const char* what() const throw();
-        
     protected:
         /** Used to convert kind_t to a related error text */
-        static std::string error_message(kind_t kind);
-
-    private:
+        std::string get_template(kind_t kind);
         kind_t m_kind;
-        std::string m_option_name; // The name of the option which
-                                   // caused the exception.
-        std::string m_option_value; // Optional: value of the option m_options_name
-        mutable std::string m_message; // For on-demand formatting in 'what'
-
     };
 
-    /** Class thrown if there is an invalid option value givenn */
+    /** Class thrown if there is an invalid option value given */
     class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value 
         : public validation_error
     {
@@ -186,54 +392,20 @@
 #endif
     };
 
-    /** Class thrown when there are too many positional options. 
-        This is a programming error.
-    */
-    class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
+    /** Class thrown if there is an invalid bool value given */
+    class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value 
+        : public validation_error
+    {
     public:
-        too_many_positional_options_error() 
-         : error("too many positional options") 
-        {}
+        invalid_bool_value(const std::string& value);
     };
 
-    /** Class thrown when there are syntax errors in given command line */
-    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
-    public:
-        invalid_command_line_syntax(const std::string& tokens, kind_t kind);
-    };
 
-    /** Class thrown when there are programming error related to style */
-    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
-    public:
-        invalid_command_line_style(const std::string& msg)
-        : error(msg)
-        {}
-    };
 
-    /** Class thrown if config file can not be read */
-    class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
-    public:
-        reading_file(const char* filename)
-         : error(std::string("can not read file ").append(filename))
-        {}
-    };
+
+
     
-     /** Class thrown when a required/mandatory option is missing */
-     class BOOST_PROGRAM_OPTIONS_DECL required_option : public error {
-     public:
-        required_option(const std::string& name)
-        : error(std::string("missing required option ").append(name))
-        , m_option_name(name)
-        {}
- 
-        ~required_option() throw() {}
 
-        const std::string& get_option_name() const throw();
-        
-     private:
-        std::string m_option_name; // The name of the option which
-                                   // caused the exception.
-     };
 }}
 
 #if defined(BOOST_MSVC)
Modified: branches/release/boost/program_options/options_description.hpp
==============================================================================
--- branches/release/boost/program_options/options_description.hpp	(original)
+++ branches/release/boost/program_options/options_description.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -102,6 +102,16 @@
         */
         const std::string& key(const std::string& option) const;
 
+
+        /** Returns the canonical name for the option description to enable the user to
+            recognised a matching option.
+            1) For short options ('-', '/'), returns the short name prefixed.
+            2) For long options ('--' / '-') returns the long name prefixed
+            3) All other cases, returns the long name (if present) or the short name,
+                unprefixed.
+        */
+        std::string canonical_display_name(int canonical_option_style = 0) const;
+
         const std::string& long_name() const;
 
         /// Explanation of this option
Modified: branches/release/boost/program_options/parsers.hpp
==============================================================================
--- branches/release/boost/program_options/parsers.hpp	(original)
+++ branches/release/boost/program_options/parsers.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -36,8 +36,8 @@
     template<class charT>
     class basic_parsed_options {
     public:
-        explicit basic_parsed_options(const options_description* xdescription) 
-        : description(xdescription) {}
+        explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0) 
+        : description(xdescription), m_options_prefix(options_prefix) {}
         /** Options found in the source. */
         std::vector< basic_option<charT> > options;
         /** Options description that was used for parsing. 
@@ -46,6 +46,17 @@
             up to the caller. Can be NULL.
          */
         const options_description* description;
+
+        /** Mainly used for the diagnostic messages in exceptions.
+         *  The canonical option prefix  for the parser which generated these results,
+         *  depending on the settings for basic_command_line_parser::style() or
+         *  cmdline::style(). In order of precedence of command_line_style enums:
+         *      allow_long
+         *      allow_long_disguise
+         *      allow_dash_for_short
+         *      allow_slash_for_short
+        */ 
+        int m_options_prefix;
     };
 
     /** Specialization of basic_parsed_options which:
@@ -64,6 +75,17 @@
         /** Stores UTF8 encoded options that were passed to constructor,
             to avoid reverse conversion in some cases. */
         basic_parsed_options<char> utf8_encoded_options;        
+
+        /** Mainly used for the diagnostic messages in exceptions.
+         *  The canonical option prefix  for the parser which generated these results,
+         *  depending on the settings for basic_command_line_parser::style() or
+         *  cmdline::style(). In order of precedence of command_line_style enums:
+         *      allow_long
+         *      allow_long_disguise
+         *      allow_dash_for_short
+         *      allow_slash_for_short
+        */ 
+        int m_options_prefix;
     };
 
     typedef basic_parsed_options<char> parsed_options;
@@ -260,6 +282,10 @@
 
 }}
 
+#if defined(BOOST_MSVC)
+#   pragma warning (pop)
+#endif
+
 #undef DECL
 
 #include "boost/program_options/detail/parsers.hpp"
Modified: branches/release/boost/program_options/value_semantic.hpp
==============================================================================
--- branches/release/boost/program_options/value_semantic.hpp	(original)
+++ branches/release/boost/program_options/value_semantic.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -261,13 +261,21 @@
             return this;
         }
 
-        /** Specifies that the value can span multiple tokens. */
+        /** Specifies that the value can span multiple tokens. 
+        */
         typed_value* multitoken()
         {
             m_multitoken = true;
             return this;
         }
 
+        /** Specifies that no tokens may be provided as the value of
+            this option, which means that only presense of the option
+            is significant. For such option to be useful, either the
+            'validate' function should be specialized, or the 
+            'implicit_value' method should be also used. In most
+            cases, you can use the 'bool_switch' function instead of
+            using this method. */
         typed_value* zero_tokens() 
         {
             m_zero_tokens = true;
Modified: branches/release/boost/program_options/variables_map.hpp
==============================================================================
--- branches/release/boost/program_options/variables_map.hpp	(original)
+++ branches/release/boost/program_options/variables_map.hpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -153,6 +153,9 @@
         // Resolve conflict between inherited operators.
         const variable_value& operator[](const std::string& name) const
         { return abstract_variables_map::operator[](name); }
+
+        // Override to clear some extra fields.
+        void clear(); 
         
         void notify();
 
@@ -171,8 +174,10 @@
                           bool utf8);
         
         /** Names of required options, filled by parser which has
-            access to options_description. */
-        std::set<std::string> m_required;
+            access to options_description.
+            The map values are the "canonical" names for each corresponding option.
+            This is useful in creating diagnostic messages when the option is absent. */
+        std::map<std::string, std::string> m_required;
     };
 
 
@@ -208,4 +213,8 @@
 
 }}
 
+#if defined(BOOST_MSVC)
+#   pragma warning (pop)
+#endif
+
 #endif
Modified: branches/release/libs/program_options/build/Jamfile.v2
==============================================================================
--- branches/release/libs/program_options/build/Jamfile.v2	(original)
+++ branches/release/libs/program_options/build/Jamfile.v2	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -12,6 +12,8 @@
 lib boost_program_options
     : $(SOURCES).cpp
     : <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
+      # See https://svn.boost.org/trac/boost/ticket/5049
+      <target-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
     :
     : <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
     ;
Modified: branches/release/libs/program_options/doc/overview.xml
==============================================================================
--- branches/release/libs/program_options/doc/overview.xml	(original)
+++ branches/release/libs/program_options/doc/overview.xml	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -181,7 +181,7 @@
 desc.add_options()
     ("help", "produce help message")
     ("compression", value<string>(), "compression level")
-    ("verbose", value<string>()->zero_tokens(), "verbosity level")
+    ("verbose", value<string>()->implicit_value("0"), "verbosity level")
     ("email", value<string>()->multitoken(), "email to send to")
     ;
       </programlisting>
Modified: branches/release/libs/program_options/example/first.cpp
==============================================================================
--- branches/release/libs/program_options/example/first.cpp	(original)
+++ branches/release/libs/program_options/example/first.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -20,7 +20,7 @@
         po::options_description desc("Allowed options");
         desc.add_options()
             ("help", "produce help message")
-            ("compression", po::value<int>(), "set compression level")
+            ("compression", po::value<double>(), "set compression level")
         ;
 
         po::variables_map vm;        
@@ -29,12 +29,12 @@
 
         if (vm.count("help")) {
             cout << desc << "\n";
-            return 1;
+            return 0;
         }
 
         if (vm.count("compression")) {
             cout << "Compression level was set to " 
-                 << vm["compression"].as<int>() << ".\n";
+                 << vm["compression"].as<double>() << ".\n";
         } else {
             cout << "Compression level was not set.\n";
         }
Modified: branches/release/libs/program_options/example/multiple_sources.cpp
==============================================================================
--- branches/release/libs/program_options/example/multiple_sources.cpp	(original)
+++ branches/release/libs/program_options/example/multiple_sources.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -18,7 +18,7 @@
 template<class T>
 ostream& operator<<(ostream& os, const vector<T>& v)
 {
-    copy(v.begin(), v.end(), ostream_iterator<T>(cout, " ")); 
+    copy(v.begin(), v.end(), ostream_iterator<T>(os, " ")); 
     return os;
 }
 
Modified: branches/release/libs/program_options/example/options_description.cpp
==============================================================================
--- branches/release/libs/program_options/example/options_description.cpp	(original)
+++ branches/release/libs/program_options/example/options_description.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -18,7 +18,7 @@
 template<class T>
 ostream& operator<<(ostream& os, const vector<T>& v)
 {
-    copy(v.begin(), v.end(), ostream_iterator<T>(cout, " ")); 
+    copy(v.begin(), v.end(), ostream_iterator<T>(os, " ")); 
     return os;
 }
 
Modified: branches/release/libs/program_options/src/cmdline.cpp
==============================================================================
--- branches/release/libs/program_options/src/cmdline.cpp	(original)
+++ branches/release/libs/program_options/src/cmdline.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -34,64 +34,43 @@
     using namespace std;
     using namespace boost::program_options::command_line_style;
     
-    invalid_syntax::
-    invalid_syntax(const string& tokens, kind_t kind)
-     : error(error_message(kind).append(" in '").append(tokens).append("'"))
-     , m_tokens(tokens)
-     , m_kind(kind)                       
-    {}
     
     string 
-    invalid_syntax::error_message(kind_t kind)
+    invalid_syntax::get_template(kind_t kind)
     {
         // Initially, store the message in 'const char*' variable,
         // to avoid conversion to string in all cases.
         const char* msg;
         switch(kind)
         {
+        case empty_adjacent_parameter:
+            msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
+            break;
+        case missing_parameter:
+            msg = "the required argument for option '%canonical_option%' is missing";
+            break;
+        case unrecognized_line:
+            msg = "the options configuration file contains an invalid line '%invalid_line%'";
+            break;
+        // none of the following are currently used:
         case long_not_allowed:
-            msg = "long options are not allowed";
+            msg = "the unabbreviated option '%canonical_option%' is not valid";
             break;
         case long_adjacent_not_allowed:
-            msg = "parameters adjacent to long options not allowed";
+            msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
             break;
         case short_adjacent_not_allowed:
-            msg = "parameters adjust to short options are not allowed";
-            break;
-        case empty_adjacent_parameter:
-            msg = "adjacent parameter is empty";
-            break;
-        case missing_parameter:
-            msg = "required parameter is missing";
+            msg = "the abbreviated option '%canonical_option%' does not take any arguments";
             break;
         case extra_parameter:
-            msg = "extra parameter";
-            break;
-        case unrecognized_line:
-            msg = "unrecognized line";
+            msg = "option '%canonical_option%' does not take any arguments";
             break;
         default:
-            msg = "unknown error";
+            msg = "unknown command line syntax error for '%s'";
         }
         return msg;
     }
 
-    invalid_syntax::kind_t 
-    invalid_syntax::kind() const
-    {
-        return m_kind;
-    }
-    
-    const string& 
-    invalid_syntax::tokens() const
-    {
-        return m_tokens;
-    }
-
-    invalid_command_line_syntax::
-    invalid_command_line_syntax(const string& tokens, kind_t kind)
-    : invalid_syntax(tokens, kind)
-    {}
 
 }}
 
@@ -156,15 +135,26 @@
         const char* error = 0;
         if (allow_some_long && 
             !(style & long_allow_adjacent) && !(style & long_allow_next))
-            error = "style disallows parameters for long options";
+            error = "boost::program_options misconfiguration: "
+                    "choose one or other of 'command_line_style::long_allow_next' "
+                    "(whitespace separated arguments) or "
+                    "'command_line_style::long_allow_adjacent' ('=' separated arguments) for "
+                    "long options.";
 
         if (!error && (style & allow_short) &&
             !(style & short_allow_adjacent) && !(style & short_allow_next))
-            error = "style disallows parameters for short options";
+            error = "boost::program_options misconfiguration: "
+                    "choose one or other of 'command_line_style::short_allow_next' "
+                    "(whitespace separated arguments) or "
+                    "'command_line_style::short_allow_adjacent' ('=' separated arguments) for "
+                    "short options.";
 
         if (!error && (style & allow_short) &&
             !(style & allow_dash_for_short) && !(style & allow_slash_for_short))
-            error = "style disallows all characters for short options";
+            error = "boost::program_options misconfiguration: "
+                    "choose one or other of 'command_line_style::allow_slash_for_short' "
+                    "(slashes) or 'command_line_style::allow_dash_for_short' (dashes) for "
+                    "short options.";
 
         if (error)
             boost::throw_exception(invalid_command_line_style(error));
@@ -192,6 +182,23 @@
         m_positional = &positional;
     }
 
+    int
+    cmdline::get_canonical_option_prefix()
+    {
+        if (m_style & allow_long)
+            return allow_long;
+
+        if (m_style & allow_long_disguise)
+            return allow_long_disguise;
+
+        if ((m_style & allow_short) && (m_style & allow_dash_for_short))
+            return allow_dash_for_short;
+
+        if ((m_style & allow_short) && (m_style & allow_slash_for_short))
+            return allow_slash_for_short;
+
+        return 0;
+    }
 
     vector<option>
     cmdline::run()
@@ -277,7 +284,7 @@
         }
 
         /* If an key option is followed by a positional option,
-           can can consume more tokens (e.g. it's multitoke option),
+           can can consume more tokens (e.g. it's multitoken option),
            give those tokens to it.  */
         vector<option> result2;
         for (unsigned i = 0; i < result.size(); ++i)
@@ -288,11 +295,21 @@
             if (opt.string_key.empty())
                 continue;
 
-            const option_description* xd = 
-                m_desc->find_nothrow(opt.string_key, 
-                                        is_style_active(allow_guessing),
-                                        is_style_active(long_case_insensitive),
-                                        is_style_active(short_case_insensitive));
+            const option_description* xd;
+            try
+            {
+                xd = m_desc->find_nothrow(opt.string_key, 
+                                            is_style_active(allow_guessing),
+                                            is_style_active(long_case_insensitive),
+                                            is_style_active(short_case_insensitive));
+            } 
+            catch(error_with_option_name& e)
+            {
+                // add context and rethrow
+                e.add_context(opt.string_key, opt.original_tokens[0], get_canonical_option_prefix());
+                throw;
+            }
+
             if (!xd)
                 continue;
 
@@ -383,92 +400,112 @@
         if (opt.string_key.empty())
             return;
 
-        // First check that the option is valid, and get its description.
-        const option_description* xd = m_desc->find_nothrow(opt.string_key, 
-                is_style_active(allow_guessing),
-                is_style_active(long_case_insensitive),
-                is_style_active(short_case_insensitive));
+        // 
+        // Be defensive:
+        // will have no original token if option created by handle_additional_parser()
+        std::string original_token_for_exceptions = opt.string_key;
+        if (opt.original_tokens.size())
+            original_token_for_exceptions = opt.original_tokens[0];
 
-        if (!xd)
+        try
         {
-            if (m_allow_unregistered) {
-                opt.unregistered = true;
-                return;
-            } else {
-                boost::throw_exception(unknown_option(opt.string_key));
-            }                
-        }
-        const option_description& d = *xd;
-
-        // Canonize the name
-        opt.string_key = d.key(opt.string_key);
-
-        // We check that the min/max number of tokens for the option
-        // agrees with the number of tokens we have. The 'adjacent_value'
-        // (the value in --foo=1) counts as a separate token, and if present
-        // must be consumed. The following tokens on the command line may be
-        // left unconsumed.
+            // First check that the option is valid, and get its description.
+            const option_description* xd = m_desc->find_nothrow(opt.string_key, 
+                    is_style_active(allow_guessing),
+                    is_style_active(long_case_insensitive),
+                    is_style_active(short_case_insensitive));
 
-        // We don't check if those tokens look like option, or not!
-
-        unsigned min_tokens = d.semantic()->min_tokens();
-        unsigned max_tokens = d.semantic()->max_tokens();
-        
-        unsigned present_tokens = opt.value.size() + other_tokens.size();
-        
-        if (present_tokens >= min_tokens)
-        {
-            if (!opt.value.empty() && max_tokens == 0) 
-            {
-                boost::throw_exception(invalid_command_line_syntax(opt.string_key,
-                                             invalid_command_line_syntax::extra_parameter));
-            }
-            
-            // If an option wants, at minimum, N tokens, we grab them there,
-            // when adding these tokens as values to current option we check
-            // if they look like options
-            if (opt.value.size() <= min_tokens) 
-            {
-                min_tokens -= opt.value.size();
-            }
-            else
+            if (!xd)
             {
-                min_tokens = 0;
+                if (m_allow_unregistered) {
+                    opt.unregistered = true;
+                    return;
+                } else {
+                    boost::throw_exception(unknown_option());
+                }                
             }
+            const option_description& d = *xd;
+
+            // Canonize the name
+            opt.string_key = d.key(opt.string_key);
+
+            // We check that the min/max number of tokens for the option
+            // agrees with the number of tokens we have. The 'adjacent_value'
+            // (the value in --foo=1) counts as a separate token, and if present
+            // must be consumed. The following tokens on the command line may be
+            // left unconsumed.
+
+            // We don't check if those tokens look like option, or not!
 
-            // Everything's OK, move the values to the result.            
-            for(;!other_tokens.empty() && min_tokens--; ) 
+            unsigned min_tokens = d.semantic()->min_tokens();
+            unsigned max_tokens = d.semantic()->max_tokens();
+            
+            unsigned present_tokens = opt.value.size() + other_tokens.size();
+            
+            if (present_tokens >= min_tokens)
             {
-                // check if extra parameter looks like a known option
-                // we use style parsers to check if it is syntactically an option, 
-                // additionally we check if an option_description exists
-                vector<option> followed_option;  
-                vector<string> next_token(1, other_tokens[0]);      
-                for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
+                if (!opt.value.empty() && max_tokens == 0) 
                 {
-                    followed_option = style_parsers[i](next_token);
+                    boost::throw_exception(
+                        invalid_command_line_syntax(invalid_command_line_syntax::extra_parameter));
                 }
-                if (!followed_option.empty()) 
+                
+                // If an option wants, at minimum, N tokens, we grab them there,
+                // when adding these tokens as values to current option we check
+                // if they look like options
+                if (opt.value.size() <= min_tokens) 
                 {
-                    const option_description* od = m_desc->find_nothrow(other_tokens[0], 
-                              is_style_active(allow_guessing),
-                              is_style_active(long_case_insensitive),
-                              is_style_active(short_case_insensitive));
-                    if (od) 
-                        boost::throw_exception(invalid_command_line_syntax(opt.string_key,
-                                                    invalid_command_line_syntax::missing_parameter));
+                    min_tokens -= opt.value.size();
+                }
+                else
+                {
+                    min_tokens = 0;
+                }
+
+                // Everything's OK, move the values to the result.            
+                for(;!other_tokens.empty() && min_tokens--; ) 
+                {
+                    // check if extra parameter looks like a known option
+                    // we use style parsers to check if it is syntactically an option, 
+                    // additionally we check if an option_description exists
+                    vector<option> followed_option;  
+                    vector<string> next_token(1, other_tokens[0]);      
+                    for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
+                    {
+                        followed_option = style_parsers[i](next_token);
+                    }
+                    if (!followed_option.empty()) 
+                    {
+                        original_token_for_exceptions = other_tokens[0];
+                        const option_description* od = m_desc->find_nothrow(other_tokens[0], 
+                                  is_style_active(allow_guessing),
+                                  is_style_active(long_case_insensitive),
+                                  is_style_active(short_case_insensitive));
+                        if (od) 
+                            boost::throw_exception(
+                                invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
+                    }
+                    opt.value.push_back(other_tokens[0]);
+                    opt.original_tokens.push_back(other_tokens[0]);
+                    other_tokens.erase(other_tokens.begin());
                 }
-                opt.value.push_back(other_tokens[0]);
-                opt.original_tokens.push_back(other_tokens[0]);
-                other_tokens.erase(other_tokens.begin());
             }
-        }
-        else
-        {
-            boost::throw_exception(invalid_command_line_syntax(opt.string_key,
-                                            invalid_command_line_syntax::missing_parameter)); 
+            else
+            {
+                boost::throw_exception(
+                            invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter)); 
 
+            }
+        } 
+        // use only original token for unknown_option / ambiguous_option since by definition
+        //    they are unrecognised / unparsable
+        catch(error_with_option_name& e)
+        {
+            // add context and rethrow
+            e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
+            throw;
         }
+
     }
 
     vector<option> 
@@ -486,8 +523,11 @@
                 name = tok.substr(2, p-2);
                 adjacent = tok.substr(p+1);
                 if (adjacent.empty())
-                    boost::throw_exception( invalid_command_line_syntax(name,
-                                                      invalid_command_line_syntax::empty_adjacent_parameter) );
+                    boost::throw_exception( invalid_command_line_syntax(
+                                                      invalid_command_line_syntax::empty_adjacent_parameter, 
+                                                      name,
+                                                      name,
+                                                      get_canonical_option_prefix()) );
             }
             else
             {
@@ -523,9 +563,20 @@
             // of token is considered to be value, not further grouped
             // option.
             for(;;) {
-                const option_description* d 
-                    = m_desc->find_nothrow(name, false, false,
-                            is_style_active(short_case_insensitive));
+                const option_description* d;
+                try
+                {
+                     
+                    d = m_desc->find_nothrow(name, false, false,
+                                                is_style_active(short_case_insensitive));
+                } 
+                catch(error_with_option_name& e)
+                {
+                    // add context and rethrow
+                    e.add_context(name, name, get_canonical_option_prefix());
+                    throw;
+                }
+
 
                 // FIXME: check for 'allow_sticky'.
                 if (d && (m_style & allow_sticky) &&
@@ -589,15 +640,24 @@
             ((tok[0] == '-' && tok[1] != '-') ||
              ((m_style & allow_slash_for_short) && tok[0] == '/')))            
         {
-            if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1), 
-                                     is_style_active(allow_guessing),
-                                     is_style_active(long_case_insensitive),
-                                     is_style_active(short_case_insensitive)))
-            {
-                args[0].insert(0, "-");
-                if (args[0][1] == '/')
-                    args[0][1] = '-';
-                return parse_long_option(args);
+            try
+            {
+                if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1), 
+                                         is_style_active(allow_guessing),
+                                         is_style_active(long_case_insensitive),
+                                         is_style_active(short_case_insensitive)))
+                {
+                    args[0].insert(0, "-");
+                    if (args[0][1] == '/')
+                        args[0][1] = '-';
+                    return parse_long_option(args);
+                }
+            } 
+            catch(error_with_option_name& e)
+            {
+                // add context and rethrow
+                e.add_context(tok, tok, get_canonical_option_prefix());
+                throw;
             }
         }
         return vector<option>();
Modified: branches/release/libs/program_options/src/config_file.cpp
==============================================================================
--- branches/release/libs/program_options/src/config_file.cpp	(original)
+++ branches/release/libs/program_options/src/config_file.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -57,7 +57,9 @@
                     bad_prefixes = true;
             }
             if (bad_prefixes)
-                boost::throw_exception(error("bad prefixes"));
+                boost::throw_exception(error("options '" + string(name) + "' and '" +
+                                             *i + "*' will both match the same "
+                                             "arguments from the configuration file"));
             allowed_prefixes.insert(s);
         }
     }
@@ -117,7 +119,7 @@
                     break;
 
                 } else {
-                    boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
+                    boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
                 }
             }
         }
Modified: branches/release/libs/program_options/src/options_description.cpp
==============================================================================
--- branches/release/libs/program_options/src/options_description.cpp	(original)
+++ branches/release/libs/program_options/src/options_description.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -137,6 +137,31 @@
             return m_short_name;
     }
 
+    std::string 
+    option_description::canonical_display_name(int prefix_style) const
+    {
+        if (!m_long_name.empty()) 
+        {
+            if (prefix_style == command_line_style::allow_long)
+                return "--" + m_long_name;
+            if (prefix_style == command_line_style::allow_long_disguise)
+                return "-" + m_long_name;
+        }
+		// sanity check: m_short_name[0] should be '-' or '/'
+        if (m_short_name.length() == 2)
+        {
+            if (prefix_style == command_line_style::allow_slash_for_short)
+                return string("/") + m_short_name[1];
+            if (prefix_style == command_line_style::allow_dash_for_short)
+                return string("-") + m_short_name[1];
+        }
+        if (!m_long_name.empty()) 
+            return m_long_name;
+        else
+            return m_short_name;
+    }
+
+
     const std::string&
     option_description::long_name() const
     {
@@ -174,10 +199,13 @@
     option_description::format_name() const
     {
         if (!m_short_name.empty())
-            return string(m_short_name).append(" [ --").
-            append(m_long_name).append(" ]");
-        else
-            return string("--").append(m_long_name);
+        {
+            return m_long_name.empty() 
+                ? m_short_name 
+                : string(m_short_name).append(" [ --").
+                  append(m_long_name).append(" ]");
+        }
+        return string("--").append(m_long_name);
     }
 
     std::string 
@@ -289,7 +317,7 @@
         const option_description* d = find_nothrow(name, approx, 
                                        long_ignore_case, short_ignore_case);
         if (!d)
-            boost::throw_exception(unknown_option(name));
+            boost::throw_exception(unknown_option());
         return *d;
     }
 
@@ -337,8 +365,7 @@
             }
         }
         if (full_matches.size() > 1) 
-            boost::throw_exception(
-                ambiguous_option(name, full_matches));
+            boost::throw_exception(ambiguous_option(full_matches));
         
         // If we have a full match, and an approximate match,
         // ignore approximate match instead of reporting error.
@@ -346,8 +373,7 @@
         // "--all" on the command line should select the first one,
         // without ambiguity.
         if (full_matches.empty() && approximate_matches.size() > 1)
-            boost::throw_exception(
-                ambiguous_option(name, approximate_matches));
+            boost::throw_exception(ambiguous_option(approximate_matches));
 
         return found.get();
     }
@@ -396,7 +422,7 @@
                 if (count(par.begin(), par.end(), '\t') > 1)
                 {
                     boost::throw_exception(program_options::error(
-                        "Only one tab per paragraph is allowed"));
+                        "Only one tab per paragraph is allowed in the options description"));
                 }
           
                 // erase tab from string
Modified: branches/release/libs/program_options/src/parsers.cpp
==============================================================================
--- branches/release/libs/program_options/src/parsers.cpp	(original)
+++ branches/release/libs/program_options/src/parsers.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -45,7 +45,10 @@
 // See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
 // See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
 #if defined(__APPLE__) && defined(__DYNAMIC__)
-#include <crt_externs.h>
+// The proper include for this is crt_externs.h, however it's not
+// available on iOS. The right replacement is not known. See
+// https://svn.boost.org/trac/boost/ticket/5053
+extern "C" { extern char ***_NSGetEnviron(void); }
 #define environ (*_NSGetEnviron()) 
 #else
 #if defined(__MWERKS__)
@@ -85,7 +88,8 @@
     basic_parsed_options<wchar_t>
     ::basic_parsed_options(const parsed_options& po)
     : description(po.description),
-      utf8_encoded_options(po)
+      utf8_encoded_options(po),
+      m_options_prefix(po.m_options_prefix)
     {
         for (unsigned i = 0; i < po.options.size(); ++i)
             options.push_back(woption_from_option(po.options[i]));
@@ -107,7 +111,7 @@
 
             if (d.long_name().empty())
                 boost::throw_exception(
-                    error("long name required for config file"));
+                    error("abbreviated option names are not permitted in options configuration files"));
 
             allowed_options.insert(d.long_name());
         }
Modified: branches/release/libs/program_options/src/value_semantic.cpp
==============================================================================
--- branches/release/libs/program_options/src/value_semantic.cpp	(original)
+++ branches/release/libs/program_options/src/value_semantic.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -7,6 +7,8 @@
 #include <boost/program_options/config.hpp>
 #include <boost/program_options/value_semantic.hpp>
 #include <boost/program_options/detail/convert.hpp>
+#include <boost/program_options/detail/cmdline.hpp>
+#include <set>
 
 #include <cctype>
 
@@ -14,6 +16,22 @@
 
     using namespace std;
 
+
+#ifndef BOOST_NO_STD_WSTRING
+    namespace
+    {
+        std::string convert_value(const std::wstring& s)
+        {
+            try {
+                return to_local_8_bit(s);
+            }
+            catch(const std::exception&) {
+                return "<unrepresentable unicode string>";
+            }
+        }
+    }
+#endif
+
     void 
     value_semantic_codecvt_helper<char>::
     parse(boost::any& value_store, 
@@ -139,7 +157,7 @@
         else if (s == "off" || s == "no" || s == "0" || s == "false")
             v = any(false);
         else
-            boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
+            boost::throw_exception(invalid_bool_value(s));
     }
 
     // This is blatant copy-paste. However, templating this will cause a problem,
@@ -161,7 +179,7 @@
         else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
             v = any(false);
         else
-            boost::throw_exception(validation_error(validation_error::invalid_bool_value));
+            boost::throw_exception(invalid_bool_value(convert_value(s)));
     }
 #endif
     BOOST_PROGRAM_OPTIONS_DECL 
@@ -194,120 +212,212 @@
 
     invalid_option_value::
     invalid_option_value(const std::string& bad_value)
-    : validation_error(validation_error::invalid_option_value, bad_value)
-    {}
-
-#ifndef BOOST_NO_STD_WSTRING
-    namespace
+    : validation_error(validation_error::invalid_option_value)
     {
-        std::string convert_value(const std::wstring& s)
-        {
-            try {
-                return to_local_8_bit(s);
-            }
-            catch(const std::exception&) {
-                return "<unrepresentable unicode string>";
-            }
-        }
+        set_substitute("value", bad_value);
     }
 
+#ifndef BOOST_NO_STD_WSTRING
     invalid_option_value::
     invalid_option_value(const std::wstring& bad_value)
-    : validation_error(validation_error::invalid_option_value, convert_value(bad_value))
-    {}
+    : validation_error(validation_error::invalid_option_value)
+    {
+        set_substitute("value", convert_value(bad_value));
+    }
 #endif
-    const std::string& 
-    unknown_option::get_option_name() const throw()
-    { 
-        return m_option_name; 
-    }
-
-    const std::string& 
-    ambiguous_option::get_option_name() const throw()
-    { 
-        return m_option_name; 
-    }
- 
-    const std::vector<std::string>& 
-    ambiguous_option::alternatives() const throw()
+
+
+
+    invalid_bool_value::
+    invalid_bool_value(const std::string& bad_value)
+    : validation_error(validation_error::invalid_bool_value)
     {
-        return m_alternatives;
+        set_substitute("value", bad_value);
     }
 
-    void 
-    multiple_values::set_option_name(const std::string& option_name)
+
+
+
+
+
+    error_with_option_name::error_with_option_name( const std::string& template_,
+                                                  const std::string& option_name,
+                                                  const std::string& original_token,
+                                                  int option_style) : 
+                                        error(template_),
+                                        m_option_style(option_style),
+                                        m_error_template(template_)
     {
-        m_option_name = option_name;
+        //                     parameter            |     placeholder               |   value
+        //                     ---------            |     -----------               |   -----
+        set_substitute_default("canonical_option",  "option '%canonical_option%'",  "option");
+        set_substitute_default("value",             "argument ('%value%')",         "argument");
+        set_substitute_default("prefix",            "%prefix%",                     "");
+        m_substitutions["option"] = option_name;
+        m_substitutions["original_token"] = original_token;
     }
 
-    const std::string& 
-    multiple_values::get_option_name() const throw()
+
+    const char* error_with_option_name::what() const throw()
     {
-        return m_option_name;
+        // will substitute tokens each time what is run()
+        substitute_placeholders(m_error_template);
+
+        return m_message.c_str();
     }
-    
-    void 
-    multiple_occurrences::set_option_name(const std::string& option_name)
+
+    void error_with_option_name::replace_token(const string& from, const string& to) const
     {
-        m_option_name = option_name;
+        while (1)
+        {
+            std::size_t pos = m_message.find(from.c_str(), 0, from.length());
+            // not found: all replaced
+            if (pos == std::string::npos)
+                return;
+            m_message.replace(pos, from.length(), to);
+        }
     }
 
-    const std::string& 
-    multiple_occurrences::get_option_name() const throw()
+    string error_with_option_name::get_canonical_option_prefix() const
     {
-        return m_option_name;
-    }
-        
-    validation_error::    
-    validation_error(kind_t kind, 
-                     const std::string& option_value, 
-                     const std::string& option_name)
-     : error("")
-     , m_kind(kind) 
-     , m_option_name(option_name)
-     , m_option_value(option_value)
-     , m_message(error_message(kind))
-    {
-       if (!option_value.empty())
-       {
-          m_message.append(std::string("'") + option_value + std::string("'"));
-       }
+        switch (m_option_style)
+        {
+        case command_line_style::allow_dash_for_short:
+            return "-";
+        case command_line_style::allow_slash_for_short:
+            return "/";
+        case command_line_style::allow_long_disguise:
+            return "-";
+        case command_line_style::allow_long:
+            return "--";
+        case 0:
+            return "";
+        }
+        throw std::logic_error("error_with_option_name::m_option_style can only be "
+                               "one of [0, allow_dash_for_short, allow_slash_for_short, "
+                               "allow_long_disguise or allow_long]");
     }
 
-    void 
-    validation_error::set_option_name(const std::string& option_name)
+
+    string error_with_option_name::get_canonical_option_name() const
     {
-        m_option_name = option_name;
+        if (!m_substitutions.find("option")->second.length())
+            return m_substitutions.find("original_token")->second;
+
+        string original_token   = strip_prefixes(m_substitutions.find("original_token")->second);
+        string option_name      = strip_prefixes(m_substitutions.find("option")->second);
+
+        //  For long options, use option name
+        if (m_option_style == command_line_style::allow_long        || 
+             m_option_style == command_line_style::allow_long_disguise)
+            return get_canonical_option_prefix() + option_name;
+
+        //  For short options use first letter of original_token
+        if (m_option_style && original_token.length())
+            return get_canonical_option_prefix() + original_token[0];
+
+        // no prefix
+        return option_name;
     }
 
-    const std::string& 
-    validation_error::get_option_name() const throw()
+
+    void error_with_option_name::substitute_placeholders(const string& error_template) const
     {
-        return m_option_name;
+        m_message = error_template;
+        std::map<std::string, std::string> substitutions(m_substitutions);
+        substitutions["canonical_option"]   = get_canonical_option_name();
+        substitutions["prefix"]             = get_canonical_option_prefix();
+
+
+        //
+        //  replace placeholder with defaults if values are missing 
+        // 
+        for (map<string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
+              iter != m_substitution_defaults.end(); ++iter)
+        {
+            // missing parameter: use default
+            if (substitutions.count(iter->first) == 0 ||
+                substitutions[iter->first].length() == 0)
+                replace_token(iter->second.first, iter->second.second);
+        }
+
+
+        //
+        //  replace placeholder with values
+        //  placeholder are denoted by surrounding '%'
+        // 
+        for (map<string, string>::iterator iter = substitutions.begin();
+              iter != substitutions.end(); ++iter)
+            replace_token('%' + iter->first + '%', iter->second);
     }
 
-    std::string 
-    validation_error::error_message(kind_t kind)
+
+    void ambiguous_option::substitute_placeholders(const string& original_error_template) const
+    {
+        // For short forms, all alternatives must be identical, by
+        //      definition, to the specified option, so we don't need to
+        //      display alternatives
+        if (m_option_style == command_line_style::allow_dash_for_short || 
+            m_option_style == command_line_style::allow_slash_for_short)
+        {
+            error_with_option_name::substitute_placeholders(original_error_template);
+            return;
+        }
+
+
+        string error_template  = original_error_template;
+        // remove duplicates using std::set
+        std::set<std::string>   alternatives_set (m_alternatives.begin(), m_alternatives.end());
+        std::vector<std::string> alternatives_vec (alternatives_set.begin(), alternatives_set.end());
+
+        error_template += " and matches ";
+        // Being very cautious: should be > 1 alternative!
+        if (alternatives_vec.size() > 1)
+        {
+            for (unsigned i = 0; i < alternatives_vec.size() - 1; ++i)
+                error_template += "'%prefix%" + alternatives_vec[i] + "', ";
+            error_template += "and ";
+        }
+
+        // there is a programming error if multiple options have the same name...
+        if (m_alternatives.size() > 1 && alternatives_vec.size() == 1)
+            error_template += "different versions of ";
+
+        error_template += "'%prefix%" + alternatives_vec.back() + "'";
+
+
+        // use inherited logic
+        error_with_option_name::substitute_placeholders(error_template);
+    }
+
+
+
+
+
+
+    string 
+    validation_error::get_template(kind_t kind)
     {
         // Initially, store the message in 'const char*' variable,
         // to avoid conversion to std::string in all cases.
         const char* msg;
         switch(kind)
         {
-        case multiple_values_not_allowed:
-            msg = "multiple values not allowed";
-            break;
-        case at_least_one_value_required:
-            msg = "at least one value required";
-            break;
         case invalid_bool_value:
-            msg = "invalid bool value";
+            msg = "the argument ('%value%') for option '%canonical_option%' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'";
             break;
         case invalid_option_value:
-            msg = "invalid option value";
+            msg = "the argument ('%value%') for option '%canonical_option%' is invalid";
+            break;
+        case multiple_values_not_allowed:
+            msg = "option '%canonical_option%' only takes a single argument";
+            break;
+        case at_least_one_value_required:
+            msg = "option '%canonical_option%' requires at least one argument";
             break;
+        // currently unused
         case invalid_option:
-            msg = "invalid option";
+            msg = "option '%canonical_option%' is not valid";
             break;
         default:
             msg = "unknown error";
@@ -315,21 +425,4 @@
         return msg;
     }
 
-    const char* 
-    validation_error::what() const throw()
-    {
-        if (!m_option_name.empty())
-        {
-            m_message = "in option '" + m_option_name + "': " 
-                + error_message(m_kind);
-        }
-        return m_message.c_str();
-    }
-    
-    const std::string& 
-    required_option::get_option_name() const throw()
-    {
-        return m_option_name;
-    }
-
 }}
Modified: branches/release/libs/program_options/src/variables_map.cpp
==============================================================================
--- branches/release/libs/program_options/src/variables_map.cpp	(original)
+++ branches/release/libs/program_options/src/variables_map.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -38,65 +38,68 @@
         // Declared once, to please Intel in VC++ mode;
         unsigned i;
 
-        // First, convert/store all given options
-        for (i = 0; i < options.options.size(); ++i) {
+        // Declared here so can be used to provide context for exceptions
+        string option_name;
+        string original_token;
 
-            const string& name = options.options[i].string_key;
-            // Skip positional options without name
-            if (name.empty())
-                continue;
-
-            // Ignore unregistered option. The 'unregistered'
-            // field can be true only if user has explicitly asked
-            // to allow unregistered options. We can't store them
-            // to variables map (lacking any information about paring), 
-            // so just ignore them.
-            if (options.options[i].unregistered)
-                continue;
-
-            // If option has final value, skip this assignment
-            if (xm.m_final.count(name))
-                continue;
+        try
+        {
 
-            const option_description& d = desc.find(name, false, 
-                                                      false, false);
+            // First, convert/store all given options
+            for (i = 0; i < options.options.size(); ++i) {
 
-            variable_value& v = m[name];            
-            if (v.defaulted()) {
-                // Explicit assignment here erases defaulted value
-                v = variable_value();
-            }
-            
-            try {
+                option_name = options.options[i].string_key;
+                original_token = options.options[i].original_tokens.size() ? 
+                                options.options[i].original_tokens[0] :
+                                option_name;
+                // Skip positional options without name
+                if (option_name.empty())
+                    continue;
+
+                // Ignore unregistered option. The 'unregistered'
+                // field can be true only if user has explicitly asked
+                // to allow unregistered options. We can't store them
+                // to variables map (lacking any information about paring), 
+                // so just ignore them.
+                if (options.options[i].unregistered)
+                    continue;
+
+                // If option has final value, skip this assignment
+                if (xm.m_final.count(option_name))
+                    continue;
+
+                string original_token = options.options[i].original_tokens.size() ? 
+                                        options.options[i].original_tokens[0]     : "";
+                const option_description& d = desc.find(option_name, false, 
+                                                        false, false);
+
+                variable_value& v = m[option_name];            
+                if (v.defaulted()) {
+                    // Explicit assignment here erases defaulted value
+                    v = variable_value();
+                }
+                
                 d.semantic()->parse(v.value(), options.options[i].value, utf8);
+
+                v.m_value_semantic = d.semantic();
+                
+                // The option is not composing, and the value is explicitly
+                // provided. Ignore values of this option for subsequent
+                // calls to 'store'. We store this to a temporary set,
+                // so that several assignment inside *this* 'store' call
+                // are allowed.
+                if (!d.semantic()->is_composing())
+                    new_final.insert(option_name);
             }
+        } 
 #ifndef BOOST_NO_EXCEPTIONS
-            catch(validation_error& e)
-            {
-                e.set_option_name(name);
-                throw;
-            }
-            catch(multiple_occurrences& e)
-            {
-                e.set_option_name(name);
-                throw;
-            }
-            catch(multiple_values& e) 
-            {
-                e.set_option_name(name);
-                throw;
-            }
-#endif
-            v.m_value_semantic = d.semantic();
-            
-            // The option is not composing, and the value is explicitly
-            // provided. Ignore values of this option for subsequent
-            // calls to 'store'. We store this to a temporary set,
-            // so that several assignment inside *this* 'store' call
-            // are allowed.
-            if (!d.semantic()->is_composing())
-                new_final.insert(name);
+        catch(error_with_option_name& e)
+        {
+            // add context and rethrow
+            e.add_context(option_name, original_token, options.m_options_prefix);
+            throw;
         }
+#endif
         xm.m_final.insert(new_final.begin(), new_final.end());
 
         
@@ -127,7 +130,14 @@
 
             // add empty value if this is an required option
             if (d.semantic()->is_required()) {
-               xm.m_required.insert(key);
+
+                // For option names specified in multiple ways, e.g. on the command line,
+                // config file etc, the following precedence rules apply:
+                //  "--"  >  ("-" or "/")  >  ""
+                //  Precedence is set conveniently by a single call to length()
+                string canonical_name = d.canonical_display_name(options.m_options_prefix);
+                if (canonical_name.length() > xm.m_required[key].length())
+                    xm.m_required[key] = canonical_name;
             }
         }
     }
@@ -182,6 +192,13 @@
     : abstract_variables_map(next)
     {}
 
+    void variables_map::clear()
+    {
+        std::map<std::string, variable_value>::clear();
+        m_final.clear();
+        m_required.clear();
+    }
+
     const variable_value&
     variables_map::get(const std::string& name) const
     {
@@ -197,15 +214,16 @@
     variables_map::notify()
     {
         // This checks if all required options occur
-        for (set<string>::const_iterator r = m_required.begin();
+        for (map<string, string>::const_iterator r = m_required.begin();
              r != m_required.end();
              ++r)
         {
-            const string& opt = *r;
+            const string& opt = r->first;
+            const string& display_opt = r->second;
             map<string, variable_value>::const_iterator iter = find(opt);
             if (iter == end() || iter->second.empty()) 
             {
-                boost::throw_exception(required_option(opt));
+                boost::throw_exception(required_option(display_opt));
             
             }
         }
Modified: branches/release/libs/program_options/test/cmdline_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/cmdline_test.cpp	(original)
+++ branches/release/libs/program_options/test/cmdline_test.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -378,6 +378,15 @@
         {0, 0, 0}
     };
     test_cmdline("opt123 opt56 foo,f=", style, test_cases1);
+
+    test_case test_cases2[] = { 
+        {"--fname file --fname2 file2", s_success, "fname: file fname2: file2"},
+        {"--fnam file --fnam file2", s_ambiguous_option, ""},
+        {"--fnam file --fname2 file2", s_ambiguous_option, ""},
+        {"--fname2 file2 --fnam file", s_ambiguous_option, ""},
+        {0, 0, 0} 
+    };
+    test_cmdline("fname fname2", style, test_cases2);
 }
 
 void test_arguments()
Modified: branches/release/libs/program_options/test/exception_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/exception_test.cpp	(original)
+++ branches/release/libs/program_options/test/exception_test.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -63,7 +63,7 @@
    catch (unknown_option& e)
    {
       BOOST_CHECK_EQUAL(e.get_option_name(), "-f");      
-      BOOST_CHECK_EQUAL(string(e.what()), "unknown option -f");
+      BOOST_CHECK_EQUAL(string(e.what()), "unrecognised option '-f'");
    }
 }
 
@@ -94,8 +94,8 @@
       //   because: untyped_value always has one value and this is filtered before reach specific
       //   validation and parsing
       //
-      BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");      
-      BOOST_CHECK_EQUAL(string(e.what()), "in option 'cfgfile': multiple values not allowed");
+      BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");      
+      BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
    }
 }
 
@@ -118,8 +118,8 @@
    }
    catch (multiple_occurrences& e)
    {
-      BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");      
-      BOOST_CHECK_EQUAL(string(e.what()), "multiple occurrences");
+      BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");      
+      BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
    }
 }
 
@@ -145,7 +145,7 @@
    catch (invalid_command_line_syntax& e)
    {
       BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
-      BOOST_CHECK_EQUAL(e.tokens(), "cfgfile");
+      BOOST_CHECK_EQUAL(e.tokens(), "--cfgfile");
    }
 }
 
Modified: branches/release/libs/program_options/test/program_options_size_test.py
==============================================================================
--- branches/release/libs/program_options/test/program_options_size_test.py	(original)
+++ branches/release/libs/program_options/test/program_options_size_test.py	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -21,7 +21,7 @@
       f.write("(\"opt%d\", value<int>())\n")
    f.write(";\n}\n")   
    f.close()
-   os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/boost-rc program_options_test.cpp")
+   os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/Boost/boost-svn program_options_test.cpp")
 
    nm = os.popen("nm -S program_options_test.o")
    for l in nm:
@@ -45,7 +45,7 @@
    print "Avarage: ", (last_size-first_size)/(range[-1]-range[0])
 
 if __name__ == '__main__':
-   for compiler in [ "g++-3.3 -Os", "g++-3.3 -O3", "g++-3.4 -Os", "g++-3.4 -O3"]:
+   for compiler in [ "g++ -Os", "g++ -O3"]:
       print "****", compiler, "****"
       run_tests(range(1, 20), compiler)
 
Modified: branches/release/libs/program_options/test/required_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/required_test.cpp	(original)
+++ branches/release/libs/program_options/test/required_test.cpp	2012-04-08 06:02:26 EDT (Sun, 08 Apr 2012)
@@ -34,6 +34,7 @@
          notify(vm);    
       } 
       catch (required_option& e) {
+         BOOST_CHECK_EQUAL(e.what(), string("the option '--cfgfile' is required but missing"));
          throwed = true;
       }      
       BOOST_CHECK(throwed);