Add some tests to make sure xmlgen's validity.
Signed-off-by: Shi Lei <shi_lei(a)massclouds.com>
---
tests/meson.build | 1 +
tests/xmlgenin/conf/array.h | 17 +
tests/xmlgenin/conf/empty.h | 7 +
tests/xmlgenin/conf/enum-first-item.h | 12 +
tests/xmlgenin/conf/external.h | 9 +
tests/xmlgenin/conf/genformat-separate.h | 11 +
tests/xmlgenin/conf/genformat.h | 11 +
tests/xmlgenin/conf/genparse.h | 11 +
tests/xmlgenin/conf/namespace.h | 12 +
tests/xmlgenin/conf/required.h | 9 +
tests/xmlgenin/conf/skipparse.h | 10 +
tests/xmlgenin/conf/specify.h | 13 +
tests/xmlgenin/conf/xmlattr.h | 10 +
tests/xmlgenin/conf/xmlelem.h | 10 +
tests/xmlgenin/conf/xmlgroup.h | 8 +
tests/xmlgenin/conf/xmlswitch.h | 17 +
tests/xmlgenin/util/enums.h | 58 +++
tests/xmlgenin/util/structs.h | 67 ++++
tests/xmlgenout/array.txt | 364 ++++++++++++++++++
tests/xmlgenout/empty.txt | 181 +++++++++
tests/xmlgenout/enum-first-item.txt | 297 ++++++++++++++
tests/xmlgenout/external.txt | 205 ++++++++++
tests/xmlgenout/genformat-separate.txt | 190 +++++++++
tests/xmlgenout/genformat.txt | 142 +++++++
tests/xmlgenout/genparse.txt | 154 ++++++++
tests/xmlgenout/namespace.txt | 222 +++++++++++
tests/xmlgenout/required.txt | 236 ++++++++++++
tests/xmlgenout/skipparse.txt | 223 +++++++++++
tests/xmlgenout/specify.txt | 291 ++++++++++++++
tests/xmlgenout/xmlattr.txt | 252 ++++++++++++
tests/xmlgenout/xmlelem.txt | 243 ++++++++++++
tests/xmlgenout/xmlgroup.txt | 204 ++++++++++
tests/xmlgenout/xmlswitch.txt | 470 +++++++++++++++++++++++
tests/xmlgentest.c | 107 ++++++
34 files changed, 4074 insertions(+)
create mode 100644 tests/xmlgenin/conf/array.h
create mode 100644 tests/xmlgenin/conf/empty.h
create mode 100644 tests/xmlgenin/conf/enum-first-item.h
create mode 100644 tests/xmlgenin/conf/external.h
create mode 100644 tests/xmlgenin/conf/genformat-separate.h
create mode 100644 tests/xmlgenin/conf/genformat.h
create mode 100644 tests/xmlgenin/conf/genparse.h
create mode 100644 tests/xmlgenin/conf/namespace.h
create mode 100644 tests/xmlgenin/conf/required.h
create mode 100644 tests/xmlgenin/conf/skipparse.h
create mode 100644 tests/xmlgenin/conf/specify.h
create mode 100644 tests/xmlgenin/conf/xmlattr.h
create mode 100644 tests/xmlgenin/conf/xmlelem.h
create mode 100644 tests/xmlgenin/conf/xmlgroup.h
create mode 100644 tests/xmlgenin/conf/xmlswitch.h
create mode 100644 tests/xmlgenin/util/enums.h
create mode 100644 tests/xmlgenin/util/structs.h
create mode 100644 tests/xmlgenout/array.txt
create mode 100644 tests/xmlgenout/empty.txt
create mode 100644 tests/xmlgenout/enum-first-item.txt
create mode 100644 tests/xmlgenout/external.txt
create mode 100644 tests/xmlgenout/genformat-separate.txt
create mode 100644 tests/xmlgenout/genformat.txt
create mode 100644 tests/xmlgenout/genparse.txt
create mode 100644 tests/xmlgenout/namespace.txt
create mode 100644 tests/xmlgenout/required.txt
create mode 100644 tests/xmlgenout/skipparse.txt
create mode 100644 tests/xmlgenout/specify.txt
create mode 100644 tests/xmlgenout/xmlattr.txt
create mode 100644 tests/xmlgenout/xmlelem.txt
create mode 100644 tests/xmlgenout/xmlgroup.txt
create mode 100644 tests/xmlgenout/xmlswitch.txt
create mode 100644 tests/xmlgentest.c
diff --git a/tests/meson.build b/tests/meson.build
index 14ace476..166416cc 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -340,6 +340,7 @@ tests += [
{ 'name': 'viruritest' },
{ 'name': 'vshtabletest', 'link_with': [ libvirt_shell_lib ]
},
{ 'name': 'virmigtest' },
+ { 'name': 'xmlgentest' },
]
if host_machine.system() == 'linux'
diff --git a/tests/xmlgenin/conf/array.h b/tests/xmlgenin/conf/array.h
new file mode 100644
index 00000000..8f003be4
--- /dev/null
+++ b/tests/xmlgenin/conf/array.h
@@ -0,0 +1,17 @@
+/* Test array features */
+
+#pragma once
+
+typedef struct _virArrayDef virArrayDef;
+struct _virArrayDef { /* genparse, genformat */
+ size_t nnames;
+ char **names; /* xmlelem:hostname, array */
+ size_t nfwds;
+ virNetworkDNSForwarder *forwarders; /* xmlelem, array:nfwds */
+ size_t ntxts;
+ virNetworkDNSTxtDef *txts; /* xmlelem, array */
+
+ size_t nroutes;
+ /* ptr to array of static routes on this interface */
+ virNetDevIPRoute **routes; /* xmlelem, array */
+};
diff --git a/tests/xmlgenin/conf/empty.h b/tests/xmlgenin/conf/empty.h
new file mode 100644
index 00000000..c8292c8e
--- /dev/null
+++ b/tests/xmlgenin/conf/empty.h
@@ -0,0 +1,7 @@
+/* Test empty struct */
+
+#pragma once
+
+typedef struct _virEmptyDef virEmptyDef;
+struct _virEmptyDef { /* genparse, genformat */
+};
diff --git a/tests/xmlgenin/conf/enum-first-item.h
b/tests/xmlgenin/conf/enum-first-item.h
new file mode 100644
index 00000000..c62dfe8a
--- /dev/null
+++ b/tests/xmlgenin/conf/enum-first-item.h
@@ -0,0 +1,12 @@
+/* Test first item for enum features */
+
+#pragma once
+
+typedef struct _virEnumFirstItemDef virEnumFirstItemDef;
+struct _virEnumFirstItemDef { /* genparse, genformat */
+ virNetworkBridgeMACTableManagerType has_def; /* xmlattr */
+ virNetworkForwardType has_none; /* xmlattr */
+ virTristateBool has_absent; /* xmlattr */
+
+ virDomainGraphicsType no_default; /* xmlattr */
+};
diff --git a/tests/xmlgenin/conf/external.h b/tests/xmlgenin/conf/external.h
new file mode 100644
index 00000000..52b46acd
--- /dev/null
+++ b/tests/xmlgenin/conf/external.h
@@ -0,0 +1,9 @@
+/* Test specify features */
+
+#pragma once
+
+typedef struct _virExternalDef virExternalDef;
+struct _virExternalDef { /* genparse, genformat */
+ /* xmlNode is an external type which is not defined in libvirt */
+ xmlNode *metadata; /* xmlelem */
+};
diff --git a/tests/xmlgenin/conf/genformat-separate.h
b/tests/xmlgenin/conf/genformat-separate.h
new file mode 100644
index 00000000..8e4643af
--- /dev/null
+++ b/tests/xmlgenin/conf/genformat-separate.h
@@ -0,0 +1,11 @@
+/* Test genformat-separate features */
+
+#pragma once
+
+typedef struct _virSeparateDef virSeparateDef;
+struct _virSeparateDef { /* genformat:separate */
+ virTristateBool enable; /* xmlattr */
+ virSocketAddr ip; /* xmlelem */
+ size_t ntxts;
+ virNetworkDNSTxtDef *txts; /* xmlelem, array */
+};
diff --git a/tests/xmlgenin/conf/genformat.h b/tests/xmlgenin/conf/genformat.h
new file mode 100644
index 00000000..fb92351a
--- /dev/null
+++ b/tests/xmlgenin/conf/genformat.h
@@ -0,0 +1,11 @@
+/* Test genformat features */
+
+#pragma once
+
+typedef struct _virGenFormatDef virGenFormatDef;
+struct _virGenFormatDef { /* genformat */
+ virTristateBool enable; /* xmlattr */
+ virSocketAddr ip; /* xmlelem */
+ size_t ntxts;
+ virNetworkDNSTxtDef *txts; /* xmlelem, array */
+};
diff --git a/tests/xmlgenin/conf/genparse.h b/tests/xmlgenin/conf/genparse.h
new file mode 100644
index 00000000..daf53817
--- /dev/null
+++ b/tests/xmlgenin/conf/genparse.h
@@ -0,0 +1,11 @@
+/* Test genparse features */
+
+#pragma once
+
+typedef struct _virGenParseDef virGenParseDef;
+struct _virGenParseDef { /* genparse */
+ virTristateBool enable; /* xmlattr */
+ virSocketAddr ip; /* xmlelem */
+ size_t ntxts;
+ virNetworkDNSTxtDef *txts; /* xmlelem, array */
+};
diff --git a/tests/xmlgenin/conf/namespace.h b/tests/xmlgenin/conf/namespace.h
new file mode 100644
index 00000000..0637e64a
--- /dev/null
+++ b/tests/xmlgenin/conf/namespace.h
@@ -0,0 +1,12 @@
+/* Test namespace features */
+
+#pragma once
+
+typedef struct _virNameSpaceDef virNameSpaceDef;
+struct _virNameSpaceDef { /* genparse, genformat */
+ char *name; /* xmlelem */
+
+ /* Network specific XML namespace data */
+ void *namespaceData;
+ virXMLNamespace ns;
+};
diff --git a/tests/xmlgenin/conf/required.h b/tests/xmlgenin/conf/required.h
new file mode 100644
index 00000000..d45af727
--- /dev/null
+++ b/tests/xmlgenin/conf/required.h
@@ -0,0 +1,9 @@
+/* Test required features */
+
+#pragma once
+
+typedef struct _virRequiredDef virRequiredDef;
+struct _virRequiredDef { /* genparse, genformat */
+ char *name; /* xmlattr, required */
+ virNetworkBootpDef bootp; /* xmlelem, required */
+};
diff --git a/tests/xmlgenin/conf/skipparse.h b/tests/xmlgenin/conf/skipparse.h
new file mode 100644
index 00000000..680a1107
--- /dev/null
+++ b/tests/xmlgenin/conf/skipparse.h
@@ -0,0 +1,10 @@
+/* Test skipparse features */
+
+#pragma once
+
+typedef struct _virSkipParseDef virSkipParseDef;
+struct _virSkipParseDef { /* genparse, genformat */
+ int connections; /* xmlattr, skipparse */
+ size_t nifs;
+ virNetworkForwardIfDef *ifs; /* xmlelem, array, skipparse */
+};
diff --git a/tests/xmlgenin/conf/specify.h b/tests/xmlgenin/conf/specify.h
new file mode 100644
index 00000000..419bd24d
--- /dev/null
+++ b/tests/xmlgenin/conf/specify.h
@@ -0,0 +1,13 @@
+/* Test specify features */
+
+#pragma once
+
+typedef struct _virSpecifyDef virSpecifyDef;
+struct _virSpecifyDef { /* genparse, genformat */
+ virNetworkDHCPLeaseTimeUnitType unit; /* xmlattr */
+ unsigned long expiry; /* xmlattr, specify:unit */
+ virMacAddr mac; /* xmlattr:mac/address */
+ bool mac_specified; /* specify:mac */
+ virUUID uuid; /* xmlelem, xmltext */
+ bool uuid_specified; /* specify:uuid */
+};
diff --git a/tests/xmlgenin/conf/xmlattr.h b/tests/xmlgenin/conf/xmlattr.h
new file mode 100644
index 00000000..60dfae9a
--- /dev/null
+++ b/tests/xmlgenin/conf/xmlattr.h
@@ -0,0 +1,10 @@
+/* Test xmlattr features */
+
+#pragma once
+
+typedef struct _virXMLAttrDef virXMLAttrDef;
+struct _virXMLAttrDef { /* genparse, genformat */
+ char *family; /* xmlattr */
+ virTristateBool localPTR; /* xmlattr:localPtr */
+ char *tftproot; /* xmlattr:tftp/root */
+};
diff --git a/tests/xmlgenin/conf/xmlelem.h b/tests/xmlgenin/conf/xmlelem.h
new file mode 100644
index 00000000..d111f2b5
--- /dev/null
+++ b/tests/xmlgenin/conf/xmlelem.h
@@ -0,0 +1,10 @@
+/* Test xmlelem features */
+
+#pragma once
+
+typedef struct _virXMLElemDef virXMLElemDef;
+struct _virXMLElemDef { /* genparse, genformat */
+ virPortRange port; /* xmlelem */
+ virSocketAddrRange addr; /* xmlelem:address */
+ virUUID uuid; /* xmlelem, xmltext */
+};
diff --git a/tests/xmlgenin/conf/xmlgroup.h b/tests/xmlgenin/conf/xmlgroup.h
new file mode 100644
index 00000000..ed12d919
--- /dev/null
+++ b/tests/xmlgenin/conf/xmlgroup.h
@@ -0,0 +1,8 @@
+/* Test xmlgroup features */
+
+#pragma once
+
+typedef struct _virXMLGroupDef virXMLGroupDef;
+struct _virXMLGroupDef { /* genparse, genformat */
+ virUtilAuthDef auth; /* xmlgroup */
+};
diff --git a/tests/xmlgenin/conf/xmlswitch.h b/tests/xmlgenin/conf/xmlswitch.h
new file mode 100644
index 00000000..8730f1b3
--- /dev/null
+++ b/tests/xmlgenin/conf/xmlswitch.h
@@ -0,0 +1,17 @@
+/* Test xmlswitch features */
+
+#pragma once
+
+typedef struct _virXMLSwitchDef virXMLSwitchDef;
+struct _virXMLSwitchDef { /* genparse, genformat */
+ virDomainGraphicsType type; /* xmlattr */
+
+ union {
+ virDomainGraphicsSDLDef sdl; /* xmlgroup */
+ virDomainGraphicsVNCDef vnc; /* xmlgroup */
+ virDomainGraphicsRDPDef rdp; /* xmlgroup */
+ virDomainGraphicsDesktopDef desktop; /* xmlgroup */
+ virDomainGraphicsSpiceDef spice; /* xmlgroup */
+ virDomainGraphicsEGLHeadlessDef egl_headless; /* xmlgroup */
+ } data; /* xmlswitch:type */
+};
diff --git a/tests/xmlgenin/util/enums.h b/tests/xmlgenin/util/enums.h
new file mode 100644
index 00000000..89d2eccd
--- /dev/null
+++ b/tests/xmlgenin/util/enums.h
@@ -0,0 +1,58 @@
+/* Basic enum */
+
+#pragma once
+
+/*
+ * The tool xmlgen scans all header-files in 'util' and 'conf'
+ * to find all enum types, and further, to determine whether
+ * they have default item.
+ *
+ */
+
+typedef enum {
+ VIR_DOMAIN_GRAPHICS_TYPE_SDL,
+ VIR_DOMAIN_GRAPHICS_TYPE_VNC,
+ VIR_DOMAIN_GRAPHICS_TYPE_RDP,
+ VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP,
+ VIR_DOMAIN_GRAPHICS_TYPE_SPICE,
+ VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS,
+
+ VIR_DOMAIN_GRAPHICS_TYPE_LAST
+} virDomainGraphicsType;
+
+typedef enum {
+ VIR_NETWORK_FORWARD_NONE = 0,
+ VIR_NETWORK_FORWARD_NAT,
+ VIR_NETWORK_FORWARD_ROUTE,
+ VIR_NETWORK_FORWARD_OPEN,
+ VIR_NETWORK_FORWARD_BRIDGE,
+ VIR_NETWORK_FORWARD_PRIVATE,
+ VIR_NETWORK_FORWARD_VEPA,
+ VIR_NETWORK_FORWARD_PASSTHROUGH,
+ VIR_NETWORK_FORWARD_HOSTDEV,
+
+ VIR_NETWORK_FORWARD_LAST,
+} virNetworkForwardType;
+
+typedef enum {
+ VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_DEFAULT = 0,
+ VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_KERNEL,
+ VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LIBVIRT,
+ VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST,
+} virNetworkBridgeMACTableManagerType;
+
+typedef enum {
+ VIR_TRISTATE_BOOL_ABSENT = 0,
+ VIR_TRISTATE_BOOL_YES,
+ VIR_TRISTATE_BOOL_NO,
+
+ VIR_TRISTATE_BOOL_LAST
+} virTristateBool;
+
+typedef enum {
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS = 0,
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES,
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_HOURS,
+
+ VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
+} virNetworkDHCPLeaseTimeUnitType;
diff --git a/tests/xmlgenin/util/structs.h b/tests/xmlgenin/util/structs.h
new file mode 100644
index 00000000..80c10096
--- /dev/null
+++ b/tests/xmlgenin/util/structs.h
@@ -0,0 +1,67 @@
+/* Basic structs */
+
+#pragma once
+
+/*
+ * The tool xmlgen scans all header-files in 'util' and 'conf'
+ * to find all struct types.
+ * For tests, it's unnecessary to include any members for these structs.
+ */
+
+typedef struct _virNetDevIPRoute virNetDevIPRoute;
+struct _virNetDevIPRoute {
+};
+
+typedef struct _virNetworkDNSForwarder virNetworkDNSForwarder;
+struct _virNetworkDNSForwarder {
+};
+
+typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;
+struct _virNetworkDNSTxtDef {
+};
+
+typedef struct _virSocketAddr virSocketAddr;
+struct _virSocketAddr {
+};
+
+typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
+struct _virNetworkForwardIfDef {
+};
+
+typedef struct _virPortRange virPortRange;
+struct _virPortRange {
+};
+
+typedef struct _virSocketAddrRange virSocketAddrRange;
+struct _virSocketAddrRange {
+};
+
+typedef struct _virUtilAuthDef virUtilAuthDef;
+struct _virUtilAuthDef {
+};
+
+typedef struct _virNetworkBootpDef virNetworkBootpDef;
+struct _virNetworkBootpDef {
+};
+
+typedef struct _virMacAddr virMacAddr;
+struct _virMacAddr {
+};
+
+struct _virDomainGraphicsSDLDef {
+};
+
+struct _virDomainGraphicsVNCDef {
+};
+
+struct _virDomainGraphicsRDPDef {
+};
+
+struct _virDomainGraphicsDesktopDef {
+};
+
+struct _virDomainGraphicsSpiceDef {
+};
+
+struct _virDomainGraphicsEGLHeadlessDef {
+};
diff --git a/tests/xmlgenout/array.txt b/tests/xmlgenout/array.txt
new file mode 100644
index 00000000..ccb2d168
--- /dev/null
+++ b/tests/xmlgenout/array.txt
@@ -0,0 +1,364 @@
+[conf/array.generated.h]
+
+void
+virArrayDefClear(virArrayDef *def);
+
+
+[conf/array.generated.c]
+
+void
+virArrayDefClear(virArrayDef *def)
+{
+ if (!def)
+ return;
+
+ if (def->nnames) {
+ size_t i;
+ for (i = 0; i < def->nnames; i++) {
+ g_free(def->names[i]);
+ def->names[i] = NULL;
+ }
+ }
+ g_free(def->names);
+ def->names = NULL;
+ def->nnames = 0;
+
+ if (def->nfwds) {
+ size_t i;
+ for (i = 0; i < def->nfwds; i++)
+ virNetworkDNSForwarderClear(&def->forwarders[i]);
+ }
+ g_free(def->forwarders);
+ def->forwarders = NULL;
+ def->nfwds = 0;
+
+ if (def->ntxts) {
+ size_t i;
+ for (i = 0; i < def->ntxts; i++)
+ virNetworkDNSTxtDefClear(&def->txts[i]);
+ }
+ g_free(def->txts);
+ def->txts = NULL;
+ def->ntxts = 0;
+
+ if (def->nroutes) {
+ size_t i;
+ for (i = 0; i < def->nroutes; i++) {
+ virNetDevIPRouteClear(def->routes[i]);
+ g_free(def->routes[i]);
+ def->routes[i] = NULL;
+ }
+ }
+ g_free(def->routes);
+ def->routes = NULL;
+ def->nroutes = 0;
+}
+
+
+[conf/array.generated.h]
+
+int
+virArrayDefParseXML(xmlNodePtr node,
+ virArrayDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/array.generated.h]
+
+#ifdef ENABLE_VIR_ARRAY_DEF_PARSE_HOOK
+
+int
+virArrayDefParseHook(xmlNodePtr node,
+ virArrayDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ int nHostnameNodes,
+ int nForwarderNodes,
+ int nTxtNodes,
+ int nRouteNodes);
+
+#endif
+
+
+[conf/array.generated.h]
+
+#ifdef ENABLE_VIR_ARRAY_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virArrayDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/array.generated.c]
+
+int
+virArrayDefParseXML(xmlNodePtr node,
+ virArrayDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ int nHostnameNodes = 0;
+ xmlNodePtr *nodes = NULL;
+ int nForwarderNodes = 0;
+ int nTxtNodes = 0;
+ int nRouteNodes = 0;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_ARRAY_DEF_PARSE_HOOK_SET_ARGS
+ virArrayDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ nHostnameNodes = virXMLChildNodeSet(node, "hostname", &nodes);
+ if (nHostnameNodes > 0) {
+ size_t i;
+
+ def->names = g_new0(typeof(*def->names), nHostnameNodes);
+ for (i = 0; i < nHostnameNodes; i++) {
+ xmlNodePtr tnode = nodes[i];
+ def->names[i] = virXMLNodeContentString(tnode);
+ }
+ def->nnames = nHostnameNodes;
+ g_free(nodes);
+ nodes = NULL;
+ } else if (nHostnameNodes < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s element found."),
+ "hostname");
+ goto error;
+ }
+
+ nForwarderNodes = virXMLChildNodeSet(node, "forwarder", &nodes);
+ if (nForwarderNodes > 0) {
+ size_t i;
+
+ def->forwarders = g_new0(typeof(*def->forwarders), nForwarderNodes);
+ for (i = 0; i < nForwarderNodes; i++) {
+ xmlNodePtr tnode = nodes[i];
+ if (virNetworkDNSForwarderParseXML(tnode, &def->forwarders[i],
instname, arg_parent, arg_opaque) < 0)
+ goto error;
+ }
+ def->nfwds = nForwarderNodes;
+ g_free(nodes);
+ nodes = NULL;
+ } else if (nForwarderNodes < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s element found."),
+ "forwarder");
+ goto error;
+ }
+
+ nTxtNodes = virXMLChildNodeSet(node, "txt", &nodes);
+ if (nTxtNodes > 0) {
+ size_t i;
+
+ def->txts = g_new0(typeof(*def->txts), nTxtNodes);
+ for (i = 0; i < nTxtNodes; i++) {
+ xmlNodePtr tnode = nodes[i];
+ if (virNetworkDNSTxtDefParseXML(tnode, &def->txts[i], instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ }
+ def->ntxts = nTxtNodes;
+ g_free(nodes);
+ nodes = NULL;
+ } else if (nTxtNodes < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s element found."),
+ "txt");
+ goto error;
+ }
+
+ nRouteNodes = virXMLChildNodeSet(node, "route", &nodes);
+ if (nRouteNodes > 0) {
+ size_t i;
+
+ def->routes = g_new0(typeof(*def->routes), nRouteNodes);
+ for (i = 0; i < nRouteNodes; i++) {
+ xmlNodePtr tnode = nodes[i];
+ def->routes[i] = g_new0(typeof(*def->routes[i]), 1);
+ if (virNetDevIPRouteParseXML(tnode, def->routes[i], instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ }
+ def->nroutes = nRouteNodes;
+ g_free(nodes);
+ nodes = NULL;
+ } else if (nRouteNodes < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s element found."),
+ "route");
+ goto error;
+ }
+
+#ifdef ENABLE_VIR_ARRAY_DEF_PARSE_HOOK
+ if (virArrayDefParseHook(node, def, instname, parent, opaque, nHostnameNodes,
nForwarderNodes, nTxtNodes, nRouteNodes) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ g_free(nodes);
+ nodes = NULL;
+ virArrayDefClear(def);
+ return -1;
+}
+
+
+[conf/array.generated.h]
+
+int
+virArrayDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virArrayDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/array.generated.h]
+
+#ifdef ENABLE_VIR_ARRAY_DEF_FORMAT_HOOK
+
+int
+virArrayDefFormatHook(const virArrayDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *namesBuf,
+ virBuffer *forwardersBuf,
+ virBuffer *txtsBuf,
+ virBuffer *routesBuf);
+
+#endif /* ENABLE_VIR_ARRAY_DEF_FORMAT_HOOK */
+
+
+[conf/array.generated.c]
+
+int
+virArrayDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virArrayDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) namesBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) forwardersBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) txtsBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) routesBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_ARRAY_DEF_FORMAT_HOOK
+ if (virArrayDefFormatHook(def, parent, opaque, &empty, &shortcut,
&namesBuf, &forwardersBuf, &txtsBuf, &routesBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_ARRAY_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->nnames || def->nfwds || def->ntxts ||
def->nroutes))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&namesBuf, buf);
+ if (!virBufferTouched(&namesBuf) && def->nnames) {
+ size_t i;
+ for (i = 0; i < def->nnames; i++)
+ virBufferEscapeString(buf, "<hostname>%s</hostname>\n",
def->names[i]);
+ }
+ virBufferAddBuffer(buf, &namesBuf);
+
+ virBufferInheritIndent(&forwardersBuf, buf);
+ if (!virBufferTouched(&forwardersBuf) && def->nfwds) {
+ size_t i;
+ for (i = 0; i < def->nfwds; i++) {
+ if (virNetworkDNSForwarderFormatBuf(buf, "forwarder",
&def->forwarders[i], def, opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &forwardersBuf);
+
+ virBufferInheritIndent(&txtsBuf, buf);
+ if (!virBufferTouched(&txtsBuf) && def->ntxts) {
+ size_t i;
+ for (i = 0; i < def->ntxts; i++) {
+ if (virNetworkDNSTxtDefFormatBuf(buf, "txt", &def->txts[i],
def, opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &txtsBuf);
+
+ virBufferInheritIndent(&routesBuf, buf);
+ if (!virBufferTouched(&routesBuf) && def->nroutes) {
+ size_t i;
+ for (i = 0; i < def->nroutes; i++) {
+ if (virNetDevIPRouteFormatBuf(buf, "route", def->routes[i], def,
opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &routesBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/array.generated.h]
+
+bool
+virArrayDefCheck(const virArrayDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/array.generated.c]
+
+#ifndef RESET_VIR_ARRAY_DEF_CHECK
+
+bool
+virArrayDefCheck(const virArrayDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->nnames || def->nfwds || def->ntxts || def->nroutes;
+}
+
+#endif /* RESET_VIR_ARRAY_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/array.h" */
+/* Makesure "array.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_ARRAY_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_ARRAY_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_ARRAY_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_ARRAY_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "array.generated.h"
diff --git a/tests/xmlgenout/empty.txt b/tests/xmlgenout/empty.txt
new file mode 100644
index 00000000..c83a2c12
--- /dev/null
+++ b/tests/xmlgenout/empty.txt
@@ -0,0 +1,181 @@
+[conf/empty.generated.h]
+
+void
+virEmptyDefClear(virEmptyDef *def);
+
+
+[conf/empty.generated.c]
+
+void
+virEmptyDefClear(virEmptyDef *def)
+{
+ if (!def)
+ return;
+}
+
+
+[conf/empty.generated.h]
+
+int
+virEmptyDefParseXML(xmlNodePtr node,
+ virEmptyDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/empty.generated.h]
+
+#ifdef ENABLE_VIR_EMPTY_DEF_PARSE_HOOK
+
+int
+virEmptyDefParseHook(xmlNodePtr node,
+ virEmptyDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+#endif
+
+
+[conf/empty.generated.h]
+
+#ifdef ENABLE_VIR_EMPTY_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virEmptyDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/empty.generated.c]
+
+int
+virEmptyDefParseXML(xmlNodePtr node,
+ virEmptyDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_EMPTY_DEF_PARSE_HOOK_SET_ARGS
+ virEmptyDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+#ifdef ENABLE_VIR_EMPTY_DEF_PARSE_HOOK
+ if (virEmptyDefParseHook(node, def, instname, parent, opaque) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virEmptyDefClear(def);
+ return -1;
+}
+
+
+[conf/empty.generated.h]
+
+int
+virEmptyDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virEmptyDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/empty.generated.h]
+
+#ifdef ENABLE_VIR_EMPTY_DEF_FORMAT_HOOK
+
+int
+virEmptyDefFormatHook(const virEmptyDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut);
+
+#endif /* ENABLE_VIR_EMPTY_DEF_FORMAT_HOOK */
+
+
+[conf/empty.generated.c]
+
+int
+virEmptyDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virEmptyDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_EMPTY_DEF_FORMAT_HOOK
+ if (virEmptyDefFormatHook(def, parent, opaque, &empty, &shortcut) < 0)
+ return -1;
+#endif /* ENABLE_VIR_EMPTY_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty)
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferAddLit(buf, "/>\n");
+
+ return 0;
+}
+
+
+[conf/empty.generated.h]
+
+bool
+virEmptyDefCheck(const virEmptyDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/empty.generated.c]
+
+#ifndef RESET_VIR_EMPTY_DEF_CHECK
+
+bool
+virEmptyDefCheck(const virEmptyDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return false;
+}
+
+#endif /* RESET_VIR_EMPTY_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/empty.h" */
+/* Makesure "empty.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_EMPTY_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_EMPTY_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_EMPTY_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_EMPTY_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "empty.generated.h"
diff --git a/tests/xmlgenout/enum-first-item.txt b/tests/xmlgenout/enum-first-item.txt
new file mode 100644
index 00000000..4186d46d
--- /dev/null
+++ b/tests/xmlgenout/enum-first-item.txt
@@ -0,0 +1,297 @@
+[conf/enum-first-item.generated.h]
+
+void
+virEnumFirstItemDefClear(virEnumFirstItemDef *def);
+
+
+[conf/enum-first-item.generated.c]
+
+void
+virEnumFirstItemDefClear(virEnumFirstItemDef *def)
+{
+ if (!def)
+ return;
+
+ def->has_def = 0;
+
+ def->has_none = 0;
+
+ def->has_absent = 0;
+
+ def->no_default = 0;
+}
+
+
+[conf/enum-first-item.generated.h]
+
+int
+virEnumFirstItemDefParseXML(xmlNodePtr node,
+ virEnumFirstItemDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/enum-first-item.generated.h]
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK
+
+int
+virEnumFirstItemDefParseHook(xmlNodePtr node,
+ virEnumFirstItemDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ const char *has_defStr,
+ const char *has_noneStr,
+ const char *has_absentStr,
+ const char *no_defaultStr);
+
+#endif
+
+
+[conf/enum-first-item.generated.h]
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virEnumFirstItemDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/enum-first-item.generated.c]
+
+int
+virEnumFirstItemDefParseXML(xmlNodePtr node,
+ virEnumFirstItemDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ g_autofree char *has_defStr = NULL;
+ g_autofree char *has_noneStr = NULL;
+ g_autofree char *has_absentStr = NULL;
+ g_autofree char *no_defaultStr = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK_SET_ARGS
+ virEnumFirstItemDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ has_defStr = virXMLPropString(node, "has_def");
+ if (has_defStr) {
+ if ((def->has_def = virNetworkBridgeMACTableManagerTypeFromString(has_defStr))
<= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "has_def", has_defStr, instname);
+ goto error;
+ }
+ }
+
+ has_noneStr = virXMLPropString(node, "has_none");
+ if (has_noneStr) {
+ if ((def->has_none = virNetworkForwardTypeFromString(has_noneStr)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "has_none", has_noneStr, instname);
+ goto error;
+ }
+ }
+
+ has_absentStr = virXMLPropString(node, "has_absent");
+ if (has_absentStr) {
+ if ((def->has_absent = virTristateBoolTypeFromString(has_absentStr)) <= 0)
{
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "has_absent", has_absentStr, instname);
+ goto error;
+ }
+ }
+
+ no_defaultStr = virXMLPropString(node, "no_default");
+ if (no_defaultStr) {
+ if ((def->no_default = virDomainGraphicsTypeFromString(no_defaultStr)) < 0)
{
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "no_default", no_defaultStr, instname);
+ goto error;
+ }
+ }
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK
+ if (virEnumFirstItemDefParseHook(node, def, instname, parent, opaque, has_defStr,
has_noneStr, has_absentStr, no_defaultStr) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virEnumFirstItemDefClear(def);
+ return -1;
+}
+
+
+[conf/enum-first-item.generated.h]
+
+int
+virEnumFirstItemDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virEnumFirstItemDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/enum-first-item.generated.h]
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_FORMAT_HOOK
+
+int
+virEnumFirstItemDefFormatHook(const virEnumFirstItemDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *has_defBuf,
+ virBuffer *has_noneBuf,
+ virBuffer *has_absentBuf,
+ virBuffer *no_defaultBuf);
+
+#endif /* ENABLE_VIR_ENUM_FIRST_ITEM_DEF_FORMAT_HOOK */
+
+
+[conf/enum-first-item.generated.c]
+
+int
+virEnumFirstItemDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virEnumFirstItemDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) has_defBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) has_noneBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) has_absentBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) no_defaultBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_ENUM_FIRST_ITEM_DEF_FORMAT_HOOK
+ if (virEnumFirstItemDefFormatHook(def, parent, opaque, &empty, &shortcut,
&has_defBuf, &has_noneBuf, &has_absentBuf, &no_defaultBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_ENUM_FIRST_ITEM_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->has_def > 0 || def->has_none > 0 ||
def->has_absent > 0 || def->no_default >= 0))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&has_defBuf, buf);
+ if (!virBufferTouched(&has_defBuf) && def->has_def > 0) {
+ const char *str = virNetworkBridgeMACTableManagerTypeToString(def->has_def);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "has_def", def->has_def);
+ return -1;
+ }
+ virBufferAsprintf(&has_defBuf, " has_def='%s'", str);
+ }
+ virBufferAddBuffer(buf, &has_defBuf);
+
+ virBufferInheritIndent(&has_noneBuf, buf);
+ if (!virBufferTouched(&has_noneBuf) && def->has_none > 0) {
+ const char *str = virNetworkForwardTypeToString(def->has_none);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "has_none", def->has_none);
+ return -1;
+ }
+ virBufferAsprintf(&has_noneBuf, " has_none='%s'", str);
+ }
+ virBufferAddBuffer(buf, &has_noneBuf);
+
+ virBufferInheritIndent(&has_absentBuf, buf);
+ if (!virBufferTouched(&has_absentBuf) && def->has_absent > 0) {
+ const char *str = virTristateBoolTypeToString(def->has_absent);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "has_absent", def->has_absent);
+ return -1;
+ }
+ virBufferAsprintf(&has_absentBuf, " has_absent='%s'",
str);
+ }
+ virBufferAddBuffer(buf, &has_absentBuf);
+
+ virBufferInheritIndent(&no_defaultBuf, buf);
+ if (!virBufferTouched(&no_defaultBuf) && def->no_default >= 0) {
+ const char *str = virDomainGraphicsTypeToString(def->no_default);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "no_default", def->no_default);
+ return -1;
+ }
+ virBufferAsprintf(&no_defaultBuf, " no_default='%s'",
str);
+ }
+ virBufferAddBuffer(buf, &no_defaultBuf);
+
+ virBufferAddLit(buf, "/>\n");
+
+ return 0;
+}
+
+
+[conf/enum-first-item.generated.h]
+
+bool
+virEnumFirstItemDefCheck(const virEnumFirstItemDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/enum-first-item.generated.c]
+
+#ifndef RESET_VIR_ENUM_FIRST_ITEM_DEF_CHECK
+
+bool
+virEnumFirstItemDefCheck(const virEnumFirstItemDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->has_def > 0 || def->has_none > 0 || def->has_absent > 0
|| def->no_default >= 0;
+}
+
+#endif /* RESET_VIR_ENUM_FIRST_ITEM_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/enum-first-item.h" */
+/* Makesure "enum-first-item.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_ENUM_FIRST_ITEM_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_ENUM_FIRST_ITEM_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_ENUM_FIRST_ITEM_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "enum-first-item.generated.h"
diff --git a/tests/xmlgenout/external.txt b/tests/xmlgenout/external.txt
new file mode 100644
index 00000000..4f0ea691
--- /dev/null
+++ b/tests/xmlgenout/external.txt
@@ -0,0 +1,205 @@
+[conf/external.generated.h]
+
+void
+virExternalDefClear(virExternalDef *def);
+
+
+[conf/external.generated.c]
+
+void
+virExternalDefClear(virExternalDef *def)
+{
+ if (!def)
+ return;
+
+ xmlNodeClear(&def->metadata);
+}
+
+
+[conf/external.generated.h]
+
+int
+virExternalDefParseXML(xmlNodePtr node,
+ virExternalDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/external.generated.h]
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK
+
+int
+virExternalDefParseHook(xmlNodePtr node,
+ virExternalDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ xmlNodePtr metadataNode);
+
+#endif
+
+
+[conf/external.generated.h]
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virExternalDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/external.generated.c]
+
+int
+virExternalDefParseXML(xmlNodePtr node,
+ virExternalDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ xmlNodePtr metadataNode = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK_SET_ARGS
+ virExternalDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ metadataNode = virXMLChildNode(node, "metadata");
+ if (metadataNode) {
+ if (xmlNodeParseXML(metadataNode, &def->metadata, instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ }
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK
+ if (virExternalDefParseHook(node, def, instname, parent, opaque, metadataNode) <
0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virExternalDefClear(def);
+ return -1;
+}
+
+
+[conf/external.generated.h]
+
+int
+virExternalDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virExternalDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/external.generated.h]
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_FORMAT_HOOK
+
+int
+virExternalDefFormatHook(const virExternalDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *metadataBuf);
+
+#endif /* ENABLE_VIR_EXTERNAL_DEF_FORMAT_HOOK */
+
+
+[conf/external.generated.c]
+
+int
+virExternalDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virExternalDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) metadataBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_EXTERNAL_DEF_FORMAT_HOOK
+ if (virExternalDefFormatHook(def, parent, opaque, &empty, &shortcut,
&metadataBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_EXTERNAL_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(xmlNodeCheck(&def->metadata, def, opaque)))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&metadataBuf, buf);
+ if (!virBufferTouched(&metadataBuf) &&
xmlNodeCheck(&def->metadata, def, opaque)) {
+ if (xmlNodeFormatBuf(&metadataBuf, "metadata",
&def->metadata, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &metadataBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/external.generated.h]
+
+bool
+virExternalDefCheck(const virExternalDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/external.generated.c]
+
+#ifndef RESET_VIR_EXTERNAL_DEF_CHECK
+
+bool
+virExternalDefCheck(const virExternalDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return xmlNodeCheck(&def->metadata, def, opaque);
+}
+
+#endif /* RESET_VIR_EXTERNAL_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/external.h" */
+/* Makesure "external.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_EXTERNAL_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_EXTERNAL_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_EXTERNAL_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "external.generated.h"
diff --git a/tests/xmlgenout/genformat-separate.txt
b/tests/xmlgenout/genformat-separate.txt
new file mode 100644
index 00000000..90729d2a
--- /dev/null
+++ b/tests/xmlgenout/genformat-separate.txt
@@ -0,0 +1,190 @@
+[conf/genformat-separate.generated.h]
+
+#ifdef ENABLE_VIR_SEPARATE_DEF_FORMAT_ATTR_HOOK
+
+int
+virSeparateDefFormatAttrHook(const virSeparateDef *def,
+ const void *parent,
+ const void *opaque,
+ virBuffer *enableBuf);
+
+#endif /* ENABLE_VIR_SEPARATE_DEF_FORMAT_ATTR_HOOK */
+
+
+[conf/genformat-separate.generated.h]
+
+int
+virSeparateDefFormatAttr(virBuffer *buf,
+ const virSeparateDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat-separate.generated.c]
+
+int
+virSeparateDefFormatAttr(virBuffer *buf,
+ const virSeparateDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) enableBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_SEPARATE_DEF_FORMAT_ATTR_HOOK
+ if (virSeparateDefFormatAttrHook(def, parent, opaque, &enableBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_SEPARATE_DEF_FORMAT_ATTR_HOOK */
+
+ virBufferInheritIndent(&enableBuf, buf);
+ if (!virBufferTouched(&enableBuf) && def->enable > 0) {
+ const char *str = virTristateBoolTypeToString(def->enable);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "enable", def->enable);
+ return -1;
+ }
+ virBufferAsprintf(&enableBuf, " enable='%s'", str);
+ }
+ virBufferAddBuffer(buf, &enableBuf);
+
+ return 0;
+}
+
+
+[conf/genformat-separate.generated.h]
+
+bool
+virSeparateDefCheckAttr(const virSeparateDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat-separate.generated.c]
+
+#ifndef RESET_VIR_SEPARATE_DEF_CHECK_ATTR
+
+bool
+virSeparateDefCheckAttr(const virSeparateDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->enable > 0;
+}
+
+#endif /* RESET_VIR_SEPARATE_DEF_CHECK_ATTR */
+
+
+[conf/genformat-separate.generated.h]
+
+#ifdef ENABLE_VIR_SEPARATE_DEF_FORMAT_ELEM_HOOK
+
+int
+virSeparateDefFormatElemHook(const virSeparateDef *def,
+ const void *parent,
+ const void *opaque,
+ virBuffer *ipBuf,
+ virBuffer *txtsBuf);
+
+#endif /* ENABLE_VIR_SEPARATE_DEF_FORMAT_ELEM_HOOK */
+
+
+[conf/genformat-separate.generated.h]
+
+int
+virSeparateDefFormatElem(virBuffer *buf,
+ const virSeparateDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat-separate.generated.c]
+
+int
+virSeparateDefFormatElem(virBuffer *buf,
+ const virSeparateDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) ipBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) txtsBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_SEPARATE_DEF_FORMAT_ELEM_HOOK
+ if (virSeparateDefFormatElemHook(def, parent, opaque, &ipBuf, &txtsBuf) <
0)
+ return -1;
+#endif /* ENABLE_VIR_SEPARATE_DEF_FORMAT_ELEM_HOOK */
+
+ virBufferInheritIndent(&ipBuf, buf);
+ if (!virBufferTouched(&ipBuf) && virSocketAddrCheck(&def->ip, def,
opaque)) {
+ if (virSocketAddrFormatBuf(&ipBuf, "ip", &def->ip, def,
opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &ipBuf);
+
+ virBufferInheritIndent(&txtsBuf, buf);
+ if (!virBufferTouched(&txtsBuf) && def->ntxts) {
+ size_t i;
+ for (i = 0; i < def->ntxts; i++) {
+ if (virNetworkDNSTxtDefFormatBuf(buf, "txt", &def->txts[i],
def, opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &txtsBuf);
+
+ return 0;
+}
+
+
+[conf/genformat-separate.generated.h]
+
+bool
+virSeparateDefCheckElem(const virSeparateDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat-separate.generated.c]
+
+#ifndef RESET_VIR_SEPARATE_DEF_CHECK_ELEM
+
+bool
+virSeparateDefCheckElem(const virSeparateDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return virSocketAddrCheck(&def->ip, def, opaque) || def->ntxts;
+}
+
+#endif /* RESET_VIR_SEPARATE_DEF_CHECK_ELEM */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/genformat-separate.h" */
+/* Makesure "genformat-separate.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_SEPARATE_DEF_FORMAT_ATTR_HOOK */
+/* #define ENABLE_VIR_SEPARATE_DEF_FORMAT_ELEM_HOOK */
+
+/* #define RESET_VIR_SEPARATE_DEF_CHECK_ATTR */
+/* #define RESET_VIR_SEPARATE_DEF_CHECK_ELEM */
+
+/* Makesure below is the bottom line! */
+#include "genformat-separate.generated.h"
diff --git a/tests/xmlgenout/genformat.txt b/tests/xmlgenout/genformat.txt
new file mode 100644
index 00000000..72e4e0c0
--- /dev/null
+++ b/tests/xmlgenout/genformat.txt
@@ -0,0 +1,142 @@
+[conf/genformat.generated.h]
+
+int
+virGenFormatDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virGenFormatDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat.generated.h]
+
+#ifdef ENABLE_VIR_GEN_FORMAT_DEF_FORMAT_HOOK
+
+int
+virGenFormatDefFormatHook(const virGenFormatDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *enableBuf,
+ virBuffer *ipBuf,
+ virBuffer *txtsBuf);
+
+#endif /* ENABLE_VIR_GEN_FORMAT_DEF_FORMAT_HOOK */
+
+
+[conf/genformat.generated.c]
+
+int
+virGenFormatDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virGenFormatDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) enableBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) ipBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) txtsBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_GEN_FORMAT_DEF_FORMAT_HOOK
+ if (virGenFormatDefFormatHook(def, parent, opaque, &empty, &shortcut,
&enableBuf, &ipBuf, &txtsBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_GEN_FORMAT_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->enable > 0 || virSocketAddrCheck(&def->ip, def,
opaque) || def->ntxts))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&enableBuf, buf);
+ if (!virBufferTouched(&enableBuf) && def->enable > 0) {
+ const char *str = virTristateBoolTypeToString(def->enable);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "enable", def->enable);
+ return -1;
+ }
+ virBufferAsprintf(&enableBuf, " enable='%s'", str);
+ }
+ virBufferAddBuffer(buf, &enableBuf);
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(virSocketAddrCheck(&def->ip, def, opaque) ||
def->ntxts)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&ipBuf, buf);
+ if (!virBufferTouched(&ipBuf) && virSocketAddrCheck(&def->ip, def,
opaque)) {
+ if (virSocketAddrFormatBuf(&ipBuf, "ip", &def->ip, def,
opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &ipBuf);
+
+ virBufferInheritIndent(&txtsBuf, buf);
+ if (!virBufferTouched(&txtsBuf) && def->ntxts) {
+ size_t i;
+ for (i = 0; i < def->ntxts; i++) {
+ if (virNetworkDNSTxtDefFormatBuf(buf, "txt", &def->txts[i],
def, opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &txtsBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/genformat.generated.h]
+
+bool
+virGenFormatDefCheck(const virGenFormatDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/genformat.generated.c]
+
+#ifndef RESET_VIR_GEN_FORMAT_DEF_CHECK
+
+bool
+virGenFormatDefCheck(const virGenFormatDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->enable > 0 || virSocketAddrCheck(&def->ip, def, opaque) ||
def->ntxts;
+}
+
+#endif /* RESET_VIR_GEN_FORMAT_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/genformat.h" */
+/* Makesure "genformat.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_GEN_FORMAT_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_GEN_FORMAT_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "genformat.generated.h"
diff --git a/tests/xmlgenout/genparse.txt b/tests/xmlgenout/genparse.txt
new file mode 100644
index 00000000..e24762e1
--- /dev/null
+++ b/tests/xmlgenout/genparse.txt
@@ -0,0 +1,154 @@
+[conf/genparse.generated.h]
+
+void
+virGenParseDefClear(virGenParseDef *def);
+
+
+[conf/genparse.generated.c]
+
+void
+virGenParseDefClear(virGenParseDef *def)
+{
+ if (!def)
+ return;
+
+ def->enable = 0;
+
+ virSocketAddrClear(&def->ip);
+
+ if (def->ntxts) {
+ size_t i;
+ for (i = 0; i < def->ntxts; i++)
+ virNetworkDNSTxtDefClear(&def->txts[i]);
+ }
+ g_free(def->txts);
+ def->txts = NULL;
+ def->ntxts = 0;
+}
+
+
+[conf/genparse.generated.h]
+
+int
+virGenParseDefParseXML(xmlNodePtr node,
+ virGenParseDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/genparse.generated.h]
+
+#ifdef ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK
+
+int
+virGenParseDefParseHook(xmlNodePtr node,
+ virGenParseDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ const char *enableStr,
+ xmlNodePtr ipNode,
+ int nTxtNodes);
+
+#endif
+
+
+[conf/genparse.generated.h]
+
+#ifdef ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virGenParseDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/genparse.generated.c]
+
+int
+virGenParseDefParseXML(xmlNodePtr node,
+ virGenParseDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ g_autofree char *enableStr = NULL;
+ xmlNodePtr ipNode = NULL;
+ int nTxtNodes = 0;
+ xmlNodePtr *nodes = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK_SET_ARGS
+ virGenParseDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ enableStr = virXMLPropString(node, "enable");
+ if (enableStr) {
+ if ((def->enable = virTristateBoolTypeFromString(enableStr)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "enable", enableStr, instname);
+ goto error;
+ }
+ }
+
+ ipNode = virXMLChildNode(node, "ip");
+ if (ipNode) {
+ if (virSocketAddrParseXML(ipNode, &def->ip, instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ }
+
+ nTxtNodes = virXMLChildNodeSet(node, "txt", &nodes);
+ if (nTxtNodes > 0) {
+ size_t i;
+
+ def->txts = g_new0(typeof(*def->txts), nTxtNodes);
+ for (i = 0; i < nTxtNodes; i++) {
+ xmlNodePtr tnode = nodes[i];
+ if (virNetworkDNSTxtDefParseXML(tnode, &def->txts[i], instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ }
+ def->ntxts = nTxtNodes;
+ g_free(nodes);
+ nodes = NULL;
+ } else if (nTxtNodes < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid %s element found."),
+ "txt");
+ goto error;
+ }
+
+#ifdef ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK
+ if (virGenParseDefParseHook(node, def, instname, parent, opaque, enableStr, ipNode,
nTxtNodes) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ g_free(nodes);
+ nodes = NULL;
+ virGenParseDefClear(def);
+ return -1;
+}
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/genparse.h" */
+/* Makesure "genparse.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_GEN_PARSE_DEF_PARSE_HOOK_SET_ARGS */
+
+/* Makesure below is the bottom line! */
+#include "genparse.generated.h"
diff --git a/tests/xmlgenout/namespace.txt b/tests/xmlgenout/namespace.txt
new file mode 100644
index 00000000..df1660dd
--- /dev/null
+++ b/tests/xmlgenout/namespace.txt
@@ -0,0 +1,222 @@
+[conf/namespace.generated.h]
+
+void
+virNameSpaceDefClear(virNameSpaceDef *def);
+
+
+[conf/namespace.generated.c]
+
+void
+virNameSpaceDefClear(virNameSpaceDef *def)
+{
+ if (!def)
+ return;
+
+ g_free(def->name);
+ def->name = NULL;
+
+ if (def->namespaceData && def->ns.free)
+ (def->ns.free)(def->namespaceData);
+}
+
+
+[conf/namespace.generated.h]
+
+int
+virNameSpaceDefParseXML(xmlNodePtr node,
+ virNameSpaceDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ xmlXPathContextPtr ctxt,
+ virNetworkXMLOption *xmlopt);
+
+
+[conf/namespace.generated.h]
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK
+
+int
+virNameSpaceDefParseHook(xmlNodePtr node,
+ virNameSpaceDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ xmlXPathContextPtr ctxt,
+ virNetworkXMLOption *xmlopt);
+
+#endif
+
+
+[conf/namespace.generated.h]
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virNameSpaceDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/namespace.generated.c]
+
+int
+virNameSpaceDefParseXML(xmlNodePtr node,
+ virNameSpaceDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED,
+ xmlXPathContextPtr ctxt,
+ virNetworkXMLOption *xmlopt)
+{
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK_SET_ARGS
+ virNameSpaceDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ def->name = virXMLChildNodeContent(node, "name");
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK
+ if (virNameSpaceDefParseHook(node, def, instname, parent, opaque, ctxt, xmlopt) <
0)
+ goto error;
+#endif
+
+ if (xmlopt)
+ def->ns = xmlopt->ns;
+ if (def->ns.parse) {
+ if (virXMLNamespaceRegister(ctxt, &def->ns) < 0)
+ goto error;
+ if ((def->ns.parse)(ctxt, &def->namespaceData) < 0)
+ goto error;
+ }
+ return 0;
+
+ error:
+ virNameSpaceDefClear(def);
+ return -1;
+}
+
+
+[conf/namespace.generated.h]
+
+int
+virNameSpaceDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virNameSpaceDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/namespace.generated.h]
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_FORMAT_HOOK
+
+int
+virNameSpaceDefFormatHook(const virNameSpaceDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *nameBuf);
+
+#endif /* ENABLE_VIR_NAME_SPACE_DEF_FORMAT_HOOK */
+
+
+[conf/namespace.generated.c]
+
+int
+virNameSpaceDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virNameSpaceDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) nameBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_NAME_SPACE_DEF_FORMAT_HOOK
+ if (virNameSpaceDefFormatHook(def, parent, opaque, &empty, &shortcut,
&nameBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_NAME_SPACE_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->name))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ if (def->namespaceData && def->ns.format)
+ virXMLNamespaceFormatNS(buf, &def->ns);
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&nameBuf, buf);
+ if (!virBufferTouched(&nameBuf) && def->name)
+ virBufferEscapeString(&nameBuf, "<name>%s</name>\n",
def->name);
+ virBufferAddBuffer(buf, &nameBuf);
+
+ if (def->namespaceData && def->ns.format) {
+ if ((def->ns.format)(buf, def->namespaceData) < 0)
+ return -1;
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/namespace.generated.h]
+
+bool
+virNameSpaceDefCheck(const virNameSpaceDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/namespace.generated.c]
+
+#ifndef RESET_VIR_NAME_SPACE_DEF_CHECK
+
+bool
+virNameSpaceDefCheck(const virNameSpaceDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->name;
+}
+
+#endif /* RESET_VIR_NAME_SPACE_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/namespace.h" */
+/* Makesure "namespace.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_NAME_SPACE_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_NAME_SPACE_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_NAME_SPACE_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "namespace.generated.h"
diff --git a/tests/xmlgenout/required.txt b/tests/xmlgenout/required.txt
new file mode 100644
index 00000000..df509284
--- /dev/null
+++ b/tests/xmlgenout/required.txt
@@ -0,0 +1,236 @@
+[conf/required.generated.h]
+
+void
+virRequiredDefClear(virRequiredDef *def);
+
+
+[conf/required.generated.c]
+
+void
+virRequiredDefClear(virRequiredDef *def)
+{
+ if (!def)
+ return;
+
+ g_free(def->name);
+ def->name = NULL;
+
+ virNetworkBootpDefClear(&def->bootp);
+}
+
+
+[conf/required.generated.h]
+
+int
+virRequiredDefParseXML(xmlNodePtr node,
+ virRequiredDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/required.generated.h]
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK
+
+int
+virRequiredDefParseHook(xmlNodePtr node,
+ virRequiredDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ xmlNodePtr bootpNode);
+
+#endif
+
+
+[conf/required.generated.h]
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virRequiredDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/required.generated.c]
+
+int
+virRequiredDefParseXML(xmlNodePtr node,
+ virRequiredDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ xmlNodePtr bootpNode = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK_SET_ARGS
+ virRequiredDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ def->name = virXMLPropString(node, "name");
+ if (def->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Missing '%s' setting in '%s'"),
+ "name", instname);
+ goto error;
+ }
+
+ bootpNode = virXMLChildNode(node, "bootp");
+ if (bootpNode == NULL) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Missing '%s' setting in '%s'"),
+ "bootp", instname);
+ goto error;
+ }
+ if (bootpNode) {
+ if (virNetworkBootpDefParseXML(bootpNode, &def->bootp, instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ }
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK
+ if (virRequiredDefParseHook(node, def, instname, parent, opaque, bootpNode) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virRequiredDefClear(def);
+ return -1;
+}
+
+
+[conf/required.generated.h]
+
+int
+virRequiredDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virRequiredDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/required.generated.h]
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_FORMAT_HOOK
+
+int
+virRequiredDefFormatHook(const virRequiredDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *nameBuf,
+ virBuffer *bootpBuf);
+
+#endif /* ENABLE_VIR_REQUIRED_DEF_FORMAT_HOOK */
+
+
+[conf/required.generated.c]
+
+int
+virRequiredDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virRequiredDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) nameBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) bootpBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_REQUIRED_DEF_FORMAT_HOOK
+ if (virRequiredDefFormatHook(def, parent, opaque, &empty, &shortcut,
&nameBuf, &bootpBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_REQUIRED_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->name || virNetworkBootpDefCheck(&def->bootp, def,
opaque)))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&nameBuf, buf);
+ if (!virBufferTouched(&nameBuf))
+ virBufferEscapeString(&nameBuf, " name='%s'",
def->name);
+ virBufferAddBuffer(buf, &nameBuf);
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(virNetworkBootpDefCheck(&def->bootp, def, opaque))) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&bootpBuf, buf);
+ if (!virBufferTouched(&bootpBuf)) {
+ if (virNetworkBootpDefFormatBuf(&bootpBuf, "bootp",
&def->bootp, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &bootpBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/required.generated.h]
+
+bool
+virRequiredDefCheck(const virRequiredDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/required.generated.c]
+
+#ifndef RESET_VIR_REQUIRED_DEF_CHECK
+
+bool
+virRequiredDefCheck(const virRequiredDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->name || virNetworkBootpDefCheck(&def->bootp, def, opaque);
+}
+
+#endif /* RESET_VIR_REQUIRED_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/required.h" */
+/* Makesure "required.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_REQUIRED_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_REQUIRED_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_REQUIRED_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "required.generated.h"
diff --git a/tests/xmlgenout/skipparse.txt b/tests/xmlgenout/skipparse.txt
new file mode 100644
index 00000000..b6f6546a
--- /dev/null
+++ b/tests/xmlgenout/skipparse.txt
@@ -0,0 +1,223 @@
+[conf/skipparse.generated.h]
+
+void
+virSkipParseDefClear(virSkipParseDef *def);
+
+
+[conf/skipparse.generated.c]
+
+void
+virSkipParseDefClear(virSkipParseDef *def)
+{
+ if (!def)
+ return;
+
+ def->connections = 0;
+
+ if (def->nifs) {
+ size_t i;
+ for (i = 0; i < def->nifs; i++)
+ virNetworkForwardIfDefClear(&def->ifs[i]);
+ }
+ g_free(def->ifs);
+ def->ifs = NULL;
+ def->nifs = 0;
+}
+
+
+[conf/skipparse.generated.h]
+
+int
+virSkipParseDefParseXML(xmlNodePtr node,
+ virSkipParseDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/skipparse.generated.h]
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK
+
+int
+virSkipParseDefParseHook(xmlNodePtr node,
+ virSkipParseDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+#endif
+
+
+[conf/skipparse.generated.h]
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virSkipParseDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/skipparse.generated.c]
+
+int
+virSkipParseDefParseXML(xmlNodePtr node,
+ virSkipParseDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK_SET_ARGS
+ virSkipParseDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK
+ if (virSkipParseDefParseHook(node, def, instname, parent, opaque) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virSkipParseDefClear(def);
+ return -1;
+}
+
+
+[conf/skipparse.generated.h]
+
+int
+virSkipParseDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virSkipParseDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/skipparse.generated.h]
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_FORMAT_HOOK
+
+int
+virSkipParseDefFormatHook(const virSkipParseDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *connectionsBuf,
+ virBuffer *ifsBuf);
+
+#endif /* ENABLE_VIR_SKIP_PARSE_DEF_FORMAT_HOOK */
+
+
+[conf/skipparse.generated.c]
+
+int
+virSkipParseDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virSkipParseDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) connectionsBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) ifsBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_SKIP_PARSE_DEF_FORMAT_HOOK
+ if (virSkipParseDefFormatHook(def, parent, opaque, &empty, &shortcut,
&connectionsBuf, &ifsBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_SKIP_PARSE_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->connections || def->nifs))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&connectionsBuf, buf);
+ if (!virBufferTouched(&connectionsBuf) && def->connections)
+ virBufferAsprintf(&connectionsBuf, " connections='%d'",
def->connections);
+ virBufferAddBuffer(buf, &connectionsBuf);
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(def->nifs)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&ifsBuf, buf);
+ if (!virBufferTouched(&ifsBuf) && def->nifs) {
+ size_t i;
+ for (i = 0; i < def->nifs; i++) {
+ if (virNetworkForwardIfDefFormatBuf(buf, "if", &def->ifs[i],
def, opaque) < 0)
+ return -1;
+ }
+ }
+ virBufferAddBuffer(buf, &ifsBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/skipparse.generated.h]
+
+bool
+virSkipParseDefCheck(const virSkipParseDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/skipparse.generated.c]
+
+#ifndef RESET_VIR_SKIP_PARSE_DEF_CHECK
+
+bool
+virSkipParseDefCheck(const virSkipParseDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->connections || def->nifs;
+}
+
+#endif /* RESET_VIR_SKIP_PARSE_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/skipparse.h" */
+/* Makesure "skipparse.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_SKIP_PARSE_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_SKIP_PARSE_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_SKIP_PARSE_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "skipparse.generated.h"
diff --git a/tests/xmlgenout/specify.txt b/tests/xmlgenout/specify.txt
new file mode 100644
index 00000000..dd6dac9c
--- /dev/null
+++ b/tests/xmlgenout/specify.txt
@@ -0,0 +1,291 @@
+[conf/specify.generated.h]
+
+void
+virSpecifyDefClear(virSpecifyDef *def);
+
+
+[conf/specify.generated.c]
+
+void
+virSpecifyDefClear(virSpecifyDef *def)
+{
+ if (!def)
+ return;
+
+ def->unit = 0;
+
+ def->expiry = 0;
+
+ virMacAddrClear(&def->mac);
+ def->mac_specified = false;
+
+ virUUIDClear(&def->uuid);
+ def->uuid_specified = false;
+}
+
+
+[conf/specify.generated.h]
+
+int
+virSpecifyDefParseXML(xmlNodePtr node,
+ virSpecifyDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/specify.generated.h]
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK
+
+int
+virSpecifyDefParseHook(xmlNodePtr node,
+ virSpecifyDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ const char *unitStr,
+ const char *expiryStr,
+ const char *macStr,
+ const char *uuidStr);
+
+#endif
+
+
+[conf/specify.generated.h]
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virSpecifyDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/specify.generated.c]
+
+int
+virSpecifyDefParseXML(xmlNodePtr node,
+ virSpecifyDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ g_autofree char *unitStr = NULL;
+ g_autofree char *expiryStr = NULL;
+ g_autofree char *macStr = NULL;
+ g_autofree char *uuidStr = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK_SET_ARGS
+ virSpecifyDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ unitStr = virXMLPropString(node, "unit");
+ if (unitStr) {
+ if ((def->unit = virNetworkDHCPLeaseTimeUnitTypeFromString(unitStr)) < 0)
{
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "unit", unitStr, instname);
+ goto error;
+ }
+ }
+
+ expiryStr = virXMLPropString(node, "expiry");
+ if (expiryStr) {
+ if (virStrToLong_ulp(expiryStr, NULL, 0, &def->expiry) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "expiry", expiryStr, instname);
+ goto error;
+ }
+ }
+
+ macStr = virXMLChildPropString(node, "mac/address");
+ if (macStr) {
+ if (virMacAddrParseXML(macStr, &def->mac, instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ def->mac_specified = true;
+ }
+
+ uuidStr = virXMLChildNodeContent(node, "uuid");
+ if (uuidStr) {
+ if (virUUIDParseXML(uuidStr, &def->uuid, instname, arg_parent, arg_opaque)
< 0)
+ goto error;
+ def->uuid_specified = true;
+ }
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK
+ if (virSpecifyDefParseHook(node, def, instname, parent, opaque, unitStr, expiryStr,
macStr, uuidStr) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virSpecifyDefClear(def);
+ return -1;
+}
+
+
+[conf/specify.generated.h]
+
+int
+virSpecifyDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virSpecifyDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/specify.generated.h]
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_FORMAT_HOOK
+
+int
+virSpecifyDefFormatHook(const virSpecifyDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *unitBuf,
+ virBuffer *expiryBuf,
+ virBuffer *mac_addressBuf,
+ virBuffer *uuidBuf);
+
+#endif /* ENABLE_VIR_SPECIFY_DEF_FORMAT_HOOK */
+
+
+[conf/specify.generated.c]
+
+int
+virSpecifyDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virSpecifyDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) unitBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) expiryBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) mac_addressBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) uuidBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_SPECIFY_DEF_FORMAT_HOOK
+ if (virSpecifyDefFormatHook(def, parent, opaque, &empty, &shortcut,
&unitBuf, &expiryBuf, &mac_addressBuf, &uuidBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_SPECIFY_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->expiry || def->uuid_specified ||
def->mac_specified))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&unitBuf, buf);
+ if (!virBufferTouched(&unitBuf) && def->expiry) {
+ const char *str = virNetworkDHCPLeaseTimeUnitTypeToString(def->unit);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "unit", def->unit);
+ return -1;
+ }
+ virBufferAsprintf(&unitBuf, " unit='%s'", str);
+ }
+ virBufferAddBuffer(buf, &unitBuf);
+
+ virBufferInheritIndent(&expiryBuf, buf);
+ if (!virBufferTouched(&expiryBuf) && def->expiry)
+ virBufferAsprintf(&expiryBuf, " expiry='%lu'",
def->expiry);
+ virBufferAddBuffer(buf, &expiryBuf);
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(def->uuid_specified || def->mac_specified)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ if (virBufferUse(&mac_addressBuf) || def->mac_specified) {
+ virBufferAddLit(buf, "<mac");
+
+ virBufferInheritIndent(&mac_addressBuf, buf);
+ if (!virBufferTouched(&mac_addressBuf) && def->mac_specified) {
+ if (virMacAddrFormatBuf(&mac_addressBuf, "
address='%s'", &def->mac, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &mac_addressBuf);
+
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ virBufferInheritIndent(&uuidBuf, buf);
+ if (!virBufferTouched(&uuidBuf) && def->uuid_specified) {
+ if (virUUIDFormatBuf(&uuidBuf, "<uuid>%s</uuid>\n",
&def->uuid, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &uuidBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/specify.generated.h]
+
+bool
+virSpecifyDefCheck(const virSpecifyDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/specify.generated.c]
+
+#ifndef RESET_VIR_SPECIFY_DEF_CHECK
+
+bool
+virSpecifyDefCheck(const virSpecifyDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->expiry || def->uuid_specified || def->mac_specified;
+}
+
+#endif /* RESET_VIR_SPECIFY_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/specify.h" */
+/* Makesure "specify.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_SPECIFY_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_SPECIFY_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_SPECIFY_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "specify.generated.h"
diff --git a/tests/xmlgenout/xmlattr.txt b/tests/xmlgenout/xmlattr.txt
new file mode 100644
index 00000000..228eb3cc
--- /dev/null
+++ b/tests/xmlgenout/xmlattr.txt
@@ -0,0 +1,252 @@
+[conf/xmlattr.generated.h]
+
+void
+virXMLAttrDefClear(virXMLAttrDef *def);
+
+
+[conf/xmlattr.generated.c]
+
+void
+virXMLAttrDefClear(virXMLAttrDef *def)
+{
+ if (!def)
+ return;
+
+ g_free(def->family);
+ def->family = NULL;
+
+ def->localPTR = 0;
+
+ g_free(def->tftproot);
+ def->tftproot = NULL;
+}
+
+
+[conf/xmlattr.generated.h]
+
+int
+virXMLAttrDefParseXML(xmlNodePtr node,
+ virXMLAttrDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/xmlattr.generated.h]
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK
+
+int
+virXMLAttrDefParseHook(xmlNodePtr node,
+ virXMLAttrDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ const char *localPTRStr);
+
+#endif
+
+
+[conf/xmlattr.generated.h]
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virXMLAttrDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/xmlattr.generated.c]
+
+int
+virXMLAttrDefParseXML(xmlNodePtr node,
+ virXMLAttrDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ g_autofree char *localPTRStr = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK_SET_ARGS
+ virXMLAttrDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ def->family = virXMLPropString(node, "family");
+
+ localPTRStr = virXMLPropString(node, "localPtr");
+ if (localPTRStr) {
+ if ((def->localPTR = virTristateBoolTypeFromString(localPTRStr)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "localPtr", localPTRStr, instname);
+ goto error;
+ }
+ }
+
+ def->tftproot = virXMLChildPropString(node, "tftp/root");
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK
+ if (virXMLAttrDefParseHook(node, def, instname, parent, opaque, localPTRStr) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virXMLAttrDefClear(def);
+ return -1;
+}
+
+
+[conf/xmlattr.generated.h]
+
+int
+virXMLAttrDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLAttrDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlattr.generated.h]
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_FORMAT_HOOK
+
+int
+virXMLAttrDefFormatHook(const virXMLAttrDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *familyBuf,
+ virBuffer *localPTRBuf,
+ virBuffer *tftp_rootBuf);
+
+#endif /* ENABLE_VIR_XMLATTR_DEF_FORMAT_HOOK */
+
+
+[conf/xmlattr.generated.c]
+
+int
+virXMLAttrDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLAttrDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) familyBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) localPTRBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) tftp_rootBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_XMLATTR_DEF_FORMAT_HOOK
+ if (virXMLAttrDefFormatHook(def, parent, opaque, &empty, &shortcut,
&familyBuf, &localPTRBuf, &tftp_rootBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_XMLATTR_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->family || def->localPTR > 0 || def->tftproot))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&familyBuf, buf);
+ if (!virBufferTouched(&familyBuf) && def->family)
+ virBufferEscapeString(&familyBuf, " family='%s'",
def->family);
+ virBufferAddBuffer(buf, &familyBuf);
+
+ virBufferInheritIndent(&localPTRBuf, buf);
+ if (!virBufferTouched(&localPTRBuf) && def->localPTR > 0) {
+ const char *str = virTristateBoolTypeToString(def->localPTR);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "localPtr", def->localPTR);
+ return -1;
+ }
+ virBufferAsprintf(&localPTRBuf, " localPtr='%s'", str);
+ }
+ virBufferAddBuffer(buf, &localPTRBuf);
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(def->tftproot)) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ if (virBufferUse(&tftp_rootBuf) || def->tftproot) {
+ virBufferAddLit(buf, "<tftp");
+
+ virBufferInheritIndent(&tftp_rootBuf, buf);
+ if (!virBufferTouched(&tftp_rootBuf) && def->tftproot)
+ virBufferEscapeString(&tftp_rootBuf, " root='%s'",
def->tftproot);
+ virBufferAddBuffer(buf, &tftp_rootBuf);
+
+ virBufferAddLit(buf, "/>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/xmlattr.generated.h]
+
+bool
+virXMLAttrDefCheck(const virXMLAttrDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlattr.generated.c]
+
+#ifndef RESET_VIR_XMLATTR_DEF_CHECK
+
+bool
+virXMLAttrDefCheck(const virXMLAttrDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->family || def->localPTR > 0 || def->tftproot;
+}
+
+#endif /* RESET_VIR_XMLATTR_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/xmlattr.h" */
+/* Makesure "xmlattr.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_XMLATTR_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_XMLATTR_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_XMLATTR_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "xmlattr.generated.h"
diff --git a/tests/xmlgenout/xmlelem.txt b/tests/xmlgenout/xmlelem.txt
new file mode 100644
index 00000000..d910eda2
--- /dev/null
+++ b/tests/xmlgenout/xmlelem.txt
@@ -0,0 +1,243 @@
+[conf/xmlelem.generated.h]
+
+void
+virXMLElemDefClear(virXMLElemDef *def);
+
+
+[conf/xmlelem.generated.c]
+
+void
+virXMLElemDefClear(virXMLElemDef *def)
+{
+ if (!def)
+ return;
+
+ virPortRangeClear(&def->port);
+
+ virSocketAddrRangeClear(&def->addr);
+
+ virUUIDClear(&def->uuid);
+}
+
+
+[conf/xmlelem.generated.h]
+
+int
+virXMLElemDefParseXML(xmlNodePtr node,
+ virXMLElemDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/xmlelem.generated.h]
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK
+
+int
+virXMLElemDefParseHook(xmlNodePtr node,
+ virXMLElemDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ xmlNodePtr portNode,
+ xmlNodePtr addrNode,
+ const char *uuidStr);
+
+#endif
+
+
+[conf/xmlelem.generated.h]
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virXMLElemDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/xmlelem.generated.c]
+
+int
+virXMLElemDefParseXML(xmlNodePtr node,
+ virXMLElemDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ xmlNodePtr portNode = NULL;
+ xmlNodePtr addrNode = NULL;
+ g_autofree char *uuidStr = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK_SET_ARGS
+ virXMLElemDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ portNode = virXMLChildNode(node, "port");
+ if (portNode) {
+ if (virPortRangeParseXML(portNode, &def->port, instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ }
+
+ addrNode = virXMLChildNode(node, "address");
+ if (addrNode) {
+ if (virSocketAddrRangeParseXML(addrNode, &def->addr, instname, arg_parent,
arg_opaque) < 0)
+ goto error;
+ }
+
+ uuidStr = virXMLChildNodeContent(node, "uuid");
+ if (uuidStr) {
+ if (virUUIDParseXML(uuidStr, &def->uuid, instname, arg_parent, arg_opaque)
< 0)
+ goto error;
+ }
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK
+ if (virXMLElemDefParseHook(node, def, instname, parent, opaque, portNode, addrNode,
uuidStr) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virXMLElemDefClear(def);
+ return -1;
+}
+
+
+[conf/xmlelem.generated.h]
+
+int
+virXMLElemDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLElemDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlelem.generated.h]
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_FORMAT_HOOK
+
+int
+virXMLElemDefFormatHook(const virXMLElemDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *portBuf,
+ virBuffer *addrBuf,
+ virBuffer *uuidBuf);
+
+#endif /* ENABLE_VIR_XMLELEM_DEF_FORMAT_HOOK */
+
+
+[conf/xmlelem.generated.c]
+
+int
+virXMLElemDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLElemDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) portBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) addrBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) uuidBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_XMLELEM_DEF_FORMAT_HOOK
+ if (virXMLElemDefFormatHook(def, parent, opaque, &empty, &shortcut,
&portBuf, &addrBuf, &uuidBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_XMLELEM_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(virPortRangeCheck(&def->port, def, opaque) ||
virSocketAddrRangeCheck(&def->addr, def, opaque) || virUUIDCheck(&def->uuid,
def, opaque)))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferInheritIndent(&portBuf, buf);
+ if (!virBufferTouched(&portBuf) && virPortRangeCheck(&def->port,
def, opaque)) {
+ if (virPortRangeFormatBuf(&portBuf, "port", &def->port, def,
opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &portBuf);
+
+ virBufferInheritIndent(&addrBuf, buf);
+ if (!virBufferTouched(&addrBuf) &&
virSocketAddrRangeCheck(&def->addr, def, opaque)) {
+ if (virSocketAddrRangeFormatBuf(&addrBuf, "address",
&def->addr, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &addrBuf);
+
+ virBufferInheritIndent(&uuidBuf, buf);
+ if (!virBufferTouched(&uuidBuf) && virUUIDCheck(&def->uuid, def,
opaque)) {
+ if (virUUIDFormatBuf(&uuidBuf, "<uuid>%s</uuid>\n",
&def->uuid, def, opaque) < 0)
+ return -1;
+ }
+ virBufferAddBuffer(buf, &uuidBuf);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/xmlelem.generated.h]
+
+bool
+virXMLElemDefCheck(const virXMLElemDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlelem.generated.c]
+
+#ifndef RESET_VIR_XMLELEM_DEF_CHECK
+
+bool
+virXMLElemDefCheck(const virXMLElemDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return virPortRangeCheck(&def->port, def, opaque) ||
virSocketAddrRangeCheck(&def->addr, def, opaque) || virUUIDCheck(&def->uuid,
def, opaque);
+}
+
+#endif /* RESET_VIR_XMLELEM_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/xmlelem.h" */
+/* Makesure "xmlelem.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_XMLELEM_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_XMLELEM_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_XMLELEM_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "xmlelem.generated.h"
diff --git a/tests/xmlgenout/xmlgroup.txt b/tests/xmlgenout/xmlgroup.txt
new file mode 100644
index 00000000..ff9d7e09
--- /dev/null
+++ b/tests/xmlgenout/xmlgroup.txt
@@ -0,0 +1,204 @@
+[conf/xmlgroup.generated.h]
+
+void
+virXMLGroupDefClear(virXMLGroupDef *def);
+
+
+[conf/xmlgroup.generated.c]
+
+void
+virXMLGroupDefClear(virXMLGroupDef *def)
+{
+ if (!def)
+ return;
+
+ virUtilAuthDefClear(&def->auth);
+}
+
+
+[conf/xmlgroup.generated.h]
+
+int
+virXMLGroupDefParseXML(xmlNodePtr node,
+ virXMLGroupDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/xmlgroup.generated.h]
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK
+
+int
+virXMLGroupDefParseHook(xmlNodePtr node,
+ virXMLGroupDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+#endif
+
+
+[conf/xmlgroup.generated.h]
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virXMLGroupDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/xmlgroup.generated.c]
+
+int
+virXMLGroupDefParseXML(xmlNodePtr node,
+ virXMLGroupDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK_SET_ARGS
+ virXMLGroupDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ if (virUtilAuthDefParseXML(node, &def->auth, instname, arg_parent, arg_opaque)
< 0)
+ goto error;
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK
+ if (virXMLGroupDefParseHook(node, def, instname, parent, opaque) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virXMLGroupDefClear(def);
+ return -1;
+}
+
+
+[conf/xmlgroup.generated.h]
+
+int
+virXMLGroupDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLGroupDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlgroup.generated.h]
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_FORMAT_HOOK
+
+int
+virXMLGroupDefFormatHook(const virXMLGroupDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut);
+
+#endif /* ENABLE_VIR_XMLGROUP_DEF_FORMAT_HOOK */
+
+
+[conf/xmlgroup.generated.c]
+
+int
+virXMLGroupDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLGroupDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_XMLGROUP_DEF_FORMAT_HOOK
+ if (virXMLGroupDefFormatHook(def, parent, opaque, &empty, &shortcut) < 0)
+ return -1;
+#endif /* ENABLE_VIR_XMLGROUP_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(virUtilAuthDefCheckAttr(&def->auth, def, opaque) ||
virUtilAuthDefCheckElem(&def->auth, def, opaque)))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ if (virUtilAuthDefFormatAttr(buf, &def->auth, def, opaque) < 0)
+ return -1;
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(virUtilAuthDefCheckElem(&def->auth, def, opaque))) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ if (virUtilAuthDefFormatElem(buf, &def->auth, def, opaque) < 0)
+ return -1;
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/xmlgroup.generated.h]
+
+bool
+virXMLGroupDefCheck(const virXMLGroupDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlgroup.generated.c]
+
+#ifndef RESET_VIR_XMLGROUP_DEF_CHECK
+
+bool
+virXMLGroupDefCheck(const virXMLGroupDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return virUtilAuthDefCheckAttr(&def->auth, def, opaque) ||
virUtilAuthDefCheckElem(&def->auth, def, opaque);
+}
+
+#endif /* RESET_VIR_XMLGROUP_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/xmlgroup.h" */
+/* Makesure "xmlgroup.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_XMLGROUP_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_XMLGROUP_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_XMLGROUP_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "xmlgroup.generated.h"
diff --git a/tests/xmlgenout/xmlswitch.txt b/tests/xmlgenout/xmlswitch.txt
new file mode 100644
index 00000000..772f1353
--- /dev/null
+++ b/tests/xmlgenout/xmlswitch.txt
@@ -0,0 +1,470 @@
+[conf/xmlswitch.generated.h]
+
+void
+virXMLSwitchDefClear(virXMLSwitchDef *def);
+
+
+[conf/xmlswitch.generated.c]
+
+void
+virXMLSwitchDefClear(virXMLSwitchDef *def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ virDomainGraphicsSDLDefClear(&def->data.sdl);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ virDomainGraphicsVNCDefClear(&def->data.vnc);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ virDomainGraphicsRDPDefClear(&def->data.rdp);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ virDomainGraphicsDesktopDefClear(&def->data.desktop);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ virDomainGraphicsSpiceDefClear(&def->data.spice);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ virDomainGraphicsEGLHeadlessDefClear(&def->data.egl_headless);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+ def->type = 0;
+}
+
+
+[conf/xmlswitch.generated.h]
+
+int
+virXMLSwitchDefParseXML(xmlNodePtr node,
+ virXMLSwitchDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque);
+
+
+[conf/xmlswitch.generated.h]
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK
+
+int
+virXMLSwitchDefParseHook(xmlNodePtr node,
+ virXMLSwitchDef *def,
+ const char *instname,
+ void *parent,
+ void *opaque,
+ const char *typeStr);
+
+#endif
+
+
+[conf/xmlswitch.generated.h]
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK_SET_ARGS
+
+void
+virXMLSwitchDefParseXMLSetArgs(xmlNodePtr node,
+ void *parent,
+ void **pparent,
+ void **popaque);
+
+#endif
+
+
+[conf/xmlswitch.generated.c]
+
+int
+virXMLSwitchDefParseXML(xmlNodePtr node,
+ virXMLSwitchDef *def,
+ const char *instname G_GNUC_UNUSED,
+ void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ g_autofree char *typeStr = NULL;
+ void *arg_parent G_GNUC_UNUSED = def;
+ void *arg_opaque G_GNUC_UNUSED = opaque;
+
+ if (!def)
+ goto error;
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK_SET_ARGS
+ virXMLSwitchDefParseXMLSetArgs(node, parent, &arg_parent, &arg_opaque);
+#endif
+
+ typeStr = virXMLPropString(node, "type");
+ if (typeStr) {
+ if ((def->type = virDomainGraphicsTypeFromString(typeStr)) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid '%s' setting '%s' in
'%s'"),
+ "type", typeStr, instname);
+ goto error;
+ }
+ }
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ if (virDomainGraphicsSDLDefParseXML(node, &def->data.sdl, instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if (virDomainGraphicsVNCDefParseXML(node, &def->data.vnc, instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ if (virDomainGraphicsRDPDefParseXML(node, &def->data.rdp, instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ if (virDomainGraphicsDesktopDefParseXML(node, &def->data.desktop,
instname, arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ if (virDomainGraphicsSpiceDefParseXML(node, &def->data.spice, instname,
arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ if (virDomainGraphicsEGLHeadlessDefParseXML(node, &def->data.egl_headless,
instname, arg_parent, arg_opaque) < 0)
+ goto error;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK
+ if (virXMLSwitchDefParseHook(node, def, instname, parent, opaque, typeStr) < 0)
+ goto error;
+#endif
+
+ return 0;
+
+ error:
+ virXMLSwitchDefClear(def);
+ return -1;
+}
+
+
+[conf/xmlswitch.generated.h]
+
+bool
+virXMLSwitchDefDataCheckAttr(const virXMLSwitchDef *def,
+ void *opaque);
+
+
+[conf/xmlswitch.generated.c]
+
+#ifndef RESET_VIR_XMLSWITCH_DEF_DATA_CHECK_ATTR
+
+bool
+virXMLSwitchDefDataCheckAttr(const virXMLSwitchDef *def,
+ void *opaque G_GNUC_UNUSED)
+{
+ bool ret = false;
+ if (!def)
+ return false;
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ ret = virDomainGraphicsSDLDefCheckAttr(&def->data.sdl, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ ret = virDomainGraphicsVNCDefCheckAttr(&def->data.vnc, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ ret = virDomainGraphicsRDPDefCheckAttr(&def->data.rdp, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ ret = virDomainGraphicsDesktopDefCheckAttr(&def->data.desktop, def,
opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ ret = virDomainGraphicsSpiceDefCheckAttr(&def->data.spice, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ ret = virDomainGraphicsEGLHeadlessDefCheckAttr(&def->data.egl_headless,
def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* RESET_VIR_XMLSWITCH_DEF_DATA_CHECK_ATTR */
+
+
+[conf/xmlswitch.generated.h]
+
+bool
+virXMLSwitchDefDataCheckElem(const virXMLSwitchDef *def,
+ void *opaque);
+
+
+[conf/xmlswitch.generated.c]
+
+#ifndef RESET_VIR_XMLSWITCH_DEF_DATA_CHECK_ELEM
+
+bool
+virXMLSwitchDefDataCheckElem(const virXMLSwitchDef *def,
+ void *opaque G_GNUC_UNUSED)
+{
+ bool ret = false;
+ if (!def)
+ return false;
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ ret = virDomainGraphicsSDLDefCheckElem(&def->data.sdl, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ ret = virDomainGraphicsVNCDefCheckElem(&def->data.vnc, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ ret = virDomainGraphicsRDPDefCheckElem(&def->data.rdp, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ ret = virDomainGraphicsDesktopDefCheckElem(&def->data.desktop, def,
opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ ret = virDomainGraphicsSpiceDefCheckElem(&def->data.spice, def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ ret = virDomainGraphicsEGLHeadlessDefCheckElem(&def->data.egl_headless,
def, opaque);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+ return ret;
+}
+
+#endif /* RESET_VIR_XMLSWITCH_DEF_DATA_CHECK_ELEM */
+
+
+[conf/xmlswitch.generated.h]
+
+int
+virXMLSwitchDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLSwitchDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlswitch.generated.h]
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_FORMAT_HOOK
+
+int
+virXMLSwitchDefFormatHook(const virXMLSwitchDef *def,
+ const void *parent,
+ const void *opaque,
+ virTristateBool *empty,
+ virTristateBool *shortcut,
+ virBuffer *typeBuf);
+
+#endif /* ENABLE_VIR_XMLSWITCH_DEF_FORMAT_HOOK */
+
+
+[conf/xmlswitch.generated.c]
+
+int
+virXMLSwitchDefFormatBuf(virBuffer *buf,
+ const char *name,
+ const virXMLSwitchDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ virTristateBool empty G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ virTristateBool shortcut G_GNUC_UNUSED = VIR_TRISTATE_BOOL_ABSENT;
+ g_auto(virBuffer) typeBuf = VIR_BUFFER_INITIALIZER;
+
+ if (!def || !buf)
+ return 0;
+
+#ifdef ENABLE_VIR_XMLSWITCH_DEF_FORMAT_HOOK
+ if (virXMLSwitchDefFormatHook(def, parent, opaque, &empty, &shortcut,
&typeBuf) < 0)
+ return -1;
+#endif /* ENABLE_VIR_XMLSWITCH_DEF_FORMAT_HOOK */
+
+ if (empty != VIR_TRISTATE_BOOL_NO)
+ if (empty || !(def->type >= 0 || virXMLSwitchDefDataCheckAttr(def, opaque)
|| virXMLSwitchDefDataCheckElem(def, opaque)))
+ return 0;
+
+ virBufferAsprintf(buf, "<%s", name);
+
+ virBufferInheritIndent(&typeBuf, buf);
+ if (!virBufferTouched(&typeBuf) && def->type >= 0) {
+ const char *str = virDomainGraphicsTypeToString(def->type);
+ if (!str) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown %s type %d"),
+ "type", def->type);
+ return -1;
+ }
+ virBufferAsprintf(&typeBuf, " type='%s'", str);
+ }
+ virBufferAddBuffer(buf, &typeBuf);
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ if (virDomainGraphicsSDLDefFormatAttr(buf, &def->data.sdl, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if (virDomainGraphicsVNCDefFormatAttr(buf, &def->data.vnc, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ if (virDomainGraphicsRDPDefFormatAttr(buf, &def->data.rdp, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ if (virDomainGraphicsDesktopDefFormatAttr(buf, &def->data.desktop, def,
opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ if (virDomainGraphicsSpiceDefFormatAttr(buf, &def->data.spice, def,
opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ if (virDomainGraphicsEGLHeadlessDefFormatAttr(buf,
&def->data.egl_headless, def, opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+ if (shortcut != VIR_TRISTATE_BOOL_NO) {
+ if (shortcut || !(virXMLSwitchDefDataCheckElem(def, opaque))) {
+ virBufferAddLit(buf, "/>\n");
+ return 0;
+ }
+ }
+
+ virBufferAddLit(buf, ">\n");
+
+ virBufferAdjustIndent(buf, 2);
+
+ switch (def->type) {
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ if (virDomainGraphicsSDLDefFormatElem(buf, &def->data.sdl, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if (virDomainGraphicsVNCDefFormatElem(buf, &def->data.vnc, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
+ if (virDomainGraphicsRDPDefFormatElem(buf, &def->data.rdp, def, opaque)
< 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
+ if (virDomainGraphicsDesktopDefFormatElem(buf, &def->data.desktop, def,
opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
+ if (virDomainGraphicsSpiceDefFormatElem(buf, &def->data.spice, def,
opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
+ if (virDomainGraphicsEGLHeadlessDefFormatElem(buf,
&def->data.egl_headless, def, opaque) < 0)
+ return -1;
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
+ break;
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", name);
+
+ return 0;
+}
+
+
+[conf/xmlswitch.generated.h]
+
+bool
+virXMLSwitchDefCheck(const virXMLSwitchDef *def,
+ const void *parent,
+ void *opaque);
+
+
+[conf/xmlswitch.generated.c]
+
+#ifndef RESET_VIR_XMLSWITCH_DEF_CHECK
+
+bool
+virXMLSwitchDefCheck(const virXMLSwitchDef *def,
+ const void *parent G_GNUC_UNUSED,
+ void *opaque G_GNUC_UNUSED)
+{
+ if (!def)
+ return false;
+
+ return def->type >= 0 || virXMLSwitchDefDataCheckAttr(def, opaque) ||
virXMLSwitchDefDataCheckElem(def, opaque);
+}
+
+#endif /* RESET_VIR_XMLSWITCH_DEF_CHECK */
+
+
+[Tips]
+
+/* Put these lines at the bottom of "conf/xmlswitch.h" */
+/* Makesure "xmlswitch.h" to be appended into conf_xmlgen_input in
src/conf/meson.build */
+
+/* Define macro to enable hook or redefine check when necessary */
+/* #define ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK */
+/* #define ENABLE_VIR_XMLSWITCH_DEF_PARSE_HOOK_SET_ARGS */
+/* #define ENABLE_VIR_XMLSWITCH_DEF_FORMAT_HOOK */
+
+/* #define RESET_VIR_XMLSWITCH_DEF_CHECK */
+
+/* Makesure below is the bottom line! */
+#include "xmlswitch.generated.h"
diff --git a/tests/xmlgentest.c b/tests/xmlgentest.c
new file mode 100644
index 00000000..a20773dc
--- /dev/null
+++ b/tests/xmlgentest.c
@@ -0,0 +1,107 @@
+#include <config.h>
+
+#include "internal.h"
+#include "testutils.h"
+#include "vircommand.h"
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+typedef enum {
+ TEST_COMPARE_RESULT_SUCCESS,
+ TEST_COMPARE_RESULT_FAIL_GENERATE,
+ TEST_COMPARE_RESULT_FAIL_COMPARE,
+} testCompareResult;
+
+struct testInfo {
+ const char *name;
+ const char *target;
+ testCompareResult expectResult;
+};
+
+static int
+testCompareGenFiles(const void *data)
+{
+ int ret = 0;
+ testCompareResult result = TEST_COMPARE_RESULT_SUCCESS;
+ const struct testInfo *info = data;
+ g_autofree char *outbuf = NULL;
+ g_autoptr(virCommand) cmd = NULL;
+ g_autofree char *outfile = NULL;
+ char *actual = NULL;
+
+ cmd = virCommandNewArgList(PYTHON3, "-B",
+ abs_top_srcdir "/scripts/xmlgen/main.py",
+ "-s", abs_srcdir "/xmlgenin",
+ "-b", abs_builddir "/xmlgenin",
+ "-d", "",
+ "show", info->target, NULL);
+
+ virCommandSetOutputBuffer(cmd, &outbuf);
+
+ if (virCommandRun(cmd, NULL) < 0) {
+ result = TEST_COMPARE_RESULT_FAIL_GENERATE;
+ goto cleanup;
+ }
+
+ /* Skip first empty line */
+ if (outbuf && outbuf[0] == '\n')
+ actual = outbuf + 1;
+ else
+ actual = outbuf;
+
+ outfile = g_strdup_printf("%s/xmlgenout/%s.txt", abs_srcdir,
info->name);
+ if (virTestCompareToFile(actual, outfile) < 0) {
+ result = TEST_COMPARE_RESULT_FAIL_COMPARE;
+ goto cleanup;
+ }
+
+ cleanup:
+ if (result == info->expectResult) {
+ ret = 0;
+ if (info->expectResult != TEST_COMPARE_RESULT_SUCCESS) {
+ VIR_TEST_DEBUG("Got expected failure code=%d msg=%s",
+ result, virGetLastErrorMessage());
+ }
+ } else {
+ ret = -1;
+ VIR_TEST_DEBUG("Expected result code=%d but received code=%d",
+ info->expectResult, result);
+ }
+ virResetLastError();
+
+ return ret;
+}
+
+static int
+mymain(void)
+{
+ int ret = 0;
+
+#define DO_TEST(name, target) \
+ do { \
+ const struct testInfo info = {name, target, TEST_COMPARE_RESULT_SUCCESS}; \
+ if (virTestRun("xmlgen: generate for " target " in test "
name, \
+ testCompareGenFiles, &info) < 0) \
+ ret = -1; \
+ } while (0)
+
+ DO_TEST("empty", "virEmptyDef");
+ DO_TEST("genparse", "virGenParseDef");
+ DO_TEST("genformat", "virGenFormatDef");
+ DO_TEST("genformat-separate", "virSeparateDef");
+ DO_TEST("xmlattr", "virXMLAttrDef");
+ DO_TEST("xmlelem", "virXMLElemDef");
+ DO_TEST("array", "virArrayDef");
+ DO_TEST("required", "virRequiredDef");
+ DO_TEST("specify", "virSpecifyDef");
+ DO_TEST("skipparse", "virSkipParseDef");
+ DO_TEST("xmlgroup", "virXMLGroupDef");
+ DO_TEST("xmlswitch", "virXMLSwitchDef");
+ DO_TEST("enum-first-item", "virEnumFirstItemDef");
+ DO_TEST("namespace", "virNameSpaceDef");
+ DO_TEST("external", "virExternalDef");
+
+ return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+VIR_TEST_MAIN(mymain)
--
2.25.1