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