diff --git a/examples/Makefile.am b/examples/Makefile.am index 29f4bb6..65a4024 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -9,5 +9,6 @@ dctool_SOURCES = \ common.c \ dctool.h \ dctool.c \ + dctool_help.c \ utils.h \ utils.c diff --git a/examples/dctool.c b/examples/dctool.c index 0bc3c55..28d94c1 100644 --- a/examples/dctool.c +++ b/examples/dctool.c @@ -48,6 +48,7 @@ #endif static const dctool_command_t *g_commands[] = { + &dctool_help, NULL }; @@ -70,6 +71,51 @@ dctool_command_find (const char *name) return g_commands[i]; } +void +dctool_command_showhelp (const dctool_command_t *command) +{ + if (command == NULL) { + unsigned int maxlength = 0; + for (size_t i = 0; g_commands[i] != NULL; ++i) { + unsigned int length = strlen (g_commands[i]->name); + if (length > maxlength) + maxlength = length; + } + printf ( + "A simple command line interface for the libdivecomputer library\n" + "\n" + "Usage:\n" + " dctool [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" + " -d, --device Device name\n" + " -f, --family Device family type\n" + " -m, --model Device model number\n" + " -l, --logfile Logfile\n" + " -q, --quiet Quiet mode\n" + " -v, --verbose Verbose mode\n" +#else + " -h Show help message\n" + " -d Device name\n" + " -f Family type\n" + " -m Model number\n" + " -l Logfile\n" + " -q Quiet mode\n" + " -v Verbose mode\n" +#endif + "\n" + "Available commands:\n"); + for (size_t i = 0; g_commands[i] != NULL; ++i) { + printf (" %-*s%s\n", maxlength + 3, g_commands[i]->name, g_commands[i]->description); + } + printf ("\nSee 'dctool help ' for more information on a specific command.\n\n"); + } else { + printf ("%s\n\n%s\n", command->description, command->usage); + } +} + int dctool_cancel_cb (void *userdata) { @@ -165,34 +211,17 @@ main (int argc, char *argv[]) argv += optind; optind = RESET; - // Show help message. + // Translate the help option into a command. + char *argv_help[] = {(char *) "help", NULL, NULL}; if (help || argv[0] == NULL) { - printf ( - "A simple command line interface for the libdivecomputer library\n" - "\n" - "Usage:\n" - " dctool [options] []\n" - "\n" - "Options:\n" -#ifdef HAVE_GETOPT_LONG - " -h, --help Show help message\n" - " -d, --device Device name\n" - " -f, --family Device family type\n" - " -m, --model Device model number\n" - " -l, --logfile Logfile\n" - " -q, --quiet Quiet mode\n" - " -v, --verbose Verbose mode\n" -#else - " -h Show help message\n" - " -d Device name\n" - " -f Family type\n" - " -m Model number\n" - " -l Logfile\n" - " -q Quiet mode\n" - " -v Verbose mode\n" -#endif - "\n"); - return EXIT_SUCCESS; + if (argv[0]) { + argv_help[1] = argv[0]; + argv = argv_help; + argc = 2; + } else { + argv = argv_help; + argc = 1; + } } // Try to find the command. diff --git a/examples/dctool.h b/examples/dctool.h index f8a08ac..8edbc6a 100644 --- a/examples/dctool.h +++ b/examples/dctool.h @@ -42,6 +42,14 @@ typedef struct dctool_command_t { const char *usage; } dctool_command_t; +extern const dctool_command_t dctool_help; + +const dctool_command_t * +dctool_command_find (const char *name); + +void +dctool_command_showhelp (const dctool_command_t *command); + int dctool_cancel_cb (void *userdata); diff --git a/examples/dctool_help.c b/examples/dctool_help.c new file mode 100644 index 0000000..2848c24 --- /dev/null +++ b/examples/dctool_help.c @@ -0,0 +1,105 @@ +/* + * libdivecomputer + * + * Copyright (C) 2015 Jef Driesen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_GETOPT_H +#include +#endif + +#include +#include + +#include "dctool.h" +#include "utils.h" + +static int +dctool_help_run (int argc, char *argv[], dc_context_t *context, dc_descriptor_t *descriptor) +{ + // Default option values. + unsigned int help = 0; + + // Parse the command-line options. + int opt = 0; + const char *optstring = "h"; +#ifdef HAVE_GETOPT_LONG + struct option options[] = { + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0 } + }; + while ((opt = getopt_long (argc, argv, optstring, options, NULL)) != -1) { +#else + while ((opt = getopt (argc, argv, optstring)) != -1) { +#endif + switch (opt) { + case 'h': + help = 1; + break; + default: + return EXIT_FAILURE; + } + } + + argc -= optind; + argv += optind; + + // Show help message. + if (help) { + dctool_command_showhelp (&dctool_help); + return EXIT_SUCCESS; + } + + // Try to find the command. + const dctool_command_t *command = NULL; + if (argv[0] != NULL) { + command = dctool_command_find (argv[0]); + if (command == NULL) { + message ("Unknown command %s.\n", argv[0]); + return EXIT_FAILURE; + } + } + + // Show help message for the command. + dctool_command_showhelp (command); + + return EXIT_SUCCESS; +} + +const dctool_command_t dctool_help = { + dctool_help_run, + DCTOOL_CONFIG_NONE, + "help", + "Show basic help instructions", + "Usage:\n" + " dctool help [options] []\n" + "\n" + "Options:\n" +#ifdef HAVE_GETOPT_LONG + " -h, --help Show help message\n" +#else + " -h Show help message\n" +#endif +};