Import option handler from ponymap
This commit is contained in:
		
							parent
							
								
									59b1c5c056
								
							
						
					
					
						commit
						cd1a55a0d1
					
				| @ -69,7 +69,7 @@ foreach (page zyklonb kike) | ||||
| 	set (page_output "${PROJECT_BINARY_DIR}/${page}.1") | ||||
| 	list (APPEND project_MAN_PAGES "${page_output}") | ||||
| 	add_custom_command (OUTPUT ${page_output} | ||||
| 		COMMAND ${HELP2MAN_EXECUTABLE} -N --no-discard-stderr # FIXME | ||||
| 		COMMAND ${HELP2MAN_EXECUTABLE} -N | ||||
| 			"${PROJECT_BINARY_DIR}/${page}" -o ${page_output} | ||||
| 		DEPENDS ${page} | ||||
| 		COMMENT "Generating man page for ${page}" VERBATIM) | ||||
|  | ||||
							
								
								
									
										149
									
								
								common.c
									
									
									
									
									
								
							
							
						
						
									
										149
									
								
								common.c
									
									
									
									
									
								
							| @ -1995,3 +1995,152 @@ call_write_default_config (const char *hint, const struct config_item *table) | ||||
| 	print_status ("configuration written to `%s'", filename); | ||||
| 	free (filename); | ||||
| } | ||||
| 
 | ||||
| // --- Option handler ----------------------------------------------------------
 | ||||
| 
 | ||||
| // Simple wrapper for the getopt_long API to make it easier to use and maintain.
 | ||||
| 
 | ||||
| #define OPT_USAGE_ALIGNMENT_COLUMN 30   ///< Alignment for option descriptions
 | ||||
| 
 | ||||
| enum | ||||
| { | ||||
| 	OPT_OPTIONAL_ARG  = (1 << 0),       ///< The argument is optional
 | ||||
| 	OPT_LONG_ONLY     = (1 << 1)        ///< Ignore the short name in opt_string
 | ||||
| }; | ||||
| 
 | ||||
| // All options need to have both a short name, and a long name.  The short name
 | ||||
| // is what is returned from opt_handler_get().  It is possible to define a value
 | ||||
| // completely out of the character range combined with the OPT_LONG_ONLY flag.
 | ||||
| //
 | ||||
| // When `arg_hint' is defined, the option is assumed to have an argument.
 | ||||
| 
 | ||||
| struct opt | ||||
| { | ||||
| 	int short_name;                     ///< The single-letter name
 | ||||
| 	const char *long_name;              ///< The long name
 | ||||
| 	const char *arg_hint;               ///< Option argument hint
 | ||||
| 	int flags;                          ///< Option flags
 | ||||
| 	const char *description;            ///< Option description
 | ||||
| }; | ||||
| 
 | ||||
| struct opt_handler | ||||
| { | ||||
| 	int argc;                           ///< The number of program arguments
 | ||||
| 	char **argv;                        ///< Program arguments
 | ||||
| 
 | ||||
| 	const char *arg_hint;               ///< Program arguments hint
 | ||||
| 	const char *description;            ///< Description of the program
 | ||||
| 
 | ||||
| 	const struct opt *opts;             ///< The list of options
 | ||||
| 	size_t opts_len;                    ///< The length of the option array
 | ||||
| 
 | ||||
| 	struct option *options;             ///< The list of options for getopt
 | ||||
| 	char *opt_string;                   ///< The `optstring' for getopt
 | ||||
| }; | ||||
| 
 | ||||
| static void | ||||
| opt_handler_free (struct opt_handler *self) | ||||
| { | ||||
| 	free (self->options); | ||||
| 	free (self->opt_string); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| opt_handler_init (struct opt_handler *self, int argc, char **argv, | ||||
| 	const struct opt *opts, const char *arg_hint, const char *description) | ||||
| { | ||||
| 	memset (self, 0, sizeof *self); | ||||
| 	self->argc = argc; | ||||
| 	self->argv = argv; | ||||
| 	self->arg_hint = arg_hint; | ||||
| 	self->description = description; | ||||
| 
 | ||||
| 	size_t len = 0; | ||||
| 	for (const struct opt *iter = opts; iter->long_name; iter++) | ||||
| 		len++; | ||||
| 
 | ||||
| 	self->opts = opts; | ||||
| 	self->opts_len = len; | ||||
| 	self->options = xcalloc (len + 1, sizeof *self->options); | ||||
| 
 | ||||
| 	struct str opt_string; | ||||
| 	str_init (&opt_string); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < len; i++) | ||||
| 	{ | ||||
| 		const struct opt *opt = opts + i; | ||||
| 		struct option *mapped = self->options + i; | ||||
| 
 | ||||
| 		mapped->name = opt->long_name; | ||||
| 		if (!opt->arg_hint) | ||||
| 			mapped->has_arg = no_argument; | ||||
| 		else if (opt->flags & OPT_OPTIONAL_ARG) | ||||
| 			mapped->has_arg = optional_argument; | ||||
| 		else | ||||
| 			mapped->has_arg = required_argument; | ||||
| 		mapped->val = opt->short_name; | ||||
| 
 | ||||
| 		if (opt->flags & OPT_LONG_ONLY) | ||||
| 			continue; | ||||
| 
 | ||||
| 		str_append_c (&opt_string, opt->short_name); | ||||
| 		if (opt->arg_hint) | ||||
| 		{ | ||||
| 			str_append_c (&opt_string, ':'); | ||||
| 			if (opt->flags & OPT_OPTIONAL_ARG) | ||||
| 				str_append_c (&opt_string, ':'); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	self->opt_string = str_steal (&opt_string); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| opt_handler_usage (struct opt_handler *self, FILE *stream) | ||||
| { | ||||
| 	struct str usage; | ||||
| 	str_init (&usage); | ||||
| 
 | ||||
| 	str_append_printf (&usage, "Usage: %s [OPTION]... %s\n", | ||||
| 		self->argv[0], self->arg_hint ? self->arg_hint : ""); | ||||
| 	str_append_printf (&usage, "%s\n\n", self->description); | ||||
| 
 | ||||
| 	for (size_t i = 0; i < self->opts_len; i++) | ||||
| 	{ | ||||
| 		struct str row; | ||||
| 		str_init (&row); | ||||
| 
 | ||||
| 		const struct opt *opt = self->opts + i; | ||||
| 		if (!(opt->flags & OPT_LONG_ONLY)) | ||||
| 			str_append_printf (&row, "  -%c, ", opt->short_name); | ||||
| 		else | ||||
| 			str_append (&row, "      "); | ||||
| 		str_append_printf (&row, "--%s", opt->long_name); | ||||
| 		if (opt->arg_hint) | ||||
| 			str_append_printf (&row, (opt->flags & OPT_OPTIONAL_ARG) | ||||
| 				? " [%s]" : " %s", opt->arg_hint); | ||||
| 
 | ||||
| 		// TODO: keep the indent if there are multiple lines
 | ||||
| 		if (row.len + 2 <= OPT_USAGE_ALIGNMENT_COLUMN) | ||||
| 		{ | ||||
| 			str_append (&row, "  "); | ||||
| 			str_append_printf (&usage, "%-*s%s\n", | ||||
| 				OPT_USAGE_ALIGNMENT_COLUMN, row.str, opt->description); | ||||
| 		} | ||||
| 		else | ||||
| 			str_append_printf (&usage, "%s\n%-*s%s\n", row.str, | ||||
| 				OPT_USAGE_ALIGNMENT_COLUMN, "", opt->description); | ||||
| 
 | ||||
| 		str_free (&row); | ||||
| 	} | ||||
| 
 | ||||
| 	fputs (usage.str, stream); | ||||
| 	str_free (&usage); | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| opt_handler_get (struct opt_handler *self) | ||||
| { | ||||
| 	return getopt_long (self->argc, self->argv, | ||||
| 		self->opt_string, self->options, NULL); | ||||
| } | ||||
|  | ||||
							
								
								
									
										50
									
								
								kike.c
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								kike.c
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| /*
 | ||||
|  * kike.c: the experimental IRC daemon | ||||
|  * | ||||
|  * Copyright (c) 2014, Přemysl Janouch <p.janouch@gmail.com> | ||||
|  * Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com> | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
| @ -3072,50 +3072,32 @@ daemonize (void) | ||||
| 		exit_fatal ("failed to reopen FD's: %s", strerror (errno)); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| print_usage (const char *program_name) | ||||
| { | ||||
| 	fprintf (stderr, | ||||
| 		"Usage: %s [OPTION]...\n" | ||||
| 		"Experimental IRC server.\n" | ||||
| 		"\n" | ||||
| 		"  -d, --debug     run in debug mode (do not daemonize)\n" | ||||
| 		"  -h, --help      display this help and exit\n" | ||||
| 		"  -V, --version   output version information and exit\n" | ||||
| 		"  --write-default-cfg [filename]\n" | ||||
| 		"                  write a default configuration file and exit\n", | ||||
| 		program_name); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| main (int argc, char *argv[]) | ||||
| { | ||||
| 	const char *invocation_name = argv[0]; | ||||
| 
 | ||||
| 	static struct option opts[] = | ||||
| 	static const struct opt opts[] = | ||||
| 	{ | ||||
| 		{ "debug",             no_argument,       NULL, 'd' }, | ||||
| 		{ "help",              no_argument,       NULL, 'h' }, | ||||
| 		{ "version",           no_argument,       NULL, 'V' }, | ||||
| 		{ "write-default-cfg", optional_argument, NULL, 'w' }, | ||||
| 		{ NULL,                0,                 NULL,  0  } | ||||
| 		{ 'd', "debug", NULL, 0, "run in debug mode (do not daemonize)" }, | ||||
| 		{ 'h', "help", NULL, 0, "display this help and exit" }, | ||||
| 		{ 'V', "version", NULL, 0, "output version information and exit" }, | ||||
| 		{ 'w', "write-default-cfg", "FILENAME", | ||||
| 		  OPT_OPTIONAL_ARG | OPT_LONG_ONLY, | ||||
| 		  "write a default configuration file and exit" }, | ||||
| 		{ 0, NULL, NULL, 0, NULL } | ||||
| 	}; | ||||
| 
 | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		int c, opt_index; | ||||
| 
 | ||||
| 		c = getopt_long (argc, argv, "dhV", opts, &opt_index); | ||||
| 		if (c == -1) | ||||
| 			break; | ||||
| 	struct opt_handler oh; | ||||
| 	opt_handler_init (&oh, argc, argv, opts, NULL, "Experimental IRC daemon."); | ||||
| 
 | ||||
| 	int c; | ||||
| 	while ((c = opt_handler_get (&oh)) != -1) | ||||
| 	switch (c) | ||||
| 	{ | ||||
| 	case 'd': | ||||
| 		g_debug_mode = true; | ||||
| 		break; | ||||
| 	case 'h': | ||||
| 			print_usage (invocation_name); | ||||
| 		opt_handler_usage (&oh, stdout); | ||||
| 		exit (EXIT_SUCCESS); | ||||
| 	case 'V': | ||||
| 		printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); | ||||
| @ -3125,9 +3107,11 @@ main (int argc, char *argv[]) | ||||
| 		exit (EXIT_SUCCESS); | ||||
| 	default: | ||||
| 		print_error ("wrong options"); | ||||
| 		opt_handler_usage (&oh, stderr); | ||||
| 		exit (EXIT_FAILURE); | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	opt_handler_free (&oh); | ||||
| 
 | ||||
| 	print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting"); | ||||
| 	setup_signal_handlers (); | ||||
|  | ||||
							
								
								
									
										49
									
								
								zyklonb.c
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								zyklonb.c
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| /*
 | ||||
|  * zyklonb.c: the experimental IRC bot | ||||
|  * | ||||
|  * Copyright (c) 2014, Přemysl Janouch <p.janouch@gmail.com> | ||||
|  * Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com> | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Permission to use, copy, modify, and/or distribute this software for any | ||||
| @ -2150,52 +2150,35 @@ on_signal_pipe_readable (const struct pollfd *fd, struct bot_context *ctx) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| print_usage (const char *program_name) | ||||
| { | ||||
| 	fprintf (stderr, | ||||
| 		"Usage: %s [OPTION]...\n" | ||||
| 		"Experimental IRC bot.\n" | ||||
| 		"\n" | ||||
| 		"  -d, --debug     run in debug mode\n" | ||||
| 		"  -h, --help      display this help and exit\n" | ||||
| 		"  -V, --version   output version information and exit\n" | ||||
| 		"  --write-default-cfg [filename]\n" | ||||
| 		"                  write a default configuration file and exit\n", | ||||
| 		program_name); | ||||
| } | ||||
| 
 | ||||
| int | ||||
| main (int argc, char *argv[]) | ||||
| { | ||||
| 	const char *invocation_name = argv[0]; | ||||
| 	str_vector_init (&g_original_argv); | ||||
| 	str_vector_add_vector (&g_original_argv, argv); | ||||
| 
 | ||||
| 	static struct option opts[] = | ||||
| 	static const struct opt opts[] = | ||||
| 	{ | ||||
| 		{ "debug",             no_argument,       NULL, 'd' }, | ||||
| 		{ "help",              no_argument,       NULL, 'h' }, | ||||
| 		{ "version",           no_argument,       NULL, 'V' }, | ||||
| 		{ "write-default-cfg", optional_argument, NULL, 'w' }, | ||||
| 		{ NULL,                0,                 NULL,  0  } | ||||
| 		{ 'd', "debug", NULL, 0, "run in debug mode" }, | ||||
| 		{ 'h', "help", NULL, 0, "display this help and exit" }, | ||||
| 		{ 'V', "version", NULL, 0, "output version information and exit" }, | ||||
| 		{ 'w', "write-default-cfg", "FILENAME", | ||||
| 		  OPT_OPTIONAL_ARG | OPT_LONG_ONLY, | ||||
| 		  "write a default configuration file and exit" }, | ||||
| 		{ 0, NULL, NULL, 0, NULL } | ||||
| 	}; | ||||
| 
 | ||||
| 	while (1) | ||||
| 	{ | ||||
| 		int c, opt_index; | ||||
| 
 | ||||
| 		c = getopt_long (argc, argv, "dhV", opts, &opt_index); | ||||
| 		if (c == -1) | ||||
| 			break; | ||||
| 	struct opt_handler oh; | ||||
| 	opt_handler_init (&oh, argc, argv, opts, NULL, "Experimental IRC bot."); | ||||
| 
 | ||||
| 	int c; | ||||
| 	while ((c = opt_handler_get (&oh)) != -1) | ||||
| 	switch (c) | ||||
| 	{ | ||||
| 	case 'd': | ||||
| 		g_debug_mode = true; | ||||
| 		break; | ||||
| 	case 'h': | ||||
| 			print_usage (invocation_name); | ||||
| 		opt_handler_usage (&oh, stdout); | ||||
| 		exit (EXIT_SUCCESS); | ||||
| 	case 'V': | ||||
| 		printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); | ||||
| @ -2205,9 +2188,11 @@ main (int argc, char *argv[]) | ||||
| 		exit (EXIT_SUCCESS); | ||||
| 	default: | ||||
| 		print_error ("wrong options"); | ||||
| 		opt_handler_usage (&oh, stderr); | ||||
| 		exit (EXIT_FAILURE); | ||||
| 	} | ||||
| 	} | ||||
| 
 | ||||
| 	opt_handler_free (&oh); | ||||
| 
 | ||||
| 	print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting"); | ||||
| 	setup_signal_handlers (); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user