advgetopt 2.0.49
Parse complex command line arguments and configuration files in C++.
edit_config.cpp
Go to the documentation of this file.
1// Copyright (c) 2006-2025 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
28// advgetopt
29//
30#include <advgetopt/advgetopt.h>
31#include <advgetopt/conf_file.h>
32#include <advgetopt/exception.h>
33#include <advgetopt/version.h>
34
35
36// snapdev
37//
38#include <snapdev/join_strings.h>
39
40
41// libexcept
42//
43#include <libexcept/file_inheritance.h>
44
45
46// boost
47//
48#include <boost/preprocessor/stringize.hpp>
49
50
51// C++
52//
53#include <iostream>
54
55
56// C
57//
58#include <unistd.h>
59
60
61// last include
62//
63#include <snapdev/poison.h>
64
65
66
68{
70 advgetopt::Name("colon")
73 , advgetopt::Help("Accept a colon as the assignment operator.")
74 ),
76 advgetopt::Name("create-backup")
80 , advgetopt::Help("Create a backup before updating the configuration file. If the file exists, keep that old backup instead.")
81 ),
83 advgetopt::Name("dashes")
86 , advgetopt::Help("Output parameter names with dashes.")
87 ),
89 advgetopt::Name("equal")
92 , advgetopt::Help("Accept an equal sign as the assignment operator (this is the default is not assignment is specified).")
93 ),
95 advgetopt::Name("must-exist")
98 , advgetopt::Help("If the value does not exist, an error is printed and the process exits with 1.")
99 ),
101 advgetopt::Name("no-warning")
104 , advgetopt::Help("By default, if the --remove-comments option is used, the tool writes a warning at the beginning of the file. Use this flag to avoid that warning.")
105 ),
107 advgetopt::Name("priority")
111 , advgetopt::Help("Priority when saving file under a sub-directory.")
112 ),
114 advgetopt::Name("remove-comments")
117 , advgetopt::Help("By default, the tool tries to keep the comments intact. Use this flag to remove comments.")
118 ),
120 advgetopt::Name("replace-backup")
124 , advgetopt::Help("Create a backup before updating the configuration file. If the file exists, replace it.")
125 ),
127 advgetopt::Name("space")
130 , advgetopt::Help("Accept just a space as the assignment operator.")
131 ),
133 advgetopt::Name("sub-directory")
137 , advgetopt::Help("If defined, try reading the file from that sub-directory. If not found there, try in the parent (as defined on the command line). Always save in that sub-directory if editing.")
138 , advgetopt::EnvironmentVariableName("SUBDIRECTORY")
139 ),
141 advgetopt::Name("underscores")
144 , advgetopt::Help("Output parameter names with underscores (default).")
145 ),
147 advgetopt::Name("--")
151 , advgetopt::Help("Configuration filename, field name, optionally, a new value.")
152 ),
154};
155
156
157
158
173
174
175// until we have C++20 remove warnings this way
176#pragma GCC diagnostic push
177#pragma GCC diagnostic ignored "-Wpedantic"
179{
180 .f_project_name = "advgetopt",
181 .f_group_name = nullptr,
182 .f_options = g_options,
183 .f_options_files_directory = nullptr,
185 .f_environment_variable_intro = "EDIT_CONFIG_",
186 .f_section_variables_name = nullptr,
187 .f_configuration_files = nullptr,
188 .f_configuration_filename = nullptr,
189 .f_configuration_directories = nullptr,
191 .f_help_header = "Usage: %p [-<opt>] <configuration filename> <field name> [<new value>]\n"
192 "where -<opt> is one or more of:",
193 .f_help_footer = "%c",
194 .f_version = LIBADVGETOPT_VERSION_STRING,
195 .f_license = "GNU GPL v2",
196 .f_copyright = "Copyright (c) 2013-"
197 BOOST_PP_STRINGIZE(UTC_BUILD_YEAR)
198 " by Made to Order Software Corporation -- All Rights Reserved",
199 .f_build_date = UTC_BUILD_DATE,
200 .f_build_time = UTC_BUILD_TIME,
201 .f_groups = g_group_descriptions,
202};
203#pragma GCC diagnostic pop
204
205
206
207
208
210{
211public:
212 edit_config(int argc, char * argv[]);
213
214 void run();
215
216private:
218};
219
220
230edit_config::edit_config(int argc, char * argv[])
231 : f_opt(g_options_environment, argc, argv)
232{
233 if(f_opt.is_defined("create-backup")
234 && f_opt.is_defined("replace-backup"))
235 {
236 std::cerr
238 << ":error: the --create-backup and --replace-backup command line options are mutually exclusive."
239 << std::endl;
240 exit(1);
241 }
242
243 if(!f_opt.is_defined("--"))
244 {
245 std::cerr
247 << ":error: no configuration name, field name, and value defined."
248 << std::endl;
249 exit(1);
250 }
251
252 int const sz(f_opt.size("--"));
253
254 if(sz < 2)
255 {
256 std::cerr << f_opt.get_program_name() << ":error: to the minimum a configuration name and a field name are required." << std::endl;
257 exit(1);
258 }
259
260 if(sz > 3)
261 {
262 std::cerr << f_opt.get_program_name() << ":error: to the maximum a configuration name, a field name, and a value can be defined." << std::endl;
263 exit(1);
264 }
265}
266
267
275{
276 std::string config_name(f_opt.get_string("--", 0));
277
278 std::string sub_directory_name;
279 if(f_opt.is_defined("sub-directory"))
280 {
282 advgetopt::split_string(config_name, segments, { "/" });
283 std::string filename(segments.back());
284 segments.pop_back();
285 segments.push_back(f_opt.get_string("sub-directory"));
286 if(f_opt.is_defined("priority"))
287 {
288 segments.push_back(f_opt.get_string("priority") + '-' + filename);
289 }
290 else
291 {
292 segments.push_back(filename);
293 }
294
295 sub_directory_name = snapdev::join_strings(segments, "/");
296 if(access(sub_directory_name.c_str(), F_OK) == 0)
297 {
298 config_name = sub_directory_name;
299 }
300 }
301
302 advgetopt::assignment_operator_t assignment_operator(0);
303
304 if(f_opt.is_defined("colon"))
305 {
306 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_COLON;
307 }
308 if(f_opt.is_defined("equal"))
309 {
310 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_EQUAL;
311 }
312 if(f_opt.is_defined("space"))
313 {
314 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_SPACE;
315 }
316
318 if(f_opt.is_defined("dashes"))
319 {
320 if(f_opt.is_defined("underscore"))
321 {
322 std::cerr << "error: --dashes & --underscores are mutually exclusive.\n";
323 exit(1);
324 }
325 name_separator = advgetopt::NAME_SEPARATOR_DASHES;
326 }
327
329 config_name
331 , assignment_operator
334 | (f_opt.is_defined("remove-comments")
335 ? 0
338 , name_separator);
340
341 std::string const field_name(f_opt.get_string("--", 1));
342
343 if(f_opt.is_defined("must-exist")
344 && !config->has_parameter(field_name))
345 {
346 std::cerr << "error: field \""
347 << field_name
348 << "\" not found in \""
349 << config_name
350 << "\".\n";
351 exit(1);
352 }
353
354 if(f_opt.size("--") == 2)
355 {
356 // retrieval, get the value and print to std::cout
357 //
358 if(config->has_parameter(field_name))
359 {
360 std::cout << config->get_parameter(field_name) << std::endl;
361 }
362 else
363 {
364 std::cout << std::endl;
365 }
366 }
367 else
368 {
369 std::string const new_value(f_opt.get_string("--", 2));
370
371 std::string::size_type colon(field_name.rfind(':'));
372 if(colon != std::string::npos)
373 {
374 std::string const name_only(field_name.substr(colon + 1));
375 while(colon > 0
376 && field_name[colon - 1] == ':')
377 {
378 --colon;
379 }
380 std::string const sections(field_name.substr(0, colon));
381 config->set_parameter(sections, name_only, new_value);
382 }
383 else
384 {
385 config->set_parameter(std::string(), field_name, new_value);
386 }
387
388 bool replace_backup(false);
389 std::string backup_extension;
390 if(f_opt.is_defined("create-backup"))
391 {
392 backup_extension = f_opt.get_string("create-backup");
393 }
394 else if(f_opt.is_defined("replace-backup"))
395 {
396 replace_backup = true;
397 backup_extension = f_opt.get_string("replace-backup");
398 }
399 config->save_configuration(
400 backup_extension
401 , replace_backup
402 , !f_opt.is_defined("no-warning")
403 , sub_directory_name);
404 }
405}
406
407
408
409
410
411int main(int argc, char * argv[])
412{
413 libexcept::verify_inherited_files();
414
415 try
416 {
417 edit_config s(argc, argv);
418 s.run();
419 return 0;
420 }
421 catch( advgetopt::getopt_exit const & except )
422 {
423 return except.code();
424 }
425 catch(std::exception const & e)
426 {
427 std::cerr << "edit-config: exception: " << e.what() << std::endl;
428 return 1;
429 }
430}
431
432// vim: ts=4 sw=4 et
Definitions of the advanced getopt class.
std::shared_ptr< conf_file > pointer_t
Definition conf_file.h:186
static pointer_t get_conf_file(conf_file_setup const &setup)
Create and read a conf_file.
Class used to parse command line options.
Definition advgetopt.h:77
std::string get_string(std::string const &name, int idx=0, bool raw=false) const
Get the content of an option as a string.
std::size_t size(std::string const &name) const
Retrieve the number of arguments.
bool is_defined(std::string const &name) const
Check whether a parameter is defined.
std::string get_program_name() const
Get the basename of the program.
void run()
Run the command.
edit_config(int argc, char *argv[])
Initialize the DNS options object.
advgetopt::getopt f_opt
Declaration of the conf_file class used to read a configuration file.
int main(int argc, char *argv[])
advgetopt::option const g_options[]
advgetopt::group_description const g_group_descriptions[]
advgetopt::options_environment const g_options_environment
Definitions of the advanced getopt exceptions.
constexpr group_description define_group(ARGS ...args)
Definition options.h:403
constexpr comment_t COMMENT_SAVE
Definition conf_file.h:86
void split_string(std::string const &str, string_list_t &result, string_list_t const &separators)
Split a string in sub-strings separated by separators.
Definition utils.cpp:347
constexpr group_description end_groups()
Definition options.h:419
constexpr section_operator_t SECTION_OPERATOR_INI_FILE
Definition conf_file.h:97
std::uint_fast16_t assignment_operator_t
Definition conf_file.h:69
static constexpr flag_t GETOPT_FLAG_GROUP_OPTIONS
Definition flags.h:72
constexpr option define_option(ARGS ...args)
Definition options.h:259
constexpr comment_t COMMENT_SHELL
Definition conf_file.h:83
constexpr flag_t command_flags()
Definition flags.h:191
constexpr option end_options()
Definition options.h:294
constexpr assignment_operator_t ASSIGNMENT_OPERATOR_EQUAL
Definition conf_file.h:71
constexpr name_separator_t NAME_SEPARATOR_DASHES
Definition conf_file.h:107
constexpr flag_t GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS
Definition options.h:435
static constexpr flag_t GETOPT_FLAG_GROUP_COMMANDS
Definition flags.h:71
constexpr assignment_operator_t ASSIGNMENT_OPERATOR_SPACE
Definition conf_file.h:73
constexpr flag_t all_flags()
Definition flags.h:154
constexpr name_separator_t NAME_SEPARATOR_UNDERSCORES
Definition conf_file.h:106
static constexpr flag_t GETOPT_FLAG_DEFAULT_OPTION
Definition flags.h:54
constexpr comment_t COMMENT_INI
Definition conf_file.h:82
static constexpr flag_t GETOPT_FLAG_MULTIPLE
Definition flags.h:53
static constexpr flag_t GETOPT_FLAG_REQUIRED
Definition flags.h:52
std::uint_fast16_t name_separator_t
Definition conf_file.h:104
constexpr flag_t standalone_all_flags()
Definition flags.h:166
std::vector< std::string > string_list_t
Definition utils.h:41
constexpr assignment_operator_t ASSIGNMENT_OPERATOR_COLON
Definition conf_file.h:72
Structure representing an option.
Definition options.h:70
char const * f_environment_variable_name
Definition options.h:74
Definitions of the advanced getopt class version.
#define LIBADVGETOPT_VERSION_STRING
Definition version.h:32

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.