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