qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH RFC] remove QEMUOptionParameter


From: Dong Xu Wang
Subject: [Qemu-devel] [PATCH RFC] remove QEMUOptionParameter
Date: Thu, 6 Sep 2012 11:13:31 +0800

QEMU now has QEMUOptionParameter and QemuOpts to parse parameters, so we can
remove one safely. This RFC removed QEMUOptionParameter and use QemuOpts. But
the patch is not completed, I think it is better to send a RFC first. In the
RFC, I only allow qcow2 and raw file format and did not test it completly, if
you have any concerns and suggestions about the main idea, please let me know,
that wil be very grateful.

Signed-off-by: Dong Xu Wang <address@hidden>
---
 block.c             |  106 ++++++++-----
 block.h             |    8 +-
 block/Makefile.objs |    9 +-
 block/qcow2.c       |  123 ++++----------
 block/raw-posix.c   |   45 +----
 block/raw.c         |   12 +--
 block_int.h         |    5 +-
 qemu-config.c       |   85 ++++++++++
 qemu-img.c          |   67 ++++----
 qemu-option.c       |  456 +++++++++++++++++++--------------------------------
 qemu-option.h       |   47 +-----
 11 files changed, 417 insertions(+), 546 deletions(-)

diff --git a/block.c b/block.c
index 470bdcc..8e973ff 100644
--- a/block.c
+++ b/block.c
@@ -351,7 +351,7 @@ BlockDriver *bdrv_find_whitelisted_format(const char 
*format_name)
 typedef struct CreateCo {
     BlockDriver *drv;
     char *filename;
-    QEMUOptionParameter *options;
+    QemuOpts *options;
     int ret;
 } CreateCo;
 
@@ -364,7 +364,7 @@ static void coroutine_fn bdrv_create_co_entry(void *opaque)
 }
 
 int bdrv_create(BlockDriver *drv, const char* filename,
-    QEMUOptionParameter *options)
+    QemuOpts *opts)
 {
     int ret;
 
@@ -372,7 +372,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
     CreateCo cco = {
         .drv = drv,
         .filename = g_strdup(filename),
-        .options = options,
+        .options = opts,
         .ret = NOT_DONE,
     };
 
@@ -397,7 +397,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
     return ret;
 }
 
-int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
+int bdrv_create_file(const char *filename, QemuOpts *opts)
 {
     BlockDriver *drv;
 
@@ -406,7 +406,7 @@ int bdrv_create_file(const char* filename, 
QEMUOptionParameter *options)
         return -ENOENT;
     }
 
-    return bdrv_create(drv, filename, options);
+    return bdrv_create(drv, filename, opts);
 }
 
 /*
@@ -742,8 +742,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, 
int flags,
         int64_t total_size;
         int is_protocol = 0;
         BlockDriver *bdrv_qcow2;
-        QEMUOptionParameter *options;
+        QemuOpts *options;
         char backing_filename[PATH_MAX];
+        char buf_total_size[1024];
 
         /* if snapshot, we create a temporary backing file and open it
            instead of opening 'filename' directly */
@@ -775,17 +776,19 @@ int bdrv_open(BlockDriverState *bs, const char *filename, 
int flags,
             return -errno;
 
         bdrv_qcow2 = bdrv_find_format("qcow2");
-        options = parse_option_parameters("", bdrv_qcow2->create_options, 
NULL);
+        options = qemu_opts_create(qemu_find_opts("qcow2_create_options"),
+            NULL, 0, NULL);
 
-        set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
-        set_option_parameter(options, BLOCK_OPT_BACKING_FILE, 
backing_filename);
+        snprintf(buf_total_size, sizeof(buf_total_size),
+            "%" PRId64, total_size);
+        qemu_opt_set(options, BLOCK_OPT_SIZE, buf_total_size);
+        qemu_opt_set(options, BLOCK_OPT_BACKING_FILE, backing_filename);
         if (drv) {
-            set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
+            qemu_opt_set(options, BLOCK_OPT_BACKING_FMT,
                 drv->format_name);
         }
 
         ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
-        free_option_parameters(options);
         if (ret < 0) {
             return ret;
         }
@@ -3901,12 +3904,16 @@ int bdrv_img_create(const char *filename, const char 
*fmt,
                     const char *base_filename, const char *base_fmt,
                     char *options, uint64_t img_size, int flags)
 {
-    QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *backing_fmt, *backing_file, *size;
+    QemuOpts *param = NULL;
+    QemuOptsList *create_options = NULL;
+    const char *backing_fmt, *backing_file, *size;
     BlockDriverState *bs = NULL;
     BlockDriver *drv, *proto_drv;
     BlockDriver *backing_drv = NULL;
     int ret = 0;
+    char buf_img_size[1024];
+    char create_buff[1024];
+    char proto_buff[1024];
 
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
@@ -3922,20 +3929,19 @@ int bdrv_img_create(const char *filename, const char 
*fmt,
         ret = -EINVAL;
         goto out;
     }
-
-    create_options = append_option_parameters(create_options,
-                                              drv->create_options);
-    create_options = append_option_parameters(create_options,
-                                              proto_drv->create_options);
-
+    get_format_create_options(create_buff, sizeof(create_buff), drv);
+    get_proto_create_options(proto_buff, sizeof(proto_buff), proto_drv);
+    create_options = append_opts_list(qemu_find_opts(create_buff),
+                                              qemu_find_opts(proto_buff));
     /* Create parameter list with default values */
-    param = parse_option_parameters("", create_options, param);
+    param = qemu_opts_create(create_options, NULL, 0, NULL);
 
-    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
+    snprintf(buf_img_size, sizeof(buf_img_size), "%" PRId64, img_size);
+    qemu_opt_set(param, BLOCK_OPT_SIZE, buf_img_size);
 
     /* Parse -o options */
     if (options) {
-        param = parse_option_parameters(options, create_options, param);
+        param = parse_opts_list(options, create_options, param);
         if (param == NULL) {
             error_report("Invalid options for file format '%s'.", fmt);
             ret = -EINVAL;
@@ -3944,7 +3950,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
     }
 
     if (base_filename) {
-        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
+        if (qemu_opt_set(param, BLOCK_OPT_BACKING_FILE,
                                  base_filename)) {
             error_report("Backing file not supported for file format '%s'",
                          fmt);
@@ -3954,7 +3960,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
     }
 
     if (base_fmt) {
-        if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+        if (qemu_opt_set(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
             error_report("Backing file format not supported for file "
                          "format '%s'", fmt);
             ret = -EINVAL;
@@ -3962,9 +3968,9 @@ int bdrv_img_create(const char *filename, const char *fmt,
         }
     }
 
-    backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
-    if (backing_file && backing_file->value.s) {
-        if (!strcmp(filename, backing_file->value.s)) {
+    backing_file = qemu_opt_get(param, BLOCK_OPT_BACKING_FILE);
+    if (backing_file) {
+        if (!strcmp(filename, backing_file)) {
             error_report("Error: Trying to create an image with the "
                          "same filename as the backing file");
             ret = -EINVAL;
@@ -3972,12 +3978,12 @@ int bdrv_img_create(const char *filename, const char 
*fmt,
         }
     }
 
-    backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
-    if (backing_fmt && backing_fmt->value.s) {
-        backing_drv = bdrv_find_format(backing_fmt->value.s);
+    backing_fmt = qemu_opt_get(param, BLOCK_OPT_BACKING_FMT);
+    if (backing_fmt) {
+        backing_drv = bdrv_find_format(backing_fmt);
         if (!backing_drv) {
             error_report("Unknown backing file format '%s'",
-                         backing_fmt->value.s);
+                         backing_fmt);
             ret = -EINVAL;
             goto out;
         }
@@ -3985,9 +3991,9 @@ int bdrv_img_create(const char *filename, const char *fmt,
 
     // The size for the image must always be specified, with one exception:
     // If we are using a backing file, we can obtain the size from there
-    size = get_option_parameter(param, BLOCK_OPT_SIZE);
-    if (size && size->value.n == -1) {
-        if (backing_file && backing_file->value.s) {
+    size = qemu_opt_get(param, BLOCK_OPT_SIZE);
+    if (size && !strcmp(size, "-1")) {
+        if (backing_file) {
             uint64_t size;
             char buf[32];
             int back_flags;
@@ -3998,16 +4004,16 @@ int bdrv_img_create(const char *filename, const char 
*fmt,
 
             bs = bdrv_new("");
 
-            ret = bdrv_open(bs, backing_file->value.s, back_flags, 
backing_drv);
+            ret = bdrv_open(bs, backing_file, back_flags, backing_drv);
             if (ret < 0) {
-                error_report("Could not open '%s'", backing_file->value.s);
+                error_report("Could not open '%s'", backing_file);
                 goto out;
             }
             bdrv_get_geometry(bs, &size);
             size *= 512;
 
             snprintf(buf, sizeof(buf), "%" PRId64, size);
-            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
+            qemu_opt_set(param, BLOCK_OPT_SIZE, buf);
         } else {
             error_report("Image creation needs a size parameter");
             ret = -EINVAL;
@@ -4016,7 +4022,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
     }
 
     printf("Formatting '%s', fmt=%s ", filename, fmt);
-    print_option_parameters(param);
+    qemu_opts_print(param, NULL);
     puts("");
 
     ret = bdrv_create(drv, filename, param);
@@ -4035,8 +4041,7 @@ int bdrv_img_create(const char *filename, const char *fmt,
     }
 
 out:
-    free_option_parameters(create_options);
-    free_option_parameters(param);
+    free_opts_list(create_options);
 
     if (bs) {
         bdrv_delete(bs);
@@ -4171,3 +4176,24 @@ void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, 
int64_t ns)
         job->busy = true;
     }
 }
+
+void get_proto_create_options(char *proto_buff,
+    int buf_len, BlockDriver *proto_drv)
+{
+    if (strcmp(proto_drv->format_name, "host_device") ||
+        strcmp(proto_drv->format_name, "host_floppy") ||
+        strcmp(proto_drv->format_name, "host_cdrom")) {
+        snprintf(proto_buff, buf_len,
+            "%s", "file_proto_create_opts");
+    } else {
+        snprintf(proto_buff, buf_len,
+            "%s""_proto_create_opts", proto_drv->format_name);
+    }
+}
+
+void get_format_create_options(char *create_buff, int buf_len, BlockDriver* 
drv)
+{
+    snprintf(create_buff, buf_len,
+            "%s""_create_opts", drv->format_name);
+}
+
diff --git a/block.h b/block.h
index 2e2be11..04ec173 100644
--- a/block.h
+++ b/block.h
@@ -119,8 +119,8 @@ BlockDriver *bdrv_find_protocol(const char *filename);
 BlockDriver *bdrv_find_format(const char *format_name);
 BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 int bdrv_create(BlockDriver *drv, const char* filename,
-    QEMUOptionParameter *options);
-int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
+    QemuOpts *options);
+int bdrv_create_file(const char *filename, QemuOpts *options);
 BlockDriverState *bdrv_new(const char *device_name);
 void bdrv_make_anon(BlockDriverState *bs);
 void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
@@ -405,4 +405,8 @@ typedef enum {
 #define BLKDBG_EVENT(bs, evt) bdrv_debug_event(bs, evt)
 void bdrv_debug_event(BlockDriverState *bs, BlkDebugEvent event);
 
+void get_proto_create_options(char *proto_buff,
+    int buf_len, BlockDriver *proto_drv);
+void get_format_create_options(char *create_buff,
+    int buf_len, BlockDriver *drv);
 #endif
diff --git a/block/Makefile.objs b/block/Makefile.objs
index b5754d3..19de020 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -1,8 +1,9 @@
-block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o 
vvfat.o
+#block-obj-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o 
vvfat.o
 block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o 
qcow2-cache.o
-block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
-block-obj-y += qed-check.o
-block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+#block-obj-y += qed.o qed-gencb.o qed-l2-cache.o qed-table.o qed-cluster.o
+#block-obj-y += qed-check.o
+#block-obj-y += parallels.o nbd.o blkdebug.o sheepdog.o blkverify.o
+block-obj-y += raw.o
 block-obj-y += stream.o
 block-obj-$(CONFIG_WIN32) += raw-win32.o
 block-obj-$(CONFIG_POSIX) += raw-posix.o
diff --git a/block/qcow2.c b/block/qcow2.c
index 8f183f1..c0f3764 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1170,7 +1170,7 @@ static int preallocate(BlockDriverState *bs)
 static int qcow2_create2(const char *filename, int64_t total_size,
                          const char *backing_file, const char *backing_format,
                          int flags, size_t cluster_size, int prealloc,
-                         QEMUOptionParameter *options, int version)
+                         QemuOpts *options, int version)
 {
     /* Calculate cluster_bits */
     int cluster_bits;
@@ -1201,6 +1201,7 @@ static int qcow2_create2(const char *filename, int64_t 
total_size,
     uint8_t* refcount_table;
     int ret;
 
+    qemu_opt_set(options, BLOCK_OPT_SIZE, "0");
     ret = bdrv_create_file(filename, options);
     if (ret < 0) {
         return ret;
@@ -1304,7 +1305,7 @@ out:
     return ret;
 }
 
-static int qcow2_create(const char *filename, QEMUOptionParameter *options)
+static int qcow2_create(const char *filename, QemuOpts *param)
 {
     const char *backing_file = NULL;
     const char *backing_fmt = NULL;
@@ -1313,45 +1314,41 @@ static int qcow2_create(const char *filename, 
QEMUOptionParameter *options)
     size_t cluster_size = DEFAULT_CLUSTER_SIZE;
     int prealloc = 0;
     int version = 2;
+    const char *buf;
 
     /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            sectors = options->value.n / 512;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
-            backing_fmt = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
-            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
-        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
-            if (options->value.n) {
-                cluster_size = options->value.n;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
-            if (!options->value.s || !strcmp(options->value.s, "off")) {
-                prealloc = 0;
-            } else if (!strcmp(options->value.s, "metadata")) {
-                prealloc = 1;
-            } else {
-                fprintf(stderr, "Invalid preallocation mode: '%s'\n",
-                    options->value.s);
-                return -EINVAL;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
-            if (!options->value.s || !strcmp(options->value.s, "0.10")) {
-                version = 2;
-            } else if (!strcmp(options->value.s, "1.1")) {
-                version = 3;
-            } else {
-                fprintf(stderr, "Invalid compatibility level: '%s'\n",
-                    options->value.s);
-                return -EINVAL;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
-            flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0;
-        }
-        options++;
+    sectors = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0) / 512;
+    backing_file = qemu_opt_get(param, BLOCK_OPT_BACKING_FILE);
+    backing_fmt = qemu_opt_get(param, BLOCK_OPT_BACKING_FMT);
+    if (qemu_opt_get_bool(param, BLOCK_OPT_ENCRYPT, 0)) {
+        flags |= BLOCK_FLAG_ENCRYPT;
+    }
+    cluster_size =
+        qemu_opt_get_size(param, BLOCK_OPT_CLUSTER_SIZE, DEFAULT_CLUSTER_SIZE);
+    buf = qemu_opt_get(param, BLOCK_OPT_PREALLOC);
+    if (!buf || !strcmp(buf, "off")) {
+        prealloc = 0;
+    } else if (!strcmp(buf, "metadata")) {
+        prealloc = 1;
+    } else {
+        fprintf(stderr, "Invalid preallocation mode: '%s'\n",
+            buf);
+        return -EINVAL;
+    }
+
+    buf = qemu_opt_get(param, BLOCK_OPT_COMPAT_LEVEL);
+    if (!buf || !strcmp(buf, "0.10")) {
+        version = 2;
+    } else if (!strcmp(buf, "1.1")) {
+        version = 3;
+    } else {
+        fprintf(stderr, "Invalid compatibility level: '%s'\n",
+            buf);
+        return -EINVAL;
+    }
+
+    if (qemu_opt_get_bool(param, BLOCK_OPT_LAZY_REFCOUNTS, 0)) {
+        flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
     }
 
     if (backing_file && prealloc) {
@@ -1367,7 +1364,7 @@ static int qcow2_create(const char *filename, 
QEMUOptionParameter *options)
     }
 
     return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
-                         cluster_size, prealloc, options, version);
+                         cluster_size, prealloc, param, version);
 }
 
 static int qcow2_make_empty(BlockDriverState *bs)
@@ -1628,51 +1625,6 @@ static int qcow2_load_vmstate(BlockDriverState *bs, 
uint8_t *buf,
     return ret;
 }
 
-static QEMUOptionParameter qcow2_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    {
-        .name = BLOCK_OPT_COMPAT_LEVEL,
-        .type = OPT_STRING,
-        .help = "Compatibility level (0.10 or 1.1)"
-    },
-    {
-        .name = BLOCK_OPT_BACKING_FILE,
-        .type = OPT_STRING,
-        .help = "File name of a base image"
-    },
-    {
-        .name = BLOCK_OPT_BACKING_FMT,
-        .type = OPT_STRING,
-        .help = "Image format of the base image"
-    },
-    {
-        .name = BLOCK_OPT_ENCRYPT,
-        .type = OPT_FLAG,
-        .help = "Encrypt the image"
-    },
-    {
-        .name = BLOCK_OPT_CLUSTER_SIZE,
-        .type = OPT_SIZE,
-        .help = "qcow2 cluster size",
-        .value = { .n = DEFAULT_CLUSTER_SIZE },
-    },
-    {
-        .name = BLOCK_OPT_PREALLOC,
-        .type = OPT_STRING,
-        .help = "Preallocation mode (allowed values: off, metadata)"
-    },
-    {
-        .name = BLOCK_OPT_LAZY_REFCOUNTS,
-        .type = OPT_FLAG,
-        .help = "Postpone refcount updates",
-    },
-    { NULL }
-};
-
 static BlockDriver bdrv_qcow2 = {
     .format_name        = "qcow2",
     .instance_size      = sizeof(BDRVQcowState),
@@ -1707,7 +1659,6 @@ static BlockDriver bdrv_qcow2 = {
 
     .bdrv_invalidate_cache      = qcow2_invalidate_cache,
 
-    .create_options = qcow2_create_options,
     .bdrv_check = qcow2_check,
 };
 
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6be20b1..bcce7ed 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -558,19 +558,13 @@ static int64_t 
raw_get_allocated_file_size(BlockDriverState *bs)
     return (int64_t)st.st_blocks * 512;
 }
 
-static int raw_create(const char *filename, QEMUOptionParameter *options)
+static int raw_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int result = 0;
     int64_t total_size = 0;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / BDRV_SECTOR_SIZE;
-        }
-        options++;
-    }
+    total_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
 
     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
                    0644);
@@ -720,15 +714,6 @@ static coroutine_fn int raw_co_discard(BlockDriverState 
*bs,
     return 0;
 }
 
-static QEMUOptionParameter raw_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
-};
-
 static BlockDriver bdrv_file = {
     .format_name = "file",
     .protocol_name = "file",
@@ -748,8 +733,6 @@ static BlockDriver bdrv_file = {
     .bdrv_getlength = raw_getlength,
     .bdrv_get_allocated_file_size
                         = raw_get_allocated_file_size,
-
-    .create_options = raw_create_options,
 };
 
 /***********************************************/
@@ -962,20 +945,14 @@ static int fd_open(BlockDriverState *bs)
 
 #endif /* !linux && !FreeBSD */
 
-static int hdev_create(const char *filename, QEMUOptionParameter *options)
+static int hdev_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int ret = 0;
     struct stat stat_buf;
     int64_t total_size = 0;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, "size")) {
-            total_size = options->value.n / BDRV_SECTOR_SIZE;
-        }
-        options++;
-    }
+    total_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
 
     fd = qemu_open(filename, O_WRONLY | O_BINARY);
     if (fd < 0)
@@ -999,21 +976,20 @@ static int hdev_has_zero_init(BlockDriverState *bs)
 
 static BlockDriver bdrv_host_device = {
     .format_name        = "host_device",
-    .protocol_name        = "host_device",
+    .protocol_name      = "host_device",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device  = hdev_probe_device,
     .bdrv_file_open     = hdev_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
-    .bdrv_aio_readv    = raw_aio_readv,
-    .bdrv_aio_writev   = raw_aio_writev,
-    .bdrv_aio_flush    = raw_aio_flush,
+    .bdrv_aio_readv     = raw_aio_readv,
+    .bdrv_aio_writev    = raw_aio_writev,
+    .bdrv_aio_flush     = raw_aio_flush,
 
     .bdrv_truncate      = raw_truncate,
-    .bdrv_getlength    = raw_getlength,
+    .bdrv_getlength     = raw_getlength,
     .bdrv_get_allocated_file_size
                         = raw_get_allocated_file_size,
 
@@ -1126,7 +1102,6 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_file_open     = floppy_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
@@ -1225,7 +1200,6 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
@@ -1344,7 +1318,6 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_file_open     = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
diff --git a/block/raw.c b/block/raw.c
index ff34ea4..a6a6758 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -87,20 +87,11 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
    return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
 }
 
-static int raw_create(const char *filename, QEMUOptionParameter *options)
+static int raw_create(const char *filename, QemuOpts *options)
 {
     return bdrv_create_file(filename, options);
 }
 
-static QEMUOptionParameter raw_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
-};
-
 static int raw_has_zero_init(BlockDriverState *bs)
 {
     return bdrv_has_zero_init(bs->file);
@@ -133,7 +124,6 @@ static BlockDriver bdrv_raw = {
     .bdrv_aio_ioctl     = raw_aio_ioctl,
 
     .bdrv_create        = raw_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = raw_has_zero_init,
 };
 
diff --git a/block_int.h b/block_int.h
index 4452f6f..5eea367 100644
--- a/block_int.h
+++ b/block_int.h
@@ -147,7 +147,7 @@ struct BlockDriver {
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
     void (*bdrv_rebind)(BlockDriverState *bs);
-    int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
+    int (*bdrv_create)(const char *filename, QemuOpts *options);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
     /* aio */
@@ -236,9 +236,6 @@ struct BlockDriver {
         unsigned long int req, void *buf,
         BlockDriverCompletionFunc *cb, void *opaque);
 
-    /* List of options for creating images, terminated by name == NULL */
-    QEMUOptionParameter *create_options;
-
 
     /*
      * Returns 0 for completed check, -errno for internal errors.
diff --git a/qemu-config.c b/qemu-config.c
index c05ffbc..0376c92 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -5,6 +5,87 @@
 #include "hw/qdev.h"
 #include "error.h"
 
+#include "block_int.h"
+#define QCOW2_DEFAULT_CLUSTER_SIZE 65536
+
+static QemuOptsList file_proto_create_opts = {
+    .name = "file_proto_create_opts",
+    .head = QTAILQ_HEAD_INITIALIZER(file_proto_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
+};
+
+/************************************************************/
+static QemuOptsList raw_create_opts = {
+    .name = "raw_create_opts",
+    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
+};
+
+static QemuOptsList qcow2_create_opts = {
+    .name = "qcow2_create_opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_COMPAT_LEVEL,
+            .type = QEMU_OPT_STRING,
+            .help = "Compatibility level (0.10 or 1.1)"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FMT,
+            .type = QEMU_OPT_STRING,
+            .help = "Image format of the base image"
+        },
+        {
+            .name = BLOCK_OPT_ENCRYPT,
+            .type = QEMU_OPT_BOOL,
+            .help = "Encrypt the image"
+        },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "qcow2 cluster size",
+            .def_value = QCOW2_DEFAULT_CLUSTER_SIZE
+        },
+        {
+            .name = BLOCK_OPT_PREALLOC,
+            .type = QEMU_OPT_STRING,
+            .help = "Preallocation mode (allowed values: off, metadata)"
+        },
+        {
+            .name = BLOCK_OPT_LAZY_REFCOUNTS,
+            .type = QEMU_OPT_BOOL,
+            .help = "Postpone refcount updates",
+        },
+        { /* end of list */ }
+    }
+};
+
+/*******************************************************************/
+
 static QemuOptsList qemu_drive_opts = {
     .name = "drive",
     .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
@@ -659,6 +740,10 @@ static QemuOptsList *vm_config_groups[32] = {
     &qemu_boot_opts,
     &qemu_iscsi_opts,
     &qemu_sandbox_opts,
+
+    &file_proto_create_opts,
+    &raw_create_opts,
+    &qcow2_create_opts,
     NULL,
 };
 
diff --git a/qemu-img.c b/qemu-img.c
index b41e670..a442b5e 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -195,7 +195,9 @@ static int read_password(char *buf, int buf_size)
 static int print_block_option_help(const char *filename, const char *fmt)
 {
     BlockDriver *drv, *proto_drv;
-    QEMUOptionParameter *create_options = NULL;
+    QemuOptsList *create_options = NULL;
+    char create_buff[1024];
+    char proto_buff[1024];
 
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
@@ -209,13 +211,12 @@ static int print_block_option_help(const char *filename, 
const char *fmt)
         error_report("Unknown protocol '%s'", filename);
         return 1;
     }
-
-    create_options = append_option_parameters(create_options,
-                                              drv->create_options);
-    create_options = append_option_parameters(create_options,
-                                              proto_drv->create_options);
-    print_option_help(create_options);
-    free_option_parameters(create_options);
+    get_format_create_options(create_buff, sizeof(create_buff), drv);
+    get_proto_create_options(proto_buff, sizeof(proto_buff), proto_drv);
+    create_options = append_opts_list(qemu_find_opts(create_buff),
+                                              qemu_find_opts(proto_buff));
+    print_opts_list(create_options);
+    free_opts_list(create_options);
     return 0;
 }
 
@@ -265,19 +266,19 @@ fail:
     return NULL;
 }
 
-static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
+static int add_old_style_options(const char *fmt, QemuOpts *list,
                                  const char *base_filename,
                                  const char *base_fmt)
 {
     if (base_filename) {
-        if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE, base_filename)) 
{
+        if (qemu_opt_set(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
             error_report("Backing file not supported for file format '%s'",
                          fmt);
             return -1;
         }
     }
     if (base_fmt) {
-        if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+        if (qemu_opt_set(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
             error_report("Backing file format not supported for file "
                          "format '%s'", fmt);
             return -1;
@@ -664,12 +665,15 @@ static int img_convert(int argc, char **argv)
     uint8_t * buf = NULL;
     const uint8_t *buf1;
     BlockDriverInfo bdi;
-    QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *out_baseimg_param;
+    QemuOpts *param = NULL;
+    QemuOptsList *create_options = NULL;
+    const char *out_baseimg_param;
     char *options = NULL;
     const char *snapshot_name = NULL;
     float local_progress;
     int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
+    char buf_size[1024];
+    char create_buff[1024], proto_buff[1024];
 
     fmt = NULL;
     out_fmt = "raw";
@@ -800,40 +804,40 @@ static int img_convert(int argc, char **argv)
         goto out;
     }
 
-    create_options = append_option_parameters(create_options,
-                                              drv->create_options);
-    create_options = append_option_parameters(create_options,
-                                              proto_drv->create_options);
+    get_format_create_options(create_buff, sizeof(create_buff), drv);
+    get_proto_create_options(proto_buff, sizeof(proto_buff), proto_drv);
+    create_options = append_opts_list(qemu_find_opts(create_buff),
+                                              qemu_find_opts(proto_buff));
 
     if (options) {
-        param = parse_option_parameters(options, create_options, param);
+        param = parse_opts_list(options, create_options, param);
         if (param == NULL) {
             error_report("Invalid options for file format '%s'.", out_fmt);
             ret = -1;
             goto out;
         }
     } else {
-        param = parse_option_parameters("", create_options, param);
+        param = qemu_opts_create(create_options, NULL, 0, NULL);
     }
-
-    set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
+    snprintf(buf_size, sizeof(buf_size), "%" PRId64, total_sectors * 512);
+    qemu_opt_set(param, BLOCK_OPT_SIZE, buf_size);
     ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
     if (ret < 0) {
         goto out;
     }
 
     /* Get backing file name if -o backing_file was used */
-    out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+    out_baseimg_param = qemu_opt_get(param, BLOCK_OPT_BACKING_FILE);
     if (out_baseimg_param) {
-        out_baseimg = out_baseimg_param->value.s;
+        out_baseimg = out_baseimg_param;
     }
 
     /* Check if compression is supported */
     if (compress) {
-        QEMUOptionParameter *encryption =
-            get_option_parameter(param, BLOCK_OPT_ENCRYPT);
-        QEMUOptionParameter *preallocation =
-            get_option_parameter(param, BLOCK_OPT_PREALLOC);
+        const char *encryption =
+            qemu_opt_get(param, BLOCK_OPT_ENCRYPT);
+        const char *preallocation =
+            qemu_opt_get(param, BLOCK_OPT_PREALLOC);
 
         if (!drv->bdrv_write_compressed) {
             error_report("Compression not supported for this file format");
@@ -841,15 +845,15 @@ static int img_convert(int argc, char **argv)
             goto out;
         }
 
-        if (encryption && encryption->value.n) {
+        if (encryption) {
             error_report("Compression and encryption not supported at "
                          "the same time");
             ret = -1;
             goto out;
         }
 
-        if (preallocation && preallocation->value.s
-            && strcmp(preallocation->value.s, "off"))
+        if (preallocation
+            && strcmp(preallocation, "off"))
         {
             error_report("Compression and preallocation not supported at "
                          "the same time");
@@ -1063,8 +1067,7 @@ static int img_convert(int argc, char **argv)
     }
 out:
     qemu_progress_end();
-    free_option_parameters(create_options);
-    free_option_parameters(param);
+    free_opts_list(create_options);
     qemu_vfree(buf);
     if (out_bs) {
         bdrv_delete(out_bs);
diff --git a/qemu-option.c b/qemu-option.c
index 27891e7..b83ca52 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -153,22 +153,6 @@ int check_params(char *buf, int buf_size,
     return 0;
 }
 
-/*
- * Searches an option list for an option with the given name
- */
-QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
-    const char *name)
-{
-    while (list && list->name) {
-        if (!strcmp(list->name, name)) {
-            return list;
-        }
-        list++;
-    }
-
-    return NULL;
-}
-
 static void parse_option_bool(const char *name, const char *value, bool *ret,
                               Error **errp)
 {
@@ -240,275 +224,6 @@ static void parse_option_size(const char *name, const 
char *value,
     }
 }
 
-/*
- * Sets the value of a parameter in a given option list. The parsing of the
- * value depends on the type of option:
- *
- * OPT_FLAG (uses value.n):
- *      If no value is given, the flag is set to 1.
- *      Otherwise the value must be "on" (set to 1) or "off" (set to 0)
- *
- * OPT_STRING (uses value.s):
- *      value is strdup()ed and assigned as option value
- *
- * OPT_SIZE (uses value.n):
- *      The value is converted to an integer. Suffixes for kilobytes etc. are
- *      allowed (powers of 1024).
- *
- * Returns 0 on succes, -1 in error cases
- */
-int set_option_parameter(QEMUOptionParameter *list, const char *name,
-    const char *value)
-{
-    bool flag;
-    Error *local_err = NULL;
-
-    // Find a matching parameter
-    list = get_option_parameter(list, name);
-    if (list == NULL) {
-        fprintf(stderr, "Unknown option '%s'\n", name);
-        return -1;
-    }
-
-    // Process parameter
-    switch (list->type) {
-    case OPT_FLAG:
-        parse_option_bool(name, value, &flag, &local_err);
-        if (!error_is_set(&local_err)) {
-            list->value.n = flag;
-        }
-        break;
-
-    case OPT_STRING:
-        if (value != NULL) {
-            list->value.s = g_strdup(value);
-        } else {
-            fprintf(stderr, "Option '%s' needs a parameter\n", name);
-            return -1;
-        }
-        break;
-
-    case OPT_SIZE:
-        parse_option_size(name, value, &list->value.n, &local_err);
-        break;
-
-    default:
-        fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
-        return -1;
-    }
-
-    if (error_is_set(&local_err)) {
-        qerror_report_err(local_err);
-        error_free(local_err);
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Sets the given parameter to an integer instead of a string.
- * This function cannot be used to set string options.
- *
- * Returns 0 on success, -1 in error cases
- */
-int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
-    uint64_t value)
-{
-    // Find a matching parameter
-    list = get_option_parameter(list, name);
-    if (list == NULL) {
-        fprintf(stderr, "Unknown option '%s'\n", name);
-        return -1;
-    }
-
-    // Process parameter
-    switch (list->type) {
-    case OPT_FLAG:
-    case OPT_NUMBER:
-    case OPT_SIZE:
-        list->value.n = value;
-        break;
-
-    default:
-        return -1;
-    }
-
-    return 0;
-}
-
-/*
- * Frees a option list. If it contains strings, the strings are freed as well.
- */
-void free_option_parameters(QEMUOptionParameter *list)
-{
-    QEMUOptionParameter *cur = list;
-
-    while (cur && cur->name) {
-        if (cur->type == OPT_STRING) {
-            g_free(cur->value.s);
-        }
-        cur++;
-    }
-
-    g_free(list);
-}
-
-/*
- * Count valid options in list
- */
-static size_t count_option_parameters(QEMUOptionParameter *list)
-{
-    size_t num_options = 0;
-
-    while (list && list->name) {
-        num_options++;
-        list++;
-    }
-
-    return num_options;
-}
-
-/*
- * Append an option list (list) to an option list (dest).
- *
- * If dest is NULL, a new copy of list is created.
- *
- * Returns a pointer to the first element of dest (or the newly allocated copy)
- */
-QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
-    QEMUOptionParameter *list)
-{
-    size_t num_options, num_dest_options;
-
-    num_options = count_option_parameters(dest);
-    num_dest_options = num_options;
-
-    num_options += count_option_parameters(list);
-
-    dest = g_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
-    dest[num_dest_options].name = NULL;
-
-    while (list && list->name) {
-        if (get_option_parameter(dest, list->name) == NULL) {
-            dest[num_dest_options++] = *list;
-            dest[num_dest_options].name = NULL;
-        }
-        list++;
-    }
-
-    return dest;
-}
-
-/*
- * Parses a parameter string (param) into an option list (dest).
- *
- * list is the template option list. If dest is NULL, a new copy of list is
- * created. If list is NULL, this function fails.
- *
- * A parameter string consists of one or more parameters, separated by commas.
- * Each parameter consists of its name and possibly of a value. In the latter
- * case, the value is delimited by an = character. To specify a value which
- * contains commas, double each comma so it won't be recognized as the end of
- * the parameter.
- *
- * For more details of the parsing see above.
- *
- * Returns a pointer to the first element of dest (or the newly allocated copy)
- * or NULL in error cases
- */
-QEMUOptionParameter *parse_option_parameters(const char *param,
-    QEMUOptionParameter *list, QEMUOptionParameter *dest)
-{
-    QEMUOptionParameter *allocated = NULL;
-    char name[256];
-    char value[256];
-    char *param_delim, *value_delim;
-    char next_delim;
-
-    if (list == NULL) {
-        return NULL;
-    }
-
-    if (dest == NULL) {
-        dest = allocated = append_option_parameters(NULL, list);
-    }
-
-    while (*param) {
-
-        // Find parameter name and value in the string
-        param_delim = strchr(param, ',');
-        value_delim = strchr(param, '=');
-
-        if (value_delim && (value_delim < param_delim || !param_delim)) {
-            next_delim = '=';
-        } else {
-            next_delim = ',';
-            value_delim = NULL;
-        }
-
-        param = get_opt_name(name, sizeof(name), param, next_delim);
-        if (value_delim) {
-            param = get_opt_value(value, sizeof(value), param + 1);
-        }
-        if (*param != '\0') {
-            param++;
-        }
-
-        // Set the parameter
-        if (set_option_parameter(dest, name, value_delim ? value : NULL)) {
-            goto fail;
-        }
-    }
-
-    return dest;
-
-fail:
-    // Only free the list if it was newly allocated
-    free_option_parameters(allocated);
-    return NULL;
-}
-
-/*
- * Prints all options of a list that have a value to stdout
- */
-void print_option_parameters(QEMUOptionParameter *list)
-{
-    while (list && list->name) {
-        switch (list->type) {
-            case OPT_STRING:
-                 if (list->value.s != NULL) {
-                     printf("%s='%s' ", list->name, list->value.s);
-                 }
-                break;
-            case OPT_FLAG:
-                printf("%s=%s ", list->name, list->value.n ? "on" : "off");
-                break;
-            case OPT_SIZE:
-            case OPT_NUMBER:
-                printf("%s=%" PRId64 " ", list->name, list->value.n);
-                break;
-            default:
-                printf("%s=(unknown type) ", list->name);
-                break;
-        }
-        list++;
-    }
-}
-
-/*
- * Prints an overview of all available options
- */
-void print_option_help(QEMUOptionParameter *list)
-{
-    printf("Supported options:\n");
-    while (list && list->name) {
-        printf("%-16s %s\n", list->name,
-            list->help ? list->help : "No description available");
-        list++;
-    }
-}
-
 /* ------------------------------------------------------------------ */
 
 static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
@@ -832,14 +547,36 @@ void qemu_opts_del(QemuOpts *opts)
 
 int qemu_opts_print(QemuOpts *opts, void *dummy)
 {
-    QemuOpt *opt;
+    QemuOpt *opt = NULL;
+    QemuOptDesc *desc = opts->list->desc;
 
-    fprintf(stderr, "%s: %s:", opts->list->name,
-            opts->id ? opts->id : "<noid>");
-    QTAILQ_FOREACH(opt, &opts->head, next) {
-        fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
+    while (desc && desc->name) {
+        opt = qemu_opt_find(opts, desc->name);
+        switch (desc->type) {
+        case QEMU_OPT_STRING:
+            if (opt != NULL) {
+                printf("%s='%s' ", opt->name, opt->str);
+            }
+            break;
+        case QEMU_OPT_BOOL:
+            printf("%s=%s ", desc->name, (opt && opt->str) ? "on" : "off");
+            break;
+        case QEMU_OPT_NUMBER:
+        case QEMU_OPT_SIZE:
+            if (strcmp(desc->name, "cluster_size")) {
+                printf("%s=%" PRId64 " ", desc->name,
+                    (opt && opt->value.uint) ? opt->value.uint : 0);
+            } else {
+                printf("%s=%" PRId64 " ", desc->name,
+                    (opt && opt->value.uint) ? opt->value.uint : 
desc->def_value);
+            }
+            break;
+        default:
+            printf("%s=(unknown type) ", desc->name);
+            break;
+        }
+        desc++;
     }
-    fprintf(stderr, "\n");
     return 0;
 }
 
@@ -1110,3 +847,140 @@ int qemu_opts_foreach(QemuOptsList *list, 
qemu_opts_loopfunc func, void *opaque,
     loc_pop(&loc);
     return rc;
 }
+
+static size_t count_opts_list(QemuOptsList *list)
+{
+    size_t i = 0;
+
+    while (list && list->desc[i].name) {
+        i++;
+    }
+
+    return i;
+}
+
+static bool opts_desc_find(QemuOptsList *list, const char *name)
+{
+    const QemuOptDesc *desc = list->desc;
+    int i;
+
+    for (i = 0; desc[i].name != NULL; i++) {
+        if (strcmp(desc[i].name, name) == 0) {
+            return true;;
+        }
+    }
+    return false;
+}
+
+/* merge two QemuOptsLists to one and return it. */
+QemuOptsList *append_opts_list(QemuOptsList *first,
+    QemuOptsList *second)
+{
+    size_t num_first_options, num_second_options;
+    QemuOptsList *dest = NULL;
+    int i = 0;
+    int index = 0;
+
+    num_first_options = count_opts_list(first);
+    num_second_options = count_opts_list(second);
+    if (num_first_options + num_second_options == 0) {
+        return NULL;
+    }
+
+    dest = g_malloc0(sizeof(QemuOptsList)
+        + (num_first_options + num_second_options) * sizeof(QemuOptDesc));
+
+    if (first) {
+        memcpy(dest, first, sizeof(QemuOptsList));
+    } else if (second) {
+        memcpy(dest, second, sizeof(QemuOptsList));
+    }
+
+    while (first && (first->desc[i].name)) {
+        if (!opts_desc_find(dest, first->desc[i].name)) {
+            dest->desc[index].name = strdup(first->desc[i].name);
+            dest->desc[index].help = strdup(first->desc[i].help);
+            dest->desc[index].type = first->desc[i].type;
+            dest->desc[index].def_value = first->desc[i].def_value;
+            dest->desc[++index].name = NULL;
+        }
+        i++;
+    }
+    i = 0;
+    while (second && (second->desc[i].name)) {
+        if (!opts_desc_find(dest, second->desc[i].name)) {
+            dest->desc[index].name = strdup(first->desc[i].name);
+            dest->desc[index].help = strdup(first->desc[i].help);
+            dest->desc[index].type = second->desc[i].type;
+            dest->desc[index].def_value = second->desc[i].def_value;
+            dest->desc[++i].name = NULL;
+        }
+        i++;
+    }
+    return dest;
+}
+
+void free_opts_list(QemuOptsList *list)
+{
+    int i = 0;
+
+    while (list && list->desc[i].name) {
+        g_free((char *)list->desc[i].name);
+        g_free((char *)list->desc[i].help);
+        i++;
+    }
+
+    g_free(list);
+}
+
+void print_opts_list(QemuOptsList *list)
+{
+    int i = 0;
+    printf("Supported options:\n");
+    while (list && list->desc[i].name) {
+        printf("%-16s %s\n", list->desc[i].name,
+            list->desc[i].help ? list->desc[i].help : "No description 
available");
+        i++;
+    }
+}
+
+QemuOpts *parse_opts_list(const char *param,
+    QemuOptsList *list, QemuOpts *dest)
+{
+    char name[256];
+    char value[256];
+    char *param_delim, *value_delim;
+    char next_delim;
+
+    if (list == NULL) {
+        return NULL;
+    }
+    while (*param) {
+        param_delim = strchr(param, ',');
+        value_delim = strchr(param, '=');
+
+        if (value_delim && (value_delim < param_delim || !param_delim)) {
+            next_delim = '=';
+        } else {
+            next_delim = ',';
+            value_delim = NULL;
+        }
+
+        param = get_opt_name(name, sizeof(name), param, next_delim);
+        if (value_delim) {
+            param = get_opt_value(value, sizeof(value), param + 1);
+        }
+        if (*param != '\0') {
+            param++;
+        }
+
+        if (qemu_opt_set(dest, name, value_delim ? value : NULL)) {
+            goto fail;
+        }
+    }
+
+    return dest;
+
+fail:
+    return NULL;
+}
diff --git a/qemu-option.h b/qemu-option.h
index ca72986..75718fe 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -31,24 +31,6 @@
 #include "error.h"
 #include "qdict.h"
 
-enum QEMUOptionParType {
-    OPT_FLAG,
-    OPT_NUMBER,
-    OPT_SIZE,
-    OPT_STRING,
-};
-
-typedef struct QEMUOptionParameter {
-    const char *name;
-    enum QEMUOptionParType type;
-    union {
-        uint64_t n;
-        char* s;
-    } value;
-    const char *help;
-} QEMUOptionParameter;
-
-
 const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
 const char *get_opt_value(char *buf, int buf_size, const char *p);
 int get_next_param_value(char *buf, int buf_size,
@@ -58,27 +40,6 @@ int get_param_value(char *buf, int buf_size,
 int check_params(char *buf, int buf_size,
                  const char * const *params, const char *str);
 
-
-/*
- * The following functions take a parameter list as input. This is a pointer to
- * the first element of a QEMUOptionParameter array which is terminated by an
- * entry with entry->name == NULL.
- */
-
-QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
-    const char *name);
-int set_option_parameter(QEMUOptionParameter *list, const char *name,
-    const char *value);
-int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
-    uint64_t value);
-QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
-    QEMUOptionParameter *list);
-QEMUOptionParameter *parse_option_parameters(const char *param,
-    QEMUOptionParameter *list, QEMUOptionParameter *dest);
-void free_option_parameters(QEMUOptionParameter *list);
-void print_option_parameters(QEMUOptionParameter *list);
-void print_option_help(QEMUOptionParameter *list);
-
 /* ------------------------------------------------------------------ */
 
 typedef struct QemuOpt QemuOpt;
@@ -96,6 +57,7 @@ typedef struct QemuOptDesc {
     const char *name;
     enum QemuOptType type;
     const char *help;
+    uint64_t def_value;
 } QemuOptDesc;
 
 struct QemuOptsList {
@@ -152,5 +114,10 @@ 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);
-
+QemuOptsList *append_opts_list(QemuOptsList *dest,
+    QemuOptsList *list);
+void free_opts_list(QemuOptsList *list);
+void print_opts_list(QemuOptsList *list);
+QemuOpts *parse_opts_list(const char *param,
+    QemuOptsList *list, QemuOpts *dest);
 #endif
-- 
1.7.1




reply via email to

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