changes (part 1) from 1.4.3 branch (XMLConfiguration delimiter, OptionProcessor)

This commit is contained in:
Marian Krivos
2011-11-15 13:59:05 +00:00
parent 97ec3f5bf6
commit cc90b38ae5
6 changed files with 245 additions and 119 deletions

View File

@@ -58,7 +58,7 @@ class Util_API OptionProcessor
/// The process() method takes an argument from the command line. /// The process() method takes an argument from the command line.
/// If that argument starts with an option prefix, the argument /// If that argument starts with an option prefix, the argument
/// is further processed. Otherwise, the argument is ignored and /// is further processed. Otherwise, the argument is ignored and
/// false is ignored. The argument must match one of the options /// false is returned. The argument must match one of the options
/// given in the OptionSet that is passed to the OptionProcessor /// given in the OptionSet that is passed to the OptionProcessor
/// with the constructor. If an option is part of a group, at most /// with the constructor. If an option is part of a group, at most
/// one option of the group can be passed to the OptionProcessor. /// one option of the group can be passed to the OptionProcessor.
@@ -82,6 +82,16 @@ class Util_API OptionProcessor
/// a (partial) long option name. /// a (partial) long option name.
/// If the special option '--' is encountered in Unix mode, all following /// If the special option '--' is encountered in Unix mode, all following
/// options are ignored. /// options are ignored.
///
/// Option arguments can be specified in three ways. If a Unix short option
/// ("-o") is given, the argument directly follows the option name, without
/// any delimiting character or space ("-ovalue"). In default option mode, or if a
/// Unix long option ("--option") is given, the option argument is
/// delimited from the option name with either an equal sign ('=') or
/// a colon (':'), as in "--option=value" or "/option:value". Finally,
/// a required option argument can be specified on the command line after the
/// option, delimited with a space, as in "--option value" or "-o value".
/// The latter only works for required option arguments, not optional ones.
{ {
public: public:
OptionProcessor(const OptionSet& options); OptionProcessor(const OptionSet& options);
@@ -130,6 +140,7 @@ private:
bool _ignore; bool _ignore;
std::set<std::string> _groups; std::set<std::string> _groups;
std::set<std::string> _specifiedOptions; std::set<std::string> _specifiedOptions;
std::string _deferredOption;
}; };

View File

@@ -89,29 +89,62 @@ class Util_API XMLConfiguration: public AbstractConfiguration
/// ///
/// Enumerating attributes is not supported. /// Enumerating attributes is not supported.
/// Calling keys("prop3.prop4") will return an empty range. /// Calling keys("prop3.prop4") will return an empty range.
///
/// As a special feature, the delimiter character used to delimit
/// property names can be changed to something other than period ('.') by
/// passing the desired character to the constructor. This allows
/// working with XML documents having element names with periods
/// in them.
{ {
public: public:
XMLConfiguration(); XMLConfiguration();
/// Creates an empty XMLConfiguration. /// Creates an empty XMLConfiguration.
XMLConfiguration(char delim);
/// Creates an empty XMLConfiguration, using the given
/// delimiter char instead of the default '.'.
XMLConfiguration(Poco::XML::InputSource* pInputSource); XMLConfiguration(Poco::XML::InputSource* pInputSource);
/// Creates an XMLConfiguration and loads the XML document from /// Creates an XMLConfiguration and loads the XML document from
/// the given InputSource. /// the given InputSource.
XMLConfiguration(Poco::XML::InputSource* pInputSource, char delim);
/// Creates an XMLConfiguration and loads the XML document from
/// the given InputSource. Uses the given delimiter char instead
/// of the default '.'.
XMLConfiguration(std::istream& istr); XMLConfiguration(std::istream& istr);
/// Creates an XMLConfiguration and loads the XML document from /// Creates an XMLConfiguration and loads the XML document from
/// the given stream. /// the given stream.
XMLConfiguration(std::istream& istr, char delim);
/// Creates an XMLConfiguration and loads the XML document from
/// the given stream. Uses the given delimiter char instead
/// of the default '.'.
XMLConfiguration(const std::string& path); XMLConfiguration(const std::string& path);
/// Creates an XMLConfiguration and loads the XML document from /// Creates an XMLConfiguration and loads the XML document from
/// the given path. /// the given path.
XMLConfiguration(const std::string& path, char delim);
/// Creates an XMLConfiguration and loads the XML document from
/// the given path. Uses the given delimiter char instead
/// of the default '.'.
XMLConfiguration(const Poco::XML::Document* pDocument); XMLConfiguration(const Poco::XML::Document* pDocument);
/// Creates the XMLConfiguration using the given XML document. /// Creates the XMLConfiguration using the given XML document.
XMLConfiguration(const Poco::XML::Document* pDocument, char delim);
/// Creates the XMLConfiguration using the given XML document.
/// Uses the given delimiter char instead of the default '.'.
XMLConfiguration(const Poco::XML::Node* pNode); XMLConfiguration(const Poco::XML::Node* pNode);
/// Creates the XMLConfiguration using the given XML node. /// Creates the XMLConfiguration using the given XML node.
XMLConfiguration(const Poco::XML::Node* pNode, char delim);
/// Creates the XMLConfiguration using the given XML node.
/// Uses the given delimiter char instead of the default '.'.
void load(Poco::XML::InputSource* pInputSource); void load(Poco::XML::InputSource* pInputSource);
/// Loads the XML document containing the configuration data /// Loads the XML document containing the configuration data
/// from the given InputSource. /// from the given InputSource.
@@ -166,7 +199,7 @@ protected:
private: private:
const Poco::XML::Node* findNode(const std::string& key) const; const Poco::XML::Node* findNode(const std::string& key) const;
Poco::XML::Node* findNode(const std::string& key); Poco::XML::Node* findNode(const std::string& key);
static Poco::XML::Node* findNode(std::string::const_iterator& it, const std::string::const_iterator& end, Poco::XML::Node* pNode, bool create = false); Poco::XML::Node* findNode(std::string::const_iterator& it, const std::string::const_iterator& end, Poco::XML::Node* pNode, bool create = false) const;
static Poco::XML::Node* findElement(const std::string& name, Poco::XML::Node* pNode, bool create); static Poco::XML::Node* findElement(const std::string& name, Poco::XML::Node* pNode, bool create);
static Poco::XML::Node* findElement(int index, Poco::XML::Node* pNode, bool create); static Poco::XML::Node* findElement(int index, Poco::XML::Node* pNode, bool create);
static Poco::XML::Node* findElement(const std::string& attr, const std::string& value, Poco::XML::Node* pNode); static Poco::XML::Node* findElement(const std::string& attr, const std::string& value, Poco::XML::Node* pNode);
@@ -174,6 +207,7 @@ private:
Poco::XML::AutoPtr<Poco::XML::Node> _pRoot; Poco::XML::AutoPtr<Poco::XML::Node> _pRoot;
Poco::XML::AutoPtr<Poco::XML::Document> _pDocument; Poco::XML::AutoPtr<Poco::XML::Document> _pDocument;
char _delim;
}; };

View File

@@ -371,7 +371,7 @@ void Application::processOptions()
std::string value; std::string value;
if (processor.process(*it, name, value)) if (processor.process(*it, name, value))
{ {
if (!name.empty()) // "--" option to end options processing if (!name.empty()) // "--" option to end options processing or deferred argument
{ {
handleOption(name, value); handleOption(name, value);
} }

View File

@@ -176,7 +176,15 @@ void HelpFormatter::formatOptions(std::ostream& ostr) const
for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it) for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
{ {
formatOption(ostr, *it, optWidth); formatOption(ostr, *it, optWidth);
if (_indent < optWidth)
{
ostr << '\n' << std::string(_indent, ' ');
formatText(ostr, it->description(), _indent, _indent);
}
else
{
formatText(ostr, it->description(), _indent, optWidth); formatText(ostr, it->description(), _indent, optWidth);
}
ostr << '\n'; ostr << '\n';
} }
} }

View File

@@ -65,9 +65,13 @@ void OptionProcessor::setUnixStyle(bool flag)
bool OptionProcessor::process(const std::string& argument, std::string& optionName, std::string& optionArg) bool OptionProcessor::process(const std::string& argument, std::string& optionName, std::string& optionArg)
{ {
optionName.clear();
optionArg.clear();
if (!_ignore) if (!_ignore)
{ {
if (_unixStyle) if (!_deferredOption.empty())
return processCommon(argument, false, optionName, optionArg);
else if (_unixStyle)
return processUnix(argument, optionName, optionArg); return processUnix(argument, optionName, optionArg);
else else
return processDefault(argument, optionName, optionArg); return processDefault(argument, optionName, optionArg);
@@ -83,6 +87,12 @@ void OptionProcessor::checkRequired() const
if (it->required() && _specifiedOptions.find(it->fullName()) == _specifiedOptions.end()) if (it->required() && _specifiedOptions.find(it->fullName()) == _specifiedOptions.end())
throw MissingOptionException(it->fullName()); throw MissingOptionException(it->fullName());
} }
if (!_deferredOption.empty())
{
std::string optionArg;
const Option& option = _options.getOption(_deferredOption, false);
option.process(_deferredOption, optionArg); // will throw MissingArgumentException
}
} }
@@ -133,6 +143,17 @@ bool OptionProcessor::processDefault(const std::string& argument, std::string& o
bool OptionProcessor::processCommon(const std::string& optionStr, bool isShort, std::string& optionName, std::string& optionArg) bool OptionProcessor::processCommon(const std::string& optionStr, bool isShort, std::string& optionName, std::string& optionArg)
{ {
if (!_deferredOption.empty())
{
const Option& option = _options.getOption(_deferredOption, false);
std::string optionWithArg(_deferredOption);
_deferredOption.clear();
optionWithArg += '=';
optionWithArg += optionStr;
option.process(optionWithArg, optionArg);
optionName = option.fullName();
return true;
}
if (optionStr.empty()) throw EmptyOptionException(); if (optionStr.empty()) throw EmptyOptionException();
const Option& option = _options.getOption(optionStr, isShort); const Option& option = _options.getOption(optionStr, isShort);
const std::string& group = option.group(); const std::string& group = option.group();
@@ -146,6 +167,11 @@ bool OptionProcessor::processCommon(const std::string& optionStr, bool isShort,
if (_specifiedOptions.find(option.fullName()) != _specifiedOptions.end() && !option.repeatable()) if (_specifiedOptions.find(option.fullName()) != _specifiedOptions.end() && !option.repeatable())
throw DuplicateOptionException(option.fullName()); throw DuplicateOptionException(option.fullName());
_specifiedOptions.insert(option.fullName()); _specifiedOptions.insert(option.fullName());
if (option.argumentRequired() && ((!isShort && optionStr.find_first_of(":=") == std::string::npos) || (isShort && optionStr.length() == option.shortName().length())))
{
_deferredOption = option.fullName();
return true;
}
option.process(optionStr, optionArg); option.process(optionStr, optionArg);
optionName = option.fullName(); optionName = option.fullName();
return true; return true;

View File

@@ -51,36 +51,83 @@ namespace Poco {
namespace Util { namespace Util {
XMLConfiguration::XMLConfiguration() XMLConfiguration::XMLConfiguration():
_delim('.')
{ {
} }
XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource) XMLConfiguration::XMLConfiguration(char delim):
_delim(delim)
{
}
XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource):
_delim('.')
{ {
load(pInputSource); load(pInputSource);
} }
XMLConfiguration::XMLConfiguration(std::istream& istr) XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource, char delim):
_delim(delim)
{
load(pInputSource);
}
XMLConfiguration::XMLConfiguration(std::istream& istr):
_delim('.')
{ {
load(istr); load(istr);
} }
XMLConfiguration::XMLConfiguration(const std::string& path) XMLConfiguration::XMLConfiguration(std::istream& istr, char delim):
_delim(delim)
{
load(istr);
}
XMLConfiguration::XMLConfiguration(const std::string& path):
_delim('.')
{ {
load(path); load(path);
} }
XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument) XMLConfiguration::XMLConfiguration(const std::string& path, char delim):
_delim(delim)
{
load(path);
}
XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument):
_delim('.')
{ {
load(pDocument); load(pDocument);
} }
XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode) XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument, char delim):
_delim(delim)
{
load(pDocument);
}
XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode):
_delim('.')
{
load(pNode);
}
XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode, char delim):
_delim(delim)
{ {
load(pNode); load(pNode);
} }
@@ -294,7 +341,7 @@ Poco::XML::Node* XMLConfiguration::findNode(const std::string& key)
} }
Poco::XML::Node* XMLConfiguration::findNode(std::string::const_iterator& it, const std::string::const_iterator& end, Poco::XML::Node* pNode, bool create) Poco::XML::Node* XMLConfiguration::findNode(std::string::const_iterator& it, const std::string::const_iterator& end, Poco::XML::Node* pNode, bool create) const
{ {
if (pNode && it != end) if (pNode && it != end)
{ {
@@ -339,9 +386,9 @@ Poco::XML::Node* XMLConfiguration::findNode(std::string::const_iterator& it, con
} }
else else
{ {
while (it != end && *it == '.') ++it; while (it != end && *it == _delim) ++it;
std::string key; std::string key;
while (it != end && *it != '.' && *it != '[') key += *it++; while (it != end && *it != _delim && *it != '[') key += *it++;
return findNode(it, end, findElement(key, pNode, create), create); return findNode(it, end, findElement(key, pNode, create), create);
} }
} }