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