changes (part 1) from 1.4.3 branch (XMLConfiguration delimiter, OptionProcessor)
This commit is contained in:
Родитель
97ec3f5bf6
Коммит
cc90b38ae5
|
@ -55,13 +55,13 @@ class Util_API OptionProcessor
|
|||
/// An OptionProcessor is used to process the command line
|
||||
/// arguments of an application.
|
||||
///
|
||||
/// The process() method takes an argument from the command line.
|
||||
/// If that argument starts with an option prefix, the argument
|
||||
/// is further processed. Otherwise, the argument is ignored and
|
||||
/// false is ignored. The argument must match one of the options
|
||||
/// given in the OptionSet that is passed to the OptionProcessor
|
||||
/// with the constructor. If an option is part of a group, at most
|
||||
/// one option of the group can be passed to the OptionProcessor.
|
||||
/// The process() method takes an argument from the command line.
|
||||
/// If that argument starts with an option prefix, the argument
|
||||
/// is further processed. Otherwise, the argument is ignored and
|
||||
/// false is returned. The argument must match one of the options
|
||||
/// given in the OptionSet that is passed to the OptionProcessor
|
||||
/// with the constructor. If an option is part of a group, at most
|
||||
/// one option of the group can be passed to the OptionProcessor.
|
||||
/// Otherwise an IncompatibleOptionsException is thrown.
|
||||
/// If the same option is given multiple times, but the option
|
||||
/// is not repeatable, a DuplicateOptionException is thrown.
|
||||
|
@ -79,12 +79,22 @@ class Util_API OptionProcessor
|
|||
/// by a short option name, or another dash, followed by a (partial)
|
||||
/// long option name.
|
||||
/// In default mode, the option prefix is a slash '/', followed by
|
||||
/// a (partial) long option name.
|
||||
/// If the special option '--' is encountered in Unix mode, all following
|
||||
/// options are ignored.
|
||||
/// a (partial) long option name.
|
||||
/// If the special option '--' is encountered in Unix mode, all following
|
||||
/// 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:
|
||||
OptionProcessor(const OptionSet& options);
|
||||
OptionProcessor(const OptionSet& options);
|
||||
/// Creates the OptionProcessor, using the given OptionSet.
|
||||
|
||||
~OptionProcessor();
|
||||
|
@ -127,9 +137,10 @@ private:
|
|||
|
||||
const OptionSet& _options;
|
||||
bool _unixStyle;
|
||||
bool _ignore;
|
||||
std::set<std::string> _groups;
|
||||
std::set<std::string> _specifiedOptions;
|
||||
bool _ignore;
|
||||
std::set<std::string> _groups;
|
||||
std::set<std::string> _specifiedOptions;
|
||||
std::string _deferredOption;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -86,35 +86,68 @@ class Util_API XMLConfiguration: public AbstractConfiguration
|
|||
/// prop5[1] -> value6
|
||||
/// prop5[@id=first] -> value5
|
||||
/// prop5[@id='second'] -> value6
|
||||
///
|
||||
/// Enumerating attributes is not supported.
|
||||
/// Calling keys("prop3.prop4") will return an empty range.
|
||||
///
|
||||
/// Enumerating attributes is not supported.
|
||||
/// 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:
|
||||
XMLConfiguration();
|
||||
/// Creates an empty XMLConfiguration.
|
||||
XMLConfiguration();
|
||||
/// Creates an empty XMLConfiguration.
|
||||
|
||||
XMLConfiguration(Poco::XML::InputSource* pInputSource);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// the given InputSource.
|
||||
XMLConfiguration(char delim);
|
||||
/// Creates an empty XMLConfiguration, using the given
|
||||
/// delimiter char instead of the default '.'.
|
||||
|
||||
XMLConfiguration(std::istream& istr);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// the given stream.
|
||||
XMLConfiguration(Poco::XML::InputSource* pInputSource);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// the given InputSource.
|
||||
|
||||
XMLConfiguration(const std::string& path);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// the given path.
|
||||
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(const Poco::XML::Document* pDocument);
|
||||
/// Creates the XMLConfiguration using the given XML document.
|
||||
|
||||
XMLConfiguration(const Poco::XML::Node* pNode);
|
||||
/// Creates the XMLConfiguration using the given XML node.
|
||||
XMLConfiguration(std::istream& istr);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// the given stream.
|
||||
|
||||
void load(Poco::XML::InputSource* pInputSource);
|
||||
/// Loads the XML document containing the configuration data
|
||||
/// from the given InputSource.
|
||||
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);
|
||||
/// Creates an XMLConfiguration and loads the XML document from
|
||||
/// 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);
|
||||
/// 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);
|
||||
/// 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);
|
||||
/// Loads the XML document containing the configuration data
|
||||
/// from the given InputSource.
|
||||
|
||||
void load(std::istream& istr);
|
||||
/// Loads the XML document containing the configuration data
|
||||
|
@ -164,16 +197,17 @@ protected:
|
|||
~XMLConfiguration();
|
||||
|
||||
private:
|
||||
const Poco::XML::Node* findNode(const std::string& key) const;
|
||||
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);
|
||||
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(const std::string& attr, const std::string& value, Poco::XML::Node* pNode);
|
||||
const Poco::XML::Node* findNode(const std::string& key) const;
|
||||
Poco::XML::Node* findNode(const std::string& key);
|
||||
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(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* findAttribute(const std::string& name, Poco::XML::Node* pNode, bool create);
|
||||
|
||||
Poco::XML::AutoPtr<Poco::XML::Node> _pRoot;
|
||||
Poco::XML::AutoPtr<Poco::XML::Document> _pDocument;
|
||||
Poco::XML::AutoPtr<Poco::XML::Node> _pRoot;
|
||||
Poco::XML::AutoPtr<Poco::XML::Document> _pDocument;
|
||||
char _delim;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -116,15 +116,15 @@ void Application::setup()
|
|||
|
||||
_pConfig->add(new SystemConfiguration, PRIO_SYSTEM, false, false);
|
||||
_pConfig->add(new MapConfiguration, PRIO_APPLICATION, true, false);
|
||||
|
||||
addSubsystem(new LoggingSubsystem);
|
||||
|
||||
|
||||
addSubsystem(new LoggingSubsystem);
|
||||
|
||||
#if defined(POCO_OS_FAMILY_UNIX) && !defined(POCO_VXWORKS)
|
||||
_workingDirAtLaunch = Path::current();
|
||||
_workingDirAtLaunch = Path::current();
|
||||
|
||||
#if !defined(_DEBUG)
|
||||
Poco::SignalHandler::install();
|
||||
#endif
|
||||
#if !defined(_DEBUG)
|
||||
Poco::SignalHandler::install();
|
||||
#endif
|
||||
#else
|
||||
setUnixOptions(false);
|
||||
#endif
|
||||
|
@ -368,13 +368,13 @@ void Application::processOptions()
|
|||
while (it != _args.end() && !_stopOptionsProcessing)
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
if (processor.process(*it, name, value))
|
||||
{
|
||||
if (!name.empty()) // "--" option to end options processing
|
||||
{
|
||||
handleOption(name, value);
|
||||
}
|
||||
std::string value;
|
||||
if (processor.process(*it, name, value))
|
||||
{
|
||||
if (!name.empty()) // "--" option to end options processing or deferred argument
|
||||
{
|
||||
handleOption(name, value);
|
||||
}
|
||||
it = _args.erase(it);
|
||||
}
|
||||
else ++it;
|
||||
|
@ -393,19 +393,19 @@ void Application::getApplicationPath(Poco::Path& appPath) const
|
|||
if (path.isAbsolute())
|
||||
{
|
||||
appPath = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
appPath = _workingDirAtLaunch;
|
||||
appPath.append(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Path::find(Environment::get("PATH"), _command, appPath))
|
||||
appPath = Path(_workingDirAtLaunch, _command);
|
||||
appPath.makeAbsolute();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
appPath = _workingDirAtLaunch;
|
||||
appPath.append(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Path::find(Environment::get("PATH"), _command, appPath))
|
||||
appPath = Path(_workingDirAtLaunch, _command);
|
||||
appPath.makeAbsolute();
|
||||
}
|
||||
#elif defined(POCO_OS_FAMILY_WINDOWS)
|
||||
#if defined(POCO_WIN32_UTF8) && !defined(POCO_NO_WSTRING)
|
||||
wchar_t path[1024];
|
||||
|
|
|
@ -173,12 +173,20 @@ int HelpFormatter::calcIndent() const
|
|||
void HelpFormatter::formatOptions(std::ostream& ostr) const
|
||||
{
|
||||
int optWidth = calcIndent();
|
||||
for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
|
||||
{
|
||||
formatOption(ostr, *it, optWidth);
|
||||
formatText(ostr, it->description(), _indent, optWidth);
|
||||
ostr << '\n';
|
||||
}
|
||||
for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
|
||||
{
|
||||
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);
|
||||
}
|
||||
ostr << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -65,12 +65,16 @@ void OptionProcessor::setUnixStyle(bool flag)
|
|||
|
||||
bool OptionProcessor::process(const std::string& argument, std::string& optionName, std::string& optionArg)
|
||||
{
|
||||
if (!_ignore)
|
||||
{
|
||||
if (_unixStyle)
|
||||
return processUnix(argument, optionName, optionArg);
|
||||
else
|
||||
return processDefault(argument, optionName, optionArg);
|
||||
optionName.clear();
|
||||
optionArg.clear();
|
||||
if (!_ignore)
|
||||
{
|
||||
if (!_deferredOption.empty())
|
||||
return processCommon(argument, false, optionName, optionArg);
|
||||
else if (_unixStyle)
|
||||
return processUnix(argument, optionName, optionArg);
|
||||
else
|
||||
return processDefault(argument, optionName, optionArg);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -80,9 +84,15 @@ void OptionProcessor::checkRequired() const
|
|||
{
|
||||
for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
|
||||
{
|
||||
if (it->required() && _specifiedOptions.find(it->fullName()) == _specifiedOptions.end())
|
||||
throw MissingOptionException(it->fullName());
|
||||
}
|
||||
if (it->required() && _specifiedOptions.find(it->fullName()) == _specifiedOptions.end())
|
||||
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,9 +143,20 @@ 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)
|
||||
{
|
||||
if (optionStr.empty()) throw EmptyOptionException();
|
||||
const Option& option = _options.getOption(optionStr, isShort);
|
||||
const std::string& group = option.group();
|
||||
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();
|
||||
const Option& option = _options.getOption(optionStr, isShort);
|
||||
const std::string& group = option.group();
|
||||
if (!group.empty())
|
||||
{
|
||||
if (_groups.find(group) != _groups.end())
|
||||
|
@ -143,12 +164,17 @@ bool OptionProcessor::processCommon(const std::string& optionStr, bool isShort,
|
|||
else
|
||||
_groups.insert(group);
|
||||
}
|
||||
if (_specifiedOptions.find(option.fullName()) != _specifiedOptions.end() && !option.repeatable())
|
||||
throw DuplicateOptionException(option.fullName());
|
||||
_specifiedOptions.insert(option.fullName());
|
||||
option.process(optionStr, optionArg);
|
||||
optionName = option.fullName();
|
||||
return true;
|
||||
if (_specifiedOptions.find(option.fullName()) != _specifiedOptions.end() && !option.repeatable())
|
||||
throw DuplicateOptionException(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);
|
||||
optionName = option.fullName();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -51,38 +51,85 @@ namespace Poco {
|
|||
namespace Util {
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration()
|
||||
XMLConfiguration::XMLConfiguration():
|
||||
_delim('.')
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource)
|
||||
XMLConfiguration::XMLConfiguration(char delim):
|
||||
_delim(delim)
|
||||
{
|
||||
load(pInputSource);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(std::istream& istr)
|
||||
XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource):
|
||||
_delim('.')
|
||||
{
|
||||
load(istr);
|
||||
load(pInputSource);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const std::string& path)
|
||||
XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource, char delim):
|
||||
_delim(delim)
|
||||
{
|
||||
load(path);
|
||||
load(pInputSource);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument)
|
||||
XMLConfiguration::XMLConfiguration(std::istream& istr):
|
||||
_delim('.')
|
||||
{
|
||||
load(pDocument);
|
||||
load(istr);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode)
|
||||
|
||||
XMLConfiguration::XMLConfiguration(std::istream& istr, char delim):
|
||||
_delim(delim)
|
||||
{
|
||||
load(pNode);
|
||||
load(istr);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const std::string& path):
|
||||
_delim('.')
|
||||
{
|
||||
load(path);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const std::string& path, char delim):
|
||||
_delim(delim)
|
||||
{
|
||||
load(path);
|
||||
}
|
||||
|
||||
|
||||
XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument):
|
||||
_delim('.')
|
||||
{
|
||||
load(pDocument);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -294,10 +341,10 @@ 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)
|
||||
{
|
||||
if (*it == '[')
|
||||
{
|
||||
++it;
|
||||
|
@ -336,15 +383,15 @@ Poco::XML::Node* XMLConfiguration::findNode(std::string::const_iterator& it, con
|
|||
if (it != end) ++it;
|
||||
return findNode(it, end, findElement(Poco::NumberParser::parse(index), pNode, create), create);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (it != end && *it == '.') ++it;
|
||||
std::string key;
|
||||
while (it != end && *it != '.' && *it != '[') key += *it++;
|
||||
return findNode(it, end, findElement(key, pNode, create), create);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (it != end && *it == _delim) ++it;
|
||||
std::string key;
|
||||
while (it != end && *it != _delim && *it != '[') key += *it++;
|
||||
return findNode(it, end, findElement(key, pNode, create), create);
|
||||
}
|
||||
}
|
||||
else return pNode;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче