Create qemu-option.h

This patch creates a new header file and the corresponding implementation file
for parsing of parameter strings for options (like used in -drive). Part of
this is code moved from vl.c (so qemu-img can use it later).

The idea is to have a data structure describing all accepted parameters. When
parsing a parameter string, the structure is copied and filled with the
parameter values.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Kevin Wolf 2009-05-18 16:42:09 +02:00 committed by Anthony Liguori
parent daa91de28d
commit d3f243676a
5 changed files with 418 additions and 40 deletions

View File

@ -65,7 +65,7 @@ recurse-all: $(SUBDIR_RULES)
#######################################################################
# BLOCK_OBJS is code used by both qemu system emulation and qemu-img
BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o module.o
BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o
BLOCK_OBJS+=block/cow.o block/qcow.o aes.o block/vmdk.o block/cloop.o
BLOCK_OBJS+=block/dmg.o block/bochs.o block/vpc.o block/vvfat.o
BLOCK_OBJS+=block/qcow2.o block/parallels.o block/nbd.o

349
qemu-option.c Normal file
View File

@ -0,0 +1,349 @@
/*
* Commandline option parsing functions
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include <string.h>
#include "qemu-common.h"
#include "qemu-option.h"
/*
* Extracts the name of an option from the parameter string (p points at the
* first byte of the option name)
*
* The option name is delimited by delim (usually , or =) or the string end
* and is copied into buf. If the option name is longer than buf_size, it is
* truncated. buf is always zero terminated.
*
* The return value is the position of the delimiter/zero byte after the option
* name in p.
*/
const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
{
char *q;
q = buf;
while (*p != '\0' && *p != delim) {
if (q && (q - buf) < buf_size - 1)
*q++ = *p;
p++;
}
if (q)
*q = '\0';
return p;
}
/*
* Extracts the value of an option from the parameter string p (p points at the
* first byte of the option value)
*
* This function is comparable to get_opt_name with the difference that the
* delimiter is fixed to be comma which starts a new option. To specify an
* option value that contains commas, double each comma.
*/
const char *get_opt_value(char *buf, int buf_size, const char *p)
{
char *q;
q = buf;
while (*p != '\0') {
if (*p == ',') {
if (*(p + 1) != ',')
break;
p++;
}
if (q && (q - buf) < buf_size - 1)
*q++ = *p;
p++;
}
if (q)
*q = '\0';
return p;
}
/*
* 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;
}
/*
* 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)
{
// 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:
if (value != NULL) {
if (!strcmp(value, "on")) {
list->value.n = 1;
} else if (!strcmp(value, "off")) {
list->value.n = 0;
} else {
fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);
return -1;
}
} else {
list->value.n = 1;
}
break;
case OPT_STRING:
if (value != NULL) {
list->value.s = strdup(value);
} else {
fprintf(stderr, "Option '%s' needs a parameter\n", name);
return -1;
}
break;
case OPT_SIZE:
if (value != NULL) {
double sizef = strtod(value, (char**) &value);
switch (*value) {
case 'T':
sizef *= 1024;
case 'G':
sizef *= 1024;
case 'M':
sizef *= 1024;
case 'K':
case 'k':
sizef *= 1024;
case 'b':
case '\0':
list->value.n = (uint64_t) sizef;
break;
default:
fprintf(stderr, "Option '%s' needs size as parameter\n", name);
fprintf(stderr, "You may use k, M, G or T suffixes for "
"kilobytes, megabytes, gigabytes and terabytes.\n");
return -1;
}
} else {
fprintf(stderr, "Option '%s' needs a parameter\n", name);
return -1;
}
break;
default:
fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
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) {
free(cur->value.s);
}
cur++;
}
free(list);
}
/*
* Parses a parameter string (param) into an option list (dest).
*
* list is the templace is. If dest is NULL, a new copy of list is created for
* it. 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 *cur;
QEMUOptionParameter *allocated = NULL;
char name[256];
char value[256];
char *param_delim, *value_delim;
char next_delim;
size_t num_options;
if (list == NULL) {
return NULL;
}
if (dest == NULL) {
// Count valid options
num_options = 0;
cur = list;
while (cur->name) {
num_options++;
cur++;
}
// Create a copy of the option list to fill in values
dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter));
allocated = dest;
memcpy(dest, list, (num_options + 1) * sizeof(QEMUOptionParameter));
}
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=(unkown type) ", list->name);
break;
}
list++;
}
}

67
qemu-option.h Normal file
View File

@ -0,0 +1,67 @@
/*
* Commandline option parsing functions
*
* Copyright (c) 2003-2008 Fabrice Bellard
* Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_OPTIONS_H
#define QEMU_OPTIONS_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;
} 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);
/*
* 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 *parse_option_parameters(const char *param,
QEMUOptionParameter *list, QEMUOptionParameter *dest);
void free_option_parameters(QEMUOptionParameter *list);
void print_option_parameters(QEMUOptionParameter *list);
#endif

View File

@ -265,8 +265,6 @@ void do_usb_add(Monitor *mon, const char *devname);
void do_usb_del(Monitor *mon, const char *devname);
void usb_info(Monitor *mon);
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_param_value(char *buf, int buf_size,
const char *tag, const char *str);
int check_params(const char * const *params, const char *str);

38
vl.c
View File

@ -156,6 +156,7 @@ int main(int argc, char **argv)
#include "migration.h"
#include "kvm.h"
#include "balloon.h"
#include "qemu-option.h"
#include "disas.h"
@ -1809,43 +1810,6 @@ static int socket_init(void)
}
#endif
const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
{
char *q;
q = buf;
while (*p != '\0' && *p != delim) {
if (q && (q - buf) < buf_size - 1)
*q++ = *p;
p++;
}
if (q)
*q = '\0';
return p;
}
const char *get_opt_value(char *buf, int buf_size, const char *p)
{
char *q;
q = buf;
while (*p != '\0') {
if (*p == ',') {
if (*(p + 1) != ',')
break;
p++;
}
if (q && (q - buf) < buf_size - 1)
*q++ = *p;
p++;
}
if (q)
*q = '\0';
return p;
}
int get_param_value(char *buf, int buf_size,
const char *tag, const char *str)
{