Line data Source code
1 : // Copyright (c) 2006-2024 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/advgetopt 4 : // contact@m2osw.com 5 : // 6 : // This program is free software; you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation; either version 2 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License along 17 : // with this program; if not, write to the Free Software Foundation, Inc., 18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 : #pragma once 20 : 21 : /** \file 22 : * \brief Declaration of the conf_file class used to read a configuration file. 23 : * 24 : * The library offers a way to read a configuration file parameters without 25 : * doing anything more than that. The getopt class uses it to read and verify 26 : * the parameters. It also uses it to read files of configuration options. 27 : */ 28 : 29 : // self 30 : // 31 : #include <advgetopt/variables.h> 32 : 33 : 34 : // C++ 35 : // 36 : #include <cstdint> 37 : #include <fstream> 38 : #include <functional> 39 : #include <map> 40 : #include <memory> 41 : #include <set> 42 : 43 : 44 : 45 : namespace advgetopt 46 : { 47 : 48 : 49 : 50 : enum class callback_action_t 51 : { 52 : created, 53 : updated, 54 : erased 55 : }; 56 : 57 : 58 : enum class line_continuation_t 59 : { 60 : line_continuation_single_line, // no continuation support 61 : line_continuation_rfc_822, // like email/HTTP, whitespace at start of next line 62 : line_continuation_msdos, // '&' at end of line 63 : line_continuation_unix, // '\' at end of line 64 : line_continuation_fortran, // '&' at start of next line 65 : line_continuation_semicolon // ';' ends the _line_ 66 : }; 67 : 68 : 69 : typedef std::uint_fast16_t assignment_operator_t; 70 : 71 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_EQUAL = 0x0001; // a = b 72 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_COLON = 0x0002; // a: b 73 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_SPACE = 0x0004; // a b 74 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_EXTENDED = 0x0008; // a += b AND a ?= b 75 : 76 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_MASK = 0x000F; 77 : 78 : 79 : typedef std::uint_fast16_t comment_t; 80 : 81 : constexpr comment_t COMMENT_NONE = 0x0000; // no support for comments 82 : constexpr comment_t COMMENT_INI = 0x0001; // ; comment 83 : constexpr comment_t COMMENT_SHELL = 0x0002; // # comment 84 : constexpr comment_t COMMENT_CPP = 0x0004; // // comment 85 : 86 : constexpr comment_t COMMENT_SAVE = 0x8000; // save comments along parameters 87 : 88 : constexpr comment_t COMMENT_MASK = 0x0007; 89 : 90 : 91 : typedef std::uint_fast16_t section_operator_t; 92 : 93 : constexpr section_operator_t SECTION_OPERATOR_NONE = 0x0000; // no support 94 : constexpr section_operator_t SECTION_OPERATOR_C = 0x0001; // a.b 95 : constexpr section_operator_t SECTION_OPERATOR_CPP = 0x0002; // a::b 96 : constexpr section_operator_t SECTION_OPERATOR_BLOCK = 0x0004; // a { ... } 97 : constexpr section_operator_t SECTION_OPERATOR_INI_FILE = 0x0008; // [a] 98 : 99 : constexpr section_operator_t SECTION_OPERATOR_ONE_SECTION = 0x8000; // accept at most 1 section 100 : 101 : constexpr section_operator_t SECTION_OPERATOR_MASK = 0x000F; 102 : 103 : 104 : typedef std::uint_fast16_t name_separator_t; 105 : 106 : constexpr name_separator_t NAME_SEPARATOR_UNDERSCORES = 0x0001; // output underscore ('_') instead of dashes 107 : constexpr name_separator_t NAME_SEPARATOR_DASHES = 0x0002; // output dashes ('-') 108 : 109 : 110 : class conf_file_setup 111 : { 112 : public: 113 : typedef std::shared_ptr<conf_file_setup> pointer_t; 114 : 115 : conf_file_setup( 116 : std::string const & filename 117 : , line_continuation_t line_continuation = line_continuation_t::line_continuation_unix 118 : , assignment_operator_t assignment_operator = ASSIGNMENT_OPERATOR_EQUAL 119 : , comment_t comment = COMMENT_INI | COMMENT_SHELL 120 : , section_operator_t section_operator = SECTION_OPERATOR_INI_FILE 121 : , name_separator_t name_separator = NAME_SEPARATOR_UNDERSCORES); 122 : conf_file_setup( 123 : std::string const & filename 124 : , conf_file_setup const & original); 125 : 126 : bool is_valid() const; 127 : std::string const & get_original_filename() const; 128 : std::string const & get_filename() const; 129 : line_continuation_t get_line_continuation() const; 130 : assignment_operator_t get_assignment_operator() const; 131 : comment_t get_comment() const; 132 : section_operator_t get_section_operator() const; 133 : std::string get_config_url() const; 134 : name_separator_t get_name_separator() const; 135 : void set_section_to_ignore(std::string const & section_name); 136 : std::string const & get_section_to_ignore() const; 137 : 138 : private: 139 : void initialize(); 140 : 141 : std::string f_original_filename = std::string(); 142 : std::string f_filename = std::string(); 143 : std::string f_section_to_ignore = std::string(); 144 : line_continuation_t f_line_continuation = line_continuation_t::line_continuation_unix; 145 : assignment_operator_t f_assignment_operator = ASSIGNMENT_OPERATOR_EQUAL; 146 : comment_t f_comment = COMMENT_INI | COMMENT_SHELL; 147 : section_operator_t f_section_operator = SECTION_OPERATOR_INI_FILE; 148 : mutable std::string f_url = std::string(); 149 : name_separator_t f_name_separator = NAME_SEPARATOR_UNDERSCORES; 150 : }; 151 : 152 : 153 : class parameter_value 154 : { 155 : public: 156 : parameter_value(); 157 : parameter_value(parameter_value const & rhs); 158 : parameter_value(std::string const & value); 159 : 160 : parameter_value & operator = (parameter_value const & rhs); 161 : parameter_value & operator = (std::string const & value); 162 : operator std::string () const; 163 : 164 : void set_value(std::string const & value); 165 : void set_comment(std::string const & comment); 166 : void set_line(int line); 167 : void set_assignment_operator(assignment_t a); 168 : 169 : std::string const & get_value() const; 170 : std::string get_comment(bool ensure_newline = false) const; 171 : int get_line() const; 172 : assignment_t get_assignment_operator() const; 173 : 174 : private: 175 : std::string f_value = std::string(); 176 : std::string f_comment = std::string(); 177 : int f_line = 0; 178 : assignment_t f_assignment_operator = assignment_t::ASSIGNMENT_SET; 179 : }; 180 : 181 : 182 : class conf_file 183 : : public std::enable_shared_from_this<conf_file> 184 : { 185 : public: 186 : typedef std::shared_ptr<conf_file> pointer_t; 187 : typedef string_set_t sections_t; 188 : typedef std::map<std::string, parameter_value> parameters_t; 189 : typedef std::function<void( 190 : pointer_t conf_file 191 : , callback_action_t action 192 : , std::string const & parameter_name 193 : , std::string const & value)> callback_t; 194 : typedef int callback_id_t; 195 : 196 : static pointer_t get_conf_file(conf_file_setup const & setup); 197 : static void reset_conf_files(); 198 : 199 : bool save_configuration( 200 : std::string backup_extension = std::string(".bak") 201 : , bool replace_backup = false 202 : , bool prepend_warning = true 203 : , std::string output_filename = std::string()); 204 : 205 : conf_file_setup const & get_setup() const; 206 : callback_id_t add_callback( 207 : callback_t const & c 208 : , std::string const & parameter_name = std::string()); 209 : void remove_callback(callback_id_t id); 210 : 211 : bool exists() const; 212 : int get_errno() const; 213 : 214 : int section_to_variables( 215 : std::string const & section_name 216 : , variables::pointer_t var); 217 : void set_variables(variables::pointer_t variables); 218 : variables::pointer_t get_variables() const; 219 : sections_t get_sections() const; 220 : parameters_t get_parameters() const; 221 : bool has_parameter(std::string name) const; 222 : std::string get_parameter(std::string name) const; 223 : bool set_parameter( 224 : std::string section 225 : , std::string name 226 : , std::string const & value 227 : , assignment_t op = assignment_t::ASSIGNMENT_NONE 228 : , std::string const & comment = std::string()); 229 : bool erase_parameter(std::string name); 230 : void erase_all_parameters(); 231 : bool was_modified() const; 232 : 233 : assignment_t is_assignment_operator(char const * & s, bool skip) const; 234 : bool is_comment(char const * s) const; 235 : 236 : private: 237 : struct callback_entry_t 238 : { 239 2 : callback_entry_t( 240 : callback_id_t id 241 : , callback_t const & c 242 : , std::string const & name) 243 2 : : f_id(id) 244 2 : , f_callback(c) 245 2 : , f_parameter_name(name) 246 : { 247 2 : } 248 : 249 : callback_id_t f_id = 0; 250 : callback_t f_callback = callback_t(); 251 : std::string f_parameter_name = std::string(); 252 : }; 253 : typedef std::vector<callback_entry_t> 254 : callback_vector_t; 255 : 256 : conf_file(conf_file_setup const & setup); 257 : 258 : int getc(std::ifstream & stream); 259 : void ungetc(int c); 260 : bool get_line(std::ifstream & stream, std::string & line); 261 : void read_configuration(); 262 : void value_changed( 263 : callback_action_t action 264 : , std::string const & parameter_name 265 : , std::string const & value); 266 : 267 : conf_file_setup const f_setup; 268 : 269 : int f_unget_char = '\0'; 270 : int f_line = 0; 271 : int f_errno = 0; 272 : bool f_reading = false; 273 : bool f_exists = false; 274 : 275 : bool f_modified = false; 276 : sections_t f_sections = sections_t(); 277 : variables::pointer_t f_variables = variables::pointer_t(); 278 : parameters_t f_parameters = parameters_t(); 279 : callback_vector_t f_callbacks = callback_vector_t(); 280 : callback_id_t f_next_callback_id = 0; 281 : }; 282 : 283 : 284 : bool iswspace(int c); 285 : 286 : 287 : } // namespace advgetopt 288 : // vim: ts=4 sw=4 et