]> www.infradead.org Git - users/sagi/nvme-cli.git/commitdiff
Improved command line support
authorStephen Bates <stephen.bates@pmcs.com>
Thu, 12 Feb 2015 13:24:16 +0000 (13:24 +0000)
committerStephen Bates <stephen.bates@pmcs.com>
Wed, 18 Feb 2015 17:10:15 +0000 (17:10 +0000)
Converted nvme.c to use argconfig. This provides improved command line
support and suffix support (e.g. 4k, 1M).

Makefile
nvme.c
regress
scripts/latency [moved from latency with 100% similarity]
src/argconfig.c [new file with mode: 0644]
src/argconfig.h [new file with mode: 0644]
src/suffix.c [new file with mode: 0644]
src/suffix.h [new file with mode: 0644]

index b0a0c6f86e2ac60949afc7db5a842c35c597fbd7..db88e038722244924e2d3bec6c69c3932b76e313 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
-CFLAGS := -m64 -O2 -g -pthread -D_GNU_SOURCE -D_REENTRANT -Wall -Werror
+CFLAGS := -I $(SRC) -m64 -std=c99 -O2 -g -pthread -D_GNU_SOURCE -D_REENTRANT -Wall -Werror
 LDFLAGS := -lm
 NVME = nvme
 INSTALL ?= install
-
+SRC = ./src
 LIBUDEV:=$(shell ld -ludev > /dev/null 2>&1 ; echo $$?)
 ifeq ($(LIBUDEV),0)
        LDFLAGS += -ludev
@@ -11,8 +11,14 @@ endif
 
 default: $(NVME)
 
-nvme: nvme.c
-       $(CC) $(CFLAGS) nvme.c $(LDFLAGS) -o $(NVME)
+nvme: nvme.c ./linux/nvme.h argconfig.o suffix.o
+       $(CC) $(CFLAGS) nvme.c $(LDFLAGS) -o $(NVME) argconfig.o suffix.o
+
+argconfig.o: $(SRC)/argconfig.c $(SRC)/argconfig.h $(SRC)/suffix.h
+       $(CC) -c $(CFLAGS) $(SRC)/argconfig.c
+
+suffix.o: $(SRC)/suffix.c $(SRC)/suffix.h
+       $(CC) -c $(CFLAGS) $(SRC)/suffix.c
 
 doc: $(NVME)
        $(MAKE) -C Documentation
@@ -30,6 +36,3 @@ install: default
        $(INSTALL) -m 755 nvme /usr/local/bin
 
 .PHONY: default all doc clean clobber install
-
-test:
-       @echo $(LIBUDEV)
\ No newline at end of file
diff --git a/nvme.c b/nvme.c
index 5acbef29c6f9521a2fad9b754c14b4e0317699f2..ff4f000ea1a5ede3f4ac68ab6c026234054ee09c 100644 (file)
--- a/nvme.c
+++ b/nvme.c
@@ -43,6 +43,7 @@
 #include <sys/time.h>
 
 #include "linux/nvme.h"
+#include "src/argconfig.h"
 
 static int fd;
 static struct stat nvme_stat;
@@ -150,38 +151,6 @@ static void get_dev(int optind, int argc, char **argv)
        open_dev((const char *)argv[optind]);
 }
 
-static void get_long(char *optarg, __u64 *val)
-{
-       if (sscanf(optarg, "%lli", val) == 1)
-               return;
-       fprintf(stderr, "bad param for command value:%s\n", optarg);
-       exit(EINVAL);
-}
-
-static void get_int(char *optarg, __u32 *val)
-{
-       if (sscanf(optarg, "%i", val) == 1)
-               return;
-       fprintf(stderr, "bad param for command value:%s\n", optarg);
-       exit(EINVAL);
-}
-
-static void get_short(char *optarg, __u16 *val)
-{
-       if (sscanf(optarg, "%hi", val) == 1)
-               return;
-       fprintf(stderr, "bad param for command value:%s\n", optarg);
-       exit(EINVAL);
-}
-
-static void get_byte(char *optarg, __u8 *val)
-{
-       if (sscanf(optarg, "%hhi", val) == 1)
-               return;
-       fprintf(stderr, "bad param for command value:%s\n", optarg);
-       exit(EINVAL);
-}
-
 static void show_error_log(struct nvme_error_log_page *err_log, int entries)
 {
        int i;
@@ -565,34 +534,35 @@ static void show_nvme_id_ns(struct nvme_id_ns *ns, int id, int vs)
 static int get_smart_log(int argc, char **argv)
 {
        struct nvme_smart_log smart_log;
-       int long_index, opt, err;
-       unsigned int raw = 0, nsid = 0xffffffff;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+       int err;
+
+       struct config {
+               __u32 namespace_id;
+               __u8  raw_binary;
        };
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0xffffffff,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "get_smart_log", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:b", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
        err = nvme_get_log(&smart_log,
                sizeof(smart_log), 0x2 | (((sizeof(smart_log) / 4) - 1) << 16),
-               nsid);
+               cfg.namespace_id);
        if (!err) {
-               if (!raw)
-                       show_smart_log(&smart_log, nsid);
+               if (!cfg.raw_binary)
+                       show_smart_log(&smart_log, cfg.namespace_id);
                else
                        d_raw((unsigned char *)&smart_log, sizeof(smart_log));
        }
@@ -603,76 +573,80 @@ static int get_smart_log(int argc, char **argv)
 
 static int get_error_log(int argc, char **argv)
 {
-       int opt, err, long_index = 0;
-       unsigned int raw = 0, log_entries = 64, nsid = 0xffffffff;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"log-entries", required_argument, 0, 'e'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+       int err;
+
+       struct config {
+               __u32 namespace_id;
+               __u32 log_entries;
+               __u8  raw_binary;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:e:b", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'e':
-                       get_int(optarg, &log_entries);
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       if (!log_entries) {
+       const struct config defaults = {
+               .namespace_id = 0xffffffff,
+               .log_entries  = 64,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"log-entries",  "NUM",  CFG_POSITIVE, &defaults.log_entries,  required_argument, NULL},
+               {"e",            "NUM",  CFG_POSITIVE, &defaults.log_entries,  required_argument, NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "get_error_log", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (!cfg.log_entries) {
                fprintf(stderr, "non-zero log-entires is required param\n");
                return EINVAL;
-       } else {
-               struct nvme_error_log_page err_log[log_entries];
+       }
+       struct nvme_error_log_page err_log[cfg.log_entries];
        
-               err = nvme_get_log(err_log,
-                               sizeof(err_log), 0x1 | (((sizeof(err_log) / 4) - 1) << 16),
-                               nsid);
-               if (!err) {
-                       if (!raw)
-                               show_error_log(err_log, log_entries);
-                       else
-                               d_raw((unsigned char *)err_log, sizeof(err_log));
-               }
-               else if (err > 0)
-                       fprintf(stderr, "NVMe Status: %s\n", nvme_status_to_string(err));
-               return err;
+       err = nvme_get_log(err_log,
+                          sizeof(err_log), 0x1 | (((sizeof(err_log) / 4) - 1) << 16),
+                          cfg.namespace_id);
+       if (!err) {
+               if (!cfg.raw_binary)
+                       show_error_log(err_log, cfg.log_entries);
+               else
+                       d_raw((unsigned char *)err_log, sizeof(err_log));
        }
+       else if (err > 0)
+               fprintf(stderr, "NVMe Status: %s\n", nvme_status_to_string(err));
+       return err;
 }
 
 static int get_fw_log(int argc, char **argv)
 {
-       int err, opt, long_index = 0, raw = 0;
+       int err;
        struct nvme_firmware_log_page fw_log;
-       static struct option opts[] = {
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+
+       struct config {
+               __u8  raw_binary;
        };
+       struct config cfg;
+
+       const struct config defaults = {
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"raw-binary", "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",          "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "get_fw_log", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       while ((opt = getopt_long(argc, (char **)argv, "b", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'b':
-                       raw = 1;
-                       break;
-               }
-       }
-       get_dev(optind, argc, argv);
        err = nvme_get_log(&fw_log,
                        sizeof(fw_log), 0x3 | (((sizeof(fw_log) / 4) - 1) << 16),
                        0xffffffff);
        if (!err) {
-               if (!raw)
+               if (!cfg.raw_binary)
                        show_fw_log(&fw_log);
                else
                        d_raw((unsigned char *)&fw_log, sizeof(fw_log));
@@ -686,50 +660,53 @@ static int get_fw_log(int argc, char **argv)
 
 static int get_log(int argc, char **argv)
 {
-       int opt, err, long_index = 0;
-       unsigned int raw = 0, lid = 0, log_len = 0, nsid = 0xffffffff;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"log-id", required_argument, 0, 'i'},
-               {"log-len", required_argument, 0, 'l'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+       int err;
+
+       struct config {
+               __u32 namespace_id;
+               __u32 log_id;
+               __u32 log_len;
+               __u8  raw_binary;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:i:l:b", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'i':
-                       get_int(optarg, &lid);
-                       break;
-               case 'l':
-                       get_int(optarg, &log_len);
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       if (!log_len) {
+       const struct config defaults = {
+               .namespace_id = 0,
+               .log_id       = 0,
+               .log_len      = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"log-id",       "NUM",  CFG_POSITIVE, &defaults.log_id,       required_argument, NULL},
+               {"i",            "NUM",  CFG_POSITIVE, &defaults.log_id,       required_argument, NULL},
+               {"log-len",      "NUM",  CFG_POSITIVE, &defaults.log_len,      required_argument, NULL},
+               {"l",            "NUM",  CFG_POSITIVE, &defaults.log_len,      required_argument, NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "get_log", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (!cfg.log_len) {
                fprintf(stderr, "non-zero log-len is required param\n");
                return EINVAL;
        } else {
-               unsigned char log[log_len];
+               unsigned char log[cfg.log_len];
 
-               err = nvme_get_log(log, log_len, lid | (((log_len / 4) - 1) << 16), nsid);
+               err = nvme_get_log(log, cfg.log_len, cfg.log_id | (((cfg.log_len / 4) - 1) << 16), 
+                                  cfg.namespace_id);
                if (!err) {
-                       if (!raw) {
+                       if (!cfg.raw_binary) {
                                printf("Device:%s log-id:%d namespace-id:%#x",
-                                                               devicename, lid, nsid);
-                               d(log, log_len, 16, 1);
+                                      devicename, cfg.log_id, 
+                                      cfg.namespace_id);
+                               d(log, cfg.log_len, 16, 1);
                        } else
-                               d_raw((unsigned char *)log, log_len);
+                               d_raw((unsigned char *)log, cfg.log_len);
                } else if (err > 0)
                        fprintf(stderr, "NVMe Status: %s\n",
                                                nvme_status_to_string(err));
@@ -739,26 +716,28 @@ static int get_log(int argc, char **argv)
 
 static int list_ns(int argc, char **argv)
 {
-       int opt, err, i, long_index = 0;
-       unsigned int nsid = 0;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {0, 0, 0, 0 }
-       };
+       int err, i;
        __u32 ns_list[1024];
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       err = identify(nsid, ns_list, 2);
+       struct config {
+               __u32 namespace_id;
+       };
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "list_ns", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       err = identify(cfg.namespace_id, ns_list, 2);
        if (!err) {
                for (i = 0; i < 1024; i++)
                        if (ns_list[i])
@@ -766,7 +745,7 @@ static int list_ns(int argc, char **argv)
        }
        else if (err > 0)
                fprintf(stderr, "NVMe Status: %s NSID:%d\n",
-                               nvme_status_to_string(err), nsid);
+                               nvme_status_to_string(err), cfg.namespace_id);
        return err;
 }
 
@@ -822,34 +801,35 @@ static int list(int argc, char **argv)
 
 static int id_ctrl(int argc, char **argv)
 {
-       int opt, err, raw = 0, vs = 0, long_index = 0;
+       int err;
        struct nvme_id_ctrl ctrl;
-       static struct option opts[] = {
-               {"vendor-specific", no_argument, 0, 'v'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+
+       struct config {
+               __u8  vendor_specific;
+               __u8  raw_binary;
        };
+       struct config cfg;
+
+       const struct config defaults = {
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"vendor-specific", "NUM",  CFG_POSITIVE, &defaults.vendor_specific, no_argument,       NULL},
+               {"v",               "NUM",  CFG_POSITIVE, &defaults.vendor_specific, no_argument,       NULL},
+               {"raw-binary",      "NUM",  CFG_POSITIVE, &defaults.raw_binary,      no_argument,       NULL},
+               {"b",               "NUM",  CFG_POSITIVE, &defaults.raw_binary,      no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "id_ctrl", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       while ((opt = getopt_long(argc, (char **)argv, "vb", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'v':
-                       vs = 1;
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
        err = identify(0, &ctrl, 1);
        if (!err) {
-               if (raw)
+               if (cfg.raw_binary)
                        d_raw((unsigned char *)&ctrl, sizeof(ctrl));
                else
-                       show_nvme_id_ctrl(&ctrl, vs);
+                       show_nvme_id_ctrl(&ctrl, cfg.vendor_specific);
        }
        else if (err > 0)
                fprintf(stderr, "NVMe Status: %s\n", nvme_status_to_string(err));
@@ -860,55 +840,55 @@ static int id_ctrl(int argc, char **argv)
 static int id_ns(int argc, char **argv)
 {
        struct nvme_id_ns ns;
-       int opt, err, long_index = 0;
-       unsigned int nsid = 0, vs = 0, raw = 0;
-
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"vendor-specific", no_argument, 0, 'v'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+       int err;
+
+       struct config {
+               __u32 namespace_id;
+               __u8  vendor_specific;
+               __u8  raw_binary;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:vb", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'v':
-                       vs = 1;
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       if (!nsid) {
+       const struct config defaults = {
+               .namespace_id    = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id",    "NUM",  CFG_POSITIVE, &defaults.namespace_id,    required_argument, NULL},
+               {"n",               "NUM",  CFG_POSITIVE, &defaults.namespace_id,    required_argument, NULL},
+               {"vendor-specific", "NUM",  CFG_POSITIVE, &defaults.vendor_specific, no_argument,       NULL},
+               {"v",               "NUM",  CFG_POSITIVE, &defaults.vendor_specific, no_argument,       NULL},
+               {"raw-binary",      "NUM",  CFG_POSITIVE, &defaults.raw_binary,      no_argument,       NULL},
+               {"b",               "NUM",  CFG_POSITIVE, &defaults.raw_binary,      no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "id_ns", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (!cfg.namespace_id) {
                if (!S_ISBLK(nvme_stat.st_mode)) {
                        fprintf(stderr,
                                "%s: non-block device requires namespace-id param\n",
                                devicename);
                        exit(ENOTBLK);
                }
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        perror(devicename);
                        exit(errno);
                }
        }
-       err = identify(nsid, &ns, 0);
+       err = identify(cfg.namespace_id, &ns, 0);
        if (!err) {
-               if (raw)
+               if (cfg.raw_binary)
                        d_raw((unsigned char *)&ns, sizeof(ns));
                else
-                       show_nvme_id_ns(&ns, nsid, vs);
+                       show_nvme_id_ns(&ns, cfg.namespace_id, cfg.vendor_specific);
        }
        else if (err > 0)
-               fprintf(stderr, "NVMe Status: %s NSID:%d\n", nvme_status_to_string(err), nsid);
+               fprintf(stderr, "NVMe Status: %s NSID:%d\n", nvme_status_to_string(err), 
+                       cfg.namespace_id);
        return err;
 }
 
@@ -953,75 +933,75 @@ static int nvme_feature(int opcode, void *buf, int data_len, __u32 fid,
 
 static int get_feature(int argc, char **argv)
 {
-       int opt, err, long_index = 0;
-       unsigned int f, result, raw = 0, cdw10, cdw11 = 0, nsid = 0, data_len = 0;
-       unsigned char sel = 0;
+       int err;
+       unsigned int result, cdw10 = 0;
        void *buf = NULL;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"feature-id", required_argument, 0, 'f'},
-               {"sel", required_argument, 0, 's'},
-               {"cdw11", required_argument, 0, 0},
-               {"data-len", required_argument, 0, 'l'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {0, 0, 0, 0 }
+
+       struct config {
+               __u32 namespace_id;
+               __u32 feature_id;
+               __u8  sel;
+               __u32 cdw11;
+               __u32 data_len;
+               __u8  raw_binary;
+       };
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0,
+               .feature_id   = 0,
+               .sel          = 0,
+               .cdw11        = 0,
+               .data_len     = 0,
        };
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:f:l:s:b", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 0:
-                       get_int(optarg, &cdw11);
-                       break;
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'f':
-                       get_int(optarg, &f);
-                       break;
-               case 'l':
-                       get_int(optarg, &data_len);
-                       break;
-               case 's':
-                       get_byte(optarg, &sel);
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       if (sel > 7) {
-               fprintf(stderr, "invalid 'select' param:%d\n", sel);
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"feature-id",   "NUM",  CFG_POSITIVE, &defaults.feature_id,   required_argument, NULL},
+               {"f",            "NUM",  CFG_POSITIVE, &defaults.feature_id,   required_argument, NULL},
+               {"sel",          "NUM",  CFG_POSITIVE, &defaults.sel,          required_argument, NULL},
+               {"s",            "NUM",  CFG_POSITIVE, &defaults.sel,          required_argument, NULL},
+               {"cdw11",        "NUM",  CFG_POSITIVE, &defaults.cdw11,        required_argument, NULL},
+               {"data-len",     "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {"l",            "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "get_feature", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (cfg.sel > 7) {
+               fprintf(stderr, "invalid 'select' param:%d\n", cfg.sel);
                return EINVAL;
        }
-       if (!f) {
+       if (!cfg.feature_id) {
                fprintf(stderr, "feature-id required param\n");
                return EINVAL;
        }
-       if (f == NVME_FEAT_LBA_RANGE)
-               data_len = 4096;
-       if (data_len)
-               buf = malloc(data_len);
+       if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
+               cfg.data_len = 4096;
+       if (cfg.data_len)
+               buf = malloc(cfg.data_len);
 
-       cdw10 = sel << 8 | f;
-       err = nvme_feature(nvme_admin_get_features, buf, data_len, cdw10, nsid,
-                                                       cdw11, &result);
+       cdw10 = cfg.sel << 8 | cfg.feature_id;
+       err = nvme_feature(nvme_admin_get_features, buf, cfg.data_len, cdw10, 
+                          cfg.namespace_id, cfg.cdw11, &result);
        if (!err) {
-               printf("get-feature:%d(%s), value:%#08x\n", f,
-                       nvme_feature_to_string(f), result);
+               printf("get-feature:%d(%s), value:%#08x\n", cfg.feature_id,
+                       nvme_feature_to_string(cfg.feature_id), result);
                if (buf) {
-                       if (!raw) {
-                               if (f == NVME_FEAT_LBA_RANGE)
+                       if (!cfg.raw_binary) {
+                               if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
                                        show_lba_range((struct nvme_lba_range_type *)buf,
                                                                        result);
                                else
-                                       d(buf, data_len, 16, 1);
+                                       d(buf, cfg.data_len, 16, 1);
                        }
                        else
-                               d_raw(buf, data_len);
+                               d_raw(buf, cfg.data_len);
                }
        }
        else if (err > 0)
@@ -1034,37 +1014,40 @@ static int get_feature(int argc, char **argv)
 #define min(x, y) x > y ? y : x;
 static int fw_download(int argc, char **argv)
 {
-       int opt, err, long_index = 0, fw_fd = -1;
-       unsigned int fw_size, xfer_size = 4096, offset = 0;
+       int err, fw_fd = -1;
+       unsigned int fw_size;
        struct stat sb;
        struct nvme_admin_cmd cmd;
        void *fw_buf;
-       static struct option opts[] = {
-               {"fw", required_argument, 0, 'f'},
-               {"xfer", required_argument, 0, 'x'},
-               {"offset", required_argument, 0, 'o'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               char  *fw;
+               __u32 xfer;
+               __u32 offset;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "x:f:o:", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'f':
-                       fw_fd = open(optarg, O_RDONLY);
-                       break;
-               case 'x':
-                       get_int(optarg, &xfer_size);
-                       break;
-               case 'p':
-                       get_int(optarg, &offset);
-                       offset <<= 2;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .fw     = "",
+               .xfer   = 0,
+               .offset = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"fw",     "FILE", CFG_STRING,   &defaults.fw,     required_argument, NULL},
+               {"f",      "FILE", CFG_STRING,   &defaults.fw,     required_argument, NULL},
+               {"xfer",   "NUM",  CFG_POSITIVE, &defaults.xfer,   required_argument, NULL},
+               {"x",      "NUM",  CFG_POSITIVE, &defaults.xfer,   required_argument, NULL},
+               {"offset", "NUM",  CFG_POSITIVE, &defaults.offset, required_argument, NULL},
+               {"o",      "NUM",  CFG_POSITIVE, &defaults.offset, required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "fw_download", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
+       fw_fd = open(cfg.fw, O_RDONLY);
+       cfg.offset <<= 2;
        if (fw_fd < 0) {
                fprintf(stderr, "no firmware file provided\n");
                return EINVAL;
@@ -1084,18 +1067,18 @@ static int fw_download(int argc, char **argv)
                fprintf(stderr, "No memory for f/w size:%d\n", fw_size);
                return ENOMEM;
        }
-       if (xfer_size % 4096)
-               xfer_size = 4096;
+       if (cfg.xfer % 4096)
+               cfg.xfer = 4096;
 
        while (fw_size > 0) {
-               xfer_size = min(xfer_size, fw_size);
+               cfg.xfer = min(cfg.xfer, fw_size);
 
                memset(&cmd, 0, sizeof(cmd));
-               cmd.opcode = nvme_admin_download_fw;
-               cmd.addr = (__u64)fw_buf;
-               cmd.data_len = xfer_size;
-               cmd.cdw10 = (xfer_size >> 2) - 1;
-               cmd.cdw11 offset >> 2; 
+               cmd.opcode   = nvme_admin_download_fw;
+               cmd.addr     = (__u64)fw_buf;
+               cmd.data_len = cfg.xfer;
+               cmd.cdw10    = (cfg.xfer >> 2) - 1;
+               cmd.cdw11    = cfg.offset >> 2; 
 
                err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
                if (err < 0) {
@@ -1105,9 +1088,9 @@ static int fw_download(int argc, char **argv)
                        fprintf(stderr, "NVME Admin command error:%d\n", err);
                        break;
                }
-               fw_buf += xfer_size;
-               fw_size -= xfer_size;
-               offset += xfer_size;
+               fw_buf     += cfg.xfer;
+               fw_size    -= cfg.xfer;
+               cfg.offset += cfg.xfer;
        }
        if (!err)
                printf("Firmware download success\n");
@@ -1116,41 +1099,43 @@ static int fw_download(int argc, char **argv)
 
 static int fw_activate(int argc, char **argv)
 {
-       int opt, err, long_index;
-       unsigned char slot = 0, action = 1;
+       int err;
        struct nvme_admin_cmd cmd;
-       static struct option opts[] = {
-               {"slot", required_argument, 0, 's'},
-               {"action", required_argument, 0, 'a'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               __u8 slot;
+               __u8 action;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "s:a:", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 's':
-                       get_byte(optarg, &slot);
-                       if (slot > 7) {
-                               fprintf(stderr, "invalid slot:%d\n", slot);
-                               return EINVAL;
-                       }
-                       break;
-               case 'a':
-                       get_byte(optarg, &action);
-                       if (action > 3) {
-                               fprintf(stderr, "invalid action:%d\n", action);
-                               return EINVAL;
-                       }
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .slot   = 0,
+               .action = 0,
+       };
 
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"slot",   "NUM", CFG_POSITIVE, &defaults.slot,   required_argument, NULL},
+               {"s",      "NUM", CFG_POSITIVE, &defaults.slot,   required_argument, NULL},
+               {"action", "NUM", CFG_POSITIVE, &defaults.action, required_argument, NULL},
+               {"a",      "NUM", CFG_POSITIVE, &defaults.action, required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "fw_activate", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+       
+       if (cfg.slot > 7) {
+               fprintf(stderr, "invalid slot:%d\n", cfg.slot);
+               return EINVAL;
+       }
+       if (cfg.action > 3) {
+               fprintf(stderr, "invalid action:%d\n", cfg.action);
+               return EINVAL;
+       }
+       
        memset(&cmd, 0, sizeof(cmd));
        cmd.opcode = nvme_admin_activate_fw;
-       cmd.cdw10 = (action << 3) | slot;
+       cmd.cdw10  = (cfg.action << 3) | cfg.slot;
 
        err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
        if (err < 0)
@@ -1158,7 +1143,8 @@ static int fw_activate(int argc, char **argv)
        else if (err != 0)
                fprintf(stderr, "NVME Admin command error:%d\n", err);
        else
-               printf("Success activating firmware action:%d slot:%d\n", action, slot);
+               printf("Success activating firmware action:%d slot:%d\n", 
+                      cfg.action, cfg.slot);
        return err;
 }
 
@@ -1212,58 +1198,60 @@ static int show_registers(int argc, char **argv)
 
 static int format(int argc, char **argv)
 {
-       int opt, err, long_index;
-       unsigned int nsid = 0xffffffff;
-       unsigned char lbaf = 0, ses = 0, pil = 0, pi = 0, ms = 0;
+       int err;
        struct nvme_admin_cmd cmd;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"lbaf", required_argument, 0, 'l'},
-               {"ses", required_argument, 0, 's'},
-               {"pil", required_argument, 0, 'p'},
-               {"pi", required_argument, 0, 'i'},
-               {"ms", required_argument, 0, 'm'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               __u32 namespace_id;
+               __u8  lbaf;
+               __u8  ses;
+               __u8  pi;
+               __u8  pil;
+               __u8  ms;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:l:s:p:i:m:", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               case 'l': get_byte(optarg, &lbaf); break;
-               case 's': get_byte(optarg, &ses); break;
-               case 'p': get_byte(optarg, &pil); break;
-               case 'i': get_byte(optarg, &pi); break;
-               case 'm': get_byte(optarg, &ms); break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .namespace_id = 0xffffffff,
+               .lbaf         = 0,
+               .ses          = 0,
+               .pi           = 0,
+       };
 
-       if (ms > 1) {
-               fprintf(stderr, "invalid pi:%d\n", ms);
-               return EINVAL;
-       }
-       if (pil > 1) {
-               fprintf(stderr, "invalid pi location:%d\n", pil);
-               return EINVAL;
-       }
-       if (ses > 7) {
-               fprintf(stderr, "invalid secure erase settings:%d\n", ses);
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"lbaf",         "NUM",  CFG_POSITIVE, &defaults.lbaf,         required_argument, NULL},
+               {"l",            "NUM",  CFG_POSITIVE, &defaults.lbaf,         required_argument, NULL},
+               {"ses",          "NUM",  CFG_POSITIVE, &defaults.ses,          required_argument, NULL},
+               {"s",            "NUM",  CFG_POSITIVE, &defaults.ses,          required_argument, NULL},
+               {"pi",           "NUM",  CFG_POSITIVE, &defaults.pi,           required_argument, NULL},
+               {"i",            "NUM",  CFG_POSITIVE, &defaults.pi,           required_argument, NULL},
+               {"pil",          "NUM",  CFG_POSITIVE, &defaults.pil,          no_argument,       NULL},
+               {"p",            "NUM",  CFG_POSITIVE, &defaults.pil,          no_argument,       NULL},
+               {"ms",           "NUM",  CFG_POSITIVE, &defaults.ms,           no_argument,       NULL},
+               {"m",            "NUM",  CFG_POSITIVE, &defaults.ms,           no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "format", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (cfg.ses > 7) {
+               fprintf(stderr, "invalid secure erase settings:%d\n", cfg.ses);
                return EINVAL;
        }
-       if (lbaf > 15) {
-               fprintf(stderr, "invalid lbaf:%d\n", lbaf);
+       if (cfg.lbaf > 15) {
+               fprintf(stderr, "invalid lbaf:%d\n", cfg.lbaf);
                return EINVAL;
        }
-       if (pi > 7) {
-               fprintf(stderr, "invalid pi:%d\n", pi);
+       if (cfg.pi > 7) {
+               fprintf(stderr, "invalid pi:%d\n", cfg.pi);
                return EINVAL;
        }
        if (S_ISBLK(nvme_stat.st_mode)) {
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        fprintf(stderr,
                                "%s: failed to return namespace id\n",
                                devicename);
@@ -1273,8 +1261,8 @@ static int format(int argc, char **argv)
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.opcode = nvme_admin_format_nvm;
-       cmd.nsid = nsid;
-       cmd.cdw10 = (lbaf << 0) | (ms << 4) | (pi << 5) | (pil << 8) | (ses << 9);
+       cmd.nsid   = cfg.namespace_id;
+       cmd.cdw10  = (cfg.lbaf << 0) | (cfg.ms << 4) | (cfg.pi << 5) | (cfg.pil << 8) | (cfg.ses << 9);
        
        err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
        if (err < 0)
@@ -1283,7 +1271,7 @@ static int format(int argc, char **argv)
                fprintf(stderr, "NVME Admin command error:%s(%d)\n",
                                        nvme_status_to_string(err), err);
        else {
-               printf("Success formatting namespace:%x\n", nsid);
+               printf("Success formatting namespace:%x\n", cfg.namespace_id);
                ioctl(fd, BLKRRPART);
        }
        return err;
@@ -1292,61 +1280,64 @@ static int format(int argc, char **argv)
 /* FIXME: read a buffer from a file if the feature requires one */
 static int set_feature(int argc, char **argv)
 {
-       int opt, err, long_index = 0, val = -1;
-       unsigned int f, v, result, nsid = 0, data_len = 0;
+       int err;
+       unsigned int result;
        void *buf = NULL;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"feature-id", required_argument, 0, 'f'},
-               {"value", required_argument, 0, 'v'},
-               {"data-len", required_argument, 0, 'l'},
-               {0, 0, 0, 0 }
+
+       struct config {
+               __u32 namespace_id;
+               __u32 feature_id;
+               __u32 value;
+               __u32 data_len;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:f:l:v:", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case 'n':
-                       get_int(optarg, &nsid);
-                       break;
-               case 'f':
-                       get_int(optarg, &f);
-                       break;
-               case 'l':
-                       get_int(optarg, &data_len);
-                       break;
-               case 'v':
-                       get_int(optarg, &v);
-                       val = (int)v;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
-       if (val == -1) {
+       const struct config defaults = {
+               .namespace_id = 0,
+               .feature_id   = 0,
+               .value        = 0,
+               .data_len     = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"feature-id",   "NUM",  CFG_POSITIVE, &defaults.feature_id,   required_argument, NULL},
+               {"f",            "NUM",  CFG_POSITIVE, &defaults.feature_id,   required_argument, NULL},
+               {"value",        "NUM",  CFG_POSITIVE, &defaults.value,        required_argument, NULL},
+               {"v",            "NUM",  CFG_POSITIVE, &defaults.value,        required_argument, NULL},
+               {"data-len",     "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {"l",            "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "set_feature", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (cfg.value == -1) {
                fprintf(stderr, "feature value required param\n");
                return EINVAL;
        }
-       if (!f) {
+       if (!cfg.feature_id) {
                fprintf(stderr, "feature-id required param\n");
                return EINVAL;
        }
-       if (f == NVME_FEAT_LBA_RANGE)
-               data_len = 4096;
-       if (data_len)
-               buf = malloc(data_len);
+       if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
+               cfg.data_len = 4096;
+       if (cfg.data_len)
+               buf = malloc(cfg.data_len);
 
-       err = nvme_feature(nvme_admin_set_features, buf, data_len, f, nsid, v, &result);
+       err = nvme_feature(nvme_admin_set_features, buf, cfg.data_len, cfg.feature_id, 
+                          cfg.namespace_id, cfg.value, &result);
        if (!err) {
-               printf("set-feature:%d(%s), value:%#08x\n", f,
-                       nvme_feature_to_string(f), result);
+               printf("set-feature:%d(%s), value:%#08x\n", cfg.feature_id,
+                       nvme_feature_to_string(cfg.feature_id), result);
                if (buf) {
-                       if (f == NVME_FEAT_LBA_RANGE)
+                       if (cfg.feature_id == NVME_FEAT_LBA_RANGE)
                                show_lba_range((struct nvme_lba_range_type *)buf,
                                                                result);
                        else
-                               d(buf, data_len, 16, 1);
+                               d(buf, cfg.data_len, 16, 1);
                }
        }
        else if (err > 0)
@@ -1360,41 +1351,41 @@ static int sec_send(int argc, char **argv)
 {
        struct stat sb;
        struct nvme_admin_cmd cmd;
-        int err, sec_fd = -1, opt, long_index = 0;
+        int err, sec_fd = -1;
        void *sec_buf;
-       unsigned int tl = 0;
-       unsigned short spsp = 0;
-       unsigned char secp = 0;
        unsigned int sec_size;
-       static struct option opts[] = {
-               {"file", required_argument, 0, 'f'},
-               {"secp", required_argument, 0, 'p'},
-               {"spsp", required_argument, 0, 's'},
-               {"tl", required_argument, 0, 't'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               char  *file;
+               __u8  secp;
+               __u16 spsp;
+               __u32 tl;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "f:p:s:t:", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'f':
-                       sec_fd = open(optarg, O_RDONLY);
-                       break;
-               case 'p':
-                       get_short(optarg, &spsp);
-                       break;
-               case 's':
-                       get_byte(optarg, &secp);
-                       break;
-               case 't':
-                       get_int(optarg, &tl);
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .file = "",
+               .secp = 0,
+               .spsp = 0,
+               .tl   = 0,
+       };
 
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"file",       "FILE",  CFG_STRING,   &defaults.file,       required_argument, NULL},
+               {"f",          "FILE",  CFG_STRING,   &defaults.file,       required_argument, NULL},
+               {"secp",       "NUM",   CFG_POSITIVE, &defaults.secp,       required_argument, NULL},
+               {"p",          "NUM",   CFG_POSITIVE, &defaults.secp,       required_argument, NULL},
+               {"spsp",       "NUM",   CFG_POSITIVE, &defaults.spsp,       required_argument, NULL},
+               {"s",          "NUM",   CFG_POSITIVE, &defaults.spsp,       required_argument, NULL},
+               {"tl",         "NUM",   CFG_POSITIVE, &defaults.tl,         required_argument, NULL},
+               {"t",          "NUM",   CFG_POSITIVE, &defaults.tl,         required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "sec_send", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       sec_fd = open(cfg.file, O_RDONLY);
        if (sec_fd < 0) {
                fprintf(stderr, "no firmware file provided\n");
                return EINVAL;
@@ -1411,11 +1402,11 @@ static int sec_send(int argc, char **argv)
        }
 
         memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_admin_security_send;
-        cmd.cdw10 = secp << 24 | spsp << 8;
-        cmd.cdw11 tl;
+        cmd.opcode   = nvme_admin_security_send;
+        cmd.cdw10    = cfg.secp << 24 | cfg.spsp << 8;
+        cmd.cdw11    = cfg.tl;
         cmd.data_len = sec_size;
-        cmd.addr = (__u64)sec_buf;
+        cmd.addr     = (__u64)sec_buf;
 
         err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
         if (err < 0)
@@ -1430,27 +1421,29 @@ static int sec_send(int argc, char **argv)
 static int flush(int argc, char **argv)
 {
        struct nvme_passthru_cmd cmd;
-       unsigned int nsid = 0xffffffff;
-        int err, opt, long_index = 0;
+        int err;
 
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               { 0, 0, 0, 0}
+       struct config {
+               __u32 namespace_id;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .namespace_id = 0xffffffff,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "flush", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
        memset(&cmd, 0, sizeof(cmd));
        cmd.opcode = nvme_cmd_flush;
-       cmd.nsid = nsid;
+       cmd.nsid   = cfg.namespace_id;
 
        err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
        if (err < 0)
@@ -1466,64 +1459,74 @@ static int flush(int argc, char **argv)
 static int resv_acquire(int argc, char **argv)
 {
        struct nvme_passthru_cmd cmd;
-        int err, opt, long_index = 0;
-       unsigned int nsid = 0;
-       unsigned char rtype = 0, racqa = 0, iekey = 0;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"crkey", required_argument, 0, 'c'},
-               {"prkey", required_argument, 0, 'p'},
-               {"rtype", required_argument, 0, 't'},
-               {"racqa", required_argument, 0, 'a'},
-               {"iekey", no_argument, 0, 'i'},
-               { 0, 0, 0, 0}
+        int err;
+       __u64 payload[2];
+
+       struct config {
+               __u32 namespace_id;
+               __u64 crkey;
+               __u64 prkey;
+               __u8  rtype;
+               __u8  racqa;
+               __u8  iekey;
        };
-       __u64 prkey= 0, crkey = 0, payload[2];
-
-       while ((opt = getopt_long(argc, (char **)argv, "n:c:p:t:a:i", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               case 'c': get_long(optarg, &crkey); break;
-               case 'p': get_long(optarg, &prkey); break;
-               case 't': get_byte(optarg, &rtype); break;
-               case 'a': get_byte(optarg, &racqa); break;
-               case 'i': iekey = 1; break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0,
+               .crkey        = 0,
+               .prkey        = 0,
+               .rtype        = 0,
+               .racqa        = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"crkey",        "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"c",            "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"prkey",        "NUM",  CFG_LONG_SUFFIX, &defaults.prkey,        required_argument, NULL},
+               {"p",            "NUM",  CFG_LONG_SUFFIX, &defaults.prkey,        required_argument, NULL},
+               {"rtype",        "NUM",  CFG_POSITIVE,    &defaults.rtype,        required_argument, NULL},
+               {"t",            "NUM",  CFG_POSITIVE,    &defaults.rtype,        required_argument, NULL},
+               {"racqa",        "NUM",  CFG_POSITIVE,    &defaults.racqa,        required_argument, NULL},
+               {"a",            "NUM",  CFG_POSITIVE,    &defaults.racqa,        required_argument, NULL},
+               {"iekey",        "NUM",  CFG_POSITIVE,    &defaults.iekey,        no_argument,       NULL},
+               {"i",            "NUM",  CFG_POSITIVE,    &defaults.iekey,        no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "resv_acquire", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       if (!nsid) {
+       if (!cfg.namespace_id) {
                if (!S_ISBLK(nvme_stat.st_mode)) {
                        fprintf(stderr,
                                "%s: non-block device requires namespace-id param\n",
                                devicename);
                        exit(ENOTBLK);
                }
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        fprintf(stderr,
                                "%s: failed to return namespace id\n",
                                devicename);
                        return errno;
                }
        }
-       if (racqa > 7) {
-               fprintf(stderr, "invalid racqa:%d\n", racqa);
+       if (cfg.racqa > 7) {
+               fprintf(stderr, "invalid racqa:%d\n", cfg.racqa);
                return EINVAL;
        }
 
-       payload[0] = crkey;
-       payload[1] = prkey;
+       payload[0] = cfg.crkey;
+       payload[1] = cfg.prkey;
 
        memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_cmd_resv_acquire;
-        cmd.nsid = nsid;
-        cmd.cdw10 = rtype << 8 | iekey << 3 | racqa;
-
-        cmd.addr = (__u64)payload;
+        cmd.opcode   = nvme_cmd_resv_acquire;
+        cmd.nsid     = cfg.namespace_id;
+        cmd.cdw10    = cfg.rtype << 8 | cfg.iekey << 3 | cfg.racqa;
+        cmd.addr     = (__u64)payload;
         cmd.data_len = sizeof(payload);
 
         err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
@@ -1539,68 +1542,74 @@ static int resv_acquire(int argc, char **argv)
 static int resv_register(int argc, char **argv)
 {
        struct nvme_passthru_cmd cmd;
-        int err, opt, long_index = 0;
-       unsigned int nsid = 0;
-       unsigned char rrega = 0, iekey = 0, cptpl = 0;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"crkey", required_argument, 0, 'c'},
-               {"nrkey", required_argument, 0, 'k'},
-               {"rrega", required_argument, 0, 'r'},
-               {"cptpl", required_argument, 0, 'p'},
-               {"iekey", required_argument, 0, 'i'},
-               { 0, 0, 0, 0}
+        int err;
+       __u64 payload[2];
+
+       struct config {
+               __u32 namespace_id;
+               __u64 crkey;
+               __u64 nrkey;
+               __u8  rrega;
+               __u8  cptpl;
+               __u8  iekey;
        };
-       __u64 nrkey= 0, crkey = 0, payload[2];
-
-       while ((opt = getopt_long(argc, (char **)argv, "n:c:p:t:i:k:", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               case 'c': get_long(optarg, &crkey); break;
-               case 'k': get_long(optarg, &nrkey); break;
-               case 'r': get_byte(optarg, &rrega); break;
-               case 'p': get_byte(optarg, &cptpl); break;
-               case 'i': get_byte(optarg, &iekey); break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0,
+               .crkey        = 0,
+               .nrkey        = 0,
+               .rrega        = 0,
+               .cptpl        = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"crkey",        "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"c",            "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"nrkey",        "NUM",  CFG_LONG_SUFFIX, &defaults.nrkey,        required_argument, NULL},
+               {"k",            "NUM",  CFG_LONG_SUFFIX, &defaults.nrkey,        required_argument, NULL},
+               {"rrega",        "NUM",  CFG_POSITIVE,    &defaults.rrega,        required_argument, NULL},
+               {"r",            "NUM",  CFG_POSITIVE,    &defaults.rrega,        required_argument, NULL},
+               {"cptpl",        "NUM",  CFG_POSITIVE,    &defaults.cptpl,        required_argument, NULL},
+               {"p",            "NUM",  CFG_POSITIVE,    &defaults.cptpl,        required_argument, NULL},
+               {"iekey",        "NUM",  CFG_POSITIVE,    &defaults.iekey,        no_argument,       NULL},
+               {"i",            "NUM",  CFG_POSITIVE,    &defaults.iekey,        no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "resv_register", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       if (!nsid) {
+       if (!cfg.namespace_id) {
                if (!S_ISBLK(nvme_stat.st_mode)) {
                        fprintf(stderr,
                                "%s: non-block device requires namespace-id param\n",
                                devicename);
                        exit(ENOTBLK);
                }
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        fprintf(stderr,
                                "%s: failed to return namespace id\n",
                                devicename);
                        return errno;
                }
        }
-       if (iekey > 1) {
-               fprintf(stderr, "invalid iekey:%d\n", iekey);
-               return EINVAL;
-       }
-       if (cptpl > 3) {
-               fprintf(stderr, "invalid cptpl:%d\n", cptpl);
+       if (cfg.cptpl > 3) {
+               fprintf(stderr, "invalid cptpl:%d\n", cfg.cptpl);
                return EINVAL;
        }
 
-       payload[0] = crkey;
-       payload[1] = nrkey;
+       payload[0] = cfg.crkey;
+       payload[1] = cfg.nrkey;
 
        memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_cmd_resv_register;
-        cmd.nsid = nsid;
-       cmd.cdw10 = cptpl << 30 | iekey << 3 | rrega;
-
-        cmd.addr = (__u64)payload;
+        cmd.opcode   = nvme_cmd_resv_register;
+        cmd.nsid     = cfg.namespace_id;
+       cmd.cdw10    = cfg.cptpl << 30 | cfg.iekey << 3 | cfg.rrega;
+        cmd.addr     = (__u64)payload;
         cmd.data_len = sizeof(payload);
 
         err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
@@ -1616,64 +1625,72 @@ static int resv_register(int argc, char **argv)
 static int resv_release(int argc, char **argv)
 {
        struct nvme_passthru_cmd cmd;
-        int err, opt, long_index = 0;
-       unsigned int nsid = 0;
-       unsigned char rtype = 0, rrela = 0, iekey = 0;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"crkey", required_argument, 0, 'c'},
-               {"rtype", required_argument, 0, 't'},
-               {"rrela", required_argument, 0, 'a'},
-               {"iekey", required_argument, 0, 'i'},
-               { 0, 0, 0, 0}
+        int err;
+
+       struct config {
+               __u32 namespace_id;
+               __u64 crkey;
+               __u8  rtype;
+               __u8  rrela;
+               __u8  iekey;
        };
-       __u64 crkey = 0;
-
-       while ((opt = getopt_long(argc, (char **)argv, "n:c:p:t:a:i:", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               case 'c': get_long(optarg, &crkey); break;
-               case 't': get_byte(optarg, &rtype); break;
-               case 'a': get_byte(optarg, &rrela); break;
-               case 'i': get_byte(optarg, &iekey); break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       struct config cfg;
+
+       const struct config defaults = {
+               .namespace_id = 0,
+               .crkey        = 0,
+               .rtype        = 0,
+               .rrela        = 0,
+               .iekey        = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE,    &defaults.namespace_id, required_argument, NULL},
+               {"crkey",        "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"c",            "NUM",  CFG_LONG_SUFFIX, &defaults.crkey,        required_argument, NULL},
+               {"rtype",        "NUM",  CFG_POSITIVE,    &defaults.rtype,        required_argument, NULL},
+               {"t",            "NUM",  CFG_POSITIVE,    &defaults.rtype,        required_argument, NULL},
+               {"rrela",        "NUM",  CFG_POSITIVE,    &defaults.rrela,        required_argument, NULL},
+               {"a",            "NUM",  CFG_POSITIVE,    &defaults.rrela,        required_argument, NULL},
+               {"iekey",        "NUM",  CFG_POSITIVE,    &defaults.iekey,        required_argument, NULL},
+               {"i",            "NUM",  CFG_POSITIVE,    &defaults.iekey,        required_argument, NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "resv_release", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       if (!nsid) {
+       if (!cfg.namespace_id) {
                if (!S_ISBLK(nvme_stat.st_mode)) {
                        fprintf(stderr,
                                "%s: non-block device requires namespace-id param\n",
                                devicename);
                        exit(ENOTBLK);
                }
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        fprintf(stderr,
                                "%s: failed to return namespace id\n",
                                devicename);
                        return errno;
                }
        }
-       if (iekey > 1) {
-               fprintf(stderr, "invalid iekey:%d\n", iekey);
+       if (cfg.iekey > 1) {
+               fprintf(stderr, "invalid iekey:%d\n", cfg.iekey);
                return EINVAL;
        }
-       if (rrela > 7) {
-               fprintf(stderr, "invalid rrela:%d\n", rrela);
+       if (cfg.rrela > 7) {
+               fprintf(stderr, "invalid rrela:%d\n", cfg.rrela);
                return EINVAL;
        }
 
        memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_cmd_resv_release;
-        cmd.nsid = nsid;
-       cmd.cdw10 = rtype << 8 | iekey << 3 | rrela;
-
-        cmd.addr = (__u64)&crkey;
-        cmd.data_len = sizeof(crkey);
+        cmd.opcode   = nvme_cmd_resv_release;
+        cmd.nsid     = cfg.namespace_id;
+       cmd.cdw10    = cfg.rtype << 8 | cfg.iekey << 3 | cfg.rrela;
+        cmd.addr     = (__u64)&cfg.crkey;
+        cmd.data_len = sizeof(cfg.crkey);
 
         err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
         if (err < 0)
@@ -1688,58 +1705,63 @@ static int resv_release(int argc, char **argv)
 static int resv_report(int argc, char **argv)
 {
        struct nvme_passthru_cmd cmd;
-        int err, opt, long_index = 0, raw = 0;
-       unsigned int nsid = 0, numd = 0x1000 > 2;
+        int err;
        struct nvme_reservation_status *status;
-       static struct option opts[] = {
-               {"namespace-id", required_argument, 0, 'n'},
-               {"numd", required_argument, 0, 'd'},
-               {"raw-binary", no_argument, 0, 'b'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               __u32 namespace_id;
+               __u32 numd;
+               __u8  raw_binary;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "n:d:r", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'n': get_int(optarg, &nsid); break;
-               case 'd': get_int(optarg, &numd); break;
-               case 'r': raw = 0; break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .namespace_id = 0,
+               .numd         = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"numd",         "NUM",  CFG_POSITIVE, &defaults.numd,         required_argument, NULL},
+               {"d",            "NUM",  CFG_POSITIVE, &defaults.numd,         required_argument, NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "resv_report", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
 
-       if (!nsid) {
+       if (!cfg.namespace_id) {
                if (!S_ISBLK(nvme_stat.st_mode)) {
                        fprintf(stderr,
                                "%s: non-block device requires namespace-id param\n",
                                devicename);
                        exit(ENOTBLK);
                }
-               nsid = ioctl(fd, NVME_IOCTL_ID);
-               if (nsid <= 0) {
+               cfg.namespace_id = ioctl(fd, NVME_IOCTL_ID);
+               if (cfg.namespace_id <= 0) {
                        fprintf(stderr,
                                "%s: failed to return namespace id\n",
                                devicename);
                        return errno;
                }
        }
-       if (!numd || numd > (0x1000 >> 2))
-               numd = 0x1000 >> 2;
+       if (!cfg.numd || cfg.numd > (0x1000 >> 2))
+               cfg.numd = 0x1000 >> 2;
 
-       if (posix_memalign((void **)&status, getpagesize(), numd << 2)) {
-               fprintf(stderr, "No memory for resv report:%d\n", numd << 2);
+       if (posix_memalign((void **)&status, getpagesize(), cfg.numd << 2)) {
+               fprintf(stderr, "No memory for resv report:%d\n", cfg.numd << 2);
                return ENOMEM;
        }
 
        memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_cmd_resv_report;
-        cmd.nsid = nsid;
-        cmd.cdw10 = numd;
-
-        cmd.addr = (__u64)status;
-        cmd.data_len = numd << 2;
+        cmd.opcode   = nvme_cmd_resv_report;
+        cmd.nsid     = cfg.namespace_id;
+        cmd.cdw10    = cfg.numd;
+        cmd.addr     = (__u64)status;
+        cmd.data_len = cfg.numd << 2;
 
         err = ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
         if (err < 0)
@@ -1747,11 +1769,11 @@ static int resv_report(int argc, char **argv)
         else if (err != 0)
                 fprintf(stderr, "NVME IO command error:%04x\n", err);
         else {
-               if (!raw) {
+               if (!cfg.raw_binary) {
                        printf("NVME Reservation Report success\n");
                        show_nvme_resv_report(status);
                } else
-                       d_raw((unsigned char *)status, numd << 2);
+                       d_raw((unsigned char *)status, cfg.numd << 2);
        }
        return 0;
 }
@@ -1761,94 +1783,122 @@ static int submit_io(int opcode, char *command, int argc, char **argv)
        struct nvme_user_io io;
        struct timeval start_time, end_time;
        void *buffer, *mbuffer = NULL;
-        int err, opt, dfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO,
-         show = 0, dry_run = 0, long_index = 0, latency = 0;
-       unsigned int data_size = 0, metadata_size = 0;
-       __u8 prinfo = 0;
-
-       /* XXX: metadata ? */
-       static struct option opts[] = {
-               {"start-block", required_argument, 0, 's'},
-               {"block-count", required_argument, 0, 'c'},
-               {"data-size", required_argument, 0, 'z'},
-               {"metadata-size", required_argument, 0, 'y'},
-               {"ref-tag", required_argument, 0, 'r'},
-               {"data", required_argument, 0, 'd'},
-               {"prinfo", required_argument, 0, 'p'},
-               {"app-tag-mask", required_argument, 0, 'm'},
-               {"app-tag", required_argument, 0, 'a'},
-               {"limited-retry", no_argument, 0, 'l'},
-               {"force-unit-access", no_argument, 0, 'f'},
-               {"show-command", no_argument, 0, 'v'},
-               {"dry-run", no_argument, 0, 'w'},
-               {"latency", no_argument, 0, 't'},
-               { 0, 0, 0, 0}
+        int err, dfd = opcode & 1 ? STDIN_FILENO : STDOUT_FILENO;
+
+       struct config {
+               __u64 start_block;
+               __u16 block_count;
+               __u32 data_size;
+               __u32 metadata_size;
+               __u32 ref_tag;
+               char  *data;
+               __u8  prinfo;
+               __u8  app_tag_mask;
+               __u32 app_tag;
+               __u8  limited_retry;
+               __u8  force_unit_access;
+               __u8  show;
+               __u8  dry_run;
+               __u8  latency;
+       };
+       struct config cfg;
+
+       const struct config defaults = {
+               .start_block     = 0,
+               .block_count     = 0,
+               .data_size       = 0,
+               .metadata_size   = 0,
+               .ref_tag         = 0,
+               .data            = "",
+               .prinfo          = 0,
+               .app_tag_mask    = 0,
+               .app_tag         = 0,
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"s",                 "NUM",  CFG_LONG_SUFFIX, &defaults.start_block,       required_argument, NULL},
+               {"start-block",       "NUM",  CFG_LONG_SUFFIX, &defaults.start_block,       required_argument, NULL},
+               {"c",                 "NUM",  CFG_LONG_SUFFIX, &defaults.block_count,       required_argument, NULL},
+               {"block-count",       "NUM",  CFG_LONG_SUFFIX, &defaults.block_count,       required_argument, NULL},
+               {"z",                 "NUM",  CFG_LONG_SUFFIX, &defaults.data_size,         required_argument, NULL},
+               {"data-size",         "NUM",  CFG_LONG_SUFFIX, &defaults.data_size,         required_argument, NULL},
+               {"y",                 "NUM",  CFG_POSITIVE,    &defaults.metadata_size,     required_argument, NULL},
+               {"metadata-size",     "NUM",  CFG_POSITIVE,    &defaults.metadata_size,     required_argument, NULL},
+               {"r",                 "NUM",  CFG_POSITIVE,    &defaults.ref_tag,           required_argument, NULL},
+               {"ref-tag",           "NUM",  CFG_POSITIVE,    &defaults.ref_tag,           required_argument, NULL},
+               {"d",                 "FILE", CFG_STRING,      &defaults.data,              required_argument, NULL},
+               {"data",              "FILE", CFG_STRING,      &defaults.data,              required_argument, NULL},
+               {"p",                 "NUM",  CFG_POSITIVE,    &defaults.prinfo,            required_argument, NULL},
+               {"prinfo",            "NUM",  CFG_POSITIVE,    &defaults.prinfo,            required_argument, NULL},
+               {"t",                 "NUM",  CFG_POSITIVE,    &defaults.prinfo,            required_argument, NULL},
+               {"app-tag",           "NUM",  CFG_POSITIVE,    &defaults.prinfo,            required_argument, NULL},
+               {"m",                 "NUM",  CFG_POSITIVE,    &defaults.app_tag_mask,      required_argument, NULL},
+               {"app-tag-mask",      "NUM",  CFG_POSITIVE,    &defaults.app_tag_mask,      required_argument, NULL},
+               {"a",                 "NUM",  CFG_POSITIVE,    &defaults.app_tag,           required_argument, NULL},
+               {"app-tag",           "NUM",  CFG_POSITIVE,    &defaults.app_tag,           required_argument, NULL},
+               {"l",                 "",     CFG_NONE,        &defaults.limited_retry,     no_argument,       NULL},
+               {"limited-retry",     "",     CFG_NONE,        &defaults.limited_retry,     no_argument,       NULL},
+               {"f",                 "",     CFG_NONE,        &defaults.force_unit_access, no_argument,       NULL},
+               {"force-unit-access", "",     CFG_NONE,        &defaults.force_unit_access, no_argument,       NULL},
+               {"v",                 "",     CFG_NONE,        &defaults.show,              no_argument,       NULL},
+               {"show-command",      "",     CFG_NONE,        &defaults.show,              no_argument,       NULL},
+               {"w",                 "",     CFG_NONE,        &defaults.dry_run,           no_argument,       NULL},
+               {"dry-run",           "",     CFG_NONE,        &defaults.dry_run,           no_argument,       NULL},
+               {"t",                 "",     CFG_NONE,        &defaults.latency,           no_argument,       NULL},
+               {"latency",           "",     CFG_NONE,        &defaults.latency,           no_argument,       NULL},
+               {0}
        };
 
+       argconfig_parse(argc, argv, command, command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
        memset(&io, 0, sizeof(io));
-       while ((opt = getopt_long(argc, (char **)argv, "p:s:c:z:y:r:d:m:a:lfvwt", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 's': get_long(optarg, &io.slba); break;
-               case 'c': get_short(optarg, &io.nblocks); break;
-               case 'z': get_int(optarg, &data_size); break;
-               case 'y': get_int(optarg, &metadata_size); break;
-               case 'r': get_int(optarg, &io.reftag); break;
-               case 'm': get_short(optarg, &io.appmask); break;
-               case 'a': get_short(optarg, &io.apptag); break;
-               case 'p':
-                       get_byte(optarg, &prinfo);
-                       if (prinfo > 0xf)
-                               return EINVAL;
-                       io.control |= (prinfo << 10);
-                       break;
-               case 'l':
-                       io.control |= NVME_RW_LR;
-                       break;
-               case 'f':
-                       io.control |= NVME_RW_FUA;
-                       break;
-               case 'd': 
-                       if (opcode & 1)
-                         dfd = open(optarg, O_RDONLY);           
-                       else
-                         dfd = open(optarg, O_WRONLY | O_CREAT, 
-                                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH);
-                       if (dfd < 0) {
-                               perror(optarg);
-                               return EINVAL;
-                       }
-                       break;
-               case 'v': show = 1; break;
-               case 'w': dry_run = 1; break;
-               case 't': latency = 1; break;
-               default:
+
+       io.slba    = cfg.start_block;
+       io.nblocks = cfg.block_count;
+       io.reftag  = cfg.ref_tag;
+       io.appmask = cfg.app_tag_mask;
+       io.apptag  = cfg.app_tag;
+       if (cfg.prinfo > 0xf)
+               return EINVAL;
+       io.control |= (cfg.prinfo << 10);
+       if (cfg.limited_retry)
+               io.control |= NVME_RW_LR;
+       if (cfg.force_unit_access)
+               io.control |= NVME_RW_FUA;
+       if (strlen(cfg.data)){
+               if (opcode & 1)
+                       dfd = open(cfg.data, O_RDONLY);           
+               else
+                       dfd = open(cfg.data, O_WRONLY | O_CREAT, 
+                                  S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP| S_IROTH);
+               if (dfd < 0) {
+                       perror(cfg.data);
                        return EINVAL;
                }
-       };
-       get_dev(optind, argc, argv);
+       }
+       get_dev(1, argc, argv);
 
-       if (!data_size) {
+       if (!cfg.data_size)     {
                fprintf(stderr, "data size not provided\n");
                return EINVAL;
        }
-       buffer = malloc(data_size);
-       if (metadata_size)
-               mbuffer = malloc(metadata_size);
-       if ((opcode & 1) && read(dfd, (void *)buffer, data_size) < 0) {
+       buffer = malloc(cfg.data_size);
+       if (cfg.metadata_size)
+               mbuffer = malloc(cfg.metadata_size);
+       if ((opcode & 1) && read(dfd, (void *)buffer, cfg.data_size) < 0) {
                fprintf(stderr, "failed to read data buffer from input file\n");
                return EINVAL;
        }
-       if ((opcode & 1) && metadata_size && read(dfd, (void *)mbuffer, metadata_size) < 0) {
+       if ((opcode & 1) && cfg.metadata_size && read(dfd, (void *)mbuffer, cfg.metadata_size) < 0) {
                fprintf(stderr, "failed to read meta-data buffer from input file\n");
                return EINVAL;
        }
 
         io.opcode = opcode;
-       io.addr = (__u64)buffer;
-       if (metadata_size)
+       io.addr   = (__u64)buffer;
+       if (cfg.metadata_size)
                io.metadata = (__u64)mbuffer;
-       if (show) {
+       if (cfg.show) {
                printf("opcode       : %02x\n" , io.opcode);
                printf("flags        : %02x\n" , io.flags);
                printf("control      : %04x\n" , io.control);
@@ -1861,14 +1911,14 @@ static int submit_io(int opcode, char *command, int argc, char **argv)
                printf("reftag       : %08x\n" , io.reftag);
                printf("apptag       : %04x\n" , io.apptag);
                printf("appmask      : %04x\n" , io.appmask);
-               if (dry_run)
+               if (cfg.dry_run)
                  goto free_and_return;
        }
 
        gettimeofday(&start_time, NULL);
        err = ioctl(fd, NVME_IOCTL_SUBMIT_IO, &io);
        gettimeofday(&end_time, NULL);
-       if (latency)
+       if (cfg.latency)
          fprintf(stdout, " latency: %s: %llu us\n", 
                  command, elapsed_utime(start_time, end_time));
        if (err < 0)
@@ -1876,7 +1926,7 @@ static int submit_io(int opcode, char *command, int argc, char **argv)
        else if (err)
                printf("%s:%s(%04x)\n", command, nvme_status_to_string(err), err);
        else {
-               if (!(opcode & 1) && write(dfd, (void *)buffer, data_size) < 0) {
+               if (!(opcode & 1) && write(dfd, (void *)buffer, cfg.data_size) < 0) {
                        fprintf(stderr, "failed to write buffer to output file\n");
                        return EINVAL;
                } else
@@ -1884,7 +1934,7 @@ static int submit_io(int opcode, char *command, int argc, char **argv)
        }
  free_and_return:
        free(buffer);
-       if (metadata_size)
+       if (cfg.metadata_size)
                free(mbuffer);
        return 0;
 }
@@ -1907,60 +1957,55 @@ static int write_cmd(int argc, char **argv)
 static int sec_recv(int argc, char **argv)
 {
        struct nvme_admin_cmd cmd;
-        int err, opt, long_index = 0, raw = 0;
+        int err;
        void *sec_buf = NULL;
-       unsigned int al = 0;
-       unsigned short spsp = 0;
-       unsigned char secp = 0;
-       unsigned int sec_size = 0;
-       static struct option opts[] = {
-               {"size", required_argument, 0, 'x'},
-               {"file", required_argument, 0, 'f'},
-               {"secp", required_argument, 0, 'p'},
-               {"spsp", required_argument, 0, 's'},
-               {"al", required_argument, 0, 't'},
-               {"raw-binary", no_argument, 0, 'b'},
-               { 0, 0, 0, 0}
+
+       struct config {
+               __u32 size;
+               __u8  secp;
+               __u16 spsp;
+               __u32 al;
+               __u8  raw_binary;
        };
+       struct config cfg;
 
-       while ((opt = getopt_long(argc, (char **)argv, "f:p:s:t:", opts,
-                                                       &long_index)) != -1) {
-               switch(opt) {
-               case 'x':
-                       get_int(optarg, &sec_size);
-                       break;
-               case 'p':
-                       get_short(optarg, &spsp);
-                       break;
-               case 's':
-                       get_byte(optarg, &secp);
-                       break;
-               case 't':
-                       get_int(optarg, &al);
-                       break;
-               case 'b':
-                       raw = 1;
-                       break;
-               default:
-                       return EINVAL;
-               }
-       }
-       get_dev(optind, argc, argv);
+       const struct config defaults = {
+               .size = 0,
+               .secp = 0,
+               .spsp = 0,
+               .al   = 0,
+       };
 
-       if (sec_size) {
-               if (posix_memalign(&sec_buf, getpagesize(), sec_size)) {
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"size",       "NUM",  CFG_POSITIVE, &defaults.size,       required_argument, NULL},
+               {"x",          "NUM",  CFG_POSITIVE, &defaults.size,       required_argument, NULL},
+               {"secp",       "NUM",  CFG_POSITIVE, &defaults.secp,       required_argument, NULL},
+               {"p",          "NUM",  CFG_POSITIVE, &defaults.secp,       required_argument, NULL},
+               {"spsp",       "NUM",  CFG_POSITIVE, &defaults.spsp,       required_argument, NULL},
+               {"s",          "NUM",  CFG_POSITIVE, &defaults.spsp,       required_argument, NULL},
+               {"al",         "NUM",  CFG_POSITIVE, &defaults.al,         required_argument, NULL},
+               {"t",          "NUM",  CFG_POSITIVE, &defaults.al,         required_argument, NULL},
+               {"raw-binary", "NUM",  CFG_POSITIVE, &defaults.raw_binary, no_argument,       NULL},
+               {"b",          "NUM",  CFG_POSITIVE, &defaults.raw_binary, no_argument,       NULL},
+               {0}
+       };
+       argconfig_parse(argc, argv, "sec_recv", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       get_dev(1, argc, argv);
+
+       if (cfg.size) {
+               if (posix_memalign(&sec_buf, getpagesize(), cfg.size)) {
                        fprintf(stderr, "No memory for security size:%d\n",
-                                                               sec_size);
+                                                               cfg.size);
                        return ENOMEM;
                }
        }
-
         memset(&cmd, 0, sizeof(cmd));
-        cmd.opcode = nvme_admin_security_recv;
-        cmd.cdw10 = secp << 24 | spsp << 8;
-        cmd.cdw11 al;
-        cmd.data_len = sec_size;
-        cmd.addr = (__u64)sec_buf;
+        cmd.opcode   = nvme_admin_security_recv;
+        cmd.cdw10    = cfg.secp << 24 | cfg.spsp << 8;
+        cmd.cdw11    = cfg.al;
+        cmd.data_len = cfg.size;
+        cmd.addr     = (__u64)sec_buf;
 
         err = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &cmd);
         if (err < 0)
@@ -1969,102 +2014,159 @@ static int sec_recv(int argc, char **argv)
                 fprintf(stderr, "NVME Security Receivce Command Error:%d\n",
                                                                        err);
        else {
-               if (!raw) {
+               if (!cfg.raw_binary) {
                        printf("NVME Security Receivce Command Success:%d\n",
                                                        cmd.result);
-                       d(sec_buf, sec_size, 16, 1);
-               } else if (sec_size)
-                       d_raw((unsigned char *)&sec_buf, sec_size);
+                       d(sec_buf, cfg.size, 16, 1);
+               } else if (cfg.size)
+                       d_raw((unsigned char *)&sec_buf, cfg.size);
        }
         return err;
 }
 
 static int nvme_passthru(int argc, char **argv, int ioctl_cmd)
 {
-       int r = 0, w = 0;
-       int opt, err, raw = 0, show = 0, dry_run = 0, long_index = 0, wfd = STDIN_FILENO;
+       int err, wfd = STDIN_FILENO;
        struct nvme_passthru_cmd cmd;
-       static struct option opts[] = {
-               {"opcode", required_argument, 0, 'o'},
-               {"flags", required_argument, 0, 'f'},
-               {"rsvd", required_argument, 0, 'R'},
-               {"namespace-id", required_argument, 0, 'n'},
-               {"data-len", required_argument, 0, 'l'},
-               {"metadata-len", required_argument, 0, 'm'},
-               {"timeout", required_argument, 0, 't'},
-               {"cdw2", required_argument, 0, '2'},
-               {"cdw3", required_argument, 0, '3'},
-               {"cdw10", required_argument, 0, '4'},
-               {"cdw11", required_argument, 0, '5'},
-               {"cdw12", required_argument, 0, '6'},
-               {"cdw13", required_argument, 0, '7'},
-               {"cdw14", required_argument, 0, '8'},
-               {"cdw15", required_argument, 0, '9'},
-               {"raw-binary", no_argument, 0, 'b'},
-               {"show-command", no_argument, 0, 's'},
-               {"dry-run", no_argument, 0, 'd'},
-               {"read", no_argument, 0, 'r'},
-               {"write", no_argument, 0, 'w'},
-               {"input-file", no_argument, 0, 'i'},
-               {0, 0, 0, 0}
+
+       struct config {
+               __u8  opcode;
+               __u8  flags;
+               __u16 rsvd;
+               __u32 namespace_id;
+               __u32 data_len;
+               __u32 metadata_len;
+               __u32 timeout;
+               __u32 cdw2;
+               __u32 cdw3;
+               __u32 cdw10;
+               __u32 cdw11;
+               __u32 cdw12;
+               __u32 cdw13;
+               __u32 cdw14;
+               __u32 cdw15;
+               char  *input_file;
+               __u8  raw_binary;
+               __u8  show_command;
+               __u8  dry_run;  
+               __u8  read;     
+               __u8  write;    
+       };
+       struct config cfg;
+
+       const struct config defaults = {
+               .opcode       = 0,
+               .flags        = 0,
+               .rsvd         = 0,
+               .namespace_id = 0,
+               .data_len     = 0,
+               .metadata_len = 0,
+               .timeout      = 0,
+               .cdw2         = 0,
+               .cdw3         = 0,
+               .cdw10        = 0,
+               .cdw11        = 0,
+               .cdw12        = 0,
+               .cdw13        = 0,
+               .cdw14        = 0,
+               .cdw15        = 0,
+               .input_file   = "",
+       };
+
+       const struct argconfig_commandline_options command_line_options[] = {
+               {"opcode",       "NUM",  CFG_POSITIVE, &defaults.opcode,       required_argument, NULL},
+               {"o",            "NUM",  CFG_POSITIVE, &defaults.opcode,       required_argument, NULL},
+               {"flags",        "NUM",  CFG_POSITIVE, &defaults.flags,        required_argument, NULL},
+               {"f",            "NUM",  CFG_POSITIVE, &defaults.flags,        required_argument, NULL},
+               {"rsvd",         "NUM",  CFG_POSITIVE, &defaults.rsvd,         required_argument, NULL},
+               {"R",            "NUM",  CFG_POSITIVE, &defaults.rsvd,         required_argument, NULL},
+               {"namespace-id", "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"n",            "NUM",  CFG_POSITIVE, &defaults.namespace_id, required_argument, NULL},
+               {"data-len",     "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {"l",            "NUM",  CFG_POSITIVE, &defaults.data_len,     required_argument, NULL},
+               {"metadata-len", "NUM",  CFG_POSITIVE, &defaults.metadata_len, required_argument, NULL},
+               {"m",            "NUM",  CFG_POSITIVE, &defaults.metadata_len, required_argument, NULL},
+               {"timeout",      "NUM",  CFG_POSITIVE, &defaults.timeout,      required_argument, NULL},
+               {"t",            "NUM",  CFG_POSITIVE, &defaults.timeout,      required_argument, NULL},
+               {"cdw2",         "NUM",  CFG_POSITIVE, &defaults.cdw2,         required_argument, NULL},
+               {"2",            "NUM",  CFG_POSITIVE, &defaults.cdw2,         required_argument, NULL},
+               {"cdw3",         "NUM",  CFG_POSITIVE, &defaults.cdw3,         required_argument, NULL},
+               {"3",            "NUM",  CFG_POSITIVE, &defaults.cdw3,         required_argument, NULL},
+               {"cdw10",        "NUM",  CFG_POSITIVE, &defaults.cdw10,        required_argument, NULL},
+               {"4",            "NUM",  CFG_POSITIVE, &defaults.cdw10,        required_argument, NULL},
+               {"cdw11",        "NUM",  CFG_POSITIVE, &defaults.cdw11,        required_argument, NULL},
+               {"5",            "NUM",  CFG_POSITIVE, &defaults.cdw11,        required_argument, NULL},
+               {"cdw12",        "NUM",  CFG_POSITIVE, &defaults.cdw12,        required_argument, NULL},
+               {"6",            "NUM",  CFG_POSITIVE, &defaults.cdw12,        required_argument, NULL},
+               {"cdw13",        "NUM",  CFG_POSITIVE, &defaults.cdw13,        required_argument, NULL},
+               {"7",            "NUM",  CFG_POSITIVE, &defaults.cdw13,        required_argument, NULL},
+               {"cdw14",        "NUM",  CFG_POSITIVE, &defaults.cdw14,        required_argument, NULL},
+               {"8",            "NUM",  CFG_POSITIVE, &defaults.cdw14,        required_argument, NULL},
+               {"cdw15",        "NUM",  CFG_POSITIVE, &defaults.cdw15,        required_argument, NULL},
+               {"9",            "NUM",  CFG_POSITIVE, &defaults.cdw15,        required_argument, NULL},
+               {"input-file",   "FILE", CFG_STRING,   &defaults.input_file,   no_argument,       NULL},
+               {"i",            "FILE", CFG_STRING,   &defaults.input_file,   no_argument,       NULL},
+               {"raw-binary",   "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"b",            "NUM",  CFG_POSITIVE, &defaults.raw_binary,   no_argument,       NULL},
+               {"show-command", "NUM",  CFG_POSITIVE, &defaults.show_command, no_argument,       NULL},
+               {"s",            "NUM",  CFG_POSITIVE, &defaults.show_command, no_argument,       NULL},
+               {"dry-run",      "NUM",  CFG_POSITIVE, &defaults.dry_run,      no_argument,       NULL},
+               {"d",            "NUM",  CFG_POSITIVE, &defaults.dry_run,      no_argument,       NULL},
+               {"read",         "NUM",  CFG_POSITIVE, &defaults.read,         no_argument,       NULL},
+               {"r",            "NUM",  CFG_POSITIVE, &defaults.read,         no_argument,       NULL},
+               {"write",        "NUM",  CFG_POSITIVE, &defaults.write,        no_argument,       NULL},
+               {"w",            "NUM",  CFG_POSITIVE, &defaults.write,        no_argument,       NULL},
+               {0}
        };
 
        memset(&cmd, 0, sizeof(cmd));
-       while ((opt = getopt_long(argc, (char **)argv, "o:n:f:l:R:m:t:i:bsdrw", opts,
-                                                       &long_index)) != -1) {
-               switch (opt) {
-               case '2': get_int(optarg, &cmd.cdw2); break;
-               case '3': get_int(optarg, &cmd.cdw3); break;
-               case '4': get_int(optarg, &cmd.cdw10); break;
-               case '5': get_int(optarg, &cmd.cdw11); break;
-               case '6': get_int(optarg, &cmd.cdw12); break;
-               case '7': get_int(optarg, &cmd.cdw13); break;
-               case '8': get_int(optarg, &cmd.cdw14); break;
-               case '9': get_int(optarg, &cmd.cdw15); break;
-               case 'o': get_byte(optarg, &cmd.opcode); break;
-               case 'f': get_byte(optarg, &cmd.flags); break;
-               case 'R': get_short(optarg, &cmd.rsvd1); break;
-               case 'n': get_int(optarg, &cmd.nsid); break;
-               case 'l': get_int(optarg, &cmd.data_len); break;
-               case 'm': get_int(optarg, &cmd.metadata_len); break;
-               case 't': get_int(optarg, &cmd.timeout_ms); break;
-               case 'b': raw = 1; break;
-               case 's': show = 1; break;
-               case 'd': dry_run = 1; break;
-               case 'r': r = 1; break;
-               case 'w': w = 1; break;
-               case 'i':
-                       wfd = open(optarg, O_RDONLY);
-                       if (wfd < 0) {
-                               perror(optarg);
-                               return EINVAL;
-                       }
-                       break;
-               default:
+       argconfig_parse(argc, argv, "nvme_passthrou", command_line_options,
+                       &defaults, &cfg, sizeof(cfg));
+       
+       cmd.cdw2         = cfg.cdw13;
+       cmd.cdw3         = cfg.cdw13;
+       cmd.cdw10        = cfg.cdw13;
+       cmd.cdw11        = cfg.cdw13;
+       cmd.cdw12        = cfg.cdw13;
+       cmd.cdw13        = cfg.cdw13;
+       cmd.cdw14        = cfg.cdw14;
+       cmd.cdw15        = cfg.cdw15;
+       cmd.opcode       = cfg.opcode;
+       cmd.flags        = cfg.flags;
+       cmd.rsvd1        = cfg.rsvd;
+       cmd.nsid         = cfg.namespace_id;
+       cmd.data_len     = cfg.data_len;
+       cmd.metadata_len = cfg.metadata_len;
+       cmd.timeout_ms   = cfg.timeout;
+       if (strlen(cfg.input_file)){
+               wfd = open(cfg.input_file, O_RDONLY, 
+                          S_IRUSR | S_IRGRP | S_IROTH);
+               if (wfd < 0) {
+                       perror(cfg.input_file);
                        return EINVAL;
                }
        }
-       get_dev(optind, argc, argv);
+       get_dev(1, argc, argv);
        if (cmd.metadata_len)
                cmd.metadata = (__u64)malloc(cmd.metadata_len);
        if (cmd.data_len) {
                cmd.addr = (__u64)malloc(cmd.data_len);
-               if (!r && !w) {
+               if (!cfg.read && !cfg.write) {
                        fprintf(stderr, "data direction not given\n");
                        return EINVAL;
                }
-               if (r && w) {
+               if (cfg.read && cfg.write) {
                        fprintf(stderr, "command can't be both read and write\n");
                        return EINVAL;
                }
-               if (w) {
+               if (cfg.write) {
                        if (read(wfd, (void *)cmd.addr, cmd.data_len) < 0) {
                                fprintf(stderr, "failed to read write buffer\n");
                                return EINVAL;
                        }
                }
        }
-       if (show) {
+       if (cfg.show_command) {
                printf("opcode       : %02x\n", cmd.opcode);
                printf("flags        : %02x\n", cmd.flags);
                printf("rsvd1        : %04x\n", cmd.rsvd1);
@@ -2082,17 +2184,17 @@ static int nvme_passthru(int argc, char **argv, int ioctl_cmd)
                printf("cdw14        : %08x\n", cmd.cdw14);
                printf("cdw15        : %08x\n", cmd.cdw15);
                printf("timeout_ms   : %08x\n", cmd.timeout_ms);
-               if (dry_run)
+               if (cfg.dry_run)
                  return 0;
        }
        err = ioctl(fd, ioctl_cmd, &cmd);
        if (err >= 0) {
-               if (!raw) {
+               if (!cfg.raw_binary) {
                        printf("NVMe Status:%s Command Result:%08x\n",
                                nvme_status_to_string(err), cmd.result);
-                       if (cmd.addr && r && !err)
+                       if (cmd.addr && cfg.read && !err)
                                d((unsigned char *)cmd.addr, cmd.data_len, 16, 1);
-               } else if (!err && cmd.addr && r)
+               } else if (!err && cmd.addr && cfg.read)
                        d_raw((unsigned char *)cmd.addr, cmd.data_len);
        } else
                perror("ioctl");
diff --git a/regress b/regress
index 99c6a5c1bc51624fdbd298162d32c2d8fa234c0a..01e339912c9b83a50b130c15fb5dc388b6d0df3c 100755 (executable)
--- a/regress
+++ b/regress
@@ -26,7 +26,7 @@ LIST=false
 RAND_BASE=temp.rand
 RAND_WFILE=${RAND_BASE}.write
 RAND_RFILE=${RAND_BASE}.read
-RAND_SIZE=512
+RAND_SIZE=4k
 
 green=$(tput bold)$(tput setaf 2)
 red=$(tput bold)$(tput setaf 1)
similarity index 100%
rename from latency
rename to scripts/latency
diff --git a/src/argconfig.c b/src/argconfig.c
new file mode 100644 (file)
index 0000000..937bc53
--- /dev/null
@@ -0,0 +1,771 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2014 PMC-Sierra, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you
+// may not use this file except in compliance with the License. You may
+// obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+//
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+//
+//   Author: Logan Gunthorpe
+//
+//   Date:   Oct 23 2014
+//
+//   Description:
+//     Functions for parsing command line options.
+//
+////////////////////////////////////////////////////////////////////////
+
+#include "argconfig.h"
+#include "suffix.h"
+
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+
+#define MAX_HELP_FUNC 20
+static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = {NULL};
+
+char END_DEFAULT[] = "__end_default__";
+
+static int print_word_wrapped(const char *s, int indent, int start)
+{
+    const int width = 76;
+    const char *c;
+    int next_space = -1;
+    int last_line = indent;
+
+    for (c = s; *c != 0; c++) {
+        if (*c == ' ' || next_space < 0) {
+            next_space = 0;
+            for (const char *t = c+1; *t != 0 && *t != ' '; t++)
+                next_space++;
+            if ( ((int)(c-s)+start+next_space) > (last_line-indent+width)) {
+                last_line = (int) (c-s) + start;
+
+                putchar('\n');
+                for (int i = 0; i < indent; i++)
+                    putchar(' ');
+
+                start = indent;
+                continue;
+            }
+        }
+
+        putchar(*c);
+    }
+
+    return (int) (c - s) + start - last_line + indent;
+}
+
+const char *append_usage_str = "";
+
+void argconfig_append_usage(const char *str)
+{
+    append_usage_str = str;
+}
+
+void argconfig_print_help(char *command, const char *program_desc,
+                          const struct argconfig_commandline_options * options)
+{
+    const struct argconfig_commandline_options *s;
+    const int bufsize = 120;
+    char buf[bufsize];
+    int  last_line, nodefault;
+
+    printf("Usage: %s [OPTIONS] %s\n\n", command, append_usage_str);
+    print_word_wrapped(program_desc, 0, 0);
+    printf("\n\nOptions:\n");
+
+    buf[0] = ' ';
+    buf[1] = ' ';
+    buf[2] = 0;
+
+    for (s = options; s->option != 0; s++) {
+        if (s->option[0] == '=') {
+            const char *c = s->option;
+            while (*c == '=') c++;
+            printf("\n%s\n", c);
+            continue;
+        }
+
+        strcat(buf, "-");
+        strcat(buf, s->option);
+        strcat(buf, " ");
+        strcat(buf, s->meta);
+
+        if (s->help == NULL) {
+            strcat(buf, ", ");
+            continue;
+        }
+
+        printf("%-30s", buf);
+        if (strlen(buf) > 29)
+            printf("%-31s", "\n");
+
+        last_line = print_word_wrapped(s->help, 30, 30);
+
+        nodefault = 0;
+        if (s->config_type == CFG_STRING) {
+            if (*((char **) s->default_value)) {
+                sprintf(&buf[3], " - default: '%s'", *((char **) s->default_value));
+                nodefault = strlen(*((char **) s->default_value)) == 0;
+            } else {
+                nodefault = 1;
+            }
+        } else if (s->config_type == CFG_INT || s->config_type == CFG_POSITIVE){
+            sprintf(&buf[3], " - default: %d", *((int *) s->default_value));
+        } else if (s->config_type == CFG_LONG){
+            sprintf(&buf[3], " - default: %ld", *((long *) s->default_value));
+        } else if (s->config_type == CFG_LONG_SUFFIX){
+            long long val = *((long *) s->default_value);
+            const char *s = suffix_binary_get(&val);
+            sprintf(&buf[3], " - default: %lld%s", val, s);
+        } else if (s->config_type == CFG_SIZE){
+            sprintf(&buf[3], " - default: %zd", *((size_t *) s->default_value));
+        } else if (s->config_type == CFG_DOUBLE){
+            sprintf(&buf[3], " - default: %.2f", *((double *) s->default_value));
+        } else {
+            sprintf(&buf[3], " ");
+        }
+
+
+        if (!nodefault && s->config_type != CFG_NONE)
+            print_word_wrapped(&buf[3], 30, last_line);
+
+        putchar('\n');
+
+        buf[2] = 0;
+    }
+
+    for (int i = 0; i < MAX_HELP_FUNC; i++) {
+        if (help_funcs[i] == NULL) break;
+        putchar('\n');
+        help_funcs[i]();
+    }
+
+    putchar('\n');
+}
+
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+                    const struct argconfig_commandline_options *options,
+                    const void *config_default, void *config_out,
+                    size_t config_size)
+{
+    int c;
+    int option_index = 0, short_index = 0;
+    int options_count = 0;
+    struct option *long_opts;
+    char * short_opts;
+    const struct argconfig_commandline_options *s;
+    void *value_addr;
+
+    errno = 0;
+
+    memcpy(config_out, config_default, config_size);
+
+    for (s = options; s->option != 0; s++)
+        options_count++;
+
+    long_opts = malloc(sizeof(struct option)* (options_count + 1));
+    short_opts = malloc(sizeof(*short_opts) * (options_count*2 + 2));
+    short_opts[short_index++] = '-';
+
+    if (long_opts == NULL) {
+        fprintf(stderr,  "Unable to allocate memory!\n");
+        exit(1);
+    }
+
+    for (s = options; s->option != 0; s++) {
+        if (strlen(s->option) == 1) {
+            short_opts[short_index++] = s->option[0];
+            if (s->argument_type == required_argument) {
+                short_opts[short_index++] = ':';
+            }
+        }
+
+        long_opts[option_index].name    = s->option;
+        long_opts[option_index].has_arg = s->argument_type;
+        if (s->argument_type == no_argument &&
+            s->default_value != NULL)
+        {
+            value_addr = (void *) ((char *) s->default_value -
+                                   (char *) config_default +
+                                   (char *) config_out);
+            long_opts[option_index].flag    = value_addr;
+            long_opts[option_index].val     = 1;
+        } else {
+            long_opts[option_index].flag    = NULL;
+            long_opts[option_index].val     = 0;
+        }
+        option_index++;
+    }
+    long_opts[option_index].name = NULL;
+    long_opts[option_index].flag = NULL;
+    long_opts[option_index].val  = 0;
+    short_opts[short_index] = 0;
+
+    int non_opt_args = 0;
+
+    while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
+                                 &option_index)) != -1)
+    {
+        if (c == '?' || c == 'h' || c == ':' ||
+            (c == 0 &&
+             (!strcmp(long_opts[option_index].name, "h") ||
+              !strcmp(long_opts[option_index].name, "help") ||
+              !strcmp(long_opts[option_index].name, "-help"))))
+        {
+            argconfig_print_help(argv[0], program_desc, options);
+            exit(1);
+        } else if (c == 1) {
+            argv[1+non_opt_args] = optarg;
+            non_opt_args++;
+            continue;
+        } else if (c){
+            for (option_index = 0; options[option_index].option[0] != c ||
+                 options[option_index].option[1] != 0; option_index++);
+            if (long_opts[option_index].flag != NULL)
+                *long_opts[option_index].flag = 1;
+        }
+
+        s = &options[option_index];
+        while(s->default_value == NULL) s++;
+        value_addr = (void *) ((char *) s->default_value -
+                               (char *) config_default +
+                               (char *) config_out);
+
+
+        if (s->config_type == CFG_STRING) {
+            *((char **) value_addr) = optarg;
+        } else if (s->config_type == CFG_SIZE) {
+            *((size_t *) value_addr) = strtol(optarg, NULL, 0);
+            if (errno) {
+                fprintf(stderr, "Expected integer argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+        } else if (s->config_type == CFG_INT) {
+            *((int *) value_addr) = strtol(optarg, NULL, 0);
+            if (errno) {
+                fprintf(stderr, "Expected integer argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+        } else if (s->config_type == CFG_BOOL) {
+            int tmp = strtol(optarg, NULL, 0);
+            if (errno || tmp < 0 || tmp > 1) {
+                fprintf(stderr, "Expected 0 or 1 argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+            *((int *) value_addr) = tmp;
+        } else if (s->config_type == CFG_POSITIVE) {
+            int tmp = strtol(optarg, NULL, 0);
+            if (errno || tmp < 0) {
+                fprintf(stderr, "Expected positive argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+            *((int *) value_addr) = tmp;
+        } else if (s->config_type == CFG_INCREMENT) {
+            (*((int *) value_addr))++;
+        } else if (s->config_type == CFG_LONG) {
+            *((long *) value_addr) = strtol(optarg, NULL, 0);
+            if (errno) {
+                fprintf(stderr, "Expected long integer argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+        } else if (s->config_type == CFG_LONG_SUFFIX) {
+            *((long *) value_addr) = suffix_binary_parse(optarg);
+            if (errno) {
+                fprintf(stderr, "Expected long suffixed integer argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+        } else if (s->config_type == CFG_DOUBLE) {
+            *((double *) value_addr) = strtod(optarg, NULL);
+            if (errno) {
+                fprintf(stderr, "Expected float argument for '%s' but got '%s'!\n",
+                        long_opts[option_index].name, optarg);
+                exit(1);
+            }
+        } else if (s->config_type == CFG_SUBOPTS) {
+            char **opts = ((char **) value_addr);
+            int remaining_space = CFG_MAX_SUBOPTS;
+            int enddefault = 0;
+            while (0 && *opts != NULL) {
+                if (*opts == END_DEFAULT)
+                    enddefault = 1;
+                remaining_space--;
+                opts++;
+            }
+
+            if (!enddefault) {
+                *opts = END_DEFAULT;
+                remaining_space -= 2;
+                opts += 2;
+            }
+
+            int r = argconfig_parse_subopt_string(optarg, opts, remaining_space);
+            if (r == 2) {
+                fprintf(stderr, "Error Parsing Sub-Options: Too many options!\n");
+                exit(1);
+            } else if (r) {
+                fprintf(stderr, "Error Parsing Sub-Options\n");
+                exit(1);
+            }
+        } else if (s->config_type == CFG_FILE_A ||
+                   s->config_type == CFG_FILE_R ||
+                   s->config_type == CFG_FILE_W ||
+                   s->config_type == CFG_FILE_AP ||
+                   s->config_type == CFG_FILE_RP ||
+                   s->config_type == CFG_FILE_WP)
+        {
+            const char *fopts = "";
+            if (s->config_type == CFG_FILE_A)
+                fopts = "a";
+            else if (s->config_type == CFG_FILE_R)
+                fopts = "r";
+            else if (s->config_type == CFG_FILE_W)
+                fopts = "w";
+            else if (s->config_type == CFG_FILE_AP)
+                fopts = "a+";
+            else if (s->config_type == CFG_FILE_RP)
+                fopts = "r+";
+            else if (s->config_type == CFG_FILE_WP)
+                fopts = "w+";
+
+            FILE *f = fopen(optarg, fopts);
+            if (f == NULL) {
+                fprintf(stderr, "Unable to open %s file: %s\n", s->option,
+                        optarg);
+                exit(1);
+            }
+
+            *((FILE **) value_addr) = f;
+        }
+    }
+
+    free(short_opts);
+    free(long_opts);
+
+    for (int i = optind; i < argc; i++) {
+        argv[1+non_opt_args] = argv[i];
+        non_opt_args++;
+    }
+
+    return non_opt_args;
+}
+
+
+int argconfig_parse_subopt_string (char *string, char **options,
+                                   size_t max_options)
+{
+    char **o = options;
+    char *tmp;
+
+    if (!strlen(string) || string == NULL) {
+        *(o++) = NULL;
+        *(o++) = NULL;
+        return 0;
+    }
+
+    tmp = calloc(strlen(string)+2, 1);
+    if (tmp == NULL) {
+        fprintf(stderr,  "Unable to allocate memory!\n");
+        exit(1);
+    }
+    strcpy(tmp, string);
+
+    size_t toklen;
+    toklen = strcspn(tmp, "=");
+    if (!toklen) return 1;
+    *(o++) = tmp;
+    tmp[toklen] = 0;
+    tmp += toklen + 1;
+
+
+    while (1) {
+        if (*tmp == '"' || *tmp == '\'' || *tmp == '[' || *tmp == '(' ||
+            *tmp == '{') {
+
+            tmp++;
+            toklen = strcspn(tmp, "\"'])}");
+
+            if (!toklen) return 1;
+            *(o++) = tmp;
+            tmp[toklen] = 0;
+            tmp += toklen + 1;
+
+            toklen = strcspn(tmp, ";:,");
+            tmp[toklen] = 0;
+            tmp += toklen + 1;
+        } else {
+            toklen = strcspn(tmp, ";:,");
+            if (!toklen) return 1;
+            *(o++) = tmp;
+            tmp[toklen] = 0;
+            tmp += toklen + 1;
+        }
+
+
+        toklen = strcspn(tmp, "=");
+        if (!toklen) break;
+        *(o++) = tmp;
+        tmp[toklen] = 0;
+        tmp += toklen + 1;
+
+        if ((o - options) > (max_options-2))
+            return 2;
+    }
+
+    *(o++) = NULL;
+    *(o++) = NULL;
+
+    return 0;
+}
+
+unsigned argconfig_parse_comma_sep_array(char *string,int *val,unsigned max_length)
+{
+  unsigned ret = 0;
+  char *tmp;
+  char *p;
+
+  if (!strlen(string) || string == NULL)
+    return -1;
+
+  tmp = malloc(strlen(string)+1);
+  if (tmp==NULL) {
+    fprintf(stderr,  "Unable to allocate memory!\n");
+    exit(1);}
+
+  tmp = strtok(string,",");
+  if (tmp==NULL)
+    return -1;
+
+  val[ret] = strtol(tmp,&p,0);
+  if (*p!=0)
+    return -1;
+  ret++;
+
+  while(1) {
+    tmp = strtok(NULL,",");
+    if (tmp==NULL)
+      return ret;
+    if (ret>=max_length)
+      return -1;
+    val[ret] = strtol(tmp,&p,0);
+    if (*p!=0)
+      return -1;
+    ret++;
+    }
+
+}
+
+unsigned argconfig_parse_comma_sep_arrayd(char *string,double *val,unsigned max_length)
+{
+  unsigned ret = 0;
+  char *tmp;
+  char *p;
+
+  if (!strlen(string) || string == NULL)
+    return -1;
+
+  tmp = malloc(strlen(string)+1);
+  if (tmp==NULL) {
+    fprintf(stderr,  "Unable to allocate memory!\n");
+    exit(1);}
+
+  tmp = strtok(string,",");
+  if (tmp==NULL)
+    return -1;
+
+  val[ret] = strtod(tmp,&p);
+  if (*p!=0)
+    return -1;
+  ret++;
+
+  while(1) {
+    tmp = strtok(NULL,",");
+    if (tmp==NULL)
+      return ret;
+    if (ret>=max_length)
+      return -1;
+    val[ret] = strtod(tmp,&p);
+    if (*p!=0)
+      return -1;
+    ret++;
+    }
+
+}
+
+void argconfig_register_help_func(argconfig_help_func * f) {
+    for (int i = 0; i < MAX_HELP_FUNC; i++) {
+        if (help_funcs[i] == NULL) {
+            help_funcs[i] = f;
+            help_funcs[i+1] = NULL;
+            break;
+        }
+    }
+}
+
+void argconfig_print_subopt_help(const struct argconfig_sub_options * options,
+                                 int indent)
+{
+    const struct argconfig_sub_options *s;
+    const int bufsize = 120;
+    char buf[bufsize];
+    int  last_line, nodefault;
+
+    buf[0] = ' ';
+    buf[1] = ' ';
+    buf[2] = 0;
+
+    for (s = options; s->option != 0; s++) {
+        if (s->option[0] == '=') {
+            const char *c = s->option;
+            while (*c == '=') c++;
+            printf("\n%*s%s", indent, "", c);
+            continue;
+        }
+
+        strcat(buf, s->option);
+        strcat(buf, "=");
+        strcat(buf, s->meta);
+
+        if (s->help == NULL) {
+            strcat(buf, ", ");
+            continue;
+        }
+
+        printf("%*s%-*s", indent, "", 30-indent, buf);
+        if (strlen(buf) > 29-indent)
+            printf("%-31s", "\n");
+
+        last_line = print_word_wrapped(s->help, 30-indent, 30-indent);
+
+        nodefault = 0;
+        if (s->config_type == CFG_STRING) {
+            sprintf(&buf[3], " - default: '%s'", *((char **) s->default_value));
+            nodefault = strlen(*((char **) s->default_value)) == 0;
+        } else if (s->config_type == CFG_INT || s->config_type == CFG_BOOL){
+            sprintf(&buf[3], " - default: %d", *((int *) s->default_value));
+        } else if (s->config_type == CFG_LONG){
+            sprintf(&buf[3], " - default: %ld", *((long *) s->default_value));
+        } else if (s->config_type == CFG_LONG_SUFFIX){
+            long long val = *((long *) s->default_value);
+            const char *s = suffix_binary_get(&val);
+            sprintf(&buf[3], " - default: %lld%s", val, s);
+        } else if (s->config_type == CFG_SIZE){
+            sprintf(&buf[3], " - default: %zd", *((size_t *) s->default_value));
+        } else if (s->config_type == CFG_DOUBLE){
+            sprintf(&buf[3], " - default: %.2f", *((double *) s->default_value));
+        } else {
+            sprintf(&buf[3], " ");
+        }
+
+
+        if (!nodefault && s->config_type != CFG_NONE)
+            print_word_wrapped(&buf[3], 30, last_line);
+
+        putchar('\n');
+
+        buf[2] = 0;
+    }
+}
+
+void argconfig_parse_subopt(char * const opts[], const char *module,
+                            const struct argconfig_sub_options *options,
+                            const void *config_default, void *config_out,
+                            size_t config_size)
+{
+    memcpy(config_out, config_default, config_size);
+    int enddefault = 0;
+
+    const struct argconfig_sub_options *s;
+    errno = 0;
+
+    for (char * const *o = opts; o != NULL && *o != NULL; o += 2) {
+        if (*o == END_DEFAULT) {
+            enddefault = 1;
+            continue;
+        }
+
+        for (s = options; s->option != NULL; s++)
+            if (strcmp(o[0], s->option) == 0)
+                break;
+
+        if (s->option == NULL && enddefault) {
+            fprintf(stderr, "%s: Invalid option '%s'.\n", module, o[0]);
+        } else if (s->option == NULL) {
+            continue;
+        }
+
+        void *value_addr = (void *) ((char *) s->default_value -
+                                     (char *) config_default +
+                                     (char *) config_out);
+
+        if (s->config_type == CFG_STRING) {
+            *((char **) value_addr) = o[1];
+        } else if (s->config_type == CFG_INT) {
+            *((int *) value_addr) = (int) strtol(o[1], NULL, 0);
+        } else if (s->config_type == CFG_SIZE) {
+            *((size_t *) value_addr) = (size_t) strtol(o[1], NULL, 0);
+        } else if (s->config_type == CFG_LONG) {
+            *((long *) value_addr) = strtol(o[1], NULL, 0);
+        } else if (s->config_type == CFG_LONG_SUFFIX) {
+            *((long *) value_addr) = suffix_binary_parse(o[1]);
+        } else if (s->config_type == CFG_DOUBLE) {
+            *((double *) value_addr) = strtod(o[1], NULL);
+        } else if (s->config_type == CFG_BOOL) {
+            int tmp = strtol(o[1], NULL, 0);
+            if (tmp < 0 || tmp > 1) errno = 1;
+            *((int *) value_addr) = (int) tmp;
+        } else if (s->config_type == CFG_POSITIVE) {
+            int tmp = strtol(o[1], NULL, 0);
+            if (tmp < 0) errno = 1;
+            *((int *) value_addr) = (int) tmp;
+        } else if (s->config_type == CFG_FILE_A ||
+                   s->config_type == CFG_FILE_R ||
+                   s->config_type == CFG_FILE_W ||
+                   s->config_type == CFG_FILE_AP ||
+                   s->config_type == CFG_FILE_RP ||
+                   s->config_type == CFG_FILE_WP)
+        {
+            const char *fopts = "";
+            if (s->config_type == CFG_FILE_A)
+                fopts = "a";
+            else if (s->config_type == CFG_FILE_R)
+                fopts = "r";
+            else if (s->config_type == CFG_FILE_W)
+                fopts = "w";
+            else if (s->config_type == CFG_FILE_AP)
+                fopts = "a+";
+            else if (s->config_type == CFG_FILE_RP)
+                fopts = "r+";
+            else if (s->config_type == CFG_FILE_WP)
+                fopts = "w+";
+
+            FILE *f = fopen(o[1], fopts);
+            if (f == NULL) {
+                fprintf(stderr, "Unable to open %s file: %s\n", s->option,
+                        o[1]);
+                exit(1);
+            }
+
+            *((FILE **) value_addr) = f;
+        }
+
+
+        if (errno) {
+            fprintf(stderr, "%s: Invalid value '%s' for option '%s'.\n", module,
+                    o[1], o[0]);
+            exit(1);
+        }
+    }
+
+}
+
+int argconfig_set_subopt(const char *opt,
+                         const struct argconfig_sub_options *options,
+                         const void *config_default, void *config_out, va_list argp)
+{
+    const struct argconfig_sub_options *s;
+    for (s = options; s->option != NULL; s++)
+        if (strcmp(opt, s->option) == 0)
+            break;
+
+    if (s->option == NULL)
+        return 1;
+
+    void *value_addr = (void *) ((char *) s->default_value -
+                                 (char *) config_default +
+                                 (char *) config_out);
+
+    if (s->config_type == CFG_STRING) {
+        *((char **) value_addr) = va_arg(argp, char *);
+    } else if (s->config_type == CFG_INT ||
+               s->config_type == CFG_BOOL ||
+               s->config_type == CFG_POSITIVE)
+    {
+        *((int *) value_addr) = va_arg(argp, int);
+    } else if (s->config_type == CFG_SIZE) {
+        *((size_t *) value_addr) = va_arg(argp, size_t);
+    } else if (s->config_type == CFG_LONG) {
+        *((long *) value_addr) = va_arg(argp, long);
+    } else if (s->config_type == CFG_LONG_SUFFIX) {
+        *((long *) value_addr) = va_arg(argp, long);
+    } else if (s->config_type == CFG_DOUBLE) {
+        *((double *) value_addr) = va_arg(argp, double);
+    } else if (s->config_type == CFG_FILE_A ||
+               s->config_type == CFG_FILE_R ||
+               s->config_type == CFG_FILE_W ||
+               s->config_type == CFG_FILE_AP ||
+               s->config_type == CFG_FILE_RP ||
+               s->config_type == CFG_FILE_WP)
+    {
+
+        *((FILE **) value_addr) = va_arg(argp, FILE *);
+    }
+
+    return 0;
+}
+
+
+int argconfig_get_subopt(const char *opt,
+                         const struct argconfig_sub_options *options,
+                         const void *config_default, void *config_out, va_list argp)
+{
+    const struct argconfig_sub_options *s;
+    for (s = options; s->option != NULL; s++)
+        if (strcmp(opt, s->option) == 0)
+            break;
+
+    if (s->option == NULL)
+        return 1;
+
+    void *value_addr = (void *) ((char *) s->default_value -
+                                 (char *) config_default +
+                                 (char *) config_out);
+
+    if (s->config_type == CFG_STRING) {
+        *va_arg(argp, char **) = *((char **) value_addr);
+    } else if (s->config_type == CFG_INT ||
+               s->config_type == CFG_BOOL ||
+               s->config_type == CFG_POSITIVE)
+    {
+        *va_arg(argp, int *) = *((int *) value_addr);
+    } else if (s->config_type == CFG_SIZE) {
+        *va_arg(argp, size_t *) = *((size_t *) value_addr);
+    } else if (s->config_type == CFG_LONG) {
+        *va_arg(argp, long *) = *((long *) value_addr);
+    } else if (s->config_type == CFG_LONG_SUFFIX) {
+        *va_arg(argp, long *) = *((long *) value_addr);
+    } else if (s->config_type == CFG_DOUBLE) {
+        *va_arg(argp, double *) = *((double *) value_addr);
+    } else if (s->config_type == CFG_FILE_A ||
+               s->config_type == CFG_FILE_R ||
+               s->config_type == CFG_FILE_W ||
+               s->config_type == CFG_FILE_AP ||
+               s->config_type == CFG_FILE_RP ||
+               s->config_type == CFG_FILE_WP)
+    {
+        *va_arg(argp, FILE **) = *((FILE **) value_addr);
+    }
+
+    return 0;
+}
diff --git a/src/argconfig.h b/src/argconfig.h
new file mode 100644 (file)
index 0000000..e8957d0
--- /dev/null
@@ -0,0 +1,126 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2014 PMC-Sierra, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you
+// may not use this file except in compliance with the License. You may
+// obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+//
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+//
+//   Author: Logan Gunthorpe <logang@deltatee.com>
+//           Logan Gunthorpe
+//
+//   Date:   Oct 23 2014
+//
+//   Description:
+//     Header file for argconfig.c
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifndef argconfig_H
+#define argconfig_H
+
+#include <string.h>
+#include <getopt.h>
+#include <stdarg.h>
+
+enum argconfig_types {CFG_NONE,
+        CFG_STRING,
+        CFG_INT,
+        CFG_SIZE,
+        CFG_LONG,
+        CFG_LONG_SUFFIX,
+        CFG_DOUBLE,
+        CFG_BOOL,
+        CFG_POSITIVE,
+        CFG_INCREMENT,
+        CFG_SUBOPTS,
+        CFG_FILE_A,
+        CFG_FILE_W,
+        CFG_FILE_R,
+        CFG_FILE_AP,
+        CFG_FILE_WP,
+        CFG_FILE_RP,
+};
+
+//Deprecated
+#define NO_DEFAULT     CFG_NONE
+#define DEFAULT_STRING CFG_STRING
+#define DEFAULT_INT    CFG_INT
+#define DEFAULT_SIZE   CFG_SIZE
+#define DEFAULT_DOUBLE CFG_DOUBLE
+
+struct argconfig_commandline_options {
+    const char *option;
+    const char *meta;
+    enum argconfig_types config_type;
+    const void *default_value;
+    int        argument_type;
+    const char *help;
+};
+
+#define CFG_MAX_SUBOPTS 500
+
+
+
+struct argconfig_sub_options {
+    const char *option;
+    const char *meta;
+    enum argconfig_types config_type;
+    const void *default_value;
+    const char *help;
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef void argconfig_help_func();
+void argconfig_append_usage(const char *str);
+void argconfig_print_help(char *command, const char *program_desc,
+                       const struct argconfig_commandline_options * options);
+
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+                    const struct argconfig_commandline_options *options,
+                    const void *config_default, void *config_out,
+                    size_t config_size);
+int argconfig_parse_subopt_string (char *string, char **options,
+                                size_t max_options);
+unsigned argconfig_parse_comma_sep_array(char *string,int *ret,
+                                     unsigned max_length);
+unsigned argconfig_parse_comma_sep_arrayd(char *string,double *ret,
+                                     unsigned max_length);
+void argconfig_register_help_func(argconfig_help_func * f);
+
+void argconfig_print_subopt_help(const struct argconfig_sub_options * options,
+                              int indent);
+
+void argconfig_parse_subopt(char * const opts[], const char *module,
+                            const struct argconfig_sub_options *options,
+                            const void *config_default, void *config_out,
+                            size_t config_size);
+
+int argconfig_set_subopt(const char *opt,
+                         const struct argconfig_sub_options *options,
+                         const void *config_default, void *config_out, va_list arg);
+int argconfig_get_subopt(const char *opt,
+                         const struct argconfig_sub_options *options,
+                         const void *config_default, void *config_out, va_list arg);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/src/suffix.c b/src/suffix.c
new file mode 100644 (file)
index 0000000..50c4fa6
--- /dev/null
@@ -0,0 +1,124 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2014 PMC-Sierra, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you
+// may not use this file except in compliance with the License. You may
+// obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+//
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+//
+//   Author: Logan Gunthorpe
+//
+//   Date:   Oct 23 2014
+//
+//   Description:
+//     Functions for dealing with number suffixes
+//
+////////////////////////////////////////////////////////////////////////
+
+#include "suffix.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+static struct si_suffix {
+    double magnitude;
+    const char *suffix;
+} si_suffixes[] = {
+    {1e15,  "P"},
+    {1e12,  "T"},
+    {1e9,   "G"},
+    {1e6,   "M"},
+    {1e3,   "k"},
+    {1e0,   ""},
+    {1e-3,  "m"},
+    {1e-6,  "u"},
+    {1e-9,  "n"},
+    {1e-12, "p"},
+    {1e-15, "f"},
+    {0}
+};
+
+const char *suffix_si_get(double *value)
+{
+    struct si_suffix *s;
+
+    for (s = si_suffixes; s->magnitude != 0; s++) {
+        if (*value >= s->magnitude) {
+            *value /= s->magnitude;
+            return s->suffix;
+        }
+    }
+
+    return "";
+}
+
+static struct binary_suffix {
+    int shift;
+    const char *suffix;
+} binary_suffixes[] = {
+    {50, "Pi"},
+    {40, "Ti"},
+    {30, "Gi"},
+    {20, "Mi"},
+    {10, "Ki"},
+    {0,  ""},
+};
+
+const char *suffix_binary_get(long long *value) {
+    struct binary_suffix *s;
+
+    for (s = binary_suffixes; s->shift != 0; s++) {
+        if (llabs(*value) >= (1LL << s->shift)) {
+            *value = (*value + (1 << (s->shift - 1))) /  (1 << s->shift);
+            return s->suffix;
+        }
+    }
+
+    return "";
+}
+
+const char *suffix_dbinary_get(double *value) {
+    struct binary_suffix *s;
+
+    for (s = binary_suffixes; s->shift != 0; s++) {
+        if (llabs(*value) >= (1LL << s->shift)) {
+            *value = *value /  (1 << s->shift);
+            return s->suffix;
+        }
+    }
+
+    return "";
+}
+
+long long suffix_binary_parse(const char *value)
+{
+    char *suffix;
+    errno = 0;
+    long long ret = strtol(value, &suffix, 0);
+    if (errno)
+        return 0;
+
+    struct binary_suffix *s;
+    for (s = binary_suffixes; s->shift != 0; s++) {
+        if (tolower(suffix[0]) == tolower(s->suffix[0])) {
+            ret <<= s->shift;
+            return ret;
+        }
+    }
+
+    if (suffix[0] != '\0')
+                errno = EINVAL;
+
+    return ret;
+}
diff --git a/src/suffix.h b/src/suffix.h
new file mode 100644 (file)
index 0000000..a38c1a9
--- /dev/null
@@ -0,0 +1,35 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2014 PMC-Sierra, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you
+// may not use this file except in compliance with the License. You may
+// obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+// applicable law or agreed to in writing, software distributed under the
+// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for
+// the specific language governing permissions and limitations under the
+// License.
+//
+////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////
+//
+//   Author: Logan Gunthorpe
+//
+//   Date:   Oct 23 2014
+//
+//   Description:
+//     Functions for dealing with number suffixes
+//
+////////////////////////////////////////////////////////////////////////
+
+#ifndef __ARGCONFIG_SUFFIX_H__
+
+const char *suffix_si_get(double *value);
+const char *suffix_binary_get(long long *value);
+const char *suffix_dbinary_get(double *value);
+long long suffix_binary_parse(const char *value);
+
+#endif