1 
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29 
30 #pragma once
31 
32 // appleseed.foundation headers.
33 #include "foundation/core/concepts/noncopyable.h"
34 #include "foundation/utility/foreach.h"
35 
36 // Standard headers.
37 #include <cassert>
38 #include <cstddef>
39 #include <string>
40 #include <vector>
41 
42 // Forward declarations.
43 namespace foundation    { class ParseResults; }
44 
45 namespace foundation
46 {
47 
48 //
49 // A vector of strings.
50 //
51 
52 typedef std::vector<std::string> StringVector;
53 
54 
55 //
56 // Base class for option handlers.
57 //
58 
59 class OptionHandler
60   : public NonCopyable
61 {
62   public:
63     // Flags.
64     enum Flags
65     {
66         None        = 0,            // none of the flags below are set
67         Required    = 1UL << 0,     // this option is required and must appear on the command line
68         Hidden      = 1UL << 1,     // don't list this option in program usage
69         Repeatable  = 1UL << 2      // this option can appear multiple times on a command line
70     };
71 
72     // Constructor.
73     OptionHandler();
74 
75     // Add a name for this option.
76     OptionHandler& add_name(const std::string& name);
77 
78     // Return the first name of the option.
79     const std::string& get_name() const;
80 
81     // Set a description of this option.
82     OptionHandler& set_description(const std::string& description);
83 
84     // Set the syntax for this option.
85     OptionHandler& set_syntax(const std::string& syntax);
86 
87     // Set the flags for this option.
88     OptionHandler& set_flags(const Flags flags);
89 
90     // Return true if this option is set.
91     virtual bool is_set() const;
92 
93   protected:
94     friend class CommandLineParser;
95 
96     StringVector    m_names;
97     std::string     m_description;
98     std::string     m_syntax;
99     Flags           m_flags;
100     size_t          m_occurrence_count;
101 
102     // Return a description of this option.
103     // The returned value may be different than what was set with set_description().
104     virtual std::string get_description() const;
105 
106     // Return the maximum number of values this option can handle.
107     virtual size_t get_max_value_count() const = 0;
108 
109     // Parse a vector of values.
110     virtual void parse(
111         const std::string&      name,
112         const StringVector&     values,
113         ParseResults&           results) = 0;
114 
115     // Print this option to a string.
116     virtual void print(std::string& s) const = 0;
117 
118     // Return true if an argument matches any of the name of this option.
119     bool match_name(const std::string& arg) const;
120 };
121 
122 
123 //
124 // OptionHandler class implementation.
125 //
126 
OptionHandler()127 inline OptionHandler::OptionHandler()
128   : m_flags(None)
129   , m_occurrence_count(0)
130 {
131 }
132 
add_name(const std::string & name)133 inline OptionHandler& OptionHandler::add_name(const std::string& name)
134 {
135     m_names.push_back(name);
136     return *this;
137 }
138 
get_name()139 inline const std::string& OptionHandler::get_name() const
140 {
141     assert(!m_names.empty());
142     return m_names[0];
143 }
144 
set_description(const std::string & description)145 inline OptionHandler& OptionHandler::set_description(const std::string& description)
146 {
147     m_description = description;
148     return *this;
149 }
150 
set_syntax(const std::string & syntax)151 inline OptionHandler& OptionHandler::set_syntax(const std::string& syntax)
152 {
153     m_syntax = syntax;
154     return *this;
155 }
156 
set_flags(const Flags flags)157 inline OptionHandler& OptionHandler::set_flags(const Flags flags)
158 {
159     m_flags = flags;
160     return *this;
161 }
162 
is_set()163 inline bool OptionHandler::is_set() const
164 {
165     return m_occurrence_count > 0;
166 }
167 
get_description()168 inline std::string OptionHandler::get_description() const
169 {
170     return m_description;
171 }
172 
match_name(const std::string & arg)173 inline bool OptionHandler::match_name(const std::string& arg) const
174 {
175     for (const_each<StringVector> i = m_names; i; ++i)
176     {
177         if (arg == *i)
178             return true;
179     }
180 
181     return false;
182 }
183 
184 }   // namespace foundation
185