Line data Source code
1 : // Copyright (c) 2006-2022 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++ lib
35 : //
36 : #include <fstream>
37 : #include <functional>
38 : #include <map>
39 : #include <memory>
40 : #include <set>
41 :
42 :
43 :
44 : namespace advgetopt
45 : {
46 :
47 :
48 :
49 : enum class callback_action_t
50 : {
51 : created,
52 : updated,
53 : erased
54 : };
55 :
56 :
57 : enum class line_continuation_t
58 : {
59 : line_continuation_single_line, // no continuation support
60 : line_continuation_rfc_822, // like email/HTTP, whitespace at start of next line
61 : line_continuation_msdos, // '&' at end of line
62 : line_continuation_unix, // '\' at end of line
63 : line_continuation_fortran, // '&' at start of next line
64 : line_continuation_semicolon // ';' ends the _line_
65 : };
66 :
67 :
68 : typedef std::uint_fast16_t assignment_operator_t;
69 :
70 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_EQUAL = 0x0001; // a = b
71 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_COLON = 0x0002; // a: b
72 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_SPACE = 0x0004; // a b
73 :
74 : constexpr assignment_operator_t ASSIGNMENT_OPERATOR_MASK = 0x0007;
75 :
76 :
77 : typedef std::uint_fast16_t comment_t;
78 :
79 : constexpr comment_t COMMENT_NONE = 0x0000; // no support for comments
80 : constexpr comment_t COMMENT_INI = 0x0001; // ; comment
81 : constexpr comment_t COMMENT_SHELL = 0x0002; // # comment
82 : constexpr comment_t COMMENT_CPP = 0x0004; // // comment
83 :
84 : constexpr comment_t COMMENT_SAVE = 0x8000; // save comments along parameters
85 :
86 : constexpr comment_t COMMENT_MASK = 0x0007;
87 :
88 :
89 : typedef std::uint_fast16_t section_operator_t;
90 :
91 : constexpr section_operator_t SECTION_OPERATOR_NONE = 0x0000; // no support
92 : constexpr section_operator_t SECTION_OPERATOR_C = 0x0001; // a.b
93 : constexpr section_operator_t SECTION_OPERATOR_CPP = 0x0002; // a::b
94 : constexpr section_operator_t SECTION_OPERATOR_BLOCK = 0x0004; // a { ... }
95 : constexpr section_operator_t SECTION_OPERATOR_INI_FILE = 0x0008; // [a]
96 :
97 : constexpr section_operator_t SECTION_OPERATOR_ONE_SECTION = 0x8000; // accept at most 1 section
98 :
99 : constexpr section_operator_t SECTION_OPERATOR_MASK = 0x000F;
100 :
101 :
102 : typedef std::uint_fast16_t name_separator_t;
103 :
104 : constexpr name_separator_t NAME_SEPARATOR_UNDERSCORES = 0x0001; // output underscore ('_') instead of dashes
105 : constexpr name_separator_t NAME_SEPARATOR_DASHES = 0x0002; // output dashes ('-')
106 :
107 :
108 28890 : class conf_file_setup
109 : {
110 : public:
111 : conf_file_setup(
112 : std::string const & filename
113 : , line_continuation_t line_continuation = line_continuation_t::line_continuation_unix
114 : , assignment_operator_t assignment_operator = ASSIGNMENT_OPERATOR_EQUAL
115 : , comment_t comment = COMMENT_INI | COMMENT_SHELL
116 : , section_operator_t section_operator = SECTION_OPERATOR_INI_FILE
117 : , name_separator_t name_separator = NAME_SEPARATOR_UNDERSCORES);
118 :
119 : bool is_valid() const;
120 : std::string const & get_original_filename() const;
121 : std::string const & get_filename() const;
122 : line_continuation_t get_line_continuation() const;
123 : assignment_operator_t get_assignment_operator() const;
124 : comment_t get_comment() const;
125 : section_operator_t get_section_operator() const;
126 : std::string get_config_url() const;
127 : name_separator_t get_name_separator() const;
128 :
129 : private:
130 : std::string f_original_filename = std::string();
131 : std::string f_filename = std::string();
132 : line_continuation_t f_line_continuation = line_continuation_t::line_continuation_unix;
133 : assignment_operator_t f_assignment_operator = ASSIGNMENT_OPERATOR_EQUAL;
134 : comment_t f_comment = COMMENT_INI | COMMENT_SHELL;
135 : section_operator_t f_section_operator = SECTION_OPERATOR_INI_FILE;
136 : mutable std::string f_url = std::string();
137 : name_separator_t f_name_separator = NAME_SEPARATOR_UNDERSCORES;
138 : };
139 :
140 :
141 620 : class parameter_value
142 : {
143 : public:
144 : parameter_value();
145 : parameter_value(parameter_value const & rhs);
146 : parameter_value(std::string const & value);
147 :
148 : parameter_value & operator = (parameter_value const & rhs);
149 : parameter_value & operator = (std::string const & value);
150 : operator std::string () const;
151 :
152 : void set_value(std::string const & value);
153 : void set_comment(std::string const & comment);
154 : void set_line(int line);
155 :
156 : std::string const & get_value() const;
157 : std::string get_comment(bool ensure_newline = false) const;
158 : int get_line() const;
159 :
160 : private:
161 : std::string f_value = std::string();
162 : std::string f_comment = std::string();
163 : int f_line = 0;
164 : };
165 :
166 :
167 324 : class conf_file
168 : : public std::enable_shared_from_this<conf_file>
169 : {
170 : public:
171 : typedef std::shared_ptr<conf_file> pointer_t;
172 : typedef std::set<std::string> sections_t;
173 : typedef std::map<std::string, parameter_value> parameters_t;
174 : typedef std::function<void(
175 : pointer_t conf_file
176 : , callback_action_t action
177 : , std::string const & parameter_name
178 : , std::string const & value)> callback_t;
179 : typedef int callback_id_t;
180 :
181 : static pointer_t get_conf_file(conf_file_setup const & setup);
182 :
183 : bool save_configuration(
184 : std::string backup_extension = std::string(".bak")
185 : , bool replace_backup = false
186 : , bool prepend_warning = true
187 : , std::string output_filename = std::string());
188 :
189 : conf_file_setup const & get_setup() const;
190 : callback_id_t add_callback(
191 : callback_t const & c
192 : , std::string const & parameter_name = std::string());
193 : void remove_callback(callback_id_t id);
194 :
195 : bool exists() const;
196 : int get_errno() const;
197 :
198 : int section_to_variables(
199 : std::string const & section_name
200 : , variables::pointer_t var);
201 : void set_variables(variables::pointer_t variables);
202 : variables::pointer_t get_variables() const;
203 : sections_t get_sections() const;
204 : parameters_t get_parameters() const;
205 : bool has_parameter(std::string name) const;
206 : std::string get_parameter(std::string name) const;
207 : bool set_parameter(
208 : std::string section
209 : , std::string name
210 : , std::string const & value
211 : , std::string const & comment = std::string());
212 : bool erase_parameter(std::string name);
213 : void erase_all_parameters();
214 : bool was_modified() const;
215 :
216 : bool is_assignment_operator(int c) const;
217 : bool is_comment(char const * s) const;
218 :
219 : private:
220 16 : struct callback_entry_t
221 : {
222 2 : callback_entry_t(
223 : callback_id_t id
224 : , callback_t const & c
225 : , std::string const & name)
226 2 : : f_id(id)
227 : , f_callback(c)
228 2 : , f_parameter_name(name)
229 : {
230 2 : }
231 :
232 : callback_id_t f_id = 0;
233 : callback_t f_callback = callback_t();
234 : std::string f_parameter_name = std::string();
235 : };
236 : typedef std::vector<callback_entry_t>
237 : callback_vector_t;
238 :
239 : conf_file(conf_file_setup const & setup);
240 :
241 : int getc(std::ifstream & stream);
242 : void ungetc(int c);
243 : bool get_line(std::ifstream & stream, std::string & line);
244 : void read_configuration();
245 : void value_changed(
246 : callback_action_t action
247 : , std::string const & parameter_name
248 : , std::string const & value);
249 :
250 : conf_file_setup const f_setup;
251 :
252 : int f_unget_char = '\0';
253 : int f_line = 0;
254 : int f_errno = 0;
255 : bool f_reading = false;
256 : bool f_exists = false;
257 :
258 : bool f_modified = false;
259 : sections_t f_sections = sections_t();
260 : variables::pointer_t f_variables = variables::pointer_t();
261 : parameters_t f_parameters = parameters_t();
262 : callback_vector_t f_callbacks = callback_vector_t();
263 : callback_id_t f_next_callback_id = 0;
264 : };
265 :
266 :
267 : bool iswspace(int c);
268 :
269 :
270 : } // namespace advgetopt
271 : // vim: ts=4 sw=4 et
|