1 /******************************************************************************
2 * Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following
8 * conditions are met:
9 *
10 *     * Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *       notice, this list of conditions and the following disclaimer in
14 *       the documentation and/or other materials provided
15 *       with the distribution.
16 *     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
17 *       names of its contributors may be used to endorse or promote
18 *       products derived from this software without specific prior
19 *       written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * OF SUCH DAMAGE.
33 ****************************************************************************/
34 
35 #pragma once
36 
37 #include <pdal/pdal_internal.hpp>
38 #include <pdal/Metadata.hpp>
39 #include <pdal/util/Utils.hpp>
40 
41 #include <map>
42 #include <memory>
43 #include <vector>
44 
45 namespace pdal
46 {
47 
48 class Options;
49 class Option;
50 
51 class PDAL_DLL Option
52 {
53     PDAL_DLL friend std::ostream&
54         operator<<(std::ostream& ostr, const Option&);
55 public:
56 
57 /// @name Constructors
58 
Option()59     Option()
60     {}
61 
62     /// Primary constructor
63     template <typename T>
Option(std::string const & name,const T & value)64     Option(std::string const& name, const T& value) : m_name(name)
65     {
66         m_value = Utils::toString(value);
67     }
68 
Option(std::string const & name,const std::string & value)69     Option(std::string const& name, const std::string& value) : m_name(name), m_value(value)
70     {}
71 
Option(std::string const & name,const double & value)72     Option(std::string const& name, const double& value) : m_name(name)
73     {
74         m_value = Utils::toString(value, 15);
75     }
76 
Option(std::string const & name,const bool & value)77     Option(std::string const& name, const bool& value) :
78         m_name(name)
79     {
80         m_value = value ? "true" : "false";
81     }
82 
83     /// @return the name for the Option instance
getName() const84     std::string const& getName() const
85     {
86         return m_name;
87     }
88 
89     static std::string::size_type
parse(const std::string & name,std::string::size_type p)90     parse(const std::string& name, std::string::size_type p)
91     {
92         std::string::size_type count = 0;
93 
94         if (std::islower(name[p++]))
95         {
96             count++;
97 
98             auto isname = [](char c)
99                 { return (std::islower(c) || std::isdigit(c) || c == '_'); };
100             count += Utils::extract(name, p, isname);
101         }
102         return count;
103     }
104 
105     std::string toArg() const;
106 
107     // Make sure that the option name consists of lowercase characters or
108     // underscores.
109     static bool nameValid(const std::string& name, bool reportError);
110 
111     /// @return the value of the Option.
getValue() const112     std::string getValue() const
113         { return m_value; }
114 
115     bool empty() const;
116 
117     void toMetadata(MetadataNode& parent) const;
118 
119 /// @name Private attributes
120 private:
121     std::string m_name;
122     std::string m_value;
123 };
124 
125 
126 class PDAL_DLL Options
127 {
128     PDAL_DLL friend std::ostream&
129         operator<<(std::ostream& ostr, const Options&);
130 public:
Options()131     Options()
132     {}
133 
Options(const Option & opt)134     explicit Options(const Option& opt)
135         { add(opt); }
136 
137     void add(const Option& option);
138     void add(const Options& options);
139     void addConditional(const Option& option);
140     void addConditional(const Options& option);
141 
142     // if option name not present, just returns
143     void remove(const Option& option);
144 
replace(const Option & option)145     void replace(const Option& option)
146     {
147         remove(option);
148         add(option);
149     }
150 
toMetadata(MetadataNode & parent) const151     void toMetadata(MetadataNode& parent) const
152     {
153         for (std::string& k : getKeys())
154         {
155             StringList l = getValues(k);
156             std::string vs;
157             for (auto vi = l.begin(); vi != l.end(); ++vi)
158             {
159                if (vi != l.begin())
160                    vs += ", ";
161                vs += *vi;
162             }
163 
164             // 'userData' keys on stages and such are JSON
165             if (!Utils::iequals(k, "user_data"))
166                 parent.add(k, vs);
167             else
168                 parent.addWithType(k, vs, "json", "User JSON");
169         }
170     }
171 
172     // add an option (shortcut version, bypass need for an Option object)
add(const std::string & name,T value)173     template<typename T> void add(const std::string& name, T value)
174     {
175         Option opt(name, value);
176         add(opt);
177     }
178 
add(const std::string & name,const std::string & value)179     void add(const std::string& name, const std::string& value)
180     {
181         Option opt(name, value);
182         add(opt);
183     }
184 
add(const std::string & name,const bool & value)185     void add(const std::string& name, const bool& value)
186     {
187         Option opt(name, value);
188         add(opt);
189     }
190 
replace(const std::string & name,T value)191     template<typename T> void replace(const std::string& name, T value)
192     {
193         Option opt(name, value);
194         replace(opt);
195     }
196 
replace(const std::string & name,const std::string & value)197     void replace(const std::string& name, const std::string& value)
198     {
199         Option opt(name, value);
200         replace(opt);
201     }
202 
replace(const std::string & name,const bool & value)203     void replace(const std::string& name, const bool& value)
204     {
205         Option opt(name, value);
206         replace(opt);
207     }
208 
getValues(const std::string & name) const209     StringList getValues(const std::string& name) const
210     {
211         StringList s;
212 
213         auto ops = getOptions(name);
214         for (Option& op : ops)
215             s.push_back(op.getValue());
216         return s;
217     }
218 
getKeys() const219     StringList getKeys() const
220     {
221         StringList keys;
222 
223         for (auto it = m_options.begin(); it != m_options.end();
224             it = m_options.upper_bound(it->first))
225         {
226             keys.push_back(it->first);
227         }
228         return keys;
229     }
230 
231     std::vector<Option> getOptions(std::string const& name="") const;
232     StringList toCommandLine() const;
233     static Options fromFile(const std::string& filename,
234         bool throwOnOpenError = true);
235 
236 private:
237     std::multimap<std::string, Option> m_options;
238 
239     static Options fromJsonFile(const std::string& filename,
240         const std::string& s);
241     static Options fromCmdlineFile(const std::string& filename,
242         const std::string& s);
243 };
244 typedef std::map<std::string, Options> OptionsMap;
245 
246 } // namespace pdal
247 
248