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>
|
start using c-ctype functions
Up to now, we've been avoiding ctype functions like isspace, isdigit,
etc. because they are locale-dependent. Now that we have the c-ctype
functions, we can start using *them*, to make the code more readable
with changes like these:
- /* This may not work on EBCDIC. */
- if ((*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9'))
+ if (c_isalnum(*p))
- while ((*cur >= '0') && (*cur <= '9')) {
+ while (c_isdigit(*cur)) {
Also, some macros in conf.c used names that conflicted with
standard meaning of "BLANK" and "SPACE", so I've adjusted them
to be in line with the definition of e.g., isblank.
In addition, I've wrapped those statement macros with do {...} while (0),
so that we can't forget the ";" after a use. There was one like that
already (fixed below). The missing semicolon would mess up automatic
indenting.
* src/buf.c (virBufferURIEncodeString):
* src/conf.c (IS_EOL, SKIP_BLANKS_AND_EOL, SKIP_BLANKS)
(virConfParseLong, virConfParseValue, virConfParseName)
(virConfParseSeparator, virConfParseStatement, IS_BLANK, IS_CHAR)
(IS_DIGIT, IS_SPACE, SKIP_SPACES):
* src/nodeinfo.c:
* src/qemu_conf.c (qemudParseInterfaceXML):
* src/qemu_driver.c (qemudDomainBlockStats):
* src/sexpr.c:
* src/stats_linux.c:
* src/util.c (virParseNumber, virDiskNameToIndex):
* src/uuid.c (hextobin, virUUIDParse):
* src/virsh.c:
* src/xml.c (parseCpuNumber, virParseCpuSet):
2008-05-16 09:37:44 +00:00
|
|
|
#include "c-ctype.h"
|
2006-01-11 13:58:32 +00:00
|
|
|
#include <errno.h>
|
|
|
|
|
2008-11-04 22:30:33 +00:00
|
|
|
#include "virterror_internal.h"
|
2007-12-07 14:39:14 +00:00
|
|
|
#include "sexpr.h"
|
2008-04-25 14:53:05 +00:00
|
|
|
#include "util.h"
|
2008-06-06 11:09:57 +00:00
|
|
|
#include "memory.h"
|
2007-12-07 14:39:14 +00:00
|
|
|
|
2009-01-29 12:10:32 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_SEXPR
|
|
|
|
|
2008-10-09 15:38:31 +00:00
|
|
|
#define virSexprError(code, fmt...) \
|
2008-11-04 22:30:33 +00:00
|
|
|
virReportErrorHelper(NULL, VIR_FROM_SEXPR, code, __FILE__, \
|
2008-10-09 15:38:31 +00:00
|
|
|
__FUNCTION__, __LINE__, fmt)
|
2006-02-27 21:34:28 +00:00
|
|
|
|
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;
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
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:
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(sexpr->u.value);
|
2006-01-11 13:58:32 +00:00
|
|
|
break;
|
|
|
|
case SEXPR_NIL:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(sexpr);
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
2008-06-06 11:09:57 +00:00
|
|
|
static int
|
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
|
|
|
{
|
2008-06-06 11:09:57 +00:00
|
|
|
struct sexpr *nil = sexpr_nil();
|
|
|
|
|
|
|
|
if (nil == NULL)
|
|
|
|
return -1;
|
|
|
|
|
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;
|
2008-06-06 11:09:57 +00:00
|
|
|
lst->u.s.cdr = nil;
|
|
|
|
|
|
|
|
return 0;
|
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);
|
2008-06-06 11:09:57 +00:00
|
|
|
if (append(lst, value) < 0)
|
|
|
|
return (NULL);
|
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:
|
2009-08-25 21:54:18 +00:00
|
|
|
tmp = snprintf(buffer + ret, n_buffer - ret, "()");
|
|
|
|
if (tmp == 0)
|
|
|
|
goto error;
|
|
|
|
ret += tmp;
|
2006-01-11 13:58:32 +00:00
|
|
|
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;
|
2008-10-09 15:38:31 +00:00
|
|
|
virSexprError(VIR_ERR_SEXPR_SERIAL, "%s", 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)
|
2008-06-06 11:09:57 +00:00
|
|
|
goto error;
|
|
|
|
if (append(ret, tmp) < 0) {
|
|
|
|
sexpr_free(tmp);
|
|
|
|
goto error;
|
|
|
|
}
|
2006-01-11 13:58:32 +00:00
|
|
|
#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) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2008-06-06 11:09:57 +00:00
|
|
|
goto error;
|
2006-03-15 12:13:25 +00:00
|
|
|
}
|
2006-01-11 13:58:32 +00:00
|
|
|
|
|
|
|
if (*ptr == '\'')
|
|
|
|
ptr++;
|
|
|
|
} else {
|
|
|
|
start = ptr;
|
|
|
|
|
2008-05-09 13:50:14 +00:00
|
|
|
while (*ptr && !c_isspace(*ptr)
|
2008-04-25 14:53:05 +00:00
|
|
|
&& *ptr != ')' && *ptr != '(') {
|
2006-01-11 13:58:32 +00:00
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
2007-09-29 18:16:26 +00:00
|
|
|
ret->u.value = strndup(start, ptr - start);
|
|
|
|
if (ret->u.value == NULL) {
|
2009-01-29 12:10:32 +00:00
|
|
|
virReportOOMError(NULL);
|
2008-06-06 11:09:57 +00:00
|
|
|
goto error;
|
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;
|
|
|
|
}
|
|
|
|
|
2008-05-14 19:51:24 +00:00
|
|
|
if (STRNEQ(sexpr->u.s.car->u.value, token)) {
|
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
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-05-14 19:51:24 +00:00
|
|
|
if (STREQ(i->u.s.car->u.s.car->u.value, token)) {
|
2007-09-29 18:16:26 +00:00
|
|
|
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)
|
2008-04-10 16:54:54 +00:00
|
|
|
return NULL;
|
2007-09-29 18:31:05 +00:00
|
|
|
|
|
|
|
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
|
2008-08-01 14:43:12 +00:00
|
|
|
sexpr_has(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)
|
2008-04-10 16:54:54 +00:00
|
|
|
return 0;
|
2007-09-29 18:31:05 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2008-07-25 10:49:33 +00:00
|
|
|
int sexpr_node_copy(const struct sexpr *sexpr, const char *node, char **dst)
|
|
|
|
{
|
|
|
|
const char *val = sexpr_node(sexpr, node);
|
|
|
|
|
|
|
|
if (val) {
|
|
|
|
*dst = strdup(val);
|
|
|
|
if (!(*dst))
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
*dst = NULL;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|