diff --git a/ChangeLog b/ChangeLog
index 21b9496223..57fac00c7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Jan 11 14:57:01 CET 2006 Daniel Veillard
+
+ * docs/libvir.html: grammatical fix
+ * src/Makefile.am src/sexpr.c src/sexpr.h: starting to integrate
+ Anthony Liquori libxend code
+ * src/libvir.c: fix an uninitialized value
+
Wed Dec 21 17:58:45 CET 2005 Daniel Veillard
* docs/architecture.* docs/*: added a section on the architecture
diff --git a/docs/libvir.html b/docs/libvir.html
index 6ee2404fc9..8381cbe105 100644
--- a/docs/libvir.html
+++ b/docs/libvir.html
@@ -46,7 +46,7 @@ progresses.
-In a Xen environment, program using libvir have to execute in "Domain 0",
+
In a Xen environment, programs using libvir have to execute in "Domain 0",
which is the primary Linux OS loaded on the machine. That OS kernel provides
most if not all of the actual drivers used by the set of domains. It also
runs the Xen Store, a database of informations shared by the hypervisor, the
diff --git a/src/Makefile.am b/src/Makefile.am
index 55e17d7912..7a5e436fb5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -15,7 +15,8 @@ libvir_la_SOURCES = \
libvir.c internal.h \
hash.c hash.h \
xen_internal.c xen_internal.h \
- xml.c
+ xml.c \
+ sexpr.c sexpr.h
bin_PROGRAMS=virsh
diff --git a/src/libvir.c b/src/libvir.c
index b64614a1f8..7957308643 100644
--- a/src/libvir.c
+++ b/src/libvir.c
@@ -642,7 +642,7 @@ virDomainLookupByName(virConnectPtr conn, const char *name) {
struct xs_transaction_handle* t;
virDomainPtr ret = NULL;
unsigned int num, i, len;
- long id;
+ long id = -1;
char **idlist = NULL, *endptr;
char prop[200], *tmp;
int found = 0;
diff --git a/src/sexpr.c b/src/sexpr.c
new file mode 100644
index 0000000000..e04639bd71
--- /dev/null
+++ b/src/sexpr.c
@@ -0,0 +1,446 @@
+/*
+ * sexpr.c : S-Expression routines to communicate with the Xen Daemon
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include "sexpr.h"
+
+#include
+#include
+#include
+#include
+#include
+
+/**
+ * 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;
+
+ ret = (struct sexpr *) malloc(sizeof(*ret));
+ if (ret == NULL) {
+ 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->car);
+ sexpr_free(sexpr->cdr);
+ break;
+ case SEXPR_VALUE:
+ free(sexpr->value);
+ break;
+ case SEXPR_NIL:
+ break;
+ }
+
+ 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->value = strndup(str, len);
+ } else {
+ ret->value = strdup(str);
+ }
+
+ if (ret->value == NULL) {
+ 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(struct sexpr *car, struct sexpr *cdr)
+{
+ struct sexpr *ret = sexpr_new();
+
+ if (ret == NULL)
+ return ret;
+ ret->kind = SEXPR_CONS;
+ ret->car = car;
+ ret->cdr = cdr;
+
+ return ret;
+}
+
+/**
+ * append:
+ * @lst: an existing list
+ * @value: the value
+ *
+ * Internal operation appending a value at the end of an existing list
+ */
+static void
+append(struct sexpr *lst, struct sexpr *value)
+{
+ while (lst->kind != SEXPR_NIL) {
+ lst = lst->cdr;
+ }
+
+ lst->kind = SEXPR_CONS;
+ lst->car = value;
+ lst->cdr = sexpr_nil();
+}
+
+/**
+ * @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, struct sexpr *value)
+{
+ if (lst == NULL)
+ return(NULL);
+ if (value == NULL)
+ return(lst);
+ append(lst, value);
+ return(lst);
+}
+
+/**
+ * sexpr2string:
+ * @sexpr: an S-Expression pointer
+ * @buffer: the output buffer
+ * @n_buffer: the size of the buffer in bytes
+ *
+ * Serialize the S-Expression in the buffer.
+ * Note that the output may be truncated if @n_buffer is too small
+ * resulting in an unparseable value.
+ *
+ * Returns the number of bytes used by the serialization in the buffer or
+ * 0 in case of error.
+ */
+size_t
+sexpr2string(struct sexpr * sexpr, char *buffer, size_t n_buffer)
+{
+ size_t ret = 0, tmp;
+
+ if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0))
+ return(0);
+
+ switch (sexpr->kind) {
+ case SEXPR_CONS:
+ tmp = snprintf(buffer + ret, n_buffer - ret, "(");
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ tmp = sexpr2string(sexpr->car, buffer + ret, n_buffer - ret);
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ while (sexpr->cdr->kind != SEXPR_NIL) {
+ sexpr = sexpr->cdr;
+ tmp = snprintf(buffer + ret, n_buffer - ret, " ");
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ tmp = sexpr2string(sexpr->car, buffer + ret, n_buffer - ret);
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ }
+ tmp = snprintf(buffer + ret, n_buffer - ret, ")");
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ break;
+ case SEXPR_VALUE:
+ if (strchr(sexpr->value, ' '))
+ tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
+ sexpr->value);
+ else
+ tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
+ sexpr->value);
+ if (tmp == 0)
+ return(0);
+ ret += tmp;
+ break;
+ case SEXPR_NIL:
+ break;
+ default:
+ return(0);
+ }
+
+ return(ret);
+}
+
+#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 catrosphic. 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)
+ return NULL;
+ append(ret, tmp);
+#if 0
+ if (0) {
+ char buf[4096];
+
+ sexpr2string(ret, buf, sizeof(buf));
+ printf("%s\n", buffer);
+ }
+#endif
+ 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->value = strndup(start, ptr - start);
+
+ if (*ptr == '\'')
+ ptr++;
+ } else {
+ start = ptr;
+
+ while (*ptr && !isspace(*ptr) && *ptr != ')' && *ptr != '(') {
+ ptr++;
+ }
+
+ ret->value = strndup(start, ptr - start);
+ }
+
+ ret->kind = SEXPR_VALUE;
+ }
+
+ *end = ptr - buffer;
+
+ return ret;
+}
+
+/**
+ * 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 catrosphic. 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:
+ * @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(struct sexpr *sexpr, const char *node)
+{
+ char buffer[4096], *ptr, *token;
+
+ if ((node == NULL) || (sexpr == NULL))
+ return(NULL);
+
+ snprintf(buffer, sizeof(buffer), "%s", node);
+
+ ptr = buffer;
+ token = strsep(&ptr, "/");
+
+ if (sexpr->kind != SEXPR_CONS || sexpr->car->kind != SEXPR_VALUE) {
+ return NULL;
+ }
+
+ if (strcmp(sexpr->car->value, token) != 0) {
+ return NULL;
+ }
+
+ for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) {
+ struct sexpr *i;
+
+ if (token == NULL)
+ continue;
+
+ sexpr = sexpr->cdr;
+ for (i=sexpr; i->kind != SEXPR_NIL; i=i->cdr) {
+ if (i->kind != SEXPR_CONS ||
+ i->car->kind != SEXPR_CONS ||
+ i->car->car->kind != SEXPR_VALUE) {
+ continue;
+ }
+
+ if (strcmp(i->car->car->value, token) == 0) {
+ sexpr = i->car;
+ break;
+ }
+ }
+
+ if (i->kind == SEXPR_NIL) {
+ break;
+ }
+ }
+
+ if (token != NULL) {
+ return NULL;
+ }
+
+ if (sexpr->kind != SEXPR_CONS || sexpr->cdr->kind != SEXPR_CONS)
+ return NULL;
+
+ return sexpr->cdr;
+}
+
+/**
+ * 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(struct sexpr *sexpr, const char *node)
+{
+ struct sexpr *n = sexpr_lookup(sexpr, node);
+
+ return (n && n->car->kind == SEXPR_VALUE) ? n->car->value : NULL;
+}
diff --git a/src/sexpr.h b/src/sexpr.h
new file mode 100644
index 0000000000..c776b2e5df
--- /dev/null
+++ b/src/sexpr.h
@@ -0,0 +1,56 @@
+/*
+ * sexpr.h : S-Expression interfaces needed to communicate with the Xen Daemon
+ *
+ * Copyright (C) 2005
+ *
+ * Anthony Liguori
+ *
+ * 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
+
+enum sexpr_type {
+ SEXPR_NIL,
+ SEXPR_CONS,
+ SEXPR_VALUE,
+};
+
+struct sexpr {
+ enum sexpr_type kind;
+ union {
+ struct {
+ struct sexpr *car;
+ struct sexpr *cdr;
+ };
+ char *value;
+ };
+};
+
+/* conversion to/from strings */
+size_t sexpr2string (struct sexpr *sexpr,
+ char *buffer,
+ size_t n_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 (struct sexpr *car,
+ struct sexpr *cdr);
+struct sexpr * sexpr_append (struct sexpr *lst,
+ struct sexpr *item);
+void sexpr_free (struct sexpr *sexpr);
+
+/* lookup in S-Expressions */
+const char * sexpr_node (struct sexpr *sexpr,
+ const char *node);
+struct sexpr * sexpr_lookup (struct sexpr *sexpr,
+ const char *node);
+#endif