qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v6 7/8] QemuOpts: framework for storing and parsing


From: Gerd Hoffmann
Subject: [Qemu-devel] [PATCH v6 7/8] QemuOpts: framework for storing and parsing options.
Date: Wed, 22 Jul 2009 16:43:03 +0200

This stores device parameters in a better way than unparsed strings.

New types:
  QemuOpt       -  one key-value pair.
  QemuOpts      -  group of key-value pairs, belonging to one
                   device, i.e. one drive.
  QemuOptsList  -  list of some kind of devices, i.e. all drives.

Functions are provided to work with these types.  The plan is that some
day we will pass around QemuOpts pointers instead of strings filled with
"key1=value1,key2=value2".

Check out the next patch to see all this in action ;)

Signed-off-by: Gerd Hoffmann <address@hidden>
---
 qemu-option.c |  314 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-option.h |   45 ++++++++
 2 files changed, 359 insertions(+), 0 deletions(-)

diff --git a/qemu-option.c b/qemu-option.c
index 819b8e5..73c2175 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -182,6 +182,24 @@ static int parse_option_bool(const char *name, const char 
*value, int *ret)
     return 0;
 }
 
+static int parse_option_number(const char *name, const char *value, uint64_t 
*ret)
+{
+    char *postfix;
+    uint64_t number;
+
+    if (value != NULL) {
+        number = strtoull(value, &postfix, 0);
+        if (*postfix != '\0') {
+            fprintf(stderr, "Option '%s' needs a number as parameter\n", name);
+            return -1;
+        }
+    } else {
+        fprintf(stderr, "Option '%s' needs a parameter\n", name);
+        return -1;
+    }
+    return 0;
+}
+
 static int parse_option_size(const char *name, const char *value, uint64_t 
*ret)
 {
     char *postfix;
@@ -444,3 +462,299 @@ void print_option_help(QEMUOptionParameter *list)
         list++;
     }
 }
+
+/* ------------------------------------------------------------------ */
+
+struct QemuOpt {
+    const char   *name;
+    const char   *str;
+
+    QemuOptDesc  *desc;
+    union {
+        int      bool;
+        uint64_t uint;
+    } value;
+
+    QemuOpts     *opts;
+    TAILQ_ENTRY(QemuOpt) next;
+};
+
+struct QemuOpts {
+    const char *id;
+    QemuOptsList *list;
+    TAILQ_HEAD(, QemuOpt) head;
+    TAILQ_ENTRY(QemuOpts) next;
+};
+
+static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
+{
+    QemuOpt *opt;
+
+    TAILQ_FOREACH(opt, &opts->head, next) {
+        if (strcmp(opt->name, name) != 0)
+            continue;
+        return opt;
+    }
+    return NULL;
+}
+
+const char *qemu_opt_get(QemuOpts *opts, const char *name)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+    return opt ? opt->str : NULL;
+}
+
+int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
+    return opt->value.bool;
+}
+
+uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
+    return opt->value.uint;
+}
+
+uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
+{
+    QemuOpt *opt = qemu_opt_find(opts, name);
+
+    if (opt == NULL)
+        return defval;
+    assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
+    return opt->value.uint;
+}
+
+static int qemu_opt_parse(QemuOpt *opt)
+{
+    if (opt->desc == NULL)
+        return 0;
+    switch (opt->desc->type) {
+    case QEMU_OPT_STRING:
+        /* nothing */
+        return 0;
+    case QEMU_OPT_BOOL:
+        return parse_option_bool(opt->name, opt->str, &opt->value.bool);
+    case QEMU_OPT_NUMBER:
+        return parse_option_number(opt->name, opt->str, &opt->value.uint);
+    case QEMU_OPT_SIZE:
+        return parse_option_size(opt->name, opt->str, &opt->value.uint);
+    default:
+        abort();
+    }
+}
+
+static void qemu_opt_del(QemuOpt *opt)
+{
+    TAILQ_REMOVE(&opt->opts->head, opt, next);
+    qemu_free((/* !const */ char*)opt->name);
+    qemu_free((/* !const */ char*)opt->str);
+    qemu_free(opt);
+}
+
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+    QemuOpt *opt;
+
+    opt = qemu_opt_find(opts, name);
+    if (!opt) {
+        QemuOptDesc *desc = opts->list->desc;
+        int i;
+
+        for (i = 0; desc[i].name != NULL; i++) {
+            if (strcmp(desc[i].name, name) == 0) {
+                break;
+            }
+        }
+        if (desc[i].name == NULL) {
+            if (i == 0) {
+                /* empty list -> allow any */;
+            } else {
+                fprintf(stderr, "option \"%s\" is not valid for %s\n",
+                        name, opts->list->name);
+                return -1;
+            }
+        }
+        opt = qemu_mallocz(sizeof(*opt));
+        opt->name = qemu_strdup(name);
+        opt->opts = opts;
+        TAILQ_INSERT_TAIL(&opts->head, opt, next);
+        if (desc[i].name != NULL) {
+            opt->desc = desc+i;
+        }
+    }
+    qemu_free((/* !const */ char*)opt->str);
+    opt->str = NULL;
+    if (value) {
+        opt->str = qemu_strdup(value);
+    }
+    if (qemu_opt_parse(opt) < 0) {
+        fprintf(stderr, "Failed to parse \"%s\" for \"%s.%s\"\n", opt->str,
+                opts->list->name, opt->name);
+        qemu_opt_del(opt);
+        return -1;
+    }
+    return 0;
+}
+
+QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
+{
+    QemuOpts *opts;
+
+    TAILQ_FOREACH(opts, &list->head, next) {
+        if (!opts->id) {
+            continue;
+        }
+        if (strcmp(opts->id, id) != 0) {
+            continue;
+        }
+        return opts;
+    }
+    return NULL;
+}
+
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int 
fail_if_exists)
+{
+    QemuOpts *opts = NULL;
+
+    if (id) {
+        opts = qemu_opts_find(list, id);
+        if (opts != NULL) {
+            if (fail_if_exists) {
+                fprintf(stderr, "tried to create id \"%s\" twice for \"%s\"\n",
+                        id, list->name);
+                return NULL;
+            } else {
+                return opts;
+            }
+        }
+    }
+    opts = qemu_mallocz(sizeof(*opts));
+    if (id) {
+        opts->id = qemu_strdup(id);
+    }
+    opts->list = list;
+    TAILQ_INIT(&opts->head);
+    TAILQ_INSERT_TAIL(&list->head, opts, next);
+    return opts;
+}
+
+int qemu_opts_set(QemuOptsList *list, const char *id,
+                  const char *name, const char *value)
+{
+    QemuOpts *opts;
+
+    opts = qemu_opts_create(list, id, 1);
+    if (opts == NULL) {
+        fprintf(stderr, "id \"%s\" not found for \"%s\"\n",
+                id, list->name);
+        return -1;
+    }
+    return qemu_opt_set(opts, name, value);
+}
+
+void qemu_opts_del(QemuOpts *opts)
+{
+    QemuOpt *opt;
+
+    for (;;) {
+        opt = TAILQ_FIRST(&opts->head);
+        if (opt == NULL)
+            break;
+        qemu_opt_del(opt);
+    }
+    TAILQ_REMOVE(&opts->list->head, opts, next);
+    qemu_free(opts);
+}
+
+int qemu_opts_print(QemuOpts *opts, void *dummy)
+{
+    QemuOpt *opt;
+
+    fprintf(stderr, "%s: %s:", opts->list->name,
+            opts->id ? opts->id : "<noid>");
+    TAILQ_FOREACH(opt, &opts->head, next) {
+        fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
+
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char 
*firstname)
+{
+    char option[128], value[128], *id = NULL;
+    QemuOpts *opts;
+    const char *p,*pe,*pc;
+
+    if (get_param_value(value, sizeof(value), "id", params))
+        id = qemu_strdup(value);
+    opts = qemu_opts_create(list, id, 1);
+    if (opts == NULL)
+        return NULL;
+
+    p = params;
+    for(;;) {
+        pe = strchr(p, '=');
+        pc = strchr(p, ',');
+        if (!pe || (pc && pc < pe)) {
+            /* found "foo,more" */
+            if (p == params && firstname) {
+                /* implicitly named first option */
+                pstrcpy(option, sizeof(option), firstname);
+                p = get_opt_value(value, sizeof(value), p);
+            } else {
+                /* option without value, probably a flag */
+                p = get_opt_name(option, sizeof(option), p, ',');
+                if (strncmp(p, "no", 2) == 0) {
+                    memmove(option, option+2, strlen(option+2)+1);
+                    pstrcpy(value, sizeof(value), "off");
+                } else {
+                    pstrcpy(value, sizeof(value), "on");
+                }
+            }
+        } else {
+            /* found "foo=bar,more" */
+            p = get_opt_name(option, sizeof(option), p, '=');
+            if (*p != '=') {
+                break;
+            }
+            p++;
+            p = get_opt_value(value, sizeof(value), p);
+        }
+        if (strcmp(option, "id") != 0) {
+            /* store and parse */
+            if (-1 == qemu_opt_set(opts, option, value)) {
+                qemu_opts_del(opts);
+                return NULL;
+            }
+        }
+        if (*p != ',') {
+            break;
+        }
+        p++;
+    }
+    return opts;
+}
+
+int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void 
*opaque,
+                      int abort_on_failure)
+{
+    QemuOpts *opts;
+    int rc = 0;
+
+    TAILQ_FOREACH(opts, &list->head, next) {
+        rc = func(opts, opaque);
+        if (abort_on_failure  &&  rc != 0)
+            break;
+    }
+    return rc;
+}
diff --git a/qemu-option.h b/qemu-option.h
index 267abae..428c947 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -26,6 +26,8 @@
 #ifndef QEMU_OPTIONS_H
 #define QEMU_OPTIONS_H
 
+#include "sys-queue.h"
+
 enum QEMUOptionParType {
     OPT_FLAG,
     OPT_NUMBER,
@@ -72,4 +74,47 @@ void free_option_parameters(QEMUOptionParameter *list);
 void print_option_parameters(QEMUOptionParameter *list);
 void print_option_help(QEMUOptionParameter *list);
 
+/* ------------------------------------------------------------------ */
+
+typedef struct QemuOpt QemuOpt;
+typedef struct QemuOpts QemuOpts;
+typedef struct QemuOptsList QemuOptsList;
+
+enum QemuOptType {
+    QEMU_OPT_STRING = 0,  /* no parsing (use string as-is)                     
   */
+    QEMU_OPT_BOOL,        /* on/off                                            
   */
+    QEMU_OPT_NUMBER,      /* simple number                                     
   */
+    QEMU_OPT_SIZE,        /* size, accepts (K)ilo, (M)ega, (G)iga, (T)era 
postfix */
+};
+
+typedef struct QemuOptDesc {
+    const char *name;
+    enum QemuOptType type;
+    const char *help;
+} QemuOptDesc;
+
+struct QemuOptsList {
+    const char *name;
+    TAILQ_HEAD(, QemuOpts) head;
+    QemuOptDesc desc[];
+};
+
+const char *qemu_opt_get(QemuOpts *opts, const char *name);
+int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
+uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t 
defval);
+uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
+
+QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id);
+QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int 
fail_if_exists);
+int qemu_opts_set(QemuOptsList *list, const char *id,
+                  const char *name, const char *value);
+void qemu_opts_del(QemuOpts *opts);
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char 
*firstname);
+
+typedef int (*qemu_opts_loopfunc)(QemuOpts *opts, void *opaque);
+int qemu_opts_print(QemuOpts *opts, void *dummy);
+int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void 
*opaque,
+                      int abort_on_failure);
+
 #endif
-- 
1.6.2.5





reply via email to

[Prev in Thread] Current Thread [Next in Thread]