1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2008 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include "config.h"
22 #include <string.h>
23 #include <stdlib.h>
24 #include "ige-conf-private.h"
25 
26 typedef struct {
27         GString      *text;
28 
29         gchar        *current_key;
30         gchar        *current_value;
31         IgeConfType   current_type;
32 
33         GList        *defaults;
34 } DefaultData;
35 
36 #define BYTES_PER_READ 4096
37 
38 static void
parser_start_cb(GMarkupParseContext * context,const gchar * node_name,const gchar ** attribute_names,const gchar ** attribute_values,gpointer user_data,GError ** error)39 parser_start_cb (GMarkupParseContext  *context,
40                  const gchar          *node_name,
41                  const gchar         **attribute_names,
42                  const gchar         **attribute_values,
43                  gpointer              user_data,
44                  GError              **error)
45 {
46 	DefaultData *data = user_data;
47 
48         if (g_ascii_strcasecmp (node_name, "applyto") == 0) {
49                 data->text = g_string_new (NULL);
50         }
51         else if (g_ascii_strcasecmp (node_name, "type") == 0) {
52                 data->text = g_string_new (NULL);
53         }
54         else if (g_ascii_strcasecmp (node_name, "default") == 0) {
55                 data->text = g_string_new (NULL);
56         }
57 }
58 
59 static void
parser_end_cb(GMarkupParseContext * context,const gchar * node_name,gpointer user_data,GError ** error)60 parser_end_cb (GMarkupParseContext  *context,
61                const gchar          *node_name,
62                gpointer              user_data,
63                GError              **error)
64 {
65 	DefaultData *data = user_data;
66 
67         if (g_ascii_strcasecmp (node_name, "schema") == 0) {
68                 IgeConfDefaultItem *item;
69 
70                 item = g_slice_new0 (IgeConfDefaultItem);
71                 item->key = data->current_key;
72                 item->type = data->current_type;
73 
74                 switch (item->type) {
75                 case IGE_CONF_TYPE_INT:
76                 case IGE_CONF_TYPE_STRING:
77                         item->value = g_strdup (data->current_value);
78                         break;
79                 case IGE_CONF_TYPE_BOOLEAN:
80                         if (strcmp (data->current_value, "true") == 0) {
81                                 item->value = g_strdup ("YES");
82                         } else {
83                                 item->value = g_strdup ("NO");
84                         }
85                         break;
86                 }
87 
88                 data->defaults = g_list_prepend (data->defaults, item);
89 
90                 data->current_key = NULL;
91 
92                 g_free (data->current_value);
93                 data->current_value = NULL;
94         }
95         else if (g_ascii_strcasecmp (node_name, "applyto") == 0) {
96                 data->current_key = g_string_free (data->text, FALSE);
97                 data->text = NULL;
98         }
99         else if (g_ascii_strcasecmp (node_name, "type") == 0) {
100                 gchar *str;
101 
102                 str = g_string_free (data->text, FALSE);
103                 if (strcmp (str, "int") == 0) {
104                         data->current_type = IGE_CONF_TYPE_INT;
105                 }
106                 else if (strcmp (str, "bool") == 0) {
107                         data->current_type = IGE_CONF_TYPE_BOOLEAN;
108                 }
109                 else if (strcmp (str, "string") == 0) {
110                         data->current_type = IGE_CONF_TYPE_STRING;
111                 }
112 
113                 g_free (str);
114                 data->text = NULL;
115         }
116         else if (g_ascii_strcasecmp (node_name, "default") == 0) {
117                 data->current_value = g_string_free (data->text, FALSE);
118                 data->text = NULL;
119         }
120 }
121 
122 static void
parser_text_cb(GMarkupParseContext * context,const gchar * text,gsize text_len,gpointer user_data,GError ** error)123 parser_text_cb (GMarkupParseContext  *context,
124                 const gchar          *text,
125                 gsize                 text_len,
126                 gpointer              user_data,
127                 GError              **error)
128 {
129         DefaultData *data = user_data;
130 
131         if (data->text) {
132                 g_string_append_len (data->text, text, text_len);
133         }
134 }
135 
136 static void
parser_error_cb(GMarkupParseContext * context,GError * error,gpointer user_data)137 parser_error_cb (GMarkupParseContext *context,
138 		 GError              *error,
139 		 gpointer             user_data)
140 {
141 	g_warning ("Error: %s\n", error->message);
142 }
143 
144 GList *
_ige_conf_defaults_read_file(const gchar * path,GError ** error)145 _ige_conf_defaults_read_file (const gchar  *path,
146                               GError      **error)
147 {
148         DefaultData          data;
149 	GMarkupParser       *parser;
150 	GMarkupParseContext *context;
151 	GIOChannel          *io = NULL;
152 	gchar                buf[BYTES_PER_READ];
153 
154         io = g_io_channel_new_file (path, "r", error);
155         if (!io) {
156                 return NULL;
157         }
158 
159 	parser = g_new0 (GMarkupParser, 1);
160 
161 	parser->start_element = parser_start_cb;
162 	parser->end_element = parser_end_cb;
163 	parser->text = parser_text_cb;
164 	parser->error = parser_error_cb;
165 
166         memset (&data, 0, sizeof (DefaultData));
167 
168 	context = g_markup_parse_context_new (parser,
169                                               0,
170                                               &data,
171                                               NULL);
172 
173         while (TRUE) {
174                 GIOStatus io_status;
175                 gsize     bytes_read;
176 
177                 io_status = g_io_channel_read_chars (io, buf, BYTES_PER_READ,
178                                                      &bytes_read, error);
179                 if (io_status == G_IO_STATUS_ERROR) {
180                         goto exit;
181                 }
182                 if (io_status != G_IO_STATUS_NORMAL) {
183                         break;
184                 }
185 
186                 g_markup_parse_context_parse (context, buf, bytes_read, error);
187                 if (error != NULL && *error != NULL) {
188                         goto exit;
189                 }
190 
191                 if (bytes_read < BYTES_PER_READ) {
192                         break;
193                 }
194         }
195 
196  exit:
197         g_io_channel_unref (io);
198 	g_markup_parse_context_free (context);
199 	g_free (parser);
200 
201 	return data.defaults;
202 }
203 
204 void
_ige_conf_defaults_free_list(GList * defaults)205 _ige_conf_defaults_free_list (GList *defaults)
206 {
207         GList *l;
208 
209         for (l = defaults; l; l = l->next) {
210                 IgeConfDefaultItem *item = l->data;
211 
212                 g_free (item->value);
213                 g_slice_free (IgeConfDefaultItem, item);
214         }
215 
216         g_list_free (defaults);
217 }
218 
219 gchar *
_ige_conf_defaults_get_root(GList * defaults)220 _ige_conf_defaults_get_root (GList *defaults)
221 {
222         GList  *l;
223         gchar  *root;
224         gchar **strv_prev = NULL;
225         gint    i;
226         gint    last_common = G_MAXINT;
227 
228         for (l = defaults; l; l = l->next) {
229                 IgeConfDefaultItem  *item = l->data;
230                 gchar              **strv;
231 
232                 strv = g_strsplit (item->key, "/", 0);
233                 if (strv_prev == NULL) {
234                         strv_prev = strv;
235                         continue;
236                 }
237 
238                 i = 0;
239                 while (strv[i] && strv_prev[i] && i < last_common) {
240                         if (strcmp (strv[i], strv_prev[i]) != 0) {
241                                 last_common = i;
242                                 break;
243                         }
244                         i++;
245                 }
246 
247                 g_strfreev (strv_prev);
248                 strv_prev = strv;
249         }
250 
251         if (strv_prev) {
252                 GString *str;
253 
254                 str = g_string_new (NULL);
255                 i = 0;
256                 while (strv_prev[i] && i < last_common) {
257                         if (strv_prev[i][0] != '\0') {
258                                 g_string_append_c (str, '/');
259                                 g_string_append (str, strv_prev[i]);
260                         }
261                         i++;
262                 }
263                 root = g_string_free (str, FALSE);
264                 g_strfreev (strv_prev);
265         } else {
266                 root = g_strdup ("/");
267         }
268 
269         return root;
270 }
271 
272 static IgeConfDefaultItem *
defaults_get_item(GList * defaults,const gchar * key)273 defaults_get_item (GList       *defaults,
274                    const gchar *key)
275 {
276         GList  *l;
277 
278         for (l = defaults; l; l = l->next) {
279                 IgeConfDefaultItem *item = l->data;
280 
281                 if (strcmp (item->key, key) == 0) {
282                         return item;
283                 }
284         }
285 
286         return NULL;
287 }
288 
289 const gchar *
_ige_conf_defaults_get_string(GList * defaults,const gchar * key)290 _ige_conf_defaults_get_string (GList       *defaults,
291                                const gchar *key)
292 {
293         IgeConfDefaultItem *item;
294 
295         item = defaults_get_item (defaults, key);
296 
297         if (item) {
298                 return item->value;
299         }
300 
301         return NULL;
302 }
303 
304 gint
_ige_conf_defaults_get_int(GList * defaults,const gchar * key)305 _ige_conf_defaults_get_int (GList       *defaults,
306                             const gchar *key)
307 {
308         IgeConfDefaultItem *item;
309 
310         item = defaults_get_item (defaults, key);
311 
312         if (item) {
313                 return strtol (item->value, NULL, 10);
314         }
315 
316         return 0;
317 }
318 
319 gboolean
_ige_conf_defaults_get_bool(GList * defaults,const gchar * key)320 _ige_conf_defaults_get_bool (GList       *defaults,
321                              const gchar *key)
322 {
323         IgeConfDefaultItem *item;
324 
325         item = defaults_get_item (defaults, key);
326 
327         if (item) {
328                 if (strcmp (item->value, "false") == 0) {
329                         return FALSE;
330                 }
331                 else if (strcmp (item->value, "true") == 0) {
332                         return TRUE;
333                 }
334         }
335 
336         return FALSE;
337 }
338