advgetopt 2.0.49
Parse complex command line arguments and configuration files in C++.
build_file_of_options.cpp
Go to the documentation of this file.
1// Copyright (c) 2020-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
20
32// advgetopt
33//
34#include <advgetopt/advgetopt.h>
35#include <advgetopt/exception.h>
36#include <advgetopt/version.h>
37
38
39// libutf8
40//
41#include <libutf8/libutf8.h>
42
43
44// libexcept
45//
46#include <libexcept/file_inheritance.h>
47
48
49// snapdev
50//
51#include <snapdev/not_reached.h>
52#include <snapdev/trim_string.h>
53
54
55// boost
56//
57#include <boost/preprocessor/stringize.hpp>
58
59
60// C++
61//
62#include <iostream>
63#include <fstream>
64#include <sstream>
65
66
67// last include
68//
69#include <snapdev/poison.h>
70
71
72
73namespace
74{
75
99
100
106constexpr char const * const g_configuration_files[]
107{
108 "/etc/advgetopt/build-file-of-options.conf",
109 nullptr
110};
111
112
113
114
115// TODO: once we have stdc++20, remove all defaults
116#pragma GCC diagnostic ignored "-Wpedantic"
118{
119 .f_project_name = "build-file-of-options",
120 .f_group_name = nullptr,
121 .f_options = g_options,
122 .f_options_files_directory = nullptr,
123 .f_environment_variable_name = "BUILD_FILE_OF_OPTIONS_OPTIONS",
124 .f_environment_variable_intro = nullptr,
125 .f_section_variables_name = nullptr,
126 .f_configuration_files = g_configuration_files,
127 .f_configuration_filename = nullptr,
128 .f_configuration_directories = nullptr,
130 .f_help_header = "Usage: %p [-<opt>] <configuration file>\n"
131 "where -<opt> is one or more of:",
132 .f_help_footer = "%c",
133 .f_version = LIBADVGETOPT_VERSION_STRING,
134 .f_license = nullptr,
135 .f_copyright = "Copyright (c) 2019-" BOOST_PP_STRINGIZE(UTC_BUILD_YEAR) " Made to Order Software Corporation",
136 .f_build_date = UTC_BUILD_DATE,
137 .f_build_time = UTC_BUILD_TIME
138};
139
140
141
142
143
145{
146public:
147 build_file(int argc, char * argv[]);
148
149 int run();
150
151private:
152 int read_conf(std::string const & filename);
153 void append_flag(std::string & flags, std::string const & name);
154
156 std::ifstream f_in = std::ifstream();
157};
158
159
160
161build_file::build_file(int argc, char * argv[])
162 : f_opt(g_options_environment, argc, argv)
163{
164 if(!f_opt.is_defined("output"))
165 {
166 throw advgetopt::getopt_exit("the --output command line option is required.", 2);
167 }
168 if(f_opt.size("--") == 0)
169 {
170 throw advgetopt::getopt_exit("at least one input filename is required.", 2);
171 }
172}
173
174
176{
177 int r(0);
178
179// TODO: actually implement the tool!
180
181 // read the input in memory
182 //
183 std::size_t const max(f_opt.size("--"));
184 for(std::size_t idx(0); idx < max; ++idx)
185 {
186 r = read_conf(f_opt.get_string("--", idx));
187 if(r != 0)
188 {
189 return r;
190 }
191 }
192
193 return r;
194}
195
196
197int build_file::read_conf(std::string const & filename)
198{
199 f_in.open(filename);
200 if(!f_in.is_open())
201 {
202 std::cerr
203 << "error: could not open file \""
204 << filename
205 << "\".\n";
206 return 1;
207 }
208
209 // read "whatever" up to an empty line (line without comments or a
210 // value) -- we ignore spaces (trim)
211 //
212 std::string l;
213 int line(1);
214 for(++line; f_in; ++line)
215 {
216 for(; f_in; ++line)
217 {
218 getline(f_in, l);
219 l = snapdev::trim_string(l);
220 if(l.empty())
221 {
222 break;
223 }
224 }
225
226 bool found(false);
227 for(; f_in; ++line)
228 {
229 getline(f_in, l);
230 l = snapdev::trim_string(l);
231 if(l.length() > 0
232 && l[0] == '#')
233 {
234 found = true;
235 break;
236 }
237 }
238
239 if(found)
240 {
241 // found a comment, parse it
242 //
243 std::string::size_type const pos(l.find('='));
244 std::string name;
245 std::string params;
246 if(pos != std::string::npos)
247 {
248 // there is an equal, assume a parameter is properly
249 // defined; read its name
250 //
251 name = snapdev::trim_string(l.substr(1, pos - 1));
252 params = snapdev::trim_string(l.substr(pos + 1));
253 }
254 std::string::size_type const space(name.find(' '));
255 std::string::size_type const colon(name.find(':'));
256 if(!name.empty()
257 && space == std::string::npos
258 && colon == std::string::npos)
259 {
260 std::string alias;
261 std::string::size_type const has_alias(name.find('|'));
262 if(has_alias != std::string::npos)
263 {
264 alias = name.substr(has_alias + 1);
265 name = name.substr(0, has_alias);
266 }
267
268 std::string short_name;
269 if(params.back() == ')')
270 {
271 std::string::size_type const start_short_name(params.rfind('('));
272 short_name = params.substr(start_short_name + 1, params.length() - start_short_name - 2);
273 params = snapdev::trim_string(params.substr(0, start_short_name));
274 if(libutf8::u8length(short_name) != 1)
275 {
276 std::cerr << "error:"
277 << filename
278 << ":"
279 << line
280 << ": a short name specification must be exactly one character; \""
281 << short_name
282 << "\" is not valid.\n";
283 return 1;
284 }
285 }
286
287 // the help is the first sentence following (if there is one)
288 // the name=<possible values> line; this can be many lines
289 // of comments. We read them all up to a "Default:"
290 //
291 std::string help;
292 std::string default_value;
293 for(++line; f_in; ++line)
294 {
295 getline(f_in, l);
296 l = snapdev::trim_string(l);
297 if(l.length() > 0
298 && l[0] == '#')
299 {
300 l = snapdev::trim_string(l.substr(1));
301 if(l.length() >= sizeof("Default:")
302 && l[0] == 'D'
303 && l[1] == 'e'
304 && l[2] == 'f'
305 && l[3] == 'a'
306 && l[4] == 'u'
307 && l[5] == 'l'
308 && l[6] == 't'
309 && l[7] == ':')
310 {
311 default_value = snapdev::trim_string(l.substr(8));
312 break;
313 }
314 help += ' ';
315 help += l;
316 }
317 }
318
319 std::string::size_type const dot(help.find('.'));
320 if(dot != std::string::npos)
321 {
322 help = snapdev::trim_string(help.substr(0, dot + 1), true, true, true);
323 }
324
325 std::string flags;
326 std::cout
327 << " advgetopt::define_option(\n"
328 << " advgetopt::Name(\"" << name << "\")\n";
329
330 if(!short_name.empty())
331 {
332 std::cout
333 << " , advgetopt::ShortName(U'" << short_name << "')\n";
334 }
335
336 if(!params.empty())
337 {
338 if(params.front() != '[' || params.back() != ']')
339 {
340 append_flag(flags, "REQUIRED");
341 }
342 if((params.front() == '{' && params.back() == '}')
343 || params.find("...") != std::string::npos)
344 {
345 append_flag(flags, "MULTIPLE");
346 }
347 std::cout
348 << " , advgetopt::Args(\"" << params << "\")\n";
349 }
350
351 if(!help.empty())
352 {
353 std::cout
354 << " , advgetopt::Help(\"" << help << "\")\n";
355 }
356
357 if(!flags.empty())
358 {
359 std::cout
360 << " , advgetopt::Flags("
361 << flags << ")\n";
362 }
363
364 std::cout << " ),\n";
365
366 // if there is an alias defined, generate it now
367 //
368 if(!alias.empty())
369 {
370 flags.clear();
371 std::cout
372 << " advgetopt::define_option(\n"
373 << " advgetopt::Name(\"" << alias << "\")\n";
374
375 // TBD: do we need the other flags?
376 //
377 append_flag(flags, "ALIAS");
378
379 // advgetopt replaces the alias with name
380 //
381 std::cout
382 << " , advgetopt::Help(\"" << name << "\")\n";
383
384 if(!flags.empty())
385 {
386 std::cout
387 << " , advgetopt::Flags("
388 << flags << ")\n";
389 }
390
391 std::cout << " ),\n";
392 }
393 }
394 }
395 }
396
397 return 0;
398}
399
400
401void build_file::append_flag(std::string & flags, std::string const & name)
402{
403 if(flags.empty())
404 {
405 flags += "\n ";
406 }
407 else
408 {
409 flags += "\n , ";
410 }
411 flags += "advgetopt::GETOPT_FLAG_";
412 flags += name;
413}
414
415
416
417
418} // no name namespace
419
420
421
422
423int main(int argc, char * argv[])
424{
425 libexcept::verify_inherited_files();
426
427 try
428 {
429 build_file session(argc, argv);
430 return session.run();
431 }
432 catch(advgetopt::getopt_exit const & e)
433 {
434 if(e.code() != 1)
435 {
436 std::cerr << "error: " << e.what() << std::endl;
437 }
438 exit(e.code());
439 }
440 catch(std::exception const & e)
441 {
442 std::cerr << "error: exception caught: " << e.what() << std::endl;
443 return 1;
444 }
445 snapdev::NOT_REACHED();
446}
447
448
449// vim: ts=4 sw=4 et
450
Definitions of the advanced getopt class.
int main(int argc, char *argv[])
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.
void append_flag(std::string &flags, std::string const &name)
Definitions of the advanced getopt exceptions.
constexpr option define_option(ARGS ...args)
Definition options.h:259
constexpr flag_t command_flags()
Definition flags.h:191
constexpr option end_options()
Definition options.h:294
constexpr flag_t GETOPT_ENVIRONMENT_FLAG_PROCESS_SYSTEM_PARAMETERS
Definition options.h:435
static constexpr flag_t GETOPT_FLAG_DEFAULT_OPTION
Definition flags.h:54
static constexpr flag_t GETOPT_FLAG_MULTIPLE
Definition flags.h:53
static constexpr flag_t GETOPT_FLAG_REQUIRED
Definition flags.h:52
advgetopt::options_environment const g_options_environment
constexpr char const *const g_configuration_files[]
The tool looks for this configuration file.
advgetopt::option const g_options[]
Command line options.
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.