]> Creatis software - clitk.git/blobdiff - utilities/gengetopt/gm.cc
Sync gengetopt cmake files with rtk
[clitk.git] / utilities / gengetopt / gm.cc
diff --git a/utilities/gengetopt/gm.cc b/utilities/gengetopt/gm.cc
new file mode 100644 (file)
index 0000000..0e7b70a
--- /dev/null
@@ -0,0 +1,2042 @@
+/**
+ * Copyright (C) 1999-2010  Free Software Foundation, Inc.
+ *
+ * This file is part of GNU gengetopt
+ *
+ * GNU gengetopt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU gengetopt is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with gengetopt; see the file COPYING. If not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+#include <set>
+#include <algorithm> // for pair
+
+#include <fstream>
+
+extern "C"
+{
+#include "argsdef.h"
+#include "global_opts.h"
+};
+
+#include "ggo_options.h"
+
+#include "gm.h"
+#include "my_sstream.h"
+
+#include "groups.h"
+#include "skels/option_arg.h"
+#include "skels/required_option.h"
+#include "skels/dependant_option.h"
+#include "skels/generic_option.h"
+#include "skels/group_option.h"
+#include "skels/group_counter.h"
+#include "skels/handle_help.h"
+#include "skels/handle_version.h"
+#include "skels/print_help_string.h"
+#include "skels/multiple_opt_list.h"
+#include "skels/multiple_fill_array.h"
+#include "skels/free_string.h"
+#include "skels/free_multiple.h"
+#include "skels/reset_group.h"
+#include "skels/exit_failure.h"
+#include "skels/update_given.h"
+#include "skels/given_field.h"
+#include "skels/clear_given.h"
+#include "skels/clear_arg.h"
+#include "skels/free_list.h"
+#include "skels/file_save.h"
+#include "skels/file_save_multiple.h"
+#include "skels/init_args_info.h"
+#include "skels/custom_getopt_gen.h"
+#include "skels/check_modes.h"
+#include "skels/enum_decl.h"
+#include "gm_utils.h"
+#include "fileutils.h"
+
+#ifndef FIX_UNUSED
+#define FIX_UNUSED(X) (void) (X)
+#endif // FIX_UNUSED
+
+#define MAX_STARTING_COLUMN 32
+
+#define EXE_NAME "argv[0]"
+
+#define PARSER_NAME_PREFIX (c_source_gen_class::parser_name + "_")
+#define OPTION_VALUES_NAME(n) (PARSER_NAME_PREFIX + n + "_values")
+
+using std::endl;
+using std::set;
+
+extern char * gengetopt_package;
+extern char * gengetopt_version;
+extern char * gengetopt_purpose;
+extern char * gengetopt_description;
+extern char * gengetopt_usage;
+extern char * gengetopt_input_filename;
+
+extern groups_collection_t gengetopt_groups;
+extern modes_collection_t gengetopt_modes;
+
+// a map where for each mode we store the corresponding given field names
+// and the options
+typedef std::pair<string, string> OptionValueElem;
+typedef std::list<OptionValueElem> ModeOptions;
+typedef std::map<string, ModeOptions> ModeOptionMap;
+
+static ModeOptionMap modeOptionMap;
+
+static const ModeOptionMap &getModeOptionMap() {
+    if (modeOptionMap.size() == 0) {
+        // it's the first time, so we build it
+        struct gengetopt_option * opt;
+        foropt {
+            if (opt->mode_value) {
+                modeOptionMap[opt->mode_value].push_back
+                (std::make_pair("args_info->" + string(opt->var_arg) + "_given",
+                        string("\"--") + opt->long_opt + "\""));
+            }
+        }
+    }
+
+    return modeOptionMap;
+}
+
+// a map associating to a mode the list of gengetopt_options
+typedef std::map<string, gengetopt_option_list> ModeOptMap;
+
+static ModeOptMap modeOptMap;
+
+static const ModeOptMap &getModeOptMap() {
+    if (modeOptMap.size() == 0) {
+        // it's the first time, so we build it
+        struct gengetopt_option * opt;
+        foropt {
+            if (opt->mode_value) {
+                modeOptMap[opt->mode_value].push_back(opt);
+            }
+        }
+    }
+
+    return modeOptMap;
+}
+
+static void _generate_option_arg(ostream &stream,
+                                 unsigned int indent,
+                                 struct gengetopt_option * opt);
+
+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);
+
+CmdlineParserCreator::CmdlineParserCreator (char *function_name,
+                                            char *struct_name,
+                                            char *unamed_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 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) :
+  filename (filename_),
+  args_info_name (struct_name),
+  output_dir (outdir),
+  header_output_dir (header_outdir),
+  src_output_dir (src_outdir),
+  comment (comment_),
+  unamed_options (unamed_options_),
+  show_required_string (show_required),
+  long_help (long_help_), no_handle_help (no_handle_help_),
+  no_help (no_help_),
+  no_handle_version (no_handle_version_),
+  no_version (no_version_),
+  no_handle_error (no_handle_error_),
+  conf_parser (conf_parser_), string_parser (string_parser_),
+  gen_gengetopt_version (gen_version),
+  tab_indentation (0)
+{
+  parser_function_name = canonize_names (function_name);
+  c_filename = create_filename (filename, c_ext);
+  header_filename = create_filename (filename, header_ext);
+
+  // header_gen_class
+  const string stripped_header_file_name = strip_path (filename);
+  set_header_file_name (stripped_header_file_name);
+  header_gen_class::set_header_file_ext (header_ext);
+  c_source_gen_class::set_header_file_ext (header_ext);
+  if (gen_gengetopt_version)
+    header_gen_class::set_generator_version
+      ("version " VERSION);
+  const string my_ifndefname =
+    to_upper (strip_path (stripped_header_file_name));
+  set_ifndefname (canonize_names (my_ifndefname.c_str ()));
+  header_gen_class::set_parser_name (parser_function_name);
+  const string my_package_var_name =
+    to_upper (parser_function_name) + "_PACKAGE";
+  const string my_version_var_name =
+    to_upper (parser_function_name) + "_VERSION";
+  header_gen_class::set_package_var_name (my_package_var_name);
+  c_source_gen_class::set_package_var_name (my_package_var_name);
+  header_gen_class::set_version_var_name (my_version_var_name);
+  c_source_gen_class::set_version_var_name (my_version_var_name);
+  header_gen_class::set_args_info (args_info_name);
+  c_source_gen_class::set_args_info (args_info_name);
+  const string uppersand = "\"";
+
+  // if no_options then we don't need to generate update_arg,
+  // but if we need to handle help or version we still need to generate it
+  set_no_options (no_options_ && !no_handle_help && !no_handle_version);
+
+  if (gengetopt_package)
+    set_package_var_val
+      (uppersand + gengetopt_package + uppersand);
+  else
+    set_package_var_val ("PACKAGE");
+
+  if (gengetopt_version)
+    set_version_var_val
+      (uppersand + gengetopt_version + uppersand);
+  else
+    set_version_var_val ("VERSION");
+
+  header_gen_class::set_generate_config_parser (conf_parser);
+
+  header_gen_class::set_generate_string_parser (string_parser);
+  c_source_gen_class::set_generate_string_parser (string_parser);
+
+  // c_source_gen_class
+  set_command_line (comment);
+  if (gen_gengetopt_version)
+    c_source_gen_class::set_generator_version
+      ("version " VERSION);
+  c_source_gen_class::set_parser_name (parser_function_name);
+  set_source_name (filename);
+
+  ostringstream exit_failure_str;
+  exit_failure_gen_class exit_gen;
+  exit_gen.set_parser_name (c_source_gen_class::parser_name);
+  exit_gen.set_handle_error (! no_handle_error);
+  exit_gen.generate_exit_failure (exit_failure_str);
+  set_final_exit (exit_failure_str.str ());
+
+  set_conf_parser (conf_parser);
+  set_cmd_list (conf_parser || string_parser);
+  set_include_getopt (gen_getopt);
+
+  struct gengetopt_option * opt;
+  gen_strdup = (unamed_options != 0 || conf_parser || string_parser);
+
+  if (! gen_strdup)
+    {
+      foropt
+        if (opt->type != ARG_FLAG || opt->type != ARG_NO) {
+          gen_strdup = true;
+          break;
+        }
+    }
+
+  set_do_generate_strdup(gen_strdup);
+  set_check_possible_values(has_values());
+  set_multiple_token_functions(has_multiple_options_with_type());
+  set_multiple_options_with_default(has_multiple_options_with_default());
+  set_multiple_options(has_multiple_options());
+  set_multiple_options_string(has_multiple_options_string());
+  set_multiple_options_all_string(has_multiple_options_all_string());
+  set_has_typed_options(has_options_with_type());
+  set_has_modes(has_options_with_mode());
+  set_handle_unamed(unamed_options);
+  set_check_required_options(has_required() || has_dependencies() || has_multiple_options());
+  set_purpose(generate_purpose());
+  set_description(generate_description());
+  set_no_package((gengetopt_package == 0));
+  c_source_gen_class::set_has_hidden(has_hidden_options());
+  header_gen_class::set_has_hidden(c_source_gen_class::has_hidden);
+  c_source_gen_class::set_has_details(has_options_with_details());
+  header_gen_class::set_has_details(c_source_gen_class::has_details);
+
+  set_has_arg_types();
+}
+
+void CmdlineParserCreator::set_has_arg_types() {
+    struct gengetopt_option * opt;
+
+    set_has_arg_flag(false);
+    set_has_arg_string(false);
+    set_has_arg_int(false);
+    set_has_arg_short(false);
+    set_has_arg_long(false);
+    set_has_arg_float(false);
+    set_has_arg_double(false);
+    set_has_arg_longdouble(false);
+    set_has_arg_longlong(false);
+
+    foropt
+    {
+        switch (opt->type) {
+        case ARG_NO:
+            break;
+        case ARG_FLAG:
+            set_has_arg_flag(true);
+            break;
+        case ARG_STRING:
+            set_has_arg_string(true);
+            break;
+        case ARG_INT:
+            set_has_arg_int(true);
+            break;
+        case ARG_SHORT:
+            set_has_arg_short(true);
+            break;
+        case ARG_LONG:
+            set_has_arg_long(true);
+            break;
+        case ARG_FLOAT:
+            set_has_arg_float(true);
+            break;
+        case ARG_DOUBLE:
+            set_has_arg_double(true);
+            break;
+        case ARG_LONGDOUBLE:
+            set_has_arg_longdouble(true);
+            break;
+        case ARG_LONGLONG:
+            set_has_arg_longlong(true);
+            break;
+        case ARG_ENUM:
+            set_has_arg_enum(true);
+            break;
+        default:
+            fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
+                    __FILE__, __LINE__);
+            abort ();
+        }
+    }
+
+}
+
+void
+CmdlineParserCreator::generateBreak(ostream &stream, unsigned int indent)
+{
+  string indent_str (indent, ' ');
+
+  stream << endl;
+  stream << indent_str;
+  stream << "break;";
+}
+
+int
+CmdlineParserCreator::generate ()
+{
+  int head_result;
+
+  head_result = generate_header_file ();
+  if (head_result)
+    return head_result;
+
+  return generate_source ();
+}
+
+int
+CmdlineParserCreator::generate_header_file ()
+{
+  if (! gengetopt_options.size())
+    {
+      fprintf (stderr, "gengetopt: none option given\n");
+      return 1;
+    }
+
+  /* ****************************************************** */
+  /* HEADER FILE******************************************* */
+  /* ****************************************************** */
+
+    string header_file = header_filename;
+    if (header_output_dir.size())
+        header_file = header_output_dir + "/" + header_file;
+    else if (output_dir.size())
+        header_file = output_dir + "/" + header_file;
+
+    ofstream *output_file = open_fstream
+            (header_file.c_str());
+    generate_header (*output_file);
+    output_file->close ();
+    delete output_file;
+
+    return 0;
+}
+
+/**
+ * generate the enum value from a given option
+ * @param name the (canonized) name of the option
+ * @param val the value of the option
+ * @return the enum value string
+ */
+static const string from_value_to_enum(const string &name, const string &val) {
+    return name + "_arg_" + canonize_enum(val);
+}
+
+void
+CmdlineParserCreator::generate_enum_types(ostream &stream,
+                                          unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  FIX_UNUSED (indent);
+
+  if (has_arg_enum)
+      stream << endl;
+
+  foropt {
+    // if type is enum then it should also have values (checked during parsing)
+    // but it's better to check it
+    if (opt->type == ARG_ENUM) {
+        if (! (opt->acceptedvalues)) {
+            fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
+                            __FILE__, __LINE__);
+            abort ();
+        }
+        ostringstream enum_values;
+        enum_decl_gen_class enum_gen;
+        enum_gen.set_var_arg(opt->var_arg);
+        for (AcceptedValues::const_iterator it = opt->acceptedvalues->begin();
+            it != opt->acceptedvalues->end(); ++it) {
+            enum_values << ", ";
+            // the first enum element is set to 0
+            enum_values << from_value_to_enum(opt->var_arg, *it);
+            if (it == opt->acceptedvalues->begin())
+                enum_values << " = 0";
+
+        }
+        enum_gen.set_enum_values(enum_values.str());
+        enum_gen.generate_enum_decl(stream);
+    }
+  }
+}
+
+void
+CmdlineParserCreator::generate_option_arg(ostream &stream,
+                                          unsigned int indent)
+{
+  struct gengetopt_option * opt;
+
+  foropt {
+    _generate_option_arg (stream, indent, opt);
+  }
+}
+
+void
+_generate_option_arg(ostream &stream,
+                     unsigned int indent,
+                     struct gengetopt_option *opt)
+{
+  option_arg_gen_class option_arg_gen;
+
+  string type = "";
+  if (opt->type)
+      type = arg_types[opt->type];
+  string origtype = "char *";
+
+  if (opt->multiple) {
+    type += "*";
+    origtype += "*";
+    option_arg_gen.set_multiple(true);
+  } else {
+    option_arg_gen.set_multiple(false);
+  }
+
+  option_arg_gen.set_type(type);
+  option_arg_gen.set_origtype(origtype);
+  option_arg_gen.set_flag_arg((opt->type == ARG_FLAG));
+  option_arg_gen.set_desc(opt->desc);
+  option_arg_gen.set_name(opt->var_arg);
+  option_arg_gen.set_has_arg(opt->type != ARG_NO);
+  option_arg_gen.set_has_enum(opt->type == ARG_ENUM);
+
+  if (opt->default_given)
+    {
+      option_arg_gen.set_has_default(true);
+      option_arg_gen.set_default_value(opt->default_string);
+    }
+
+  if (opt->type == ARG_FLAG)
+    {
+      option_arg_gen.set_default_on(opt->flagstat);
+    }
+
+  if (opt->type == ARG_LONGLONG)
+    {
+      // the fallback type in case longlong is not supported by the compiler
+      string longtype = arg_types[ARG_LONG];
+      if (opt->multiple)
+          longtype += "*";
+
+      option_arg_gen.set_long_long_arg(true);
+      option_arg_gen.set_longtype(longtype);
+    }
+
+  option_arg_gen.generate_option_arg(stream, indent);
+}
+
+void
+CmdlineParserCreator::generate_option_given(ostream &stream,
+                                            unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  string indent_str (indent, ' ');
+  bool first = true;
+  given_field_gen_class given_gen;
+
+  foropt
+    {
+      switch (opt->type) {
+      case ARG_NO:
+      case ARG_FLAG:
+      case ARG_STRING:
+      case ARG_INT:
+      case ARG_SHORT:
+      case ARG_LONG:
+      case ARG_FLOAT:
+      case ARG_DOUBLE:
+      case ARG_LONGDOUBLE:
+      case ARG_LONGLONG:
+      case ARG_ENUM:
+          break;
+      default:
+        fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
+                 __FILE__, __LINE__);
+        abort ();
+      }
+      if (! first)
+        stream << indent_str;
+      else
+        first = false;
+
+      given_gen.set_arg_name (opt->var_arg);
+      given_gen.set_long_opt (opt->long_opt);
+      given_gen.set_group (opt->multiple && opt->group_value);
+      given_gen.generate_given_field (stream);
+    }
+
+  if (unamed_options)
+    {
+      stream << endl;
+      stream << indent_str;
+      stream << "char **inputs ; /**< @brief unamed options (options without names) */\n" ;
+      stream << indent_str;
+      stream << "unsigned inputs_num ; /**< @brief unamed options number */" ;
+    }
+}
+
+void
+CmdlineParserCreator::generate_option_values_decl(ostream &stream,
+                                                  unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  bool first = true;
+  FIX_UNUSED (indent);
+
+  foropt
+    {
+      if (opt->acceptedvalues) {
+        if (first) {
+          first = false;
+        }
+
+        stream << "extern const char *" << OPTION_VALUES_NAME(opt->var_arg) <<
+          "[];  /**< @brief Possible values for " << opt->long_opt << ". */\n";
+      }
+    }
+
+  if (! first)
+    stream << "\n";
+}
+
+void
+CmdlineParserCreator::generate_option_values(ostream &stream,
+                                             unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  bool first = true;
+  FIX_UNUSED (indent);
+
+  foropt
+    {
+      if (opt->acceptedvalues) {
+        if (first) {
+          first = false;
+        }
+
+        stream << "const char *" << OPTION_VALUES_NAME(opt->var_arg) <<
+          "[] = {" << opt->acceptedvalues->toString(false) <<
+          ", 0}; /*< Possible values for " << opt->long_opt << ". */\n";
+      }
+    }
+
+  if (! first)
+    stream << "\n";
+}
+
+static void generate_option_usage_string(gengetopt_option * opt, ostream &usage) {
+    const char   *type_str;
+
+    usage << " ";
+
+    if (!opt->required)
+        usage << "[";
+
+    switch (opt->type) {
+    case ARG_NO:
+    case ARG_FLAG:
+        if (opt->short_opt)
+            usage << "-" << opt->short_opt << "|";
+        usage << "--" << opt->long_opt;
+        break;
+    case ARG_INT:
+    case ARG_SHORT:
+    case ARG_LONG:
+    case ARG_FLOAT:
+    case ARG_DOUBLE:
+    case ARG_LONGDOUBLE:
+    case ARG_LONGLONG:
+    case ARG_STRING:
+    case ARG_ENUM:
+        if (opt->type_str)
+            type_str = opt->type_str;
+        else
+            type_str = arg_names[opt->type];
+
+        if (opt->short_opt)
+            usage << "-" << opt->short_opt << type_str << "|";
+        usage << "--" << opt->long_opt << "=" << type_str;
+
+        break;
+    default: fprintf (stderr, "gengetopt: bug found in %s:%d!!\n",
+            __FILE__, __LINE__);
+    abort ();
+    }
+
+    if (!opt->required)
+        usage << "]";
+}
+
+const string
+CmdlineParserCreator::generate_usage_string(bool use_config_package)
+{
+  FIX_UNUSED (use_config_package);
+  // if specified by the programmer, the usage string has the precedence
+  if (gengetopt_usage) {
+    return gengetopt_usage;
+  }
+
+  struct gengetopt_option * opt;
+  ostringstream usage;
+
+  // otherwise the config.h package constant will be used
+  if (gengetopt_package)
+    usage << gengetopt_package;
+
+  if ( long_help ) {
+      // we first generate usage strings of required options
+      // handle mode options separately
+      foropt
+          if (opt->required && !opt->hidden && !opt->mode_value) {
+              generate_option_usage_string(opt, usage);
+          }
+
+      foropt
+          if (!opt->required && !opt->hidden && !opt->mode_value) {
+              generate_option_usage_string(opt, usage);
+          }
+  } else { /* if not long help we generate it as GNU standards */
+      usage << " [OPTIONS]...";
+  }
+
+  string wrapped;
+
+  if ( unamed_options )
+      usage << " [" << unamed_options << "]...";
+
+  wrap_cstr ( wrapped, strlen("Usage: "), 2, usage.str() );
+
+  // now deal with modes
+  if (has_modes && long_help) {
+      const ModeOptMap &modeOptMap = getModeOptMap();
+
+      for (ModeOptMap::const_iterator map_it = modeOptMap.begin(); map_it != modeOptMap.end(); ++map_it) {
+          string mode_line; // a mode alternative in the usage string
+          gengetopt_option_list::const_iterator opt_it;
+          usage.str(""); // reset the usage string buffer
+
+          for (opt_it = map_it->second.begin(); opt_it != map_it->second.end(); ++opt_it) {
+              if (((*opt_it)->required) && !((*opt_it)->hidden)) {
+                  generate_option_usage_string(*opt_it, usage);
+              }
+          }
+
+          for (opt_it = map_it->second.begin(); opt_it != map_it->second.end(); ++opt_it) {
+              if (!((*opt_it)->required) && !((*opt_it)->hidden)) {
+                  generate_option_usage_string(*opt_it, usage);
+              }
+          }
+
+          wrap_cstr ( mode_line, strlen("  or : "), 2, gengetopt_package + usage.str() );
+          wrapped += "\\n  or : ";
+          wrapped += mode_line;
+      }
+  }
+
+  return wrapped;
+}
+
+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)
+{
+  string desc;
+  string desc_with_default = descript;
+
+  if (defval || values.size()) {
+      desc_with_default += "  (";
+
+      if (values.size()) {
+        desc_with_default += "possible values=";
+        desc_with_default += values;
+        if (defval)
+          desc_with_default += " ";
+      }
+
+      if (defval) {
+        desc_with_default += "default=";
+        desc_with_default += defval;
+      }
+
+      desc_with_default += ")";
+  }
+
+  if (show_required_string != "")
+    desc_with_default += " " + show_required_string;
+
+  wrap_cstr ( desc, desc_column, 2, desc_with_default );
+
+  stream << desc;
+}
+
+
+void
+CmdlineParserCreator::generate_help_option_print_from_lists(ostream &stream,
+        unsigned int indent, OptionHelpList *full_option_list,
+        OptionHelpList *option_list, const std::string &target_array,
+        const std::string &source_array) {
+    print_help_string_gen_class print_gen;
+
+    // the index into the help arrays
+    int i = 0, full_i = 0;
+    // num of help strings
+    int help_num = 0;
+
+    print_gen.set_target(target_array);
+    print_gen.set_from(source_array);
+    print_gen.set_shared(true);
+    print_gen.set_last(false);
+
+    OptionHelpList::const_iterator it = option_list->begin();
+    OptionHelpList::const_iterator it2 = full_option_list->begin();
+    // the second list is surely longer so we scan that one
+    for (; it != option_list->end() && it2 != full_option_list->end(); ++it2)
+    {
+        if (*it == *it2) {
+            // when the two strings are the same it means that's a non-hidden
+            // option, so we share it with the full help array
+            ostringstream converted_int;
+            converted_int << i;
+
+            // the index into the help array
+            print_gen.set_index(converted_int.str());
+
+            converted_int.str("");
+            converted_int << full_i;
+
+            // the index into the full help array
+            print_gen.set_full_index(converted_int.str());
+            print_gen.generate_print_help_string(stream, indent);
+
+            ++help_num;
+            ++i;
+            ++it;
+        }
+        ++full_i;
+    }
+
+    ostringstream converted_int;
+    converted_int << help_num;
+
+    // the final 0
+    print_gen.set_last(true);
+    print_gen.set_index(converted_int.str());
+    print_gen.generate_print_help_string(stream, indent);
+
+    // we increment it to store the final 0
+    converted_int.str("");
+    converted_int << ++help_num;
+
+    set_help_string_num(converted_int.str());
+
+}
+
+void
+CmdlineParserCreator::generate_help_option_print(ostream &stream,
+                                                 unsigned int indent)
+{
+    OptionHelpList *option_list = generate_help_option_list();
+
+    if (!c_source_gen_class::has_hidden && !c_source_gen_class::has_details) {
+        print_help_string_gen_class print_gen;
+        print_gen.set_shared(false);
+
+        // simple help generation
+        for (OptionHelpList::const_iterator it = option_list->begin();
+        it != option_list->end(); ++it)
+        {
+            print_gen.set_helpstring(*it);
+            print_gen.generate_print_help_string(stream, indent);
+        }
+    } else {
+        // in order to avoid generating the same help string twice, and thus
+        // to save memory, in case of hidden options (or details), we try to share most
+        // of the strings with the full help array
+        OptionHelpList *full_option_list = generate_help_option_list(true, true);
+
+        generate_help_option_print_from_lists
+        (stream, indent, full_option_list, option_list,
+                c_source_gen_class::args_info + "_help",
+                (c_source_gen_class::has_details ?
+                        c_source_gen_class::args_info + "_detailed_help" :
+                            c_source_gen_class::args_info + "_full_help"));
+
+        delete full_option_list;
+    }
+
+    delete option_list;
+}
+
+void
+CmdlineParserCreator::generate_full_help_option_print(ostream &stream,
+        unsigned int indent)
+{
+    // generate also hidden options
+    OptionHelpList *option_list = generate_help_option_list(true);
+
+    if (!c_source_gen_class::has_details) {
+        print_help_string_gen_class print_gen;
+        print_gen.set_shared(false);
+
+        for (OptionHelpList::const_iterator it = option_list->begin();
+        it != option_list->end(); ++it)
+        {
+            print_gen.set_helpstring(*it);
+            print_gen.generate_print_help_string(stream, indent);
+        }
+    } else {
+        // in order to avoid generating the same help string twice, and thus
+        // to save memory, in case of options with details, we try to share most
+        // of the strings with the full help array
+        OptionHelpList *full_option_list = generate_help_option_list(true, true);
+
+        generate_help_option_print_from_lists
+        (stream, indent, full_option_list, option_list,
+                c_source_gen_class::args_info + "_full_help",
+                c_source_gen_class::args_info + "_detailed_help");
+
+        delete full_option_list;
+    }
+
+    delete option_list;
+}
+
+void
+CmdlineParserCreator::generate_detailed_help_option_print(ostream &stream,
+        unsigned int indent)
+{
+    // generate also hidden options and details
+    OptionHelpList *option_list = generate_help_option_list(true, true);
+
+    print_help_string_gen_class print_gen;
+    print_gen.set_shared(false);
+
+    for (OptionHelpList::const_iterator it = option_list->begin();
+         it != option_list->end(); ++it)
+    {
+        print_gen.set_helpstring(*it);
+        print_gen.generate_print_help_string(stream, indent);
+    }
+
+    delete option_list;
+}
+
+void
+CmdlineParserCreator::generate_init_args_info(ostream &stream, unsigned int indent)
+{
+    struct gengetopt_option * opt;
+    init_args_info_gen_class init_args_info_gen;
+    int i = 0;
+    ostringstream index;
+
+    string help_string = c_source_gen_class::args_info;
+
+    if (c_source_gen_class::has_details) {
+        help_string += "_detailed_help";
+    } else if (c_source_gen_class::has_hidden) {
+        help_string += "_full_help";
+    } else {
+        help_string += "_help";
+    }
+    init_args_info_gen.set_help_strings(help_string);
+
+    const char *current_section = 0, *current_group = 0, *current_mode = 0;
+
+    // we have to skip section description references (that appear in the help vector)
+    foropt {
+        index.str("");
+
+        if (opt->section) {
+          if (!current_section || (strcmp(current_section, opt->section) != 0)) {
+            // a different section reference, skip it
+            current_section = opt->section;
+            ++i;
+
+            if (opt->section_desc) {
+              // section description takes another line, thus we have to skip this too
+              ++i;
+            }
+          }
+        }
+
+        // skip group desc
+        if (opt->group_value) {
+            if (!current_group || strcmp(current_group, opt->group_value) != 0) {
+                current_group = opt->group_value;
+                ++i;
+            }
+        }
+
+        // skip mode desc
+        if (opt->mode_value) {
+            if (!current_mode || strcmp(current_mode, opt->mode_value) != 0) {
+                current_mode = opt->mode_value;
+                ++i;
+            }
+        }
+
+        // also skip the text before
+        if (opt->text_before)
+            ++i;
+
+        index << i++;
+
+        init_args_info_gen.set_var_arg(opt->var_arg);
+        init_args_info_gen.set_num(index.str());
+
+        if (opt->multiple) {
+            init_args_info_gen.set_multiple(true);
+            init_args_info_gen.set_min(opt->multiple_min);
+            init_args_info_gen.set_max(opt->multiple_max);
+        } else {
+            init_args_info_gen.set_multiple(false);
+        }
+
+        init_args_info_gen.generate_init_args_info(stream, indent);
+
+        // skip the details
+        if (opt->details)
+            ++i;
+
+        // skip the text after
+        if (opt->text_after)
+            ++i;
+
+    }
+}
+
+void CmdlineParserCreator::generate_custom_getopt(ostream &stream, unsigned int indent)
+{
+    custom_getopt_gen_gen_class custom_getopt;
+
+    custom_getopt.generate_custom_getopt_gen (stream, indent);
+}
+
+const string
+CmdlineParserCreator::generate_purpose()
+{
+  string wrapped_purpose;
+
+  if (gengetopt_purpose != NULL)
+    {
+      wrap_cstr(wrapped_purpose, 0, 0, gengetopt_purpose);
+    }
+
+  return wrapped_purpose;
+}
+
+const string
+CmdlineParserCreator::generate_description()
+{
+  string wrapped_description;
+
+  if (gengetopt_description != NULL)
+    {
+      wrap_cstr(wrapped_description, 0, 0, gengetopt_description);
+    }
+
+  return wrapped_description;
+}
+
+
+OptionHelpList *
+CmdlineParserCreator::generate_help_option_list(bool generate_hidden, bool generate_details)
+{
+  OptionHelpList *option_list = new OptionHelpList;
+
+  unsigned long desc_col;
+  struct gengetopt_option * opt;
+
+  int           type_len;
+  const char   *type_str;
+  ostringstream stream;
+
+  // if we want to generate details then we will also generate hidden options
+  if (generate_details)
+      generate_hidden = true;
+
+  /* calculate columns */
+  desc_col = 0;
+  foropt {
+    // if (opt->hidden && !generate_hidden)
+    //    continue;
+    // when computing columns, we also consider hidden_options, so that
+    // the --help and --full-help will be aligned just the same
+    // IMPORTANT: this is also crucial due to how the help string array
+    // is built starting from the full-help string array:
+    // we iterate over the two lists of options and check whether the
+    // corresponding strings are the same; thus, the help strings must
+    // have the same space alignments, otherwise they're not equal
+
+    unsigned int width = 2 + 4 + 2;  // ws + "-a, " + ws
+
+    width += strlen (opt->long_opt) + 2;  // "--"
+
+    if ((opt->type != ARG_FLAG) &&
+        (opt->type != ARG_NO))
+      {
+        if (opt->type_str)
+          type_str = opt->type_str;
+        else
+          type_str = arg_names[opt->type];
+        type_len = strlen(type_str);
+
+        width += type_len + 1;        // "="
+
+        if (opt->arg_is_optional)
+          width += 2; // "[" and "]"
+      }
+
+    if (width > desc_col)
+      desc_col = width;
+  }
+
+  if (desc_col > MAX_STARTING_COLUMN)
+    desc_col = MAX_STARTING_COLUMN;
+
+  /* print justified options */
+  char *prev_group = 0;
+  char *prev_mode = 0;
+  char *curr_section = 0;
+  bool first_option = true;
+
+  foropt
+    {
+      // if the option is hidden, avoid to print a section containing only
+      // hidden options
+      if (opt->section &&
+              (!curr_section || strcmp (curr_section, opt->section)) &&
+              (!opt->hidden || generate_hidden))
+      {
+          curr_section = opt->section;
+
+          ostringstream sec_string;
+
+          if (! first_option)
+              sec_string << "\\n";
+
+          sec_string << opt->section << ":" ;
+
+          string wrapped_def;
+          wrap_cstr(wrapped_def, 0, 0, sec_string.str());
+          option_list->push_back(wrapped_def);
+
+          if (opt->section_desc)
+          {
+              string wrapped_desc ( 2, ' ');
+              wrap_cstr ( wrapped_desc, 2, 0, opt->section_desc );
+
+              option_list->push_back(wrapped_desc);
+          }
+      }
+
+      if (opt->group_value &&
+              (! prev_group || strcmp (opt->group_value, prev_group) != 0))
+      {
+          string group_string = "\\n Group: ";
+          string wrapped_desc;
+
+          if (opt->group_desc && strlen (opt->group_desc))
+          {
+              wrapped_desc = "\\n  ";
+              wrap_cstr (wrapped_desc, 2, 0, opt->group_desc);
+          }
+
+          group_string += opt->group_value + wrapped_desc;
+
+          option_list->push_back (group_string);
+
+          prev_group = opt->group_value;
+      }
+
+      if (opt->mode_value &&
+              (! prev_mode || strcmp (opt->mode_value, prev_mode) != 0))
+      {
+          string mode_string = "\\n Mode: ";
+          string wrapped_desc;
+
+          if (opt->mode_desc && strlen (opt->mode_desc))
+          {
+              wrapped_desc = "\\n  ";
+              wrap_cstr (wrapped_desc, 2, 0, opt->mode_desc);
+          }
+
+          mode_string += opt->mode_value + wrapped_desc;
+
+          option_list->push_back (mode_string);
+
+          prev_mode = opt->mode_value;
+      }
+
+      // a possible description to be printed before this option
+      if (opt->text_before)
+      {
+          string wrapped_desc;
+          wrap_cstr ( wrapped_desc, 0, 0, opt->text_before);
+
+          option_list->push_back(wrapped_desc);
+      }
+
+      if (!opt->hidden || generate_hidden) {
+          first_option = false;
+          const char * def_val = NULL;
+          string def_str = "`";
+
+          ostringstream option_stream;
+
+          if (opt->type == ARG_FLAG || opt->type == ARG_NO)
+          {
+              def_val = NULL;
+
+              if (opt->short_opt)
+                  option_stream << "  -" << opt->short_opt << ", ";
+              else
+                  option_stream << "      ";
+
+              option_stream << "--" << opt->long_opt;
+
+              if (opt->type == ARG_FLAG)
+                  def_val = opt->flagstat ? "on" : "off";
+          }
+          else
+          {
+              def_val = NULL;
+
+              if (opt->type_str)
+                  type_str = opt->type_str;
+              else
+                  type_str = arg_names[opt->type];
+
+              type_len = strlen(type_str);
+
+              if (opt->short_opt)
+              {
+                  option_stream << "  -" << opt->short_opt << ", ";
+              }
+              else
+              {
+                  option_stream << "      ";
+              }
+
+              bool arg_optional = opt->arg_is_optional;
+              option_stream << "--" << opt->long_opt
+              << (arg_optional ? "[" : "")
+              << "=" << type_str
+              << (arg_optional ? "]" : "");
+
+              if (opt->default_string)
+              {
+                  def_str += opt->default_string;
+                  def_str += "'";
+                  def_val = def_str.c_str();
+              }
+          }
+
+          const string &option_string = option_stream.str();
+          stream << option_string;
+          const char *opt_desc = opt->desc;
+
+          if ((option_string.size() >= MAX_STARTING_COLUMN) ||
+                  (desc_col <= option_string.size()))
+          {
+              string indent (MAX_STARTING_COLUMN, ' ');
+              stream << "\\n" << indent;
+          }
+          else
+          {
+              string indent (desc_col - option_string.size(), ' ');
+              stream << indent;
+          }
+
+          generate_help_desc_print(stream, desc_col, opt_desc, def_val,
+                  (opt->acceptedvalues ? opt->acceptedvalues->toString() : ""),
+                  (opt->required && show_required_string != "" ? show_required_string : ""));
+
+          option_list->push_back(stream.str());
+          stream.str("");
+      }
+
+      // before the text after we generate details if we need to
+      if (opt->details && generate_details) {
+          string wrapped_desc ( 2, ' ');
+          // details are indented
+          wrap_cstr ( wrapped_desc, 2, 0, opt->details);
+
+          option_list->push_back(wrapped_desc);
+      }
+
+      // a possible description to be printed after this option
+      if (opt->text_after)
+      {
+          string wrapped_desc;
+          wrap_cstr ( wrapped_desc, 0, 0, opt->text_after);
+
+          option_list->push_back(wrapped_desc);
+      }
+    }
+
+  return option_list;
+}
+
+template <typename Collection>
+void generate_counter_init(const Collection &collection, const string &name, ostream &stream, unsigned int indent)
+{
+    string indent_str (indent, ' ');
+    typename Collection::const_iterator end = collection.end();
+
+    for ( typename Collection::const_iterator idx = collection.begin(); idx != end; ++idx)
+    {
+        stream << indent_str;
+        stream << ARGS_STRUCT << "->" << canonize_name (idx->first) << "_" <<
+            name << "_counter = 0 ;";
+        stream << endl;
+    }
+}
+
+void
+CmdlineParserCreator::generate_given_init(ostream &stream,
+                                          unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  string indent_str (indent, ' ');
+  clear_given_gen_class clear_given;
+  clear_given.set_arg_struct(ARGS_STRUCT);
+
+  /* now we initialize "given" fields */
+  foropt
+    {
+      stream << indent_str;
+      clear_given.set_var_arg(opt->var_arg);
+      clear_given.set_group(opt->multiple && opt->group_value);
+      clear_given.generate_clear_given(stream);
+    }
+
+  // for group counter initialization
+  generate_counter_init(gengetopt_groups, "group", stream, indent);
+
+  // for mode counter initialization
+  generate_counter_init(gengetopt_modes, "mode", stream, indent);
+}
+
+void
+CmdlineParserCreator::generate_reset_groups(ostream &stream, unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  string indent_str (indent, ' ');
+  ostringstream body;
+  reset_group_gen_class reset_group;
+  clear_given_gen_class clear_given;
+  clear_given.set_arg_struct(ARGS_STRUCT);
+
+  reset_group.set_args_info (c_source_gen_class::args_info);
+
+  groups_collection_t::const_iterator end = gengetopt_groups.end();
+  for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
+        idx != end; ++idx)
+    {
+      body.str ("");
+      bool found_option = false;
+      bool multiple_arg = false;
+
+      foropt
+      {
+        if (opt->group_value && strcmp(opt->group_value, idx->first.c_str()) == 0)
+          {
+            /* now we reset "given" fields */
+            stream << indent_str;
+            clear_given.set_var_arg(opt->var_arg);
+            if (opt->multiple && opt->group_value)
+              multiple_arg = true;
+            clear_given.set_group(opt->multiple && opt->group_value);
+            clear_given.generate_clear_given(body);
+
+            free_option (opt, body, indent);
+            found_option = true;
+          }
+      }
+
+      if (found_option)
+        {
+          reset_group.set_name (canonize_name (idx->first));
+          reset_group.set_body (body.str ());
+          reset_group.generate_reset_group (stream);
+        }
+    }
+}
+
+void
+CmdlineParserCreator::free_option(struct gengetopt_option *opt,
+                                  ostream &stream, unsigned int indent)
+{
+  if (opt->type == ARG_NO)
+    return;
+
+  if (opt->type != ARG_FLAG)
+    {
+      if (opt->multiple)
+        {
+          free_multiple_gen_class free_multiple;
+          free_multiple.set_has_string_type(opt->type == ARG_STRING);
+          free_multiple.set_structure (ARGS_STRUCT);
+
+          free_multiple.set_opt_var (opt->var_arg);
+          free_multiple.generate_free_multiple
+            (stream, indent);
+        }
+      else
+        {
+          free_string_gen_class free_string;
+          free_string.set_has_string_type(opt->type == ARG_STRING);
+          free_string.set_structure (ARGS_STRUCT);
+
+          free_string.set_opt_var (opt->var_arg);
+          free_string.generate_free_string (stream, indent);
+        }
+    }
+}
+
+void
+CmdlineParserCreator::generate_list_def(ostream &stream, unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  string indent_str (indent, ' ');
+  multiple_opt_list_gen_class multiple_opt_list;
+
+  /* define linked-list structs for multiple options */
+  foropt
+    {
+      if (opt->multiple)
+        {
+          if (opt->type)
+            {
+              stream << indent_str;
+              multiple_opt_list.set_arg_name (opt->var_arg);
+              multiple_opt_list.generate_multiple_opt_list (stream, indent);
+              stream << endl;
+            }
+        }
+    }
+}
+
+void
+CmdlineParserCreator::generate_multiple_fill_array(ostream &stream, unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  string indent_str (indent, ' ');
+  multiple_fill_array_gen_class filler;
+
+  /* copy linked list into the array */
+  foropt
+    {
+      if (opt->multiple && opt->type)
+        {
+          stream << indent_str;
+          filler.set_option_var_name (opt->var_arg);
+          filler.set_arg_type(arg_type_constants[opt->type]);
+          filler.set_type (arg_types_names[opt->type]);
+          string default_string = "0";
+          if (opt->default_string) {
+              if (opt->type == ARG_STRING)
+                  default_string = string("\"") + opt->default_string + "\"";
+              else if (opt->type == ARG_ENUM)
+                  default_string = from_value_to_enum(opt->var_arg, opt->default_string);
+              else
+                  default_string = opt->default_string;
+          }
+          filler.set_default_value (default_string);
+
+          filler.generate_multiple_fill_array (stream, indent);
+
+          stream << endl;
+        }
+    }
+}
+
+void
+CmdlineParserCreator::generate_update_multiple_given(ostream &stream, unsigned int indent)
+{
+  if (! has_multiple_options())
+    return;
+
+  string indent_str (indent, ' ');
+
+  stream << endl;
+  stream << indent_str;
+
+  update_given_gen_class update_given_gen;
+  struct gengetopt_option * opt;
+
+  foropt
+    {
+      if (opt->multiple)
+        {
+          update_given_gen.set_option_var_name (opt->var_arg);
+          update_given_gen.generate_update_given (stream, indent);
+        }
+    }
+}
+
+void
+CmdlineParserCreator::generate_check_modes(ostream &stream, unsigned int indent)
+{
+    // no need to check for conflict if there's only one mode
+    if (gengetopt_modes.size() < 2)
+        return;
+
+    string indent_str (indent, ' ');
+
+    stream << endl;
+    stream << indent_str;
+
+    const ModeOptionMap &modeOptionMap = getModeOptionMap();
+
+    check_modes_gen_class check_modes_gen;
+
+    // now we check each mode options against every other mode options:
+    // the first one with the other n-1, the second one with the other n-2, etc.
+    ModeOptionMap::const_iterator map_it1, map_it2;
+    for (ModeOptionMap::const_iterator map_it = modeOptionMap.begin(); map_it != modeOptionMap.end(); ++map_it) {
+        map_it1 = map_it;
+        ++map_it;
+        if (map_it == modeOptionMap.end())
+            break;
+        for (map_it2 = map_it; map_it2 != modeOptionMap.end(); ++map_it2) {
+            const string mode1 = canonize_name(map_it1->first);
+            const string mode2 = canonize_name(map_it2->first);
+
+            check_modes_gen.set_mode1_name(mode1);
+            check_modes_gen.set_mode2_name(mode2);
+
+            ostringstream mode1_given, mode2_given, mode1_options, mode2_options;
+
+            std::for_each(map_it1->second.begin(), map_it1->second.end(), pair_print_f<OptionValueElem>(mode1_given, mode1_options));
+            std::for_each(map_it2->second.begin(), map_it2->second.end(), pair_print_f<OptionValueElem>(mode2_given, mode2_options));
+
+            check_modes_gen.set_mode1_given_fields(mode1_given.str());
+            check_modes_gen.set_mode1_options(mode1_options.str());
+            check_modes_gen.set_mode2_given_fields(mode2_given.str());
+            check_modes_gen.set_mode2_options(mode2_options.str());
+
+            check_modes_gen.generate_check_modes(stream, indent);
+        }
+        map_it = map_it1;
+    }
+}
+
+void
+CmdlineParserCreator::generate_clear_arg(ostream &stream, unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  clear_arg_gen_class clear_arg;
+
+  /* now we initialize value fields */
+  foropt
+    {
+      if (opt->type == ARG_NO)
+        continue;
+
+      clear_arg.set_name(opt->var_arg);
+      clear_arg.set_suffix("arg");
+      clear_arg.set_value("NULL");
+      clear_arg.set_has_orig(opt->type != ARG_FLAG);
+      clear_arg.set_has_arg(false);
+
+      if (opt->multiple && opt->type)
+        {
+          clear_arg.set_has_arg(true);
+        }
+      else if (opt->type == ARG_STRING)
+        {
+          clear_arg.set_has_arg(true);
+          if (opt->default_given)
+            clear_arg.set_value
+                ("gengetopt_strdup (\"" + string(opt->default_string) +
+                "\")");
+        }
+      else if (opt->type == ARG_FLAG)
+        {
+          clear_arg.set_has_arg(true);
+          clear_arg.set_suffix("flag");
+          clear_arg.set_value(opt->flagstat ? "1" : "0");
+        }
+      else if (opt->type == ARG_ENUM)
+      {
+        // initialize enum arguments to -1 (unless they have a default)
+        clear_arg.set_has_arg(true);
+        if (opt->default_given)
+            clear_arg.set_value(from_value_to_enum(opt->var_arg, opt->default_string));
+        else
+            clear_arg.set_value(string(opt->var_arg) + "__NULL");
+      }
+      else if (opt->default_given)
+        {
+          clear_arg.set_has_arg(true);
+          clear_arg.set_value(opt->default_string);
+        }
+
+      clear_arg.generate_clear_arg(stream, indent);
+    }
+}
+
+void
+CmdlineParserCreator::generate_long_option_struct(ostream &stream,
+                                                  unsigned int indent)
+{
+  string indent_str (indent, ' ');
+  struct gengetopt_option * opt;
+
+  foropt
+    {
+      stream << indent_str;
+
+      stream << "{ \"" << opt->long_opt << "\",\t"
+             << (opt->type == ARG_NO || opt->type == ARG_FLAG ? 0 :
+                 (opt->arg_is_optional ? 2 : 1))
+             << ", NULL, ";
+
+      if (opt->short_opt)
+        stream << "\'" << opt->short_opt << "\'";
+      else
+        stream << "0";
+
+      stream << " }," << endl;
+    }
+}
+
+string
+CmdlineParserCreator::generate_getopt_string()
+{
+  struct gengetopt_option * opt;
+  ostringstream built_getopt_string;
+
+  foropt
+    if (opt->short_opt)
+      {
+        built_getopt_string << opt->short_opt <<
+          (opt->type == ARG_NO || opt->type == ARG_FLAG ? "" : ":");
+        built_getopt_string <<
+          (opt->arg_is_optional ? ":" : "");
+      }
+
+  return built_getopt_string.str ();
+}
+
+void
+CmdlineParserCreator::generate_handle_no_short_option(ostream &stream,
+                                                      unsigned int indent)
+{
+  handle_options(stream, indent, false);
+}
+
+void
+CmdlineParserCreator::generate_handle_option(ostream &stream,
+                                             unsigned int indent)
+{
+  handle_options(stream, indent, true);
+}
+
+void
+CmdlineParserCreator::handle_options(ostream &stream, unsigned int indent, bool has_short)
+{
+  struct gengetopt_option * opt;
+  generic_option_gen_class option_gen;
+  string indent_str (indent, ' ');
+  bool first = true;
+
+  option_gen.set_has_short_option (has_short);
+
+  // by default we handle '?' case in the switch
+  // unless the user defined a short option as ?
+  set_handle_question_mark(true);
+
+  foropt
+    {
+      if (opt->short_opt == '?')
+          set_handle_question_mark(false);
+
+      if ((has_short && opt->short_opt) || (!has_short && !opt->short_opt))
+        {
+          if (has_short || first)
+            stream << indent_str;
+
+          option_gen.set_option_comment (opt->desc);
+          option_gen.set_long_option (opt->long_opt);
+          option_gen.set_short_option(opt->short_opt ? string (1, opt->short_opt) : "-");
+          option_gen.set_option_var_name (opt->var_arg);
+          option_gen.set_final_instructions("");
+
+          if (!no_help && ((opt->short_opt == HELP_SHORT_OPT &&
+                  strcmp(opt->long_opt, HELP_LONG_OPT) == 0)
+                  || strcmp(opt->long_opt, HELP_LONG_OPT) == 0
+                  || strcmp(opt->long_opt, FULL_HELP_LONG_OPT) == 0
+                  || strcmp(opt->long_opt, DETAILED_HELP_LONG_OPT) == 0)) {
+              bool full_help = (strcmp(opt->long_opt, FULL_HELP_LONG_OPT) == 0);
+              bool detailed_help = (strcmp(opt->long_opt, DETAILED_HELP_LONG_OPT) == 0);
+              if (no_handle_help) {
+                    // we use the final_instructions parameter to call the free function
+                    // and to return 0
+                    const string final_instructions =
+                    parser_function_name +
+                    string("_free (&local_args_info);\nreturn 0;");
+
+                    option_gen.set_final_instructions(final_instructions);
+
+                    if (full_help) {
+                        option_gen.set_long_option (FULL_HELP_LONG_OPT);
+                        option_gen.set_option_comment (FULL_HELP_OPT_DESCR);
+                    } else if (detailed_help) {
+                        option_gen.set_long_option (DETAILED_HELP_LONG_OPT);
+                        option_gen.set_option_comment (DETAILED_HELP_OPT_DESCR);
+                    } else {
+                        option_gen.set_long_option (HELP_LONG_OPT);
+                        option_gen.set_short_option (HELP_SHORT_OPT_STR);
+                        option_gen.set_option_comment (HELP_OPT_DESCR);
+                    }
+                    //option_gen.set_has_short_option (!full_help);
+              } else {
+                  handle_help_gen_class help_gen;
+                  help_gen.set_parser_name (parser_function_name);
+                  help_gen.set_full_help(full_help);
+                  help_gen.set_detailed_help(detailed_help);
+                  help_gen.set_short_opt(opt->short_opt == HELP_SHORT_OPT);
+                  help_gen.generate_handle_help (stream, indent);
+                  stream << endl;
+                  stream << endl;
+                  continue;
+              }
+          }
+
+          if (!no_version && ((opt->short_opt == VERSION_SHORT_OPT && strcmp(opt->long_opt, VERSION_LONG_OPT) == 0)
+                  || strcmp(opt->long_opt, VERSION_LONG_OPT) == 0)) {
+              if (no_handle_version) {
+                  option_gen.set_long_option (VERSION_LONG_OPT);
+                  option_gen.set_short_option (VERSION_SHORT_OPT_STR);
+                  option_gen.set_option_comment (VERSION_OPT_DESCR);
+                  //option_gen.set_has_short_option (true);
+
+                  // we use the final_instrauctions parameter to call the free function
+                  // and to return 0
+                  const string final_instructions =
+                      parser_function_name +
+                      string("_free (&local_args_info);\nreturn 0;");
+
+                  option_gen.set_final_instructions(final_instructions);
+              } else {
+                  handle_version_gen_class version_gen;
+                  version_gen.set_parser_name (parser_function_name);
+                  version_gen.set_short_opt (opt->short_opt == VERSION_SHORT_OPT);
+                  version_gen.generate_handle_version (stream, indent);
+                  stream << endl;
+                  stream << endl;
+                  continue;
+              }
+          }
+
+          if (opt->acceptedvalues != 0)
+              option_gen.set_possible_values (OPTION_VALUES_NAME(opt->var_arg));
+          else
+              option_gen.set_possible_values ("0");
+
+          string default_string = "0";
+          if (opt->default_string)
+              default_string = string("\"") + opt->default_string + "\"";
+          option_gen.set_default_value (default_string);
+
+          option_gen.set_arg_type(arg_type_constants[opt->type]);
+
+          if (opt->group_value) {
+              option_gen.set_group_var_name (canonize_name (opt->group_value));
+              option_gen.set_option_has_group(true);
+          } else
+              option_gen.set_option_has_group(false);
+
+          if (opt->mode_value) {
+              // we reuse the variable group_var_name also for modes
+              option_gen.set_group_var_name (canonize_name (opt->mode_value));
+              option_gen.set_option_has_mode(true);
+          } else
+              option_gen.set_option_has_mode(false);
+
+          option_gen.set_option_has_type(opt->type != 0);
+
+          if (opt->multiple) {
+              option_gen.set_multiple(true);
+              option_gen.set_structure (string (opt->var_arg) + "_list");
+          } else {
+              option_gen.set_multiple(false);
+              option_gen.set_structure (ARGS_STRUCT);
+          }
+
+          option_gen.generate_generic_option (stream, indent);
+
+          if (has_short)
+            {
+              stream << endl;
+            }
+
+          if (first && !has_short)
+            {
+              first = false;
+              option_gen.set_gen_else ("else ");
+            }
+        }
+    }
+
+  if (! first && !has_short) // something has been generated
+    {
+      generateBreak(stream, indent);
+      stream << endl;
+    }
+}
+
+#define GROUP_REQUIRED_COMPARISON "!="
+#define GROUP_NOT_REQUIRED_COMPARISON ">"
+#define GROUP_REQUIRED_MESSAGE "One"
+#define GROUP_NOT_REQUIRED_MESSAGE "At most one"
+
+void
+CmdlineParserCreator::generate_handle_group(ostream &stream,
+                                            unsigned int indent)
+{
+  group_option_gen_class opt_gen;
+  string indent_str (indent, ' ');
+  opt_gen.set_package_var_name (EXE_NAME);
+
+  opt_gen.set_Comparison_rule(GROUP_NOT_REQUIRED_COMPARISON " 1");
+
+  groups_collection_t::const_iterator end = gengetopt_groups.end();
+  for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
+        idx != end; ++idx)
+    {
+      stream << indent_str;
+      opt_gen.set_group_name (idx->first);
+      opt_gen.set_group_var_name (canonize_name (idx->first));
+      if (idx->second.required)
+        {
+          opt_gen.set_number_required(GROUP_REQUIRED_MESSAGE);
+        }
+      else
+        {
+          opt_gen.set_number_required(GROUP_NOT_REQUIRED_MESSAGE);
+        }
+
+      opt_gen.generate_group_option (stream, indent);
+      stream << endl;
+    }
+}
+
+void
+CmdlineParserCreator::generate_handle_required(ostream &stream,
+                                               unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  required_option_gen_class opt_gen;
+  opt_gen.set_package_var_name ("prog_name");
+
+  /* write test for required options or for multiple options
+     (occurrence number check) */
+  foropt
+    if ( opt->required || opt->multiple )
+      {
+        if (opt->mode_value) {
+            opt_gen.set_mode_condition("args_info->" +
+                    canonize_name(opt->mode_value) + "_mode_counter && ");
+        } else {
+            opt_gen.set_mode_condition("");
+        }
+
+        // build the option command line representation
+        ostringstream req_opt;
+        req_opt << "'--" << opt->long_opt << "'";
+        if (opt->short_opt)
+          req_opt << " ('-" << opt->short_opt << "')";
+
+        opt_gen.set_option_var_name (opt->var_arg);
+        opt_gen.set_option_descr (req_opt.str ());
+
+        // if the option is required this is the standard check
+        if (opt->required) {
+          opt_gen.set_checkrange(false);
+
+          opt_gen.generate_required_option (stream, indent);
+        }
+
+        // if the option is multiple we generate also the
+        // occurrence range check
+        if (opt->multiple) {
+          opt_gen.set_checkrange(true);
+
+          opt_gen.generate_required_option (stream, indent);
+        }
+
+        // notice that the above ifs are not mutual exclusive:
+        // a multiple option can have a range check without being
+        // required.
+      }
+
+  // now generate the checks for required group options
+  group_option_gen_class group_opt_gen;
+  group_opt_gen.set_package_var_name ("prog_name");
+
+  group_opt_gen.set_Comparison_rule("== 0");
+  group_opt_gen.set_number_required(GROUP_REQUIRED_MESSAGE);
+
+  groups_collection_t::const_iterator end = gengetopt_groups.end();
+  for ( groups_collection_t::const_iterator idx = gengetopt_groups.begin();
+        idx != end; ++idx)
+  {
+    if (idx->second.required)
+    {
+      group_opt_gen.set_group_name (idx->first);
+      group_opt_gen.set_group_var_name (canonize_name (idx->first));
+
+      group_opt_gen.generate_group_option (stream, indent);
+      stream << endl;
+    }
+  }
+}
+
+void
+CmdlineParserCreator::generate_handle_dependencies(ostream &stream,
+                                               unsigned int indent)
+{
+  struct gengetopt_option * opt;
+  dependant_option_gen_class opt_gen;
+  opt_gen.set_package_var_name ("prog_name");
+  string indent_str (indent, ' ');
+
+  /* write test for required options */
+  foropt
+    if ( opt->dependon )
+      {
+        stream << indent_str;
+
+        ostringstream req_opt;
+        req_opt << "'--" << opt->long_opt << "'";
+        if (opt->short_opt)
+          req_opt << " ('-" << opt->short_opt << "')";
+
+        opt_gen.set_option_var_name (opt->var_arg);
+        opt_gen.set_dep_option (canonize_name(opt->dependon));
+        opt_gen.set_option_descr (req_opt.str ());
+        opt_gen.set_dep_option_descr (opt->dependon);
+
+        opt_gen.generate_dependant_option (stream, indent);
+
+        stream << endl;
+      }
+}
+
+template <typename Collection>
+void generate_counters(const Collection &collection, const string &name, ostream &stream, unsigned int indent)
+{
+    group_counter_gen_class counter_gen;
+    string indent_str (indent, ' ');
+
+    counter_gen.set_name(name);
+
+    typename Collection::const_iterator end = collection.end();
+    for ( typename Collection::const_iterator idx = collection.begin(); idx != end; ++idx) {
+        stream << indent_str;
+        counter_gen.set_group_name (canonize_name (idx->first));
+        counter_gen.generate_group_counter (stream, indent);
+        stream << endl;
+    }
+}
+
+void
+CmdlineParserCreator::generate_group_counters(ostream &stream,
+                                              unsigned int indent)
+{
+    generate_counters(gengetopt_groups, "group", stream, indent);
+}
+
+void
+CmdlineParserCreator::generate_mode_counters(ostream &stream,
+                                              unsigned int indent)
+{
+    // we can reuse group counter gen class also for modes
+    generate_counters(gengetopt_modes, "mode", stream, indent);
+}
+
+int
+CmdlineParserCreator::generate_source ()
+{
+  /* ****************************************************** */
+  /* ********************************************** C FILE  */
+  /* ****************************************************** */
+
+  set_usage_string (generate_usage_string ());
+  set_getopt_string (generate_getopt_string ());
+
+  string output_source = c_filename;
+
+  if (src_output_dir.size())
+      output_source = src_output_dir + "/" + output_source;
+  else if (output_dir.size())
+      output_source = output_dir + "/" + output_source;
+
+  ofstream *output_file = open_fstream (output_source.c_str());
+  generate_c_source (*output_file);
+  output_file->close ();
+  delete output_file;
+
+  return 0;
+}
+
+void
+CmdlineParserCreator::generate_free(ostream &stream,
+                                    unsigned int indent)
+{
+  struct gengetopt_option * opt;
+
+  foropt
+    {
+      free_option (opt, stream, indent);
+    }
+}
+
+void
+CmdlineParserCreator::generate_list_free(ostream &stream,
+                                         unsigned int indent)
+{
+  struct gengetopt_option * opt;
+
+  if (! has_multiple_options())
+    return;
+
+  free_list_gen_class free_list;
+
+  foropt
+    {
+      if (opt->multiple && opt->type) {
+        free_list.set_list_name(opt->var_arg);
+        free_list.set_string_list(opt->type == ARG_STRING);
+        free_list.generate_free_list(stream, indent);
+      }
+    }
+}
+
+void
+CmdlineParserCreator::generate_file_save_loop(ostream &stream, unsigned int indent)
+{
+  struct gengetopt_option * opt;
+
+  file_save_multiple_gen_class file_save_multiple;
+  file_save_gen_class file_save;
+
+  const string suffix = "_orig";
+  const string suffix_given = "_given";
+
+  foropt {
+    if (opt->multiple) {
+      file_save_multiple.set_has_arg(opt->type != ARG_NO);
+      file_save_multiple.set_opt_var(opt->var_arg);
+      file_save_multiple.set_opt_name(opt->long_opt);
+      file_save_multiple.set_values
+          ((opt->acceptedvalues ? OPTION_VALUES_NAME(opt->var_arg) : "0"));
+
+      file_save_multiple.generate_file_save_multiple(stream, indent);
+    } else {
+      file_save.set_opt_name(opt->long_opt);
+      file_save.set_given(opt->var_arg + suffix_given);
+      file_save.set_values
+          ((opt->acceptedvalues ? OPTION_VALUES_NAME(opt->var_arg) : "0"));
+
+      if (opt->type != ARG_NO && opt->type != ARG_FLAG) {
+        file_save.set_arg(opt->var_arg + suffix + (opt->multiple ? " [i]" : ""));
+      } else {
+        file_save.set_arg("");
+      }
+      file_save.generate_file_save(stream, indent);
+    }
+  }
+}
+
+