qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Gerd Hoffmann <kraxel@redhat.com>
To: qemu-devel@nongnu.org
Cc: Gerd Hoffmann <kraxel@redhat.com>
Subject: [Qemu-devel] [PATCH v3 4/5] QemuOpts: framework for storing and parsing options.
Date: Thu, 16 Jul 2009 16:57:03 +0200	[thread overview]
Message-ID: <1247756224-19219-5-git-send-email-kraxel@redhat.com> (raw)
In-Reply-To: <1247756224-19219-1-git-send-email-kraxel@redhat.com>

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 <kraxel@redhat.com>
---
 Makefile.target |    2 +-
 qemu-opts.c     |  242 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-opts.h     |   36 ++++++++
 3 files changed, 279 insertions(+), 1 deletions(-)
 create mode 100644 qemu-opts.c
 create mode 100644 qemu-opts.h

diff --git a/Makefile.target b/Makefile.target
index 1a71f3a..61e9588 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -490,7 +490,7 @@ endif #CONFIG_BSD_USER
 ifndef CONFIG_USER_ONLY
 
 obj-y = vl.o osdep.o monitor.o pci.o loader.o isa_mmio.o machine.o \
-        gdbstub.o gdbstub-xml.o msix.o ioport.o
+        gdbstub.o gdbstub-xml.o msix.o ioport.o qemu-opts.o
 # virtio has to be here due to weird dependency between PCI and virtio-net.
 # need to fix this properly
 obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-console.o
diff --git a/qemu-opts.c b/qemu-opts.c
new file mode 100644
index 0000000..31b87dd
--- /dev/null
+++ b/qemu-opts.c
@@ -0,0 +1,242 @@
+#include "sysemu.h"
+#include "qemu-option.h"
+#include "qemu-opts.h"
+
+struct QemuOpt {
+    const char *name;
+    const char *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->value : NULL;
+}
+
+int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
+{
+    QemuOpt *opt;
+    int i;
+
+    opt = qemu_opt_find(opts, name);
+    if (!opt) {
+        for (i = 0; opts->list->valid[i] != NULL; i++) {
+            if (strcmp(opts->list->valid[i], name) == 0) {
+                break;
+            }
+        }
+        if (opts->list->valid[i] == 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);
+    }
+    qemu_free((/* !const */ char*)opt->value);
+    opt->value = NULL;
+    if (value) {
+        opt->value = qemu_strdup(value);
+    }
+    return 0;
+}
+
+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->value);
+    qemu_free(opt);
+}
+
+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->value);
+    }
+    fprintf(stderr, "\n");
+    return 0;
+}
+
+QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params)
+{
+    char option[128], value[128], *id = NULL;
+    QemuOpts *opts;
+    const char *p;
+
+    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(;;) {
+        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) {
+            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;
+}
+
+#if 0 /* for testing only */
+
+static QemuOptsList drivetest = {
+    .name  = "drivetest",
+    .head  = TAILQ_HEAD_INITIALIZER(drivetest.head),
+    .valid = { "bus", "unit", "if", "index",
+               "cyls", "heads", "secs", "trans",
+               "media", "snapshot", "file",
+               "cache", "format", "serial",
+               "werror", "addr",
+               NULL },
+};
+
+void qemu_opts_drivetest_add(const char *file, const char *params)
+{
+    QemuOpts *opts;
+
+    opts = qemu_opts_parse(&drivetest, params);
+    if (!opts) {
+        fprintf(stderr, "%s: huh? duplicate? (%s)\n",
+                __FUNCTION__, params);
+        return;
+    }
+    if (file)
+        qemu_opt_set(opts, "file", file);
+}
+
+void qemu_opts_drivetest_print(void)
+{
+    qemu_opts_foreach(&drivetest, qemu_opts_print, NULL, 0);
+}
+
+#endif
diff --git a/qemu-opts.h b/qemu-opts.h
new file mode 100644
index 0000000..85a3390
--- /dev/null
+++ b/qemu-opts.h
@@ -0,0 +1,36 @@
+#ifndef QEMU_OPTS_H
+#define QEMU_OPTS_H
+
+#include "sys-queue.h"
+
+typedef struct QemuOpt QemuOpt;
+typedef struct QemuOpts QemuOpts;
+typedef struct QemuOptsList QemuOptsList;
+
+struct QemuOptsList {
+    const char *name;
+    TAILQ_HEAD(, QemuOpts) head;
+    const char *valid[];
+};
+
+const char *qemu_opt_get(QemuOpts *opts, const char *name);
+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);
+
+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);
+
+#if 0 /* for testing only */
+void qemu_opts_drivetest_add(const char *file, const char *params);
+void qemu_opts_drivetest_print(void);
+#endif
+
+#endif /* QEMU_OPTS_H */
-- 
1.6.2.5

  parent reply	other threads:[~2009-07-16 14:57 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-07-16 14:56 [Qemu-devel] [PATCH v3 0/5] cleanup drive handling Gerd Hoffmann
2009-07-16 14:57 ` [Qemu-devel] [PATCH v3 1/5] kill drives_table Gerd Hoffmann
2009-07-16 14:57 ` [Qemu-devel] [PATCH v3 2/5] add support for drive ids Gerd Hoffmann
2009-07-16 14:57 ` [Qemu-devel] [PATCH v3 3/5] kill drives_opt Gerd Hoffmann
2009-07-16 14:57 ` Gerd Hoffmann [this message]
2009-07-16 16:35   ` [Qemu-devel] Re: [PATCH v3 4/5] QemuOpts: framework for storing and parsing options Jan Kiszka
2009-07-16 18:50     ` Gerd Hoffmann
2009-07-17  7:03   ` [Qemu-devel] " Kevin Wolf
2009-07-21  7:25     ` Gerd Hoffmann
2009-07-21  7:42       ` Kevin Wolf
2009-07-21 13:59     ` Gerd Hoffmann
2009-07-21 15:58       ` Kevin Wolf
2009-07-22  6:58         ` Gerd Hoffmann
2009-07-22  7:31           ` Kevin Wolf
2009-07-22  7:55             ` Gerd Hoffmann
2009-07-16 14:57 ` [Qemu-devel] [PATCH v3 5/5] switch -drive to QemuOpts Gerd Hoffmann
2009-07-16 16:07   ` Anthony Liguori
2009-07-16 18:55     ` Gerd Hoffmann
2009-07-16 19:03       ` Anthony Liguori
2009-07-16 19:32         ` Gerd Hoffmann
2009-07-16 20:08           ` Anthony Liguori

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1247756224-19219-5-git-send-email-kraxel@redhat.com \
    --to=kraxel@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).