On 2012年03月21日 01:33, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@xxxxxxxxxx> 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@xxxxxxxxxx> + */ + +#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. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list