On 2012年03月21日 01:33, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange(a)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(a)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.