2 * Copyright (C) 1999-2007 Free Software Foundation, Inc.
4 * This file is part of GNU gengetopt
6 * GNU gengetopt is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
11 * GNU gengetopt is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14 * Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with gengetopt; see the file COPYING. If not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 void gengetopt_free (void);
32 /* The following one is generated by gengetopt itself */
35 extern int yyparse () ;
37 #include "gengetopt.h"
38 #include "errorcodes.h"
41 #include "global_opts.h"
43 #include "my_sstream.h"
44 #include "my_string.h"
50 #include "skels/copyright.h"
55 char * gengetopt_package = NULL;
56 char * gengetopt_version = NULL;
57 char * gengetopt_purpose = NULL;
58 char * gengetopt_description = NULL;
59 char * gengetopt_usage = NULL;
61 modes_collection_t gengetopt_modes;
63 int gengetopt_count_line = 1;
64 char * gengetopt_input_filename = 0;
65 char *current_section = 0;
66 char *current_section_desc = 0;
67 char *current_text = 0;
68 char *current_args = 0;
70 /// whether, if not specified, an option is considered optional
71 bool default_to_optional = false;
73 int canonize_vars (void);
74 static void set_default_required_properties(void);
76 static void print_copyright();
77 static void print_reportbugs();
79 static void output_formatted_string(const string &);
81 static bool check_dependencies();
83 static int gengetopt_create_option (gengetopt_option *&opt, const char * long_opt, char short_opt,
85 int type, int flagstat, int required,
86 const char *default_value,
87 const char * group_value,
88 const char * mode_value,
89 const char * type_str,
90 const AcceptedValues *acceptedvalues,
100 /// the structure for command line arguments
101 struct gengetopt_args_info args_info ;
104 main (int argc, char **argv)
106 char *cmdline_parser_name ; /* name of the generated function */
107 char *cmdline_filename ; /* name of generated file */
108 char *c_ext ; /* extenstion of c file */
109 char *header_ext ; /* extenstion of header file */
110 string output_dir, header_output_dir, src_output_dir; /* output directory (default empty -> current dir)*/
112 int i, has_help, has_version;
115 if (cmdline_parser (argc, argv, &args_info) != 0) {
116 fprintf (stderr, "Run gengetopt --help to see the list of options.\n");
120 if (args_info.help_given)
122 cmdline_parser_print_help ();
127 if (args_info.detailed_help_given)
129 cmdline_parser_print_detailed_help ();
134 if (args_info.version_given)
136 cmdline_parser_print_version ();
141 if ( args_info.input_arg )
143 gengetopt_input_filename = strdup (args_info.input_arg);
144 input_file = freopen (args_info.input_arg, "r", stdin) ;
147 fprintf (stderr, "Error opening input file: %s\n",
148 args_info.input_arg);
151 } /* else standard input is used */
153 if (yyparse () != 0) {
158 // check whether some options were given in the input file
159 bool no_options = (gengetopt_options.size() == 0);
162 // parse the arguments passed in the "args" part of the input file
163 // by possibily overriding those given at command line
164 if (cmdline_parser_string2 (current_args, &args_info, "gengetopt", 1, 0, 0) != 0) {
165 fprintf (stderr, "Error in the args specification of the input_file.\n");
170 cmdline_parser_name = args_info.func_name_arg ;
171 cmdline_filename = args_info.file_name_arg ;
172 c_ext = args_info.c_extension_arg;
173 header_ext = args_info.header_extension_arg;
175 default_to_optional = args_info.default_optional_given;
177 // now set the default "required" property for options
178 set_default_required_properties();
180 if (! check_dependencies()) {
185 // insert options for help and version if not already present
186 gengetopt_option *opt;
189 free(current_section);
192 has_version = gengetopt_has_option (VERSION_LONG_OPT, VERSION_SHORT_OPT);
194 if (has_version != REQ_LONG_OPTION && !args_info.no_version_given) {
195 gengetopt_create_option (opt, VERSION_LONG_OPT, has_version ? '-' : VERSION_SHORT_OPT,
196 VERSION_OPT_DESCR, ARG_NO, 0, 0, 0, 0, 0, 0, 0);
197 gengetopt_options.push_front(opt);
200 if (!args_info.no_help_given && has_hidden_options() && gengetopt_has_option(FULL_HELP_LONG_OPT, 0) == 0) {
201 gengetopt_create_option (opt, FULL_HELP_LONG_OPT, '-',
202 FULL_HELP_OPT_DESCR, ARG_NO, 0, 0, 0, 0, 0, 0, 0);
203 gengetopt_options.push_front(opt);
206 if (!args_info.no_help_given && has_options_with_details() && gengetopt_has_option(DETAILED_HELP_LONG_OPT, 0) == 0) {
207 gengetopt_create_option (opt, DETAILED_HELP_LONG_OPT, '-',
208 DETAILED_HELP_OPT_DESCR, ARG_NO, 0, 0, 0, 0, 0, 0, 0);
209 gengetopt_options.push_front(opt);
212 has_help = gengetopt_has_option(HELP_LONG_OPT, HELP_SHORT_OPT);
214 if (has_help != REQ_LONG_OPTION && !args_info.no_help_given) {
215 gengetopt_create_option (opt, HELP_LONG_OPT, has_help ? '-' : HELP_SHORT_OPT,
216 HELP_OPT_DESCR, ARG_NO, 0, 0, 0, 0, 0, 0, 0);
217 gengetopt_options.push_front(opt);
220 // check whether there's pending text after all options and
221 // in case, set it to the last option
222 if (current_text && gengetopt_options.size()) {
223 gengetopt_options.back()->text_after = current_text;
224 gengetopt_set_text(0);
227 if (canonize_vars ()) {
232 if (args_info.set_package_given) {
233 if (gengetopt_package)
234 free (gengetopt_package);
235 gengetopt_package = args_info.set_package_arg;
238 if (args_info.set_version_given) {
239 if (gengetopt_version)
240 free (gengetopt_version);
241 gengetopt_version = args_info.set_version_arg;
244 ostringstream command_line;
245 for ( i = 0; i < argc ; ++i )
246 command_line << argv[i] << " ";
248 // add also possible args specification in the input file
250 command_line << current_args;
252 if (args_info.output_dir_given)
253 output_dir = args_info.output_dir_arg;
254 if (args_info.header_output_dir_given)
255 header_output_dir = args_info.header_output_dir_arg;
256 if (args_info.src_output_dir_given)
257 src_output_dir = args_info.src_output_dir_arg;
259 CmdlineParserCreator cmdline_parser_creator
260 (cmdline_parser_name,
261 args_info.arg_struct_name_arg,
262 (args_info.unamed_opts_given ? args_info.unamed_opts_arg : 0),
266 args_info.long_help_given,
267 args_info.no_handle_help_given,
268 args_info.no_help_given,
269 args_info.no_handle_version_given,
270 args_info.no_version_given,
271 args_info.no_handle_error_given,
272 args_info.conf_parser_given,
273 args_info.string_parser_given,
274 args_info.gen_version_flag,
275 args_info.include_getopt_given,
281 (args_info.show_required_given ? args_info.show_required_arg : ""));
283 if (! gengetopt_package && (args_info.show_version_given || args_info.show_help_given))
285 cerr << "package not defined; please specify it with --set-package" << endl;
288 else if (! gengetopt_version && (args_info.show_version_given || args_info.show_help_given))
290 cerr << "version not defined; please specify it with --set-version" << endl;
293 else if (args_info.show_version_given)
295 cout << gengetopt_package << " " << gengetopt_version << endl;
297 else if (args_info.show_help_given ||
298 args_info.show_full_help_given || args_info.show_detailed_help_given)
300 cout << gengetopt_package << " " << gengetopt_version << "\n" << endl;
302 if (gengetopt_purpose) {
303 output_formatted_string(cmdline_parser_creator.generate_purpose());
307 output_formatted_string("Usage: " +
308 cmdline_parser_creator.generate_usage_string(false) + "\n");
310 if (gengetopt_description) {
311 output_formatted_string(cmdline_parser_creator.generate_description());
315 // if --show-full-help is specified we have to generate also hidden options
316 OptionHelpList *option_list =
317 cmdline_parser_creator.generate_help_option_list(args_info.show_full_help_given, args_info.show_detailed_help_given);
319 std::for_each(option_list->begin(), option_list->end(),
320 output_formatted_string);
324 else if (cmdline_parser_creator.generate ())
336 output_formatted_string(const string &s)
338 for (string::const_iterator it = s.begin(); it != s.end(); ++it)
340 if (*it == '\\' && ((it+1) != s.end()) && *(it+1) == 'n') {
343 } else if (*it == '\\' && ((it+1) != s.end()) && *(it+1) == '"') {
356 gengetopt_define_package (char * s)
358 gengetopt_package = strdup (s);
359 if (gengetopt_package == NULL)
365 gengetopt_define_version (char * s)
367 gengetopt_version = strdup (s);
368 if (gengetopt_version == NULL)
374 gengetopt_define_purpose (char * s)
376 gengetopt_purpose = strdup (s);
377 if (gengetopt_purpose == NULL)
383 gengetopt_define_description (char * s)
385 gengetopt_description = strdup (s);
386 if (gengetopt_description == NULL)
391 int gengetopt_define_usage (char * s)
393 gengetopt_usage = strdup (s);
394 if (gengetopt_usage == NULL)
400 gengetopt_add_group (const char *s, const char *desc, int required)
405 if ( !gengetopt_groups.insert
406 (make_pair(string(s),Group (group_desc, required != 0))).second )
413 gengetopt_add_mode (const char *s, const char *desc)
418 if ( !gengetopt_modes.insert
419 (make_pair(string(s),Mode (mode_desc))).second )
426 gengetopt_set_section (const char * s, const char *desc)
429 free (current_section);
430 if (current_section_desc)
431 free (current_section_desc);
432 current_section = strdup (s);
434 current_section_desc = strdup (desc);
436 current_section_desc = 0;
440 gengetopt_set_text (const char * desc)
443 no need to free it, since it will be then owned by the
450 // the current text is reset
457 // a previous text was collected, so we append the new text
458 // to the current one.
459 string buffer = current_text;
461 current_text = strdup(buffer.c_str());
465 // otherwise simply copy the passed text
466 current_text = strdup (desc);
469 void gengetopt_set_args(const char *a)
475 current_args = strdup(a);
481 gengetopt_has_option (const char * long_opt, char short_opt)
483 gengetopt_option * n;
485 for (gengetopt_option_list::const_iterator it = gengetopt_options.begin();
486 it != gengetopt_options.end(); ++it)
489 if (!strcmp (n->long_opt, long_opt)) return REQ_LONG_OPTION;
490 if (short_opt && n->short_opt == short_opt)
491 return REQ_SHORT_OPTION;
497 bool check_numeric_validity(const char *val, int opt_type)
499 char *end_of_string, *expected_eos;
501 expected_eos = (char *) (val + strlen(val));
509 (void) strtol(val, &end_of_string, 0);
515 (void) strtod(val, &end_of_string);
519 // This will allow us to factorise as a single line the
520 // test for correctness of the default value
521 end_of_string = expected_eos;
524 return ( end_of_string == expected_eos );
528 check_values(const AcceptedValues *acceptedvalues, int opt_type)
530 for (AcceptedValues::const_iterator it = acceptedvalues->begin();
531 it != acceptedvalues->end(); ++it) {
532 if (!check_numeric_validity((*it).c_str(), opt_type))
540 gengetopt_create_option (gengetopt_option *&n, const char * long_opt, char short_opt,
542 int type, int flagstat, int required,
543 const char * default_value,
544 const char * group_value,
545 const char * mode_value,
546 const char * type_str,
547 const AcceptedValues *acceptedvalues,
551 if ((long_opt == NULL) ||
552 (long_opt[0] == 0) ||
556 n = new gengetopt_option;
558 return NOT_ENOUGH_MEMORY;
560 // here we will set required anyway
561 n->required_set = true;
563 n->long_opt = strdup (long_opt);
564 if (n->long_opt == NULL)
567 return NOT_ENOUGH_MEMORY;
570 n->desc = strdup (desc);
575 return NOT_ENOUGH_MEMORY;
578 n->short_opt = ((short_opt == '-') ? 0 : short_opt);
580 n->flagstat = flagstat;
581 n->required = required;
582 n->multiple = (multiple != 0);
583 n->arg_is_optional = (argoptional != 0);
586 n->type_str = strdup(type_str);
593 n->section = strdup (current_section);
594 if (current_section_desc)
595 n->section_desc = strdup (current_section_desc);
597 if (group_value != 0)
599 n->group_value = strdup(group_value);
601 groups_collection_t::const_iterator it =
602 gengetopt_groups.find(string(n->group_value));
603 if (it == gengetopt_groups.end())
604 return GROUP_UNDEFINED;
605 n->group_desc = strdup (it->second.desc.c_str ());
612 if (mode_value != 0) {
613 n->mode_value = strdup(mode_value);
614 modes_collection_t::const_iterator it =
615 gengetopt_modes.find(string(n->mode_value));
616 if (it == gengetopt_modes.end())
617 return MODE_UNDEFINED;
618 n->mode_desc = strdup (it->second.desc.c_str ());
623 if (n->group_value && n->mode_value)
627 n->acceptedvalues = acceptedvalues;
629 // if (acceptedvalues && type != ARG_NO)
630 // return NOT_REQUESTED_TYPE;
632 if (acceptedvalues && ! (n->type))
633 n->type = ARG_STRING;
635 n->default_string = 0;
636 n->default_given = (default_value != 0);
637 if (n->default_given)
639 n->default_string = strdup (default_value);
640 if ( ! check_numeric_validity(default_value, n->type) )
643 return INVALID_DEFAULT_VALUE;
648 if (! acceptedvalues->contains(n->default_string))
649 return INVALID_DEFAULT_VALUE;
653 if (acceptedvalues) {
654 if (!check_values(acceptedvalues, n->type))
655 return INVALID_NUMERIC_VALUE;
664 gengetopt_check_option (gengetopt_option *n, bool groupoption, bool modeoption)
666 if ((n->long_opt == NULL) ||
667 (n->long_opt[0] == 0) ||
671 if (strcmp(n->long_opt, HELP_LONG_OPT) == 0 && !args_info.no_help_given)
672 return HELP_REDEFINED;
674 if (strcmp(n->long_opt, VERSION_LONG_OPT) == 0 && !args_info.no_version_given)
675 return VERSION_REDEFINED;
680 n->section = strdup (current_section);
681 if (current_section_desc)
682 n->section_desc = strdup (current_section_desc);
684 n->text_before = current_text;
685 // reset the description
686 gengetopt_set_text(0);
688 if (n->group_value != 0)
691 return NOT_GROUP_OPTION;
694 n->required_set = true;
696 groups_collection_t::const_iterator it =
697 gengetopt_groups.find(string(n->group_value));
698 if (it == gengetopt_groups.end())
699 return GROUP_UNDEFINED;
700 n->group_desc = strdup (it->second.desc.c_str ());
705 return SPECIFY_GROUP;
708 if (n->mode_value != 0)
711 return NOT_MODE_OPTION;
713 modes_collection_t::const_iterator it =
714 gengetopt_modes.find(string(n->mode_value));
715 if (it == gengetopt_modes.end())
716 return MODE_UNDEFINED;
717 n->mode_desc = strdup (it->second.desc.c_str ());
725 if (n->group_value && n->mode_value)
728 // now we have to check for flag options
729 if (n->type == ARG_FLAG)
732 return SPECIFY_FLAG_STAT;
734 if (n->default_string || n->multiple || n->arg_is_optional
735 || n->type_str || n->acceptedvalues || n->required_set)
736 return NOT_VALID_SPECIFICATION;
739 n->required_set = true;
743 if (n->flagstat >= 0)
744 return NOT_VALID_SPECIFICATION;
747 // enum type can only be specified with options with values
748 if (n->type == ARG_ENUM && !(n->acceptedvalues)) {
749 return INVALID_ENUM_TYPE_USE;
752 // if (acceptedvalues && type != ARG_NO)
753 // return NOT_REQUESTED_TYPE;
755 if (n->acceptedvalues && ! (n->type))
756 n->type = ARG_STRING;
758 n->default_given = (n->default_string != 0);
759 if (n->default_given)
761 if ( !check_numeric_validity(n->default_string, n->type) )
763 return INVALID_DEFAULT_VALUE;
766 if (n->acceptedvalues)
768 if (! n->acceptedvalues->contains(n->default_string))
769 return INVALID_DEFAULT_VALUE;
773 if (n->acceptedvalues) {
774 if (!check_values(n->acceptedvalues, n->type))
775 return INVALID_NUMERIC_VALUE;
784 gengetopt_add_option (const char * long_opt, char short_opt,
786 int type, int flagstat, int required,
787 const char * default_value,
788 const char * group_value,
789 const char * mode_value,
790 const char * type_str,
791 const AcceptedValues *acceptedvalues,
795 gengetopt_option * n;
797 /* search for collisions */
798 int res = gengetopt_has_option(long_opt, short_opt);
802 res = gengetopt_create_option(n, long_opt, short_opt,
803 desc, type, flagstat, required, default_value, group_value, mode_value,
804 type_str, acceptedvalues, multiple, argoptional);
808 gengetopt_options.push_back(n);
814 gengetopt_add_option (gengetopt_option * n)
816 /* search for collisions */
817 int res = gengetopt_has_option(n);
821 gengetopt_options.push_back(n);
827 gengetopt_has_option (gengetopt_option * opt)
829 gengetopt_option * n;
831 for (gengetopt_option_list::const_iterator it = gengetopt_options.begin();
832 it != gengetopt_options.end(); ++it)
835 if (!strcmp (n->long_opt, opt->long_opt))
836 return REQ_LONG_OPTION;
837 if (opt->short_opt && n->short_opt == opt->short_opt)
838 return REQ_SHORT_OPTION;
847 gengetopt_option * n;
850 for (gengetopt_option_list::const_iterator it = gengetopt_options.begin();
851 it != gengetopt_options.end(); ++it)
855 if (strcmp(n->dependon, n->long_opt) == 0) {
856 yyerror(n, "option depends on itself");
862 for (gengetopt_option_list::const_iterator it2 = gengetopt_options.begin();
863 it2 != gengetopt_options.end(); ++it2)
865 if (strcmp(n->dependon, (*it2)->long_opt) == 0) {
872 yyerror (n, "option depends on undefined option");
882 gengetopt_free (void)
886 if (gengetopt_package != NULL)
887 free (gengetopt_package);
889 for (gengetopt_option_list::iterator it = gengetopt_options.begin(); it != gengetopt_options.end(); ++it)
892 if (p->long_opt != NULL) free (p->long_opt);
893 if (p->desc != NULL) free (p->desc);
894 if (p->var_arg != NULL) free (p->var_arg);
895 if (p->acceptedvalues) delete p->acceptedvalues;
901 canonize_var (gengetopt_option *p)
905 p->var_arg = strdup (p->long_opt);
906 if (p->var_arg == NULL) {
907 printf ("gengetopt: not enough memory to canonize vars\n");
911 for (pvar = p->var_arg; *pvar; pvar++)
912 if (*pvar == '.' || *pvar == '-') *pvar = '_';
918 for_each(gengetopt_options.begin(), gengetopt_options.end(), canonize_var);
924 set_default_required_prop (gengetopt_option *p)
926 if (!p->required_set)
927 p->required = (default_to_optional ? 0 : 1);
930 static void set_default_required_properties(void)
932 for_each(gengetopt_options.begin(), gengetopt_options.end(), set_default_required_prop);
938 copyright_gen_class copyright_g;
940 copyright_g.set_year ("1999-2009");
941 copyright_g.generate_copyright (cout);
948 cout << "Maintained by Lorenzo Bettini <http://www.lorenzobettini.it>" << endl;
949 cout << "Report bugs to <bug-gengetopt at gnu.org>" << endl;