[Libguestfs] [PATCH 1/6] Move ini_reader from builder to mllib

Pino Toscano ptoscano at redhat.com
Wed Jul 8 14:42:13 UTC 2015


Move the C INI reader and its OCaml binding from builder to mllib, so it
can be used also elsewhere.
---
 .gitignore               |   6 +-
 builder/Makefile.am      |  40 ++++-------
 builder/index-parse.y    | 176 -----------------------------------------------
 builder/index-parser-c.c | 121 --------------------------------
 builder/index-scan.l     | 144 --------------------------------------
 builder/index-struct.c   |  60 ----------------
 builder/index-struct.h   |  67 ------------------
 builder/ini_reader.ml    |  40 -----------
 builder/ini_reader.mli   |  24 -------
 mllib/Makefile.am        |  16 ++++-
 mllib/index-parse.y      | 176 +++++++++++++++++++++++++++++++++++++++++++++++
 mllib/index-parser-c.c   | 121 ++++++++++++++++++++++++++++++++
 mllib/index-scan.l       | 144 ++++++++++++++++++++++++++++++++++++++
 mllib/index-struct.c     |  60 ++++++++++++++++
 mllib/index-struct.h     |  67 ++++++++++++++++++
 mllib/ini_reader.ml      |  40 +++++++++++
 mllib/ini_reader.mli     |  24 +++++++
 po/POTFILES              |   8 +--
 po/POTFILES-ml           |   2 +-
 19 files changed, 668 insertions(+), 668 deletions(-)
 delete mode 100644 builder/index-parse.y
 delete mode 100644 builder/index-parser-c.c
 delete mode 100644 builder/index-scan.l
 delete mode 100644 builder/index-struct.c
 delete mode 100644 builder/index-struct.h
 delete mode 100644 builder/ini_reader.ml
 delete mode 100644 builder/ini_reader.mli
 create mode 100644 mllib/index-parse.y
 create mode 100644 mllib/index-parser-c.c
 create mode 100644 mllib/index-scan.l
 create mode 100644 mllib/index-struct.c
 create mode 100644 mllib/index-struct.h
 create mode 100644 mllib/ini_reader.ml
 create mode 100644 mllib/ini_reader.mli

diff --git a/.gitignore b/.gitignore
index 6089122..8aded3b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,9 +55,6 @@ Makefile.in
 /bash/virt-sparsify
 /build-aux
 /builder/.depend
-/builder/index-parse.c
-/builder/index-parse.h
-/builder/index-scan.c
 /builder/libguestfs.conf
 /builder/*.qcow2
 /builder/stamp-virt-builder.pod
@@ -312,6 +309,9 @@ Makefile.in
 /mllib/common_utils_tests
 /mllib/config.ml
 /mllib/dummy
+/mllib/index-parse.c
+/mllib/index-parse.h
+/mllib/index-scan.c
 /mllib/JSON_tests
 /mllib/libdir.ml
 /mllib/oUnit-*
diff --git a/builder/Makefile.am b/builder/Makefile.am
index d69e25f..1d9ad54 100644
--- a/builder/Makefile.am
+++ b/builder/Makefile.am
@@ -17,8 +17,6 @@
 
 include $(top_srcdir)/subdir-rules.mk
 
-AM_YFLAGS = -d
-
 EXTRA_DIST = \
 	$(SOURCES_MLI) $(SOURCES_ML) $(SOURCES_C) \
 	libguestfs.gpg \
@@ -40,7 +38,6 @@ SOURCES_MLI = \
 	cache.mli \
 	downloader.mli \
 	index_parser.mli \
-	ini_reader.mli \
 	languages.mli \
 	list_entries.mli \
 	pxzcat.mli \
@@ -52,7 +49,6 @@ SOURCES_ML = \
 	utils.ml \
 	pxzcat.ml \
 	setlocale.ml \
-	ini_reader.ml \
 	paths.ml \
 	languages.ml \
 	cache.ml \
@@ -68,14 +64,14 @@ SOURCES_C = \
 	$(top_srcdir)/mllib/fsync-c.c \
 	$(top_srcdir)/mllib/uri-c.c \
 	$(top_srcdir)/mllib/mkdtemp-c.c \
+	$(top_srcdir)/mllib/index-parse.c \
+	$(top_srcdir)/mllib/index-parser-c.c \
+	$(top_srcdir)/mllib/index-scan.c \
+	$(top_srcdir)/mllib/index-struct.c \
 	$(top_srcdir)/customize/perl_edit-c.c \
 	$(top_srcdir)/customize/crypt-c.c \
 	$(top_srcdir)/fish/uri.c \
 	$(top_srcdir)/fish/file-edit.c \
-	index-scan.c \
-	index-struct.c \
-	index-parse.c \
-	index-parser-c.c \
 	pxzcat-c.c \
 	setlocale-c.c
 
@@ -95,7 +91,8 @@ virt_builder_CPPFLAGS = \
 	-I$(shell $(OCAMLC) -where) \
 	-I$(top_srcdir)/gnulib/lib \
 	-I$(top_srcdir)/src \
-	-I$(top_srcdir)/fish
+	-I$(top_srcdir)/fish \
+	-I$(top_srcdir)/mllib
 virt_builder_CFLAGS = \
 	-pthread \
 	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
@@ -115,6 +112,7 @@ BOBJECTS = \
 	$(top_builddir)/mllib/JSON.cmo \
 	$(top_builddir)/mllib/uRI.cmo \
 	$(top_builddir)/mllib/mkdtemp.cmo \
+	$(top_builddir)/mllib/ini_reader.cmo \
 	$(top_builddir)/customize/customize_utils.cmo \
 	$(top_builddir)/customize/urandom.cmo \
 	$(top_builddir)/customize/random_seed.cmo \
@@ -273,10 +271,10 @@ install-exec-hook:
 bin_PROGRAMS += virt-index-validate
 
 virt_index_validate_SOURCES = \
-	index-parse.y \
-	index-scan.l \
-	index-struct.h \
-	index-struct.c \
+	$(top_srcdir)/mllib/index-parse.c \
+	$(top_srcdir)/mllib/index-scan.c \
+	$(top_srcdir)/mllib/index-struct.h \
+	$(top_srcdir)/mllib/index-struct.c \
 	index-validate.c
 
 virt_index_validate_CPPFLAGS = \
@@ -284,7 +282,8 @@ virt_index_validate_CPPFLAGS = \
 	-I. \
 	-I$(top_builddir) \
 	-I$(top_srcdir)/gnulib/lib -I$(top_builddir)/gnulib/lib \
-	-I$(top_srcdir)/src
+	-I$(top_srcdir)/src \
+	-I$(top_srcdir)/mllib
 virt_index_validate_CFLAGS = \
 	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
 	-Wno-unused-macros
@@ -306,21 +305,8 @@ stamp-virt-index-validate.pod: virt-index-validate.pod
 	touch $@
 
 CLEANFILES += \
-	index-parse.c \
-	index-parse.h \
-	index-scan.c \
 	stamp-virt-index-validate.pod
 
-if HAVE_OCAML
-# Automake-generated makefile has a rule ".y.c" but lacks a rule ".y.h".
-index-parse.h: index-parse.y
-	touch $(srcdir)/index-parse.y
-	$(MAKE) index-parse.c
-# Also it doesn't generate dependencies for the C files that include
-# index-parse.h.
-index-parser-c.c index-scan.c index-validate.c: index-parse.h
-endif
-
 # Apparently there's no clean way with Automake to not have them
 # in the distribution, so just remove them from the distdir.
 dist-hook:
diff --git a/builder/index-parse.y b/builder/index-parse.y
deleted file mode 100644
index 82ea9d2..0000000
--- a/builder/index-parse.y
+++ /dev/null
@@ -1,176 +0,0 @@
-/* libguestfs virt-builder tool -*- fundamental -*-
- * Copyright (C) 2013 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-%{
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "index-struct.h"
-#include "index-parse.h"
-
-#define YY_EXTRA_TYPE struct parse_context *
-
-extern void yyerror (YYLTYPE * yylloc, yyscan_t scanner, struct parse_context *context, const char *msg);
-extern int yylex (YYSTYPE * yylval, YYLTYPE * yylloc, yyscan_t scanner);
-
-extern int do_parse (struct parse_context *context, FILE *in);
-extern void scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in);
-extern void scanner_destroy (yyscan_t scanner);
-
-/* Join two strings with \n */
-static char *
-concat_newline (const char *str1, const char *str2)
-{
-  size_t len1, len2, len;
-  char *ret;
-
-  if (str2 == NULL)
-    return strdup (str1);
-
-  len1 = strlen (str1);
-  len2 = strlen (str2);
-  len = len1 + 1 /* \n */ + len2 + 1 /* \0 */;
-  ret = malloc (len);
-  memcpy (ret, str1, len1);
-  ret[len1] = '\n';
-  memcpy (ret + len1 + 1, str2, len2);
-  ret[len-1] = '\0';
-
-  return ret;
-}
-
-%}
-
-%code requires {
-#ifndef YY_TYPEDEF_YY_SCANNER_T
-#define YY_TYPEDEF_YY_SCANNER_T
-typedef void *yyscan_t;
-#endif
-}
-
-%locations
-
-%union {
-  struct section *section;
-  struct field *field;
-  char *str;
-}
-
-%token <str>   SECTION_HEADER
-%token <field> FIELD
-%token <str>   VALUE_CONT
-%token         EMPTY_LINE
-%token         PGP_PROLOGUE
-%token         PGP_EPILOGUE
-%token         UNKNOWN_LINE
-
-%type <section> sections section
-%type <field>   fields field
-%type <str>     continuations
-
-%pure-parser
-
-%lex-param   { yyscan_t scanner }
-%parse-param { yyscan_t scanner }
-%parse-param { struct parse_context *context }
-
-%destructor { section_free ($$); } <section>
-%destructor { field_free ($$); } <field>
-
-%%
-
-index:
-      sections
-        { context->parsed_index = $1; }
-    | PGP_PROLOGUE sections PGP_EPILOGUE
-        { context->parsed_index = $2; }
-
-sections:
-      emptylines section emptylines
-        { $$ = $2; }
-    | emptylines section EMPTY_LINE emptylines sections
-        { $$ = $2; $$->next = $5; }
-    | emptylines
-        { $$ = NULL; }
-
-section:
-      SECTION_HEADER fields
-        { $$ = malloc (sizeof (struct section));
-          $$->next = NULL;
-          $$->name = $1;
-          $$->fields = $2; }
-
-fields:
-      /* empty */
-        { $$ = NULL; }
-    | field fields
-        { $$ = $1; $$->next = $2; }
-
-field: FIELD continuations
-        { $$ = $1;
-          char *old_value = $$->value;
-          $$->value = concat_newline (old_value, $2);
-          free (old_value);
-          free ($2); }
-
-continuations:
-      /* empty */
-        { $$ = NULL; }
-    | VALUE_CONT continuations
-        { $$ = concat_newline ($1, $2);
-          free ($1);
-          free ($2); }
-
-emptylines:
-      /* empty */
-        {}
-    | EMPTY_LINE emptylines
-        {}
-
-%%
-
-void
-yyerror (YYLTYPE * yylloc, yyscan_t scanner, struct parse_context *context, const char *msg)
-{
-  int has_suffix = context->error_suffix != NULL && context->error_suffix[0] != 0;
-
-  fprintf (stderr, "%s%s%s%ssyntax error at line %d: %s%s%s\n",
-           context->progname ? context->progname : "",
-           context->progname ? ": " : "",
-           context->input_file ? context->input_file : "",
-           context->input_file ? ": " : "",
-           yylloc->first_line, msg,
-           has_suffix ? " " : "",
-           has_suffix ? context->error_suffix : "");
-}
-
-int
-do_parse (struct parse_context *context, FILE *in)
-{
-  yyscan_t scanner;
-  int res;
-
-  scanner_init (&scanner, context, in);
-  res = yyparse (scanner, context);
-  scanner_destroy (scanner);
-
-  return res;
-}
diff --git a/builder/index-parser-c.c b/builder/index-parser-c.c
deleted file mode 100644
index 52c8b86..0000000
--- a/builder/index-parser-c.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/* virt-builder
- * Copyright (C) 2013 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* This file handles the interface between the C/lex/yacc index file
- * parser, and the OCaml world.  See index_parser.ml for the OCaml
- * type definition.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <caml/alloc.h>
-#include <caml/fail.h>
-#include <caml/memory.h>
-#include <caml/mlvalues.h>
-
-#ifdef HAVE_CAML_UNIXSUPPORT_H
-#include <caml/unixsupport.h>
-#else
-#define Nothing ((value) 0)
-extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
-#endif
-
-#include "index-struct.h"
-#include "index-parse.h"
-
-extern int do_parse (struct parse_context *context, FILE *in);
-
-extern value virt_builder_parse_index (value progv, value error_suffixv, value filenamev);
-
-value
-virt_builder_parse_index (value progv, value error_suffixv, value filenamev)
-{
-  CAMLparam2 (progv, filenamev);
-  CAMLlocal5 (rv, v, sv, sv2, fv);
-  struct section *sections;
-  size_t i, nr_sections;
-  struct parse_context context;
-  FILE *in;
-
-  parse_context_init (&context);
-  context.progname = String_val (progv);
-  context.input_file = String_val (filenamev);
-  context.error_suffix = String_val (error_suffixv);
-
-  in = fopen (String_val (filenamev), "r");
-  if (in == NULL)
-    unix_error (errno, (char *) "fopen", filenamev);
-
-  if (do_parse (&context, in) != 0) {
-    fclose (in);
-    caml_invalid_argument ("parse error");
-  }
-
-  if (fclose (in) == EOF)
-    unix_error (errno, (char *) "fclose", filenamev);
-
-  /* Convert the parsed data to OCaml structures. */
-  nr_sections = 0;
-  for (sections = context.parsed_index; sections != NULL; sections = sections->next)
-    nr_sections++;
-  rv = caml_alloc (nr_sections, 0);
-
-  for (i = 0, sections = context.parsed_index; sections != NULL;
-       i++, sections = sections->next) {
-    struct field *fields;
-    size_t j, nr_fields;
-
-    nr_fields = 0;
-    for (fields = sections->fields; fields != NULL; fields = fields->next)
-      nr_fields++;
-    fv = caml_alloc (nr_fields, 0);
-
-    for (j = 0, fields = sections->fields; fields != NULL;
-         j++, fields = fields->next) {
-      v = caml_alloc_tuple (3);
-      sv = caml_copy_string (fields->key);
-      Store_field (v, 0, sv);   /* (key, Some subkey, value) */
-      if (fields->subkey) {
-        sv2 = caml_copy_string (fields->subkey);
-        sv = caml_alloc (1, 0);
-        Store_field (sv, 0, sv2);
-      } else
-        sv = Val_int (0);
-      Store_field (v, 1, sv);
-      sv = caml_copy_string (fields->value);
-      Store_field (v, 2, sv);
-      Store_field (fv, j, v);   /* assign to return array of fields */
-    }
-
-    v = caml_alloc_tuple (2);
-    sv = caml_copy_string (sections->name);
-    Store_field (v, 0, sv);     /* (name, fields) */
-    Store_field (v, 1, fv);
-    Store_field (rv, i, v);     /* assign to return array of sections */
-  }
-
-  /* Free parsed data. */
-  parse_context_free (&context);
-
-  CAMLreturn (rv);
-}
diff --git a/builder/index-scan.l b/builder/index-scan.l
deleted file mode 100644
index 7125913..0000000
--- a/builder/index-scan.l
+++ /dev/null
@@ -1,144 +0,0 @@
-/* libguestfs virt-builder tool -*- fundamental -*-
- * Copyright (C) 2013 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-%top{
-#include <config.h>
-}
-
-%{
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Silence gcc warnings from the generated code. */
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-/* flex creates macros that it doesn't use */
-#pragma GCC diagnostic ignored "-Wunused-macros"
-/* on aarch64, flex doesn't know that char is unsigned */
-#pragma GCC diagnostic ignored "-Wsign-compare"
-/* on debian-mipsel, flex doesn't create prototypes for all functions */
-#pragma GCC diagnostic ignored "-Wmissing-prototypes"
-#endif
-
-#include "index-struct.h"
-#include "index-parse.h"
-
-#define YY_EXTRA_TYPE struct parse_context *
-#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;
-
-extern void scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in);
-extern void scanner_destroy (yyscan_t scanner);
-
-%}
-
-%option nounput
-%option noyywrap
-%option yylineno
-%option reentrant
-%option bison-bridge
-%option bison-locations
-
-%%
-
- /* Apart from the PGP prologue/epilogue which is a hack, the
-  * scanning strategy is to deal with the file strictly line by
-  * line, and pass those lines up to the parser which deals with
-  * whether they appear in the right order to be meaningful.
-  * Note that flex does longest-match.
-  */
-
-  /* Ignore comments - '#' MUST appear at the start of a line. */
-^"#".*\n                { yyextra->seen_comments++; }
-
-  /* An empty line is significant. */
-^\n                                     { return EMPTY_LINE; }
-
-  /* [...] marks beginning of a section. */
-^"["[-A-Za-z0-9._]+"]"\n {
-                      yylval->str = strndup (yytext+1, yyleng-3);
-                      return SECTION_HEADER;
-                    }
-
-  /* field=value or field[subfield]=value */
-^[A-Za-z0-9_.]+("["[A-Za-z0-9_,.]+"]")?"=".*\n {
-                      size_t i = strcspn (yytext, "=[");
-                      yylval->field = malloc (sizeof (struct field));
-                      yylval->field->next = NULL;
-                      yylval->field->key = strndup (yytext, i);
-                      if (yytext[i] == '[') {
-                        size_t j = strcspn (yytext+i+1, "]");
-                        yylval->field->subkey = strndup (yytext+i+1, j);
-                        i += 1+j+1;
-                      } else {
-                        yylval->field->subkey = NULL;
-                      }
-                      /* Note we chop the final \n off here. */
-                      yylval->field->value = strndup (yytext+i+1, yyleng-(i+2));
-                      return FIELD;
-                    }
-
-  /* Continuation line for multi-line values. */
-^[[:blank:]].*\n        {
-                      yylval->str = strndup (yytext+1, yyleng-2);
-                      return VALUE_CONT;
-                    }
-
- /* Hack to eat the PGP prologue. */
-^"-----BEGIN PGP SIGNED MESSAGE-----\n"  {
-  int c, prevnl = 0;
-
-  /* Eat everything to the first blank line. */
-  while ((c = input (yyscanner)) != EOF) {
-    if (c == '\n' && prevnl)
-      break;
-    prevnl = c == '\n';
-  }
-
-  return PGP_PROLOGUE;
-}
-
- /* Hack to eat the PGP epilogue. */
-^"-----BEGIN PGP SIGNATURE-----\n"  {
-  /* Eat everything to the end of the file. */
-  while (input (yyscanner) != EOF)
-    ;
-
-  return PGP_EPILOGUE;
-}
-
- /* anything else is an error */
-. {
-  return UNKNOWN_LINE;
-}
-
-%%
-
-void
-scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in)
-{
-  yylex_init (scanner);
-  yyset_extra (context, *scanner);
-  yyset_in (in, *scanner);
-}
-
-void
-scanner_destroy (yyscan_t scanner)
-{
-  yylex_destroy (scanner);
-}
diff --git a/builder/index-struct.c b/builder/index-struct.c
deleted file mode 100644
index eacca6c..0000000
--- a/builder/index-struct.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* libguestfs virt-builder tool
- * Copyright (C) 2013 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "index-struct.h"
-
-void
-parse_context_init (struct parse_context *context)
-{
-  memset (context, 0, sizeof *context);
-}
-
-void
-parse_context_free (struct parse_context *context)
-{
-  section_free (context->parsed_index);
-}
-
-void
-section_free (struct section *section)
-{
-  if (section) {
-    section_free (section->next);
-    free (section->name);
-    field_free (section->fields);
-    free (section);
-  }
-}
-
-void
-field_free (struct field *field)
-{
-  if (field) {
-    field_free (field->next);
-    free (field->key);
-    free (field->subkey);
-    free (field->value);
-    free (field);
-  }
-}
diff --git a/builder/index-struct.h b/builder/index-struct.h
deleted file mode 100644
index ada35e3..0000000
--- a/builder/index-struct.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* libguestfs virt-builder tool
- * Copyright (C) 2013 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-/* The data structures produced when parsing the index file. */
-
-#ifndef INDEX_STRUCT_H
-#define INDEX_STRUCT_H
-
-/* A section or list of sections. */
-struct section {
-  struct section *next;
-  char *name;
-  struct field *fields;
-};
-
-/* A field or list of fields. */
-struct field {
-  struct field *next;
-  char *key;
-  char *subkey;
-  char *value;
-};
-
-/* A struct holding the data needed during the parsing. */
-struct parse_context {
-  struct section *parsed_index;        /* The result of the parsing. */
-  /* yyparse sets this if any comments were seen.  Required for checking
-   * compatibility with virt-builder 1.24.
-   */
-  int seen_comments;
-  const char *input_file;
-  const char *progname;
-  const char *error_suffix;
-};
-
-/* Initialize the content of a parse_context. */
-extern void parse_context_init (struct parse_context *state);
-
-/* Free the content of a parse_context.  The actual pointer is not freed. */
-extern void parse_context_free (struct parse_context *state);
-
-/* Free the content of a section, recursively freeing also its fields.
- * The actual pointer is not freed.
- */
-extern void section_free (struct section *section);
-
-/* Free the content of a field, recursively freeing also its next field.
- * The actual pointer is not freed.
- */
-extern void field_free (struct field *field);
-
-#endif /* INDEX_STRUCT_H */
diff --git a/builder/ini_reader.ml b/builder/ini_reader.ml
deleted file mode 100644
index 50a06f9..0000000
--- a/builder/ini_reader.ml
+++ /dev/null
@@ -1,40 +0,0 @@
-(* virt-builder
- * Copyright (C) 2013-2015 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *)
-
-open Common_utils
-
-type sections = section list
-and section = string * fields                (* [name] + fields *)
-and fields = field list
-and field = string * string option * string  (* key + subkey + value *)
-
-(* Types returned by the C index parser. *)
-type c_sections = c_section array
-and c_section = string * c_fields             (* [name] + fields *)
-and c_fields = field array
-
-(* Calls yyparse in the C code. *)
-external parse_index : prog:string -> error_suffix:string -> string -> c_sections = "virt_builder_parse_index"
-
-let read_ini ?(error_suffix = "") file =
-  let sections = parse_index ~prog ~error_suffix file in
-  let sections = Array.to_list sections in
-  List.map (
-    fun (n, fields) ->
-      n, Array.to_list fields
-  ) sections
diff --git a/builder/ini_reader.mli b/builder/ini_reader.mli
deleted file mode 100644
index 62567e8..0000000
--- a/builder/ini_reader.mli
+++ /dev/null
@@ -1,24 +0,0 @@
-(* virt-builder
- * Copyright (C) 2013-2015 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *)
-
-type sections = section list
-and section = string * fields                (* [name] + fields *)
-and fields = field list
-and field = string * string option * string  (* key + subkey + value *)
-
-val read_ini : ?error_suffix:string -> string -> sections
diff --git a/mllib/Makefile.am b/mllib/Makefile.am
index 272c981..f7f3a66 100644
--- a/mllib/Makefile.am
+++ b/mllib/Makefile.am
@@ -17,6 +17,8 @@
 
 include $(top_srcdir)/subdir-rules.mk
 
+AM_YFLAGS = -d
+
 EXTRA_DIST = \
 	$(SOURCES_MLI) \
 	$(filter-out config.ml libdir.ml,$(SOURCES_ML)) \
@@ -29,6 +31,7 @@ CLEANFILES = *~ *.annot *.cmi *.cmo *.cmx *.cmxa *.o
 SOURCES_MLI = \
 	common_utils.mli \
 	fsync.mli \
+	ini_reader.mli \
 	JSON.mli \
 	mkdtemp.mli \
 	planner.mli \
@@ -42,6 +45,7 @@ SOURCES_ML = \
 	common_gettext.ml \
 	common_utils.ml \
 	fsync.ml \
+	ini_reader.ml \
 	progress.ml \
 	uRI.ml \
 	mkdtemp.ml \
@@ -53,6 +57,10 @@ SOURCES_C = \
 	$(top_srcdir)/fish/progress.c \
 	$(top_srcdir)/fish/uri.c \
 	fsync-c.c \
+	index-scan.l \
+	index-struct.c \
+	index-parse.y \
+	index-parser-c.c \
 	mkdtemp-c.c \
 	progress-c.c \
 	uri-c.c
@@ -74,7 +82,8 @@ dummy_CPPFLAGS = \
 	-I$(top_srcdir)/fish
 dummy_CFLAGS = \
 	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
-	$(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS)
+	$(LIBVIRT_CFLAGS) $(LIBXML2_CFLAGS) \
+	-Wno-unused-macros
 
 BOBJECTS = $(SOURCES_ML:.ml=.cmo)
 XOBJECTS = $(BOBJECTS:.cmo=.cmx)
@@ -213,6 +222,11 @@ depend: .depend
 
 endif
 
+CLEANFILES += \
+	index-parse.c \
+	index-parse.h \
+	index-scan.c
+
 DISTCLEANFILES = .depend
 
 .PHONY: depend docs
diff --git a/mllib/index-parse.y b/mllib/index-parse.y
new file mode 100644
index 0000000..82ea9d2
--- /dev/null
+++ b/mllib/index-parse.y
@@ -0,0 +1,176 @@
+/* libguestfs virt-builder tool -*- fundamental -*-
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+%{
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "index-struct.h"
+#include "index-parse.h"
+
+#define YY_EXTRA_TYPE struct parse_context *
+
+extern void yyerror (YYLTYPE * yylloc, yyscan_t scanner, struct parse_context *context, const char *msg);
+extern int yylex (YYSTYPE * yylval, YYLTYPE * yylloc, yyscan_t scanner);
+
+extern int do_parse (struct parse_context *context, FILE *in);
+extern void scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in);
+extern void scanner_destroy (yyscan_t scanner);
+
+/* Join two strings with \n */
+static char *
+concat_newline (const char *str1, const char *str2)
+{
+  size_t len1, len2, len;
+  char *ret;
+
+  if (str2 == NULL)
+    return strdup (str1);
+
+  len1 = strlen (str1);
+  len2 = strlen (str2);
+  len = len1 + 1 /* \n */ + len2 + 1 /* \0 */;
+  ret = malloc (len);
+  memcpy (ret, str1, len1);
+  ret[len1] = '\n';
+  memcpy (ret + len1 + 1, str2, len2);
+  ret[len-1] = '\0';
+
+  return ret;
+}
+
+%}
+
+%code requires {
+#ifndef YY_TYPEDEF_YY_SCANNER_T
+#define YY_TYPEDEF_YY_SCANNER_T
+typedef void *yyscan_t;
+#endif
+}
+
+%locations
+
+%union {
+  struct section *section;
+  struct field *field;
+  char *str;
+}
+
+%token <str>   SECTION_HEADER
+%token <field> FIELD
+%token <str>   VALUE_CONT
+%token         EMPTY_LINE
+%token         PGP_PROLOGUE
+%token         PGP_EPILOGUE
+%token         UNKNOWN_LINE
+
+%type <section> sections section
+%type <field>   fields field
+%type <str>     continuations
+
+%pure-parser
+
+%lex-param   { yyscan_t scanner }
+%parse-param { yyscan_t scanner }
+%parse-param { struct parse_context *context }
+
+%destructor { section_free ($$); } <section>
+%destructor { field_free ($$); } <field>
+
+%%
+
+index:
+      sections
+        { context->parsed_index = $1; }
+    | PGP_PROLOGUE sections PGP_EPILOGUE
+        { context->parsed_index = $2; }
+
+sections:
+      emptylines section emptylines
+        { $$ = $2; }
+    | emptylines section EMPTY_LINE emptylines sections
+        { $$ = $2; $$->next = $5; }
+    | emptylines
+        { $$ = NULL; }
+
+section:
+      SECTION_HEADER fields
+        { $$ = malloc (sizeof (struct section));
+          $$->next = NULL;
+          $$->name = $1;
+          $$->fields = $2; }
+
+fields:
+      /* empty */
+        { $$ = NULL; }
+    | field fields
+        { $$ = $1; $$->next = $2; }
+
+field: FIELD continuations
+        { $$ = $1;
+          char *old_value = $$->value;
+          $$->value = concat_newline (old_value, $2);
+          free (old_value);
+          free ($2); }
+
+continuations:
+      /* empty */
+        { $$ = NULL; }
+    | VALUE_CONT continuations
+        { $$ = concat_newline ($1, $2);
+          free ($1);
+          free ($2); }
+
+emptylines:
+      /* empty */
+        {}
+    | EMPTY_LINE emptylines
+        {}
+
+%%
+
+void
+yyerror (YYLTYPE * yylloc, yyscan_t scanner, struct parse_context *context, const char *msg)
+{
+  int has_suffix = context->error_suffix != NULL && context->error_suffix[0] != 0;
+
+  fprintf (stderr, "%s%s%s%ssyntax error at line %d: %s%s%s\n",
+           context->progname ? context->progname : "",
+           context->progname ? ": " : "",
+           context->input_file ? context->input_file : "",
+           context->input_file ? ": " : "",
+           yylloc->first_line, msg,
+           has_suffix ? " " : "",
+           has_suffix ? context->error_suffix : "");
+}
+
+int
+do_parse (struct parse_context *context, FILE *in)
+{
+  yyscan_t scanner;
+  int res;
+
+  scanner_init (&scanner, context, in);
+  res = yyparse (scanner, context);
+  scanner_destroy (scanner);
+
+  return res;
+}
diff --git a/mllib/index-parser-c.c b/mllib/index-parser-c.c
new file mode 100644
index 0000000..52c8b86
--- /dev/null
+++ b/mllib/index-parser-c.c
@@ -0,0 +1,121 @@
+/* virt-builder
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* This file handles the interface between the C/lex/yacc index file
+ * parser, and the OCaml world.  See index_parser.ml for the OCaml
+ * type definition.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <caml/alloc.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#ifdef HAVE_CAML_UNIXSUPPORT_H
+#include <caml/unixsupport.h>
+#else
+#define Nothing ((value) 0)
+extern void unix_error (int errcode, char * cmdname, value arg) Noreturn;
+#endif
+
+#include "index-struct.h"
+#include "index-parse.h"
+
+extern int do_parse (struct parse_context *context, FILE *in);
+
+extern value virt_builder_parse_index (value progv, value error_suffixv, value filenamev);
+
+value
+virt_builder_parse_index (value progv, value error_suffixv, value filenamev)
+{
+  CAMLparam2 (progv, filenamev);
+  CAMLlocal5 (rv, v, sv, sv2, fv);
+  struct section *sections;
+  size_t i, nr_sections;
+  struct parse_context context;
+  FILE *in;
+
+  parse_context_init (&context);
+  context.progname = String_val (progv);
+  context.input_file = String_val (filenamev);
+  context.error_suffix = String_val (error_suffixv);
+
+  in = fopen (String_val (filenamev), "r");
+  if (in == NULL)
+    unix_error (errno, (char *) "fopen", filenamev);
+
+  if (do_parse (&context, in) != 0) {
+    fclose (in);
+    caml_invalid_argument ("parse error");
+  }
+
+  if (fclose (in) == EOF)
+    unix_error (errno, (char *) "fclose", filenamev);
+
+  /* Convert the parsed data to OCaml structures. */
+  nr_sections = 0;
+  for (sections = context.parsed_index; sections != NULL; sections = sections->next)
+    nr_sections++;
+  rv = caml_alloc (nr_sections, 0);
+
+  for (i = 0, sections = context.parsed_index; sections != NULL;
+       i++, sections = sections->next) {
+    struct field *fields;
+    size_t j, nr_fields;
+
+    nr_fields = 0;
+    for (fields = sections->fields; fields != NULL; fields = fields->next)
+      nr_fields++;
+    fv = caml_alloc (nr_fields, 0);
+
+    for (j = 0, fields = sections->fields; fields != NULL;
+         j++, fields = fields->next) {
+      v = caml_alloc_tuple (3);
+      sv = caml_copy_string (fields->key);
+      Store_field (v, 0, sv);   /* (key, Some subkey, value) */
+      if (fields->subkey) {
+        sv2 = caml_copy_string (fields->subkey);
+        sv = caml_alloc (1, 0);
+        Store_field (sv, 0, sv2);
+      } else
+        sv = Val_int (0);
+      Store_field (v, 1, sv);
+      sv = caml_copy_string (fields->value);
+      Store_field (v, 2, sv);
+      Store_field (fv, j, v);   /* assign to return array of fields */
+    }
+
+    v = caml_alloc_tuple (2);
+    sv = caml_copy_string (sections->name);
+    Store_field (v, 0, sv);     /* (name, fields) */
+    Store_field (v, 1, fv);
+    Store_field (rv, i, v);     /* assign to return array of sections */
+  }
+
+  /* Free parsed data. */
+  parse_context_free (&context);
+
+  CAMLreturn (rv);
+}
diff --git a/mllib/index-scan.l b/mllib/index-scan.l
new file mode 100644
index 0000000..7125913
--- /dev/null
+++ b/mllib/index-scan.l
@@ -0,0 +1,144 @@
+/* libguestfs virt-builder tool -*- fundamental -*-
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+%top{
+#include <config.h>
+}
+
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Silence gcc warnings from the generated code. */
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+/* flex creates macros that it doesn't use */
+#pragma GCC diagnostic ignored "-Wunused-macros"
+/* on aarch64, flex doesn't know that char is unsigned */
+#pragma GCC diagnostic ignored "-Wsign-compare"
+/* on debian-mipsel, flex doesn't create prototypes for all functions */
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#endif
+
+#include "index-struct.h"
+#include "index-parse.h"
+
+#define YY_EXTRA_TYPE struct parse_context *
+#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno;
+
+extern void scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in);
+extern void scanner_destroy (yyscan_t scanner);
+
+%}
+
+%option nounput
+%option noyywrap
+%option yylineno
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+%%
+
+ /* Apart from the PGP prologue/epilogue which is a hack, the
+  * scanning strategy is to deal with the file strictly line by
+  * line, and pass those lines up to the parser which deals with
+  * whether they appear in the right order to be meaningful.
+  * Note that flex does longest-match.
+  */
+
+  /* Ignore comments - '#' MUST appear at the start of a line. */
+^"#".*\n                { yyextra->seen_comments++; }
+
+  /* An empty line is significant. */
+^\n                                     { return EMPTY_LINE; }
+
+  /* [...] marks beginning of a section. */
+^"["[-A-Za-z0-9._]+"]"\n {
+                      yylval->str = strndup (yytext+1, yyleng-3);
+                      return SECTION_HEADER;
+                    }
+
+  /* field=value or field[subfield]=value */
+^[A-Za-z0-9_.]+("["[A-Za-z0-9_,.]+"]")?"=".*\n {
+                      size_t i = strcspn (yytext, "=[");
+                      yylval->field = malloc (sizeof (struct field));
+                      yylval->field->next = NULL;
+                      yylval->field->key = strndup (yytext, i);
+                      if (yytext[i] == '[') {
+                        size_t j = strcspn (yytext+i+1, "]");
+                        yylval->field->subkey = strndup (yytext+i+1, j);
+                        i += 1+j+1;
+                      } else {
+                        yylval->field->subkey = NULL;
+                      }
+                      /* Note we chop the final \n off here. */
+                      yylval->field->value = strndup (yytext+i+1, yyleng-(i+2));
+                      return FIELD;
+                    }
+
+  /* Continuation line for multi-line values. */
+^[[:blank:]].*\n        {
+                      yylval->str = strndup (yytext+1, yyleng-2);
+                      return VALUE_CONT;
+                    }
+
+ /* Hack to eat the PGP prologue. */
+^"-----BEGIN PGP SIGNED MESSAGE-----\n"  {
+  int c, prevnl = 0;
+
+  /* Eat everything to the first blank line. */
+  while ((c = input (yyscanner)) != EOF) {
+    if (c == '\n' && prevnl)
+      break;
+    prevnl = c == '\n';
+  }
+
+  return PGP_PROLOGUE;
+}
+
+ /* Hack to eat the PGP epilogue. */
+^"-----BEGIN PGP SIGNATURE-----\n"  {
+  /* Eat everything to the end of the file. */
+  while (input (yyscanner) != EOF)
+    ;
+
+  return PGP_EPILOGUE;
+}
+
+ /* anything else is an error */
+. {
+  return UNKNOWN_LINE;
+}
+
+%%
+
+void
+scanner_init (yyscan_t *scanner, struct parse_context *context, FILE *in)
+{
+  yylex_init (scanner);
+  yyset_extra (context, *scanner);
+  yyset_in (in, *scanner);
+}
+
+void
+scanner_destroy (yyscan_t scanner)
+{
+  yylex_destroy (scanner);
+}
diff --git a/mllib/index-struct.c b/mllib/index-struct.c
new file mode 100644
index 0000000..eacca6c
--- /dev/null
+++ b/mllib/index-struct.c
@@ -0,0 +1,60 @@
+/* libguestfs virt-builder tool
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "index-struct.h"
+
+void
+parse_context_init (struct parse_context *context)
+{
+  memset (context, 0, sizeof *context);
+}
+
+void
+parse_context_free (struct parse_context *context)
+{
+  section_free (context->parsed_index);
+}
+
+void
+section_free (struct section *section)
+{
+  if (section) {
+    section_free (section->next);
+    free (section->name);
+    field_free (section->fields);
+    free (section);
+  }
+}
+
+void
+field_free (struct field *field)
+{
+  if (field) {
+    field_free (field->next);
+    free (field->key);
+    free (field->subkey);
+    free (field->value);
+    free (field);
+  }
+}
diff --git a/mllib/index-struct.h b/mllib/index-struct.h
new file mode 100644
index 0000000..ada35e3
--- /dev/null
+++ b/mllib/index-struct.h
@@ -0,0 +1,67 @@
+/* libguestfs virt-builder tool
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* The data structures produced when parsing the index file. */
+
+#ifndef INDEX_STRUCT_H
+#define INDEX_STRUCT_H
+
+/* A section or list of sections. */
+struct section {
+  struct section *next;
+  char *name;
+  struct field *fields;
+};
+
+/* A field or list of fields. */
+struct field {
+  struct field *next;
+  char *key;
+  char *subkey;
+  char *value;
+};
+
+/* A struct holding the data needed during the parsing. */
+struct parse_context {
+  struct section *parsed_index;        /* The result of the parsing. */
+  /* yyparse sets this if any comments were seen.  Required for checking
+   * compatibility with virt-builder 1.24.
+   */
+  int seen_comments;
+  const char *input_file;
+  const char *progname;
+  const char *error_suffix;
+};
+
+/* Initialize the content of a parse_context. */
+extern void parse_context_init (struct parse_context *state);
+
+/* Free the content of a parse_context.  The actual pointer is not freed. */
+extern void parse_context_free (struct parse_context *state);
+
+/* Free the content of a section, recursively freeing also its fields.
+ * The actual pointer is not freed.
+ */
+extern void section_free (struct section *section);
+
+/* Free the content of a field, recursively freeing also its next field.
+ * The actual pointer is not freed.
+ */
+extern void field_free (struct field *field);
+
+#endif /* INDEX_STRUCT_H */
diff --git a/mllib/ini_reader.ml b/mllib/ini_reader.ml
new file mode 100644
index 0000000..50a06f9
--- /dev/null
+++ b/mllib/ini_reader.ml
@@ -0,0 +1,40 @@
+(* virt-builder
+ * Copyright (C) 2013-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Common_utils
+
+type sections = section list
+and section = string * fields                (* [name] + fields *)
+and fields = field list
+and field = string * string option * string  (* key + subkey + value *)
+
+(* Types returned by the C index parser. *)
+type c_sections = c_section array
+and c_section = string * c_fields             (* [name] + fields *)
+and c_fields = field array
+
+(* Calls yyparse in the C code. *)
+external parse_index : prog:string -> error_suffix:string -> string -> c_sections = "virt_builder_parse_index"
+
+let read_ini ?(error_suffix = "") file =
+  let sections = parse_index ~prog ~error_suffix file in
+  let sections = Array.to_list sections in
+  List.map (
+    fun (n, fields) ->
+      n, Array.to_list fields
+  ) sections
diff --git a/mllib/ini_reader.mli b/mllib/ini_reader.mli
new file mode 100644
index 0000000..62567e8
--- /dev/null
+++ b/mllib/ini_reader.mli
@@ -0,0 +1,24 @@
+(* virt-builder
+ * Copyright (C) 2013-2015 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+type sections = section list
+and section = string * fields                (* [name] + fields *)
+and fields = field list
+and field = string * string option * string  (* key + subkey + value *)
+
+val read_ini : ?error_suffix:string -> string -> sections
diff --git a/po/POTFILES b/po/POTFILES
index 7f1580c..d1115a0 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -1,8 +1,4 @@
 align/scan.c
-builder/index-parse.c
-builder/index-parser-c.c
-builder/index-scan.c
-builder/index-struct.c
 builder/index-validate.c
 builder/pxzcat-c.c
 builder/setlocale-c.c
@@ -259,6 +255,10 @@ lua/lua-guestfs.c
 make-fs/make-fs.c
 mllib/dummy.c
 mllib/fsync-c.c
+mllib/index-parse.c
+mllib/index-parser-c.c
+mllib/index-scan.c
+mllib/index-struct.c
 mllib/mkdtemp-c.c
 mllib/progress-c.c
 mllib/uri-c.c
diff --git a/po/POTFILES-ml b/po/POTFILES-ml
index 8725385..ee0294c 100644
--- a/po/POTFILES-ml
+++ b/po/POTFILES-ml
@@ -3,7 +3,6 @@ builder/cache.ml
 builder/cmdline.ml
 builder/downloader.ml
 builder/index_parser.ml
-builder/ini_reader.ml
 builder/languages.ml
 builder/list_entries.ml
 builder/paths.ml
@@ -33,6 +32,7 @@ mllib/common_utils.ml
 mllib/common_utils_tests.ml
 mllib/config.ml
 mllib/fsync.ml
+mllib/ini_reader.ml
 mllib/libdir.ml
 mllib/mkdtemp.ml
 mllib/planner.ml
-- 
2.1.0




More information about the Libguestfs mailing list