From 8e1dcd44fcad7826e5f8fa6c5caa6c23989518d9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 7 Apr 2023 14:43:34 +0200 Subject: Merging upstream version 2.4+really2.4. Signed-off-by: Daniel Baumann --- util/argconfig.c | 365 ++++++++++++++++++++++++++++--------------------------- util/argconfig.h | 11 +- util/crc32.c | 99 +++++++++++++++ util/crc32.h | 11 ++ util/json.c | 14 +++ util/json.h | 10 +- util/meson.build | 10 +- util/suffix.c | 170 ++++++++++++++++++-------- util/suffix.h | 4 +- util/types.c | 40 ++++-- util/types.h | 1 + 11 files changed, 489 insertions(+), 246 deletions(-) create mode 100644 util/crc32.c create mode 100644 util/crc32.h (limited to 'util') diff --git a/util/argconfig.c b/util/argconfig.c index 231a704..3eb885f 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -42,6 +42,12 @@ #include #include +#if __has_attribute(__fallthrough__) +#define fallthrough __attribute__((__fallthrough__)) +#else +#define fallthrough do {} while (0) +#endif + static argconfig_help_func *help_funcs[MAX_HELP_FUNC] = { NULL }; static char END_DEFAULT[] = "__end_default__"; @@ -122,69 +128,197 @@ static void show_option(const struct argconfig_commandline_options *option) } void argconfig_print_help(const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *s) { - const struct argconfig_commandline_options *s; - fprintf(stderr, "\033[1mUsage: %s\033[0m\n\n", append_usage_str); print_word_wrapped(program_desc, 0, 0, stderr); fprintf(stderr, "\n"); - if (!options || !options->option) + if (!s || !s->option) return; fprintf(stderr, "\n\033[1mOptions:\033[0m\n"); - for (s = options; (s != NULL) && (s->option != NULL); s++) + for (; s && s->option; s++) show_option(s); } +static int argconfig_error(char *type, const char *opt, const char *arg) +{ + fprintf(stderr, "Expected %s argument for '%s' but got '%s'!\n", type, opt, arg); + return -EINVAL; +} + int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val) { char *endptr; unsigned long tmp = strtoul(str, &endptr, 0); - if (errno || tmp >= 1 << 8 || str == endptr) { - fprintf(stderr, - "Expected byte argument for '%s' but got '%s'!\n", opt, - str); - return -EINVAL; - } + if (errno || tmp >= 1 << 8 || str == endptr) + return argconfig_error("byte", opt, str); *val = tmp; return 0; } +static int argconfig_parse_type(struct argconfig_commandline_options *s, struct option *option, + int index) +{ + void *value = (void *)(char *)s->default_value; + char *endptr; + const char *fopts = NULL; + FILE *f; + int ret = 0; + char **opts = ((char **)value); + int remaining_space = CFG_MAX_SUBOPTS - 2; + + switch (s->config_type) { + case CFG_STRING: + *((char **)value) = optarg; + break; + case CFG_SIZE: + *((size_t *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_INT: + *((int *)value) = strtol(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("integer", option[index].name, optarg); + break; + case CFG_BOOL: { + int tmp = strtol(optarg, &endptr, 0); + if (errno || tmp < 0 || tmp > 1 || optarg == endptr) + ret = argconfig_error("0 or 1", option[index].name, optarg); + else + *((int *)value) = tmp; + break; + } + case CFG_BYTE: + ret = argconfig_parse_byte(option[index].name, optarg, (uint8_t *)value); + break; + case CFG_SHORT: { + unsigned long tmp = strtoul(optarg, &endptr, 0); + if (errno || tmp >= 1 << 16 || optarg == endptr) + ret = argconfig_error("short", option[index].name, optarg); + else + *((uint16_t *)value) = tmp; + break; + } + case CFG_POSITIVE: { + uint32_t tmp = strtoul(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("word", option[index].name, optarg); + else + *((uint32_t *)value) = tmp; + break; + } + case CFG_INCREMENT: + *((int *)value) += 1; + break; + case CFG_LONG: + *((unsigned long *)value) = strtoul(optarg, &endptr, 0); + if (errno || optarg == endptr) + ret = argconfig_error("long integer", option[index].name, optarg); + break; + case CFG_LONG_SUFFIX: + ret = suffix_binary_parse(optarg, &endptr, (uint64_t*)value); + if (ret) + argconfig_error("long suffixed integer", option[index].name, optarg); + break; + case CFG_DOUBLE: + *((double *)value) = strtod(optarg, &endptr); + if (errno || optarg == endptr) + ret = argconfig_error("float", option[index].name, optarg); + break; + case CFG_SUBOPTS: + *opts = END_DEFAULT; + opts += 2; + ret = argconfig_parse_subopt_string(optarg, opts, remaining_space); + if (ret) { + if (ret == 2) + fprintf(stderr, "Error Parsing Sub-Options: Too many options!\n"); + else + fprintf(stderr, "Error Parsing Sub-Options\n"); + ret = -EINVAL; + } + break; + case CFG_FILE_A: + fopts = "a"; + fallthrough; + case CFG_FILE_R: + if (!fopts) + fopts = "r"; + fallthrough; + case CFG_FILE_W: + if (!fopts) + fopts = "w"; + fallthrough; + case CFG_FILE_AP: + if (!fopts) + fopts = "a+"; + fallthrough; + case CFG_FILE_RP: + if (!fopts) + fopts = "r+"; + fallthrough; + case CFG_FILE_WP: + if (!fopts) + fopts = "w+"; + f = fopen(optarg, fopts); + if (!f) { + fprintf(stderr, "Unable to open %s file: %s\n", s->option, optarg); + ret = -EINVAL; + } else { + *((FILE **)value) = f; + } + break; + case CFG_FLAG: + *((bool *)value) = true; + break; + default: + break; + } + + return ret; +} + +bool argconfig_output_format_json(bool set) +{ + static bool output_format_json = false; + + if (set) + output_format_json = true; + + return output_format_json; +} + int argconfig_parse(int argc, char *argv[], const char *program_desc, - const struct argconfig_commandline_options *options) + struct argconfig_commandline_options *options) { char *short_opts; - char *endptr; struct option *long_opts; - const struct argconfig_commandline_options *s; + struct argconfig_commandline_options *s; int c, option_index = 0, short_index = 0, options_count = 0; - void *value_addr; - int ret = -EINVAL; + int ret = 0; errno = 0; - for (s = options; s->option != NULL; s++) + for (s = options; s->option; s++) options_count++; - long_opts = malloc(sizeof(struct option) * (options_count + 2)); - short_opts = malloc(sizeof(*short_opts) * (options_count * 3 + 4)); + long_opts = calloc(1, sizeof(struct option) * (options_count + 3)); + short_opts = calloc(1, sizeof(*short_opts) * (options_count * 3 + 5)); if (!long_opts || !short_opts) { - fprintf(stderr, "failed to allocate memory for opts: %s\n", - strerror(errno)); + 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) { + for (s = options; s->option && option_index < options_count; s++) { + if (s->short_option) { short_opts[short_index++] = s->short_option; if (s->argument_type == required_argument || s->argument_type == optional_argument) @@ -195,35 +329,32 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (s->option && strlen(s->option)) { long_opts[option_index].name = s->option; long_opts[option_index].has_arg = s->argument_type; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 0; } + s->seen = false; 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++].val = 'h'; - long_opts[option_index].name = NULL; - long_opts[option_index].flag = NULL; - long_opts[option_index].val = 0; + long_opts[option_index].name = "json"; + long_opts[option_index].val = 'j'; short_opts[short_index++] = '?'; short_opts[short_index++] = 'h'; - short_opts[short_index] = 0; + short_opts[short_index] = 'j'; optind = 0; - while ((c = getopt_long_only(argc, argv, short_opts, long_opts, - &option_index)) != -1) { - if (c != 0) { + while ((c = getopt_long_only(argc, argv, short_opts, long_opts, &option_index)) != -1) { + if (c) { if (c == '?' || c == 'h') { argconfig_print_help(program_desc, options); - goto out; + ret = -EINVAL; + break; } - for (option_index = 0; option_index < options_count; - option_index++) { + if (c == 'j') + argconfig_output_format_json(true); + for (option_index = 0; option_index < options_count; option_index++) { if (c == options[option_index].short_option) break; } @@ -232,147 +363,16 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, } 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) { - if (argconfig_parse_byte(long_opts[option_index].name, - optarg, (uint8_t *)value_addr)) - goto out; - } 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) += 1; - } 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++; - } + s->seen = true; - if (!enddefault) { - *opts = END_DEFAULT; - remaining_space -= 2; - opts += 2; - } + if (!s->default_value) + continue; - 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; - } else if (s->config_type == CFG_FLAG) { - *((bool *)value_addr) = true; - } + ret = argconfig_parse_type(s, long_opts,option_index); + if (ret) + break; } - free(short_opts); - free(long_opts); - - return 0; - out: +out: free(short_opts); free(long_opts); return ret; @@ -592,3 +592,14 @@ void argconfig_register_help_func(argconfig_help_func * f) } } } + +bool argconfig_parse_seen(struct argconfig_commandline_options *s, + const char *option) +{ + for (; s && s->option; s++) { + if (!strcmp(s->option, option)) + return s->seen; + } + + return false; +} diff --git a/util/argconfig.h b/util/argconfig.h index 6ef3b6a..81eaaf4 100644 --- a/util/argconfig.h +++ b/util/argconfig.h @@ -38,6 +38,7 @@ #include #include #include +#include enum argconfig_types { CFG_FLAG, @@ -62,7 +63,7 @@ enum argconfig_types { }; #define OPT_ARGS(n) \ - const struct argconfig_commandline_options n[] + struct argconfig_commandline_options n[] #define OPT_END() { NULL } @@ -109,6 +110,7 @@ struct argconfig_commandline_options { void *default_value; int argument_type; const char *help; + bool seen; }; #define CFG_MAX_SUBOPTS 500 @@ -117,9 +119,9 @@ struct argconfig_commandline_options { 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); + struct argconfig_commandline_options *options); int argconfig_parse(int argc, char *argv[], const char *program_desc, - const struct argconfig_commandline_options *options); + struct argconfig_commandline_options *options); int argconfig_parse_subopt_string(char *string, char **options, size_t max_options); int argconfig_parse_comma_sep_array(char *string, int *ret, @@ -133,4 +135,7 @@ int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val); void argconfig_register_help_func(argconfig_help_func * f); void print_word_wrapped(const char *s, int indent, int start, FILE *stream); +bool argconfig_parse_seen(struct argconfig_commandline_options *options, + const char *option); +bool argconfig_output_format_json(bool set); #endif diff --git a/util/crc32.c b/util/crc32.c new file mode 100644 index 0000000..cc2d8f2 --- /dev/null +++ b/util/crc32.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* Copyright (C) 2002 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * 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 + + or both in parallel, as here. + + elfutils 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see . */ + +/* https://sourceware.org/git/?p=elfutils.git;a=blob;f=lib/crc32.c;hb=575198c29a427392823cc8f2400579a23d06a875 */ + +#include "crc32.h" + +/* Table computed with Mark Adler's makecrc.c utility. */ +static const uint32_t crc32_table[256] = +{ + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d +}; + +uint32_t crc32 (uint32_t crc, unsigned char *buf, size_t len) +{ + unsigned char *end; + + crc = ~crc; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc; +} diff --git a/util/crc32.h b/util/crc32.h new file mode 100644 index 0000000..e48c97d --- /dev/null +++ b/util/crc32.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef crc32_H +#define crc32_H + +#include +#include + +uint32_t crc32(uint32_t crc, unsigned char *buf, size_t len); + +#endif diff --git a/util/json.c b/util/json.c index 84d43e5..2de5848 100644 --- a/util/json.c +++ b/util/json.c @@ -35,10 +35,24 @@ struct json_object *util_json_object_new_uint64(uint64_t i) } +static int util_json_object_string_to_number(struct json_object *jso, + struct printbuf *pb, int level, + int flags) +{ + ssize_t len = json_object_get_string_len(jso); + + printbuf_memappend(pb, json_object_get_string(jso), len); + + return 0; +} + struct json_object *util_json_object_new_uint128(nvme_uint128_t val) { struct json_object *obj; + obj = json_object_new_string(uint128_t_to_string(val)); + json_object_set_serializer(obj, util_json_object_string_to_number, NULL, NULL); + return obj; } diff --git a/util/json.h b/util/json.h index 1312cb8..c362408 100644 --- a/util/json.h +++ b/util/json.h @@ -2,6 +2,7 @@ #ifndef __JSON__H #define __JSON__H +#ifdef CONFIG_JSONC #include #include "util/types.h" @@ -12,7 +13,7 @@ #define json_free_object(o) json_object_put(o) #define json_free_array(a) json_object_put(a) #define json_object_add_value_uint(o, k, v) \ - json_object_object_add(o, k, json_object_new_int(v)) + json_object_object_add(o, k, json_object_new_uint64(v)) #define json_object_add_value_int(o, k, v) \ json_object_object_add(o, k, json_object_new_int(v)) #ifndef CONFIG_JSONC_14 @@ -48,4 +49,11 @@ struct json_object *util_json_object_new_uint128(nvme_uint128_t val); struct json_object *util_json_object_new_uint128(nvme_uint128_t val); uint64_t util_json_object_get_uint64(struct json_object *obj); + +#else /* !CONFIG_JSONC */ + +struct json_object; + +#endif + #endif diff --git a/util/meson.build b/util/meson.build index 349c70c..f149d03 100644 --- a/util/meson.build +++ b/util/meson.build @@ -2,9 +2,15 @@ sources += [ 'util/argconfig.c', + 'util/base64.c', 'util/cleanup.c', - 'util/json.c', + 'util/crc32.c', 'util/suffix.c', - 'util/base64.c', 'util/types.c', ] + +if json_c_dep.found() + sources += [ + 'util/json.c', + ] +endif diff --git a/util/suffix.c b/util/suffix.c index 4106958..8ed080d 100644 --- a/util/suffix.c +++ b/util/suffix.c @@ -31,28 +31,31 @@ */ #include "suffix.h" +#include "common.h" #include #include #include #include +#include +#include +#include static struct si_suffix { long double magnitude; + unsigned int exponent; const char *suffix; } si_suffixes[] = { - {1e30, "Q"}, - {1e27, "R"}, - {1e24, "Y"}, - {1e21, "Z"}, - {1e18, "E"}, - {1e15, "P"}, - {1e12, "T"}, - {1e9, "G"}, - {1e6, "M"}, - {1e3, "k"}, - {1e0, ""}, - {0} + {1e30, 30, "Q"}, + {1e27, 27, "R"}, + {1e24, 24, "Y"}, + {1e21, 21, "Z"}, + {1e18, 18, "E"}, + {1e15, 15, "P"}, + {1e12, 12, "T"}, + {1e9, 9, "G"}, + {1e6, 6, "M"}, + {1e3, 3, "k"}, }; const char *suffix_si_get(double *value) @@ -65,36 +68,87 @@ const char *suffix_si_get(double *value) return suffix; } -uint64_t suffix_si_parse(const char *value, bool *suffixed) +int suffix_si_parse(const char *str, char **endptr, uint64_t *val) { - char *suffix; - double ret; - struct si_suffix *s; - - errno = 0; - ret = strtod(value, &suffix); - if (errno) + unsigned long long num, frac; + char *sep, *tmp; + int frac_len, len, i; + + num = strtoull(str, endptr, 0); + if (str == *endptr || + ((num == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + /* simple number, no decimal point not suffix */ + if ((*endptr)[0] == '\0') { + *val = num; return 0; + } + + /* get rid of the decimal point */ + sep = localeconv()->decimal_point; + if (sep) + len = strlen(sep); + else + len = 0; - for (s = si_suffixes; s->magnitude != 0; s++) { - if (suffix[0] == s->suffix[0]) { - if (suffixed && suffix[0] != '\0') - *suffixed = true; - return ret *= s->magnitude; + for (i = 0; i < len; i++) { + if (((*endptr)[i] == '\0') || (*endptr)[i] != sep[i]) + return -EINVAL; + } + *endptr += len; + tmp = *endptr; + + /* extract the digits after decimal point */ + frac = strtoull(tmp, endptr, 0); + if (tmp == *endptr || + ((frac == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + /* test that we have max one character as suffix */ + if ((*endptr)[0] != '\0' && (*endptr)[1] != '\0') + return -EINVAL; + + frac_len = *endptr - tmp; + + for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) { + struct si_suffix *s = &si_suffixes[i]; + + if ((*endptr)[0] != s->suffix[0]) + continue; + + /* we should check for overflow */ + for (int j = 0; j < s->exponent; j++) + num *= 10; + + if (s->exponent > frac_len) { + for (int j = 0; j < s->exponent - frac_len; j++) + frac *= 10; + } else if (s->exponent < frac_len) { + for (int j = 0; j < frac_len - s->exponent; j++) + frac /= 10; + } else { + frac = 0; } + + *val = num + frac; + return 0; } - if (suffix[0] != '\0') - errno = EINVAL; + if ((*endptr)[0] != '\0') + return -EINVAL; - return (uint64_t)ret; + *val = num; + return 0; } const char *suffix_si_get_ld(long double *value) { - struct si_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(si_suffixes); i++) { + struct si_suffix *s = &si_suffixes[i]; - for (s = si_suffixes; s->magnitude != 0; s++) { if (*value >= s->magnitude) { *value /= s->magnitude; return s->suffix; @@ -113,14 +167,15 @@ static struct binary_suffix { {30, "Gi"}, {20, "Mi"}, {10, "Ki"}, - {0, ""} }; const char *suffix_binary_get(long long *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (llabs(*value) >= (1LL << s->shift)) { *value = (*value + (1LL << (s->shift - 1))) / (1LL << s->shift); @@ -133,9 +188,11 @@ const char *suffix_binary_get(long long *value) const char *suffix_dbinary_get(double *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (fabs(*value) >= (1LL << s->shift)) { *value = *value / (1LL << s->shift); return s->suffix; @@ -145,24 +202,41 @@ const char *suffix_dbinary_get(double *value) return ""; } -uint64_t suffix_binary_parse(const char *value) +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val) { - char *suffix; - errno = 0; - uint64_t ret = strtoull(value, &suffix, 0); - if (errno) + uint64_t ret; + int i; + + ret = strtoull(str, endptr, 0); + if (str == *endptr || + ((ret == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + if (str == *endptr) { + *val = ret; + return 0; + } + + /* simple number, no decimal point, no suffix */ + if ((*endptr)[0] == '\0') { + *val = ret; return 0; + } - struct binary_suffix *s; - for (s = binary_suffixes; s->shift != 0; s++) { - if (tolower(suffix[0]) == tolower(s->suffix[0])) { + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; + + if (tolower((*endptr)[0]) == tolower(s->suffix[0]) && + (s->suffix[0] != '\0' && + (((*endptr)[0] != '\0' && + (*endptr)[1] != '\0' && + (*endptr)[2] == '\0') && + (tolower((*endptr)[1]) == tolower(s->suffix[1]))))) { ret <<= s->shift; - return ret; + *val = ret; + return 0; } } - if (suffix[0] != '\0') - errno = EINVAL; - - return ret; + return -EINVAL; } diff --git a/util/suffix.h b/util/suffix.h index b367ce4..5ea58f4 100644 --- a/util/suffix.h +++ b/util/suffix.h @@ -36,10 +36,10 @@ #include const char *suffix_si_get(double *value); -uint64_t suffix_si_parse(const char *value, bool *suffixed); +int suffix_si_parse(const char *str, char **endptr, uint64_t *val); const char *suffix_si_get_ld(long 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); +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val); #endif diff --git a/util/types.c b/util/types.c index 18ced77..daef298 100644 --- a/util/types.c +++ b/util/types.c @@ -46,14 +46,31 @@ uint64_t int48_to_long(__u8 *data) return result; } -char *uint128_t_to_string(nvme_uint128_t val) +static long double uint128_t_to_double(nvme_uint128_t data) +{ + int i; + long double result = 0; + + for (i = 0; i < sizeof(data.words) / sizeof(*data.words); i++) { + result *= 4294967296; + result += data.words[i]; + } + + return result; +} + +static char *__uint128_t_to_string(nvme_uint128_t val, bool l10n) { static char str[60]; int idx = 60; __u64 div, rem; - char *sep = localeconv()->thousands_sep; - int len = sep ? strlen(sep) : 0; - int i; + char *sep = NULL; + int i, len = 0; + + if (l10n) { + sep = localeconv()->thousands_sep; + len = strlen(sep); + } /* terminate at the end, and build up from the ones */ str[--idx] = '\0'; @@ -88,17 +105,14 @@ char *uint128_t_to_string(nvme_uint128_t val) return str + idx; } -static long double uint128_t_to_double(nvme_uint128_t data) +char *uint128_t_to_string(nvme_uint128_t val) { - int i; - long double result = 0; - - for (i = 0; i < sizeof(data.words) / sizeof(*data.words); i++) { - result *= 4294967296; - result += data.words[i]; - } + return __uint128_t_to_string(val, false); +} - return result; +char *uint128_t_to_l10n_string(nvme_uint128_t val) +{ + return __uint128_t_to_string(val, true); } char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit) diff --git a/util/types.h b/util/types.h index 2e88717..f7fe9fc 100644 --- a/util/types.h +++ b/util/types.h @@ -29,6 +29,7 @@ long double int128_to_double(__u8 *data); uint64_t int48_to_long(__u8 *data); char *uint128_t_to_string(nvme_uint128_t val); +char *uint128_t_to_l10n_string(nvme_uint128_t val); char *uint128_t_to_si_string(nvme_uint128_t val, __u32 bytes_per_unit); const char *util_uuid_to_string(unsigned char uuid[NVME_UUID_LEN]); const char *util_fw_to_string(char *c); -- cgit v1.2.3