1 /*
2  * libvirt-gconfig-helpers.c: libvirt configuration helpers
3  *
4  * Copyright (C) 2010, 2011 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library. If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  * Authors: Daniel P. Berrange <berrange@redhat.com>
21  *          Christophe Fergeau <cfergeau@gmail.com>
22  */
23 
24 #include <config.h>
25 
26 #include <string.h>
27 
28 #include <libxml/xmlerror.h>
29 #include <glib/gi18n-lib.h>
30 
31 #include "libvirt-gconfig/libvirt-gconfig.h"
32 #include "libvirt-gconfig/libvirt-gconfig-helpers-private.h"
33 
34 GQuark
gvir_config_object_error_quark(void)35 gvir_config_object_error_quark(void)
36 {
37     return g_quark_from_static_string("gvir-config-object");
38 }
39 
gvir_config_error_new_literal(GQuark domain,gint code,const gchar * message)40 static GError *gvir_config_error_new_literal(GQuark domain,
41                                              gint code,
42                                              const gchar *message)
43 {
44     xmlErrorPtr xerr = xmlGetLastError();
45 
46     if (!xerr)
47         return NULL;
48 
49     if (message)
50         return g_error_new(domain,
51                            code,
52                            "%s: %s",
53                            message,
54                            xerr->message);
55     else
56         return g_error_new(domain,
57                            code,
58                            "%s",
59                            xerr->message);
60 }
61 
62 
gvir_config_error_new(GQuark domain,gint code,const gchar * format,...)63 GError *gvir_config_error_new(GQuark domain,
64                               gint code,
65                               const gchar *format,
66                               ...)
67 {
68     GError *err;
69     va_list args;
70     gchar *message;
71 
72     va_start(args, format);
73     message = g_strdup_vprintf(format, args);
74     va_end(args);
75 
76     err = gvir_config_error_new_literal(domain, code, message);
77 
78     g_free(message);
79 
80     return err;
81 }
82 
83 
gvir_config_set_error(GError ** err,GQuark domain,gint code,const gchar * format,...)84 void gvir_config_set_error(GError **err,
85                            GQuark domain, gint code,
86                            const gchar *format, ...)
87 {
88     va_list args;
89     gchar *message;
90 
91     if (!err)
92         return;
93 
94     va_start(args, format);
95     message = g_strdup_vprintf(format, args);
96     va_end(args);
97 
98     *err = gvir_config_error_new_literal(domain, code, message);
99 
100     g_free(message);
101 }
102 
103 
gvir_config_set_error_literal(GError ** err,GQuark domain,gint code,const gchar * message)104 void gvir_config_set_error_literal(GError **err,
105                                    GQuark domain, gint code,
106                                    const gchar *message)
107 {
108     if (!err)
109         return;
110 
111     *err = gvir_config_error_new_literal(domain, code, message);
112 }
113 
114 
gvir_config_set_error_valist(GError ** err,GQuark domain,gint code,const gchar * format,va_list args)115 void gvir_config_set_error_valist(GError **err,
116                                   GQuark domain, gint code,
117                                   const gchar *format,
118                                   va_list args)
119 {
120     gchar *message;
121 
122     if (!err)
123         return;
124 
125     message = g_strdup_vprintf(format, args);
126 
127     *err = gvir_config_error_new_literal(domain, code, message);
128 
129     g_free(message);
130 }
131 
132 xmlNodePtr
gvir_config_xml_parse(const char * xml,const char * root_node,GError ** err)133 gvir_config_xml_parse(const char *xml, const char *root_node, GError **err)
134 {
135     xmlDocPtr doc;
136 
137     if (!xml) {
138         *err = g_error_new(GVIR_CONFIG_OBJECT_ERROR,
139                            0,
140                            "%s",
141                            _("No XML document to parse"));
142         return NULL;
143     }
144 
145     doc = xmlParseMemory(xml, strlen(xml));
146     if (!doc) {
147         gvir_config_set_error_literal(err, GVIR_CONFIG_OBJECT_ERROR,
148                                       0,
149                                       _("Unable to parse configuration"));
150         return NULL;
151     }
152     if ((!doc->children) ||
153          ((root_node != NULL) && g_strcmp0((char *)doc->children->name, root_node) != 0)) {
154         g_set_error(err,
155                     GVIR_CONFIG_OBJECT_ERROR,
156                     0,
157                     _("XML data has no '%s' node"),
158                     root_node);
159         xmlFreeDoc(doc);
160         return NULL;
161     }
162 
163     return doc->children;
164 }
165 
gvir_config_xml_foreach_child(xmlNodePtr node,GVirConfigXmlNodeIterator iter_func,gpointer opaque)166 void gvir_config_xml_foreach_child(xmlNodePtr node,
167                                    GVirConfigXmlNodeIterator iter_func,
168                                    gpointer opaque)
169 {
170     xmlNodePtr it;
171 
172     g_return_if_fail(iter_func != NULL);
173 
174     it = node->children;
175     while (it != NULL) {
176         gboolean cont;
177         xmlNodePtr next = it->next;
178 
179         if (!xmlIsBlankNode(it)) {
180             cont = iter_func(it, opaque);
181             if (!cont)
182                 break;
183         }
184 
185         it = next;
186     }
187 }
188 
189 /*
190  * gvir_config_xml_get_element is
191  *
192  * Copyright (C) 2006, 2007 OpenedHand Ltd.
193  *
194  * Author: Jorn Baayen <jorn@openedhand.com>
195  */
196 xmlNode *
gvir_config_xml_get_element(xmlNode * node,...)197 gvir_config_xml_get_element (xmlNode *node, ...)
198 {
199         va_list var_args;
200 
201         va_start (var_args, node);
202 
203         while (TRUE) {
204                 const char *arg;
205 
206                 arg = va_arg (var_args, const char *);
207                 if (!arg)
208                         break;
209 
210                 for (node = node->children; node; node = node->next)
211                         if (!g_strcmp0 (arg, (char *) node->name))
212                                 break;
213 
214                 if (!node)
215                         break;
216         }
217 
218         va_end (var_args);
219 
220         return node;
221 }
222 
223 G_GNUC_INTERNAL const char *
gvir_config_xml_get_child_element_content(xmlNode * node,const char * child_name)224 gvir_config_xml_get_child_element_content (xmlNode *node,
225                                            const char *child_name)
226 {
227     xmlNode *child_node;
228 
229     child_node = gvir_config_xml_get_element(node, child_name, NULL);
230     if (!child_node || !(child_node->children))
231         return NULL;
232 
233     return (const char *)child_node->children->content;
234 }
235 
236 G_GNUC_INTERNAL const char *
gvir_config_xml_get_attribute_content(xmlNodePtr node,const char * attr_name)237 gvir_config_xml_get_attribute_content(xmlNodePtr node, const char *attr_name)
238 {
239     xmlAttr *attr;
240 
241     for (attr = node->properties; attr; attr = attr->next)
242         if (g_strcmp0 (attr_name, (char *)attr->name) == 0)
243             return (const char *)attr->children->content;
244 
245     return NULL;
246 }
247 
gvir_config_genum_get_nick(GType enum_type,gint value)248 const char *gvir_config_genum_get_nick (GType enum_type, gint value)
249 {
250     GEnumClass *enum_class;
251     GEnumValue *enum_value;
252 
253     g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
254 
255     enum_class = g_type_class_ref(enum_type);
256     enum_value = g_enum_get_value(enum_class, value);
257     g_type_class_unref(enum_class);
258 
259     if (enum_value != NULL)
260         return enum_value->value_nick;
261 
262     g_return_val_if_reached(NULL);
263 }
264 
265 G_GNUC_INTERNAL int
gvir_config_genum_get_value(GType enum_type,const char * nick,gint default_value)266 gvir_config_genum_get_value (GType enum_type, const char *nick,
267                              gint default_value)
268 {
269     GEnumClass *enum_class;
270     GEnumValue *enum_value;
271 
272     g_return_val_if_fail(G_TYPE_IS_ENUM(enum_type), default_value);
273     g_return_val_if_fail(nick != NULL, default_value);
274 
275     enum_class = g_type_class_ref(enum_type);
276     enum_value = g_enum_get_value_by_nick(enum_class, nick);
277     g_type_class_unref(enum_class);
278 
279     if (enum_value != NULL)
280         return enum_value->value;
281 
282     g_return_val_if_reached(default_value);
283 }
284 
285 G_GNUC_INTERNAL char *
gvir_config_xml_node_to_string(xmlNodePtr node)286 gvir_config_xml_node_to_string(xmlNodePtr node)
287 {
288     xmlBufferPtr xmlbuf;
289     char *xml;
290 
291     if (node == NULL)
292         return NULL;
293 
294     xmlbuf = xmlBufferCreate();
295     if (xmlNodeDump(xmlbuf, node->doc, node, 0, 1) < 0)
296         xml = NULL;
297     else
298         xml = g_strndup((gchar *)xmlBufferContent(xmlbuf), xmlBufferLength(xmlbuf));
299 
300     xmlBufferFree(xmlbuf);
301 
302     return xml;
303 }
304