Adding upstream version 1.12.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
3b95ae912c
commit
ac60c09ef6
457 changed files with 159628 additions and 0 deletions
534
util/argconfig.c
Normal file
534
util/argconfig.c
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
130
util/argconfig.h
Normal file
130
util/argconfig.h
Normal file
|
@ -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
|
407
util/json.c
Normal file
407
util/json.c
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
88
util/json.h
Normal file
88
util/json.h
Normal file
|
@ -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
|
284
util/parser.c
Normal file
284
util/parser.c
Normal file
|
@ -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;
|
||||
}
|
34
util/parser.h
Normal file
34
util/parser.h
Normal file
|
@ -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 *);
|
132
util/suffix.c
Normal file
132
util/suffix.c
Normal file
|
@ -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;
|
||||
}
|
41
util/suffix.h
Normal file
41
util/suffix.h
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue