2 #include <glib/gprintf.h>
10 #include "projection.h"
16 const gchar **attribute_names;
17 const gchar **attribute_values;
18 struct xmlstate *parent;
22 struct element_func *func;
26 static const char * find_attribute(struct xmlstate *state, const char *attribute, int required)
28 const gchar **attribute_name=state->attribute_names;
29 const gchar **attribute_value=state->attribute_values;
30 while(*attribute_name) {
31 if(! g_ascii_strcasecmp(attribute,*attribute_name))
32 return *attribute_value;
37 g_set_error(state->error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "element '%s' is missing attribute '%s'", state->element, attribute);
42 find_color(struct xmlstate *state, int required, struct color *color)
47 value=find_attribute(state, "color", required);
51 sscanf(value,"#%02x%02x%02x", &r, &g, &b);
52 color->r = (r << 8) | r;
53 color->g = (g << 8) | g;
54 color->b = (b << 8) | b;
59 find_zoom(struct xmlstate *state, int required, int *min, int *max)
61 const char *value, *pos;
66 value=find_attribute(state, "zoom", required);
69 pos=index(value, '-');
71 ret=sscanf(value,"%d",min);
73 } else if (pos == value)
74 ret=sscanf(value,"-%d",max);
76 ret=sscanf(value,"%d-%d", min, max);
81 find_boolean(struct xmlstate *state, const char *attribute, int deflt, int required)
85 value=find_attribute(state, attribute, required);
88 if (g_ascii_strcasecmp(value,"no") && g_ascii_strcasecmp(value,"0") && g_ascii_strcasecmp(value,"false"))
94 convert_number(const char *val)
96 return g_ascii_strtoull(val,NULL,0);
100 xmlconfig_plugins(struct xmlstate *state)
102 state->element_object = plugins_new();
103 if (! state->element_object)
109 xmlconfig_plugin(struct xmlstate *state)
114 state->element_object=state->parent->element_object;
115 path=find_attribute(state, "path", 1);
118 active=find_boolean(state, "active", 1, 0);
119 lazy=find_boolean(state, "lazy", 1, 0);
120 plugins_add_path(state->parent->element_object, path, active, lazy);
125 xmlconfig_navit(struct xmlstate *state)
127 const char *value,*gui,*graphics;
130 enum projection pro=projection_mg;
132 value=find_attribute(state, "zoom", 0);
134 zoom=convert_number(value);
137 value=find_attribute(state, "center", 0);
138 if (! value || ! coord_parse(value, pro, &c)) {
142 gui=find_attribute(state, "gui", 0);
145 graphics=find_attribute(state, "graphics", 0);
147 graphics="gtk_drawing_area";
148 state->element_object = navit_new(gui, graphics, &c, pro, zoom);
149 if (! state->element_object)
155 xmlconfig_vehicle(struct xmlstate *state)
157 const char *s=find_attribute(state, "source", 1);
160 int update=1, follow=0;
164 if (! find_color(state, 1, &color))
166 state->element_object = vehicle_new(s);
167 if (! state->element_object)
169 if ((value=find_attribute(state, "update", 0)))
170 update=convert_number(value);
171 if ((value=find_attribute(state, "follow", 0)))
172 follow=convert_number(value);
174 navit_vehicle_add(state->parent->element_object, state->element_object, &color, update, follow);
179 xmlconfig_mapset(struct xmlstate *state)
181 state->element_object = mapset_new();
182 if (! state->element_object)
184 navit_add_mapset(state->parent->element_object, state->element_object);
190 xmlconfig_map(struct xmlstate *state)
192 const char *type=find_attribute(state, "type", 1);
193 const char *data=find_attribute(state, "data", 1);
194 if (! type || ! data)
196 state->element_object = map_new(type, data);
197 if (! state->element_object)
199 if (!find_boolean(state, "active", 1, 0))
200 map_set_active(state->element_object, 0);
201 mapset_add(state->parent->element_object, state->element_object);
207 xmlconfig_layout(struct xmlstate *state)
209 const char *name=find_attribute(state, "name", 1);
213 state->element_object = layout_new(name);
214 if (! state->element_object)
216 navit_add_layout(state->parent->element_object, state->element_object);
221 xmlconfig_layer(struct xmlstate *state)
223 const char *name=find_attribute(state, "name", 1);
226 state->element_object = layer_new(name, convert_number(find_attribute(state, "details", 0)));
227 if (! state->element_object)
229 layout_add_layer(state->parent->element_object, state->element_object);
234 xmlconfig_item(struct xmlstate *state)
236 const char *type=find_attribute(state, "type", 1);
238 enum item_type itype;
239 char *saveptr, *tok, *type_str, *str;
243 if (! find_zoom(state, 1, &min, &max))
245 state->element_object=itemtype_new(min, max);
246 if (! state->element_object)
248 type_str=g_strdup(type);
250 layer_add_itemtype(state->parent->element_object, state->element_object);
251 while ((tok=strtok_r(str, ",", &saveptr))) {
252 itype=item_from_name(tok);
253 itemtype_add_type(state->element_object, itype);
262 xmlconfig_polygon(struct xmlstate *state)
266 if (! find_color(state, 1, &color))
268 state->element_object=polygon_new(&color);
269 if (! state->element_object)
271 itemtype_add_element(state->parent->element_object, state->element_object);
277 xmlconfig_polyline(struct xmlstate *state)
283 if (! find_color(state, 1, &color))
285 width=find_attribute(state, "width", 0);
287 w=convert_number(width);
288 state->element_object=polyline_new(&color, w);
289 if (! state->element_object)
291 itemtype_add_element(state->parent->element_object, state->element_object);
297 xmlconfig_circle(struct xmlstate *state)
300 const char *width, *radius, *label_size;
303 if (! find_color(state, 1, &color))
305 width=find_attribute(state, "width", 0);
307 w=convert_number(width);
308 radius=find_attribute(state, "radius", 0);
310 r=convert_number(radius);
311 label_size=find_attribute(state, "label_size", 0);
313 ls=convert_number(label_size);
314 state->element_object=circle_new(&color, r, w, ls);
315 if (! state->element_object)
317 itemtype_add_element(state->parent->element_object, state->element_object);
323 xmlconfig_label(struct xmlstate *state)
325 const char *label_size;
328 label_size=find_attribute(state, "label_size", 0);
330 ls=convert_number(label_size);
331 state->element_object=label_new(ls);
332 if (! state->element_object)
334 itemtype_add_element(state->parent->element_object, state->element_object);
340 xmlconfig_icon(struct xmlstate *state)
342 const char *src=find_attribute(state, "src", 1);
346 state->element_object=icon_new(src);
347 if (! state->element_object)
349 itemtype_add_element(state->parent->element_object, state->element_object);
355 xmlconfig_image(struct xmlstate *state)
357 state->element_object=image_new();
358 if (! state->element_object)
360 itemtype_add_element(state->parent->element_object, state->element_object);
365 struct element_func {
368 int (*func)(struct xmlstate *state);
370 { "plugins", NULL, xmlconfig_plugins},
371 { "plugin", "plugins", xmlconfig_plugin},
372 { "navit", NULL, xmlconfig_navit},
373 { "vehicle", "navit", xmlconfig_vehicle},
374 { "mapset", "navit", xmlconfig_mapset},
375 { "map", "mapset", xmlconfig_map},
376 { "layout", "navit", xmlconfig_layout},
377 { "layer", "layout", xmlconfig_layer},
378 { "item", "layer", xmlconfig_item},
379 { "polygon", "item", xmlconfig_polygon},
380 { "polyline", "item", xmlconfig_polyline},
381 { "circle", "item", xmlconfig_circle},
382 { "label", "item", xmlconfig_label},
383 { "icon", "item", xmlconfig_icon},
384 { "image", "item", xmlconfig_image},
389 start_element (GMarkupParseContext *context,
390 const gchar *element_name,
391 const gchar **attribute_names,
392 const gchar **attribute_values,
396 struct xmlstate *new=NULL, **parent = user_data;
397 struct element_func *e=elements,*func=NULL;
398 const char *parent_name=NULL;
400 if (!g_ascii_strcasecmp(element_name, e->name)) {
406 g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
407 "Unknown element '%s'", element_name);
411 parent_name=(*parent)->element;
412 if ((parent_name && func->parent && g_ascii_strcasecmp(parent_name, func->parent)) ||
413 (!parent_name && func->parent) || (parent_name && !func->parent)) {
414 g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
415 "Element '%s' within unexpected context '%s'. Expected '%s'",
416 element_name, parent_name, func->parent);
420 new=g_new(struct xmlstate, 1);
421 new->attribute_names=attribute_names;
422 new->attribute_values=attribute_values;
424 new->element_object=NULL;
425 new->element=element_name;
429 if (!find_boolean(new, "enabled", 1, 0))
431 if (new->parent && !new->parent->element_object)
433 if (!func->func(new)) {
438 struct elem_data *data = user_data;
442 parent_object=data->elem_stack ? data->elem_stack->data : NULL;
443 parent_token=data->token_stack ? data->token_stack->data : NULL;
445 /* g_printf("start_element: %s AN: %s AV: %s\n",element_name,*attribute_names,*attribute_values); */
448 printf("Unknown element '%s'\n", element_name);
450 data->elem_stack = g_list_prepend(data->elem_stack, elem);
451 data->token_stack = g_list_prepend(data->token_stack, (gpointer)element_name);
457 /* Called for close tags </foo> */
459 end_element (GMarkupParseContext *context,
460 const gchar *element_name,
464 struct xmlstate *curr, **state = user_data;
467 if(!g_ascii_strcasecmp("plugins", element_name) && curr->element_object)
468 plugins_init(curr->element_object);
469 if(!g_ascii_strcasecmp("navit", element_name) && curr->element_object)
470 navit_init(curr->element_object);
476 /* Called for character data */
477 /* text is not nul-terminated */
479 text (GMarkupParseContext *context,
485 struct xmlstate **state = user_data;
492 static const GMarkupParser parser = {
501 gboolean config_load(char *filename, GError **error)
503 GMarkupParseContext *context;
511 struct xmlstate *curr=NULL;
513 context = g_markup_parse_context_new (&parser, 0, &curr, NULL);
515 if (!g_file_get_contents (filename, &contents, &len, error))
518 result = g_markup_parse_context_parse (context, contents, len, error);
519 if (result && curr) {
520 g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_PARSE, "element '%s' not closed", curr->element);
523 if (!result && error && *error) {
524 g_markup_parse_context_get_position(context, &line, &chr);
525 message=g_strdup_printf("%s at line %d, char %d\n", (*error)->message, line, chr);
526 g_free((*error)->message);
527 (*error)->message=message;
529 g_markup_parse_context_free (context);