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#include <snapdev/stringize.h>
40
41
42// libexcept
43//
44#include <libexcept/file_inheritance.h>
45
46
47// C++
48//
49#include <iostream>
50
51
52// C
53//
54#include <unistd.h>
55
56
57// last include
58//
59#include <snapdev/poison.h>
60
61
62
64{
66 advgetopt::Name("colon")
69 , advgetopt::Help("Accept a colon as the assignment operator.")
70 ),
72 advgetopt::Name("create-backup")
76 , advgetopt::Help("Create a backup before updating the configuration file. If the file exists, keep that old backup instead.")
77 ),
79 advgetopt::Name("dashes")
82 , advgetopt::Help("Output parameter names with dashes.")
83 ),
85 advgetopt::Name("equal")
88 , advgetopt::Help("Accept an equal sign as the assignment operator (this is the default is not assignment is specified).")
89 ),
91 advgetopt::Name("must-exist")
94 , advgetopt::Help("If the value does not exist, an error is printed and the process exits with 1.")
95 ),
97 advgetopt::Name("no-warning")
100 , 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.")
101 ),
103 advgetopt::Name("priority")
107 , advgetopt::Help("Priority when saving file under a sub-directory.")
108 ),
110 advgetopt::Name("remove-comments")
113 , advgetopt::Help("By default, the tool tries to keep the comments intact. Use this flag to remove comments.")
114 ),
116 advgetopt::Name("replace-backup")
120 , advgetopt::Help("Create a backup before updating the configuration file. If the file exists, replace it.")
121 ),
123 advgetopt::Name("space")
126 , advgetopt::Help("Accept just a space as the assignment operator.")
127 ),
129 advgetopt::Name("sub-directory")
133 , 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.")
134 , advgetopt::EnvironmentVariableName("SUBDIRECTORY")
135 ),
137 advgetopt::Name("underscores")
140 , advgetopt::Help("Output parameter names with underscores (default).")
141 ),
143 advgetopt::Name("--")
147 , advgetopt::Help("Configuration filename, field name, optionally, a new value.")
148 ),
150};
151
152
153
154
169
170
171// until we have C++20 remove warnings this way
172#pragma GCC diagnostic push
173#pragma GCC diagnostic ignored "-Wpedantic"
175{
176 .f_project_name = "advgetopt",
177 .f_group_name = nullptr,
178 .f_options = g_options,
179 .f_options_files_directory = nullptr,
181 .f_environment_variable_intro = "EDIT_CONFIG_",
182 .f_section_variables_name = nullptr,
183 .f_configuration_files = nullptr,
184 .f_configuration_filename = nullptr,
185 .f_configuration_directories = nullptr,
187 .f_help_header = "Usage: %p [-<opt>] <configuration filename> <field name> [<new value>]\n"
188 "where -<opt> is one or more of:",
189 .f_help_footer = "%c",
190 .f_version = LIBADVGETOPT_VERSION_STRING,
191 .f_license = "GNU GPL v2",
192 .f_copyright = "Copyright (c) 2013-"
193 SNAPDEV_STRINGIZE(UTC_BUILD_YEAR)
194 " by Made to Order Software Corporation -- All Rights Reserved",
195 .f_build_date = UTC_BUILD_DATE,
196 .f_build_time = UTC_BUILD_TIME,
197 .f_groups = g_group_descriptions,
198};
199#pragma GCC diagnostic pop
200
201
202
203
204
206{
207public:
208 edit_config(int argc, char * argv[]);
209
210 void run();
211
212private:
214};
215
216
226edit_config::edit_config(int argc, char * argv[])
227 : f_opt(g_options_environment, argc, argv)
228{
229 if(f_opt.is_defined("create-backup")
230 && f_opt.is_defined("replace-backup"))
231 {
232 std::cerr
234 << ":error: the --create-backup and --replace-backup command line options are mutually exclusive."
235 << std::endl;
236 exit(1);
237 }
238
239 if(!f_opt.is_defined("--"))
240 {
241 std::cerr
243 << ":error: no configuration name, field name, and value defined."
244 << std::endl;
245 exit(1);
246 }
247
248 int const sz(f_opt.size("--"));
249
250 if(sz < 2)
251 {
252 std::cerr << f_opt.get_program_name() << ":error: to the minimum a configuration name and a field name are required." << std::endl;
253 exit(1);
254 }
255
256 if(sz > 3)
257 {
258 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;
259 exit(1);
260 }
261}
262
263
271{
272 std::string config_name(f_opt.get_string("--", 0));
273
274 std::string sub_directory_name;
275 if(f_opt.is_defined("sub-directory"))
276 {
278 advgetopt::split_string(config_name, segments, { "/" });
279 std::string filename(segments.back());
280 segments.pop_back();
281 segments.push_back(f_opt.get_string("sub-directory"));
282 if(f_opt.is_defined("priority"))
283 {
284 segments.push_back(f_opt.get_string("priority") + '-' + filename);
285 }
286 else
287 {
288 segments.push_back(filename);
289 }
290
291 sub_directory_name = snapdev::join_strings(segments, "/");
292 if(access(sub_directory_name.c_str(), F_OK) == 0)
293 {
294 config_name = sub_directory_name;
295 }
296 }
297
298 advgetopt::assignment_operator_t assignment_operator(0);
299
300 if(f_opt.is_defined("colon"))
301 {
302 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_COLON;
303 }
304 if(f_opt.is_defined("equal"))
305 {
306 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_EQUAL;
307 }
308 if(f_opt.is_defined("space"))
309 {
310 assignment_operator |= advgetopt::ASSIGNMENT_OPERATOR_SPACE;
311 }
312
314 if(f_opt.is_defined("dashes"))
315 {
316 if(f_opt.is_defined("underscore"))
317 {
318 std::cerr << "error: --dashes & --underscores are mutually exclusive.\n";
319 exit(1);
320 }
321 name_separator = advgetopt::NAME_SEPARATOR_DASHES;
322 }
323
325 config_name
327 , assignment_operator
330 | (f_opt.is_defined("remove-comments")
331 ? 0
334 , name_separator);
336
337 std::string const field_name(f_opt.get_string("--", 1));
338
339 if(f_opt.is_defined("must-exist")
340 && !config->has_parameter(field_name))
341 {
342 std::cerr << "error: field \""
343 << field_name
344 << "\" not found in \""
345 << config_name
346 << "\".\n";
347 exit(1);
348 }
349
350 if(f_opt.size("--") == 2)
351 {
352 // retrieval, get the value and print to std::cout
353 //
354 if(config->has_parameter(field_name))
355 {
356 std::cout << config->get_parameter(field_name) << std::endl;
357 }
358 else
359 {
360 std::cout << std::endl;
361 }
362 }
363 else
364 {
365 std::string const new_value(f_opt.get_string("--", 2));
366
367 std::string::size_type colon(field_name.rfind(':'));
368 if(colon != std::string::npos)
369 {
370 std::string const name_only(field_name.substr(colon + 1));
371 while(colon > 0
372 && field_name[colon - 1] == ':')
373 {
374 --colon;
375 }
376 std::string const sections(field_name.substr(0, colon));
377 config->set_parameter(sections, name_only, new_value);
378 }
379 else
380 {
381 config->set_parameter(std::string(), field_name, new_value);
382 }
383
384 bool replace_backup(false);
385 std::string backup_extension;
386 if(f_opt.is_defined("create-backup"))
387 {
388 backup_extension = f_opt.get_string("create-backup");
389 }
390 else if(f_opt.is_defined("replace-backup"))
391 {
392 replace_backup = true;
393 backup_extension = f_opt.get_string("replace-backup");
394 }
395 config->save_configuration(
396 backup_extension
397 , replace_backup
398 , !f_opt.is_defined("no-warning")
399 , sub_directory_name);
400 }
401}
402
403
404
405
406
407int main(int argc, char * argv[])
408{
409 libexcept::verify_inherited_files();
410
411 try
412 {
413 edit_config s(argc, argv);
414 s.run();
415 return 0;
416 }
417 catch( advgetopt::getopt_exit const & except )
418 {
419 return except.code();
420 }
421 catch(std::exception const & e)
422 {
423 std::cerr << "edit-config: exception: " << e.what() << std::endl;
424 return 1;
425 }
426}
427
428// 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.