Exheredludis/paludis/args/args_option.cc
2016-12-04 20:33:50 -08:00

603 lines
16 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2005, 2006, 2007, 2008, 2009, 2010, 2011 Ciaran McCreesh
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
* Public License version 2, as published by the Free Software Foundation.
*
* Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <paludis/args/args_option.hh>
#include <paludis/args/args_error.hh>
#include <paludis/args/args_group.hh>
#include <paludis/args/args_section.hh>
#include <paludis/args/args_handler.hh>
#include <paludis/args/escape.hh>
#include <paludis/util/pimp-impl.hh>
#include <paludis/util/wrapped_forward_iterator-impl.hh>
#include <paludis/util/make_named_values.hh>
#include <paludis/util/join.hh>
#include <set>
#include <vector>
#include <algorithm>
#include <list>
using namespace paludis;
using namespace paludis::args;
namespace
{
struct ArgIs
{
const std::string arg;
ArgIs(const std::string & a) :
arg(a)
{
}
bool operator() (const std::pair<std::string, std::string> & p) const
{
return p.first == arg;
}
bool operator() (const AllowedEnumArg & p) const
{
return p.long_name() == arg || (p.short_name() && std::string(1, p.short_name()) == arg);
}
};
}
ArgsOption::ArgsOption(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description) :
_group(g),
_long_name(our_long_name),
_short_name(our_short_name),
_description(our_description),
_specified(aos_not)
{
g->add(this);
g->section()->handler()->add_option(this, our_long_name, our_short_name);
}
void
ArgsOption::remove()
{
_group->remove(this);
_group->section()->handler()->remove_option(_long_name, _short_name);
}
SwitchArg::SwitchArg(ArgsGroup * const our_group, const std::string & our_long_name, char our_short_name,
const std::string & our_description, const bool c) :
ArgsOption(our_group, our_long_name, our_short_name, our_description),
_can_be_negated(c)
{
}
const std::string
SwitchArg::forwardable_string() const
{
if (specified())
return "--" + long_name();
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
SwitchArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
result->push_back("--" + long_name());
return result;
}
AliasArg::AliasArg(ArgsOption * const o, const std::string & our_long_name, bool is_hidden) :
ArgsOption(o->group(), our_long_name, '\0', "Alias for --" + o->long_name()),
_other(o), _hidden(is_hidden)
{
}
const std::string
AliasArg::forwardable_string() const
{
return "";
}
const std::shared_ptr<Sequence<std::string> >
AliasArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
return result;
}
StringArg::StringArg(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description,
const bool neg) :
ArgsOption(g, our_long_name, our_short_name, our_description),
_can_be_negated(neg),
_validator(nullptr)
{
}
StringArg::StringArg(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description,
void (* v) (const std::string &), const bool neg) :
ArgsOption(g, our_long_name, our_short_name, our_description),
_can_be_negated(neg),
_validator(v)
{
}
const std::string
StringArg::forwardable_string() const
{
if (specified())
return "--" + long_name() + " " + escape(argument());
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
StringArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
{
result->push_back("--" + long_name());
result->push_back(argument());
}
return result;
}
namespace paludis
{
template<>
struct Imp<StringSetArg>
{
std::set<std::string> args;
std::vector<std::pair<std::string, std::string> > allowed_args;
};
template<>
struct Imp<StringSetArg::StringSetArgOptions>
{
std::vector<std::pair<std::string, std::string> > options;
};
template <>
struct WrappedForwardIteratorTraits<StringSetArg::ConstIteratorTag>
{
typedef std::set<std::string>::const_iterator UnderlyingIterator;
};
template <>
struct WrappedForwardIteratorTraits<StringSetArg::AllowedArgConstIteratorTag>
{
typedef std::vector<std::pair<std::string, std::string> >::const_iterator UnderlyingIterator;
};
}
StringSetArg::StringSetArg(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description,
const StringSetArgOptions & opts) :
ArgsOption(g, our_long_name, our_short_name, our_description),
_imp(),
_validator(nullptr)
{
std::copy(opts._imp->options.begin(), opts._imp->options.end(),
std::back_inserter(_imp->allowed_args));
}
StringSetArg::StringSetArg(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description,
const StringSetArgOptions & opts, void (* v) (const std::string &)) :
ArgsOption(g, our_long_name, our_short_name, our_description),
_imp(),
_validator(v)
{
std::copy(opts._imp->options.begin(), opts._imp->options.end(),
std::back_inserter(_imp->allowed_args));
}
StringSetArg::ConstIterator
StringSetArg::begin_args() const
{
return ConstIterator(_imp->args.begin());
}
StringSetArg::ConstIterator
StringSetArg::end_args() const
{
return ConstIterator(_imp->args.end());
}
IteratorRange<StringSetArg::ConstIterator>
StringSetArg::args() const
{
return {_imp->args};
}
void
StringSetArg::add_argument(const std::string & arg)
{
Context context("When handling argument '" + arg + "' for '--" + long_name() + "':");
if (! _imp->allowed_args.empty())
if (_imp->allowed_args.end() == std::find_if(_imp->allowed_args.begin(),
_imp->allowed_args.end(), ArgIs(arg)))
throw BadValue("--" + long_name(), arg);
if (_validator)
(*_validator)(arg);
_imp->args.insert(arg);
}
const std::string
StringSetArg::forwardable_string() const
{
if (specified())
return "--" + long_name() + " " + join(begin_args(), end_args(), " --" + long_name() + " ",
&escape);
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
StringSetArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
{
for (ConstIterator i(begin_args()), i_end(end_args()) ;
i != i_end ; ++i)
{
result->push_back("--" + long_name());
result->push_back(*i);
}
}
return result;
}
namespace paludis
{
template<>
struct Imp<StringSequenceArg>
{
std::list<std::string> args;
};
template <>
struct WrappedForwardIteratorTraits<StringSequenceArg::ConstIteratorTag>
{
typedef std::list<std::string>::const_iterator UnderlyingIterator;
};
}
StringSequenceArg::StringSequenceArg(ArgsGroup * const g, const std::string & our_long_name,
const char our_short_name, const std::string & our_description) :
ArgsOption(g, our_long_name, our_short_name, our_description),
_imp()
{
}
StringSequenceArg::~StringSequenceArg() = default;
StringSequenceArg::ConstIterator
StringSequenceArg::begin_args() const
{
return ConstIterator(_imp->args.begin());
}
StringSequenceArg::ConstIterator
StringSequenceArg::end_args() const
{
return ConstIterator(_imp->args.end());
}
void
StringSequenceArg::add_argument(const std::string & arg)
{
Context context("When handling argument '" + arg + "' for '--" + long_name() + "':");
_imp->args.push_back(arg);
}
const std::string
StringSequenceArg::forwardable_string() const
{
if (specified())
return "--" + long_name() + " " + join(begin_args(), end_args(), " --" + long_name() + " ",
&escape);
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
StringSequenceArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
{
for (ConstIterator i(begin_args()), i_end(end_args()) ;
i != i_end ; ++i)
{
result->push_back("--" + long_name());
result->push_back(*i);
}
}
return result;
}
IntegerArg::IntegerArg(ArgsGroup * const our_group, const std::string & our_long_name,
char our_short_name, const std::string & our_description) :
ArgsOption(our_group, our_long_name, our_short_name, our_description)
{
}
const std::string
IntegerArg::forwardable_string() const
{
if (specified())
return "--" + long_name() + " " + stringify(argument());
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
IntegerArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
{
result->push_back("--" + long_name());
result->push_back(stringify(argument()));
}
return result;
}
namespace paludis
{
template<>
struct Imp<EnumArg>
{
std::vector<AllowedEnumArg> allowed_args;
};
template<>
struct Imp<EnumArg::EnumArgOptions>
{
std::vector<AllowedEnumArg> options;
};
template <>
struct WrappedForwardIteratorTraits<EnumArg::AllowedArgConstIteratorTag>
{
typedef std::vector<AllowedEnumArg>::const_iterator UnderlyingIterator;
};
}
StringSetArg::StringSetArgOptions::StringSetArgOptions(const std::string & opt, const std::string & desc) :
_imp()
{
_imp->options.push_back(std::make_pair(opt, desc));
}
StringSetArg::StringSetArgOptions &
StringSetArg::StringSetArgOptions::operator() (const std::string & opt, const std::string & desc)
{
_imp->options.push_back(std::make_pair(opt, desc));
return *this;
}
StringSetArg::StringSetArgOptions::StringSetArgOptions(const StringSetArg::StringSetArgOptions & o) :
_imp()
{
std::copy(o._imp->options.begin(), o._imp->options.end(),
std::back_inserter(_imp->options));
}
StringSetArg::StringSetArgOptions::~StringSetArgOptions() = default;
StringSetArg::StringSetArgOptions::StringSetArgOptions() :
_imp()
{
}
void
EnumArg::set_argument(const std::string & arg)
{
Context context("When handling argument '" + arg + "' for '--" + long_name() + "':");
/* if we're given the short arg, turn it magically into the long one */
AllowedArgConstIterator i(std::find_if(_imp->allowed_args.begin(), _imp->allowed_args.end(), ArgIs(arg)));
if (i == _imp->allowed_args.end())
throw BadValue("--" + long_name(), arg);
_argument = i->long_name();
}
void
StringArg::set_argument(const std::string & arg)
{
Context context("When handling argument '" + arg + "' for '--" + long_name() + "':");
if (_validator)
(*_validator)(arg);
_argument = arg;
}
EnumArg::~EnumArg() = default;
EnumArg::EnumArgOptions::EnumArgOptions(const std::string & opt, const std::string & desc) :
_imp()
{
_imp->options.push_back(make_named_values<AllowedEnumArg>(
n::description() = desc,
n::long_name() = opt,
n::short_name() = '\0'
));
}
EnumArg::EnumArgOptions::EnumArgOptions(const std::string & opt, const char s, const std::string & desc) :
_imp()
{
_imp->options.push_back(make_named_values<AllowedEnumArg>(
n::description() = desc,
n::long_name() = opt,
n::short_name() = s
));
}
EnumArg::EnumArgOptions &
EnumArg::EnumArgOptions::operator() (const std::string & opt, const std::string & desc)
{
_imp->options.push_back(make_named_values<AllowedEnumArg>(
n::description() = desc,
n::long_name() = opt,
n::short_name() = '\0'
));
return *this;
}
EnumArg::EnumArgOptions &
EnumArg::EnumArgOptions::operator() (const std::string & opt, const char s, const std::string & desc)
{
_imp->options.push_back(make_named_values<AllowedEnumArg>(
n::description() = desc,
n::long_name() = opt,
n::short_name() = s
));
return *this;
}
EnumArg::EnumArgOptions::~EnumArgOptions() = default;
EnumArg::EnumArg(ArgsGroup * const our_group, const std::string & our_long_name,
const char our_short_name, const std::string & our_description,
const EnumArgOptions & opts, const std::string & our_default_arg) :
ArgsOption(our_group, our_long_name, our_short_name, our_description),
_imp(),
_argument(our_default_arg),
_default_arg(our_default_arg)
{
_imp->allowed_args = opts._imp->options;
}
void
EnumArg::set_default_arg(const std::string & arg)
{
_argument = arg;
_default_arg = arg;
}
EnumArg::AllowedArgConstIterator
EnumArg::begin_allowed_args() const
{
return AllowedArgConstIterator(_imp->allowed_args.begin());
}
EnumArg::AllowedArgConstIterator
EnumArg::end_allowed_args() const
{
return AllowedArgConstIterator(_imp->allowed_args.end());
}
const std::string
EnumArg::forwardable_string() const
{
if (specified())
return "--" + long_name() + " " + escape(argument());
else
return "";
}
const std::shared_ptr<Sequence<std::string> >
EnumArg::forwardable_args() const
{
std::shared_ptr<Sequence<std::string> > result(std::make_shared<Sequence<std::string>>());
if (specified())
{
result->push_back("--" + long_name());
result->push_back(argument());
}
return result;
}
StringSetArg::~StringSetArg() = default;
StringSetArg::AllowedArgConstIterator
StringSetArg::begin_allowed_args() const
{
return AllowedArgConstIterator(_imp->allowed_args.begin());
}
StringSetArg::AllowedArgConstIterator
StringSetArg::end_allowed_args() const
{
return AllowedArgConstIterator(_imp->allowed_args.end());
}
bool
AliasArg::can_be_negated() const
{
return _other->can_be_negated();
}
bool
StringArg::can_be_negated() const
{
return _can_be_negated;
}
bool
IntegerArg::can_be_negated() const
{
return false;
}
bool
EnumArg::can_be_negated() const
{
return false;
}
bool
StringSetArg::can_be_negated() const
{
return false;
}
bool
StringSequenceArg::can_be_negated() const
{
return false;
}
bool
SwitchArg::can_be_negated() const
{
return _can_be_negated;
}
namespace paludis
{
template class WrappedForwardIterator<StringSetArg::ConstIteratorTag, const std::string>;
template class WrappedForwardIterator<StringSetArg::AllowedArgConstIteratorTag,
const std::pair<std::string, std::string> >;
template class WrappedForwardIterator<EnumArg::AllowedArgConstIteratorTag,
const AllowedEnumArg>;
template class WrappedForwardIterator<StringSequenceArg::ConstIteratorTag, const std::string>;
}