summaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:40:30 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2021-07-02 20:40:30 +0000
commitdc597ce8df5ae6efd2728a2d7ba7d92486028f79 (patch)
tree55b9e9257eba4579667f9522368aa29f5be6754a /util
parentInitial commit. (diff)
downloadnvme-cli-dc597ce8df5ae6efd2728a2d7ba7d92486028f79.tar.xz
nvme-cli-dc597ce8df5ae6efd2728a2d7ba7d92486028f79.zip
Adding upstream version 1.12.upstream/1.12
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'util')
-rw-r--r--util/argconfig.c534
-rw-r--r--util/argconfig.h130
-rw-r--r--util/json.c407
-rw-r--r--util/json.h88
-rw-r--r--util/parser.c284
-rw-r--r--util/parser.h34
-rw-r--r--util/suffix.c132
-rw-r--r--util/suffix.h41
8 files changed, 1650 insertions, 0 deletions
diff --git a/util/argconfig.c b/util/argconfig.c
new file mode 100644
index 0000000..f647448
--- /dev/null
+++ b/util/argconfig.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * 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>
+#include <inttypes.h>
+
+static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL };
+
+static char END_DEFAULT[] = "__end_default__";
+
+static const char *append_usage_str = "";
+
+void argconfig_append_usage(const char *str)
+{
+ append_usage_str = str;
+}
+
+void print_word_wrapped(const char *s, int indent, int start)
+{
+ const int width = 76;
+ const char *c, *t;
+ int next_space = -1;
+ int last_line = indent;
+
+ while (start < indent) {
+ putc(' ', stderr);
+ start++;
+ }
+
+ for (c = s; *c != 0; c++) {
+ if (*c == '\n')
+ goto new_line;
+
+ if (*c == ' ' || next_space < 0) {
+ next_space = 0;
+ for (t = c + 1; *t != 0 && *t != ' '; t++)
+ next_space++;
+
+ if (((int)(c - s) + start + next_space) > (last_line - indent + width)) {
+ int i;
+new_line:
+ last_line = (int) (c-s) + start;
+ putc('\n', stderr);
+ for (i = 0; i < indent; i++)
+ putc(' ', stderr);
+ start = indent;
+ continue;
+ }
+ }
+ putc(*c, stderr);
+ }
+}
+
+static void show_option(const struct argconfig_commandline_options *option)
+{
+ char buffer[0x1000];
+ char *b = buffer;
+
+ b += sprintf(b, " [ ");
+ if (option->option) {
+ b += sprintf(b, " --%s", option->option);
+ if (option->argument_type == optional_argument)
+ b += sprintf(b, "[=<%s>]", option->meta ? option->meta : "arg");
+ if (option->argument_type == required_argument)
+ b += sprintf(b, "=<%s>", option->meta ? option->meta : "arg");
+ if (option->short_option)
+ b += sprintf(b, ",");
+ }
+ if (option->short_option) {
+ b += sprintf(b, " -%c", option->short_option);
+ if (option->argument_type == optional_argument)
+ b += sprintf(b, " [<%s>]", option->meta ? option->meta : "arg");
+ if (option->argument_type == required_argument)
+ b += sprintf(b, " <%s>", option->meta ? option->meta : "arg");
+ }
+ b += sprintf(b, " ] ");
+
+ fprintf(stderr, "%s", buffer);
+ if (option->help) {
+ print_word_wrapped("--- ", 40, b - buffer);
+ print_word_wrapped(option->help, 44, 44);
+ }
+ fprintf(stderr, "\n");
+}
+
+void argconfig_print_help(const char *program_desc,
+ const struct argconfig_commandline_options *options)
+{
+ const struct argconfig_commandline_options *s;
+
+ printf("\033[1mUsage: %s\033[0m\n\n",
+ append_usage_str);
+
+ print_word_wrapped(program_desc, 0, 0);
+ printf("\n");
+
+ if (!options || !options->option)
+ return;
+
+ printf("\n\033[1mOptions:\033[0m\n");
+ for (s = options; (s->option != NULL) && (s != NULL); s++)
+ show_option(s);
+}
+
+int argconfig_parse(int argc, char *argv[], const char *program_desc,
+ const struct argconfig_commandline_options *options)
+{
+ char *short_opts;
+ char *endptr;
+ struct option *long_opts;
+ const struct argconfig_commandline_options *s;
+ int c, option_index = 0, short_index = 0, options_count = 0;
+ void *value_addr;
+ int ret = -EINVAL;
+
+ errno = 0;
+ for (s = options; s->option != NULL; s++)
+ options_count++;
+
+ long_opts = malloc(sizeof(struct option) * (options_count + 2));
+ short_opts = malloc(sizeof(*short_opts) * (options_count * 3 + 4));
+
+ if (!long_opts || !short_opts) {
+ fprintf(stderr, "failed to allocate memory for opts: %s\n",
+ strerror(errno));
+ ret = -errno;
+ goto out;
+ }
+
+ for (s = options; (s->option != NULL) && (option_index < options_count);
+ s++) {
+ if (s->short_option != 0) {
+ short_opts[short_index++] = s->short_option;
+ if (s->argument_type == required_argument ||
+ s->argument_type == optional_argument)
+ short_opts[short_index++] = ':';
+ if (s->argument_type == optional_argument)
+ short_opts[short_index++] = ':';
+ }
+ if (s->option && strlen(s->option)) {
+ 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;
+
+ 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 = "help";
+ long_opts[option_index].flag = NULL;
+ long_opts[option_index].val = 'h';
+ option_index++;
+
+ long_opts[option_index].name = NULL;
+ long_opts[option_index].flag = NULL;
+ long_opts[option_index].val = 0;
+
+ short_opts[short_index++] = '?';
+ short_opts[short_index++] = 'h';
+ short_opts[short_index] = 0;
+
+ optind = 0;
+ while ((c = getopt_long_only(argc, argv, short_opts, long_opts,
+ &option_index)) != -1) {
+ if (c != 0) {
+ if (c == '?' || c == 'h') {
+ argconfig_print_help(program_desc, options);
+ goto out;
+ }
+ for (option_index = 0; option_index < options_count;
+ option_index++) {
+ if (c == options[option_index].short_option)
+ break;
+ }
+ if (option_index == options_count)
+ continue;
+ if (long_opts[option_index].flag) {
+ *(uint8_t *)(long_opts[option_index].flag) = 1;
+ continue;
+ }
+ }
+
+ s = &options[option_index];
+ value_addr = (void *)(char *)s->default_value;
+ if (s->config_type == CFG_STRING) {
+ *((char **)value_addr) = optarg;
+ } else if (s->config_type == CFG_SIZE) {
+ *((size_t *) value_addr) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_INT) {
+ *((int *)value_addr) = strtol(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_BOOL) {
+ int tmp = strtol(optarg, &endptr, 0);
+ if (errno || tmp < 0 || tmp > 1 || optarg == endptr) {
+ fprintf(stderr,
+ "Expected 0 or 1 argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((int *)value_addr) = tmp;
+ } else if (s->config_type == CFG_BYTE) {
+ unsigned long tmp = strtoul(optarg, &endptr, 0);
+ if (errno || tmp >= (1 << 8) || optarg == endptr) {
+ fprintf(stderr,
+ "Expected byte argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint8_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_SHORT) {
+ unsigned long tmp = strtoul(optarg, &endptr, 0);
+ if (errno || tmp >= (1 << 16) || optarg == endptr) {
+ fprintf(stderr,
+ "Expected short argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint16_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_POSITIVE) {
+ uint32_t tmp = strtoul(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected word argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ *((uint32_t *) value_addr) = tmp;
+ } else if (s->config_type == CFG_INCREMENT) {
+ (*((int *)value_addr))++;
+ } else if (s->config_type == CFG_LONG) {
+ *((unsigned long *)value_addr) = strtoul(optarg, &endptr, 0);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected long integer argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_LONG_SUFFIX) {
+ *((uint64_t *)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);
+ goto out;
+ }
+ } else if (s->config_type == CFG_DOUBLE) {
+ *((double *)value_addr) = strtod(optarg, &endptr);
+ if (errno || optarg == endptr) {
+ fprintf(stderr,
+ "Expected float argument for '%s' but got '%s'!\n",
+ long_opts[option_index].name, optarg);
+ goto out;
+ }
+ } else if (s->config_type == CFG_SUBOPTS) {
+ char **opts = ((char **)value_addr);
+ int remaining_space = CFG_MAX_SUBOPTS;
+ int enddefault = 0;
+ int r;
+ while (0 && *opts != NULL) {
+ if (*opts == END_DEFAULT)
+ enddefault = 1;
+ remaining_space--;
+ opts++;
+ }
+
+ if (!enddefault) {
+ *opts = END_DEFAULT;
+ remaining_space -= 2;
+ opts += 2;
+ }
+
+ r = argconfig_parse_subopt_string(optarg, opts,
+ remaining_space);
+ if (r == 2) {
+ fprintf(stderr,
+ "Error Parsing Sub-Options: Too many options!\n");
+ goto out;
+ } else if (r) {
+ fprintf(stderr, "Error Parsing Sub-Options\n");
+ goto out;
+ }
+ } 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 = "";
+ FILE *f;
+ 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+";
+
+ f = fopen(optarg, fopts);
+ if (f == NULL) {
+ fprintf(stderr, "Unable to open %s file: %s\n",
+ s->option, optarg);
+ goto out;
+ }
+ *((FILE **) value_addr) = f;
+ }
+ }
+ free(short_opts);
+ free(long_opts);
+
+ return 0;
+ out:
+ free(short_opts);
+ free(long_opts);
+ return ret;
+}
+
+int argconfig_parse_subopt_string(char *string, char **options,
+ size_t max_options)
+{
+ char **o = options;
+ char *tmp;
+ size_t toklen;
+
+ if (!string || !strlen(string)) {
+ *(o++) = NULL;
+ *(o++) = NULL;
+ return 0;
+ }
+
+ tmp = calloc(strlen(string) + 2, 1);
+ if (!tmp)
+ return 1;
+ strcpy(tmp, string);
+
+ toklen = strcspn(tmp, "=");
+
+ if (!toklen) {
+ free(tmp);
+ 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 (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (!tmp)
+ return 0;
+
+ 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_array_long(char *string,
+ unsigned long long *val,
+ unsigned max_length)
+{
+ unsigned ret = 0;
+ char *tmp;
+ char *p;
+
+ if (!string || !strlen(string))
+ return 0;
+
+ tmp = strtok(string, ",");
+ if (tmp == NULL)
+ return 0;
+
+ val[ret] = strtoll(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] = strtoll(tmp, &p, 0);
+ if (*p != 0)
+ return -1;
+ ret++;
+ }
+}
+
+void argconfig_register_help_func(argconfig_help_func * f)
+{
+ int i;
+ for (i = 0; i < MAX_HELP_FUNC; i++) {
+ if (help_funcs[i] == NULL) {
+ help_funcs[i] = f;
+ help_funcs[i + 1] = NULL;
+ break;
+ }
+ }
+}
diff --git a/util/argconfig.h b/util/argconfig.h
new file mode 100644
index 0000000..623b832
--- /dev/null
+++ b/util/argconfig.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * 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_BYTE,
+ CFG_SHORT,
+ CFG_POSITIVE,
+ CFG_INCREMENT,
+ CFG_SUBOPTS,
+ CFG_FILE_A,
+ CFG_FILE_W,
+ CFG_FILE_R,
+ CFG_FILE_AP,
+ CFG_FILE_WP,
+ CFG_FILE_RP,
+};
+
+#define OPT_ARGS(n) \
+ const struct argconfig_commandline_options n[]
+
+#define OPT_END() { NULL }
+
+#define OPT_FLAG(l, s, v, d) \
+ {l, s, NULL, CFG_NONE, v, no_argument, d}
+
+#define OPT_SUFFIX(l, s, v, d) \
+ {l, s, "IONUM", CFG_LONG_SUFFIX, v, required_argument, d}
+
+#define OPT_LONG(l, s, v, d) \
+ {l, s, "NUM", CFG_LONG, v, required_argument, d}
+
+#define OPT_UINT(l, s, v, d) \
+ {l, s, "NUM", CFG_POSITIVE, v, required_argument, d}
+
+#define OPT_INT(l, s, v, d) \
+ {l, s, "NUM", CFG_INT, v, required_argument, d}
+
+#define OPT_LONG(l, s, v, d) \
+ {l, s, "NUM", CFG_LONG, v, required_argument, d}
+
+#define OPT_DOUBLE(l, s, v, d) \
+ {l, s, "NUM", CFG_DOUBLE, v, required_argument, d}
+
+#define OPT_BYTE(l, s, v, d) \
+ {l, s, "NUM", CFG_BYTE, v, required_argument, d}
+
+#define OPT_SHRT(l, s, v, d) \
+ {l, s, "NUM", CFG_SHORT, v, required_argument, d}
+
+#define OPT_STRING(l, s, m, v, d) \
+ {l, s, m, CFG_STRING, v, required_argument, d}
+
+#define OPT_FMT(l, s, v, d) OPT_STRING(l, s, "FMT", v, d)
+#define OPT_FILE(l, s, v, d) OPT_STRING(l, s, "FILE", v, d)
+#define OPT_LIST(l, s, v, d) OPT_STRING(l, s, "LIST", v, d)
+
+struct argconfig_commandline_options {
+ const char *option;
+ const char short_option;
+ const char *meta;
+ enum argconfig_types config_type;
+ void *default_value;
+ int argument_type;
+ const char *help;
+};
+
+#define CFG_MAX_SUBOPTS 500
+#define MAX_HELP_FUNC 20
+
+typedef void argconfig_help_func();
+void argconfig_append_usage(const char *str);
+void argconfig_print_help(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);
+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_array_long(char *string,
+ unsigned long long *ret,
+ unsigned max_length);
+void argconfig_register_help_func(argconfig_help_func * f);
+
+void print_word_wrapped(const char *s, int indent, int start);
+#endif
diff --git a/util/json.c b/util/json.c
new file mode 100644
index 0000000..2978410
--- /dev/null
+++ b/util/json.c
@@ -0,0 +1,407 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "json.h"
+
+static inline void fail_and_notify(void)
+{
+ fprintf(stderr, "Allocation of memory for json object failed, aborting.\n");
+ abort();
+}
+
+struct json_object *json_create_object(void)
+{
+ void *test = calloc(1, sizeof(struct json_object));
+ if (!test)
+ fail_and_notify();
+ return test;
+}
+
+struct json_array *json_create_array(void)
+{
+ void *test = calloc(1, sizeof(struct json_array));
+ if (!test)
+ fail_and_notify();
+ return test;
+}
+
+static struct json_pair *json_create_pair(const char *name, struct json_value *value)
+{
+ struct json_pair *pair = malloc(sizeof(struct json_pair));
+ if (pair) {
+ pair->name = strdup(name);
+ pair->value = value;
+
+ value->parent_type = JSON_PARENT_TYPE_PAIR;
+ value->parent_pair = pair;
+ } else
+ fail_and_notify();
+
+ return pair;
+}
+
+static struct json_value *json_create_value_int(long long number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_INTEGER;
+ value->integer_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_uint(unsigned long long number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_UINT;
+ value->uint_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_float(long double number)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_FLOAT;
+ value->float_number = number;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static char *strdup_escape(const char *str)
+{
+ const char *input = str;
+ char *p, *ret;
+ int escapes;
+
+ if (!strlen(str))
+ return NULL;
+
+ escapes = 0;
+ while ((input = strpbrk(input, "\\\"")) != NULL) {
+ escapes++;
+ input++;
+ }
+
+ p = ret = malloc(strlen(str) + escapes + 1);
+ if (!ret)
+ fail_and_notify();
+
+ while (*str) {
+ if (*str == '\\' || *str == '\"')
+ *p++ = '\\';
+ *p++ = *str++;
+ }
+ *p = '\0';
+
+ return ret;
+}
+
+/*
+ * Valid JSON strings must escape '"' and '/' with a preceding '/'
+ */
+static struct json_value *json_create_value_string(const char *str)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_STRING;
+ value->string = strdup_escape(str ? str : "(null)");
+ if (!value->string) {
+ free(value);
+ value = NULL;
+ return value;
+ }
+ }
+ if (!value)
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_object(struct json_object *obj)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_OBJECT;
+ value->object = obj;
+ obj->parent = value;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static struct json_value *json_create_value_array(struct json_array *array)
+{
+ struct json_value *value = malloc(sizeof(struct json_value));
+
+ if (value) {
+ value->type = JSON_TYPE_ARRAY;
+ value->array = array;
+ array->parent = value;
+ } else
+ fail_and_notify();
+
+ return value;
+}
+
+static void json_free_pair(struct json_pair *pair);
+static void json_free_value(struct json_value *value);
+
+void json_free_object(struct json_object *obj)
+{
+ int i;
+
+ for (i = 0; i < obj->pair_cnt; i++)
+ json_free_pair(obj->pairs[i]);
+ free(obj->pairs);
+ free(obj);
+}
+
+void json_free_array(struct json_array *array)
+{
+ int i;
+
+ for (i = 0; i < array->value_cnt; i++)
+ json_free_value(array->values[i]);
+ free(array->values);
+ free(array);
+}
+
+static void json_free_pair(struct json_pair *pair)
+{
+ json_free_value(pair->value);
+ free(pair->name);
+ free(pair);
+}
+
+static void json_free_value(struct json_value *value)
+{
+ switch (value->type) {
+ case JSON_TYPE_STRING:
+ free(value->string);
+ break;
+ case JSON_TYPE_OBJECT:
+ json_free_object(value->object);
+ break;
+ case JSON_TYPE_ARRAY:
+ json_free_array(value->array);
+ break;
+ }
+ free(value);
+}
+
+static int json_array_add_value(struct json_array *array, struct json_value *value)
+{
+ struct json_value **values = realloc(array->values,
+ sizeof(struct json_value *) * (array->value_cnt + 1));
+
+ if (!values)
+ return ENOMEM;
+ values[array->value_cnt] = value;
+ array->value_cnt++;
+ array->values = values;
+
+ value->parent_type = JSON_PARENT_TYPE_ARRAY;
+ value->parent_array = array;
+ return 0;
+}
+
+static int json_object_add_pair(struct json_object *obj, struct json_pair *pair)
+{
+ struct json_pair **pairs = realloc(obj->pairs,
+ sizeof(struct json_pair *) * (obj->pair_cnt + 1));
+ if (!pairs)
+ return ENOMEM;
+ pairs[obj->pair_cnt] = pair;
+ obj->pair_cnt++;
+ obj->pairs = pairs;
+
+ pair->parent = obj;
+ return 0;
+}
+
+int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...)
+{
+ struct json_value *value;
+ struct json_pair *pair;
+ va_list args;
+ int ret;
+
+ va_start(args, type);
+ if (type == JSON_TYPE_STRING)
+ value = json_create_value_string(va_arg(args, char *));
+ else if (type == JSON_TYPE_INTEGER)
+ value = json_create_value_int(va_arg(args, long long));
+ else if (type == JSON_TYPE_UINT)
+ value = json_create_value_uint(va_arg(args, unsigned long long));
+ else if (type == JSON_TYPE_FLOAT)
+ value = json_create_value_float(va_arg(args, long double));
+ else if (type == JSON_TYPE_OBJECT)
+ value = json_create_value_object(va_arg(args, struct json_object *));
+ else
+ value = json_create_value_array(va_arg(args, struct json_array *));
+ va_end(args);
+
+ if (!value)
+ return ENOMEM;
+
+ pair = json_create_pair(name, value);
+ if (!pair) {
+ json_free_value(value);
+ return ENOMEM;
+ }
+ ret = json_object_add_pair(obj, pair);
+ if (ret) {
+ json_free_pair(pair);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static void json_print_array(struct json_array *array, void *);
+int json_array_add_value_type(struct json_array *array, int type, ...)
+{
+ struct json_value *value;
+ va_list args;
+ int ret;
+
+ va_start(args, type);
+ if (type == JSON_TYPE_STRING)
+ value = json_create_value_string(va_arg(args, char *));
+ else if (type == JSON_TYPE_INTEGER)
+ value = json_create_value_int(va_arg(args, long long));
+ else if (type == JSON_TYPE_UINT)
+ value = json_create_value_uint(va_arg(args, unsigned long long));
+ else if (type == JSON_TYPE_FLOAT)
+ value = json_create_value_float(va_arg(args, double));
+ else if (type == JSON_TYPE_OBJECT)
+ value = json_create_value_object(va_arg(args, struct json_object *));
+ else
+ value = json_create_value_array(va_arg(args, struct json_array *));
+ va_end(args);
+
+ if (!value)
+ return ENOMEM;
+
+ ret = json_array_add_value(array, value);
+ if (ret) {
+ json_free_value(value);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static int json_value_level(struct json_value *value);
+static int json_pair_level(struct json_pair *pair);
+static int json_array_level(struct json_array *array);
+static int json_object_level(struct json_object *object)
+{
+ if (object->parent == NULL)
+ return 0;
+ return json_value_level(object->parent);
+}
+
+static int json_pair_level(struct json_pair *pair)
+{
+ return json_object_level(pair->parent) + 1;
+}
+
+static int json_array_level(struct json_array *array)
+{
+ return json_value_level(array->parent);
+}
+
+static int json_value_level(struct json_value *value)
+{
+ if (value->parent_type == JSON_PARENT_TYPE_PAIR)
+ return json_pair_level(value->parent_pair);
+ else
+ return json_array_level(value->parent_array) + 1;
+}
+
+static void json_print_level(int level, void *out)
+{
+ while (level-- > 0)
+ printf(" ");
+}
+
+static void json_print_pair(struct json_pair *pair, void *);
+static void json_print_array(struct json_array *array, void *);
+static void json_print_value(struct json_value *value, void *);
+void json_print_object(struct json_object *obj, void *out)
+{
+ int i;
+
+ printf("{\n");
+ for (i = 0; i < obj->pair_cnt; i++) {
+ if (i > 0)
+ printf(",\n");
+ json_print_pair(obj->pairs[i], out);
+ }
+ printf("\n");
+ json_print_level(json_object_level(obj), out);
+ printf("}");
+}
+
+static void json_print_pair(struct json_pair *pair, void *out)
+{
+ json_print_level(json_pair_level(pair), out);
+ printf("\"%s\" : ", pair->name);
+ json_print_value(pair->value, out);
+}
+
+static void json_print_array(struct json_array *array, void *out)
+{
+ int i;
+
+ printf("[\n");
+ for (i = 0; i < array->value_cnt; i++) {
+ if (i > 0)
+ printf(",\n");
+ json_print_level(json_value_level(array->values[i]), out);
+ json_print_value(array->values[i], out);
+ }
+ printf("\n");
+ json_print_level(json_array_level(array), out);
+ printf("]");
+}
+
+static void json_print_value(struct json_value *value, void *out)
+{
+ switch (value->type) {
+ case JSON_TYPE_STRING:
+ printf( "\"%s\"", value->string);
+ break;
+ case JSON_TYPE_INTEGER:
+ printf( "%lld", value->integer_number);
+ break;
+ case JSON_TYPE_UINT:
+ printf( "%llu", value->uint_number);
+ break;
+ case JSON_TYPE_FLOAT:
+ printf( "%.0Lf", value->float_number);
+ break;
+ case JSON_TYPE_OBJECT:
+ json_print_object(value->object, out);
+ break;
+ case JSON_TYPE_ARRAY:
+ json_print_array(value->array, out);
+ break;
+ }
+}
diff --git a/util/json.h b/util/json.h
new file mode 100644
index 0000000..d78d3db
--- /dev/null
+++ b/util/json.h
@@ -0,0 +1,88 @@
+#ifndef __JSON__H
+#define __JSON__H
+
+struct json_object;
+struct json_array;
+struct json_pair;
+
+#define JSON_TYPE_STRING 0
+#define JSON_TYPE_INTEGER 1
+#define JSON_TYPE_FLOAT 2
+#define JSON_TYPE_OBJECT 3
+#define JSON_TYPE_ARRAY 4
+#define JSON_TYPE_UINT 5
+#define JSON_PARENT_TYPE_PAIR 0
+#define JSON_PARENT_TYPE_ARRAY 1
+struct json_value {
+ int type;
+ union {
+ long long integer_number;
+ unsigned long long uint_number;
+ long double float_number;
+ char *string;
+ struct json_object *object;
+ struct json_array *array;
+ };
+ int parent_type;
+ union {
+ struct json_pair *parent_pair;
+ struct json_array *parent_array;
+ };
+};
+
+struct json_array {
+ struct json_value **values;
+ int value_cnt;
+ struct json_value *parent;
+};
+
+struct json_object {
+ struct json_pair **pairs;
+ int pair_cnt;
+ struct json_value *parent;
+};
+
+struct json_pair {
+ char *name;
+ struct json_value *value;
+ struct json_object *parent;
+};
+
+struct json_object *json_create_object(void);
+struct json_array *json_create_array(void);
+
+void json_free_object(struct json_object *obj);
+void json_free_array(struct json_array *array);
+
+int json_object_add_value_type(struct json_object *obj, const char *name, int type, ...);
+#define json_object_add_value_int(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_INTEGER, (long long) (val))
+#define json_object_add_value_uint(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_UINT, (unsigned long long) (val))
+#define json_object_add_value_float(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_FLOAT, (val))
+#define json_object_add_value_string(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_STRING, (val))
+#define json_object_add_value_object(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_OBJECT, (val))
+#define json_object_add_value_array(obj, name, val) \
+ json_object_add_value_type((obj), name, JSON_TYPE_ARRAY, (val))
+int json_array_add_value_type(struct json_array *array, int type, ...);
+#define json_array_add_value_int(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_INTEGER, (val))
+#define json_array_add_value_uint(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_UINT, (val))
+#define json_array_add_value_float(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_FLOAT, (val))
+#define json_array_add_value_string(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_STRING, (val))
+#define json_array_add_value_object(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_OBJECT, (val))
+#define json_array_add_value_array(obj, val) \
+ json_array_add_value_type((obj), JSON_TYPE_ARRAY, (val))
+
+#define json_array_last_value_object(obj) \
+ (obj->values[obj->value_cnt - 1]->object)
+
+void json_print_object(struct json_object *obj, void *);
+#endif
diff --git a/util/parser.c b/util/parser.c
new file mode 100644
index 0000000..2dd0922
--- /dev/null
+++ b/util/parser.c
@@ -0,0 +1,284 @@
+/*
+ * lib/parser.c - simple parser for mount, etc. options.
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include "parser.h"
+
+/**
+ * match_one: - Determines if a string matches a simple pattern
+ * @s: the string to examine for presence of the pattern
+ * @p: the string containing the pattern
+ * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
+ * locations.
+ *
+ * Description: Determines if the pattern @p is present in string @s. Can only
+ * match extremely simple token=arg style patterns. If the pattern is found,
+ * the location(s) of the arguments will be returned in the @args array.
+ */
+static int match_one(char *s, const char *p, substring_t args[])
+{
+ char *meta;
+ int argc = 0;
+
+ if (!p)
+ return 1;
+
+ while(1) {
+ int len = -1;
+ meta = strchr(p, '%');
+ if (!meta)
+ return strcmp(p, s) == 0;
+
+ if (strncmp(p, s, meta-p))
+ return 0;
+
+ s += meta - p;
+ p = meta + 1;
+
+ if (isdigit(*p))
+ len = strtoul(p, (char **) &p, 10);
+ else if (*p == '%') {
+ if (*s++ != '%')
+ return 0;
+ p++;
+ continue;
+ }
+
+ if (argc >= MAX_OPT_ARGS)
+ return 0;
+
+ args[argc].from = s;
+ switch (*p++) {
+ case 's': {
+ size_t str_len = strlen(s);
+
+ if (str_len == 0)
+ return 0;
+ if (len == -1 || len > str_len)
+ len = str_len;
+ args[argc].to = s + len;
+ break;
+ }
+ case 'd':
+ strtol(s, &args[argc].to, 0);
+ goto num;
+ case 'u':
+ strtoul(s, &args[argc].to, 0);
+ goto num;
+ case 'o':
+ strtoul(s, &args[argc].to, 8);
+ goto num;
+ case 'x':
+ strtoul(s, &args[argc].to, 16);
+ num:
+ if (args[argc].to == args[argc].from)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ s = args[argc].to;
+ argc++;
+ }
+}
+
+/**
+ * match_token: - Find a token (and optional args) in a string
+ * @s: the string to examine for token/argument pairs
+ * @table: match_table_t describing the set of allowed option tokens and the
+ * arguments that may be associated with them. Must be terminated with a
+ * &struct match_token whose pattern is set to the NULL pointer.
+ * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match
+ * locations.
+ *
+ * Description: Detects which if any of a set of token strings has been passed
+ * to it. Tokens can include up to MAX_OPT_ARGS instances of basic c-style
+ * format identifiers which will be taken into account when matching the
+ * tokens, and whose locations will be returned in the @args array.
+ */
+int match_token(char *s, const match_table_t table, substring_t args[])
+{
+ const struct match_token *p;
+
+ for (p = table; !match_one(s, p->pattern, args) ; p++)
+ ;
+
+ return p->token;
+}
+
+/**
+ * match_number: scan a number in the given base from a substring_t
+ * @s: substring to be scanned
+ * @result: resulting integer on success
+ * @base: base to use when converting string
+ *
+ * Description: Given a &substring_t and a base, attempts to parse the substring
+ * as a number in that base. On success, sets @result to the integer represented
+ * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+static int match_number(substring_t *s, int *result, int base)
+{
+ char *endp;
+ char *buf;
+ int ret;
+ long val;
+ size_t len = s->to - s->from;
+
+ buf = malloc(len + 1);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, s->from, len);
+ buf[len] = '\0';
+
+ ret = 0;
+ val = strtol(buf, &endp, base);
+ if (endp == buf)
+ ret = -EINVAL;
+ else if (val < (long)INT_MIN || val > (long)INT_MAX)
+ ret = -ERANGE;
+ else
+ *result = (int) val;
+ free(buf);
+ return ret;
+}
+
+/**
+ * match_int: - scan a decimal representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as a decimal integer. On
+ * success, sets @result to the integer represented by the string and returns 0.
+ * Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_int(substring_t *s, int *result)
+{
+ return match_number(s, result, 0);
+}
+
+/**
+ * match_octal: - scan an octal representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as an octal integer. On
+ * success, sets @result to the integer represented by the string and returns
+ * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_octal(substring_t *s, int *result)
+{
+ return match_number(s, result, 8);
+}
+
+/**
+ * match_hex: - scan a hex representation of an integer from a substring_t
+ * @s: substring_t to be scanned
+ * @result: resulting integer on success
+ *
+ * Description: Attempts to parse the &substring_t @s as a hexadecimal integer.
+ * On success, sets @result to the integer represented by the string and
+ * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure.
+ */
+int match_hex(substring_t *s, int *result)
+{
+ return match_number(s, result, 16);
+}
+
+/**
+ * match_wildcard: - parse if a string matches given wildcard pattern
+ * @pattern: wildcard pattern
+ * @str: the string to be parsed
+ *
+ * Description: Parse the string @str to check if matches wildcard
+ * pattern @pattern. The pattern may contain two type wildcardes:
+ * '*' - matches zero or more characters
+ * '?' - matches one character
+ * If it's matched, return true, else return false.
+ */
+bool match_wildcard(const char *pattern, const char *str)
+{
+ const char *s = str;
+ const char *p = pattern;
+ bool star = false;
+
+ while (*s) {
+ switch (*p) {
+ case '?':
+ s++;
+ p++;
+ break;
+ case '*':
+ star = true;
+ str = s;
+ if (!*++p)
+ return true;
+ pattern = p;
+ break;
+ default:
+ if (*s == *p) {
+ s++;
+ p++;
+ } else {
+ if (!star)
+ return false;
+ str++;
+ s = str;
+ p = pattern;
+ }
+ break;
+ }
+ }
+
+ if (*p == '*')
+ ++p;
+ return !*p;
+}
+
+/**
+ * match_strlcpy: - Copy the characters from a substring_t to a sized buffer
+ * @dest: where to copy to
+ * @src: &substring_t to copy
+ * @size: size of destination buffer
+ *
+ * Description: Copy the characters in &substring_t @src to the
+ * c-style string @dest. Copy no more than @size - 1 characters, plus
+ * the terminating NUL. Return length of @src.
+ */
+size_t match_strlcpy(char *dest, const substring_t *src, size_t size)
+{
+ size_t ret = src->to - src->from;
+
+ if (size) {
+ size_t len = ret >= size ? size - 1 : ret;
+ memcpy(dest, src->from, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}
+
+/**
+ * match_strdup: - allocate a new string with the contents of a substring_t
+ * @s: &substring_t to copy
+ *
+ * Description: Allocates and returns a string filled with the contents of
+ * the &substring_t @s. The caller is responsible for freeing the returned
+ * string with free().
+ */
+char *match_strdup(const substring_t *s)
+{
+ size_t sz = s->to - s->from + 1;
+ char *p = malloc(sz);
+ if (p)
+ match_strlcpy(p, s, sz);
+ return p;
+}
diff --git a/util/parser.h b/util/parser.h
new file mode 100644
index 0000000..39d5b79
--- /dev/null
+++ b/util/parser.h
@@ -0,0 +1,34 @@
+/*
+ * linux/include/linux/parser.h
+ *
+ * Header for lib/parser.c
+ * Intended use of these functions is parsing filesystem argument lists,
+ * but could potentially be used anywhere else that simple option=arg
+ * parsing is required.
+ */
+
+
+/* associates an integer enumerator with a pattern string. */
+struct match_token {
+ int token;
+ const char *pattern;
+};
+
+typedef struct match_token match_table_t[];
+
+/* Maximum number of arguments that match_token will find in a pattern */
+enum {MAX_OPT_ARGS = 3};
+
+/* Describe the location within a string of a substring */
+typedef struct {
+ char *from;
+ char *to;
+} substring_t;
+
+int match_token(char *, const match_table_t table, substring_t args[]);
+int match_int(substring_t *, int *result);
+int match_octal(substring_t *, int *result);
+int match_hex(substring_t *, int *result);
+bool match_wildcard(const char *pattern, const char *str);
+size_t match_strlcpy(char *, const substring_t *, size_t);
+char *match_strdup(const substring_t *);
diff --git a/util/suffix.c b/util/suffix.c
new file mode 100644
index 0000000..bf1485f
--- /dev/null
+++ b/util/suffix.c
@@ -0,0 +1,132 @@
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * 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>
+#include <math.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 + (1LL << (s->shift - 1))) / (1LL << 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 (fabs(*value) >= (1LL << s->shift)) {
+ *value = *value / (1LL << s->shift);
+ return s->suffix;
+ }
+ }
+
+ return "";
+}
+
+uint64_t suffix_binary_parse(const char *value)
+{
+ char *suffix;
+ errno = 0;
+ uint64_t ret = strtoll(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/util/suffix.h b/util/suffix.h
new file mode 100644
index 0000000..278f472
--- /dev/null
+++ b/util/suffix.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright 2014 PMC-Sierra, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ *
+ * Author: Logan Gunthorpe
+ *
+ * Date: Oct 23 2014
+ *
+ * Description:
+ * Functions for dealing with number suffixes
+ *
+ */
+
+#ifndef __ARGCONFIG_SUFFIX_H__
+
+#include <inttypes.h>
+
+const char *suffix_si_get(double *value);
+const char *suffix_binary_get(long long *value);
+const char *suffix_dbinary_get(double *value);
+uint64_t suffix_binary_parse(const char *value);
+
+#endif