[libvirt] [PATCH 08/14] Add a virKeyfilePtr object for parsing '.ini' files

Osier Yang jyang at redhat.com
Thu Mar 22 09:34:54 UTC 2012


On 2012年03月21日 01:33, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange"<berrange at redhat.com>
>
> The '.ini' file format is a useful alternative to the existing
> config file style, when you need to have config files which
> are hashes of hashes. The 'virKeyFilePtr' object provides a
> way to parse these file types.
>
> * src/Makefile.am, src/util/virkeyfile.c,
>    src/util/virkeyfile.h: Add .ini file parser
> * tests/Makefile.am, tests/virkeyfiletest.c: Test
>    basic parsing capabilities
> ---
>   po/POTFILES.in           |    1 +
>   src/Makefile.am          |    1 +
>   src/libvirt_private.syms |   10 ++
>   src/util/virkeyfile.c    |  367 ++++++++++++++++++++++++++++++++++++++++++++++
>   src/util/virkeyfile.h    |   64 ++++++++
>   tests/Makefile.am        |    8 +-
>   tests/virkeyfiletest.c   |  123 ++++++++++++++++
>   7 files changed, 573 insertions(+), 1 deletions(-)
>   create mode 100644 src/util/virkeyfile.c
>   create mode 100644 src/util/virkeyfile.h
>   create mode 100644 tests/virkeyfiletest.c
>
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 16a3f9e..8354c09 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -127,6 +127,7 @@ src/util/util.c
>   src/util/viraudit.c
>   src/util/virfile.c
>   src/util/virhash.c
> +src/util/virkeyfile.c
>   src/util/virnetdev.c
>   src/util/virnetdevbridge.c
>   src/util/virnetdevmacvlan.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 39076cc..07d7faa 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -90,6 +90,7 @@ UTIL_SOURCES =							\
>   		util/virhash.c util/virhash.h			\
>   		util/virhashcode.c util/virhashcode.h           \
>   		util/virkeycode.c util/virkeycode.h		\
> +		util/virkeyfile.c util/virkeyfile.h		\
>   		util/virkeymaps.h				\
>   		util/virmacaddr.h util/virmacaddr.c		\
>   		util/virnetdev.h util/virnetdev.c		\
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 8a14838..3f69ec1 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -1198,6 +1198,16 @@ virKeycodeValueFromString;
>   virKeycodeValueTranslate;
>
>
> +# virkeyfile.h
> +virKeyFileNew;
> +virKeyFileLoadFile;
> +virKeyFileLoadData;
> +virKeyFileFree;
> +virKeyFileHasValue;
> +virKeyFileHasGroup;
> +virKeyFileGetValueString;

Again, the sorting, per all the strings are sorted now. :-)

> +
> +
>   # virmacaddr.h
>   virMacAddrCompare;
>   virMacAddrFormat;
> diff --git a/src/util/virkeyfile.c b/src/util/virkeyfile.c
> new file mode 100644
> index 0000000..3dd4960
> --- /dev/null
> +++ b/src/util/virkeyfile.c
> @@ -0,0 +1,367 @@
> +/*
> + * virkeyfile.c: "ini"-style configuration file handling
> + *
> + * Copyright (C) 2012 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
> + *
> + * Authors:
> + *     Daniel P. Berrange<berrange at redhat.com>
> + */
> +
> +#include<config.h>
> +
> +#include<stdio.h>
> +
> +#include "c-ctype.h"
> +#include "logging.h"
> +#include "memory.h"
> +#include "util.h"
> +#include "virhash.h"
> +#include "virkeyfile.h"
> +#include "virterror_internal.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_CONF
> +
> +typedef struct _virKeyFileGroup virKeyFileGroup;
> +typedef virKeyFileGroup *virKeyFileGroupPtr;
> +
> +typedef struct _virKeyFileParserCtxt virKeyFileParserCtxt;
> +typedef virKeyFileParserCtxt *virKeyFileParserCtxtPtr;
> +
> +struct _virKeyFile {
> +    virHashTablePtr groups;
> +};
> +
> +struct _virKeyFileParserCtxt {
> +    virKeyFilePtr conf;
> +
> +    const char *filename;
> +
> +    const char *base;
> +    const char *cur;
> +    const char *end;
> +    size_t line;
> +
> +    char *groupname;
> +    virHashTablePtr group;
> +};
> +
> +/*
> + * The grammar for the keyfile
> + *
> + * KEYFILE = (GROUP | COMMENT | BLANK )*
> + *
> + * COMMENT = ('#' | ';') [^\n]* '\n'
> + * BLANK = (' ' | '\t' )* '\n'
> + *
> + * GROUP = '[' GROUPNAME ']' '\n' (ENTRY ) *
> + * GROUPNAME = [^[]\n]+
> + *
> + * ENTRY = KEYNAME '=' VALUE
> + * VALUE = [^\n]* '\n'
> + * KEYNAME = [-a-zA-Z0-9]+
> + */
> +
> +#define IS_EOF (ctxt->cur>= ctxt->end)
> +#define IS_EOL(c) (((c) == '\n') || ((c) == '\r'))
> +#define CUR (*ctxt->cur)
> +#define NEXT if (!IS_EOF) ctxt->cur++;
> +
> +
> +#define virKeyFileError(ctxt, error, info) \
> +    virKeyFileErrorHelper(__FILE__, __FUNCTION__, __LINE__, ctxt, error, info)
> +static void
> +virKeyFileErrorHelper(const char *file, const char *func, size_t line,
> +                      virKeyFileParserCtxtPtr ctxt,
> +                      virErrorNumber error, const char *info)
> +{
> +    /* Construct the string 'filename:line: info' if we have that. */
> +    if (ctxt&&  ctxt->filename) {
> +        virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
> +                             _("%s:%zu: %s '%s'"), ctxt->filename, ctxt->line, info, ctxt->cur);
> +    } else {
> +        virReportErrorHelper(VIR_FROM_CONF, error, file, func, line,
> +                             "%s", info);
> +    }
> +}
> +
> +
> +static void virKeyFileValueFree(void *value, const void *name ATTRIBUTE_UNUSED)
> +{
> +    VIR_FREE(value);
> +}
> +
> +static int virKeyFileParseGroup(virKeyFileParserCtxtPtr ctxt)
> +{
> +    int ret = -1;
> +    const char *name;
> +    NEXT;
> +
> +    ctxt->group = NULL;
> +    VIR_FREE(ctxt->groupname);
> +
> +    name = ctxt->cur;
> +    while (!IS_EOF&&  c_isascii(CUR)&&  CUR != ']')
> +        ctxt->cur++;
> +    if (CUR != ']') {
> +        virKeyFileError(ctxt, VIR_ERR_CONF_SYNTAX, "cannot find end of group name, expected ']'");
> +        return -1;
> +    }
> +
> +    if (!(ctxt->groupname = strndup(name, ctxt->cur - name))) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +
> +    NEXT;
> +
> +    if (!(ctxt->group = virHashCreate(10, virKeyFileValueFree)))
> +        goto cleanup;
> +
> +    if (virHashAddEntry(ctxt->conf->groups, ctxt->groupname, ctxt->group)<  0)
> +        goto cleanup;
> +
> +    ret = 0;
> +cleanup:
> +    if (ret != 0) {
> +        virHashFree(ctxt->group);
> +        ctxt->group = NULL;
> +        VIR_FREE(ctxt->groupname);
> +    }
> +
> +    return ret;
> +}
> +
> +static int virKeyFileParseValue(virKeyFileParserCtxtPtr ctxt)
> +{
> +    int ret = -1;
> +    const char *keystart;
> +    const char *valuestart;
> +    char *key = NULL;
> +    char *value = NULL;
> +    size_t len;
> +
> +    if (!ctxt->groupname || !ctxt->group) {
> +        virKeyFileError(ctxt, VIR_ERR_CONF_SYNTAX, "value found before first group");
> +        return -1;
> +    }
> +
> +    keystart = ctxt->cur;
> +    while (!IS_EOF&&  c_isalnum(CUR)&&  CUR != '=')
> +        ctxt->cur++;
> +    if (CUR != '=') {
> +        virKeyFileError(ctxt, VIR_ERR_CONF_SYNTAX, "expected end of value name, expected '='");
> +        return -1;
> +    }
> +
> +    if (!(key = strndup(keystart, ctxt->cur - keystart))) {
> +        virReportOOMError();
> +        return -1;
> +    }
> +
> +    NEXT;
> +    valuestart = ctxt->cur;
> +    while (!IS_EOF&&  !IS_EOL(CUR))
> +        ctxt->cur++;
> +    if (!(IS_EOF || IS_EOL(CUR))) {
> +        virKeyFileError(ctxt, VIR_ERR_CONF_SYNTAX, "unexpected end of value");
> +        goto cleanup;
> +    }
> +    len = ctxt->cur - valuestart;
> +    if (IS_EOF&&  !IS_EOL(CUR))
> +        len++;
> +    if (!(value = strndup(valuestart, len))) {
> +        virReportOOMError();
> +        goto cleanup;
> +    }
> +
> +    if (virHashAddEntry(ctxt->group, key, value)<  0)
> +        goto cleanup;
> +
> +    NEXT;
> +
> +    ret = 0;
> +
> +cleanup:
> +    VIR_FREE(key);

Do we need to VIR_FREE(value) too?

ACK otherwise.




More information about the libvir-list mailing list