2006-01-11 13:58:32 +00:00
|
|
|
/*
|
|
|
|
* sexpr.c : S-Expression routines to communicate with the Xen Daemon
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005
|
|
|
|
*
|
|
|
|
* Anthony Liguori <aliguori@us.ibm.com>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2006-01-11 13:58:32 +00:00
|
|
|
|
2007-12-07 14:39:14 +00:00
|
|
|
#include <stdio.h>
|
2008-01-23 14:54:41 +00:00
|
|
|
#include <stdlib.h>
|
2006-01-11 13:58:32 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
2007-12-07 14:39:14 +00:00
|
|
|
#include "internal.h"
|
|
|
|
#include "sexpr.h"
|
|
|
|
|
2006-02-27 21:34:28 +00:00
|
|
|
/**
|
|
|
|
* virSexprError:
|
|
|
|
* @conn: the connection if available
|
2008-02-27 10:37:19 +00:00
|
|
|
* @error: the error number
|
2006-02-27 21:34:28 +00:00
|
|
|
* @info: extra information string
|
|
|
|
*
|
|
|
|
* Handle an error in the S-Expression code
|
|
|
|
*/
|
|
|
|
static void
|
2006-03-15 12:13:25 +00:00
|
|
|
virSexprError(virErrorNumber error, const char *info)
|
|
|
|
{
|
2006-02-27 21:34:28 +00:00
|
|
|
const char *errmsg;
|
2006-03-15 12:13:25 +00:00
|
|
|
|
2006-02-27 21:34:28 +00:00
|
|
|
if (error == VIR_ERR_OK)
|
|
|
|
return;
|
|
|
|
|
|
|
|
errmsg = __virErrorMsg(error, info);
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
__virRaiseError(NULL, NULL, NULL, VIR_FROM_SEXPR, error, VIR_ERR_ERROR,
|
2006-02-27 21:34:28 +00:00
|
|
|
errmsg, info, NULL, 0, 0, errmsg, info);
|
|
|
|
}
|
|
|
|
|
2006-01-11 13:58:32 +00:00
|
|
|
/**
|
|
|
|
* 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) {
|
2006-09-21 15:24:37 +00:00
|
|
|
virSexprError(VIR_ERR_NO_MEMORY, _("failed to allocate a node"));
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
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:
|
2007-09-29 18:16:26 +00:00
|
|
|
sexpr_free(sexpr->u.s.car);
|
|
|
|
sexpr_free(sexpr->u.s.cdr);
|
2006-01-11 13:58:32 +00:00
|
|
|
break;
|
|
|
|
case SEXPR_VALUE:
|
2007-09-29 18:16:26 +00:00
|
|
|
free(sexpr->u.value);
|
2006-01-11 13:58:32 +00:00
|
|
|
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) {
|
2007-09-29 18:16:26 +00:00
|
|
|
ret->u.value = strndup(str, len);
|
2006-01-11 13:58:32 +00:00
|
|
|
} else {
|
2007-09-29 18:16:26 +00:00
|
|
|
ret->u.value = strdup(str);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
if (ret->u.value == NULL) {
|
2006-01-11 13:58:32 +00:00
|
|
|
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 *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_cons(const struct sexpr *car, const struct sexpr *cdr)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
struct sexpr *ret = sexpr_new();
|
|
|
|
|
|
|
|
if (ret == NULL)
|
|
|
|
return ret;
|
|
|
|
ret->kind = SEXPR_CONS;
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
ret->u.s.car = (struct sexpr *) car;
|
|
|
|
ret->u.s.cdr = (struct sexpr *) cdr;
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* append:
|
|
|
|
* @lst: an existing list
|
|
|
|
* @value: the value
|
|
|
|
*
|
|
|
|
* Internal operation appending a value at the end of an existing list
|
|
|
|
*/
|
|
|
|
static void
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
append(struct sexpr *lst, const struct sexpr *value)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
while (lst->kind != SEXPR_NIL) {
|
2007-09-29 18:16:26 +00:00
|
|
|
lst = lst->u.s.cdr;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lst->kind = SEXPR_CONS;
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
lst->u.s.car = (struct sexpr *) value;
|
2007-09-29 18:16:26 +00:00
|
|
|
lst->u.s.cdr = sexpr_nil();
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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 *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_append(struct sexpr *lst, const struct sexpr *value)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
if (lst == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-01-11 13:58:32 +00:00
|
|
|
if (value == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (lst);
|
2006-01-11 13:58:32 +00:00
|
|
|
append(lst, value);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (lst);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr2string(const struct sexpr * sexpr, char *buffer, size_t n_buffer)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
size_t ret = 0, tmp;
|
|
|
|
|
|
|
|
if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
switch (sexpr->kind) {
|
|
|
|
case SEXPR_CONS:
|
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, "(");
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2007-09-29 18:16:26 +00:00
|
|
|
tmp = sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2007-09-29 18:16:26 +00:00
|
|
|
while (sexpr->u.s.cdr->kind != SEXPR_NIL) {
|
|
|
|
sexpr = sexpr->u.s.cdr;
|
2006-01-11 13:58:32 +00:00
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, " ");
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
|
|
|
tmp =
|
2007-09-29 18:16:26 +00:00
|
|
|
sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, ")");
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2006-01-11 13:58:32 +00:00
|
|
|
break;
|
|
|
|
case SEXPR_VALUE:
|
2007-09-29 18:16:26 +00:00
|
|
|
if (strchr(sexpr->u.value, ' '))
|
2006-01-11 13:58:32 +00:00
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
|
2007-09-29 18:16:26 +00:00
|
|
|
sexpr->u.value);
|
2006-01-11 13:58:32 +00:00
|
|
|
else
|
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
|
2007-09-29 18:16:26 +00:00
|
|
|
sexpr->u.value);
|
2006-03-15 12:13:25 +00:00
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2006-01-11 13:58:32 +00:00
|
|
|
break;
|
|
|
|
case SEXPR_NIL:
|
|
|
|
break;
|
2006-03-15 12:13:25 +00:00
|
|
|
default:
|
|
|
|
goto error;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
return (ret);
|
|
|
|
error:
|
2006-02-27 21:34:28 +00:00
|
|
|
buffer[n_buffer - 1] = 0;
|
|
|
|
virSexprError(VIR_ERR_SEXPR_SERIAL, buffer);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA))
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
trim(const char *string)
|
|
|
|
{
|
|
|
|
while (IS_SPACE(*string))
|
|
|
|
string++;
|
2006-03-15 12:13:25 +00:00
|
|
|
return (string);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* _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
|
2008-02-27 10:37:19 +00:00
|
|
|
* Note that failure in this function is catastrophic. If it returns
|
2006-01-11 13:58:32 +00:00
|
|
|
* 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++;
|
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
ret->u.value = strndup(start, ptr - start);
|
|
|
|
if (ret->u.value == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virSexprError(VIR_ERR_NO_MEMORY,
|
2006-09-21 15:24:37 +00:00
|
|
|
_("failed to copy a string"));
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
if (*ptr == '\'')
|
|
|
|
ptr++;
|
|
|
|
} else {
|
|
|
|
start = ptr;
|
|
|
|
|
|
|
|
while (*ptr && !isspace(*ptr) && *ptr != ')' && *ptr != '(') {
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
ret->u.value = strndup(start, ptr - start);
|
|
|
|
if (ret->u.value == NULL) {
|
2006-03-15 12:13:25 +00:00
|
|
|
virSexprError(VIR_ERR_NO_MEMORY,
|
2006-09-21 15:24:37 +00:00
|
|
|
_("failed to copy a string"));
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ret->kind = SEXPR_VALUE;
|
2007-09-29 18:16:26 +00:00
|
|
|
if (ret->u.value == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
goto error;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
*end = ptr - buffer;
|
|
|
|
|
|
|
|
return ret;
|
2006-02-27 21:34:28 +00:00
|
|
|
|
2006-03-15 12:13:25 +00:00
|
|
|
error:
|
2006-02-27 21:34:28 +00:00
|
|
|
sexpr_free(ret);
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* string2sexpr:
|
|
|
|
* @buffer: a zero terminated buffer containing an S-Expression in UTF-8
|
|
|
|
*
|
|
|
|
* Parse the S-Expression in the buffer.
|
2008-02-27 10:37:19 +00:00
|
|
|
* Note that failure in this function is catastrophic. If it returns
|
2006-01-11 13:58:32 +00:00
|
|
|
* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2007-09-29 18:31:05 +00:00
|
|
|
* sexpr_lookup_key:
|
2006-01-11 13:58:32 +00:00
|
|
|
* @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
|
2007-09-29 18:31:05 +00:00
|
|
|
* Returns the key node, rather than the data node.
|
2006-01-11 13:58:32 +00:00
|
|
|
* NOTE: path are limited to 4096 bytes.
|
|
|
|
*
|
|
|
|
* Returns the pointer to the sub expression or NULL if not found.
|
|
|
|
*/
|
2007-09-29 18:31:05 +00:00
|
|
|
static struct sexpr *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_lookup_key(const struct sexpr *sexpr, const char *node)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
char buffer[4096], *ptr, *token;
|
|
|
|
|
|
|
|
if ((node == NULL) || (sexpr == NULL))
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
snprintf(buffer, sizeof(buffer), "%s", node);
|
|
|
|
|
|
|
|
ptr = buffer;
|
|
|
|
token = strsep(&ptr, "/");
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
if (sexpr->kind != SEXPR_CONS || sexpr->u.s.car->kind != SEXPR_VALUE) {
|
2006-01-11 13:58:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
if (strcmp(sexpr->u.s.car->u.value, token) != 0) {
|
2006-01-11 13:58:32 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) {
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
const struct sexpr *i;
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
if (token == NULL)
|
|
|
|
continue;
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
sexpr = sexpr->u.s.cdr;
|
|
|
|
for (i = sexpr; i->kind != SEXPR_NIL; i = i->u.s.cdr) {
|
2006-01-11 13:58:32 +00:00
|
|
|
if (i->kind != SEXPR_CONS ||
|
2007-09-29 18:16:26 +00:00
|
|
|
i->u.s.car->kind != SEXPR_CONS ||
|
|
|
|
i->u.s.car->u.s.car->kind != SEXPR_VALUE) {
|
2006-01-11 13:58:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
if (strcmp(i->u.s.car->u.s.car->u.value, token) == 0) {
|
|
|
|
sexpr = i->u.s.car;
|
2006-01-11 13:58:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->kind == SEXPR_NIL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (token != NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
return (struct sexpr *) sexpr;
|
2007-09-29 18:31:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_lookup(const struct sexpr *sexpr, const char *node)
|
2007-09-29 18:31:05 +00:00
|
|
|
{
|
|
|
|
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)
|
2006-01-11 13:58:32 +00:00
|
|
|
return NULL;
|
|
|
|
|
2007-09-29 18:31:05 +00:00
|
|
|
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
|
|
|
|
*
|
2008-02-05 19:27:37 +00:00
|
|
|
* Returns true if the key was found, false otherwise
|
2007-09-29 18:31:05 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
sexpr_has(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;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_node(const struct sexpr *sexpr, const char *node)
|
2006-01-11 13:58:32 +00:00
|
|
|
{
|
|
|
|
struct sexpr *n = sexpr_lookup(sexpr, node);
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
return (n && n->u.s.car->kind == SEXPR_VALUE) ? n->u.s.car->u.value : NULL;
|
2006-01-11 13:58:32 +00:00
|
|
|
}
|
2006-08-26 15:30:44 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
* NOTE: path are limited to 4096 bytes.
|
|
|
|
*
|
|
|
|
* Returns the value of the node or NULL if not found.
|
|
|
|
*/
|
|
|
|
const char *
|
Adjust sexpr-related interfaces to be const-correct.
* src/sexpr.c (sexpr_cons, append, sexpr_append, sexpr2string)
(sexpr_lookup_key, sexpr_lookup, sexpr_node, sexpr_fmt_node):
Add "const" attribute where appropriate.
* src/xend_internal.c (sexpr_int, sexpr_float, sexpr_u64)
(sexpr_uuid, sexpr_to_xend_domain_info, sexpr_to_xend_node_info)
(sexpr_to_xend_topology_xml, sexpr_to_domain): Likewise.
* src/sexpr.h: Adjust prototypes.
2008-01-21 14:22:15 +00:00
|
|
|
sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
|
2006-08-26 15:30:44 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
char node[4096];
|
|
|
|
|
|
|
|
va_start(ap, fmt);
|
|
|
|
vsnprintf(node, sizeof(node), fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return sexpr_node(sexpr, node);
|
|
|
|
}
|