Coverage report for src/sexpr.c.gcov

        -:    0:Source:sexpr.c
        -:    0:Graph:./libvirt_la-sexpr.gcno
        -:    0:Data:./libvirt_la-sexpr.gcda
        -:    0:Runs:1
        -:    0:Programs:1
        -:    1:/*
        -:    2: * sexpr.c : S-Expression routines to communicate with the Xen Daemon
        -:    3: *
        -:    4: * Copyright (C) 2005
        -:    5: *
        -:    6: *      Anthony Liguori <aliguori@us.ibm.com>
        -:    7: *
        -:    8: *  This file is subject to the terms and conditions of the GNU Lesser General
        -:    9: *  Public License. See the file COPYING.LIB in the main directory of this
        -:   10: *  archive for more details.
        -:   11: */
        -:   12:
        -:   13:#define _GNU_SOURCE
        -:   14:
        -:   15:#include "sexpr.h"
        -:   16:#include "internal.h"
        -:   17:
        -:   18:#include <malloc.h>
        -:   19:#include <string.h>
        -:   20:#include <stdio.h>
        -:   21:#include <ctype.h>
        -:   22:#include <errno.h>
        -:   23:
        -:   24:/**
        -:   25: * virSexprError:
        -:   26: * @conn: the connection if available
        -:   27: * @error: the error noumber
        -:   28: * @info: extra information string
        -:   29: *
        -:   30: * Handle an error in the S-Expression code
        -:   31: */
        -:   32:static void
        -:   33:virSexprError(virErrorNumber error, const char *info)
function virSexprError called 0 returned 0% blocks executed 0%
    #####:   34:{
        -:   35:    const char *errmsg;
        -:   36:
    #####:   37:    if (error == VIR_ERR_OK)
branch  0 never executed
branch  1 never executed
    #####:   38:        return;
        -:   39:
    #####:   40:    errmsg = __virErrorMsg(error, info);
call    0 never executed
    #####:   41:    __virRaiseError(NULL, NULL, VIR_FROM_SEXPR, error, VIR_ERR_ERROR,
call    0 never executed
        -:   42:                    errmsg, info, NULL, 0, 0, errmsg, info);
        -:   43:}
        -:   44:
        -:   45:/**
        -:   46: * sexpr_new:
        -:   47: *
        -:   48: * Create a new S-Expression
        -:   49: *
        -:   50: * Returns the new node or NULL in case of memory allocation error
        -:   51: */
        -:   52:static struct sexpr *
        -:   53:sexpr_new(void)
function sexpr_new called 268 returned 100% blocks executed 67%
      268:   54:{
        -:   55:    struct sexpr *ret;
        -:   56:
      268:   57:    ret = (struct sexpr *) malloc(sizeof(*ret));
call    0 returned 100%
      268:   58:    if (ret == NULL) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:   59:        virSexprError(VIR_ERR_NO_MEMORY, "failed to allocate a node");
call    0 never executed
    #####:   60:        return (NULL);
        -:   61:    }
      268:   62:    ret->kind = SEXPR_NIL;
      268:   63:    return ret;
        -:   64:}
        -:   65:
        -:   66:/**
        -:   67: * sexpr_free:
        -:   68: * @sexpr: the S-Expression pointer
        -:   69: *
        -:   70: * Free an S-Expression
        -:   71: */
        -:   72:void
        -:   73:sexpr_free(struct sexpr *sexpr)
function sexpr_free called 268 returned 100% blocks executed 92%
      268:   74:{
      268:   75:    int serrno = errno;
call    0 returned 100%
        -:   76:
      268:   77:    if (sexpr == NULL) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:   78:        return;
        -:   79:    }
        -:   80:
      268:   81:    switch (sexpr->kind) {
branch  0 taken 50%
branch  1 taken 32%
branch  2 taken 18%
        -:   82:        case SEXPR_CONS:
      133:   83:            sexpr_free(sexpr->car);
call    0 returned 100%
      133:   84:            sexpr_free(sexpr->cdr);
call    0 returned 100%
      133:   85:            break;
        -:   86:        case SEXPR_VALUE:
       86:   87:            free(sexpr->value);
call    0 returned 100%
        -:   88:            break;
        -:   89:        case SEXPR_NIL:
        -:   90:            break;
        -:   91:    }
        -:   92:
      268:   93:    free(sexpr);
call    0 returned 100%
        -:   94:
      268:   95:    errno = serrno;
call    0 returned 100%
        -:   96:}
        -:   97:
        -:   98:/**
        -:   99: * sexpr_nil:
        -:  100: *
        -:  101: * Provide a NIL S-Expression (the pointer is not shared so NIL equality
        -:  102: * testing won't work at the pointer level).
        -:  103: *
        -:  104: * Returns a new NIL S-Expression of NULL in case of error.
        -:  105: */
        -:  106:struct sexpr *
        -:  107:sexpr_nil(void)
function sexpr_nil called 133 returned 100% blocks executed 100%
      133:  108:{
      133:  109:    return sexpr_new();
call    0 returned 100%
        -:  110:}
        -:  111:
        -:  112:/**
        -:  113: * sexpr_string:
        -:  114: * @str:  the input string, assumed to be UTF-8
        -:  115: * @len:  the length in bytes of the input
        -:  116: *
        -:  117: * Parse the input S-Expression and return a pointer to the result
        -:  118: *
        -:  119: * Returns the S-Expression pointer or NULL in case of error
        -:  120: */
        -:  121:struct sexpr *
        -:  122:sexpr_string(const char *str, ssize_t len)
function sexpr_string called 0 returned 0% blocks executed 0%
    #####:  123:{
    #####:  124:    struct sexpr *ret = sexpr_new();
call    0 never executed
        -:  125:
    #####:  126:    if (ret == NULL)
branch  0 never executed
branch  1 never executed
    #####:  127:        return ret;
    #####:  128:    ret->kind = SEXPR_VALUE;
    #####:  129:    if (len > 0) {
branch  0 never executed
branch  1 never executed
    #####:  130:        ret->value = strndup(str, len);
call    0 never executed
        -:  131:    } else {
    #####:  132:        ret->value = strdup(str);
call    0 never executed
        -:  133:    }
        -:  134:
    #####:  135:    if (ret->value == NULL) {
branch  0 never executed
branch  1 never executed
    #####:  136:        return NULL;
        -:  137:    }
        -:  138:
    #####:  139:    return ret;
        -:  140:}
        -:  141:
        -:  142:/**
        -:  143: * sexpr_cons:
        -:  144: * @car: the left operand
        -:  145: * @cdr: the right operand
        -:  146: *
        -:  147: * Implement the CONS operation assembling 2 existing S-Expressions.
        -:  148: * Note that in case of error the input data are not freed.
        -:  149: *
        -:  150: * Returns the resulting S-Expression pointer or NULL in case of error.
        -:  151: */
        -:  152:struct sexpr *
        -:  153:sexpr_cons(struct sexpr *car, struct sexpr *cdr)
function sexpr_cons called 0 returned 0% blocks executed 0%
    #####:  154:{
    #####:  155:    struct sexpr *ret = sexpr_new();
call    0 never executed
        -:  156:
    #####:  157:    if (ret == NULL)
branch  0 never executed
branch  1 never executed
    #####:  158:        return ret;
    #####:  159:    ret->kind = SEXPR_CONS;
    #####:  160:    ret->car = car;
    #####:  161:    ret->cdr = cdr;
        -:  162:
    #####:  163:    return ret;
        -:  164:}
        -:  165:
        -:  166:/**
        -:  167: * append:
        -:  168: * @lst: an existing list
        -:  169: * @value: the value
        -:  170: *
        -:  171: * Internal operation appending a value at the end of an existing list
        -:  172: */
        -:  173:static void
        -:  174:append(struct sexpr *lst, struct sexpr *value)
function append called 133 returned 100% blocks executed 100%
      133:  175:{
      501:  176:    while (lst->kind != SEXPR_NIL) {
branch  0 taken 64%
branch  1 taken 36% (fallthrough)
      235:  177:        lst = lst->cdr;
        -:  178:    }
        -:  179:
      133:  180:    lst->kind = SEXPR_CONS;
      133:  181:    lst->car = value;
      133:  182:    lst->cdr = sexpr_nil();
call    0 returned 100%
      133:  183:}
        -:  184:
        -:  185:/**
        -:  186: * @lst: an existing list
        -:  187: * @value: the value
        -:  188: *
        -:  189: * Append a value at the end of an existing list
        -:  190: *
        -:  191: * Returns lst or NULL in case of error
        -:  192: */
        -:  193:struct sexpr *
        -:  194:sexpr_append(struct sexpr *lst, struct sexpr *value)
function sexpr_append called 0 returned 0% blocks executed 0%
    #####:  195:{
    #####:  196:    if (lst == NULL)
branch  0 never executed
branch  1 never executed
    #####:  197:        return (NULL);
    #####:  198:    if (value == NULL)
branch  0 never executed
branch  1 never executed
    #####:  199:        return (lst);
    #####:  200:    append(lst, value);
call    0 never executed
    #####:  201:    return (lst);
        -:  202:}
        -:  203:
        -:  204:/**
        -:  205: * sexpr2string:
        -:  206: * @sexpr: an S-Expression pointer
        -:  207: * @buffer: the output buffer
        -:  208: * @n_buffer: the size of the buffer in bytes
        -:  209: *
        -:  210: * Serialize the S-Expression in the buffer.
        -:  211: * Note that the output may be truncated if @n_buffer is too small
        -:  212: * resulting in an unparseable value.
        -:  213: *
        -:  214: * Returns the number of bytes used by the serialization in the buffer or
        -:  215: *         0 in case of error.
        -:  216: */
        -:  217:size_t
        -:  218:sexpr2string(struct sexpr * sexpr, char *buffer, size_t n_buffer)
function sexpr2string called 0 returned 0% blocks executed 0%
    #####:  219:{
    #####:  220:    size_t ret = 0, tmp;
        -:  221:
    #####:  222:    if ((sexpr == NULL) || (buffer == NULL) || (n_buffer <= 0))
branch  0 never executed
branch  1 never executed
branch  2 never executed
branch  3 never executed
    #####:  223:        return (0);
        -:  224:
    #####:  225:    switch (sexpr->kind) {
branch  0 never executed
branch  1 never executed
branch  2 never executed
branch  3 never executed
        -:  226:        case SEXPR_CONS:
    #####:  227:            tmp = snprintf(buffer + ret, n_buffer - ret, "(");
call    0 never executed
    #####:  228:            if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  229:                goto error;
    #####:  230:            ret += tmp;
    #####:  231:            tmp = sexpr2string(sexpr->car, buffer + ret, n_buffer - ret);
call    0 never executed
    #####:  232:            if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  233:                goto error;
    #####:  234:            ret += tmp;
    #####:  235:            while (sexpr->cdr->kind != SEXPR_NIL) {
branch  0 never executed
branch  1 never executed
    #####:  236:                sexpr = sexpr->cdr;
    #####:  237:                tmp = snprintf(buffer + ret, n_buffer - ret, " ");
call    0 never executed
    #####:  238:                if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  239:                    goto error;
    #####:  240:                ret += tmp;
    #####:  241:                tmp =
call    0 never executed
        -:  242:                    sexpr2string(sexpr->car, buffer + ret, n_buffer - ret);
    #####:  243:                if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  244:                    goto error;
    #####:  245:                ret += tmp;
        -:  246:            }
    #####:  247:            tmp = snprintf(buffer + ret, n_buffer - ret, ")");
call    0 never executed
    #####:  248:            if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  249:                goto error;
    #####:  250:            ret += tmp;
    #####:  251:            break;
        -:  252:        case SEXPR_VALUE:
    #####:  253:            if (strchr(sexpr->value, ' '))
call    0 never executed
branch  1 never executed
branch  2 never executed
    #####:  254:                tmp = snprintf(buffer + ret, n_buffer - ret, "'%s'",
call    0 never executed
        -:  255:                               sexpr->value);
        -:  256:            else
    #####:  257:                tmp = snprintf(buffer + ret, n_buffer - ret, "%s",
call    0 never executed
        -:  258:                               sexpr->value);
    #####:  259:            if (tmp == 0)
branch  0 never executed
branch  1 never executed
    #####:  260:                goto error;
    #####:  261:            ret += tmp;
    #####:  262:            break;
        -:  263:        case SEXPR_NIL:
        -:  264:            break;
        -:  265:        default:
        -:  266:            goto error;
        -:  267:    }
        -:  268:
    #####:  269:    return (ret);
    #####:  270:  error:
    #####:  271:    buffer[n_buffer - 1] = 0;
    #####:  272:    virSexprError(VIR_ERR_SEXPR_SERIAL, buffer);
call    0 never executed
    #####:  273:    return (0);
        -:  274:}
        -:  275:
        -:  276:#define IS_SPACE(c) ((c == 0x20) || (c == 0x9) || (c == 0xD) || (c == 0xA))
        -:  277:
        -:  278:static const char *
        -:  279:trim(const char *string)
function trim called 317 returned 100% blocks executed 100%
      317:  280:{
      683:  281:    while (IS_SPACE(*string))
branch  0 taken 13%
branch  1 taken 87% (fallthrough)
branch  2 taken 0%
branch  3 taken 100% (fallthrough)
branch  4 taken 0%
branch  5 taken 100% (fallthrough)
       49:  282:        string++;
      317:  283:    return (string);
        -:  284:}
        -:  285:
        -:  286:/**
        -:  287: * _string2sexpr:
        -:  288: * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
        -:  289: * @end: pointer to an index in the buffer for the already parsed bytes
        -:  290: *
        -:  291: * Internal routine implementing the parse of S-Expression
        -:  292: * Note that failure in this function is catrosphic.  If it returns
        -:  293: * NULL, you've leaked memory and you're currently OOM.  It will always
        -:  294: * parse an SEXPR given a buffer
        -:  295: *
        -:  296: * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
        -:  297: *         hard error.
        -:  298: */
        -:  299:static struct sexpr *
        -:  300:_string2sexpr(const char *buffer, size_t * end)
function _string2sexpr called 135 returned 100% blocks executed 80%
      135:  301:{
      135:  302:    const char *ptr = buffer + *end;
      135:  303:    struct sexpr *ret = sexpr_new();
call    0 returned 100%
        -:  304:
      135:  305:    if (ret == NULL)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  306:        return NULL;
        -:  307:
      135:  308:    ptr = trim(ptr);
call    0 returned 100%
        -:  309:
      135:  310:    if (ptr[0] == '(') {
branch  0 taken 36% (fallthrough)
branch  1 taken 64%
       49:  311:        ret->kind = SEXPR_NIL;
        -:  312:
       49:  313:        ptr = trim(ptr + 1);
call    0 returned 100%
      231:  314:        while (*ptr && *ptr != ')') {
branch  0 taken 73%
branch  1 taken 27% (fallthrough)
        -:  315:            struct sexpr *tmp;
      133:  316:            size_t tmp_len = 0;
        -:  317:
      133:  318:            tmp = _string2sexpr(ptr, &tmp_len);
call    0 returned 100%
      133:  319:            if (tmp == NULL)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  320:                return NULL;
      133:  321:            append(ret, tmp);
call    0 returned 100%
        -:  322:#if 0
        -:  323:            if (0) {
        -:  324:                char buf[4096];
        -:  325:
        -:  326:                sexpr2string(ret, buf, sizeof(buf));
        -:  327:                printf("%s\n", buffer);
        -:  328:            }
        -:  329:#endif
      133:  330:            ptr = trim(ptr + tmp_len);
call    0 returned 100%
        -:  331:        }
        -:  332:
       49:  333:        if (*ptr == ')') {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
       49:  334:            ptr++;
        -:  335:        }
        -:  336:    } else {
        -:  337:        const char *start;
        -:  338:
       86:  339:        if (*ptr == '\'') {
branch  0 taken 29% (fallthrough)
branch  1 taken 71%
       25:  340:            ptr++;
       25:  341:            start = ptr;
        -:  342:
      468:  343:            while (*ptr && *ptr != '\'') {
branch  0 taken 94%
branch  1 taken 6% (fallthrough)
      418:  344:                if (*ptr == '\\' && ptr[1])
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
branch  2 never executed
branch  3 never executed
    #####:  345:                    ptr++;
      418:  346:                ptr++;
        -:  347:            }
        -:  348:
       25:  349:            ret->value = strndup(start, ptr - start);
call    0 returned 100%
       25:  350:            if (ret->value == NULL) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  351:                virSexprError(VIR_ERR_NO_MEMORY,
call    0 never executed
        -:  352:                              "failed to copy a string");
        -:  353:            }
        -:  354:
       25:  355:            if (*ptr == '\'')
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
       25:  356:                ptr++;
        -:  357:        } else {
       61:  358:            start = ptr;
        -:  359:
      413:  360:            while (*ptr && !isspace(*ptr) && *ptr != ')' && *ptr != '(') {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
call    2 returned 100%
branch  3 taken 86% (fallthrough)
branch  4 taken 14%
branch  5 taken 96% (fallthrough)
branch  6 taken 4%
branch  7 taken 100%
branch  8 taken 0% (fallthrough)
      291:  361:                ptr++;
        -:  362:            }
        -:  363:
       61:  364:            ret->value = strndup(start, ptr - start);
call    0 returned 100%
       61:  365:            if (ret->value == NULL) {
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  366:                virSexprError(VIR_ERR_NO_MEMORY,
call    0 never executed
        -:  367:                              "failed to copy a string");
        -:  368:            }
        -:  369:        }
        -:  370:
       86:  371:        ret->kind = SEXPR_VALUE;
       86:  372:        if (ret->value == NULL)
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
    #####:  373:            goto error;
        -:  374:    }
        -:  375:
      135:  376:    *end = ptr - buffer;
        -:  377:
      135:  378:    return ret;
        -:  379:
    #####:  380:  error:
    #####:  381:    sexpr_free(ret);
call    0 never executed
    #####:  382:    return (NULL);
        -:  383:}
        -:  384:
        -:  385:/**
        -:  386: * string2sexpr:
        -:  387: * @buffer: a zero terminated buffer containing an S-Expression in UTF-8
        -:  388: *
        -:  389: * Parse the S-Expression in the buffer.
        -:  390: * Note that failure in this function is catrosphic.  If it returns
        -:  391: * NULL, you've leaked memory and you're currently OOM.  It will always
        -:  392: * parse an SEXPR given a buffer
        -:  393: *
        -:  394: * Returns a pointer to the resulting parsed S-Expression, or NULL in case of
        -:  395: *         hard error.
        -:  396: */
        -:  397:struct sexpr *
        -:  398:string2sexpr(const char *buffer)
function string2sexpr called 2 returned 100% blocks executed 100%
        2:  399:{
        2:  400:    size_t dummy = 0;
        -:  401:
        2:  402:    return _string2sexpr(buffer, &dummy);
call    0 returned 100%
        -:  403:}
        -:  404:
        -:  405:
        -:  406:/**
        -:  407: * sexpr_lookup:
        -:  408: * @sexpr: a pointer to a parsed S-Expression
        -:  409: * @node: a path for the sub expression to lookup in the S-Expression
        -:  410: *
        -:  411: * Search a sub expression in the S-Expression based on its path
        -:  412: * NOTE: path are limited to 4096 bytes.
        -:  413: *
        -:  414: * Returns the pointer to the sub expression or NULL if not found.
        -:  415: */
        -:  416:struct sexpr *
        -:  417:sexpr_lookup(struct sexpr *sexpr, const char *node)
function sexpr_lookup called 97 returned 100% blocks executed 38%
       97:  418:{
        -:  419:    char buffer[4096], *ptr, *token;
        -:  420:
       97:  421:    if ((node == NULL) || (sexpr == NULL))
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  422:        return (NULL);
        -:  423:
       97:  424:    snprintf(buffer, sizeof(buffer), "%s", node);
call    0 returned 100%
        -:  425:
       97:  426:    ptr = buffer;
      194:  427:    token = strsep(&ptr, "/");
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
branch  4 never executed
branch  5 never executed
branch  6 never executed
branch  7 never executed
call    8 never executed
call    9 never executed
        -:  428:
       97:  429:    if (sexpr->kind != SEXPR_CONS || sexpr->car->kind != SEXPR_VALUE) {
branch  0 taken 96% (fallthrough)
branch  1 taken 4%
branch  2 taken 0% (fallthrough)
branch  3 taken 100%
        4:  430:        return NULL;
        -:  431:    }
        -:  432:
       93:  433:    if (strcmp(sexpr->car->value, token) != 0) {
call    0 returned 100%
branch  1 taken 43% (fallthrough)
branch  2 taken 57%
       40:  434:        return NULL;
        -:  435:    }
        -:  436:
      274:  437:    for (token = strsep(&ptr, "/"); token; token = strsep(&ptr, "/")) {
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
branch  4 never executed
branch  5 never executed
branch  6 never executed
branch  7 never executed
call    8 never executed
call    9 never executed
branch 10 taken 100% (fallthrough)
branch 11 taken 0%
branch 12 taken 100% (fallthrough)
branch 13 taken 0%
branch 14 never executed
branch 15 never executed
branch 16 never executed
branch 17 never executed
call   18 never executed
call   19 never executed
branch 20 taken 71%
branch 21 taken 29% (fallthrough)
        -:  438:        struct sexpr *i;
        -:  439:
       97:  440:        if (token == NULL)
branch  0 taken 0% (fallthrough)
branch  1 taken 100%
    #####:  441:            continue;
        -:  442:
       97:  443:        sexpr = sexpr->cdr;
      439:  444:        for (i = sexpr; i->kind != SEXPR_NIL; i = i->cdr) {
branch  0 taken 97%
branch  1 taken 3% (fallthrough)
      426:  445:            if (i->kind != SEXPR_CONS ||
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
branch  4 taken 100% (fallthrough)
branch  5 taken 0%
        -:  446:                i->car->kind != SEXPR_CONS ||
        -:  447:                i->car->car->kind != SEXPR_VALUE) {
        -:  448:                continue;
        -:  449:            }
        -:  450:
      426:  451:            if (strcmp(i->car->car->value, token) == 0) {
call    0 returned 100%
branch  1 taken 20% (fallthrough)
branch  2 taken 80%
       84:  452:                sexpr = i->car;
       84:  453:                break;
        -:  454:            }
        -:  455:        }
        -:  456:
       97:  457:        if (i->kind == SEXPR_NIL) {
branch  0 taken 13% (fallthrough)
branch  1 taken 87%
       13:  458:            break;
        -:  459:        }
        -:  460:    }
        -:  461:
       53:  462:    if (token != NULL) {
branch  0 taken 25% (fallthrough)
branch  1 taken 75%
       13:  463:        return NULL;
        -:  464:    }
        -:  465:
       40:  466:    if (sexpr->kind != SEXPR_CONS || sexpr->cdr->kind != SEXPR_CONS)
branch  0 taken 100% (fallthrough)
branch  1 taken 0%
branch  2 taken 0% (fallthrough)
branch  3 taken 100%
    #####:  467:        return NULL;
        -:  468:
       40:  469:    return sexpr->cdr;
        -:  470:}
        -:  471:
        -:  472:/**
        -:  473: * sexpr_node:
        -:  474: * @sexpr: a pointer to a parsed S-Expression
        -:  475: * @node: a path for the node to lookup in the S-Expression
        -:  476: *
        -:  477: * Search a node value in the S-Expression based on its path
        -:  478: * NOTE: path are limited to 4096 bytes.
        -:  479: *
        -:  480: * Returns the value of the node or NULL if not found.
        -:  481: */
        -:  482:const char *
        -:  483:sexpr_node(struct sexpr *sexpr, const char *node)
function sexpr_node called 45 returned 100% blocks executed 100%
       45:  484:{
       45:  485:    struct sexpr *n = sexpr_lookup(sexpr, node);
call    0 returned 100%
        -:  486:
       45:  487:    return (n && n->car->kind == SEXPR_VALUE) ? n->car->value : NULL;
branch  0 taken 76% (fallthrough)
branch  1 taken 24%
branch  2 taken 100% (fallthrough)
branch  3 taken 0%
        -:  488:}