X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=utilities%2Fgengetopt%2Fgm.cc;fp=utilities%2Fgengetopt%2Fgm.cc;h=0e7b70a021ef0f4fece85790004f62a8bcda22d2;hb=79381bc54b9e0c85156460daa211fe5ac83da0a7;hp=0000000000000000000000000000000000000000;hpb=4454c06e212fb6af58d206f2d6f9b76778858967;p=clitk.git diff --git a/utilities/gengetopt/gm.cc b/utilities/gengetopt/gm.cc new file mode 100644 index 0000000..0e7b70a --- /dev/null +++ b/utilities/gengetopt/gm.cc @@ -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 +#include +#include +#include +#include +#include // for pair + +#include + +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 OptionValueElem; +typedef std::list ModeOptions; +typedef std::map 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 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 +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(mode1_given, mode1_options)); + std::for_each(map_it2->second.begin(), map_it2->second.end(), pair_print_f(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 +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); + } + } +} + +