You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

473 lines
13 KiB

/* /////////////////////////////////////////////////////////////////////////
* File: stlsoft/system/cmdargs.hpp
*
* Purpose: Command-line sequences class.
*
* Created: 25th June 2005
* Updated: 10th August 2009
*
* Home: http://stlsoft.org/
*
* Copyright (c) 2005-2009, Matthew Wilson and Synesis Software
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name(s) of Matthew Wilson and Synesis Software nor the
* names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ////////////////////////////////////////////////////////////////////// */
/** \file stlsoft/system/cmdargs.hpp
*
* [C++ only] Definition of the stlsoft::cmdargs class
* (\ref group__library__system "System" Library).
*/
#ifndef STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS
#define STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
# define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_MAJOR 3
# define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_MINOR 0
# define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_REVISION 3
# define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_EDIT 30
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
/* /////////////////////////////////////////////////////////////////////////
* Compatibility
*/
/*
[Incompatibilies-start]
STLSOFT_COMPILER_IS_WATCOM:
[Incompatibilies-end]
*/
/* /////////////////////////////////////////////////////////////////////////
* Includes
*/
#ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
# include <stlsoft/stlsoft.h>
#endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
#ifdef STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING
# include <string>
#else /* ? STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
# ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
# include <stlsoft/string/simple_string.hpp>
# endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
#endif /* STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
#ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS
# include <stlsoft/string/split_functions.hpp>
#endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS */
#ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW
# include <stlsoft/string/string_view.hpp>
#endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW */
#ifndef STLSOFT_INCL_UTILITY
# define STLSOFT_INCL_UTILITY
# include <utility>
#endif /* !STLSOFT_INCL_UTILITY */
#ifndef STLSOFT_INCL_VECTOR
# define STLSOFT_INCL_VECTOR
# include <vector>
#endif /* !STLSOFT_INCL_VECTOR */
/* /////////////////////////////////////////////////////////////////////////
* Namespace
*/
#ifndef _STLSOFT_NO_NAMESPACE
namespace stlsoft
{
#endif /* _STLSOFT_NO_NAMESPACE */
/* /////////////////////////////////////////////////////////////////////////
* Classes
*/
/** Facade class that presents argc+argv command line parameters as
* two separate sequences of options (those arguments with - or --
* prefixes and, optionally, separated from an option value by a =) and
* values (those without any leading hyphens)
*
* \ingroup group__library__system
*
* \note The cmdargs instance maintains views onto the actual arguments in
* the argv array. Therefore, the behaviour is undefined if any code
* modifies the strings pointed to by the elements in the argv array, or
* repoints any of the <code>argv</code> elements to different strings.
*/
class cmdargs
{
public:
#ifdef STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING
typedef std::string string_type;
#else /* ? STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
typedef simple_string string_type;
#endif /* STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
typedef basic_string_view<char> string_view_type;
enum
{
singleDash = 1
, doubleDash = 2
, tripleDash = 3
};
/// Represents a command-line option
///
/// \warning The value of the <code>original</code> member will be
/// undefined if a copy of the instance is kept beyond the lifetime of
/// the cmdargs instance from which it was obtained.
struct option
{
string_type name;
string_type value;
int type;
int index;
string_view_type original;
option()
: name()
, value()
, type(-1)
, index(-1)
, original()
{}
option(string_type const& n, string_type const& v, int t, int i, string_view_type const& o)
: name(n)
, value(v)
, type(t)
, index(i)
, original(o)
{}
};
/// Represents a command-line value
///
/// \warning The value of the <code>name</code> member will be undefined
/// if a copy of the instance is kept beyond the lifetime of the
/// cmdargs instance from which it was obtained.
struct value
{
string_view_type name;
int index;
value()
: name()
, index(-1)
{}
value(string_view_type const& v, int i)
: name(v)
, index(i)
{}
};
typedef option options_value_type;
typedef value values_value_type;
typedef stlsoft_ns_qual_std(vector)<options_value_type> options_type;
typedef stlsoft_ns_qual_std(vector)<values_value_type> values_type;
typedef options_type::const_iterator const_options_iterator;
typedef values_type::const_iterator const_values_iterator;
typedef ss_size_t size_type;
typedef ss_bool_t bool_type;
/// \name Construction
/// @{
public:
/// Constructs from argc/argv
cmdargs(int argc, char /*const*/ ** argv);
/// Releases any resources
~cmdargs() stlsoft_throw_0();
/// @}
/// \name Attributes
/// @{
public:
/// non-mutating reference to the options
options_type const& options() const;
/// non-mutating reference to the values
values_type const& values() const;
const_options_iterator options_begin() const;
const_options_iterator options_end() const;
const_values_iterator values_begin() const;
const_values_iterator values_end() const;
/// The number of options
size_type options_size() const;
/// The number of values
size_type values_size() const;
/// The numbers options and values
size_type size() const;
/// Indicates whether there are any options and/or values
bool_type empty() const;
/// Determines whether the options collection contains an option of
/// the given name
///
/// \param optionName The name of the option to search for
/// \param type The type of the option (i.e the number of hyphens). It
/// defaults to -1, which indicates that the caller does not care.
template <ss_typename_param_k S>
bool_type has_option(S const& optionName, int type = -1) const
{
return m_options.end() != has_option_(c_str_ptr(optionName));
}
/// Determines whether the options collection contains an option of
/// the given name, and copies the found option's details into a
/// caller-supplied instance
///
/// \param optionName The name of the option to search for
/// \param type The type of the option (i.e the number of hyphens). The
/// caller can specify -1 to indicate that it does not care.
/// \param opt The instance into which the
template <ss_typename_param_k S>
bool_type has_option(S const& optionName, int type, option& opt) const
{
options_type::const_iterator it = has_option_(c_str_ptr(optionName), type);
if(m_options.end() != it)
{
opt = *it;
return true;
}
return false;
}
template <ss_typename_param_k S>
bool_type has_value(S const& valueName) const
{
return m_values.end() != has_value_(c_str_ptr(valueName));
}
template <ss_typename_param_k S>
bool_type has_value(S const& valueName, value& val) const
{
values_type::const_iterator it = has_value_(c_str_ptr(valueName));
if(m_values.end() != it)
{
val = *it;
return true;
}
return false;
}
/// @}
/// \name Implementation
/// @{
private:
values_type::const_iterator has_value_(char const* valueName) const;
options_type::const_iterator has_option_(char const* optionName, int type) const;
/// @}
/// \name Members
/// @{
private:
options_type m_options;
values_type m_values;
/// @}
};
////////////////////////////////////////////////////////////////////////////
// Unit-testing
#ifdef STLSOFT_UNITTEST
# include "./unittest/cmdargs_unittest_.h"
#endif /* STLSOFT_UNITTEST */
////////////////////////////////////////////////////////////////////////////
// Implementation
#ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
inline cmdargs::cmdargs(int argc, char /*const*/ **argv)
{
for(int i = 1; i < argc; ++i)
{
char const *arg = argv[i];
if('-' == arg[0])
{
++arg;
const int type = ('-' != arg[0]) ? singleDash : (++arg, doubleDash);
string_type s0;
string_type s1;
split(arg, '=', s0, s1);
m_options.push_back(option(s0, s1, type, i, argv[i]));
}
else
{
m_values.push_back(value(arg, i));
}
}
}
inline cmdargs::~cmdargs() stlsoft_throw_0()
{
}
inline cmdargs::options_type const& cmdargs::options() const
{
return m_options;
}
inline cmdargs::values_type const& cmdargs::values() const
{
return m_values;
}
inline cmdargs::const_options_iterator cmdargs::options_begin() const
{
return m_options.begin();
}
inline cmdargs::const_options_iterator cmdargs::options_end() const
{
return m_options.end();
}
inline cmdargs::const_values_iterator cmdargs::values_begin() const
{
return m_values.begin();
}
inline cmdargs::const_values_iterator cmdargs::values_end() const
{
return m_values.end();
}
inline cmdargs::size_type cmdargs::options_size() const
{
return m_options.size();
}
inline cmdargs::size_type cmdargs::values_size() const
{
return m_values.size();
}
inline cmdargs::size_type cmdargs::size() const
{
return options_size() + values_size();
}
inline cmdargs::bool_type cmdargs::empty() const
{
return 0 == size();
}
inline cmdargs::values_type::const_iterator cmdargs::has_value_(char const* valueName) const
{
STLSOFT_ASSERT(NULL != valueName);
values_type::const_iterator b;
for(b = m_values.begin(); b != m_values.end(); ++b)
{
if((*b).name == valueName)
{
break;
}
}
return b;
}
inline cmdargs::options_type::const_iterator cmdargs::has_option_(char const* optionName, int type) const
{
STLSOFT_ASSERT(NULL != optionName);
options_type::const_iterator b;
for(b = m_options.begin(); b != m_options.end(); ++b)
{
if( (*b).name == optionName &&
( -1 == type ||
type == (*b).type))
{
break;
}
}
return b;
}
#endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
template <ss_typename_param_k S>
inline S& operator <<(S &stm, cmdargs::option const& option)
{
static const char s_dashes[] =
{
'-'
, '-'
, '\0'
};
char const *dashes = &s_dashes[(option.type == cmdargs::singleDash)];
if(option.value.empty())
{
stm << dashes << option.name;
}
else
{
stm << dashes << option.name << '=' << option.value;
}
return stm;
}
template <ss_typename_param_k S>
inline S& operator <<(S &stm, cmdargs::value const& value)
{
stm << value.name;
return stm;
}
/* ////////////////////////////////////////////////////////////////////// */
#ifndef _STLSOFT_NO_NAMESPACE
} // namespace stlsoft
#endif /* _STLSOFT_NO_NAMESPACE */
/* ////////////////////////////////////////////////////////////////////// */
#endif /* !STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS */
/* ///////////////////////////// end of file //////////////////////////// */