libvirt/src/util/sexpr.c

633 lines
15 KiB
C
Raw Normal View History

/*
* sexpr.c : S-Expression routines to communicate with the Xen Daemon
*
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
* Copyright (C) 2010 Red Hat, Inc.
* 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.
*/
#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 "memory.h"
#define VIR_FROM_THIS VIR_FROM_SEXPR
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
#define virSexprError(code, ...) \
virReportErrorHelper(NULL, VIR_FROM_SEXPR, code, __FILE__, \
build: consistently use C99 varargs macros Prior to this patch, there was an inconsistent mix between GNU and C99. For consistency, and potential portability to other compilers, stick with the C99 vararg macro syntax. * src/conf/cpu_conf.c (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/conf/domain_conf.c (virDomainReportError): Likewise. * src/conf/domain_event.c (eventReportError): Likewise. * src/conf/interface_conf.c (virInterfaceReportError): Likewise. * src/conf/network_conf.c (virNetworkReportError): Likewise. * src/conf/node_device_conf.h (virNodeDeviceReportError): Likewise. * src/conf/secret_conf.h (virSecretReportError): Likewise. * src/conf/storage_conf.h (virStorageReportError): Likewise. * src/esx/esx_device_monitor.c (ESX_ERROR): Use C99 rather than GNU vararg macro syntax. * src/esx/esx_driver.c (ESX_ERROR): Likewise. * src/esx/esx_interface_driver.c (ESX_ERROR): Likewise. * src/esx/esx_network_driver.c (ESX_ERROR): Likewise. * src/esx/esx_secret_driver.c (ESX_ERROR): Likewise. * src/esx/esx_storage_driver.c (ESX_ERROR): Likewise. * src/esx/esx_util.c (ESX_ERROR): Likewise. * src/esx/esx_vi.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_methods.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vi_types.c (ESX_VI_ERROR): Likewise. * src/esx/esx_vmx.c (ESX_ERROR): Likewise. * src/util/hostusb.c (usbReportError): Use C99 rather than GNU vararg macro syntax. * src/util/json.c (virJSONError): Likewise. * src/util/macvtap.c (ReportError): Likewise. * src/util/pci.c (pciReportError): Likewise. * src/util/stats_linux.c (virStatsError): Likewise. * src/util/util.c (virUtilError): Likewise. * src/util/xml.c (virXMLError): Likewise. * src/xen/proxy_internal.c (virProxyError): Use C99 rather than GNU vararg macro syntax. * src/xen/sexpr.c (virSexprError): Likewise. * src/xen/xen_driver.c (xenUnifiedError): Likewise. * src/xen/xen_hypervisor.c (virXenError): Likewise. * src/xen/xen_inotify.c (virXenInotifyError): Likewise. * src/xen/xend_internal.c (virXendError): Likewise. * src/xen/xm_internal.c (xenXMError): Likewise. * src/xen/xs_internal.c (virXenStoreError): Likewise. * src/cpu/cpu.h (virCPUReportError): Use C99 rather than GNU vararg macro syntax. * src/datatypes.c (virLibConnError): Likewise. * src/interface/netcf_driver.c (interfaceReportError): Likewise. * src/libvirt.c (virLibStreamError): Likewise. * src/lxc/lxc_conf.h (lxcError): Likewise. * src/network/bridge_driver.c (networkReportError): Likewise. * src/nodeinfo.c (nodeReportError): Likewise. * src/opennebula/one_conf.h (oneError): Likewise. * src/openvz/openvz_conf.h (openvzError): Likewise. * src/phyp/phyp_driver.c (PHYP_ERROR): Likewise. * src/qemu/qemu_conf.h (qemuReportError): Likewise. * src/remote/remote_driver.c (errorf): Likewise. * src/security/security_driver.h (virSecurityReportError): Likewise. * src/test/test_driver.c (testError): Likewise. * src/uml/uml_conf.h (umlReportError): Likewise. * src/vbox/vbox_driver.c (vboxError): Likewise. * src/vbox/vbox_tmpl.c (vboxError): Likewise.
2010-03-01 23:38:28 +00:00
__FUNCTION__, __LINE__, __VA_ARGS__)
/**
* 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
* @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(const 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)
goto error;
ret += tmp;
tmp = sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
if (tmp == 0)
goto error;
ret += tmp;
while (sexpr->u.s.cdr->kind != SEXPR_NIL) {
sexpr = sexpr->u.s.cdr;
tmp = snprintf(buffer + ret, n_buffer - ret, " ");
if (tmp == 0)
goto error;
ret += tmp;
tmp =
sexpr2string(sexpr->u.s.car, buffer + ret, n_buffer - ret);
if (tmp == 0)
goto error;
ret += tmp;
}
tmp = snprintf(buffer + ret, n_buffer - ret, ")");
if (tmp == 0)
goto error;
ret += tmp;
break;
case SEXPR_VALUE:
if (strchr(sexpr->u.value, ' ') ||
strchr(sexpr->u.value, ')') ||
strchr(sexpr->u.value, '('))
tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
sexpr->u.value);
else
tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
sexpr->u.value);
if (tmp == 0)
goto error;
ret += tmp;
break;
case SEXPR_NIL:
tmp = snprintf(buffer + ret, n_buffer - ret, "()");
if (tmp == 0)
goto error;
ret += tmp;
break;
default:
goto error;
}
return (ret);
error:
buffer[n_buffer - 1] = 0;
virSexprError(VIR_ERR_SEXPR_SERIAL, "%s", buffer);
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
2008-02-27 10:37:19 +00:00
* 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.
2008-02-27 10:37:19 +00:00
* 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);
}
/**
2007-09-29 18:31:05 +00:00
* 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
2007-09-29 18:31:05 +00:00
* 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.
*/
2007-09-29 18:31:05 +00:00
static struct sexpr *
sexpr_lookup_key(const 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->u.s.car->kind != SEXPR_VALUE) {
return NULL;
}
if (STRNEQ(sexpr->u.s.car->u.value, token)) {
return NULL;
}
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) {
return NULL;
}
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 *
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;
2007-09-29 18:31:05 +00:00
if (s->kind != SEXPR_CONS || s->u.s.cdr->kind != SEXPR_CONS)
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
*
* Returns true if the key was found, false otherwise
2007-09-29 18:31:05 +00:00
*/
int
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)
return 0;
2007-09-29 18:31:05 +00:00
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) {
*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
* NOTE: path are limited to 4096 bytes.
*
* Returns the value of the node or NULL if not found.
*/
const char *
sexpr_fmt_node(const struct sexpr *sexpr, const char *fmt, ...)
{
va_list ap;
char node[4096];
va_start(ap, fmt);
vsnprintf(node, sizeof(node), fmt, ap);
va_end(ap);
return sexpr_node(sexpr, node);
}
/**
* 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;
}