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