diff options
author | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2008-05-18 10:01:53 +0000 |
---|---|---|
committer | martin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220> | 2008-05-18 10:01:53 +0000 |
commit | ca99b617483dd3b59fd42738e810309c4229a538 (patch) | |
tree | be7bb1cb1020f4022e41c004e2fa9d561ea3580d /navit/xmlconfig.c | |
parent | 77ebd4f9df170e6211c5ace8d43c997d385d9ec9 (diff) | |
download | navit-svn-ca99b617483dd3b59fd42738e810309c4229a538.tar.gz |
Fix:Core:Renamed src to navit for cleanup of includes
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@1059 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'navit/xmlconfig.c')
-rw-r--r-- | navit/xmlconfig.c | 1097 |
1 files changed, 1097 insertions, 0 deletions
diff --git a/navit/xmlconfig.c b/navit/xmlconfig.c new file mode 100644 index 00000000..726b43e0 --- /dev/null +++ b/navit/xmlconfig.c @@ -0,0 +1,1097 @@ +#include <glib.h> +#include <glib/gprintf.h> +#include <string.h> +#include "debug.h" +#include "file.h" +#include "coord.h" +#include "layout.h" +#include "mapset.h" +#include "projection.h" +#include "map.h" +#include "navigation.h" +#include "navit.h" +#include "plugin.h" +#include "route.h" +#include "speech.h" +#include "track.h" +#include "vehicle.h" +#include "point.h" +#include "graphics.h" +#include "gui.h" +#include "osd.h" +#include "log.h" +#include "xmlconfig.h" +#include "config.h" + +struct xistate { + struct xistate *parent; + struct xistate *child; + const gchar *element; + gchar **attribute_names; + gchar **attribute_values; +}; + +struct xmldocument { + const gchar *href; + const gchar *xpointer; + gpointer user_data; + struct xistate *first; + struct xistate *last; + int active; + int level; +}; + +struct xmlstate { + const gchar **attribute_names; + const gchar **attribute_values; + struct xmlstate *parent; + struct attr element_attr; + const gchar *element; + GError **error; + struct element_func *func; + struct xmldocument *document; +}; + + + +static struct attr ** convert_to_attrs(struct xmlstate *state) +{ + const gchar **attribute_name=state->attribute_names; + const gchar **attribute_value=state->attribute_values; + int count=0; + struct attr **ret; + + while (*attribute_name) { + count++; + attribute_name++; + } + ret=g_new(struct attr *, count+1); + attribute_name=state->attribute_names; + count=0; + while (*attribute_name) { + ret[count]=attr_new_from_text(*attribute_name,*attribute_value); + if (ret[count]) + count++; + attribute_name++; + attribute_value++; + } + ret[count]=NULL; + dbg(1,"ret=%p\n", ret); + return ret; +} + + +static const char * find_attribute(struct xmlstate *state, const char *attribute, int required) +{ + const gchar **attribute_name=state->attribute_names; + const gchar **attribute_value=state->attribute_values; + while(*attribute_name) { + if(! g_ascii_strcasecmp(attribute,*attribute_name)) + return *attribute_value; + attribute_name++; + attribute_value++; + } + if (required) + g_set_error(state->error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "element '%s' is missing attribute '%s'", state->element, attribute); + return NULL; +} + +static int +find_color(struct xmlstate *state, int required, struct color *color) +{ + const char *value; + int r,g,b,a; + + value=find_attribute(state, "color", required); + if (! value) + return 0; + if(strlen(value)==7){ + sscanf(value,"#%02x%02x%02x", &r, &g, &b); + color->r = (r << 8) | r; + color->g = (g << 8) | g; + color->b = (b << 8) | b; + color->a = (65535); + } else if(strlen(value)==9){ + sscanf(value,"#%02x%02x%02x%02x", &r, &g, &b, &a); + color->r = (r << 8) | r; + color->g = (g << 8) | g; + color->b = (b << 8) | b; + color->a = (a << 8) | a; + } else { + dbg(0,"color %i has unknown format\n",value); + } + return 1; +} + +static int +find_order(struct xmlstate *state, int required, int *min, int *max) +{ + const char *value, *pos; + int ret; + + *min=0; + *max=18; + value=find_attribute(state, "order", required); + if (! value) + return 0; + pos=strchr(value, '-'); + if (! pos) { + ret=sscanf(value,"%d",min); + *max=*min; + } else if (pos == value) + ret=sscanf(value,"-%d",max); + else + ret=sscanf(value,"%d-%d", min, max); + return ret; +} + +static int +find_boolean(struct xmlstate *state, const char *attribute, int deflt, int required) +{ + const char *value; + + value=find_attribute(state, attribute, required); + if (! value) + return deflt; + if (g_ascii_strcasecmp(value,"no") && g_ascii_strcasecmp(value,"0") && g_ascii_strcasecmp(value,"false")) + return 1; + return 0; +} + +static int +convert_number(const char *val) +{ + if (val) + return g_ascii_strtoull(val,NULL,0); + else + return 0; +} + +static int +convert_number_list(const char *val, int *table, int size) +{ + char *tok,*str,*val_str,*saveptr=NULL; + int i; + str=val_str=g_strdup(val); + for (i=0; i<size && (tok=strtok_r(str, ",", &saveptr)); i++) { + table[i]=convert_number(tok); + str=NULL; + } + g_free(val_str); + return i; +} + +static int +xmlconfig_config(struct xmlstate *state) +{ + state->element_attr.u.data = (void *)1; + return 1; +} + +static int +xmlconfig_plugin(struct xmlstate *state) +{ + const char *path; + int active,lazy; + + state->element_attr.u.data=state->parent->element_attr.u.data; + path=find_attribute(state, "path", 1); + if (! path) + return 0; + active=find_boolean(state, "active", 1, 0); + lazy=find_boolean(state, "lazy", 1, 0); + plugins_add_path(state->parent->element_attr.u.data, path, active, lazy); + return 1; +} + +static int +xmlconfig_speech(struct xmlstate *state) +{ + const char *type; + const char *data; + type=find_attribute(state, "type", 1); + if (! type) + return 0; + data=find_attribute(state, "data", 0); + state->element_attr.u.data = speech_new(type, data); + if (! state->element_attr.u.data) + return 0; + navit_set_speech(state->parent->element_attr.u.data, state->element_attr.u.data); + return 1; +} + +static int +xmlconfig_debug(struct xmlstate *state) +{ + const char *name,*level; + name=find_attribute(state, "name", 1); + if (! name) + return 0; + level=find_attribute(state, "level", 1); + if (! level) + return 0; + debug_level_set(name, convert_number(level)); + return 1; +} + +static int +xmlconfig_vehicle(struct xmlstate *state) +{ + struct attr **attrs; + attrs=convert_to_attrs(state); + + state->element_attr.u.data = vehicle_new(attrs); + if (! state->element_attr.u.data) + return 0; + navit_add_vehicle(state->parent->element_attr.u.data, state->element_attr.u.data, attrs); + return 1; +} + +static int +xmlconfig_log_vehicle(struct xmlstate *state) +{ + struct attr attr; + struct attr **attrs; + attrs=convert_to_attrs(state); + state->element_attr.u.data = log_new(attrs); + if (! state->element_attr.u.data) + return 0; + attr.type=attr_log; + attr.u.log=state->element_attr.u.data; + if (vehicle_add_attr(state->parent->element_attr.u.data, &attr)) + return 0; + return 1; +} + +static int +xmlconfig_log_navit(struct xmlstate *state) +{ + struct attr attr; + struct attr **attrs; + attrs=convert_to_attrs(state); + state->element_attr.u.data = log_new(attrs); + if (! state->element_attr.u.data) + return 0; + attr.type=attr_log; + attr.u.log=state->element_attr.u.data; + if (navit_add_attr(state->parent->element_attr.u.data, &attr)) + return 0; + return 1; +} + + +static int +xmlconfig_window_items(struct xmlstate *state) +{ + int distance=-1; + enum item_type itype; + const char *name=find_attribute(state, "name", 1); + const char *value=find_attribute(state, "distance", 0); + const char *type=find_attribute(state, "type", 1); + char *tok,*str,*type_str,*saveptr=NULL; + if (! name || !type) + return 0; + if (value) + distance=convert_number(value); + state->element_attr.u.data = navit_window_items_new(name, distance); + type_str=g_strdup(type); + str=type_str; + while ((tok=strtok_r(str, ",", &saveptr))) { + itype=item_from_name(tok); + navit_window_items_add_item(state->element_attr.u.data, itype); + str=NULL; + } + g_free(type_str); + + navit_add_window_items(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + + +static int +xmlconfig_tracking(struct xmlstate *state) +{ + state->element_attr.u.data = tracking_new(NULL); + navit_tracking_add(state->parent->element_attr.u.data, state->element_attr.u.data); + return 1; +} + +static int +xmlconfig_route(struct xmlstate *state) +{ + struct attr **attrs; + struct attr route_attr; + + attrs=convert_to_attrs(state); + state->element_attr.u.data = route_new(attrs); + if (! state->element_attr.u.data) { + dbg(0,"Failed to create route object\n"); + return 0; + } + route_attr.type=attr_route; + route_attr.u.route=state->element_attr.u.data; + return navit_add_attr(state->parent->element_attr.u.data, &route_attr); +} + +static int +xmlconfig_speed(struct xmlstate *state) +{ + const char *type; + const char *value; + int v; + enum item_type itype; + char *saveptr=NULL, *tok, *type_str, *str; + + type=find_attribute(state, "type", 1); + if (! type) + return 0; + value=find_attribute(state, "value", 1); + if (! value) + return 0; + v=convert_number(value); + type_str=g_strdup(type); + str=type_str; + while ((tok=strtok_r(str, ",", &saveptr))) { + itype=item_from_name(tok); + route_set_speed(state->parent->element_attr.u.data, itype, v); + str=NULL; + } + g_free(type_str); + + return 1; +} + + +static int +xmlconfig_navigation(struct xmlstate *state) +{ + struct attr **attrs; + struct attr navigation_attr; + + attrs=convert_to_attrs(state); + state->element_attr.u.data = navigation_new(attrs); + if (! state->element_attr.u.data) { + dbg(0,"Failed to create navigation object\n"); + return 0; + } + navigation_attr.type=attr_navigation; + navigation_attr.u.navigation=state->element_attr.u.data; + return navit_add_attr(state->parent->element_attr.u.data, &navigation_attr); +} + +static int +xmlconfig_osd(struct xmlstate *state) +{ + struct attr **attrs; + const char *type=find_attribute(state, "type", 1); + if (! type) + return 0; + attrs=convert_to_attrs(state); + state->element_attr.u.data = osd_new(state->parent->element_attr.u.data, type, attrs); + return 1; +} + +static int +xmlconfig_announce(struct xmlstate *state) +{ + const char *type,*value; + char key[32]; + int level[3]; + int i; + enum item_type itype; + char *saveptr=NULL, *tok, *type_str, *str; + + type=find_attribute(state, "type", 1); + if (! type) + return 0; + for (i = 0 ; i < 3 ; i++) { + sprintf(key,"level%d", i); + value=find_attribute(state, key, 0); + if (value) + level[i]=convert_number(value); + else + level[i]=-1; + } + type_str=g_strdup(type); + str=type_str; + while ((tok=strtok_r(str, ",", &saveptr))) { + itype=item_from_name(tok); + navigation_set_announce(state->parent->element_attr.u.data, itype, level); + str=NULL; + } + g_free(type_str); + return 1; +} + +static int +xmlconfig_mapset(struct xmlstate *state) +{ + state->element_attr.u.data = mapset_new(); + if (! state->element_attr.u.data) + return 0; + navit_add_mapset(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_map(struct xmlstate *state) +{ + struct attr **attrs; + const char *type=find_attribute(state, "type", 1); + if (! type) + return 0; + attrs=convert_to_attrs(state); + state->element_attr.u.data = map_new(type, attrs); + if (! state->element_attr.u.data) + return 0; + if (!find_boolean(state, "active", 1, 0)) + map_set_active(state->element_attr.u.data, 0); + mapset_add(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_layout(struct xmlstate *state) +{ + const char *name=find_attribute(state, "name", 1); + struct color color = {0xffff, 0xefef, 0xb7b7, 0xffff}; + + if (! name) + return 0; + find_color(state, 0, &color); + state->element_attr.u.data = layout_new(name, &color); + if (! state->element_attr.u.data) + return 0; + navit_add_layout(state->parent->element_attr.u.data, state->element_attr.u.data); + return 1; +} + +static int +xmlconfig_layer(struct xmlstate *state) +{ + const char *name=find_attribute(state, "name", 1); + if (! name) + return 0; + state->element_attr.u.data = layer_new(name, convert_number(find_attribute(state, "details", 0))); + if (! state->element_attr.u.data) + return 0; + layout_add_layer(state->parent->element_attr.u.data, state->element_attr.u.data); + return 1; +} + +static int +xmlconfig_item(struct xmlstate *state) +{ + const char *type=find_attribute(state, "type", 1); + int min, max; + enum item_type itype; + char *saveptr=NULL, *tok, *type_str, *str; + + if (! type) + return 0; + if (! find_order(state, 1, &min, &max)) + return 0; + state->element_attr.u.data=itemtype_new(min, max); + if (! state->element_attr.u.data) + return 0; + type_str=g_strdup(type); + str=type_str; + layer_add_itemtype(state->parent->element_attr.u.data, state->element_attr.u.data); + while ((tok=strtok_r(str, ",", &saveptr))) { + itype=item_from_name(tok); + itemtype_add_type(state->element_attr.u.data, itype); + str=NULL; + } + g_free(type_str); + + return 1; +} + +static int +xmlconfig_polygon(struct xmlstate *state) +{ + struct color color; + + if (! find_color(state, 1, &color)) + return 0; + state->element_attr.u.data=polygon_new(&color); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_polyline(struct xmlstate *state) +{ + struct color color; + const char *width, *dash, *directed; + int w=0, d=0, dt[4], ds=0; + + if (! find_color(state, 1, &color)) + return 0; + width=find_attribute(state, "width", 0); + if (width) + w=convert_number(width); + dash=find_attribute(state, "dash", 0); + if (dash) + ds=convert_number_list(dash, dt, sizeof(dt)/sizeof(*dt)); + directed=find_attribute(state, "directed", 0); + if (directed) + d=convert_number(directed); + + state->element_attr.u.data=polyline_new(&color, w, d, dt, ds); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_circle(struct xmlstate *state) +{ + struct color color; + const char *width, *radius, *label_size; + int w=0,r=0,ls=0; + + if (! find_color(state, 1, &color)) + return 0; + width=find_attribute(state, "width", 0); + if (width) + w=convert_number(width); + radius=find_attribute(state, "radius", 0); + if (radius) + r=convert_number(radius); + label_size=find_attribute(state, "label_size", 0); + if (label_size) + ls=convert_number(label_size); + state->element_attr.u.data=circle_new(&color, r, w, ls); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_label(struct xmlstate *state) +{ + const char *label_size; + int ls=0; + + label_size=find_attribute(state, "label_size", 0); + if (label_size) + ls=convert_number(label_size); + state->element_attr.u.data=label_new(ls); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_icon(struct xmlstate *state) +{ + const char *src=find_attribute(state, "src", 1); + + if (! src) + return 0; + state->element_attr.u.data=icon_new(src); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +static int +xmlconfig_image(struct xmlstate *state) +{ + state->element_attr.u.data=image_new(); + if (! state->element_attr.u.data) + return 0; + itemtype_add_element(state->parent->element_attr.u.data, state->element_attr.u.data); + + return 1; +} + +#define NEW(x) (void *(*)(struct attr *, struct attr **))(x) +#define ADD(x) (int (*)(void *, struct attr *attr))(x) +#define INIT(x) (int (*)(void *))(x) +#define DESTROY(x) (void (*)(void *))(x) +struct element_func { + char *name; + char *parent; + int (*func)(struct xmlstate *state); + void *(*new)(struct attr *parent, struct attr **attrs); + int (*add_attr)(void *, struct attr *attr); + int (*init)(void *); + void (*destroy)(void *); +} elements[] = { + { "config", NULL, xmlconfig_config}, + { "debug", "config", xmlconfig_debug}, + { "navit", "config", NULL, NEW(navit_new), ADD(navit_add_attr), INIT(navit_init), DESTROY(navit_destroy)}, + { "graphics", "navit", NULL, NEW(graphics_new), NULL, NULL, NULL}, + { "gui", "navit", NULL, NEW(gui_new), NULL, NULL, NULL}, + { "layout", "navit", xmlconfig_layout}, + { "layer", "layout", xmlconfig_layer}, + { "item", "layer", xmlconfig_item}, + { "circle", "item", xmlconfig_circle}, + { "icon", "item", xmlconfig_icon}, + { "image", "item", xmlconfig_image}, + { "label", "item", xmlconfig_label}, + { "polygon", "item", xmlconfig_polygon}, + { "polyline", "item", xmlconfig_polyline}, + { "mapset", "navit", xmlconfig_mapset}, + { "map", "mapset", xmlconfig_map}, + { "navigation", "navit", xmlconfig_navigation}, + { "osd", "navit", xmlconfig_osd}, + { "announce", "navigation", xmlconfig_announce}, + { "speech", "navit", xmlconfig_speech}, + { "tracking", "navit", xmlconfig_tracking}, + { "route", "navit", xmlconfig_route}, + { "speed", "route", xmlconfig_speed}, + { "vehicle", "navit", xmlconfig_vehicle}, + { "log", "vehicle", xmlconfig_log_vehicle}, + { "log", "navit", xmlconfig_log_navit}, + { "window_items", "navit", xmlconfig_window_items}, + { "plugins", "config", NULL, NEW(plugins_new), NULL, INIT(plugins_init), NULL}, + { "plugin", "plugins", xmlconfig_plugin}, + {}, +}; + +static void +start_element(GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + struct xmlstate *new=NULL, **parent = user_data; + struct element_func *e=elements,*func=NULL; + int found=0; + const char *parent_name=NULL; + char *s,*sep="",*possible_parents; + dbg(2,"name='%s' parent='%s'\n", element_name, *parent ? (*parent)->element:NULL); + possible_parents=g_strdup(""); + if (*parent) + parent_name=(*parent)->element; + while (e->name) { + if (!g_ascii_strcasecmp(element_name, e->name)) { + found=1; + s=g_strconcat(possible_parents,sep,e->parent,NULL); + g_free(possible_parents); + possible_parents=s; + sep=","; + if ((parent_name && e->parent && !g_ascii_strcasecmp(parent_name, e->parent)) || + (!parent_name && !e->parent)) + func=e; + } + e++; + } + if (! found) { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT, + "Unknown element '%s'", element_name); + g_free(possible_parents); + return; + } + if (! func) { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, + "Element '%s' within unexpected context '%s'. Expected '%s'%s", + element_name, parent_name, possible_parents, ! strcmp(possible_parents, "config") ? "\nPlease add <config> </config> tags at the beginning/end of your navit.xml": ""); + g_free(possible_parents); + return; + } + g_free(possible_parents); + + new=g_new(struct xmlstate, 1); + new->attribute_names=attribute_names; + new->attribute_values=attribute_values; + new->parent=*parent; + new->element_attr.u.data=NULL; + new->element=element_name; + new->error=error; + new->func=func; + *parent=new; + if (!find_boolean(new, "enabled", 1, 0)) + return; + if (new->parent && !new->parent->element_attr.u.data) + return; + if (func->func) { + if (!func->func(new)) { + return; + } + } else { + struct attr **attrs; + + attrs=convert_to_attrs(new); + new->element_attr.type=attr_none; + new->element_attr.u.data = func->new(&new->parent->element_attr, attrs); + if (! new->element_attr.u.data) + return; + new->element_attr.type=attr_from_name(element_name); + if (new->parent->func->add_attr) + new->parent->func->add_attr(new->parent->element_attr.u.data, &new->element_attr); + } + return; +} + + +/* Called for close tags </foo> */ +static void +end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + struct xmlstate *curr, **state = user_data; + + dbg(2,"name='%s'\n", element_name); + curr=*state; + if (curr->func->init) + curr->func->init(curr->element_attr.u.data); + *state=curr->parent; + g_free(curr); +} + +static gboolean parse_file(struct xmldocument *document, GError **error); + +static void +xinclude(GMarkupParseContext *context, const gchar **attribute_names, const gchar **attribute_values, struct xmldocument *doc_old, GError **error) +{ + struct xmldocument doc_new; + struct file_wordexp *we; + int i,count; + const char *href=NULL; + char **we_files; + + if (doc_old->level >= 16) { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include recursion too deep"); + return; + } + memset(&doc_new, 0, sizeof(doc_new)); + i=0; + while (attribute_names[i]) { + if(!g_ascii_strcasecmp("href", attribute_names[i])) { + if (!href) + href=attribute_values[i]; + else { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one href"); + return; + } + } else if(!g_ascii_strcasecmp("xpointer", attribute_names[i])) { + if (!doc_new.xpointer) + doc_new.xpointer=attribute_values[i]; + else { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one xpointer"); + return; + } + } else { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has invalid attributes"); + return; + } + i++; + } + if (!doc_new.xpointer && !href) { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has neither href nor xpointer"); + return; + } + doc_new.level=doc_old->level+1; + doc_new.user_data=doc_old->user_data; + if (! href) { + dbg(1,"no href, using '%s'\n", doc_old->href); + doc_new.href=doc_old->href; + parse_file(&doc_new, error); + } else { + dbg(1,"expanding '%s'\n", href); + we=file_wordexp_new(href); + we_files=file_wordexp_get_array(we); + count=file_wordexp_get_count(we); + dbg(1,"%d results\n", count); + for (i = 0 ; i < count ; i++) { + dbg(1,"result[%d]='%s'\n", i, we_files[i]); + doc_new.href=we_files[i]; + parse_file(&doc_new, error); + } + file_wordexp_destroy(we); + + } + +} +static int +strncmp_len(const char *s1, int s1len, const char *s2) +{ + int ret; +#if 0 + char c[s1len+1]; + strncpy(c, s1, s1len); + c[s1len]='\0'; + dbg(0,"'%s' vs '%s'\n", c, s2); +#endif + + ret=strncmp(s1, s2, s1len); + if (ret) + return ret; + return strlen(s2)-s1len; +} + +static int +xpointer_value(const char *test, int len, struct xistate *elem, const char **out, int out_len) +{ + int i,ret=0; + if (len <= 0 || out_len <= 0) { + return 0; + } + if (!(strncmp_len(test,len,"name(.)"))) { + out[0]=elem->element; + return 1; + } + if (test[0] == '@') { + i=0; + while (elem->attribute_names[i] && out_len > 0) { + if (!strncmp_len(test+1,len-1,elem->attribute_names[i])) { + out[ret++]=elem->attribute_values[i]; + out_len--; + } + i++; + } + return ret; + } + return 0; +} + +static int +xpointer_test(const char *test, int len, struct xistate *elem) +{ + int eq,i,count,vlen,cond_req=1,cond=0; + char c; + const char *tmp[16]; + + if (!len) + return 0; + c=test[len-1]; + if (c != '\'' && c != '"') + return 0; + eq=strcspn(test, "="); + if (eq >= len || test[eq+1] != c) + return 0; + vlen=eq; + if (eq > 0 && test[eq-1] == '!') { + cond_req=0; + vlen--; + } + count=xpointer_value(test,vlen,elem,tmp,16); + for (i = 0 ; i < count ; i++) { + if (!strncmp_len(test+eq+2,len-eq-3, tmp[i])) + cond=1; + } + if (cond == cond_req) + return 1; + return 0; +} + +static int +xpointer_element_match(const char *xpointer, int len, struct xistate *elem) +{ + int len_test; + len_test=strcspn(xpointer, "["); + if (len_test > len) + len_test=len; + if (strncmp_len(xpointer, len_test, elem->element) && (len_test != 1 || xpointer[0] != '*')) + return 0; + if (len_test == len) + return 1; + if (xpointer[len-1] != ']') + return 0; + return xpointer_test(xpointer+len_test+1, len-len_test-2, elem); +} + +static int +xpointer_xpointer_match(const char *xpointer, int len, struct xistate *first) +{ + const char *c; + int s; + dbg(2,"%s\n", xpointer); + if (xpointer[0] != '/') + return 0; + c=xpointer+1; + len--; + do { + s=strcspn(c, "/"); + if (s > len) + s=len; + if (! xpointer_element_match(c, s, first)) + return 0; + first=first->child; + c+=s+1; + len-=s+1; + } while (s < len && first); + if (s < len) + return 0; + return 1; +} + +static int +xpointer_match(const char *xpointer, struct xistate *first) +{ + char *prefix="xpointer("; + int len=strlen(xpointer); + if (! xpointer) + return 1; + if (strncmp(xpointer,prefix,strlen(prefix))) + return 0; + if (xpointer[len-1] != ')') + return 0; + return xpointer_xpointer_match(xpointer+strlen(prefix), len-strlen(prefix)-1, first); + +} + +static void +xi_start_element(GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + struct xmldocument *doc=user_data; + struct xistate *xistate; + int i,count=0; + while (attribute_names[count++]); + xistate=g_new0(struct xistate, 1); + xistate->element=element_name; + xistate->attribute_names=g_new(char *, count); + xistate->attribute_values=g_new(char *, count); + for (i = 0 ; i < count ; i++) { + xistate->attribute_names[i]=g_strdup(attribute_names[i]); + xistate->attribute_values[i]=g_strdup(attribute_values[i]); + } + xistate->parent=doc->last; + + if (doc->last) { + doc->last->child=xistate; + } else + doc->first=xistate; + doc->last=xistate; + if (doc->active > 0 || xpointer_match(doc->xpointer, doc->first)) { + if(!g_ascii_strcasecmp("xi:include", element_name)) { + xinclude(context, attribute_names, attribute_values, doc, error); + return; + } + start_element(context, element_name, attribute_names, attribute_values, doc->user_data, error); + doc->active++; + } + +} + +static void +xi_end_element (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + struct xmldocument *doc=user_data; + struct xistate *xistate=doc->last; + int i=0; + doc->last=doc->last->parent; + if (! doc->last) + doc->first=NULL; + else + doc->last->child=NULL; + if (doc->active > 0) { + if(!g_ascii_strcasecmp("xi:include", element_name)) { + return; + } + end_element(context, element_name, doc->user_data, error); + doc->active--; + } + while (xistate->attribute_names[i]) { + g_free(xistate->attribute_names[i]); + g_free(xistate->attribute_values[i]); + i++; + } + g_free(xistate->attribute_names); + g_free(xistate->attribute_values); + g_free(xistate); +} + +/* Called for character data */ +/* text is not nul-terminated */ +static void +xi_text (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ +} + + + +static const GMarkupParser parser = { + xi_start_element, + xi_end_element, + xi_text, + NULL, + NULL +}; + +static gboolean +parse_file(struct xmldocument *document, GError **error) +{ + GMarkupParseContext *context; + gchar *contents, *message; + gsize len; + gint line, chr; + gboolean result; + + dbg(1,"enter filename='%s'\n", document->href); + context = g_markup_parse_context_new (&parser, 0, document, NULL); + + if (!g_file_get_contents (document->href, &contents, &len, error)) { + g_markup_parse_context_free (context); + return FALSE; + } + document->active=document->xpointer ? 0:1; + document->first=NULL; + document->last=NULL; + result = g_markup_parse_context_parse (context, contents, len, error); + if (!result && error && *error) { + g_markup_parse_context_get_position(context, &line, &chr); + message=g_strdup_printf("%s at line %d, char %d\n", (*error)->message, line, chr); + g_free((*error)->message); + (*error)->message=message; + } + g_markup_parse_context_free (context); + g_free (contents); + dbg(1,"return %d\n", result); + + return result; +} + +gboolean config_load(char *filename, GError **error) +{ + struct xmldocument document; + struct xmlstate *curr=NULL; + gboolean result; + + dbg(1,"enter filename='%s'\n", filename); + memset(&document, 0, sizeof(document)); + document.href=filename; + document.user_data=&curr; + result=parse_file(&document, error); + if (result && curr) { + g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_PARSE, "element '%s' not closed", curr->element); + result=FALSE; + } + dbg(1,"return %d\n", result); + return result; +} + |