1 /**
2 * Copyright (C) 1999-2010 Free Software Foundation, Inc.
3 *
4 * This file is part of GNU gengetopt
5 *
6 * GNU gengetopt 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 3, or (at your option)
9 * any later version.
10 *
11 * GNU gengetopt is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 * Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with gengetopt; see the file COPYING. If not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <string>
29 #include <set>
30 #include <algorithm> // for pair
31
32 #include <fstream>
33 #include <sstream>
34
35 extern "C"
36 {
37 #include "argsdef.h"
38 #include "global_opts.h"
39 };
40
41 #include "ggo_options.h"
42
43 #include "gm.h"
44
45 #include "groups.h"
46 #include "skels/option_arg.h"
47 #include "skels/required_option.h"
48 #include "skels/dependant_option.h"
49 #include "skels/generic_option.h"
50 #include "skels/group_option.h"
51 #include "skels/group_counter.h"
52 #include "skels/handle_help.h"
53 #include "skels/handle_version.h"
54 #include "skels/print_help_string.h"
55 #include "skels/multiple_opt_list.h"
56 #include "skels/multiple_fill_array.h"
57 #include "skels/free_string.h"
58 #include "skels/free_multiple.h"
59 #include "skels/reset_group.h"
60 #include "skels/exit_failure.h"
61 #include "skels/update_given.h"
62 #include "skels/given_field.h"
63 #include "skels/clear_given.h"
64 #include "skels/clear_arg.h"
65 #include "skels/free_list.h"
66 #include "skels/file_save.h"
67 #include "skels/file_save_multiple.h"
68 #include "skels/init_args_info.h"
69 #include "skels/custom_getopt_gen.h"
70 #include "skels/check_modes.h"
71 #include "skels/enum_decl.h"
72 #include "gm_utils.h"
73 #include "fileutils.h"
74
75 #ifndef FIX_UNUSED
76 #define FIX_UNUSED(X) (void) (X)
77 #endif // FIX_UNUSED
78
79 #define MAX_STARTING_COLUMN 32
80
81 #define EXE_NAME "argv[0]"
82
83 #define PARSER_NAME_PREFIX (c_source_gen_class::parser_name + "_")
84 #define OPTION_VALUES_NAME(n) (PARSER_NAME_PREFIX + n + "_values")
85
86 using namespace std;
87
88 extern char * gengetopt_package;
89 extern char * gengetopt_version;
90 extern char * gengetopt_purpose;
91 extern char * gengetopt_versiontext;
92 extern char * gengetopt_description;
93 extern char * gengetopt_usage;
94
95 extern groups_collection_t gengetopt_groups;
96 extern modes_collection_t gengetopt_modes;
97
98 // a map where for each mode we store the corresponding given field names
99 // and the options
100 typedef std::pair<string, string> OptionValueElem;
101 typedef std::list<OptionValueElem> ModeOptions;
102 typedef std::map<string, ModeOptions> ModeOptionMap;
103
104 static ModeOptionMap modeOptionMap;
105
getModeOptionMap()106 static const ModeOptionMap &getModeOptionMap() {
107 if (modeOptionMap.size() == 0) {
108 // it's the first time, so we build it
109 struct gengetopt_option * opt;
110 foropt {
111 if (opt->mode_value) {
112 modeOptionMap[opt->mode_value].push_back
113 (std::make_pair("args_info->" + string(opt->var_arg) + "_given",
114 string("\"--") + opt->long_opt + "\""));
115 }
116 }
117 }
118
119 return modeOptionMap;
120 }
121
122 // a map associating to a mode the list of gengetopt_options
123 typedef std::map<string, gengetopt_option_list> ModeOptMap;
124
125 static ModeOptMap modeOptMap;
126
getModeOptMap()127 static const ModeOptMap &getModeOptMap() {
128 if (modeOptMap.size() == 0) {
129 // it's the first time, so we build it
130 struct gengetopt_option * opt;
131 foropt {
132 if (opt->mode_value) {
133 modeOptMap[opt->mode_value].push_back(opt);
134 }
135 }
136 }
137
138 return modeOptMap;
139 }
140
141 static void _generate_option_arg(ostream &stream,
142 unsigned int indentation,
143 struct gengetopt_option * opt);
144
145 static void
146 generate_help_desc_print(ostream &stream,
147 unsigned int desc_column,
148 const char *descript, const char *defval,
149 const string &values,
150 const string &show_required_string);
151
CmdlineParserCreator(char * function_name,char * struct_name,char * unnamed_options_,char * filename_,char * header_ext,char * c_ext,bool long_help_,bool no_handle_help_,bool no_help_,bool no_handle_version_,bool no_version_,bool no_handle_error_,bool strict_hidden_,bool conf_parser_,bool string_parser_,bool gen_version,bool gen_getopt,bool no_options_,const string & comment_,const string & outdir,const string & header_outdir,const string & src_outdir,const string & show_required)152 CmdlineParserCreator::CmdlineParserCreator (char *function_name,
153 char *struct_name,
154 char *unnamed_options_,
155 char *filename_,
156 char *header_ext, char *c_ext,
157 bool long_help_,
158 bool no_handle_help_,
159 bool no_help_,
160 bool no_handle_version_,
161 bool no_version_,
162 bool no_handle_error_,
163 bool strict_hidden_,
164 bool conf_parser_,
165 bool string_parser_,
166 bool gen_version,
167 bool gen_getopt,
168 bool no_options_,
169 const string &comment_,
170 const string &outdir,
171 const string &header_outdir,
172 const string &src_outdir,
173 const string &show_required) :
174 filename (filename_),
175 args_info_name (struct_name),
176 output_dir (outdir),
177 header_output_dir (header_outdir),
178 src_output_dir (src_outdir),
179 comment (comment_),
180 unnamed_options (unnamed_options_),
181 show_required_string (show_required),
182 long_help (long_help_), no_handle_help (no_handle_help_),
183 no_help (no_help_),
184 no_handle_version (no_handle_version_),
185 no_version (no_version_),
186 no_handle_error (no_handle_error_),
187 strict_hidden (strict_hidden_),
188 conf_parser (conf_parser_), string_parser (string_parser_),
189 gen_gengetopt_version (gen_version),
190 tab_indentation (0)
191 {
192 parser_function_name = canonize_names (function_name);
193 c_filename = create_filename (filename, c_ext);
194 header_filename = create_filename (filename, header_ext);
195
196 // header_gen_class
197 const string stripped_header_file_name = strip_path (filename);
198 set_header_file_name (stripped_header_file_name);
199 header_gen_class::set_header_file_ext (header_ext);
200 c_source_gen_class::set_header_file_ext (header_ext);
201 if (gen_gengetopt_version) {
202 header_gen_class::set_generator_version("version " VERSION);
203 }
204 const string my_ifndefname =
205 to_upper (strip_path (stripped_header_file_name));
206 set_ifndefname (canonize_names (my_ifndefname.c_str ()));
207 header_gen_class::set_parser_name (parser_function_name);
208 const string my_package_var_name =
209 to_upper (parser_function_name) + "_PACKAGE";
210 const string my_version_var_name =
211 to_upper (parser_function_name) + "_VERSION";
212 header_gen_class::set_package_var_name (my_package_var_name);
213 c_source_gen_class::set_package_var_name (my_package_var_name);
214 header_gen_class::set_version_var_name (my_version_var_name);
215 c_source_gen_class::set_version_var_name (my_version_var_name);
216 header_gen_class::set_args_info (args_info_name);
217 c_source_gen_class::set_args_info (args_info_name);
218 const string uppersand = "\"";
219
220 // if no_options then we don't need to generate update_arg,
221 // but if we need to handle help or version we still need to generate it
222 set_no_options (no_options_ && !no_handle_help && !no_handle_version);
223
224 if (gengetopt_package)
225 set_package_var_val
226 (uppersand + gengetopt_package + uppersand);
227 else
228 set_package_var_val ("PACKAGE");
229
230 if (gengetopt_version)
231 set_version_var_val
232 (uppersand + gengetopt_version + uppersand);
233 else
234 set_version_var_val ("VERSION");
235
236 header_gen_class::set_generate_config_parser (conf_parser);
237
238 header_gen_class::set_generate_string_parser (string_parser);
239 c_source_gen_class::set_generate_string_parser (string_parser);
240
241 // c_source_gen_class
242 set_command_line (comment);
243 if (gen_gengetopt_version)
244 c_source_gen_class::set_generator_version
245 ("version " VERSION);
246 c_source_gen_class::set_parser_name (parser_function_name);
247 set_source_name (filename);
248
249 ostringstream exit_failure_str;
250 exit_failure_gen_class exit_gen;
251 exit_gen.set_parser_name (c_source_gen_class::parser_name);
252 exit_gen.set_handle_error (! no_handle_error);
253 exit_gen.generate_exit_failure (exit_failure_str);
254 set_final_exit (exit_failure_str.str ());
255
256 set_conf_parser (conf_parser);
257 set_cmd_list (conf_parser || string_parser);
258 set_include_getopt (gen_getopt);
259
260 struct gengetopt_option * opt;
261 gen_strdup = (unnamed_options != 0 || conf_parser || string_parser);
262
263 if (! gen_strdup)
264 {
265 foropt
266 if (opt->type != ARG_FLAG || opt->type != ARG_NO) {
267 gen_strdup = true;
268 break;
269 }
270 }
271
272 set_do_generate_strdup(gen_strdup);
273 set_check_possible_values(has_values());
274 set_multiple_token_functions(has_multiple_options_with_type());
275 set_multiple_options_with_default(has_multiple_options_with_default());
276 set_multiple_options(has_multiple_options());
277 set_multiple_options_string(has_multiple_options_string());
278 set_multiple_options_all_string(has_multiple_options_all_string());
279 set_has_typed_options(has_options_with_type());
280 set_has_modes(has_options_with_mode());
281 set_handle_unnamed(unnamed_options);
282 set_check_required_options(has_required() || has_dependencies() || has_multiple_options());
283 set_purpose(generate_purpose());
284 set_description(generate_description());
285 set_versiontext(generate_versiontext());
286 set_no_package((gengetopt_package == 0));
287 c_source_gen_class::set_has_hidden(!strict_hidden && has_hidden_options());
288 header_gen_class::set_has_hidden(c_source_gen_class::has_hidden);
289 c_source_gen_class::set_has_details(has_options_with_details(strict_hidden));
290 header_gen_class::set_has_details(c_source_gen_class::has_details);
291
292 set_has_arg_types();
293 }
294
set_has_arg_types()295 void CmdlineParserCreator::set_has_arg_types() {
296 struct gengetopt_option * opt;
297
298 set_has_arg_flag(false);
299 set_has_arg_string(false);
300 set_has_arg_int(false);
301 set_has_arg_short(false);
302 set_has_arg_long(false);
303 set_has_arg_float(false);
304 set_has_arg_double(false);
305 set_has_arg_longdouble(false);
306 set_has_arg_longlong(false);
307
308 foropt
309 {
310 switch (opt->type) {
311 case ARG_NO:
312 break;
313 case ARG_FLAG:
314 set_has_arg_flag(true);
315 break;
316 case ARG_STRING:
317 set_has_arg_string(true);
318 break;
319 case ARG_INT:
320 set_has_arg_int(true);
321 break;
322 case ARG_SHORT:
323 set_has_arg_short(true);
324 break;
325 case ARG_LONG:
326 set_has_arg_long(true);
327 break;
328 case ARG_FLOAT:
329 set_has_arg_float(true);
330 break;
331 case ARG_DOUBLE:
332 set_has_arg_double(true);
333 break;
334 case ARG_LONGDOUBLE:
335 set_has_arg_longdouble(true);
336 break;
337 case ARG_LONGLONG:
338 set_has_arg_longlong(true);
339 break;
340 case ARG_ENUM:
341 set_has_arg_enum(true);
342 break;
343 default:
344 fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
345 __FILE__, __LINE__);
346 abort ();
347 }
348 }
349
350 }
351
352 void
generateBreak(ostream & stream,unsigned int indentation)353 CmdlineParserCreator::generateBreak(ostream &stream, unsigned int indentation)
354 {
355 string indent_str (indentation, ' ');
356
357 stream << endl;
358 stream << indent_str;
359 stream << "break;";
360 }
361
362 int
generate()363 CmdlineParserCreator::generate ()
364 {
365 int head_result;
366
367 head_result = generate_header_file ();
368 if (head_result)
369 return head_result;
370
371 return generate_source ();
372 }
373
374 int
generate_header_file()375 CmdlineParserCreator::generate_header_file ()
376 {
377 if (! gengetopt_options.size())
378 {
379 fprintf (stderr, "gengetopt: none option given\n");
380 return 1;
381 }
382
383 /* ****************************************************** */
384 /* HEADER FILE******************************************* */
385 /* ****************************************************** */
386
387 string header_file = header_filename;
388 if (header_output_dir.size())
389 header_file = header_output_dir + "/" + header_file;
390 else if (output_dir.size())
391 header_file = output_dir + "/" + header_file;
392
393 ofstream *output_file = open_fstream
394 (header_file.c_str());
395 generate_header (*output_file);
396 output_file->close ();
397 delete output_file;
398
399 return 0;
400 }
401
402 /**
403 * generate the enum value from a given option
404 * @param name the (canonized) name of the option
405 * @param val the value of the option
406 * @return the enum value string
407 */
from_value_to_enum(const string & name,const string & val)408 static const string from_value_to_enum(const string &name, const string &val) {
409 return name + "_arg_" + canonize_enum(val);
410 }
411
412 void
generate_enum_types(ostream & stream,unsigned int indentation)413 CmdlineParserCreator::generate_enum_types(ostream &stream,
414 unsigned int indentation)
415 {
416 struct gengetopt_option * opt;
417 FIX_UNUSED (indentation);
418
419 if (has_arg_enum)
420 stream << endl;
421
422 foropt {
423 // if type is enum then it should also have values (checked during parsing)
424 // but it's better to check it
425 if (opt->type == ARG_ENUM) {
426 if (! (opt->acceptedvalues)) {
427 fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
428 __FILE__, __LINE__);
429 abort ();
430 }
431 ostringstream enum_values;
432 enum_decl_gen_class enum_gen;
433 enum_gen.set_var_arg(opt->var_arg);
434 for (AcceptedValues::const_iterator iter = opt->acceptedvalues->begin();
435 iter != opt->acceptedvalues->end(); ++iter) {
436 enum_values << ", ";
437 // the first enum element is set to 0
438 enum_values << from_value_to_enum(opt->var_arg, *iter);
439 if (iter == opt->acceptedvalues->begin())
440 enum_values << " = 0";
441
442 }
443 enum_gen.set_enum_values(enum_values.str());
444 enum_gen.generate_enum_decl(stream);
445 }
446 }
447 }
448
449 void
generate_option_arg(ostream & stream,unsigned int indentation)450 CmdlineParserCreator::generate_option_arg(ostream &stream,
451 unsigned int indentation)
452 {
453 struct gengetopt_option * opt;
454
455 foropt {
456 _generate_option_arg (stream, indentation, opt);
457 }
458 }
459
460 void
_generate_option_arg(ostream & stream,unsigned int indentation,struct gengetopt_option * opt)461 _generate_option_arg(ostream &stream,
462 unsigned int indentation,
463 struct gengetopt_option *opt)
464 {
465 option_arg_gen_class option_arg_gen;
466
467 string type = "";
468 if (opt->type)
469 type = arg_types[opt->type];
470 string origtype = "char *";
471
472 if (opt->multiple) {
473 type += "*";
474 origtype += "*";
475 option_arg_gen.set_multiple(true);
476 } else {
477 option_arg_gen.set_multiple(false);
478 }
479
480 option_arg_gen.set_type(type);
481 option_arg_gen.set_origtype(origtype);
482 option_arg_gen.set_flag_arg((opt->type == ARG_FLAG));
483 option_arg_gen.set_desc(opt->desc);
484 option_arg_gen.set_name(opt->var_arg);
485 option_arg_gen.set_has_arg(opt->type != ARG_NO);
486 option_arg_gen.set_has_enum(opt->type == ARG_ENUM);
487
488 if (opt->default_given)
489 {
490 option_arg_gen.set_has_default(true);
491 option_arg_gen.set_default_value(opt->default_string);
492 }
493
494 if (opt->type == ARG_FLAG)
495 {
496 option_arg_gen.set_default_on(opt->flagstat);
497 }
498
499 if (opt->type == ARG_LONGLONG)
500 {
501 // the fallback type in case longlong is not supported by the compiler
502 string longtype = arg_types[ARG_LONG];
503 if (opt->multiple)
504 longtype += "*";
505
506 option_arg_gen.set_long_long_arg(true);
507 option_arg_gen.set_longtype(longtype);
508 }
509
510 option_arg_gen.generate_option_arg(stream, indentation);
511 }
512
513 void
generate_option_given(ostream & stream,unsigned int indentation)514 CmdlineParserCreator::generate_option_given(ostream &stream,
515 unsigned int indentation)
516 {
517 struct gengetopt_option * opt;
518 string indent_str (indentation, ' ');
519 bool first = true;
520 given_field_gen_class given_gen;
521
522 foropt
523 {
524 switch (opt->type) {
525 case ARG_NO:
526 case ARG_FLAG:
527 case ARG_STRING:
528 case ARG_INT:
529 case ARG_SHORT:
530 case ARG_LONG:
531 case ARG_FLOAT:
532 case ARG_DOUBLE:
533 case ARG_LONGDOUBLE:
534 case ARG_LONGLONG:
535 case ARG_ENUM:
536 break;
537 default:
538 fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
539 __FILE__, __LINE__);
540 abort ();
541 }
542 if (! first)
543 stream << indent_str;
544 else
545 first = false;
546
547 given_gen.set_arg_name (opt->var_arg);
548 given_gen.set_long_opt (opt->long_opt);
549 given_gen.set_group (opt->multiple && opt->group_value);
550 given_gen.generate_given_field (stream);
551 }
552
553 if (unnamed_options)
554 {
555 stream << endl;
556 stream << indent_str;
557 stream << "char **inputs ; /**< @brief unnamed options (options without names) */\n" ;
558 stream << indent_str;
559 stream << "unsigned inputs_num ; /**< @brief unnamed options number */" ;
560 }
561 }
562
563 void
generate_option_values_decl(ostream & stream,unsigned int indentation)564 CmdlineParserCreator::generate_option_values_decl(ostream &stream,
565 unsigned int indentation)
566 {
567 struct gengetopt_option * opt;
568 bool first = true;
569 FIX_UNUSED (indentation);
570
571 foropt
572 {
573 if (opt->acceptedvalues) {
574 if (first) {
575 first = false;
576 }
577
578 stream << "extern const char *" << OPTION_VALUES_NAME(opt->var_arg) <<
579 "[]; /**< @brief Possible values for " << opt->long_opt << ". */\n";
580 }
581 }
582
583 if (! first)
584 stream << "\n";
585 }
586
587 void
generate_option_values(ostream & stream,unsigned int indentation)588 CmdlineParserCreator::generate_option_values(ostream &stream,
589 unsigned int indentation)
590 {
591 struct gengetopt_option * opt;
592 bool first = true;
593 FIX_UNUSED (indentation);
594
595 foropt
596 {
597 if (opt->acceptedvalues) {
598 if (first) {
599 first = false;
600 }
601
602 stream << "const char *" << OPTION_VALUES_NAME(opt->var_arg) <<
603 "[] = {" << opt->acceptedvalues->toString(false) <<
604 ", 0}; /*< Possible values for " << opt->long_opt << ". */\n";
605 }
606 }
607
608 if (! first)
609 stream << "\n";
610 }
611
generate_option_usage_string(gengetopt_option * opt,ostream & usage)612 static void generate_option_usage_string(gengetopt_option * opt, ostream &usage) {
613 const char *type_str;
614
615 usage << " ";
616
617 if (!opt->required)
618 usage << "[";
619
620 switch (opt->type) {
621 case ARG_NO:
622 case ARG_FLAG:
623 if (opt->short_opt)
624 usage << "-" << opt->short_opt << "|";
625 usage << "--" << opt->long_opt;
626 break;
627 case ARG_INT:
628 case ARG_SHORT:
629 case ARG_LONG:
630 case ARG_FLOAT:
631 case ARG_DOUBLE:
632 case ARG_LONGDOUBLE:
633 case ARG_LONGLONG:
634 case ARG_STRING:
635 case ARG_ENUM:
636 if (opt->type_str)
637 type_str = opt->type_str;
638 else
639 type_str = arg_names[opt->type];
640
641 if (opt->short_opt)
642 usage << "-" << opt->short_opt << type_str << "|";
643 usage << "--" << opt->long_opt << "=" << type_str;
644
645 break;
646 default: fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
647 __FILE__, __LINE__);
648 abort ();
649 }
650
651 if (!opt->required)
652 usage << "]";
653 }
654
655 const string
generate_usage_string(bool use_config_package)656 CmdlineParserCreator::generate_usage_string(bool use_config_package)
657 {
658 FIX_UNUSED (use_config_package);
659 // if specified by the programmer, the usage string has the precedence
660 if (gengetopt_usage) {
661 string wrapped_usage;
662 wrap_cstr(wrapped_usage, 0, 0, gengetopt_usage);
663 return wrapped_usage;
664 }
665
666 struct gengetopt_option * opt;
667 ostringstream usage;
668
669 // otherwise the config.h package constant will be used
670 if (gengetopt_package)
671 usage << gengetopt_package;
672
673 if ( long_help ) {
674 // we first generate usage strings of required options
675 // handle mode options separately
676 foropt
677 if (opt->required && !opt->hidden && !opt->mode_value) {
678 generate_option_usage_string(opt, usage);
679 }
680
681 foropt
682 if (!opt->required && !opt->hidden && !opt->mode_value) {
683 generate_option_usage_string(opt, usage);
684 }
685 } else { /* if not long help we generate it as GNU standards */
686 usage << " [OPTION]...";
687 }
688
689 string wrapped;
690
691 if ( unnamed_options )
692 usage << " [" << unnamed_options << "]...";
693
694 wrap_cstr ( wrapped, strlen("Usage: "), 2, usage.str() );
695
696 // now deal with modes
697 if (has_modes && long_help) {
698 const ModeOptMap &modeoptmap = getModeOptMap();
699
700 for (ModeOptMap::const_iterator map_it = modeoptmap.begin(); map_it != modeoptmap.end(); ++map_it) {
701 string mode_line; // a mode alternative in the usage string
702 gengetopt_option_list::const_iterator opt_it;
703 usage.str(""); // reset the usage string buffer
704
705 // otherwise the config.h package constant will be used
706 if (gengetopt_package)
707 usage << gengetopt_package;
708
709 for (opt_it = map_it->second.begin(); opt_it != map_it->second.end(); ++opt_it) {
710 if (((*opt_it)->required) && !((*opt_it)->hidden)) {
711 generate_option_usage_string(*opt_it, usage);
712 }
713 }
714
715 for (opt_it = map_it->second.begin(); opt_it != map_it->second.end(); ++opt_it) {
716 if (!((*opt_it)->required) && !((*opt_it)->hidden)) {
717 generate_option_usage_string(*opt_it, usage);
718 }
719 }
720
721 wrap_cstr ( mode_line, strlen(" or : "), 2, usage.str() );
722 wrapped += "\\n or : ";
723 wrapped += mode_line;
724 }
725 }
726
727 return wrapped;
728 }
729
730 static void
generate_help_desc_print(ostream & stream,unsigned int desc_column,const char * descript,const char * defval,const string & values,const string & show_required_string)731 generate_help_desc_print(ostream &stream,
732 unsigned int desc_column,
733 const char *descript, const char *defval,
734 const string &values,
735 const string &show_required_string)
736 {
737 string desc;
738 string desc_with_default = descript;
739
740 if (defval || values.size()) {
741 desc_with_default += " (";
742
743 if (values.size()) {
744 desc_with_default += "possible values=";
745 desc_with_default += values;
746 if (defval)
747 desc_with_default += " ";
748 }
749
750 if (defval) {
751 desc_with_default += "default=";
752 desc_with_default += defval;
753 }
754
755 desc_with_default += ")";
756 }
757
758 if (show_required_string != "")
759 desc_with_default += " " + show_required_string;
760
761 wrap_cstr ( desc, desc_column, 2, desc_with_default );
762
763 stream << desc;
764 }
765
766
767 void
generate_help_option_print_from_lists(ostream & stream,unsigned int indentation,OptionHelpList * full_option_list,OptionHelpList * option_list,const std::string & target_array,const std::string & source_array)768 CmdlineParserCreator::generate_help_option_print_from_lists(ostream &stream,
769 unsigned int indentation, OptionHelpList *full_option_list,
770 OptionHelpList *option_list, const std::string &target_array,
771 const std::string &source_array) {
772 print_help_string_gen_class print_gen;
773
774 // the index into the help arrays
775 int i = 0, full_i = 0;
776 // num of help strings
777 int help_num = 0;
778
779 print_gen.set_target(target_array);
780 print_gen.set_from(source_array);
781 print_gen.set_shared(true);
782 print_gen.set_last(false);
783
784 OptionHelpList::const_iterator it = option_list->begin();
785 OptionHelpList::const_iterator it2 = full_option_list->begin();
786 // the second list is surely longer so we scan that one
787 for (; it != option_list->end() && it2 != full_option_list->end(); ++it2)
788 {
789 if (*it == *it2) {
790 // when the two strings are the same it means that's a non-hidden
791 // option, so we share it with the full help array
792 ostringstream converted_int;
793 converted_int << i;
794
795 // the index into the help array
796 print_gen.set_index(converted_int.str());
797
798 converted_int.str("");
799 converted_int << full_i;
800
801 // the index into the full help array
802 print_gen.set_full_index(converted_int.str());
803 print_gen.generate_print_help_string(stream, indentation);
804
805 ++help_num;
806 ++i;
807 ++it;
808 }
809 ++full_i;
810 }
811
812 ostringstream converted_int;
813 converted_int << help_num;
814
815 // the final 0
816 print_gen.set_last(true);
817 print_gen.set_index(converted_int.str());
818 print_gen.generate_print_help_string(stream, indentation);
819
820 // we increment it to store the final 0
821 converted_int.str("");
822 converted_int << ++help_num;
823
824 set_help_string_num(converted_int.str());
825
826 }
827
828 void
generate_help_option_print(ostream & stream,unsigned int indentation)829 CmdlineParserCreator::generate_help_option_print(ostream &stream,
830 unsigned int indentation)
831 {
832 OptionHelpList *option_list = generate_help_option_list();
833
834 if (!c_source_gen_class::has_hidden && !c_source_gen_class::has_details) {
835 print_help_string_gen_class print_gen;
836 print_gen.set_shared(false);
837
838 // simple help generation
839 for (OptionHelpList::const_iterator it = option_list->begin();
840 it != option_list->end(); ++it)
841 {
842 print_gen.set_helpstring(*it);
843 print_gen.generate_print_help_string(stream, indentation);
844 }
845 } else {
846 // in order to avoid generating the same help string twice, and thus
847 // to save memory, in case of hidden options (or details), we try to share most
848 // of the strings with the full help array
849 OptionHelpList *full_option_list = generate_help_option_list(true, true);
850
851 generate_help_option_print_from_lists
852 (stream, indentation, full_option_list, option_list,
853 c_source_gen_class::args_info + "_help",
854 (c_source_gen_class::has_details ?
855 c_source_gen_class::args_info + "_detailed_help" :
856 c_source_gen_class::args_info + "_full_help"));
857
858 delete full_option_list;
859 }
860
861 delete option_list;
862 }
863
864 void
generate_full_help_option_print(ostream & stream,unsigned int indentation)865 CmdlineParserCreator::generate_full_help_option_print(ostream &stream,
866 unsigned int indentation)
867 {
868 // generate also hidden options
869 OptionHelpList *option_list = generate_help_option_list(true);
870
871 if (!c_source_gen_class::has_details) {
872 print_help_string_gen_class print_gen;
873 print_gen.set_shared(false);
874
875 for (OptionHelpList::const_iterator it = option_list->begin();
876 it != option_list->end(); ++it)
877 {
878 print_gen.set_helpstring(*it);
879 print_gen.generate_print_help_string(stream, indentation);
880 }
881 } else {
882 // in order to avoid generating the same help string twice, and thus
883 // to save memory, in case of options with details, we try to share most
884 // of the strings with the full help array
885 OptionHelpList *full_option_list = generate_help_option_list(true, true);
886
887 generate_help_option_print_from_lists
888 (stream, indentation, full_option_list, option_list,
889 c_source_gen_class::args_info + "_full_help",
890 c_source_gen_class::args_info + "_detailed_help");
891
892 delete full_option_list;
893 }
894
895 delete option_list;
896 }
897
898 void
generate_detailed_help_option_print(ostream & stream,unsigned int indentation)899 CmdlineParserCreator::generate_detailed_help_option_print(ostream &stream,
900 unsigned int indentation)
901 {
902 // generate also hidden options and details
903 OptionHelpList *option_list = generate_help_option_list(true, true);
904
905 print_help_string_gen_class print_gen;
906 print_gen.set_shared(false);
907
908 for (OptionHelpList::const_iterator it = option_list->begin();
909 it != option_list->end(); ++it)
910 {
911 print_gen.set_helpstring(*it);
912 print_gen.generate_print_help_string(stream, indentation);
913 }
914
915 delete option_list;
916 }
917
918 void
generate_init_args_info(ostream & stream,unsigned int indentation)919 CmdlineParserCreator::generate_init_args_info(ostream &stream, unsigned int indentation)
920 {
921 struct gengetopt_option * opt;
922 init_args_info_gen_class init_args_info_gen;
923 int i = 0;
924 ostringstream index;
925
926 string help_string = c_source_gen_class::args_info;
927
928 if (c_source_gen_class::has_details) {
929 help_string += "_detailed_help";
930 } else if (c_source_gen_class::has_hidden) {
931 help_string += "_full_help";
932 } else {
933 help_string += "_help";
934 }
935 init_args_info_gen.set_help_strings(help_string);
936
937 const char *current_section = 0, *current_group = 0, *current_mode = 0;
938
939 // we have to skip section description references (that appear in the help vector)
940 foropt {
941 index.str("");
942
943 if (opt->section) {
944 if (!current_section || (strcmp(current_section, opt->section) != 0)) {
945 // a different section reference, skip it
946 current_section = opt->section;
947 ++i;
948
949 if (opt->section_desc) {
950 // section description takes another line, thus we have to skip this too
951 ++i;
952 }
953 }
954 }
955
956 // skip group desc
957 if (opt->group_value) {
958 if (!current_group || strcmp(current_group, opt->group_value) != 0) {
959 current_group = opt->group_value;
960 ++i;
961 }
962 }
963
964 // skip mode desc
965 if (opt->mode_value) {
966 if (!current_mode || strcmp(current_mode, opt->mode_value) != 0) {
967 current_mode = opt->mode_value;
968 ++i;
969 }
970 }
971
972 // also skip the text before
973 if (opt->text_before)
974 ++i;
975
976 index << i++;
977
978 init_args_info_gen.set_var_arg(opt->var_arg);
979 init_args_info_gen.set_num(index.str());
980
981 if (opt->multiple) {
982 init_args_info_gen.set_multiple(true);
983 init_args_info_gen.set_min(opt->multiple_min);
984 init_args_info_gen.set_max(opt->multiple_max);
985 } else {
986 init_args_info_gen.set_multiple(false);
987 }
988
989 init_args_info_gen.generate_init_args_info(stream, indentation);
990
991 // skip the details
992 if (opt->details)
993 ++i;
994
995 // skip the text after
996 if (opt->text_after)
997 ++i;
998
999 }
1000 }
1001
generate_custom_getopt(ostream & stream,unsigned int indentation)1002 void CmdlineParserCreator::generate_custom_getopt(ostream &stream, unsigned int indentation)
1003 {
1004 custom_getopt_gen_gen_class customgetopt;
1005
1006 customgetopt.generate_custom_getopt_gen (stream, indentation);
1007 }
1008
1009 const string
generate_purpose()1010 CmdlineParserCreator::generate_purpose()
1011 {
1012 string wrapped_purpose;
1013
1014 if (gengetopt_purpose != NULL)
1015 {
1016 wrap_cstr(wrapped_purpose, 0, 0, gengetopt_purpose);
1017 }
1018
1019 return wrapped_purpose;
1020 }
1021
1022 const string
generate_versiontext()1023 CmdlineParserCreator::generate_versiontext()
1024 {
1025 string wrapped_versiontext;
1026
1027 if (gengetopt_versiontext != NULL)
1028 {
1029 wrap_cstr(wrapped_versiontext, 0, 0, gengetopt_versiontext);
1030 }
1031
1032 return wrapped_versiontext;
1033 }
1034
1035 const string
generate_description()1036 CmdlineParserCreator::generate_description()
1037 {
1038 string wrapped_description;
1039
1040 if (gengetopt_description != NULL)
1041 {
1042 wrap_cstr(wrapped_description, 0, 0, gengetopt_description);
1043 }
1044
1045 return wrapped_description;
1046 }
1047
1048
1049 OptionHelpList *
generate_help_option_list(bool generate_hidden,bool generate_details)1050 CmdlineParserCreator::generate_help_option_list(bool generate_hidden, bool generate_details)
1051 {
1052 OptionHelpList *option_list = new OptionHelpList;
1053
1054 unsigned long desc_col;
1055 struct gengetopt_option * opt;
1056
1057 int type_len;
1058 const char *type_str;
1059 ostringstream stream;
1060
1061 // if we want to generate details then we will also generate hidden options
1062 if (strict_hidden)
1063 generate_hidden = false;
1064 else if (generate_details)
1065 generate_hidden = true;
1066
1067 /* calculate columns */
1068 desc_col = 0;
1069 foropt {
1070 // if (opt->hidden && !generate_hidden)
1071 // continue;
1072 // when computing columns, we also consider hidden_options, so that
1073 // the --help and --full-help will be aligned just the same
1074 // IMPORTANT: this is also crucial due to how the help string array
1075 // is built starting from the full-help string array:
1076 // we iterate over the two lists of options and check whether the
1077 // corresponding strings are the same; thus, the help strings must
1078 // have the same space alignments, otherwise they're not equal
1079
1080 unsigned int width = 2 + 4 + 2; // ws + "-a, " + ws
1081
1082 width += strlen (opt->long_opt) + 2; // "--"
1083
1084 if ((opt->type != ARG_FLAG) &&
1085 (opt->type != ARG_NO))
1086 {
1087 if (opt->type_str)
1088 type_str = opt->type_str;
1089 else
1090 type_str = arg_names[opt->type];
1091 type_len = strlen(type_str);
1092
1093 width += type_len + 1; // "="
1094
1095 if (opt->arg_is_optional)
1096 width += 2; // "[" and "]"
1097 }
1098
1099 if (width > desc_col)
1100 desc_col = width;
1101 }
1102
1103 if (desc_col > MAX_STARTING_COLUMN)
1104 desc_col = MAX_STARTING_COLUMN;
1105
1106 /* print justified options */
1107 char *prev_group = 0;
1108 char *prev_mode = 0;
1109 char *curr_section = 0;
1110 bool first_option = true;
1111
1112 foropt
1113 {
1114 // if the option is hidden and has no text, avoid printing a section
1115 // containing only hidden options
1116 if (opt->section &&
1117 (!curr_section || strcmp (curr_section, opt->section)) &&
1118 (!opt->hidden || generate_hidden ||
1119 opt->text_before || opt->text_after))
1120 {
1121 curr_section = opt->section;
1122
1123 ostringstream sec_string;
1124
1125 if (! first_option)
1126 sec_string << "\\n";
1127
1128 sec_string << opt->section << ":" ;
1129
1130 string wrapped_def;
1131 wrap_cstr(wrapped_def, 0, 0, sec_string.str());
1132 option_list->push_back(wrapped_def);
1133
1134 if (opt->section_desc)
1135 {
1136 string wrapped_desc ( 2, ' ');
1137 wrap_cstr ( wrapped_desc, 2, 0, opt->section_desc );
1138
1139 option_list->push_back(wrapped_desc);
1140 }
1141 }
1142
1143 if (opt->group_value &&
1144 (! prev_group || strcmp (opt->group_value, prev_group) != 0))
1145 {
1146 string group_string = "\\n Group: ";
1147 string wrapped_desc;
1148
1149 if (opt->group_desc && strlen (opt->group_desc))
1150 {
1151 wrapped_desc = "\\n ";
1152 wrap_cstr (wrapped_desc, 2, 0, opt->group_desc);
1153 }
1154
1155 group_string += opt->group_value + wrapped_desc;
1156
1157 option_list->push_back (group_string);
1158
1159 prev_group = opt->group_value;
1160 }
1161
1162 if (opt->mode_value &&
1163 (! prev_mode || strcmp (opt->mode_value, prev_mode) != 0))
1164 {
1165 string mode_string = "\\n Mode: ";
1166 string wrapped_desc;
1167
1168 if (opt->mode_desc && strlen (opt->mode_desc))
1169 {
1170 wrapped_desc = "\\n ";
1171 wrap_cstr (wrapped_desc, 2, 0, opt->mode_desc);
1172 }
1173
1174 mode_string += opt->mode_value + wrapped_desc;
1175
1176 option_list->push_back (mode_string);
1177
1178 prev_mode = opt->mode_value;
1179 }
1180
1181 // a possible description to be printed before this option
1182 if (opt->text_before)
1183 {
1184 string wrapped_desc;
1185 wrap_cstr ( wrapped_desc, 0, 0, opt->text_before);
1186
1187 option_list->push_back(wrapped_desc);
1188 }
1189
1190 if (!opt->hidden || generate_hidden) {
1191 first_option = false;
1192 const char * def_val = NULL;
1193 string def_str = "`";
1194
1195 ostringstream option_stream;
1196
1197 if (opt->type == ARG_FLAG || opt->type == ARG_NO)
1198 {
1199 def_val = NULL;
1200
1201 if (opt->short_opt)
1202 option_stream << " -" << opt->short_opt << ", ";
1203 else
1204 option_stream << " ";
1205
1206 option_stream << "--" << opt->long_opt;
1207
1208 if (opt->type == ARG_FLAG)
1209 def_val = opt->flagstat ? "on" : "off";
1210 }
1211 else
1212 {
1213 def_val = NULL;
1214
1215 if (opt->type_str)
1216 type_str = opt->type_str;
1217 else
1218 type_str = arg_names[opt->type];
1219
1220 type_len = strlen(type_str);
1221
1222 if (opt->short_opt)
1223 {
1224 option_stream << " -" << opt->short_opt << ", ";
1225 }
1226 else
1227 {
1228 option_stream << " ";
1229 }
1230
1231 bool arg_optional = opt->arg_is_optional;
1232 option_stream << "--" << opt->long_opt
1233 << (arg_optional ? "[" : "")
1234 << "=" << type_str
1235 << (arg_optional ? "]" : "");
1236
1237 if (opt->default_string)
1238 {
1239 def_str += opt->default_string;
1240 def_str += "'";
1241 def_val = def_str.c_str();
1242 }
1243 }
1244
1245 const string &option_string = option_stream.str();
1246 stream << option_string;
1247 const char *opt_desc = opt->desc;
1248
1249 if ((option_string.size() >= MAX_STARTING_COLUMN) ||
1250 (desc_col <= option_string.size()))
1251 {
1252 string indentation (MAX_STARTING_COLUMN, ' ');
1253 stream << "\\n" << indentation;
1254 }
1255 else
1256 {
1257 string indentation (desc_col - option_string.size(), ' ');
1258 stream << indentation;
1259 }
1260
1261 generate_help_desc_print(stream, desc_col, opt_desc, def_val,
1262 (opt->acceptedvalues ? opt->acceptedvalues->toString() : ""),
1263 (opt->required && show_required_string != "" ? show_required_string : ""));
1264
1265 option_list->push_back(stream.str());
1266 stream.str("");
1267 }
1268
1269 // before the text, we generate details if we need to and the option isn't hidden
1270 if (opt->details && generate_details && (!opt->hidden || generate_hidden)) {
1271 string wrapped_desc ( 2, ' ');
1272 // details are indented
1273 wrap_cstr ( wrapped_desc, 2, 0, opt->details);
1274
1275 option_list->push_back(wrapped_desc);
1276 }
1277
1278 // a possible description to be printed after this option
1279 if (opt->text_after)
1280 {
1281 string wrapped_desc;
1282 wrap_cstr ( wrapped_desc, 0, 0, opt->text_after);
1283
1284 option_list->push_back(wrapped_desc);
1285 }
1286 }
1287
1288 return option_list;
1289 }
1290
1291 template <typename Collection>
generate_counter_init(const Collection & collection,const string & name,ostream & stream,unsigned int indentation)1292 void generate_counter_init(const Collection &collection, const string &name, ostream &stream, unsigned int indentation)
1293 {
1294 string indent_str (indentation, ' ');
1295 typename Collection::const_iterator end = collection.end();
1296
1297 for ( typename Collection::const_iterator idx = collection.begin(); idx != end; ++idx)
1298 {
1299 stream << indent_str;
1300 stream << ARGS_STRUCT << "->" << canonize_name (idx->first) << "_" <<
1301 name << "_counter = 0 ;";
1302 stream << endl;
1303 }
1304 }
1305
1306 void
generate_given_init(ostream & stream,unsigned int indentation)1307 CmdlineParserCreator::generate_given_init(ostream &stream,
1308 unsigned int indentation)
1309 {
1310 struct gengetopt_option * opt;
1311 string indent_str (indentation, ' ');
1312 clear_given_gen_class clear_given;
1313 clear_given.set_arg_struct(ARGS_STRUCT);
1314
1315 /* now we initialize "given" fields */
1316 foropt
1317 {
1318 stream << indent_str;
1319 clear_given.set_var_arg(opt->var_arg);
1320 clear_given.set_group(opt->multiple && opt->group_value);
1321 clear_given.generate_clear_given(stream);
1322 }
1323
1324 // for group counter initialization
1325 generate_counter_init(gengetopt_groups, "group", stream, indentation);
1326
1327 // for mode counter initialization
1328 generate_counter_init(gengetopt_modes, "mode", stream, indentation);
1329 }
1330
1331 void
generate_reset_groups(ostream & stream,unsigned int indentation)1332 CmdlineParserCreator::generate_reset_groups(ostream &stream, unsigned int indentation)
1333 {
1334 struct gengetopt_option * opt;
1335 string indent_str (indentation, ' ');
1336 ostringstream body;
1337 reset_group_gen_class reset_group;
1338 clear_given_gen_class clear_given;
1339 clear_given.set_arg_struct(ARGS_STRUCT);
1340
1341 reset_group.set_args_info (c_source_gen_class::args_info);
1342
1343 groups_collection_t::const_iterator end = gengetopt_groups.end();
1344 for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
1345 idx != end; ++idx)
1346 {
1347 body.str ("");
1348 bool found_option = false;
1349
1350 foropt
1351 {
1352 if (opt->group_value && strcmp(opt->group_value, idx->first.c_str()) == 0)
1353 {
1354 /* now we reset "given" fields */
1355 stream << indent_str;
1356 clear_given.set_var_arg(opt->var_arg);
1357 clear_given.set_group(opt->multiple && opt->group_value);
1358 clear_given.generate_clear_given(body);
1359
1360 free_option (opt, body, indentation);
1361 found_option = true;
1362 }
1363 }
1364
1365 if (found_option)
1366 {
1367 reset_group.set_name (canonize_name (idx->first));
1368 reset_group.set_body (body.str ());
1369 reset_group.generate_reset_group (stream);
1370 }
1371 }
1372 }
1373
1374 void
free_option(struct gengetopt_option * opt,ostream & stream,unsigned int indentation)1375 CmdlineParserCreator::free_option(struct gengetopt_option *opt,
1376 ostream &stream, unsigned int indentation)
1377 {
1378 if (opt->type == ARG_NO)
1379 return;
1380
1381 if (opt->type != ARG_FLAG)
1382 {
1383 if (opt->multiple)
1384 {
1385 free_multiple_gen_class free_multiple;
1386 free_multiple.set_has_string_type(opt->type == ARG_STRING);
1387 free_multiple.set_structure (ARGS_STRUCT);
1388
1389 free_multiple.set_opt_var (opt->var_arg);
1390 free_multiple.generate_free_multiple
1391 (stream, indentation);
1392 }
1393 else
1394 {
1395 free_string_gen_class free_string;
1396 free_string.set_has_string_type(opt->type == ARG_STRING);
1397 free_string.set_structure (ARGS_STRUCT);
1398
1399 free_string.set_opt_var (opt->var_arg);
1400 free_string.generate_free_string (stream, indentation);
1401 }
1402 }
1403 }
1404
1405 void
generate_list_def(ostream & stream,unsigned int indentation)1406 CmdlineParserCreator::generate_list_def(ostream &stream, unsigned int indentation)
1407 {
1408 struct gengetopt_option * opt;
1409 string indent_str (indentation, ' ');
1410 multiple_opt_list_gen_class multiple_opt_list;
1411
1412 /* define linked-list structs for multiple options */
1413 foropt
1414 {
1415 if (opt->multiple)
1416 {
1417 if (opt->type)
1418 {
1419 stream << indent_str;
1420 multiple_opt_list.set_arg_name (opt->var_arg);
1421 multiple_opt_list.generate_multiple_opt_list (stream, indentation);
1422 stream << endl;
1423 }
1424 }
1425 }
1426 }
1427
1428 void
generate_multiple_fill_array(ostream & stream,unsigned int indentation)1429 CmdlineParserCreator::generate_multiple_fill_array(ostream &stream, unsigned int indentation)
1430 {
1431 struct gengetopt_option * opt;
1432 string indent_str (indentation, ' ');
1433 multiple_fill_array_gen_class filler;
1434
1435 /* copy linked list into the array */
1436 foropt
1437 {
1438 if (opt->multiple && opt->type)
1439 {
1440 stream << indent_str;
1441 filler.set_option_var_name (opt->var_arg);
1442 filler.set_arg_type(arg_type_constants[opt->type]);
1443 filler.set_type (arg_types_names[opt->type]);
1444 string default_string = "0";
1445 if (opt->default_string) {
1446 if (opt->type == ARG_STRING)
1447 default_string = string("\"") + opt->default_string + "\"";
1448 else if (opt->type == ARG_ENUM)
1449 default_string = from_value_to_enum(opt->var_arg, opt->default_string);
1450 else
1451 default_string = opt->default_string;
1452 }
1453 filler.set_default_value (default_string);
1454
1455 filler.generate_multiple_fill_array (stream, indentation);
1456
1457 stream << endl;
1458 }
1459 }
1460 }
1461
1462 void
generate_update_multiple_given(ostream & stream,unsigned int indentation)1463 CmdlineParserCreator::generate_update_multiple_given(ostream &stream, unsigned int indentation)
1464 {
1465 if (! has_multiple_options())
1466 return;
1467
1468 string indent_str (indentation, ' ');
1469
1470 stream << endl;
1471 stream << indent_str;
1472
1473 update_given_gen_class update_given_gen;
1474 struct gengetopt_option * opt;
1475
1476 foropt
1477 {
1478 if (opt->multiple)
1479 {
1480 update_given_gen.set_option_var_name (opt->var_arg);
1481 update_given_gen.generate_update_given (stream, indentation);
1482 }
1483 }
1484 }
1485
1486 void
generate_check_modes(ostream & stream,unsigned int indentation)1487 CmdlineParserCreator::generate_check_modes(ostream &stream, unsigned int indentation)
1488 {
1489 // no need to check for conflict if there's only one mode
1490 if (gengetopt_modes.size() < 2)
1491 return;
1492
1493 string indent_str (indentation, ' ');
1494
1495 stream << endl;
1496 stream << indent_str;
1497
1498 const ModeOptionMap &modeoptionmap = getModeOptionMap();
1499
1500 check_modes_gen_class check_modes_gen;
1501
1502 // now we check each mode options against every other mode options:
1503 // the first one with the other n-1, the second one with the other n-2, etc.
1504 ModeOptionMap::const_iterator map_it1, map_it2;
1505 for (ModeOptionMap::const_iterator map_it = modeoptionmap.begin(); map_it != modeoptionmap.end(); ++map_it) {
1506 map_it1 = map_it;
1507 ++map_it;
1508 if (map_it == modeoptionmap.end())
1509 break;
1510 for (map_it2 = map_it; map_it2 != modeoptionmap.end(); ++map_it2) {
1511 const string mode1 = canonize_name(map_it1->first);
1512 const string mode2 = canonize_name(map_it2->first);
1513
1514 check_modes_gen.set_mode1_name(mode1);
1515 check_modes_gen.set_mode2_name(mode2);
1516
1517 ostringstream mode1_given, mode2_given, mode1_options, mode2_options;
1518
1519 std::for_each(map_it1->second.begin(), map_it1->second.end(), pair_print_f<OptionValueElem>(mode1_given, mode1_options));
1520 std::for_each(map_it2->second.begin(), map_it2->second.end(), pair_print_f<OptionValueElem>(mode2_given, mode2_options));
1521
1522 check_modes_gen.set_mode1_given_fields(mode1_given.str());
1523 check_modes_gen.set_mode1_options(mode1_options.str());
1524 check_modes_gen.set_mode2_given_fields(mode2_given.str());
1525 check_modes_gen.set_mode2_options(mode2_options.str());
1526
1527 check_modes_gen.generate_check_modes(stream, indentation);
1528 }
1529 map_it = map_it1;
1530 }
1531 }
1532
1533 void
generate_clear_arg(ostream & stream,unsigned int indentation)1534 CmdlineParserCreator::generate_clear_arg(ostream &stream, unsigned int indentation)
1535 {
1536 struct gengetopt_option * opt;
1537 clear_arg_gen_class cleararg;
1538
1539 /* now we initialize value fields */
1540 foropt
1541 {
1542 if (opt->type == ARG_NO)
1543 continue;
1544
1545 cleararg.set_name(opt->var_arg);
1546 cleararg.set_suffix("arg");
1547 cleararg.set_value("NULL");
1548 cleararg.set_has_orig(opt->type != ARG_FLAG);
1549 cleararg.set_has_arg(false);
1550
1551 if (opt->multiple && opt->type)
1552 {
1553 cleararg.set_has_arg(true);
1554 }
1555 else if (opt->type == ARG_STRING)
1556 {
1557 cleararg.set_has_arg(true);
1558 if (opt->default_given)
1559 cleararg.set_value
1560 ("gengetopt_strdup (\"" + string(opt->default_string) +
1561 "\")");
1562 }
1563 else if (opt->type == ARG_FLAG)
1564 {
1565 cleararg.set_has_arg(true);
1566 cleararg.set_suffix("flag");
1567 cleararg.set_value(opt->flagstat ? "1" : "0");
1568 }
1569 else if (opt->type == ARG_ENUM)
1570 {
1571 // initialize enum arguments to -1 (unless they have a default)
1572 cleararg.set_has_arg(true);
1573 if (opt->default_given)
1574 cleararg.set_value(from_value_to_enum(opt->var_arg, opt->default_string));
1575 else
1576 cleararg.set_value(string(opt->var_arg) + "__NULL");
1577 }
1578 else if (opt->default_given)
1579 {
1580 cleararg.set_has_arg(true);
1581 cleararg.set_value(opt->default_string);
1582 }
1583
1584 cleararg.generate_clear_arg(stream, indentation);
1585 }
1586 }
1587
1588 void
generate_long_option_struct(ostream & stream,unsigned int indentation)1589 CmdlineParserCreator::generate_long_option_struct(ostream &stream,
1590 unsigned int indentation)
1591 {
1592 string indent_str (indentation, ' ');
1593 struct gengetopt_option * opt;
1594
1595 foropt
1596 {
1597 stream << indent_str;
1598
1599 stream << "{ \"" << opt->long_opt << "\",\t"
1600 << (opt->type == ARG_NO || opt->type == ARG_FLAG ? 0 :
1601 (opt->arg_is_optional ? 2 : 1))
1602 << ", NULL, ";
1603
1604 if (opt->short_opt)
1605 stream << "\'" << opt->short_opt << "\'";
1606 else
1607 stream << "0";
1608
1609 stream << " }," << endl;
1610 }
1611 }
1612
1613 string
generate_getopt_string()1614 CmdlineParserCreator::generate_getopt_string()
1615 {
1616 struct gengetopt_option * opt;
1617 ostringstream built_getopt_string;
1618
1619 foropt
1620 if (opt->short_opt)
1621 {
1622 built_getopt_string << opt->short_opt <<
1623 (opt->type == ARG_NO || opt->type == ARG_FLAG ? "" : ":");
1624 built_getopt_string <<
1625 (opt->arg_is_optional ? ":" : "");
1626 }
1627
1628 return built_getopt_string.str ();
1629 }
1630
1631 void
generate_handle_no_short_option(ostream & stream,unsigned int indentation)1632 CmdlineParserCreator::generate_handle_no_short_option(ostream &stream,
1633 unsigned int indentation)
1634 {
1635 handle_options(stream, indentation, false);
1636 }
1637
1638 void
generate_handle_option(ostream & stream,unsigned int indentation)1639 CmdlineParserCreator::generate_handle_option(ostream &stream,
1640 unsigned int indentation)
1641 {
1642 handle_options(stream, indentation, true);
1643 }
1644
1645 void
handle_options(ostream & stream,unsigned int indentation,bool has_short)1646 CmdlineParserCreator::handle_options(ostream &stream, unsigned int indentation, bool has_short)
1647 {
1648 struct gengetopt_option * opt;
1649 generic_option_gen_class option_gen;
1650 string indent_str (indentation, ' ');
1651 bool first = true;
1652
1653 option_gen.set_has_short_option (has_short);
1654
1655 // by default we handle '?' case in the switch
1656 // unless the user defined a short option as ?
1657 set_handle_question_mark(true);
1658
1659 foropt
1660 {
1661 if (opt->short_opt == '?')
1662 set_handle_question_mark(false);
1663
1664 if ((has_short && opt->short_opt) || (!has_short && !opt->short_opt))
1665 {
1666 if (has_short || first)
1667 stream << indent_str;
1668
1669 option_gen.set_option_comment (opt->desc);
1670 option_gen.set_long_option (opt->long_opt);
1671 option_gen.set_short_option(opt->short_opt ? string (1, opt->short_opt) : "-");
1672 option_gen.set_option_var_name (opt->var_arg);
1673 option_gen.set_final_instructions("");
1674
1675 if (!no_help && ((opt->short_opt == HELP_SHORT_OPT &&
1676 strcmp(opt->long_opt, HELP_LONG_OPT) == 0)
1677 || strcmp(opt->long_opt, HELP_LONG_OPT) == 0
1678 || strcmp(opt->long_opt, FULL_HELP_LONG_OPT) == 0
1679 || strcmp(opt->long_opt, DETAILED_HELP_LONG_OPT) == 0)) {
1680 bool full_help = (strcmp(opt->long_opt, FULL_HELP_LONG_OPT) == 0);
1681 bool detailed_help = (strcmp(opt->long_opt, DETAILED_HELP_LONG_OPT) == 0);
1682 if (no_handle_help) {
1683 // we use the final_instructions parameter to call the free function
1684 // and to return 0
1685 const string final_instructions =
1686 parser_function_name +
1687 string("_free (&local_args_info);\nreturn 0;");
1688
1689 option_gen.set_final_instructions(final_instructions);
1690
1691 if (full_help) {
1692 option_gen.set_long_option (FULL_HELP_LONG_OPT);
1693 option_gen.set_option_comment (FULL_HELP_OPT_DESCR);
1694 } else if (detailed_help) {
1695 option_gen.set_long_option (DETAILED_HELP_LONG_OPT);
1696 option_gen.set_option_comment (DETAILED_HELP_OPT_DESCR);
1697 } else {
1698 option_gen.set_long_option (HELP_LONG_OPT);
1699 option_gen.set_short_option (HELP_SHORT_OPT_STR);
1700 option_gen.set_option_comment (HELP_OPT_DESCR);
1701 }
1702 //option_gen.set_has_short_option (!full_help);
1703 } else {
1704 handle_help_gen_class help_gen;
1705 help_gen.set_parser_name (parser_function_name);
1706 help_gen.set_full_help(full_help);
1707 help_gen.set_detailed_help(detailed_help);
1708 help_gen.set_short_opt(opt->short_opt == HELP_SHORT_OPT);
1709 help_gen.generate_handle_help (stream, indentation);
1710 stream << endl;
1711 stream << endl;
1712 continue;
1713 }
1714 }
1715
1716 if (!no_version && ((opt->short_opt == VERSION_SHORT_OPT && strcmp(opt->long_opt, VERSION_LONG_OPT) == 0)
1717 || strcmp(opt->long_opt, VERSION_LONG_OPT) == 0)) {
1718 if (no_handle_version) {
1719 option_gen.set_long_option (VERSION_LONG_OPT);
1720 option_gen.set_short_option (VERSION_SHORT_OPT_STR);
1721 option_gen.set_option_comment (VERSION_OPT_DESCR);
1722 //option_gen.set_has_short_option (true);
1723
1724 // we use the final_instrauctions parameter to call the free function
1725 // and to return 0
1726 const string final_instructions =
1727 parser_function_name +
1728 string("_free (&local_args_info);\nreturn 0;");
1729
1730 option_gen.set_final_instructions(final_instructions);
1731 } else {
1732 handle_version_gen_class version_gen;
1733 version_gen.set_parser_name (parser_function_name);
1734 version_gen.set_short_opt (opt->short_opt == VERSION_SHORT_OPT);
1735 version_gen.generate_handle_version (stream, indentation);
1736 stream << endl;
1737 stream << endl;
1738 continue;
1739 }
1740 }
1741
1742 if (opt->acceptedvalues != 0)
1743 option_gen.set_possible_values (OPTION_VALUES_NAME(opt->var_arg));
1744 else
1745 option_gen.set_possible_values ("0");
1746
1747 string default_string = "0";
1748 if (opt->default_string)
1749 default_string = string("\"") + opt->default_string + "\"";
1750 option_gen.set_default_value (default_string);
1751
1752 option_gen.set_arg_type(arg_type_constants[opt->type]);
1753
1754 if (opt->group_value) {
1755 option_gen.set_group_var_name (canonize_name (opt->group_value));
1756 option_gen.set_option_has_group(true);
1757 } else
1758 option_gen.set_option_has_group(false);
1759
1760 if (opt->mode_value) {
1761 // we reuse the variable group_var_name also for modes
1762 option_gen.set_group_var_name (canonize_name (opt->mode_value));
1763 option_gen.set_option_has_mode(true);
1764 } else
1765 option_gen.set_option_has_mode(false);
1766
1767 option_gen.set_option_has_type(opt->type != 0);
1768
1769 if (opt->multiple) {
1770 option_gen.set_multiple(true);
1771 option_gen.set_structure (string (opt->var_arg) + "_list");
1772 } else {
1773 option_gen.set_multiple(false);
1774 option_gen.set_structure (ARGS_STRUCT);
1775 }
1776
1777 option_gen.generate_generic_option (stream, indentation);
1778
1779 if (has_short)
1780 {
1781 stream << endl;
1782 }
1783
1784 if (first && !has_short)
1785 {
1786 first = false;
1787 option_gen.set_gen_else ("else ");
1788 }
1789 }
1790 }
1791
1792 if (! first && !has_short) // something has been generated
1793 {
1794 generateBreak(stream, indentation);
1795 stream << endl;
1796 }
1797 }
1798
1799 #define GROUP_REQUIRED_COMPARISON "!="
1800 #define GROUP_NOT_REQUIRED_COMPARISON ">"
1801 #define GROUP_REQUIRED_MESSAGE "One"
1802 #define GROUP_NOT_REQUIRED_MESSAGE "At most one"
1803
1804 void
generate_handle_group(ostream & stream,unsigned int indentation)1805 CmdlineParserCreator::generate_handle_group(ostream &stream,
1806 unsigned int indentation)
1807 {
1808 group_option_gen_class opt_gen;
1809 string indent_str (indentation, ' ');
1810 opt_gen.set_package_var_name (EXE_NAME);
1811
1812 opt_gen.set_Comparison_rule(GROUP_NOT_REQUIRED_COMPARISON " 1");
1813
1814 groups_collection_t::const_iterator end = gengetopt_groups.end();
1815 for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
1816 idx != end; ++idx)
1817 {
1818 stream << indent_str;
1819 opt_gen.set_group_name (idx->first);
1820 opt_gen.set_group_var_name (canonize_name (idx->first));
1821 if (idx->second.required)
1822 {
1823 opt_gen.set_number_required(GROUP_REQUIRED_MESSAGE);
1824 }
1825 else
1826 {
1827 opt_gen.set_number_required(GROUP_NOT_REQUIRED_MESSAGE);
1828 }
1829
1830 opt_gen.generate_group_option (stream, indentation);
1831 stream << endl;
1832 }
1833 }
1834
1835 void
generate_handle_required(ostream & stream,unsigned int indentation)1836 CmdlineParserCreator::generate_handle_required(ostream &stream,
1837 unsigned int indentation)
1838 {
1839 struct gengetopt_option * opt;
1840 required_option_gen_class opt_gen;
1841 opt_gen.set_package_var_name ("prog_name");
1842
1843 /* write test for required options or for multiple options
1844 (occurrence number check) */
1845 foropt
1846 if ( opt->required || opt->multiple )
1847 {
1848 if (opt->mode_value) {
1849 opt_gen.set_mode_condition("args_info->" +
1850 canonize_name(opt->mode_value) + "_mode_counter && ");
1851 } else {
1852 opt_gen.set_mode_condition("");
1853 }
1854
1855 // build the option command line representation
1856 ostringstream req_opt;
1857 req_opt << "'--" << opt->long_opt << "'";
1858 if (opt->short_opt)
1859 req_opt << " ('-" << opt->short_opt << "')";
1860
1861 opt_gen.set_option_var_name (opt->var_arg);
1862 opt_gen.set_option_descr (req_opt.str ());
1863
1864 // if the option is required this is the standard check
1865 if (opt->required) {
1866 opt_gen.set_checkrange(false);
1867
1868 opt_gen.generate_required_option (stream, indentation);
1869 }
1870
1871 // if the option is multiple we generate also the
1872 // occurrence range check
1873 if (opt->multiple) {
1874 opt_gen.set_checkrange(true);
1875
1876 opt_gen.generate_required_option (stream, indentation);
1877 }
1878
1879 // notice that the above ifs are not mutually exclusive:
1880 // a multiple option can have a range check without being
1881 // required.
1882 }
1883
1884 // now generate the checks for required group options
1885 group_option_gen_class group_opt_gen;
1886 group_opt_gen.set_package_var_name ("prog_name");
1887
1888 group_opt_gen.set_Comparison_rule("== 0");
1889 group_opt_gen.set_number_required(GROUP_REQUIRED_MESSAGE);
1890
1891 groups_collection_t::const_iterator end = gengetopt_groups.end();
1892 for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
1893 idx != end; ++idx)
1894 {
1895 if (idx->second.required)
1896 {
1897 group_opt_gen.set_group_name (idx->first);
1898 group_opt_gen.set_group_var_name (canonize_name (idx->first));
1899
1900 group_opt_gen.generate_group_option (stream, indentation);
1901 stream << endl;
1902 }
1903 }
1904 }
1905
1906 void
generate_handle_dependencies(ostream & stream,unsigned int indentation)1907 CmdlineParserCreator::generate_handle_dependencies(ostream &stream,
1908 unsigned int indentation)
1909 {
1910 struct gengetopt_option * opt;
1911 dependant_option_gen_class opt_gen;
1912 opt_gen.set_package_var_name ("prog_name");
1913 string indent_str (indentation, ' ');
1914
1915 /* write test for required options */
1916 foropt
1917 if ( opt->dependon )
1918 {
1919 stream << indent_str;
1920
1921 ostringstream req_opt;
1922 req_opt << "'--" << opt->long_opt << "'";
1923 if (opt->short_opt)
1924 req_opt << " ('-" << opt->short_opt << "')";
1925
1926 opt_gen.set_option_var_name (opt->var_arg);
1927 opt_gen.set_dep_option (canonize_name(opt->dependon));
1928 opt_gen.set_option_descr (req_opt.str ());
1929 opt_gen.set_dep_option_descr (opt->dependon);
1930
1931 opt_gen.generate_dependant_option (stream, indentation);
1932
1933 stream << endl;
1934 }
1935 }
1936
1937 template <typename Collection>
generate_counters(const Collection & collection,const string & name,ostream & stream,unsigned int indentation)1938 void generate_counters(const Collection &collection, const string &name, ostream &stream, unsigned int indentation)
1939 {
1940 group_counter_gen_class counter_gen;
1941 string indent_str (indentation, ' ');
1942
1943 counter_gen.set_name(name);
1944
1945 typename Collection::const_iterator end = collection.end();
1946 for ( typename Collection::const_iterator idx = collection.begin(); idx != end; ++idx) {
1947 stream << indent_str;
1948 counter_gen.set_group_name (canonize_name (idx->first));
1949 counter_gen.generate_group_counter (stream, indentation);
1950 stream << endl;
1951 }
1952 }
1953
1954 void
generate_group_counters(ostream & stream,unsigned int indentation)1955 CmdlineParserCreator::generate_group_counters(ostream &stream,
1956 unsigned int indentation)
1957 {
1958 generate_counters(gengetopt_groups, "group", stream, indentation);
1959 }
1960
1961 void
generate_mode_counters(ostream & stream,unsigned int indentation)1962 CmdlineParserCreator::generate_mode_counters(ostream &stream,
1963 unsigned int indentation)
1964 {
1965 // we can reuse group counter gen class also for modes
1966 generate_counters(gengetopt_modes, "mode", stream, indentation);
1967 }
1968
1969 int
generate_source()1970 CmdlineParserCreator::generate_source ()
1971 {
1972 /* ****************************************************** */
1973 /* ********************************************** C FILE */
1974 /* ****************************************************** */
1975
1976 set_usage_string (generate_usage_string ());
1977 set_getopt_string (generate_getopt_string ());
1978
1979 string output_source = c_filename;
1980
1981 if (src_output_dir.size())
1982 output_source = src_output_dir + "/" + output_source;
1983 else if (output_dir.size())
1984 output_source = output_dir + "/" + output_source;
1985
1986 ofstream *output_file = open_fstream (output_source.c_str());
1987 generate_c_source (*output_file);
1988 output_file->close ();
1989 delete output_file;
1990
1991 return 0;
1992 }
1993
1994 void
generate_free(ostream & stream,unsigned int indentation)1995 CmdlineParserCreator::generate_free(ostream &stream,
1996 unsigned int indentation)
1997 {
1998 struct gengetopt_option * opt;
1999
2000 foropt
2001 {
2002 free_option (opt, stream, indentation);
2003 }
2004 }
2005
2006 void
generate_list_free(ostream & stream,unsigned int indentation)2007 CmdlineParserCreator::generate_list_free(ostream &stream,
2008 unsigned int indentation)
2009 {
2010 struct gengetopt_option * opt;
2011
2012 if (! has_multiple_options())
2013 return;
2014
2015 free_list_gen_class free_list;
2016
2017 foropt
2018 {
2019 if (opt->multiple && opt->type) {
2020 free_list.set_list_name(opt->var_arg);
2021 free_list.set_string_list(opt->type == ARG_STRING);
2022 free_list.generate_free_list(stream, indentation);
2023 }
2024 }
2025 }
2026
2027 void
generate_file_save_loop(ostream & stream,unsigned int indentation)2028 CmdlineParserCreator::generate_file_save_loop(ostream &stream, unsigned int indentation)
2029 {
2030 struct gengetopt_option * opt;
2031
2032 file_save_multiple_gen_class file_save_multiple;
2033 file_save_gen_class file_save;
2034
2035 const string suffix = "_orig";
2036 const string suffix_given = "_given";
2037
2038 foropt {
2039 if (opt->multiple) {
2040 file_save_multiple.set_has_arg(opt->type != ARG_NO);
2041 file_save_multiple.set_opt_var(opt->var_arg);
2042 file_save_multiple.set_opt_name(opt->long_opt);
2043 file_save_multiple.set_values
2044 ((opt->acceptedvalues ? OPTION_VALUES_NAME(opt->var_arg) : "0"));
2045
2046 file_save_multiple.generate_file_save_multiple(stream, indentation);
2047 } else {
2048 file_save.set_opt_name(opt->long_opt);
2049 file_save.set_given(opt->var_arg + suffix_given);
2050 file_save.set_values
2051 ((opt->acceptedvalues ? OPTION_VALUES_NAME(opt->var_arg) : "0"));
2052
2053 if (opt->type != ARG_NO && opt->type != ARG_FLAG) {
2054 file_save.set_arg(opt->var_arg + suffix + (opt->multiple ? " [i]" : ""));
2055 } else {
2056 file_save.set_arg("");
2057 }
2058 file_save.generate_file_save(stream, indentation);
2059 }
2060 }
2061 }
2062
2063
2064