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