summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sterba <dsterba@suse.com>2016-11-21 13:40:43 +0100
committerDavid Sterba <dsterba@suse.com>2017-03-31 19:40:57 +0200
commit010ceab56e067b87ea282fde6ff792c1ceefd7dc (patch)
treee77e9648f35f066ef5d18da1efebadfd60968a39
parent4a1d07e8c3ae610c863e57ee31e1484d652367ea (diff)
btrfs-progs: rework option parser to use getopt for global options
Preparatory work to support more global options. The current parser abuses the subcommand table to understand help and version when specified as options (--). These are now special case when processing the global options. Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--btrfs.c94
1 files changed, 75 insertions, 19 deletions
diff --git a/btrfs.c b/btrfs.c
index 9214ae6e..2d39f2ce 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -17,6 +17,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <getopt.h>
#include "volumes.h"
#include "crc32c.h"
@@ -164,24 +165,77 @@ static int cmd_version(int argc, char **argv)
return 0;
}
-static void check_options(int argc, char **argv)
+/*
+ * Parse global options, between binary name and first non-option argument
+ * after processing all valid options (including those with arguments).
+ *
+ * Returns index to argv where parsting stopped, optind is reset to 1
+ */
+static int handle_global_options(int argc, char **argv)
{
- const char *arg;
+ enum { OPT_HELP = 256, OPT_VERSION, OPT_FULL };
+ static const struct option long_options[] = {
+ { "help", no_argument, NULL, OPT_HELP },
+ { "version", no_argument, NULL, OPT_VERSION },
+ { "full", no_argument, NULL, OPT_FULL },
+ { NULL, 0, NULL, 0}
+ };
+ int shift;
if (argc == 0)
- return;
+ return 0;
- arg = argv[0];
+ opterr = 0;
+ while (1) {
+ int c;
+
+ c = getopt_long(argc, argv, "+", long_options, NULL);
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case OPT_HELP: break;
+ case OPT_VERSION: break;
+ case OPT_FULL: break;
+ default:
+ fprintf(stderr, "Unknown global option: %s\n",
+ argv[optind - 1]);
+ exit(129);
+ }
+ }
- if (arg[0] != '-' ||
- !strcmp(arg, "--help") ||
- !strcmp(arg, "--version"))
- return;
+ shift = optind;
+ optind = 1;
+
+ return shift;
+}
+
+void handle_special_globals(int shift, int argc, char **argv)
+{
+ int has_help = 0;
+ int has_full = 0;
+ int i;
+
+ for (i = 0; i < shift; i++) {
+ if (strcmp(argv[i], "--help") == 0)
+ has_help = 1;
+ else if (strcmp(argv[i], "--full") == 0)
+ has_full = 1;
+ }
+
+ if (has_help) {
+ if (has_full)
+ usage_command_group(&btrfs_cmd_group, 1, 0);
+ else
+ cmd_help(argc, argv);
+ exit(0);
+ }
- fprintf(stderr, "Unknown option: %s\n", arg);
- fprintf(stderr, "usage: %s\n",
- btrfs_cmd_group.usagestr[0]);
- exit(129);
+ for (i = 0; i < shift; i++)
+ if (strcmp(argv[i], "--version") == 0) {
+ cmd_version(argc, argv);
+ exit(0);
+ }
}
static const struct cmd_group btrfs_cmd_group = {
@@ -223,13 +277,15 @@ int main(int argc, char **argv)
if (!strcmp(bname, "btrfsck")) {
argv[0] = "check";
} else {
- argc--;
- argv++;
- check_options(argc, argv);
- if (argc > 0) {
- if (!prefixcmp(argv[0], "--"))
- argv[0] += 2;
- } else {
+ int shift;
+
+ shift = handle_global_options(argc, argv);
+ handle_special_globals(shift, argc, argv);
+ while (shift-- > 0) {
+ argc--;
+ argv++;
+ }
+ if (argc == 0) {
usage_command_group_short(&btrfs_cmd_group);
exit(1);
}