[Libguestfs] [PATCH 3/5] Copy C sources from libguestfs

Pino Toscano ptoscano at redhat.com
Tue Jul 9 14:05:16 UTC 2019


Copy some common C sources from libguestfs, trimmed to only what
virt-p2v needs.
---
 Makefile.am                        |   1 +
 libguestfs/README                  |   4 +
 libguestfs/cleanups.c              |  96 +++++++++++
 libguestfs/cleanups.h              |  74 +++++++++
 libguestfs/guestfs-utils.c         | 247 +++++++++++++++++++++++++++++
 libguestfs/guestfs-utils.h         |  85 ++++++++++
 libguestfs/libxml2-cleanups.c      |  94 +++++++++++
 libguestfs/libxml2-writer-macros.h | 200 +++++++++++++++++++++++
 8 files changed, 801 insertions(+)
 create mode 100644 libguestfs/README
 create mode 100644 libguestfs/cleanups.c
 create mode 100644 libguestfs/cleanups.h
 create mode 100644 libguestfs/guestfs-utils.c
 create mode 100644 libguestfs/guestfs-utils.h
 create mode 100644 libguestfs/libxml2-cleanups.c
 create mode 100644 libguestfs/libxml2-writer-macros.h

diff --git a/Makefile.am b/Makefile.am
index 736b8fc..0d67dbf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,6 +38,7 @@ EXTRA_DIST = \
 	kiwi-config.sh \
 	kiwi-config.xml.in \
 	launch-virt-p2v \
+	libguestfs/README \
 	miniexpect/README \
 	p2v.ks.in \
 	p2v.service \
diff --git a/libguestfs/README b/libguestfs/README
new file mode 100644
index 0000000..fbf367b
--- /dev/null
+++ b/libguestfs/README
@@ -0,0 +1,4 @@
+This directory contains sources mostly copied from libguestfs.
+The sources were trimmed to contain only what is used by virt-p2v.
+
+Fixes ought to be sent also to libguestfs, to avoid diverging from libguestfs.
diff --git a/libguestfs/cleanups.c b/libguestfs/cleanups.c
new file mode 100644
index 0000000..dae75ee
--- /dev/null
+++ b/libguestfs/cleanups.c
@@ -0,0 +1,96 @@
+/* libguestfs
+ * Copyright (C) 2013 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * Libguestfs uses C<CLEANUP_*> macros to simplify temporary
+ * allocations.  They are implemented using the
+ * C<__attribute__((cleanup))> feature of gcc and clang.  Typical
+ * usage is:
+ *
+ *  fn ()
+ *  {
+ *    CLEANUP_FREE char *str = NULL;
+ *    str = safe_asprintf (g, "foo");
+ *    // str is freed automatically when the function returns
+ *  }
+ *
+ * There are a few catches to be aware of with the cleanup mechanism:
+ *
+ * =over 4
+ *
+ * =item *
+ *
+ * If a cleanup variable is not initialized, then you can end up
+ * calling L<free(3)> with an undefined value, resulting in the
+ * program crashing.  For this reason, you should usually initialize
+ * every cleanup variable with something, eg. C<NULL>
+ *
+ * =item *
+ *
+ * Don't mark variables holding return values as cleanup variables.
+ *
+ * =item *
+ *
+ * The C<main()> function shouldn't use cleanup variables since it is
+ * normally exited by calling L<exit(3)>, and that doesn't call the
+ * cleanup handlers.
+ *
+ * =back
+ *
+ * The functions in this file are used internally by the C<CLEANUP_*>
+ * macros.  Don't call them directly.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "guestfs-utils.h"
+
+/* Stdlib cleanups. */
+
+void
+guestfs_int_cleanup_free (void *ptr)
+{
+  free (* (void **) ptr);
+}
+
+void
+guestfs_int_cleanup_fclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+    fclose (f);
+}
+
+void
+guestfs_int_cleanup_pclose (void *ptr)
+{
+  FILE *f = * (FILE **) ptr;
+
+  if (f)
+    pclose (f);
+}
+
+void
+guestfs_int_cleanup_free_string_list (char ***ptr)
+{
+  guestfs_int_free_string_list (*ptr);
+}
diff --git a/libguestfs/cleanups.h b/libguestfs/cleanups.h
new file mode 100644
index 0000000..4defdef
--- /dev/null
+++ b/libguestfs/cleanups.h
@@ -0,0 +1,74 @@
+/* libguestfs
+ * Copyright (C) 2013-2019 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GUESTFS_CLEANUPS_H_
+#define GUESTFS_CLEANUPS_H_
+
+#ifdef HAVE_ATTRIBUTE_CLEANUP
+#define CLEANUP_FREE                                    \
+  __attribute__((cleanup(guestfs_int_cleanup_free)))
+#define CLEANUP_FCLOSE                                  \
+  __attribute__((cleanup(guestfs_int_cleanup_fclose)))
+#define CLEANUP_PCLOSE                                  \
+  __attribute__((cleanup(guestfs_int_cleanup_pclose)))
+#define CLEANUP_FREE_STRING_LIST                                \
+  __attribute__((cleanup(guestfs_int_cleanup_free_string_list)))
+#define CLEANUP_XMLFREE                                 \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlFree)))
+#define CLEANUP_XMLBUFFERFREE                                   \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlBufferFree)))
+#define CLEANUP_XMLFREEDOC                                      \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlFreeDoc)))
+#define CLEANUP_XMLFREEURI                                              \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlFreeURI)))
+#define CLEANUP_XMLFREETEXTWRITER                               \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlFreeTextWriter)))
+#define CLEANUP_XMLXPATHFREECONTEXT                                     \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlXPathFreeContext)))
+#define CLEANUP_XMLXPATHFREEOBJECT                                      \
+  __attribute__((cleanup(guestfs_int_cleanup_xmlXPathFreeObject)))
+#else
+#define CLEANUP_FREE
+#define CLEANUP_FCLOSE
+#define CLEANUP_PCLOSE
+#define CLEANUP_FREE_STRING_LIST
+#define CLEANUP_XMLFREE
+#define CLEANUP_XMLBUFFERFREE
+#define CLEANUP_XMLFREEDOC
+#define CLEANUP_XMLFREEURI
+#define CLEANUP_XMLFREETEXTWRITER
+#define CLEANUP_XMLXPATHFREECONTEXT
+#define CLEANUP_XMLXPATHFREEOBJECT
+#endif
+
+/* These functions are used internally by the CLEANUP_* macros.
+ * Don't call them directly.
+ */
+extern void guestfs_int_cleanup_free (void *ptr);
+extern void guestfs_int_cleanup_fclose (void *ptr);
+extern void guestfs_int_cleanup_pclose (void *ptr);
+extern void guestfs_int_cleanup_free_string_list (char ***ptr);
+extern void guestfs_int_cleanup_xmlFree (void *ptr);
+extern void guestfs_int_cleanup_xmlBufferFree (void *ptr);
+extern void guestfs_int_cleanup_xmlFreeDoc (void *ptr);
+extern void guestfs_int_cleanup_xmlFreeURI (void *ptr);
+extern void guestfs_int_cleanup_xmlFreeTextWriter (void *ptr);
+extern void guestfs_int_cleanup_xmlXPathFreeContext (void *ptr);
+extern void guestfs_int_cleanup_xmlXPathFreeObject (void *ptr);
+
+#endif /* GUESTFS_CLEANUPS_H_ */
diff --git a/libguestfs/guestfs-utils.c b/libguestfs/guestfs-utils.c
new file mode 100644
index 0000000..505c9f6
--- /dev/null
+++ b/libguestfs/guestfs-utils.c
@@ -0,0 +1,247 @@
+/* libguestfs
+ * Copyright (C) 2009-2019 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "guestfs-utils.h"
+
+void
+guestfs_int_free_string_list (char **argv)
+{
+  size_t i;
+
+  if (argv == NULL)
+    return;
+
+  for (i = 0; argv[i] != NULL; ++i)
+    free (argv[i]);
+  free (argv);
+}
+
+size_t
+guestfs_int_count_strings (char *const *argv)
+{
+  size_t r;
+
+  for (r = 0; argv[r]; ++r)
+    ;
+
+  return r;
+}
+
+char **
+guestfs_int_copy_string_list (char *const *argv)
+{
+  const size_t n = guestfs_int_count_strings (argv);
+  size_t i, j;
+  char **ret;
+
+  ret = malloc ((n+1) * sizeof (char *));
+  if (ret == NULL)
+    return NULL;
+  ret[n] = NULL;
+
+  for (i = 0; i < n; ++i) {
+    ret[i] = strdup (argv[i]);
+    if (ret[i] == NULL) {
+      for (j = 0; j < i; ++j)
+        free (ret[j]);
+      free (ret);
+      return NULL;
+    }
+  }
+
+  return ret;
+}
+
+/**
+ * Split string at separator character C<sep>, returning the list of
+ * strings.  Returns C<NULL> on memory allocation failure.
+ *
+ * Note (assuming C<sep> is C<:>):
+ *
+ * =over 4
+ *
+ * =item C<str == NULL>
+ *
+ * aborts
+ *
+ * =item C<str == "">
+ *
+ * returns C<[]>
+ *
+ * =item C<str == "abc">
+ *
+ * returns C<["abc"]>
+ *
+ * =item C<str == ":">
+ *
+ * returns C<["", ""]>
+ *
+ * =back
+ */
+char **
+guestfs_int_split_string (char sep, const char *str)
+{
+  size_t i, n, c;
+  const size_t len = strlen (str);
+  char reject[2] = { sep, '\0' };
+  char **ret;
+
+  /* We have to handle the empty string case differently else the code
+   * below will return [""].
+   */
+  if (str[0] == '\0') {
+    ret = malloc (1 * sizeof (char *));
+    if (!ret)
+      return NULL;
+    ret[0] = NULL;
+    return ret;
+  }
+
+  for (n = i = 0; i < len; ++i)
+    if (str[i] == sep)
+      n++;
+
+  /* We always return a list of length 1 + (# separator characters).
+   * We also have to add a trailing NULL.
+   */
+  ret = malloc ((n+2) * sizeof (char *));
+  if (!ret)
+    return NULL;
+  ret[n+1] = NULL;
+
+  for (n = i = 0; i <= len; ++i, ++n) {
+    c = strcspn (&str[i], reject);
+    ret[n] = strndup (&str[i], c);
+    if (ret[n] == NULL) {
+      for (i = 0; i < n; ++i)
+        free (ret[i]);
+      free (ret);
+      return NULL;
+    }
+    i += c;
+    if (str[i] == '\0') /* end of string? */
+      break;
+  }
+
+  return ret;
+}
+
+/**
+ * Return a random string of characters.
+ *
+ * Notes:
+ *
+ * =over 4
+ *
+ * =item *
+ *
+ * The C<ret> buffer must have length C<len+1> in order to store the
+ * final C<\0> character.
+ *
+ * =item *
+ *
+ * There is about 5 bits of randomness per output character (so about
+ * C<5*len> bits of randomness in the resulting string).
+ *
+ * =back
+ */
+int
+guestfs_int_random_string (char *ret, size_t len)
+{
+  int fd;
+  size_t i;
+  unsigned char c;
+  int saved_errno;
+
+  fd = open ("/dev/urandom", O_RDONLY|O_CLOEXEC);
+  if (fd == -1)
+    return -1;
+
+  for (i = 0; i < len; ++i) {
+    if (read (fd, &c, 1) != 1) {
+      saved_errno = errno;
+      close (fd);
+      errno = saved_errno;
+      return -1;
+    }
+    /* Do not change this! */
+    ret[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[c % 36];
+  }
+  ret[len] = '\0';
+
+  if (close (fd) == -1)
+    return -1;
+
+  return 0;
+}
+
+/**
+ * This turns a drive index (eg. C<27>) into a drive name
+ * (eg. C<"ab">).
+ *
+ * Drive indexes count from C<0>.  The return buffer has to be large
+ * enough for the resulting string, and the returned pointer points to
+ * the *end* of the string.
+ *
+ * L<https://rwmj.wordpress.com/2011/01/09/how-are-linux-drives-named-beyond-drive-26-devsdz/>
+ */
+char *
+guestfs_int_drive_name (size_t index, char *ret)
+{
+  if (index >= 26)
+    ret = guestfs_int_drive_name (index/26 - 1, ret);
+  index %= 26;
+  *ret++ = 'a' + index;
+  *ret = '\0';
+  return ret;
+}
+
+/**
+ * Similar to C<Tcl_GetBoolean>.
+ */
+int
+guestfs_int_is_true (const char *str)
+{
+  if (STREQ (str, "1") ||
+      STRCASEEQ (str, "true") ||
+      STRCASEEQ (str, "t") ||
+      STRCASEEQ (str, "yes") ||
+      STRCASEEQ (str, "y") ||
+      STRCASEEQ (str, "on"))
+    return 1;
+
+  if (STREQ (str, "0") ||
+      STRCASEEQ (str, "false") ||
+      STRCASEEQ (str, "f") ||
+      STRCASEEQ (str, "no") ||
+      STRCASEEQ (str, "n") ||
+      STRCASEEQ (str, "off"))
+    return 0;
+
+  return -1;
+}
diff --git a/libguestfs/guestfs-utils.h b/libguestfs/guestfs-utils.h
new file mode 100644
index 0000000..d5557a4
--- /dev/null
+++ b/libguestfs/guestfs-utils.h
@@ -0,0 +1,85 @@
+/* libguestfs
+ * Copyright (C) 2013-2019 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef GUESTFS_UTILS_H_
+#define GUESTFS_UTILS_H_
+
+#include <string.h>
+
+#include "cleanups.h"
+
+#define _(str) dgettext(PACKAGE, (str))
+
+#define STREQ(a,b) (strcmp((a),(b)) == 0)
+#define STRCASEEQ(a,b) (strcasecmp((a),(b)) == 0)
+#define STRNEQ(a,b) (strcmp((a),(b)) != 0)
+#define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0)
+
+/* A simple (indeed, simplistic) way to build up short lists of
+ * arguments.  Your code must define MAX_ARGS to a suitable "larger
+ * than could ever be needed" value.  (If the value is exceeded then
+ * your code will abort).  For more complex needs, use something else
+ * more suitable.
+ */
+#define ADD_ARG(argv,i,v)                                               \
+  do {                                                                  \
+    if ((i) >= MAX_ARGS) {                                              \
+      fprintf (stderr, "%s: %d: internal error: exceeded MAX_ARGS (%zu) when constructing the command line\n", __FILE__, __LINE__, (size_t) MAX_ARGS); \
+      abort ();                                                         \
+    }                                                                   \
+    (argv)[(i)++] = (v);                                                \
+  } while (0)
+
+extern void guestfs_int_free_string_list (char **);
+extern size_t guestfs_int_count_strings (char *const *);
+extern char **guestfs_int_copy_string_list (char *const *);
+extern char **guestfs_int_split_string (char sep, const char *);
+extern int guestfs_int_random_string (char *ret, size_t len);
+extern char *guestfs_int_drive_name (size_t index, char *ret);
+extern int guestfs_int_is_true (const char *str);
+
+/* ANSI colours.  These are defined as macros so that we don't have to
+ * define the force_colour global variable in the library.
+ */
+#define ansi_green(fp)                           \
+  do {                                           \
+    if (force_colour || isatty (fileno (fp)))    \
+      fputs ("\033[0;32m", (fp));                \
+  } while (0)
+#define ansi_red(fp)                             \
+  do {                                           \
+    if (force_colour || isatty (fileno (fp)))    \
+      fputs ("\033[1;31m", (fp));                \
+  } while (0)
+#define ansi_blue(fp)                            \
+  do {                                           \
+    if (force_colour || isatty (fileno (fp)))    \
+      fputs ("\033[1;34m", (fp));                \
+  } while (0)
+#define ansi_magenta(fp)                         \
+  do {                                           \
+    if (force_colour || isatty (fileno (fp)))    \
+      fputs ("\033[1;35m", (fp));                \
+  } while (0)
+#define ansi_restore(fp)                         \
+  do {                                           \
+    if (force_colour || isatty (fileno (fp)))    \
+      fputs ("\033[0m", (fp));                   \
+  } while (0)
+
+#endif /* GUESTFS_UTILS_H_ */
diff --git a/libguestfs/libxml2-cleanups.c b/libguestfs/libxml2-cleanups.c
new file mode 100644
index 0000000..829c620
--- /dev/null
+++ b/libguestfs/libxml2-cleanups.c
@@ -0,0 +1,94 @@
+/* libguestfs
+ * Copyright (C) 2013-2019 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libxml/uri.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlwriter.h>
+
+#include "cleanups.h"
+
+void
+guestfs_int_cleanup_xmlFree (void *ptr)
+{
+  xmlChar *buf = * (xmlChar **) ptr;
+
+  if (buf)
+    xmlFree (buf);
+}
+
+void
+guestfs_int_cleanup_xmlBufferFree (void *ptr)
+{
+  xmlBufferPtr xb = * (xmlBufferPtr *) ptr;
+
+  if (xb)
+    xmlBufferFree (xb);
+}
+
+void
+guestfs_int_cleanup_xmlFreeDoc (void *ptr)
+{
+  xmlDocPtr doc = * (xmlDocPtr *) ptr;
+
+  if (doc)
+    xmlFreeDoc (doc);
+}
+
+void
+guestfs_int_cleanup_xmlFreeURI (void *ptr)
+{
+  xmlURIPtr uri = * (xmlURIPtr *) ptr;
+
+  if (uri)
+    xmlFreeURI (uri);
+}
+
+void
+guestfs_int_cleanup_xmlFreeTextWriter (void *ptr)
+{
+  xmlTextWriterPtr xo = * (xmlTextWriterPtr *) ptr;
+
+  if (xo)
+    xmlFreeTextWriter (xo);
+}
+
+void
+guestfs_int_cleanup_xmlXPathFreeContext (void *ptr)
+{
+  xmlXPathContextPtr ctx = * (xmlXPathContextPtr *) ptr;
+
+  if (ctx)
+    xmlXPathFreeContext (ctx);
+}
+
+void
+guestfs_int_cleanup_xmlXPathFreeObject (void *ptr)
+{
+  xmlXPathObjectPtr obj = * (xmlXPathObjectPtr *) ptr;
+
+  if (obj)
+    xmlXPathFreeObject (obj);
+}
diff --git a/libguestfs/libxml2-writer-macros.h b/libguestfs/libxml2-writer-macros.h
new file mode 100644
index 0000000..66a7a8f
--- /dev/null
+++ b/libguestfs/libxml2-writer-macros.h
@@ -0,0 +1,200 @@
+/* libguestfs
+ * Copyright (C) 2009-2019 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 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * These macros make it easier to write XML.  To use them correctly
+ * you must be aware of these assumptions:
+ *
+ * =over 4
+ *
+ * =item *
+ *
+ * The C<xmlTextWriterPtr> is called C<xo>.  It is used implicitly
+ * by all the macros.
+ *
+ * =item *
+ *
+ * On failure, a function called C<xml_error> is called which you must
+ * define (usually as a macro).  You must use C<CLEANUP_*> macros in
+ * your functions if you want correct cleanup of local variables along
+ * the error path.
+ *
+ * =item *
+ *
+ * All the "bad" casting is hidden inside the macros.
+ *
+ * =back
+ */
+
+#ifndef GUESTFS_LIBXML2_WRITER_MACROS_H_
+#define GUESTFS_LIBXML2_WRITER_MACROS_H_
+
+#include <stdarg.h>
+
+/**
+ * To define an XML element use:
+ *
+ *  start_element ("name") {
+ *    ...
+ *  } end_element ();
+ *
+ * which produces C<<< <name>...</name> >>>
+ */
+#define start_element(element)						\
+  if (xmlTextWriterStartElement (xo, BAD_CAST (element)) == -1) {	\
+    xml_error ("xmlTextWriterStartElement");				\
+  }									\
+  do
+
+#define end_element()				\
+  while (0);					\
+  do {						\
+    if (xmlTextWriterEndElement (xo) == -1) {	\
+      xml_error ("xmlTextWriterEndElement");	\
+    }						\
+  } while (0)
+
+/**
+ * To define an empty element:
+ *
+ *  empty_element ("name");
+ *
+ * which produces C<<< <name/> >>>
+ */
+#define empty_element(element)                                  \
+  do { start_element ((element)) {} end_element (); } while (0)
+
+/**
+ * To define a single element with no attributes containing some text:
+ *
+ *  single_element ("name", text);
+ *
+ * which produces C<<< <name>text</name> >>>
+ */
+#define single_element(element,str)             \
+  do {                                          \
+    start_element ((element)) {                 \
+      string ((str));                           \
+    } end_element ();                           \
+  } while (0)
+
+/**
+ * To define a single element with no attributes containing some text
+ * using a format string:
+ *
+ *  single_element_format ("cores", "%d", nr_cores);
+ *
+ * which produces C<<< <cores>4</cores> >>>
+ */
+#define single_element_format(element,fs,...)   \
+  do {                                          \
+    start_element ((element)) {                 \
+      string_format ((fs), ##__VA_ARGS__);      \
+    } end_element ();                           \
+  } while (0)
+
+/**
+ * To define an XML element with attributes, use:
+ *
+ *  start_element ("name") {
+ *    attribute ("foo", "bar");
+ *    attribute_format ("count", "%d", count);
+ *    ...
+ *  } end_element ();
+ *
+ * which produces C<<< <name foo="bar" count="123">...</name> >>>
+ */
+#define attribute(key,value)                                            \
+  do {                                                                  \
+    if (xmlTextWriterWriteAttribute (xo, BAD_CAST (key),                \
+                                     BAD_CAST (value)) == -1) {         \
+      xml_error ("xmlTextWriterWriteAttribute");                        \
+    }                                                                   \
+  } while (0)
+
+#define attribute_format(key,fs,...)                                    \
+  do {                                                                  \
+    if (xmlTextWriterWriteFormatAttribute (xo, BAD_CAST (key),          \
+                                           fs, ##__VA_ARGS__) == -1) {  \
+      xml_error ("xmlTextWriterWriteFormatAttribute");                  \
+    }                                                                   \
+  } while (0)
+
+/**
+ * C<attribute_ns (prefix, key, namespace_uri, value)> defines a
+ * namespaced attribute.
+ */
+#define attribute_ns(prefix,key,namespace_uri,value)                    \
+  do {                                                                  \
+    if (xmlTextWriterWriteAttributeNS (xo, BAD_CAST (prefix),           \
+                                       BAD_CAST (key),                  \
+                                       BAD_CAST (namespace_uri),        \
+                                       BAD_CAST (value)) == -1) {       \
+      xml_error ("xmlTextWriterWriteAttribute");                        \
+    }                                                                   \
+  } while (0)
+
+/**
+ * To define a verbatim string, use:
+ *
+ *  string ("hello");
+ */
+#define string(str)                                                     \
+  do {                                                                  \
+    if (xmlTextWriterWriteString (xo, BAD_CAST(str)) == -1) {           \
+      xml_error ("xmlTextWriterWriteString");                           \
+    }                                                                   \
+  } while (0)
+
+/**
+ * To define a verbatim string using a format string, use:
+ *
+ *  string ("%s, world", greeting);
+ */
+#define string_format(fs,...)                                           \
+  do {                                                                  \
+    if (xmlTextWriterWriteFormatString (xo, fs, ##__VA_ARGS__) == -1) { \
+      xml_error ("xmlTextWriterWriteFormatString");                     \
+    }                                                                   \
+  } while (0)
+
+/**
+ * To write a string encoded as base64:
+ *
+ *  base64 (data, size);
+ */
+#define base64(data, size)                                              \
+  do {                                                                  \
+    if (xmlTextWriterWriteBase64 (xo, (data), 0, (size)) == -1) {       \
+      xml_error ("xmlTextWriterWriteBase64");                           \
+    }                                                                   \
+  } while (0)
+
+/**
+ * To define a comment in the XML, use:
+ *
+ *   comment ("number of items = %d", nr_items);
+ */
+#define comment(fs,...)                                                 \
+  do {                                                                  \
+    if (xmlTextWriterWriteFormatComment (xo, fs, ##__VA_ARGS__) == -1) { \
+      xml_error ("xmlTextWriterWriteFormatComment");                    \
+    }                                                                   \
+  } while (0)
+
+#endif /* GUESTFS_LIBXML2_WRITER_MACROS_H_ */
-- 
2.21.0




More information about the Libguestfs mailing list