/[zanavi_public1]/navit/navit/xmlconfig.c
ZANavi

Contents of /navit/navit/xmlconfig.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations) (download)
Fri Oct 28 21:19:04 2011 UTC (12 years, 5 months ago) by zoff99
File MIME type: text/plain
File size: 31903 byte(s)
import files
1 zoff99 2 /**
2     * Navit, a modular navigation system.
3     * Copyright (C) 2005-2009 Navit Team
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
7     * version 2 as published by the Free Software Foundation.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with this program; if not, write to the
16     * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     * Boston, MA 02110-1301, USA.
18     */
19    
20     /* see http://library.gnome.org/devel/glib/stable/glib-Simple-XML-Subset-Parser.html
21     * for details on how the xml file parser works.
22     */
23    
24     #include <stdlib.h>
25     #include <glib.h>
26     #include <glib/gprintf.h>
27     #include <string.h>
28     #include <ctype.h>
29     #include "debug.h"
30     #include "config.h"
31     #include "file.h"
32     #include "coord.h"
33     #include "layout.h"
34     #include "mapset.h"
35     #include "projection.h"
36     #include "map.h"
37     #include "navigation.h"
38     #include "navit.h"
39     #include "plugin.h"
40     #include "route.h"
41     #include "speech.h"
42     #include "track.h"
43     #include "vehicle.h"
44     #include "point.h"
45     #include "graphics.h"
46     #include "gui.h"
47     #include "osd.h"
48     #include "log.h"
49     #include "announcement.h"
50     #include "vehicleprofile.h"
51     #include "roadprofile.h"
52     #include "config_.h"
53     #include "xmlconfig.h"
54    
55     #ifdef HAVE_GLIB
56     #define ATTR_DISTANCE 1
57     const int xml_attr_distance=1;
58     #else
59     #include "ezxml.h"
60     const int xml_attr_distance=2;
61     #define ATTR_DISTANCE 2
62     #define G_MARKUP_ERROR 0
63     #define G_MARKUP_ERROR_INVALID_CONTENT 0
64     #define G_MARKUP_ERROR_PARSE 0
65     #define G_MARKUP_ERROR_UNKNOWN_ELEMENT 0
66     typedef void * GMarkupParseContext;
67     #endif
68    
69     struct xistate {
70     struct xistate *parent;
71     struct xistate *child;
72     const gchar *element;
73     const gchar **attribute_names;
74     const gchar **attribute_values;
75     };
76    
77     struct xmldocument {
78     const gchar *href;
79     const gchar *xpointer;
80     gpointer user_data;
81     struct xistate *first;
82     struct xistate *last;
83     int active;
84     int level;
85     };
86    
87    
88     struct xmlstate {
89     const gchar **attribute_names;
90     const gchar **attribute_values;
91     struct xmlstate *parent;
92     struct attr element_attr;
93     const gchar *element;
94     xmlerror **error;
95     struct element_func *func;
96     struct object_func *object_func;
97     struct xmldocument *document;
98     };
99    
100    
101     struct attr_fixme {
102     char *element;
103     char **attr_fixme;
104     };
105    
106     static struct attr ** convert_to_attrs(struct xmlstate *state, struct attr_fixme *fixme)
107     {
108     const gchar **attribute_name=state->attribute_names;
109     const gchar **attribute_value=state->attribute_values;
110     const gchar *name;
111     int count=0;
112     struct attr **ret;
113     static int fixme_count;
114    
115     while (*attribute_name) {
116     count++;
117     attribute_name++;
118     }
119     ret=g_new(struct attr *, count+1);
120     attribute_name=state->attribute_names;
121     count=0;
122     while (*attribute_name) {
123     name=*attribute_name;
124     if (fixme) {
125     char **attr_fixme=fixme->attr_fixme;
126     while (attr_fixme[0]) {
127     if (! strcmp(name, attr_fixme[0])) {
128     name=attr_fixme[1];
129     if (fixme_count++ < 10)
130     dbg(0,"Please change attribute '%s' to '%s' in <%s />\n", attr_fixme[0], attr_fixme[1], fixme->element);
131     break;
132     }
133     attr_fixme+=2;
134     }
135     }
136     ret[count]=attr_new_from_text(name,*attribute_value);
137     if (ret[count])
138     count++;
139     else if (strcmp(*attribute_name,"enabled") && strcmp(*attribute_name,"xmlns:xi"))
140     dbg(0,"failed to create attribute '%s' with value '%s'\n", *attribute_name,*attribute_value);
141     attribute_name++;
142     attribute_value++;
143     }
144     ret[count]=NULL;
145     dbg(1,"ret=%p\n", ret);
146     return ret;
147     }
148    
149    
150     static const char * find_attribute(struct xmlstate *state, const char *attribute, int required)
151     {
152     const gchar **attribute_name=state->attribute_names;
153     const gchar **attribute_value=state->attribute_values;
154     while(*attribute_name) {
155     if(! g_ascii_strcasecmp(attribute,*attribute_name))
156     return *attribute_value;
157     attribute_name++;
158     attribute_value++;
159     }
160     if (required)
161     g_set_error(state->error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "element '%s' is missing attribute '%s'", state->element, attribute);
162     return NULL;
163     }
164    
165     static int
166     find_boolean(struct xmlstate *state, const char *attribute, int deflt, int required)
167     {
168     const char *value;
169    
170     value=find_attribute(state, attribute, required);
171     if (! value)
172     return deflt;
173     if (g_ascii_strcasecmp(value,"no") && g_ascii_strcasecmp(value,"0") && g_ascii_strcasecmp(value,"false"))
174     return 1;
175     return 0;
176     }
177    
178     /**
179     * * Convert a string number to int
180     * *
181     * * @param val the string value to convert
182     * * @returns int value of converted string
183     * */
184     static int
185     convert_number(const char *val)
186     {
187     if (val)
188     return g_ascii_strtoull(val,NULL,0);
189     else
190     return 0;
191     }
192    
193     static int
194     xmlconfig_announce(struct xmlstate *state)
195     {
196     const char *type,*value;
197     char key[32];
198     int level[3];
199     int i;
200     enum item_type itype;
201     char *tok, *type_str, *str;
202    
203     type=find_attribute(state, "type", 1);
204     if (! type)
205     return 0;
206     for (i = 0 ; i < 3 ; i++) {
207     sprintf(key,"level%d", i);
208     value=find_attribute(state, key, 0);
209     if (value)
210     level[i]=convert_number(value);
211     else
212     level[i]=-1;
213     }
214     type_str=g_strdup(type);
215     str=type_str;
216     while ((tok=strtok(str, ","))) {
217     itype=item_from_name(tok);
218     navigation_set_announce(state->parent->element_attr.u.data, itype, level);
219     str=NULL;
220     }
221     g_free(type_str);
222     return 1;
223     }
224     /**
225     * * Define the elements in our config
226     * *
227     * */
228    
229     #define NEW(x) (void *(*)(struct attr *, struct attr **))(x)
230     #define GET(x) (int (*)(void *, enum attr_type type, struct attr *attr, struct attr_iter *iter))(x)
231     #define ITERN(x) (struct attr_iter * (*)(void *))(x)
232     #define ITERD(x) (void (*)(struct attr_iter *iter))(x)
233     #define SET(x) (int (*)(void *, struct attr *attr))(x)
234     #define ADD(x) (int (*)(void *, struct attr *attr))(x)
235     #define REMOVE(x) (int (*)(void *, struct attr *attr))(x)
236     #define INIT(x) (int (*)(void *))(x)
237     #define DESTROY(x) (void (*)(void *))(x)
238    
239     static struct object_func object_funcs[] = {
240     { attr_announcement,NEW(announcement_new), GET(announcement_get_attr), NULL, NULL, SET(announcement_set_attr), ADD(announcement_add_attr) },
241     { attr_arrows, NEW(arrows_new)},
242     { attr_circle, NEW(circle_new), NULL, NULL, NULL, NULL, ADD(element_add_attr)},
243     { attr_config, NEW(config_new), GET(config_get_attr), ITERN(config_attr_iter_new), ITERD(config_attr_iter_destroy), SET(config_set_attr), ADD(config_add_attr), REMOVE(config_remove_attr), NULL, DESTROY(config_destroy)},
244     { attr_coord, NEW(coord_new_from_attrs)},
245     { attr_cursor, NEW(cursor_new), NULL, NULL, NULL, NULL, ADD(cursor_add_attr)},
246     { attr_debug, NEW(debug_new)},
247     { attr_graphics, NEW(graphics_new)},
248     { attr_gui, NEW(gui_new), GET(gui_get_attr), NULL, NULL, SET(gui_set_attr), ADD(gui_add_attr)},
249     { attr_icon, NEW(icon_new), NULL, NULL, NULL, NULL, ADD(element_add_attr)},
250     { attr_image, NEW(image_new)},
251     { attr_itemgra, NEW(itemgra_new), NULL, NULL, NULL, NULL, ADD(itemgra_add_attr)},
252     { attr_layer, NEW(layer_new), NULL, NULL, NULL, NULL, ADD(layer_add_attr)},
253     { attr_layout, NEW(layout_new), NULL, NULL, NULL, NULL, ADD(layout_add_attr)},
254     { attr_log, NEW(log_new)},
255     { attr_map, NEW(map_new)},
256     { attr_mapset, NEW(mapset_new), NULL, NULL, NULL, NULL, ADD(mapset_add_attr_name)},
257     { attr_navigation, NEW(navigation_new), GET(navigation_get_attr)},
258     { attr_navit, NEW(navit_new), GET(navit_get_attr), ITERN(navit_attr_iter_new), ITERD(navit_attr_iter_destroy), SET(navit_set_attr), ADD(navit_add_attr), REMOVE(navit_remove_attr), INIT(navit_init), DESTROY(navit_destroy)},
259     { attr_osd, NEW(osd_new)},
260     { attr_plugins, NEW(plugins_new), NULL, NULL, NULL, NULL, NULL, NULL, INIT(plugins_init)},
261     { attr_plugin, NEW(plugin_new)},
262     { attr_polygon, NEW(polygon_new), NULL, NULL, NULL, NULL, ADD(element_add_attr)},
263     { attr_polyline, NEW(polyline_new), NULL, NULL, NULL, NULL, ADD(element_add_attr)},
264     { attr_roadprofile,NEW(roadprofile_new), GET(roadprofile_get_attr), NULL, NULL, SET(roadprofile_set_attr), ADD(roadprofile_add_attr) },
265     { attr_route, NEW(route_new), GET(route_get_attr), NULL, NULL, SET(route_set_attr), ADD(route_add_attr), REMOVE(route_remove_attr)},
266     { attr_speech, NEW(speech_new), GET(speech_get_attr), NULL, NULL, SET(speech_set_attr)},
267     { attr_text, NEW(text_new)},
268     { attr_tracking, NEW(tracking_new)},
269     { attr_vehicle, NEW(vehicle_new), GET(vehicle_get_attr), NULL, NULL, SET(vehicle_set_attr), ADD(vehicle_add_attr), REMOVE(vehicle_remove_attr) },
270     { attr_vehicleprofile, NEW(vehicleprofile_new), GET(vehicleprofile_get_attr), NULL, NULL, SET(vehicleprofile_set_attr), ADD(vehicleprofile_add_attr) },
271     };
272    
273     struct object_func *
274     object_func_lookup(enum attr_type type)
275     {
276     int i;
277     for (i = 0 ; i < sizeof(object_funcs)/sizeof(struct object_func); i++) {
278     if (object_funcs[i].type == type)
279     return &object_funcs[i];
280     }
281     return NULL;
282     }
283    
284     struct element_func {
285     char *name;
286     char *parent;
287     int (*func)(struct xmlstate *state);
288     enum attr_type type;
289     };
290     struct element_func *elements;
291    
292     static char *attr_fixme_itemgra[]={
293     "type","item_types",
294     NULL,NULL,
295     };
296    
297     static char *attr_fixme_text[]={
298     "label_size","text_size",
299     NULL,NULL,
300     };
301    
302     static char *attr_fixme_circle[]={
303     "label_size","text_size",
304     NULL,NULL,
305     };
306    
307     static struct attr_fixme attr_fixmes[]={
308     {"item",attr_fixme_itemgra},
309     {"itemgra",attr_fixme_itemgra},
310     {"text",attr_fixme_text},
311     {"label",attr_fixme_text},
312     {"circle",attr_fixme_circle},
313     {NULL,NULL},
314     };
315    
316    
317     static char *element_fixmes[]={
318     "item","itemgra",
319     "label","text",
320     NULL,NULL,
321     };
322    
323     static void initStatic(void) {
324     elements=g_new0(struct element_func,40); //39 is a number of elements + ending NULL element
325    
326     elements[0].name="config";
327     elements[0].parent=NULL;
328     elements[0].func=NULL;
329     elements[0].type=attr_config;
330    
331     elements[1].name="announce";
332     elements[1].parent="navigation";
333     elements[1].func=xmlconfig_announce;
334    
335     elements[2].name="speech";
336     elements[2].parent="navit";
337     elements[2].func=NULL;
338     elements[2].type=attr_speech;
339    
340     elements[3].name="tracking";
341     elements[3].parent="navit";
342     elements[3].func=NULL;
343     elements[3].type=attr_tracking;
344    
345     elements[4].name="route";
346     elements[4].parent="navit";
347     elements[4].func=NULL;
348     elements[4].type=attr_route;
349    
350     elements[5].name="mapset";
351     elements[5].parent="navit";
352     elements[5].func=NULL;
353     elements[5].type=attr_mapset;
354    
355     elements[6].name="map";
356     elements[6].parent="mapset";
357     elements[6].func=NULL;
358     elements[6].type=attr_map;
359    
360     elements[7].name="debug";
361     elements[7].parent="config";
362     elements[7].func=NULL;
363     elements[7].type=attr_debug;
364    
365     elements[8].name="osd";
366     elements[8].parent="navit";
367     elements[8].func=NULL;
368     elements[8].type=attr_osd;
369    
370     elements[9].name="navigation";
371     elements[9].parent="navit";
372     elements[9].func=NULL;
373     elements[9].type=attr_navigation;
374    
375     elements[10].name="navit";
376     elements[10].parent="config";
377     elements[10].func=NULL;
378     elements[10].type=attr_navit;
379    
380     elements[11].name="graphics";
381     elements[11].parent="navit";
382     elements[11].func=NULL;
383     elements[11].type=attr_graphics;
384    
385     elements[12].name="gui";
386     elements[12].parent="navit";
387     elements[12].func=NULL;
388     elements[12].type=attr_gui;
389    
390     elements[13].name="layout";
391     elements[13].parent="navit";
392     elements[13].func=NULL;
393     elements[13].type=attr_layout;
394    
395     elements[14].name="cursor";
396     elements[14].parent="layout";
397     elements[14].func=NULL;
398     elements[14].type=attr_cursor;
399    
400     elements[15].name="layer";
401     elements[15].parent="layout";
402     elements[15].func=NULL;
403     elements[15].type=attr_layer;
404    
405     elements[16].name="itemgra";
406     elements[16].parent="layer";
407     elements[16].func=NULL;
408     elements[16].type=attr_itemgra;
409    
410     elements[17].name="circle";
411     elements[17].parent="itemgra";
412     elements[17].func=NULL;
413     elements[17].type=attr_circle;
414    
415     elements[18].name="coord";
416     elements[18].parent="circle";
417     elements[18].func=NULL;
418     elements[18].type=attr_coord;
419    
420     elements[19].name="icon";
421     elements[19].parent="itemgra";
422     elements[19].func=NULL;
423     elements[19].type=attr_icon;
424    
425     elements[20].name="coord";
426     elements[20].parent="icon";
427     elements[20].func=NULL;
428     elements[20].type=attr_coord;
429    
430     elements[21].name="image";
431     elements[21].parent="itemgra";
432     elements[21].func=NULL;
433     elements[21].type=attr_image;
434    
435     elements[22].name="text";
436     elements[22].parent="itemgra";
437     elements[22].func=NULL;
438     elements[22].type=attr_text;
439    
440     elements[23].name="polygon";
441     elements[23].parent="itemgra";
442     elements[23].func=NULL;
443     elements[23].type=attr_polygon;
444    
445     elements[24].name="coord";
446     elements[24].parent="polygon";
447     elements[24].func=NULL;
448     elements[24].type=attr_coord;
449    
450     elements[25].name="polyline";
451     elements[25].parent="itemgra";
452     elements[25].func=NULL;
453     elements[25].type=attr_polyline;
454    
455     elements[26].name="coord";
456     elements[26].parent="polyline";
457     elements[26].func=NULL;
458     elements[26].type=attr_coord;
459    
460     elements[27].name="arrows";
461     elements[27].parent="itemgra";
462     elements[27].func=NULL;
463     elements[27].type=attr_arrows;
464    
465     elements[28].name="vehicle";
466     elements[28].parent="navit";
467     elements[28].func=NULL;
468     elements[28].type=attr_vehicle;
469    
470     elements[29].name="vehicleprofile";
471     elements[29].parent="navit";
472     elements[29].func=NULL;
473     elements[29].type=attr_vehicleprofile;
474    
475     elements[30].name="roadprofile";
476     elements[30].parent="vehicleprofile";
477     elements[30].func=NULL;
478     elements[30].type=attr_roadprofile;
479    
480     elements[31].name="announcement";
481     elements[31].parent="roadprofile";
482     elements[31].func=NULL;
483     elements[31].type=attr_announcement;
484    
485     elements[32].name="cursor";
486     elements[32].parent="vehicle";
487     elements[32].func=NULL;
488     elements[32].type=attr_cursor;
489    
490     elements[33].name="itemgra";
491     elements[33].parent="cursor";
492     elements[33].func=NULL;
493     elements[33].type=attr_itemgra;
494    
495     elements[34].name="log";
496     elements[34].parent="vehicle";
497     elements[34].func=NULL;
498     elements[34].type=attr_log;
499    
500     elements[35].name="log";
501     elements[35].parent="navit";
502     elements[35].func=NULL;
503     elements[35].type=attr_log;
504    
505     elements[36].name="plugins";
506     elements[36].parent="config";
507     elements[36].func=NULL;
508     elements[36].type=attr_plugins;
509    
510     elements[37].name="plugin";
511     elements[37].parent="plugins";
512     elements[37].func=NULL;
513     elements[37].type=attr_plugin;
514     }
515    
516     /**
517     * * Parse the opening tag of a config element
518     * *
519     * * @param context document parse context
520     * * @param element_name the current tag name
521     * * @param attribute_names ptr to return the set of attribute names
522     * * @param attribute_values ptr return the set of attribute values
523     * * @param user_data ptr to xmlstate structure
524     * * @param error ptr return error context
525     * * @returns nothing
526     * */
527    
528     static void
529     start_element(GMarkupParseContext *context,
530     const gchar *element_name,
531     const gchar **attribute_names,
532     const gchar **attribute_values,
533     gpointer user_data,
534     xmlerror **error)
535     {
536     struct xmlstate *new=NULL, **parent = user_data;
537     struct element_func *e=elements,*func=NULL;
538     struct attr_fixme *attr_fixme=attr_fixmes;
539     char **element_fixme=element_fixmes;
540     int found=0;
541     static int fixme_count;
542     const char *parent_name=NULL;
543     char *s,*sep="",*possible_parents;
544     struct attr *parent_attr;
545     dbg(2,"name='%s' parent='%s'\n", element_name, *parent ? (*parent)->element:NULL);
546    
547     if (!strcmp(element_name,"xml"))
548     return;
549     /* determine if we have to fix any attributes */
550     while (attr_fixme[0].element) {
551     if (!strcmp(element_name,attr_fixme[0].element))
552     break;
553     attr_fixme++;
554     }
555     if (!attr_fixme[0].element)
556     attr_fixme=NULL;
557    
558     /* tell user to fix deprecated element names */
559     while (element_fixme[0]) {
560     if (!strcmp(element_name,element_fixme[0])) {
561     element_name=element_fixme[1];
562     if (fixme_count++ < 10)
563     dbg(0,"Please change <%s /> to <%s /> in config file\n", element_fixme[0], element_fixme[1]);
564     }
565     element_fixme+=2;
566     }
567     /* validate that this element is valid
568     * and that the element has a valid parent */
569     possible_parents=g_strdup("");
570     if (*parent)
571     parent_name=(*parent)->element;
572     while (e->name) {
573     if (!g_ascii_strcasecmp(element_name, e->name)) {
574     found=1;
575     s=g_strconcat(possible_parents,sep,e->parent,NULL);
576     g_free(possible_parents);
577     possible_parents=s;
578     sep=",";
579     if ((parent_name && e->parent && !g_ascii_strcasecmp(parent_name, e->parent)) ||
580     (!parent_name && !e->parent))
581     func=e;
582     }
583     e++;
584     }
585     if (! found) {
586     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_UNKNOWN_ELEMENT,
587     "Unknown element '%s'", element_name);
588     g_free(possible_parents);
589     return;
590     }
591     if (! func) {
592     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT,
593     "Element '%s' within unexpected context '%s'. Expected '%s'%s",
594     element_name, parent_name, possible_parents, ! strcmp(possible_parents, "config") ? "\nPlease add <config> </config> tags at the beginning/end of your navit.xml": "");
595     g_free(possible_parents);
596     return;
597     }
598     g_free(possible_parents);
599    
600     new=g_new(struct xmlstate, 1);
601     new->attribute_names=attribute_names;
602     new->attribute_values=attribute_values;
603     new->parent=*parent;
604     new->element_attr.u.data=NULL;
605     new->element=element_name;
606     new->error=error;
607     new->func=func;
608     new->object_func=NULL;
609     *parent=new;
610     if (!find_boolean(new, "enabled", 1, 0))
611     return;
612     if (new->parent && !new->parent->element_attr.u.data)
613     return;
614     if (func->func) {
615     if (!func->func(new)) {
616     return;
617     }
618     } else {
619     struct attr **attrs;
620    
621     new->object_func=object_func_lookup(func->type);
622     if (! new->object_func)
623     return;
624     attrs=convert_to_attrs(new,attr_fixme);
625     new->element_attr.type=attr_none;
626     if (!new->parent || new->parent->element_attr.type == attr_none)
627     parent_attr=NULL;
628     else
629     parent_attr=&new->parent->element_attr;
630     new->element_attr.u.data = new->object_func->create(parent_attr, attrs);
631     if (! new->element_attr.u.data)
632     return;
633     new->element_attr.type=attr_from_name(element_name);
634     if (new->element_attr.type == attr_none)
635     dbg(0,"failed to create object of type '%s'\n", element_name);
636     if (new->parent && new->parent->object_func && new->parent->object_func->add_attr)
637     new->parent->object_func->add_attr(new->parent->element_attr.u.data, &new->element_attr);
638     }
639     return;
640     }
641    
642    
643     /* Called for close tags </foo> */
644     static void
645     end_element (GMarkupParseContext *context,
646     const gchar *element_name,
647     gpointer user_data,
648     xmlerror **error)
649     {
650     struct xmlstate *curr, **state = user_data;
651    
652     if (!strcmp(element_name,"xml"))
653     return;
654     dbg(2,"name='%s'\n", element_name);
655     curr=*state;
656     if (curr->object_func && curr->object_func->init)
657     curr->object_func->init(curr->element_attr.u.data);
658     *state=curr->parent;
659     g_free(curr);
660     }
661    
662     static gboolean parse_file(struct xmldocument *document, xmlerror **error);
663    
664     static void
665     xinclude(GMarkupParseContext *context, const gchar **attribute_names, const gchar **attribute_values, struct xmldocument *doc_old, xmlerror **error)
666     {
667     struct xmldocument doc_new;
668     struct file_wordexp *we;
669     int i,count;
670     const char *href=NULL;
671     char **we_files;
672    
673     if (doc_old->level >= 16) {
674     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include recursion too deep");
675     return;
676     }
677     memset(&doc_new, 0, sizeof(doc_new));
678     i=0;
679     while (attribute_names[i]) {
680     if(!g_ascii_strcasecmp("href", attribute_names[i])) {
681     if (!href)
682     href=attribute_values[i];
683     else {
684     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one href");
685     return;
686     }
687     } else if(!g_ascii_strcasecmp("xpointer", attribute_names[i])) {
688     if (!doc_new.xpointer)
689     doc_new.xpointer=attribute_values[i];
690     else {
691     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one xpointer");
692     return;
693     }
694     } else {
695     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has invalid attributes");
696     return;
697     }
698     i++;
699     }
700     if (!doc_new.xpointer && !href) {
701     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has neither href nor xpointer");
702     return;
703     }
704     doc_new.level=doc_old->level+1;
705     doc_new.user_data=doc_old->user_data;
706     if (! href) {
707     dbg(1,"no href, using '%s'\n", doc_old->href);
708     doc_new.href=doc_old->href;
709     if (file_exists(doc_new.href)) {
710     parse_file(&doc_new, error);
711     } else {
712     dbg(0,"Unable to include %s\n",doc_new.href);
713     }
714     } else {
715     dbg(1,"expanding '%s'\n", href);
716     we=file_wordexp_new(href);
717     we_files=file_wordexp_get_array(we);
718     count=file_wordexp_get_count(we);
719     dbg(1,"%d results\n", count);
720     if (file_exists(we_files[0])) {
721     for (i = 0 ; i < count ; i++) {
722     dbg(1,"result[%d]='%s'\n", i, we_files[i]);
723     doc_new.href=we_files[i];
724     parse_file(&doc_new, error);
725     }
726     } else {
727     dbg(0,"Unable to include %s\n",we_files[0]);
728     }
729     file_wordexp_destroy(we);
730    
731     }
732    
733     }
734    
735     static int
736     strncmp_len(const char *s1, int s1len, const char *s2)
737     {
738     int ret;
739     #if 0
740     char c[s1len+1];
741     strncpy(c, s1, s1len);
742     c[s1len]='\0';
743     dbg(0,"'%s' vs '%s'\n", c, s2);
744     #endif
745    
746     ret=strncmp(s1, s2, s1len);
747     if (ret)
748     return ret;
749     return strlen(s2)-s1len;
750     }
751    
752     static int
753     xpointer_value(const char *test, int len, struct xistate *elem, const char **out, int out_len)
754     {
755     int i,ret=0;
756     if (len <= 0 || out_len <= 0) {
757     return 0;
758     }
759     if (!(strncmp_len(test,len,"name(.)"))) {
760     out[0]=elem->element;
761     return 1;
762     }
763     if (test[0] == '@') {
764     i=0;
765     while (elem->attribute_names[i] && out_len > 0) {
766     if (!strncmp_len(test+1,len-1,elem->attribute_names[i])) {
767     out[ret++]=elem->attribute_values[i];
768     out_len--;
769     }
770     i++;
771     }
772     return ret;
773     }
774     return 0;
775     }
776    
777     static int
778     xpointer_test(const char *test, int len, struct xistate *elem)
779     {
780     int eq,i,count,vlen,cond_req=1,cond=0;
781     char c;
782     const char *tmp[16];
783     #if 0
784     char test2[len+1];
785    
786     strncpy(test2, test, len);
787     test2[len]='\0';
788     dbg(0,"%s\n", test2);
789     #endif
790     if (!len)
791     return 0;
792     c=test[len-1];
793     if (c != '\'' && c != '"')
794     return 0;
795     eq=strcspn(test, "=");
796     if (eq >= len || test[eq+1] != c)
797     return 0;
798     vlen=eq;
799     if (eq > 0 && test[eq-1] == '!') {
800     cond_req=0;
801     vlen--;
802     }
803     count=xpointer_value(test,vlen,elem,tmp,16);
804     for (i = 0 ; i < count ; i++) {
805     if (!strncmp_len(test+eq+2,len-eq-3, tmp[i]))
806     cond=1;
807     }
808     if (cond == cond_req)
809     return 1;
810     return 0;
811     }
812    
813     static int
814     xpointer_element_match(const char *xpointer, int len, struct xistate *elem)
815     {
816     int start,tlen,tlen2;
817     #if 0
818     char test2[len+1];
819    
820     strncpy(test2, xpointer, len);
821     test2[len]='\0';
822     dbg(0,"%s\n", test2);
823     #endif
824     start=strcspn(xpointer, "[");
825     if (start > len)
826     start=len;
827     if (strncmp_len(xpointer, start, elem->element) && (start != 1 || xpointer[0] != '*'))
828     return 0;
829     if (start == len)
830     return 1;
831     if (xpointer[len-1] != ']')
832     return 0;
833     tlen=len-start-2;
834     for (;;) {
835     start++;
836     tlen2=strcspn(xpointer+start,"]");
837     if (start + tlen2 > len)
838     return 1;
839     if (!xpointer_test(xpointer+start, tlen2, elem))
840     return 0;
841     start+=tlen2+1;
842     }
843     }
844    
845     static int
846     xpointer_xpointer_match(const char *xpointer, int len, struct xistate *first)
847     {
848     const char *c;
849     int s;
850     dbg(2,"%s\n", xpointer);
851     if (xpointer[0] != '/')
852     return 0;
853     c=xpointer+1;
854     len--;
855     do {
856     s=strcspn(c, "/");
857     if (s > len)
858     s=len;
859     if (! xpointer_element_match(c, s, first))
860     return 0;
861     first=first->child;
862     c+=s+1;
863     len-=s+1;
864     } while (len > 0 && first);
865     if (len > 0)
866     return 0;
867     return 1;
868     }
869    
870     static int
871     xpointer_match(const char *xpointer, struct xistate *first)
872     {
873     char *prefix="xpointer(";
874     int len;
875     if (! xpointer)
876     return 1;
877     len=strlen(xpointer);
878     if (strncmp(xpointer,prefix,strlen(prefix)))
879     return 0;
880     if (xpointer[len-1] != ')')
881     return 0;
882     return xpointer_xpointer_match(xpointer+strlen(prefix), len-strlen(prefix)-1, first);
883    
884     }
885    
886     static void
887     xi_start_element(GMarkupParseContext *context,
888     const gchar *element_name,
889     const gchar **attribute_names,
890     const gchar **attribute_values,
891     gpointer user_data,
892     xmlerror **error)
893     {
894     struct xmldocument *doc=user_data;
895     struct xistate *xistate;
896     int i,count=0;
897     while (attribute_names[count++*ATTR_DISTANCE]);
898     xistate=g_new0(struct xistate, 1);
899     xistate->element=element_name;
900     xistate->attribute_names=g_new0(const char *, count);
901     xistate->attribute_values=g_new0(const char *, count);
902     for (i = 0 ; i < count ; i++) {
903     if (attribute_names[i*ATTR_DISTANCE] && attribute_values[i*ATTR_DISTANCE]) {
904     xistate->attribute_names[i]=g_strdup(attribute_names[i*ATTR_DISTANCE]);
905     xistate->attribute_values[i]=g_strdup(attribute_values[i*ATTR_DISTANCE]);
906     }
907     }
908     xistate->parent=doc->last;
909    
910     if (doc->last) {
911     doc->last->child=xistate;
912     } else
913     doc->first=xistate;
914     doc->last=xistate;
915     if (doc->active > 0 || xpointer_match(doc->xpointer, doc->first)) {
916     if(!g_ascii_strcasecmp("xi:include", element_name)) {
917     xinclude(context, xistate->attribute_names, xistate->attribute_values, doc, error);
918     return;
919     }
920     start_element(context, element_name, xistate->attribute_names, xistate->attribute_values, doc->user_data, error);
921     doc->active++;
922     }
923    
924     }
925     /**
926     * * Reached closing tag of a config element
927     * *
928     * * @param context
929     * * @param element name
930     * * @param user_data ptr to xmldocument
931     * * @param error ptr to struct for error information
932     * * @returns nothing
933     * */
934    
935     static void
936     xi_end_element (GMarkupParseContext *context,
937     const gchar *element_name,
938     gpointer user_data,
939     xmlerror **error)
940     {
941     struct xmldocument *doc=user_data;
942     struct xistate *xistate=doc->last;
943     int i=0;
944     doc->last=doc->last->parent;
945     if (! doc->last)
946     doc->first=NULL;
947     else
948     doc->last->child=NULL;
949     if (doc->active > 0) {
950     if(!g_ascii_strcasecmp("xi:include", element_name)) {
951     return;
952     }
953     end_element(context, element_name, doc->user_data, error);
954     doc->active--;
955     }
956     while (xistate->attribute_names[i]) {
957     g_free((char *)(xistate->attribute_names[i]));
958     g_free((char *)(xistate->attribute_values[i]));
959     i++;
960     }
961     g_free(xistate->attribute_names);
962     g_free(xistate->attribute_values);
963     g_free(xistate);
964     }
965    
966     /* Called for character data */
967     /* text is not nul-terminated */
968     static void
969     xi_text (GMarkupParseContext *context,
970     const gchar *text,
971     gsize text_len,
972     gpointer user_data,
973     xmlerror **error)
974     {
975     struct xmldocument *doc=user_data;
976     int i;
977     if (doc->active) {
978     for (i = 0 ; i < text_len ; i++) {
979     if (!isspace(text[i])) {
980     struct xmldocument *doc=user_data;
981     struct xmlstate *curr, **state = doc->user_data;
982     struct attr attr;
983     char *text_dup = malloc(text_len+1);
984    
985     curr=*state;
986     strncpy(text_dup, text, text_len);
987     text_dup[text_len]='\0';
988     attr.type=attr_xml_text;
989     attr.u.str=text_dup;
990     if (curr->object_func && curr->object_func->add_attr && curr->element_attr.u.data)
991     curr->object_func->add_attr(curr->element_attr.u.data, &attr);
992     free(text_dup);
993     return;
994     }
995     }
996     }
997     }
998    
999     #ifndef HAVE_GLIB
1000     static void
1001     parse_node_text(ezxml_t node, void *data, void (*start)(void *, const char *, const char **, const char **, void *, void *),
1002     void (*end)(void *, const char *, void *, void *),
1003     void (*text)(void *, const char *, int, void *, void *))
1004     {
1005     while (node) {
1006     if (start)
1007     start(NULL, node->name, (const char **)node->attr, (const char **)(node->attr+1), data, NULL);
1008     if (text && node->txt)
1009     text(NULL, node->txt, strlen(node->txt), data, NULL);
1010     if (node->child)
1011     parse_node_text(node->child, data, start, end, text);
1012     if (end)
1013     end(NULL, node->name, data, NULL);
1014     node=node->ordered;
1015     }
1016     }
1017     #endif
1018    
1019     void
1020     xml_parse_text(const char *document, void *data, void (*start)(void *, const char *, const char **, const char **, void *, void *),
1021     void (*end)(void *, const char *, void *, void *),
1022     void (*text)(void *, const char *, int, void *, void *))
1023     {
1024     #ifdef HAVE_GLIB
1025     GMarkupParser parser = { start, end, text, NULL, NULL};
1026     GMarkupParseContext *context;
1027     gboolean result;
1028    
1029     context = g_markup_parse_context_new (&parser, 0, data, NULL);
1030     result = g_markup_parse_context_parse (context, document, strlen(document), NULL);
1031     g_markup_parse_context_free (context);
1032     #else
1033     char *str=g_strdup(document);
1034     ezxml_t root = ezxml_parse_str(str, strlen(str));
1035     if (!root)
1036     return;
1037     parse_node_text(root, data, start, end, text);
1038     ezxml_free(root);
1039     g_free(str);
1040     #endif
1041     }
1042    
1043    
1044     #ifdef HAVE_GLIB
1045    
1046     static const GMarkupParser parser = {
1047     xi_start_element,
1048     xi_end_element,
1049     xi_text,
1050     NULL,
1051     NULL
1052     };
1053     /**
1054     * * Parse the contents of the configuration file
1055     * *
1056     * * @param document struct holding info about the config file
1057     * * @param error info on any errors detected
1058     * * @returns boolean TRUE or FALSE
1059     * */
1060    
1061     static gboolean
1062     parse_file(struct xmldocument *document, xmlerror **error)
1063     {
1064     GMarkupParseContext *context;
1065     gchar *contents, *message;
1066     gsize len;
1067     gint line, chr;
1068     gboolean result;
1069     char *xmldir,*newxmldir,*xmlfile,*newxmlfile,*sep;
1070    
1071     dbg(1,"enter filename='%s'\n", document->href);
1072     #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 12
1073     #define G_MARKUP_TREAT_CDATA_AS_TEXT 0
1074     #endif
1075     context = g_markup_parse_context_new (&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, document, NULL);
1076    
1077     if (!g_file_get_contents (document->href, &contents, &len, error)) {
1078     g_markup_parse_context_free (context);
1079     return FALSE;
1080     }
1081     xmldir=getenv("XMLDIR");
1082     xmlfile=getenv("XMLFILE");
1083     newxmlfile=g_strdup(document->href);
1084     newxmldir=g_strdup(document->href);
1085     if ((sep=strrchr(newxmldir,'/')))
1086     *sep='\0';
1087     else {
1088     g_free(newxmldir);
1089     newxmldir=g_strdup(".");
1090     }
1091     setenv("XMLDIR",newxmldir,1);
1092     setenv("XMLFILE",newxmlfile,1);
1093     document->active=document->xpointer ? 0:1;
1094     document->first=NULL;
1095     document->last=NULL;
1096     result = g_markup_parse_context_parse (context, contents, len, error);
1097     if (!result && error && *error) {
1098     g_markup_parse_context_get_position(context, &line, &chr);
1099     message=g_strdup_printf("%s at line %d, char %d\n", (*error)->message, line, chr);
1100     g_free((*error)->message);
1101     (*error)->message=message;
1102     }
1103     g_markup_parse_context_free (context);
1104     g_free (contents);
1105     if (xmldir)
1106     setenv("XMLDIR",xmldir,1);
1107     else
1108     #ifndef __MINGW32__
1109     unsetenv("XMLDIR");
1110     #else
1111     putenv("XMLDIR=");
1112     #endif /* __MINGW32__ */
1113     if (xmlfile)
1114     setenv("XMLFILE",xmlfile,1);
1115     else
1116     #ifndef __MINGW32__
1117     unsetenv("XMLFILE");
1118     #else
1119     putenv("XMLFILE=");
1120     #endif /* __MINGW32__ */
1121     g_free(newxmldir);
1122     g_free(newxmlfile);
1123     dbg(1,"return %d\n", result);
1124    
1125     return result;
1126     }
1127     #else
1128     static void
1129     parse_node(struct xmldocument *document, ezxml_t node)
1130     {
1131     while (node) {
1132     xi_start_element(NULL,node->name, node->attr, node->attr+1, document, NULL);
1133     if (node->txt)
1134     xi_text(NULL,node->txt,strlen(node->txt),document,NULL);
1135     if (node->child)
1136     parse_node(document, node->child);
1137     xi_end_element (NULL,node->name,document,NULL);
1138     node=node->ordered;
1139     }
1140     }
1141    
1142     static gboolean
1143     parse_file(struct xmldocument *document, xmlerror **error)
1144     {
1145     FILE *f;
1146     ezxml_t root;
1147    
1148     f=fopen(document->href,"rb");
1149     if (!f)
1150     return FALSE;
1151     root = ezxml_parse_fp(f);
1152     fclose(f);
1153     if (!root)
1154     return FALSE;
1155     document->active=document->xpointer ? 0:1;
1156     document->first=NULL;
1157     document->last=NULL;
1158    
1159     parse_node(document, root);
1160    
1161     return TRUE;
1162     }
1163     #endif
1164    
1165     /**
1166     * * Load and parse the master config file
1167     * *
1168     * * @param filename FQFN of the file
1169     * * @param error ptr to error details, if any
1170     * * @returns boolean TRUE or FALSE (if error detected)
1171     * */
1172    
1173     gboolean config_load(const char *filename, xmlerror **error)
1174     {
1175     struct xmldocument document;
1176     struct xmlstate *curr=NULL;
1177     gboolean result;
1178    
1179     initStatic();
1180    
1181     dbg(1,"enter filename='%s'\n", filename);
1182     memset(&document, 0, sizeof(document));
1183     document.href=filename;
1184     document.user_data=&curr;
1185     result=parse_file(&document, error);
1186     if (result && curr) {
1187     g_set_error(error,G_MARKUP_ERROR,G_MARKUP_ERROR_PARSE, "element '%s' not closed", curr->element);
1188     result=FALSE;
1189     }
1190     dbg(1,"return %d\n", result);
1191     return result;
1192     }
1193    

   
Visit the ZANavi Wiki