Line data Source code
1 : // Copyright (c) 2006-2024 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 : /** \file
21 : * \brief Advanced getopt usage() implementation.
22 : *
23 : * The advgetopt class usage() and helper functions are grouped in this
24 : * file.
25 : */
26 :
27 : // self
28 : //
29 : #include "advgetopt/advgetopt.h"
30 :
31 : #include "advgetopt/exception.h"
32 :
33 :
34 : // snapdev
35 : //
36 : #include <snapdev/join_strings.h>
37 : #include <snapdev/tokenize_format.h>
38 :
39 :
40 : // C++
41 : //
42 : #include <iomanip>
43 : #include <iostream>
44 :
45 :
46 : // last include
47 : //
48 : #include <snapdev/poison.h>
49 :
50 :
51 :
52 :
53 : namespace advgetopt
54 : {
55 :
56 :
57 :
58 : /** \brief Transform group names in --\<name>-help commands.
59 : *
60 : * This function allows for the group names to be transformed into help
61 : * command line options.
62 : */
63 355 : void getopt::parse_options_from_group_names()
64 : {
65 : // add the --long-help if at least one option uses the GROUP1, GROUP2,
66 : // or SYSTEM
67 : //
68 : // add the --system-help if at least one option uses SYSTEM
69 : //
70 355 : bool add_long_help(false);
71 355 : bool add_system_help(false);
72 :
73 355 : for(auto it(f_options_by_name.begin())
74 1999 : ; it != f_options_by_name.end()
75 1644 : ; ++it)
76 : {
77 1644 : if(it->second->has_flag(GETOPT_FLAG_SHOW_GROUP1 | GETOPT_FLAG_SHOW_GROUP2 | GETOPT_FLAG_SHOW_SYSTEM))
78 : {
79 790 : add_long_help = true;
80 : }
81 :
82 1644 : if(it->second->has_flag(GETOPT_FLAG_SHOW_SYSTEM))
83 : {
84 760 : add_system_help = true;
85 : }
86 : }
87 :
88 355 : if(add_long_help)
89 : {
90 99 : option_info::pointer_t opt(std::make_shared<option_info>("long-help"));
91 99 : opt->add_flag(GETOPT_FLAG_COMMAND_LINE
92 : | GETOPT_FLAG_FLAG
93 : | GETOPT_FLAG_GROUP_COMMANDS);
94 99 : opt->set_help("show all the help from all the available options.");
95 99 : f_options_by_name["long-help"] = opt;
96 99 : if(f_options_by_short_name.find(L'?') == f_options_by_short_name.end())
97 : {
98 99 : opt->set_short_name(L'?');
99 99 : f_options_by_short_name[L'?'] = opt;
100 : }
101 99 : }
102 :
103 355 : if(add_system_help)
104 : {
105 95 : option_info::pointer_t opt(std::make_shared<option_info>("system-help"));
106 95 : opt->add_flag(GETOPT_FLAG_COMMAND_LINE
107 : | GETOPT_FLAG_FLAG
108 : | GETOPT_FLAG_GROUP_COMMANDS);
109 95 : opt->set_help("show commands and options added by libraries.");
110 95 : f_options_by_name["system-help"] = opt;
111 95 : if(f_options_by_short_name.find(L'S') == f_options_by_short_name.end())
112 : {
113 91 : opt->set_short_name(L'S');
114 91 : f_options_by_short_name[L'S'] = opt;
115 : }
116 95 : }
117 :
118 355 : if(f_options_environment.f_groups == nullptr)
119 : {
120 : // no groups, ignore following loop
121 : //
122 321 : return;
123 : }
124 :
125 102 : for(group_description const * grp = f_options_environment.f_groups
126 102 : ; grp->f_group != GETOPT_FLAG_GROUP_NONE
127 : ; ++grp)
128 : {
129 : // the name is not mandatory, without it you do not get the command
130 : // line option but still get the group description
131 : //
132 68 : if(grp->f_name != nullptr
133 6 : && *grp->f_name != '\0')
134 : {
135 12 : std::string const name(grp->f_name);
136 6 : std::string const option_name(name + "-help");
137 6 : option_info::pointer_t opt(std::make_shared<option_info>(option_name));
138 6 : opt->add_flag(GETOPT_FLAG_COMMAND_LINE
139 : | GETOPT_FLAG_FLAG
140 : | GETOPT_FLAG_GROUP_COMMANDS);
141 12 : opt->set_help("show help from the \""
142 12 : + name
143 18 : + "\" group of options.");
144 6 : f_options_by_name[option_name] = opt;
145 6 : }
146 : }
147 : }
148 :
149 :
150 : /** \brief Search for \p group in the list of group names.
151 : *
152 : * This function is used to search for the name of a group.
153 : *
154 : * Groups are used by the usage() function to list options by some user
155 : * selected group.
156 : *
157 : * For example, it is often that a tool has a set of commands such as
158 : * `--delete` and a set of options such as `--verbose`. These can represent
159 : * to clear groups of commands and options.
160 : *
161 : * \param[in] group The group to look for (i.e. GETOPT_FLAG_GROUP_ONE).
162 : *
163 : * \return The group structure or nullptr when not found.
164 : */
165 45 : group_description const * getopt::find_group(flag_t group) const
166 : {
167 45 : if(f_options_environment.f_groups == nullptr)
168 : {
169 2 : return nullptr;
170 : }
171 :
172 43 : if((group & ~GETOPT_FLAG_GROUP_MASK) != 0)
173 : {
174 29 : throw getopt_logic_error("group parameter must represent a valid group.");
175 : }
176 14 : if(group == GETOPT_FLAG_GROUP_NONE)
177 : {
178 1 : throw getopt_logic_error("group NONE cannot be assigned a name so you cannot search for it.");
179 : }
180 :
181 21 : for(group_description const * grp(f_options_environment.f_groups)
182 21 : ; grp->f_group != GETOPT_FLAG_GROUP_NONE
183 : ; ++grp)
184 : {
185 20 : if(group == grp->f_group)
186 : {
187 12 : if((grp->f_name == nullptr || *grp->f_name == '\0')
188 2 : && (grp->f_description == nullptr || *grp->f_description == '\0'))
189 : {
190 2 : throw getopt_logic_error("at least one of a group name or description must be defined (a non-empty string).");
191 : }
192 10 : return grp;
193 : }
194 : }
195 :
196 : // group not defined
197 : //
198 1 : return nullptr;
199 : }
200 :
201 :
202 : /** \brief Create a string of the command line arguments.
203 : *
204 : * This function assembles the command line arguments in a string and
205 : * returns that string.
206 : *
207 : * The function has the ability to wrap strings around for better formatting.
208 : *
209 : * The list of arguments to show is defined by the \p show parameter. When
210 : * \p show is 0, then only the regular and error arguments are shown.
211 : * Otherwise only the argumenst with the specified flags are show. Only
212 : * the `..._SHOW_...` flags are valid here.
213 : *
214 : * When an error occurs, it is customary to set \p show to
215 : * GETOPT_FLAG_SHOW_USAGE_ON_ERROR so only a limited set of arguments
216 : * are shown.
217 : *
218 : * The library offers two groups in case you have a command line tools
219 : * with a large number of options, those two can be used to only show
220 : * those specific set of options with using a specific `--help` argument.
221 : *
222 : * \note
223 : * This function does NOT print anything in the output. This is your
224 : * responsibility. We do it this way because you may be using a logger
225 : * and not want to print the usage in the \em wrong destination.
226 : *
227 : * \bug
228 : * The options are written from our map. This means the order will be
229 : * alphabetical and not the order in which you defined the options.
230 : * We are not looking into fixing this problem. That's just something
231 : * you want to keep in mind.
232 : *
233 : * \param[in] show Selection of the options to show.
234 : *
235 : * \return The assembled command line arguments.
236 : */
237 80 : std::string getopt::usage(flag_t show) const
238 : {
239 80 : std::stringstream ss;
240 :
241 80 : flag_t specific_group(show & GETOPT_FLAG_GROUP_MASK);
242 :
243 : // ignore all the non-show flags
244 : //
245 80 : show &= GETOPT_FLAG_SHOW_USAGE_ON_ERROR
246 : | GETOPT_FLAG_SHOW_ALL
247 : | GETOPT_FLAG_SHOW_GROUP1
248 : | GETOPT_FLAG_SHOW_GROUP2
249 : | GETOPT_FLAG_SHOW_SYSTEM;
250 :
251 80 : size_t const line_width(get_screen_width());
252 80 : ss << breakup_line(process_help_string(f_options_environment.f_help_header), 0, line_width);
253 :
254 80 : std::string save_default;
255 80 : std::string save_help;
256 :
257 80 : flag_t pos(GETOPT_FLAG_GROUP_MINIMUM);
258 80 : flag_t group_max(GETOPT_FLAG_GROUP_MAXIMUM);
259 80 : if(f_options_environment.f_groups == nullptr)
260 : {
261 73 : group_max = GETOPT_FLAG_GROUP_MINIMUM;
262 73 : specific_group = GETOPT_FLAG_GROUP_NONE;
263 : }
264 7 : else if(specific_group != GETOPT_FLAG_GROUP_NONE)
265 : {
266 : // only display that specific group if asked to do so
267 : //
268 2 : pos = specific_group >> GETOPT_FLAG_GROUP_SHIFT;
269 2 : group_max = pos;
270 : }
271 :
272 80 : std::multimap<advgetopt::option_info::pointer_t, advgetopt::option_info::pointer_t> alias_reverse_references;
273 372 : for(auto const & opt : f_options_by_name)
274 : {
275 292 : if(!opt.second->has_flag(GETOPT_FLAG_ALIAS))
276 : {
277 280 : continue;
278 : }
279 12 : alias_reverse_references.insert(std::make_pair(opt.second->get_alias_destination(), opt.second));
280 : }
281 :
282 195 : for(; pos <= group_max; ++pos)
283 : {
284 115 : bool group_name_shown(false);
285 115 : flag_t const group(pos << GETOPT_FLAG_GROUP_SHIFT);
286 897 : for(auto const & opt : f_options_by_name)
287 : {
288 782 : if((opt.second->get_flags() & GETOPT_FLAG_GROUP_MASK) != group
289 782 : && f_options_environment.f_groups != nullptr)
290 : {
291 : // this could be optimized but we'd probably not see much
292 : // difference overall and it's just for the usage() call
293 : //
294 509 : continue;
295 : }
296 :
297 273 : std::string const help(opt.second->get_help());
298 273 : if(help.empty())
299 : {
300 : // ignore entries without help
301 : //
302 10 : continue;
303 : }
304 :
305 263 : if(opt.second->has_flag(GETOPT_FLAG_ALIAS))
306 : {
307 : // ignore entries representing an alias
308 : //
309 12 : continue;
310 : }
311 :
312 251 : if((show & GETOPT_FLAG_SHOW_ALL) == 0)
313 : {
314 189 : if(show != 0)
315 : {
316 66 : if(!opt.second->has_flag(show))
317 : {
318 : // usage selected group is not present in this option, ignore
319 : //
320 58 : continue;
321 : }
322 : }
323 123 : else if(opt.second->has_flag(GETOPT_FLAG_SHOW_GROUP1
324 : | GETOPT_FLAG_SHOW_GROUP2
325 : | GETOPT_FLAG_SHOW_SYSTEM))
326 : {
327 : // do not show specialized groups
328 : //
329 22 : continue;
330 : }
331 : }
332 :
333 171 : if(!group_name_shown)
334 : {
335 85 : group_name_shown = true;
336 :
337 85 : if(group != GETOPT_FLAG_GROUP_NONE)
338 : {
339 8 : group_description const * grp(find_group(group));
340 8 : if(grp != nullptr)
341 : {
342 8 : ss << std::endl
343 8 : << breakup_line(process_help_string(grp->f_description), 0, line_width);
344 : }
345 : }
346 : }
347 :
348 171 : std::stringstream argument;
349 :
350 171 : if(opt.second->is_default_option())
351 : {
352 6 : switch(opt.second->get_flags() & (GETOPT_FLAG_REQUIRED | GETOPT_FLAG_MULTIPLE))
353 : {
354 1 : case 0:
355 1 : argument << "[default argument]";
356 1 : break;
357 :
358 1 : case GETOPT_FLAG_REQUIRED:
359 1 : argument << "<default argument>";
360 1 : break;
361 :
362 2 : case GETOPT_FLAG_MULTIPLE:
363 2 : argument << "[default arguments]";
364 2 : break;
365 :
366 2 : case GETOPT_FLAG_REQUIRED | GETOPT_FLAG_MULTIPLE:
367 2 : argument << "<default arguments>";
368 2 : break;
369 :
370 : }
371 : }
372 : else
373 : {
374 165 : argument << "--" << opt.second->get_name();
375 165 : auto aliases(alias_reverse_references.lower_bound(opt.second));
376 165 : if(aliases->first == opt.second)
377 : {
378 6 : auto end(alias_reverse_references.upper_bound(opt.second));
379 12 : for(auto a(aliases); a != end; ++a)
380 : {
381 6 : argument << " or --" << a->second->get_name();
382 : }
383 : }
384 165 : if(opt.second->get_short_name() != NO_SHORT_NAME)
385 : {
386 50 : argument << " or -" << short_name_to_string(opt.second->get_short_name());
387 : }
388 165 : if(aliases->first == opt.second)
389 : {
390 6 : auto end(alias_reverse_references.upper_bound(opt.second));
391 12 : for(; aliases != end; ++aliases)
392 : {
393 6 : if(aliases->second->get_short_name() != NO_SHORT_NAME)
394 : {
395 0 : argument << " or -" << short_name_to_string(aliases->second->get_short_name());
396 : }
397 : }
398 : }
399 :
400 165 : switch(opt.second->get_flags() & (GETOPT_FLAG_FLAG | GETOPT_FLAG_REQUIRED | GETOPT_FLAG_MULTIPLE))
401 : {
402 1 : case 0:
403 1 : argument << " [<arg>]";
404 1 : break;
405 :
406 34 : case GETOPT_FLAG_REQUIRED:
407 34 : argument << " <arg>";
408 34 : break;
409 :
410 8 : case GETOPT_FLAG_MULTIPLE:
411 8 : argument << " {<arg>}";
412 8 : break;
413 :
414 6 : case GETOPT_FLAG_REQUIRED | GETOPT_FLAG_MULTIPLE:
415 6 : argument << " <arg> {<arg>}";
416 6 : break;
417 :
418 : }
419 : }
420 :
421 171 : if(opt.second->has_flag(GETOPT_FLAG_DYNAMIC_CONFIGURATION))
422 : {
423 0 : argument << "*";
424 : }
425 :
426 171 : if(opt.second->has_default())
427 : {
428 : argument << " (default is \""
429 9 : << opt.second->get_default()
430 18 : << "\")";
431 : }
432 :
433 : // Output argument string with help
434 : //
435 171 : if(opt.second->is_default_option())
436 : {
437 6 : save_default = argument.str();
438 6 : save_help = help;
439 : }
440 : else
441 : {
442 165 : std::string variable_name;
443 165 : if(!opt.second->get_environment_variable_name().empty())
444 : {
445 2 : variable_name += "\nEnvironment Variable Name: \"";
446 2 : if(f_options_environment.f_environment_variable_intro != nullptr)
447 : {
448 2 : variable_name += f_options_environment.f_environment_variable_intro;
449 : }
450 2 : variable_name += opt.second->get_environment_variable_name();
451 2 : variable_name += '"';
452 : }
453 495 : ss << format_usage_string(argument.str()
454 330 : , process_help_string((help + variable_name).c_str())
455 : , 30
456 165 : , line_width);
457 165 : }
458 273 : }
459 : }
460 :
461 80 : if(!save_default.empty())
462 : {
463 18 : ss << format_usage_string(save_default
464 12 : , process_help_string(save_help.c_str())
465 : , 30
466 6 : , line_width);
467 : }
468 :
469 80 : if(f_options_environment.f_help_footer != nullptr
470 78 : && f_options_environment.f_help_footer[0] != '\0')
471 : {
472 78 : ss << std::endl;
473 78 : ss << breakup_line(process_help_string(f_options_environment.f_help_footer), 0, line_width);
474 : }
475 :
476 160 : return ss.str();
477 80 : }
478 :
479 :
480 : class usage_flag_traits
481 : {
482 : public:
483 : static constexpr snapdev::format_flag_t const FORMAT_FLAG_EXTENDED = 0x01; // '*'
484 :
485 514 : static bool is_flag(char c, snapdev::format_item<char> & f)
486 : {
487 514 : switch(c)
488 : {
489 98 : case '*':
490 98 : if(f.has_flags(FORMAT_FLAG_EXTENDED))
491 : {
492 0 : f.add_error(snapdev::format_error_t::FORMAT_ERROR_DUPLICATE);
493 : }
494 98 : f.add_flags(FORMAT_FLAG_EXTENDED);
495 98 : return true;
496 :
497 416 : default:
498 416 : return false;
499 :
500 : }
501 : }
502 : };
503 :
504 :
505 : class usage_letter_traits
506 : {
507 : public:
508 416 : static std::string::size_type is_format(char const * s, snapdev::format_item<char> & f)
509 : {
510 416 : switch(s[0])
511 : {
512 416 : case 'a':
513 : case 'b':
514 : case 'c':
515 : case 'd':
516 : case 'e':
517 : case 'E':
518 : case 'f':
519 : case 'g':
520 : case 'i':
521 : case 'l':
522 : case 'm':
523 : case 'o':
524 : case 'p':
525 : case 's':
526 : case 't':
527 : case 'v':
528 : case 'w':
529 416 : f.format(s[0]);
530 416 : return 1UL;
531 :
532 : }
533 :
534 0 : f.add_error(snapdev::format_error_t::FORMAT_ERROR_UNKNOWN);
535 0 : return 0;
536 : }
537 : };
538 :
539 :
540 : /** \brief Change the % flags in help strings.
541 : *
542 : * This function goes through the help string and replaces the `%\<flag>`
543 : * with various content available in the getopt object.
544 : *
545 : * This is helpful for various reasons. For example, you may use the
546 : * same set of options in several different programs, in which case the
547 : * `%p` is likely useful to print out the name of the program currently
548 : * in use.
549 : *
550 : * Similarly we offer ways to print out lists of configuration files,
551 : * the environment variable name & value, etc. The following is the
552 : * list of supported flags:
553 : *
554 : * \li "%%" -- print out a percent
555 : * \li "%a" -- print out the project name (a.k.a. application name)
556 : * \li "%b" -- print out the build date
557 : * \li "%c" -- print out the copyright notice
558 : * \li "%d" -- print out the first directory with configuration files.
559 : * \li "%*d" -- print out the complete list of directories with configuration
560 : * files.
561 : * \li "%e" -- print out the name of the environment variable.
562 : * \li "%*e" -- print out the name and value of the environment variable.
563 : * \li "%f" -- print out the first configuration path and filename.
564 : * \li "%*f" -- print out all the configuration full paths.
565 : * \li "%g" -- print out the list of existing configuration files.
566 : * \li "%*g" -- print out the list of all possible configuration files.
567 : * \li "%i" -- print out the directory to option files.
568 : * \li "%l" -- print out the license.
569 : * \li "%o" -- show the configuration filename where changes get written.
570 : * \li "%p" -- print out the program basename.
571 : * \li "%*p" -- print out the full program name.
572 : * \li "%s" -- print out the group name.
573 : * \li "%t" -- print out the build time.
574 : * \li "%v" -- print out the version.
575 : * \li "%w" -- print out the list of all the writable configuration files.
576 : *
577 : * Here is an example where the `%p` can be used:
578 : *
579 : * \code
580 : * "Usage: %p [-opt] filename ..."
581 : * \endcode
582 : *
583 : * The other flags are more often used in places like the copyright notice
584 : * the footer, the license notice, etc.
585 : *
586 : * \param[in] help A string that may include `%` flags.
587 : *
588 : * \return The string with any '%\<flag>' replaced.
589 : *
590 : * \sa parse_program_name()
591 : */
592 338 : std::string getopt::process_help_string(char const * help) const
593 : {
594 338 : if(help == nullptr)
595 : {
596 1 : return std::string();
597 : }
598 :
599 337 : snapdev::format_item<char>::list_t items(snapdev::tokenize_format<
600 : char
601 : , usage_letter_traits
602 1011 : , usage_flag_traits>(help));
603 :
604 1404 : for(auto it(items.begin()); it != items.end(); ++it)
605 : {
606 1067 : switch(it->format())
607 : {
608 19 : case 'a':
609 19 : if(f_options_environment.f_project_name != nullptr)
610 : {
611 16 : it->string(f_options_environment.f_project_name);
612 : }
613 19 : break;
614 :
615 19 : case 'b':
616 19 : if(f_options_environment.f_build_date != nullptr)
617 : {
618 16 : it->string(f_options_environment.f_build_date);
619 : }
620 19 : break;
621 :
622 19 : case 'c':
623 19 : if(f_options_environment.f_copyright != nullptr)
624 : {
625 16 : it->string(f_options_environment.f_copyright);
626 : }
627 19 : break;
628 :
629 38 : case 'd':
630 38 : if(f_options_environment.f_configuration_directories != nullptr
631 32 : && *f_options_environment.f_configuration_directories != nullptr)
632 : {
633 26 : if(it->has_flags(usage_flag_traits::FORMAT_FLAG_EXTENDED))
634 : {
635 13 : std::string joined;
636 65 : for(char const * const * directories(f_options_environment.f_configuration_directories);
637 65 : *directories != nullptr;
638 : ++directories)
639 : {
640 52 : if(!joined.empty())
641 : {
642 39 : joined += ", ";
643 : }
644 52 : joined += *directories;
645 : }
646 13 : it->string(joined);
647 13 : }
648 : else
649 : {
650 13 : it->string(*f_options_environment.f_configuration_directories);
651 : }
652 : }
653 38 : break;
654 :
655 56 : case 'e':
656 56 : if(f_options_environment.f_environment_variable_name != nullptr
657 44 : && *f_options_environment.f_environment_variable_name != '\0')
658 : {
659 32 : if(it->has_flags(usage_flag_traits::FORMAT_FLAG_EXTENDED))
660 : {
661 32 : std::string var(f_options_environment.f_environment_variable_name);
662 16 : char const * env(getenv(f_options_environment.f_environment_variable_name));
663 16 : if(env != nullptr)
664 : {
665 8 : var += '=';
666 8 : var += env;
667 : }
668 : else
669 : {
670 8 : var += " (not set)";
671 : }
672 16 : it->string(var);
673 16 : }
674 : else
675 : {
676 16 : it->string(f_options_environment.f_environment_variable_name);
677 : }
678 : }
679 56 : break;
680 :
681 13 : case 'E':
682 13 : if(f_options_environment.f_environment_variable_intro != nullptr)
683 : {
684 10 : it->string(f_options_environment.f_environment_variable_intro);
685 : }
686 13 : break;
687 :
688 38 : case 'f':
689 38 : if(f_options_environment.f_configuration_files != nullptr
690 32 : && *f_options_environment.f_configuration_files != nullptr)
691 : {
692 26 : if(it->has_flags(usage_flag_traits::FORMAT_FLAG_EXTENDED))
693 : {
694 13 : std::string joined;
695 65 : for(char const * const * filenames(f_options_environment.f_configuration_files);
696 65 : *filenames != nullptr;
697 : ++filenames)
698 : {
699 52 : if(!joined.empty())
700 : {
701 39 : joined += ", ";
702 : }
703 52 : joined += *filenames;
704 : }
705 13 : it->string(joined);
706 13 : }
707 : else
708 : {
709 13 : it->string(*f_options_environment.f_configuration_files);
710 : }
711 : }
712 38 : break;
713 :
714 41 : case 'g':
715 : {
716 41 : string_list_t const list(get_configuration_filenames(!it->has_flags(usage_flag_traits::FORMAT_FLAG_EXTENDED), false));
717 41 : it->string(snapdev::join_strings(list, ", "));
718 41 : }
719 : break;
720 :
721 19 : case 'i':
722 : // in the advgetopt_options.cpp, we clearly add a final "/"
723 : // so we want to add it here too, to be consistent
724 19 : it->string(get_options_filename());
725 19 : break;
726 :
727 19 : case 'l':
728 19 : if(f_options_environment.f_license != nullptr)
729 : {
730 16 : it->string(f_options_environment.f_license);
731 : }
732 19 : break;
733 :
734 10 : case 'm':
735 10 : if(f_options_environment.f_section_variables_name != nullptr)
736 : {
737 5 : it->string(f_options_environment.f_section_variables_name);
738 : }
739 10 : break;
740 :
741 19 : case 'o':
742 19 : it->string(get_output_filename());
743 19 : break;
744 :
745 41 : case 'p':
746 41 : if(it->has_flags(usage_flag_traits::FORMAT_FLAG_EXTENDED))
747 : {
748 13 : it->string(f_program_fullname);
749 : }
750 : else
751 : {
752 28 : it->string(f_program_name);
753 : }
754 41 : break;
755 :
756 5 : case 's':
757 5 : if(f_options_environment.f_group_name != nullptr)
758 : {
759 5 : it->string(f_options_environment.f_group_name);
760 : }
761 5 : break;
762 :
763 19 : case 't':
764 19 : if(f_options_environment.f_build_time != nullptr)
765 : {
766 16 : it->string(f_options_environment.f_build_time);
767 : }
768 19 : break;
769 :
770 19 : case 'v':
771 19 : if(f_options_environment.f_version != nullptr)
772 : {
773 16 : it->string(f_options_environment.f_version);
774 : }
775 19 : break;
776 :
777 22 : case 'w':
778 : {
779 22 : string_list_t const list(get_configuration_filenames(true, true));
780 22 : it->string(snapdev::join_strings(list, ", "));
781 22 : }
782 : break;
783 :
784 : }
785 : }
786 :
787 674 : snapdev::format_item<char> empty_item;
788 674 : return snapdev::join_strings(items, empty_item);
789 337 : }
790 :
791 :
792 :
793 :
794 : } // namespace advgetopt
795 : // vim: ts=4 sw=4 et
|