From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> --- cfg.mk | 2 +- po/POTFILES.in | 2 +- src/Makefile.am | 2 +- src/util/sexpr.c | 625 ------------------------------------------------ src/util/sexpr.h | 58 ----- src/util/virsexpr.c | 625 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virsexpr.h | 58 +++++ src/xen/xend_internal.c | 2 +- src/xenxs/xen_sxpr.h | 2 +- src/xenxs/xen_xm.c | 2 +- 10 files changed, 689 insertions(+), 689 deletions(-) delete mode 100644 src/util/sexpr.c delete mode 100644 src/util/sexpr.h create mode 100644 src/util/virsexpr.c create mode 100644 src/util/virsexpr.h diff --git a/cfg.mk b/cfg.mk index e23f1c5..0a66797 100644 --- a/cfg.mk +++ b/cfg.mk @@ -807,7 +807,7 @@ exclude_file_name_regexp--sc_prohibit_sprintf = \ exclude_file_name_regexp--sc_prohibit_strncpy = ^src/util/util\.c$$ exclude_file_name_regexp--sc_prohibit_strtol = \ - ^src/(util/sexpr|(vbox|xen|xenxs)/.*)\.c$$ + ^src/(util/virsexpr|(vbox|xen|xenxs)/.*)\.c$$ exclude_file_name_regexp--sc_prohibit_xmlGetProp = ^src/util/xml\.c$$ diff --git a/po/POTFILES.in b/po/POTFILES.in index fb73807..2b09531 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -138,7 +138,6 @@ src/test/test_driver.c src/uml/uml_conf.c src/uml/uml_driver.c src/util/iohelper.c -src/util/sexpr.c src/util/stats_linux.c src/util/storage_file.c src/util/sysinfo.c @@ -173,6 +172,7 @@ src/util/virpci.c src/util/virpidfile.c src/util/virprocess.c src/util/virrandom.c +src/util/virsexpr.c src/util/virsocketaddr.c src/util/virterror.c src/util/virterror_internal.h diff --git a/src/Makefile.am b/src/Makefile.am index c0e35dc..c0dfd38 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -53,7 +53,6 @@ augeastest_DATA = # These files are not related to driver APIs. Simply generic # helper APIs for various purposes UTIL_SOURCES = \ - util/sexpr.c util/sexpr.h \ util/stats_linux.c util/stats_linux.h \ util/storage_file.c util/storage_file.h \ util/sysinfo.c util/sysinfo.h \ @@ -86,6 +85,7 @@ UTIL_SOURCES = \ util/virpci.c util/virpci.h \ util/virpidfile.c util/virpidfile.h \ util/virprocess.c util/virprocess.h \ + util/virsexpr.c util/virsexpr.h \ util/virtypedparam.c util/virtypedparam.h \ util/xml.c util/xml.h \ util/virterror.c util/virterror_internal.h \ diff --git a/src/util/sexpr.c b/src/util/sexpr.c deleted file mode 100644 index ae0cc18..0000000 --- a/src/util/sexpr.c +++ /dev/null @@ -1,625 +0,0 @@ -/* - * sexpr.c : S-Expression routines to communicate with the Xen Daemon - * - * Copyright (C) 2010-2011 Red Hat, Inc. - * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx> - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License. See the file COPYING.LIB in the main directory of this - * archive for more details. - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "c-ctype.h" -#include <errno.h> - -#include "virterror_internal.h" -#include "sexpr.h" -#include "util.h" -#include "viralloc.h" - -#define VIR_FROM_THIS VIR_FROM_SEXPR - - -/** - * sexpr_new: - * - * Create a new S-Expression - * - * Returns the new node or NULL in case of memory allocation error - */ -static struct sexpr * -sexpr_new(void) -{ - struct sexpr *ret; - - if (VIR_ALLOC(ret) < 0) { - virReportOOMError(); - return NULL; - } - ret->kind = SEXPR_NIL; - return ret; -} - -/** - * sexpr_free: - * @sexpr: the S-Expression pointer - * - * Free an S-Expression - */ -void -sexpr_free(struct sexpr *sexpr) -{ - int serrno = errno; - - if (sexpr == NULL) { - return; - } - - switch (sexpr->kind) { - case SEXPR_CONS: - sexpr_free(sexpr->u.s.car); - sexpr_free(sexpr->u.s.cdr); - break; - case SEXPR_VALUE: - VIR_FREE(sexpr->u.value); - break; - case SEXPR_NIL: - break; - } - - VIR_FREE(sexpr); - - errno = serrno; -} - -/** - * sexpr_nil: - * - * Provide a NIL S-Expression (the pointer is not shared so NIL equality - * testing won't work at the pointer level). - * - * Returns a new NIL S-Expression of NULL in case of error. - */ -struct sexpr * -sexpr_nil(void) -{ - return sexpr_new(); -} - -/** - * sexpr_string: - * @str: the input string, assumed to be UTF-8 - * @len: the length in bytes of the input - * - * Parse the input S-Expression and return a pointer to the result - * - * Returns the S-Expression pointer or NULL in case of error - */ -struct sexpr * -sexpr_string(const char *str, ssize_t len) -{ - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return ret; - ret->kind = SEXPR_VALUE; - if (len > 0) { - ret->u.value = strndup(str, len); - } else { - ret->u.value = strdup(str); - } - - if (ret->u.value == NULL) { - VIR_FREE(ret); - return NULL; - } - - return ret; -} - -/** - * sexpr_cons: - * @car: the left operand - * @cdr: the right operand - * - * Implement the CONS operation assembling 2 existing S-Expressions. - * Note that in case of error the input data are not freed. - * - * Returns the resulting S-Expression pointer or NULL in case of error. - */ -struct sexpr * -sexpr_cons(const struct sexpr *car, const struct sexpr *cdr) -{ - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return ret; - ret->kind = SEXPR_CONS; - ret->u.s.car = (struct sexpr *) car; - ret->u.s.cdr = (struct sexpr *) cdr; - - return ret; -} - -/** - * append: - * @lst: an existing list - * @value: the value - * - * Internal operation appending a value at the end of an existing list - */ -static int -append(struct sexpr *lst, const struct sexpr *value) -{ - struct sexpr *nil = sexpr_nil(); - - if (nil == NULL) - return -1; - - while (lst->kind != SEXPR_NIL) { - lst = lst->u.s.cdr; - } - - lst->kind = SEXPR_CONS; - lst->u.s.car = (struct sexpr *) value; - lst->u.s.cdr = nil; - - return 0; -} - -/** - * @lst: an existing list - * @value: the value - * - * Append a value at the end of an existing list - * - * Returns lst or NULL in case of error - */ -struct sexpr * -sexpr_append(struct sexpr *lst, const struct sexpr *value) -{ - if (lst == NULL) - return NULL; - if (value == NULL) - return lst; - if (append(lst, value) < 0) - return NULL; - return lst; -} - -/** - * sexpr2string: - * @sexpr: an S-Expression pointer - * @buffer: the output buffer - * - * Serialize the S-Expression in the buffer. - * - * Returns 0 on success, -1 on error. - */ -int -sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer) -{ - if ((sexpr == NULL) || (buffer == NULL)) - return -1; - - switch (sexpr->kind) { - case SEXPR_CONS: - virBufferAddChar(buffer, '('); - - if (sexpr2string(sexpr->u.s.car, buffer) < 0) - return -1; - - while (sexpr->u.s.cdr->kind != SEXPR_NIL) { - sexpr = sexpr->u.s.cdr; - - virBufferAddChar(buffer, ' '); - - if (sexpr2string(sexpr->u.s.car, buffer) < 0) - return -1; - } - - virBufferAddChar(buffer, ')'); - break; - case SEXPR_VALUE: - if (strchr(sexpr->u.value, ' ') || - strchr(sexpr->u.value, ')') || - strchr(sexpr->u.value, '(')) - virBufferAsprintf(buffer, "'%s'", sexpr->u.value); - else - virBufferAdd(buffer, sexpr->u.value, -1); - - break; - case SEXPR_NIL: - virBufferAddLit(buffer, "()"); - break; - default: - virReportError(VIR_ERR_SEXPR_SERIAL, - _("unknown s-expression kind %d"), sexpr->kind); - return -1; - } - - return 0; -} - -#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA)) - -static const char * -trim(const char *string) -{ - while (IS_SPACE(*string)) - string++; - return string; -} - -/** - * _string2sexpr: - * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 - * @end: pointer to an index in the buffer for the already parsed bytes - * - * Internal routine implementing the parse of S-Expression - * Note that failure in this function is catastrophic. If it returns - * NULL, you've leaked memory and you're currently OOM. It will always - * parse an SEXPR given a buffer - * - * Returns a pointer to the resulting parsed S-Expression, or NULL in case of - * hard error. - */ -static struct sexpr * -_string2sexpr(const char *buffer, size_t * end) -{ - const char *ptr = buffer + *end; - struct sexpr *ret = sexpr_new(); - - if (ret == NULL) - return NULL; - - ptr = trim(ptr); - - if (ptr[0] == '(') { - ret->kind = SEXPR_NIL; - - ptr = trim(ptr + 1); - while (*ptr && *ptr != ')') { - struct sexpr *tmp; - size_t tmp_len = 0; - - tmp = _string2sexpr(ptr, &tmp_len); - if (tmp == NULL) - goto error; - if (append(ret, tmp) < 0) { - sexpr_free(tmp); - goto error; - } - ptr = trim(ptr + tmp_len); - } - - if (*ptr == ')') { - ptr++; - } - } else { - const char *start; - - if (*ptr == '\'') { - ptr++; - start = ptr; - - while (*ptr && *ptr != '\'') { - if (*ptr == '\\' && ptr[1]) - ptr++; - ptr++; - } - - ret->u.value = strndup(start, ptr - start); - if (ret->u.value == NULL) { - virReportOOMError(); - goto error; - } - - if (*ptr == '\'') - ptr++; - } else { - start = ptr; - - while (*ptr && !c_isspace(*ptr) - && *ptr != ')' && *ptr != '(') { - ptr++; - } - - ret->u.value = strndup(start, ptr - start); - if (ret->u.value == NULL) { - virReportOOMError(); - goto error; - } - } - - ret->kind = SEXPR_VALUE; - if (ret->u.value == NULL) - goto error; - } - - *end = ptr - buffer; - - return ret; - - error: - sexpr_free(ret); - return NULL; -} - -/** - * string2sexpr: - * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 - * - * Parse the S-Expression in the buffer. - * Note that failure in this function is catastrophic. If it returns - * NULL, you've leaked memory and you're currently OOM. It will always - * parse an SEXPR given a buffer - * - * Returns a pointer to the resulting parsed S-Expression, or NULL in case of - * hard error. - */ -struct sexpr * -string2sexpr(const char *buffer) -{ - size_t dummy = 0; - - return _string2sexpr(buffer, &dummy); -} - - -/** - * sexpr_lookup_key: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path - * Returns the key node, rather than the data node. - * NOTE: path are limited to 4096 bytes. - * - * Returns the pointer to the sub expression or NULL if not found. - */ -static struct sexpr * -sexpr_lookup_key(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *result = NULL; - char *buffer, *ptr, *token; - - if ((node == NULL) || (sexpr == NULL)) - return NULL; - - buffer = strdup(node); - - if (buffer == NULL) { - virReportOOMError(); - return NULL; - } - - ptr = buffer; - token = strsep(&ptr, "/"); - - if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) { - goto cleanup; - } - - if (STRNEQ(sexpr->u.s.car->u.value, token)) { - goto cleanup; - } - - for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) { - const struct sexpr *i; - - sexpr = sexpr->u.s.cdr; - for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) { - if (i->kind != SEXPR_CONS || - i->u.s.car->kind != SEXPR_CONS || - i->u.s.car->u.s.car->kind != SEXPR_VALUE) { - continue; - } - - if (STREQ(i->u.s.car->u.s.car->u.value, token)) { - sexpr = i->u.s.car; - break; - } - } - - if (i->kind == SEXPR_NIL) { - break; - } - } - - if (token != NULL) { - goto cleanup; - } - - result = (struct sexpr *) sexpr; - -cleanup: - VIR_FREE(buffer); - - return result; -} - -/** - * sexpr_lookup: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path. - * NOTE: path are limited to 4096 bytes. - * - * Returns the pointer to the sub expression or NULL if not found. - */ -struct sexpr * -sexpr_lookup(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *s = sexpr_lookup_key(sexpr, node); - - if (s == NULL) - return NULL; - - if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS) - return NULL; - - return s->u.s.cdr; -} - -/** - * sexpr_has: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the sub expression to lookup in the S-Expression - * - * Search a sub expression in the S-Expression based on its path. - * NOTE: path are limited to 4096 bytes. - * NB, even if the key was found sexpr_lookup may return NULL if - * the corresponding value was empty - * - * Returns true if the key was found, false otherwise - */ -int -sexpr_has(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *s = sexpr_lookup_key(sexpr, node); - - if (s == NULL) - return 0; - - if (s->kind != SEXPR_CONS) - return 0; - - return 1; -} - -/** - * sexpr_node: - * @sexpr: a pointer to a parsed S-Expression - * @node: a path for the node to lookup in the S-Expression - * - * Search a node value in the S-Expression based on its path - * NOTE: path are limited to 4096 bytes. - * - * Returns the value of the node or NULL if not found. - */ -const char * -sexpr_node(const struct sexpr *sexpr, const char *node) -{ - struct sexpr *n = sexpr_lookup(sexpr, node); - - return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL; -} - -int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst) -{ - const char *val = sexpr_node(sexpr, node); - - if (val && *val) { - *dst = strdup(val); - if (!(*dst)) - return -1; - } else { - *dst = NULL; - } - return 0; -} - - -/** - * sexpr_fmt_node: - * @sexpr: a pointer to a parsed S-Expression - * @fmt: a path for the node to lookup in the S-Expression - * @... extra data to build the path - * - * Search a node value in the S-Expression based on its path - * - * Returns the value of the node or NULL if not found. - */ -const char * -sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) -{ - int result; - va_list ap; - char *node; - const char *value; - - va_start(ap, fmt); - result = virVasprintf(&node, fmt, ap); - va_end(ap); - - if (result < 0) { - return NULL; - } - - value = sexpr_node(sexpr, node); - - VIR_FREE(node); - - return value; -} - -/** - * sexpr_int: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup an int value in the S-Expression - * - * Returns the value found or 0 if not found (but may not be an error). - * This function suffers from the flaw that zero is both a correct - * return value and an error indicator: careful! - */ -int -sexpr_int(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtol(value, NULL, 0); - } - return 0; -} - - -/** - * sexpr_float: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup a float value in the S-Expression - * - * Returns the value found or 0 if not found (but may not be an error) - */ -double -sexpr_float(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtod(value, NULL); - } - return 0; -} - -/** - * sexpr_u64: - * @sexpr: an S-Expression - * @name: the name for the value - * - * convenience function to lookup a 64bits unsigned int value in the - * S-Expression - * - * Returns the value found or 0 if not found (but may not be an error) - */ -uint64_t -sexpr_u64(const struct sexpr *sexpr, const char *name) -{ - const char *value = sexpr_node(sexpr, name); - - if (value) { - return strtoll(value, NULL, 0); - } - return 0; -} diff --git a/src/util/sexpr.h b/src/util/sexpr.h deleted file mode 100644 index 13ec481..0000000 --- a/src/util/sexpr.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon - * - * Copyright (C) 2012 Red Hat, Inc. - * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx> - * - * This file is subject to the terms and conditions of the GNU Lesser General - * Public License. See the file COPYING.LIB in the main directory of this - * archive for more details. - */ - -#ifndef _LIBVIR_SEXPR_H_ -# define _LIBVIR_SEXPR_H_ - -# include "internal.h" -# include "virbuffer.h" - -enum sexpr_type { - SEXPR_NIL, - SEXPR_CONS, - SEXPR_VALUE, -}; - -struct sexpr { - enum sexpr_type kind; - union { - struct { - struct sexpr *car; - struct sexpr *cdr; - } s; - char *value; - } u; -}; - -/* conversion to/from strings */ -int sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer); -struct sexpr *string2sexpr(const char *buffer); - -/* constructors and destructors */ -struct sexpr *sexpr_nil(void); -struct sexpr *sexpr_string(const char *str, ssize_t len); -struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr); -struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item); -void sexpr_free(struct sexpr *sexpr); - -/* lookup in S-Expressions */ -const char *sexpr_node(const struct sexpr *sexpr, const char *node); -int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst); -const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) - ATTRIBUTE_FMT_PRINTF(2,3); -struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node); -int sexpr_has(const struct sexpr *sexpr, const char *node); - -int sexpr_int(const struct sexpr *sexpr, const char *name); -double sexpr_float(const struct sexpr *sexpr, const char *name); -uint64_t sexpr_u64(const struct sexpr *sexpr, const char *name); - -#endif diff --git a/src/util/virsexpr.c b/src/util/virsexpr.c new file mode 100644 index 0000000..80c24c4 --- /dev/null +++ b/src/util/virsexpr.c @@ -0,0 +1,625 @@ +/* + * sexpr.c : S-Expression routines to communicate with the Xen Daemon + * + * Copyright (C) 2010-2011 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file COPYING.LIB in the main directory of this + * archive for more details. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "c-ctype.h" +#include <errno.h> + +#include "virterror_internal.h" +#include "virsexpr.h" +#include "util.h" +#include "viralloc.h" + +#define VIR_FROM_THIS VIR_FROM_SEXPR + + +/** + * sexpr_new: + * + * Create a new S-Expression + * + * Returns the new node or NULL in case of memory allocation error + */ +static struct sexpr * +sexpr_new(void) +{ + struct sexpr *ret; + + if (VIR_ALLOC(ret) < 0) { + virReportOOMError(); + return NULL; + } + ret->kind = SEXPR_NIL; + return ret; +} + +/** + * sexpr_free: + * @sexpr: the S-Expression pointer + * + * Free an S-Expression + */ +void +sexpr_free(struct sexpr *sexpr) +{ + int serrno = errno; + + if (sexpr == NULL) { + return; + } + + switch (sexpr->kind) { + case SEXPR_CONS: + sexpr_free(sexpr->u.s.car); + sexpr_free(sexpr->u.s.cdr); + break; + case SEXPR_VALUE: + VIR_FREE(sexpr->u.value); + break; + case SEXPR_NIL: + break; + } + + VIR_FREE(sexpr); + + errno = serrno; +} + +/** + * sexpr_nil: + * + * Provide a NIL S-Expression (the pointer is not shared so NIL equality + * testing won't work at the pointer level). + * + * Returns a new NIL S-Expression of NULL in case of error. + */ +struct sexpr * +sexpr_nil(void) +{ + return sexpr_new(); +} + +/** + * sexpr_string: + * @str: the input string, assumed to be UTF-8 + * @len: the length in bytes of the input + * + * Parse the input S-Expression and return a pointer to the result + * + * Returns the S-Expression pointer or NULL in case of error + */ +struct sexpr * +sexpr_string(const char *str, ssize_t len) +{ + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return ret; + ret->kind = SEXPR_VALUE; + if (len > 0) { + ret->u.value = strndup(str, len); + } else { + ret->u.value = strdup(str); + } + + if (ret->u.value == NULL) { + VIR_FREE(ret); + return NULL; + } + + return ret; +} + +/** + * sexpr_cons: + * @car: the left operand + * @cdr: the right operand + * + * Implement the CONS operation assembling 2 existing S-Expressions. + * Note that in case of error the input data are not freed. + * + * Returns the resulting S-Expression pointer or NULL in case of error. + */ +struct sexpr * +sexpr_cons(const struct sexpr *car, const struct sexpr *cdr) +{ + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return ret; + ret->kind = SEXPR_CONS; + ret->u.s.car = (struct sexpr *) car; + ret->u.s.cdr = (struct sexpr *) cdr; + + return ret; +} + +/** + * append: + * @lst: an existing list + * @value: the value + * + * Internal operation appending a value at the end of an existing list + */ +static int +append(struct sexpr *lst, const struct sexpr *value) +{ + struct sexpr *nil = sexpr_nil(); + + if (nil == NULL) + return -1; + + while (lst->kind != SEXPR_NIL) { + lst = lst->u.s.cdr; + } + + lst->kind = SEXPR_CONS; + lst->u.s.car = (struct sexpr *) value; + lst->u.s.cdr = nil; + + return 0; +} + +/** + * @lst: an existing list + * @value: the value + * + * Append a value at the end of an existing list + * + * Returns lst or NULL in case of error + */ +struct sexpr * +sexpr_append(struct sexpr *lst, const struct sexpr *value) +{ + if (lst == NULL) + return NULL; + if (value == NULL) + return lst; + if (append(lst, value) < 0) + return NULL; + return lst; +} + +/** + * sexpr2string: + * @sexpr: an S-Expression pointer + * @buffer: the output buffer + * + * Serialize the S-Expression in the buffer. + * + * Returns 0 on success, -1 on error. + */ +int +sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer) +{ + if ((sexpr == NULL) || (buffer == NULL)) + return -1; + + switch (sexpr->kind) { + case SEXPR_CONS: + virBufferAddChar(buffer, '('); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) + return -1; + + while (sexpr->u.s.cdr->kind != SEXPR_NIL) { + sexpr = sexpr->u.s.cdr; + + virBufferAddChar(buffer, ' '); + + if (sexpr2string(sexpr->u.s.car, buffer) < 0) + return -1; + } + + virBufferAddChar(buffer, ')'); + break; + case SEXPR_VALUE: + if (strchr(sexpr->u.value, ' ') || + strchr(sexpr->u.value, ')') || + strchr(sexpr->u.value, '(')) + virBufferAsprintf(buffer, "'%s'", sexpr->u.value); + else + virBufferAdd(buffer, sexpr->u.value, -1); + + break; + case SEXPR_NIL: + virBufferAddLit(buffer, "()"); + break; + default: + virReportError(VIR_ERR_SEXPR_SERIAL, + _("unknown s-expression kind %d"), sexpr->kind); + return -1; + } + + return 0; +} + +#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA)) + +static const char * +trim(const char *string) +{ + while (IS_SPACE(*string)) + string++; + return string; +} + +/** + * _string2sexpr: + * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 + * @end: pointer to an index in the buffer for the already parsed bytes + * + * Internal routine implementing the parse of S-Expression + * Note that failure in this function is catastrophic. If it returns + * NULL, you've leaked memory and you're currently OOM. It will always + * parse an SEXPR given a buffer + * + * Returns a pointer to the resulting parsed S-Expression, or NULL in case of + * hard error. + */ +static struct sexpr * +_string2sexpr(const char *buffer, size_t * end) +{ + const char *ptr = buffer + *end; + struct sexpr *ret = sexpr_new(); + + if (ret == NULL) + return NULL; + + ptr = trim(ptr); + + if (ptr[0] == '(') { + ret->kind = SEXPR_NIL; + + ptr = trim(ptr + 1); + while (*ptr && *ptr != ')') { + struct sexpr *tmp; + size_t tmp_len = 0; + + tmp = _string2sexpr(ptr, &tmp_len); + if (tmp == NULL) + goto error; + if (append(ret, tmp) < 0) { + sexpr_free(tmp); + goto error; + } + ptr = trim(ptr + tmp_len); + } + + if (*ptr == ')') { + ptr++; + } + } else { + const char *start; + + if (*ptr == '\'') { + ptr++; + start = ptr; + + while (*ptr && *ptr != '\'') { + if (*ptr == '\\' && ptr[1]) + ptr++; + ptr++; + } + + ret->u.value = strndup(start, ptr - start); + if (ret->u.value == NULL) { + virReportOOMError(); + goto error; + } + + if (*ptr == '\'') + ptr++; + } else { + start = ptr; + + while (*ptr && !c_isspace(*ptr) + && *ptr != ')' && *ptr != '(') { + ptr++; + } + + ret->u.value = strndup(start, ptr - start); + if (ret->u.value == NULL) { + virReportOOMError(); + goto error; + } + } + + ret->kind = SEXPR_VALUE; + if (ret->u.value == NULL) + goto error; + } + + *end = ptr - buffer; + + return ret; + + error: + sexpr_free(ret); + return NULL; +} + +/** + * string2sexpr: + * @buffer: a zero terminated buffer containing an S-Expression in UTF-8 + * + * Parse the S-Expression in the buffer. + * Note that failure in this function is catastrophic. If it returns + * NULL, you've leaked memory and you're currently OOM. It will always + * parse an SEXPR given a buffer + * + * Returns a pointer to the resulting parsed S-Expression, or NULL in case of + * hard error. + */ +struct sexpr * +string2sexpr(const char *buffer) +{ + size_t dummy = 0; + + return _string2sexpr(buffer, &dummy); +} + + +/** + * sexpr_lookup_key: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path + * Returns the key node, rather than the data node. + * NOTE: path are limited to 4096 bytes. + * + * Returns the pointer to the sub expression or NULL if not found. + */ +static struct sexpr * +sexpr_lookup_key(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *result = NULL; + char *buffer, *ptr, *token; + + if ((node == NULL) || (sexpr == NULL)) + return NULL; + + buffer = strdup(node); + + if (buffer == NULL) { + virReportOOMError(); + return NULL; + } + + ptr = buffer; + token = strsep(&ptr, "/"); + + if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) { + goto cleanup; + } + + if (STRNEQ(sexpr->u.s.car->u.value, token)) { + goto cleanup; + } + + for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) { + const struct sexpr *i; + + sexpr = sexpr->u.s.cdr; + for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) { + if (i->kind != SEXPR_CONS || + i->u.s.car->kind != SEXPR_CONS || + i->u.s.car->u.s.car->kind != SEXPR_VALUE) { + continue; + } + + if (STREQ(i->u.s.car->u.s.car->u.value, token)) { + sexpr = i->u.s.car; + break; + } + } + + if (i->kind == SEXPR_NIL) { + break; + } + } + + if (token != NULL) { + goto cleanup; + } + + result = (struct sexpr *) sexpr; + +cleanup: + VIR_FREE(buffer); + + return result; +} + +/** + * sexpr_lookup: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path. + * NOTE: path are limited to 4096 bytes. + * + * Returns the pointer to the sub expression or NULL if not found. + */ +struct sexpr * +sexpr_lookup(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *s = sexpr_lookup_key(sexpr, node); + + if (s == NULL) + return NULL; + + if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS) + return NULL; + + return s->u.s.cdr; +} + +/** + * sexpr_has: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the sub expression to lookup in the S-Expression + * + * Search a sub expression in the S-Expression based on its path. + * NOTE: path are limited to 4096 bytes. + * NB, even if the key was found sexpr_lookup may return NULL if + * the corresponding value was empty + * + * Returns true if the key was found, false otherwise + */ +int +sexpr_has(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *s = sexpr_lookup_key(sexpr, node); + + if (s == NULL) + return 0; + + if (s->kind != SEXPR_CONS) + return 0; + + return 1; +} + +/** + * sexpr_node: + * @sexpr: a pointer to a parsed S-Expression + * @node: a path for the node to lookup in the S-Expression + * + * Search a node value in the S-Expression based on its path + * NOTE: path are limited to 4096 bytes. + * + * Returns the value of the node or NULL if not found. + */ +const char * +sexpr_node(const struct sexpr *sexpr, const char *node) +{ + struct sexpr *n = sexpr_lookup(sexpr, node); + + return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL; +} + +int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst) +{ + const char *val = sexpr_node(sexpr, node); + + if (val && *val) { + *dst = strdup(val); + if (!(*dst)) + return -1; + } else { + *dst = NULL; + } + return 0; +} + + +/** + * sexpr_fmt_node: + * @sexpr: a pointer to a parsed S-Expression + * @fmt: a path for the node to lookup in the S-Expression + * @... extra data to build the path + * + * Search a node value in the S-Expression based on its path + * + * Returns the value of the node or NULL if not found. + */ +const char * +sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) +{ + int result; + va_list ap; + char *node; + const char *value; + + va_start(ap, fmt); + result = virVasprintf(&node, fmt, ap); + va_end(ap); + + if (result < 0) { + return NULL; + } + + value = sexpr_node(sexpr, node); + + VIR_FREE(node); + + return value; +} + +/** + * sexpr_int: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup an int value in the S-Expression + * + * Returns the value found or 0 if not found (but may not be an error). + * This function suffers from the flaw that zero is both a correct + * return value and an error indicator: careful! + */ +int +sexpr_int(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtol(value, NULL, 0); + } + return 0; +} + + +/** + * sexpr_float: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup a float value in the S-Expression + * + * Returns the value found or 0 if not found (but may not be an error) + */ +double +sexpr_float(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtod(value, NULL); + } + return 0; +} + +/** + * sexpr_u64: + * @sexpr: an S-Expression + * @name: the name for the value + * + * convenience function to lookup a 64bits unsigned int value in the + * S-Expression + * + * Returns the value found or 0 if not found (but may not be an error) + */ +uint64_t +sexpr_u64(const struct sexpr *sexpr, const char *name) +{ + const char *value = sexpr_node(sexpr, name); + + if (value) { + return strtoll(value, NULL, 0); + } + return 0; +} diff --git a/src/util/virsexpr.h b/src/util/virsexpr.h new file mode 100644 index 0000000..13ec481 --- /dev/null +++ b/src/util/virsexpr.h @@ -0,0 +1,58 @@ +/* + * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon + * + * Copyright (C) 2012 Red Hat, Inc. + * Copyright (C) 2005 Anthony Liguori <aliguori@xxxxxxxxxx> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License. See the file COPYING.LIB in the main directory of this + * archive for more details. + */ + +#ifndef _LIBVIR_SEXPR_H_ +# define _LIBVIR_SEXPR_H_ + +# include "internal.h" +# include "virbuffer.h" + +enum sexpr_type { + SEXPR_NIL, + SEXPR_CONS, + SEXPR_VALUE, +}; + +struct sexpr { + enum sexpr_type kind; + union { + struct { + struct sexpr *car; + struct sexpr *cdr; + } s; + char *value; + } u; +}; + +/* conversion to/from strings */ +int sexpr2string(const struct sexpr *sexpr, virBufferPtr buffer); +struct sexpr *string2sexpr(const char *buffer); + +/* constructors and destructors */ +struct sexpr *sexpr_nil(void); +struct sexpr *sexpr_string(const char *str, ssize_t len); +struct sexpr *sexpr_cons(const struct sexpr *car, const struct sexpr *cdr); +struct sexpr *sexpr_append(struct sexpr *lst, const struct sexpr *item); +void sexpr_free(struct sexpr *sexpr); + +/* lookup in S-Expressions */ +const char *sexpr_node(const struct sexpr *sexpr, const char *node); +int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst); +const char *sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...) + ATTRIBUTE_FMT_PRINTF(2,3); +struct sexpr *sexpr_lookup(const struct sexpr *sexpr, const char *node); +int sexpr_has(const struct sexpr *sexpr, const char *node); + +int sexpr_int(const struct sexpr *sexpr, const char *name); +double sexpr_float(const struct sexpr *sexpr, const char *name); +uint64_t sexpr_u64(const struct sexpr *sexpr, const char *name); + +#endif diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c index a4005f4..6e8bc2f 100644 --- a/src/xen/xend_internal.c +++ b/src/xen/xend_internal.c @@ -35,7 +35,7 @@ #include "xend_internal.h" #include "driver.h" #include "util.h" -#include "sexpr.h" +#include "virsexpr.h" #include "xen_sxpr.h" #include "virbuffer.h" #include "uuid.h" diff --git a/src/xenxs/xen_sxpr.h b/src/xenxs/xen_sxpr.h index 4ff640c..d7ce46a 100644 --- a/src/xenxs/xen_sxpr.h +++ b/src/xenxs/xen_sxpr.h @@ -30,7 +30,7 @@ # include "internal.h" # include "virconf.h" # include "domain_conf.h" -# include "sexpr.h" +# include "virsexpr.h" typedef enum { XEND_CONFIG_VERSION_3_0_2 = 1, diff --git a/src/xenxs/xen_xm.c b/src/xenxs/xen_xm.c index 7d67bbe..c29df1c 100644 --- a/src/xenxs/xen_xm.c +++ b/src/xenxs/xen_xm.c @@ -31,7 +31,7 @@ #include "viralloc.h" #include "verify.h" #include "uuid.h" -#include "sexpr.h" +#include "virsexpr.h" #include "count-one-bits.h" #include "xenxs_private.h" #include "xen_xm.h" -- 1.7.11.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list