#include <string.h>
#include <errno.h>
#include <limits.h>
+#include <stdlib.h>
#include "parse.h"
#include "debug.h"
+static struct fio_option *fio_options;
+
static int vp_cmp(const void *p1, const void *p2)
{
const struct value_pair *vp1 = p1;
*/
int str_to_decimal(const char *str, long long *val, int kilo)
{
- int len;
+ int len, base;
len = strlen(str);
if (!len)
return 1;
- *val = strtoll(str, NULL, 10);
+ if (strstr(str, "0x") || strstr(str, "0X"))
+ base = 16;
+ else
+ base = 10;
+
+ *val = strtoll(str, NULL, base);
if (*val == LONG_MAX && errno == ERANGE)
return 1;
void strip_blank_end(char *p)
{
- char *s;
+ char *start = p, *s;
s = strchr(p, ';');
if (s)
p = s;
s = p + strlen(p);
- while ((isspace(*s) || iscntrl(*s)) && (s > p))
+ while ((isspace(*s) || iscntrl(*s)) && (s > start))
s--;
*(s + 1) = '\0';
dprint(FD_PARSE, "__handle_option=%s, type=%d, ptr=%s\n", o->name,
o->type, ptr);
- if (!ptr && o->type != FIO_OPT_STR_SET) {
+ if (!ptr && o->type != FIO_OPT_STR_SET && o->type != FIO_OPT_STR) {
fprintf(stderr, "Option %s requires an argument\n", o->name);
return 1;
}
}
case FIO_OPT_STR_VAL_TIME:
is_time = 1;
+ case FIO_OPT_INT:
case FIO_OPT_STR_VAL:
case FIO_OPT_STR_VAL_INT: {
fio_opt_str_val_fn *fn = o->cb;
if (fn)
ret = fn(data, &ull);
else {
- if (o->type == FIO_OPT_STR_VAL_INT) {
+ if (o->type == FIO_OPT_STR_VAL_INT ||
+ o->type == FIO_OPT_INT) {
if (first)
val_store(ilp, ull, o->off1, data);
if (!more && o->off2)
break;
}
- case FIO_OPT_INT:
case FIO_OPT_BOOL: {
fio_opt_int_fn *fn = o->cb;
}
break;
}
+ case FIO_OPT_DEPRECATED:
+ fprintf(stdout, "Option %s is deprecated\n", o->name);
+ break;
default:
fprintf(stderr, "Bad option type %u\n", o->type);
ret = 1;
return r1 && r2;
}
+static struct fio_option *get_option(const char *opt,
+ struct fio_option *options, char **post)
+{
+ struct fio_option *o;
+ char *ret;
+
+ ret = strchr(opt, '=');
+ if (ret) {
+ *post = ret;
+ *ret = '\0';
+ ret = (char *) opt;
+ (*post)++;
+ strip_blank_end(ret);
+ o = find_option(options, ret);
+ } else {
+ o = find_option(options, opt);
+ *post = NULL;
+ }
+
+ return o;
+}
+
+static int opt_cmp(const void *p1, const void *p2)
+{
+ struct fio_option *o1, *o2;
+ char *s1, *s2, *foo;
+ int prio1, prio2;
+
+ s1 = strdup(*((char **) p1));
+ s2 = strdup(*((char **) p2));
+
+ o1 = get_option(s1, fio_options, &foo);
+ o2 = get_option(s2, fio_options, &foo);
+
+ prio1 = prio2 = 0;
+ if (o1)
+ prio1 = o1->prio;
+ if (o2)
+ prio2 = o2->prio;
+
+ free(s1);
+ free(s2);
+ return prio2 - prio1;
+}
+
+void sort_options(char **opts, struct fio_option *options, int num_opts)
+{
+ fio_options = options;
+ qsort(opts, num_opts, sizeof(char *), opt_cmp);
+ fio_options = NULL;
+}
+
int parse_cmd_option(const char *opt, const char *val,
struct fio_option *options, void *data)
{
o = find_option(options, opt);
if (!o) {
- fprintf(stderr, "Bad option %s\n", opt);
+ fprintf(stderr, "Bad option <%s>\n", opt);
return 1;
}
return 1;
}
+/*
+ * Return a copy of the input string with substrings of the form ${VARNAME}
+ * substituted with the value of the environment variable VARNAME. The
+ * substitution always occurs, even if VARNAME is empty or the corresponding
+ * environment variable undefined.
+ */
+static char *option_dup_subs(const char *opt)
+{
+ char out[OPT_LEN_MAX+1];
+ char in[OPT_LEN_MAX+1];
+ char *outptr = out;
+ char *inptr = in;
+ char *ch1, *ch2, *env;
+ ssize_t nchr = OPT_LEN_MAX;
+ size_t envlen;
+
+ in[OPT_LEN_MAX] = '\0';
+ strncpy(in, opt, OPT_LEN_MAX);
+
+ while (*inptr && nchr > 0) {
+ if (inptr[0] == '$' && inptr[1] == '{') {
+ ch2 = strchr(inptr, '}');
+ if (ch2 && inptr+1 < ch2) {
+ ch1 = inptr+2;
+ inptr = ch2+1;
+ *ch2 = '\0';
+
+ env = getenv(ch1);
+ if (env) {
+ envlen = strlen(env);
+ if (envlen <= nchr) {
+ memcpy(outptr, env, envlen);
+ outptr += envlen;
+ nchr -= envlen;
+ }
+ }
+
+ continue;
+ }
+ }
+
+ *outptr++ = *inptr++;
+ --nchr;
+ }
+
+ *outptr = '\0';
+ return strdup(out);
+}
+
int parse_option(const char *opt, struct fio_option *options, void *data)
{
struct fio_option *o;
- char *pre, *post;
- char *tmp;
-
- tmp = strdup(opt);
-
- pre = strchr(tmp, '=');
- if (pre) {
- post = pre;
- *pre = '\0';
- pre = tmp;
- post++;
- o = find_option(options, pre);
- } else {
- o = find_option(options, tmp);
- post = NULL;
- }
+ char *post, *tmp;
+ tmp = option_dup_subs(opt);
+
+ o = get_option(tmp, options, &post);
if (!o) {
- fprintf(stderr, "Bad option %s\n", tmp);
+ fprintf(stderr, "Bad option <%s>\n", tmp);
free(tmp);
return 1;
}
for (o = &options[0]; o->name; o++) {
int match = 0;
+ if (o->type == FIO_OPT_DEPRECATED)
+ continue;
+
if (name) {
if (!strcmp(name, o->name) ||
(o->alias && !strcmp(name, o->alias)))
dprint(FD_PARSE, "init options\n");
for (o = &options[0]; o->name; o++) {
+ if (o->type == FIO_OPT_DEPRECATED)
+ continue;
if (o->type == FIO_OPT_BOOL) {
o->minval = 0;
o->maxval = 1;