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

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/system/cmdargs.hpp
  3. *
  4. * Purpose: Command-line sequences class.
  5. *
  6. * Created: 25th June 2005
  7. * Updated: 10th August 2009
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2005-2009, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are
  16. * met:
  17. *
  18. * - Redistributions of source code must retain the above copyright notice,
  19. * this list of conditions and the following disclaimer.
  20. * - Redistributions in binary form must reproduce the above copyright
  21. * notice, this list of conditions and the following disclaimer in the
  22. * documentation and/or other materials provided with the distribution.
  23. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the
  24. * names of any contributors may be used to endorse or promote products
  25. * derived from this software without specific prior written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  28. * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  29. * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  30. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  31. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  32. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  33. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  34. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  35. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * ////////////////////////////////////////////////////////////////////// */
  40. /** \file stlsoft/system/cmdargs.hpp
  41. *
  42. * [C++ only] Definition of the stlsoft::cmdargs class
  43. * (\ref group__library__system "System" Library).
  44. */
  45. #ifndef STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS
  46. #define STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS
  47. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  48. # define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_MAJOR 3
  49. # define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_MINOR 0
  50. # define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_REVISION 3
  51. # define STLSOFT_VER_STLSOFT_SYSTEM_HPP_CMDARGS_EDIT 30
  52. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  53. /* /////////////////////////////////////////////////////////////////////////
  54. * Compatibility
  55. */
  56. /*
  57. [Incompatibilies-start]
  58. STLSOFT_COMPILER_IS_WATCOM:
  59. [Incompatibilies-end]
  60. */
  61. /* /////////////////////////////////////////////////////////////////////////
  62. * Includes
  63. */
  64. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  65. # include <stlsoft/stlsoft.h>
  66. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  67. #ifdef STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING
  68. # include <string>
  69. #else /* ? STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
  70. # ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
  71. # include <stlsoft/string/simple_string.hpp>
  72. # endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
  73. #endif /* STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
  74. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS
  75. # include <stlsoft/string/split_functions.hpp>
  76. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SPLIT_FUNCTIONS */
  77. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW
  78. # include <stlsoft/string/string_view.hpp>
  79. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_VIEW */
  80. #ifndef STLSOFT_INCL_UTILITY
  81. # define STLSOFT_INCL_UTILITY
  82. # include <utility>
  83. #endif /* !STLSOFT_INCL_UTILITY */
  84. #ifndef STLSOFT_INCL_VECTOR
  85. # define STLSOFT_INCL_VECTOR
  86. # include <vector>
  87. #endif /* !STLSOFT_INCL_VECTOR */
  88. /* /////////////////////////////////////////////////////////////////////////
  89. * Namespace
  90. */
  91. #ifndef _STLSOFT_NO_NAMESPACE
  92. namespace stlsoft
  93. {
  94. #endif /* _STLSOFT_NO_NAMESPACE */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Classes
  97. */
  98. /** Facade class that presents argc+argv command line parameters as
  99. * two separate sequences of options (those arguments with - or --
  100. * prefixes and, optionally, separated from an option value by a =) and
  101. * values (those without any leading hyphens)
  102. *
  103. * \ingroup group__library__system
  104. *
  105. * \note The cmdargs instance maintains views onto the actual arguments in
  106. * the argv array. Therefore, the behaviour is undefined if any code
  107. * modifies the strings pointed to by the elements in the argv array, or
  108. * repoints any of the <code>argv</code> elements to different strings.
  109. */
  110. class cmdargs
  111. {
  112. public:
  113. #ifdef STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING
  114. typedef std::string string_type;
  115. #else /* ? STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
  116. typedef simple_string string_type;
  117. #endif /* STLSOFT_SYSTEM_CMDARGS_USE_STD_STRING */
  118. typedef basic_string_view<char> string_view_type;
  119. enum
  120. {
  121. singleDash = 1
  122. , doubleDash = 2
  123. , tripleDash = 3
  124. };
  125. /// Represents a command-line option
  126. ///
  127. /// \warning The value of the <code>original</code> member will be
  128. /// undefined if a copy of the instance is kept beyond the lifetime of
  129. /// the cmdargs instance from which it was obtained.
  130. struct option
  131. {
  132. string_type name;
  133. string_type value;
  134. int type;
  135. int index;
  136. string_view_type original;
  137. option()
  138. : name()
  139. , value()
  140. , type(-1)
  141. , index(-1)
  142. , original()
  143. {}
  144. option(string_type const& n, string_type const& v, int t, int i, string_view_type const& o)
  145. : name(n)
  146. , value(v)
  147. , type(t)
  148. , index(i)
  149. , original(o)
  150. {}
  151. };
  152. /// Represents a command-line value
  153. ///
  154. /// \warning The value of the <code>name</code> member will be undefined
  155. /// if a copy of the instance is kept beyond the lifetime of the
  156. /// cmdargs instance from which it was obtained.
  157. struct value
  158. {
  159. string_view_type name;
  160. int index;
  161. value()
  162. : name()
  163. , index(-1)
  164. {}
  165. value(string_view_type const& v, int i)
  166. : name(v)
  167. , index(i)
  168. {}
  169. };
  170. typedef option options_value_type;
  171. typedef value values_value_type;
  172. typedef stlsoft_ns_qual_std(vector)<options_value_type> options_type;
  173. typedef stlsoft_ns_qual_std(vector)<values_value_type> values_type;
  174. typedef options_type::const_iterator const_options_iterator;
  175. typedef values_type::const_iterator const_values_iterator;
  176. typedef ss_size_t size_type;
  177. typedef ss_bool_t bool_type;
  178. /// \name Construction
  179. /// @{
  180. public:
  181. /// Constructs from argc/argv
  182. cmdargs(int argc, char /*const*/ ** argv);
  183. /// Releases any resources
  184. ~cmdargs() stlsoft_throw_0();
  185. /// @}
  186. /// \name Attributes
  187. /// @{
  188. public:
  189. /// non-mutating reference to the options
  190. options_type const& options() const;
  191. /// non-mutating reference to the values
  192. values_type const& values() const;
  193. const_options_iterator options_begin() const;
  194. const_options_iterator options_end() const;
  195. const_values_iterator values_begin() const;
  196. const_values_iterator values_end() const;
  197. /// The number of options
  198. size_type options_size() const;
  199. /// The number of values
  200. size_type values_size() const;
  201. /// The numbers options and values
  202. size_type size() const;
  203. /// Indicates whether there are any options and/or values
  204. bool_type empty() const;
  205. /// Determines whether the options collection contains an option of
  206. /// the given name
  207. ///
  208. /// \param optionName The name of the option to search for
  209. /// \param type The type of the option (i.e the number of hyphens). It
  210. /// defaults to -1, which indicates that the caller does not care.
  211. template <ss_typename_param_k S>
  212. bool_type has_option(S const& optionName, int type = -1) const
  213. {
  214. return m_options.end() != has_option_(c_str_ptr(optionName));
  215. }
  216. /// Determines whether the options collection contains an option of
  217. /// the given name, and copies the found option's details into a
  218. /// caller-supplied instance
  219. ///
  220. /// \param optionName The name of the option to search for
  221. /// \param type The type of the option (i.e the number of hyphens). The
  222. /// caller can specify -1 to indicate that it does not care.
  223. /// \param opt The instance into which the
  224. template <ss_typename_param_k S>
  225. bool_type has_option(S const& optionName, int type, option& opt) const
  226. {
  227. options_type::const_iterator it = has_option_(c_str_ptr(optionName), type);
  228. if(m_options.end() != it)
  229. {
  230. opt = *it;
  231. return true;
  232. }
  233. return false;
  234. }
  235. template <ss_typename_param_k S>
  236. bool_type has_value(S const& valueName) const
  237. {
  238. return m_values.end() != has_value_(c_str_ptr(valueName));
  239. }
  240. template <ss_typename_param_k S>
  241. bool_type has_value(S const& valueName, value& val) const
  242. {
  243. values_type::const_iterator it = has_value_(c_str_ptr(valueName));
  244. if(m_values.end() != it)
  245. {
  246. val = *it;
  247. return true;
  248. }
  249. return false;
  250. }
  251. /// @}
  252. /// \name Implementation
  253. /// @{
  254. private:
  255. values_type::const_iterator has_value_(char const* valueName) const;
  256. options_type::const_iterator has_option_(char const* optionName, int type) const;
  257. /// @}
  258. /// \name Members
  259. /// @{
  260. private:
  261. options_type m_options;
  262. values_type m_values;
  263. /// @}
  264. };
  265. ////////////////////////////////////////////////////////////////////////////
  266. // Unit-testing
  267. #ifdef STLSOFT_UNITTEST
  268. # include "./unittest/cmdargs_unittest_.h"
  269. #endif /* STLSOFT_UNITTEST */
  270. ////////////////////////////////////////////////////////////////////////////
  271. // Implementation
  272. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  273. inline cmdargs::cmdargs(int argc, char /*const*/ **argv)
  274. {
  275. for(int i = 1; i < argc; ++i)
  276. {
  277. char const *arg = argv[i];
  278. if('-' == arg[0])
  279. {
  280. ++arg;
  281. const int type = ('-' != arg[0]) ? singleDash : (++arg, doubleDash);
  282. string_type s0;
  283. string_type s1;
  284. split(arg, '=', s0, s1);
  285. m_options.push_back(option(s0, s1, type, i, argv[i]));
  286. }
  287. else
  288. {
  289. m_values.push_back(value(arg, i));
  290. }
  291. }
  292. }
  293. inline cmdargs::~cmdargs() stlsoft_throw_0()
  294. {
  295. }
  296. inline cmdargs::options_type const& cmdargs::options() const
  297. {
  298. return m_options;
  299. }
  300. inline cmdargs::values_type const& cmdargs::values() const
  301. {
  302. return m_values;
  303. }
  304. inline cmdargs::const_options_iterator cmdargs::options_begin() const
  305. {
  306. return m_options.begin();
  307. }
  308. inline cmdargs::const_options_iterator cmdargs::options_end() const
  309. {
  310. return m_options.end();
  311. }
  312. inline cmdargs::const_values_iterator cmdargs::values_begin() const
  313. {
  314. return m_values.begin();
  315. }
  316. inline cmdargs::const_values_iterator cmdargs::values_end() const
  317. {
  318. return m_values.end();
  319. }
  320. inline cmdargs::size_type cmdargs::options_size() const
  321. {
  322. return m_options.size();
  323. }
  324. inline cmdargs::size_type cmdargs::values_size() const
  325. {
  326. return m_values.size();
  327. }
  328. inline cmdargs::size_type cmdargs::size() const
  329. {
  330. return options_size() + values_size();
  331. }
  332. inline cmdargs::bool_type cmdargs::empty() const
  333. {
  334. return 0 == size();
  335. }
  336. inline cmdargs::values_type::const_iterator cmdargs::has_value_(char const* valueName) const
  337. {
  338. STLSOFT_ASSERT(NULL != valueName);
  339. values_type::const_iterator b;
  340. for(b = m_values.begin(); b != m_values.end(); ++b)
  341. {
  342. if((*b).name == valueName)
  343. {
  344. break;
  345. }
  346. }
  347. return b;
  348. }
  349. inline cmdargs::options_type::const_iterator cmdargs::has_option_(char const* optionName, int type) const
  350. {
  351. STLSOFT_ASSERT(NULL != optionName);
  352. options_type::const_iterator b;
  353. for(b = m_options.begin(); b != m_options.end(); ++b)
  354. {
  355. if( (*b).name == optionName &&
  356. ( -1 == type ||
  357. type == (*b).type))
  358. {
  359. break;
  360. }
  361. }
  362. return b;
  363. }
  364. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  365. template <ss_typename_param_k S>
  366. inline S& operator <<(S &stm, cmdargs::option const& option)
  367. {
  368. static const char s_dashes[] =
  369. {
  370. '-'
  371. , '-'
  372. , '\0'
  373. };
  374. char const *dashes = &s_dashes[(option.type == cmdargs::singleDash)];
  375. if(option.value.empty())
  376. {
  377. stm << dashes << option.name;
  378. }
  379. else
  380. {
  381. stm << dashes << option.name << '=' << option.value;
  382. }
  383. return stm;
  384. }
  385. template <ss_typename_param_k S>
  386. inline S& operator <<(S &stm, cmdargs::value const& value)
  387. {
  388. stm << value.name;
  389. return stm;
  390. }
  391. /* ////////////////////////////////////////////////////////////////////// */
  392. #ifndef _STLSOFT_NO_NAMESPACE
  393. } // namespace stlsoft
  394. #endif /* _STLSOFT_NO_NAMESPACE */
  395. /* ////////////////////////////////////////////////////////////////////// */
  396. #endif /* !STLSOFT_INCL_STLSOFT_SYSTEM_HPP_CMDARGS */
  397. /* ///////////////////////////// end of file //////////////////////////// */