source: trunk/ruleset.c @ 38

Last change on this file since 38 was 38, checked in by marius, 6 years ago

free to g_free in new added free

  • Property svn:eol-style set to native
  • Property svn:keywords set to "Date Author Id Revision HeadURL"
  • Property svn:mime-type set to text/plain
File size: 10.8 KB
Line 
1/*
2 * Memphis - Cairo Rederer for OSM in C
3 * Copyright (C) 2008  <marius.rieder@durchmesser.ch>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (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
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19#include <glib.h>
20#include <glib/gstdio.h>
21#include <time.h>
22#include <expat.h>
23#include <stdio.h>
24#include <string.h>
25
26#include "main.h"
27#include "list.h"
28#include "ruleset.h"
29
30#define BUFFSIZE 1024
31#define MAXDEPTH 20
32#define MAXSTACK 20
33
34// External Vars
35extern memphisOpt   *opts;
36extern GTree        *keyStrings;
37extern GTree        *valStrings;
38extern GTree        *patternStrings;
39
40// Pointers to work with
41cfgRule     *currentRule;
42cfgRule     *ruleStack[MAXSTACK];
43char        **stringStack;
44
45/**
46 * cfgStartElement:
47 * @userdata:   cfgRules struct to work with
48 * @name:       The element name
49 * @atts:       The element attributes
50 *
51 * Called when the start of an element has been detected.
52 */
53static void XMLCALL
54cfgStartElement(void *userData, const char *name, const char **atts) {
55    cfgRules *ruleset = (cfgRules *)userData;
56    if (opts->debug > 1)
57        fprintf(stdout,"cfgStartElement\n");
58
59    // Parsing Rules
60    if (strcmp((char *) name, "rules") == 0) {
61        // Init Ruleset
62        ruleset->rule = NULL;
63
64        while (*atts != NULL) {
65            if(strcmp((char *) *(atts), "background") == 0) {
66                sscanf((char *) *(atts+1),"#%2x%2x%2x",
67                                    (unsigned int *)&ruleset->background[0],
68                                    (unsigned int *)&ruleset->background[1],
69                                    (unsigned int *)&ruleset->background[2]);
70            }
71            atts+=2;
72        }
73    }
74    // Parsing Rule
75    else if (strcmp(name, "rule") == 0) {
76        ruleset->cntRule++;
77        ruleset->depth++;
78
79        // Create Rule
80        cfgRule *new;
81        new = g_new(cfgRule, 1);
82        new->next = NULL;
83        new->type = 0;
84        new->parent = NULL;
85        new->nparent = NULL;
86        new->draw = NULL;
87        new->ndraw = NULL;
88
89        int c;
90
91        // Populate Rule
92        while (*atts != NULL) {
93            if(strcmp((char *) *(atts), "e") == 0) {
94                if(strstr((char *) *(atts +1),"way") != NULL)
95                    new->type |= WAY;
96                if(strstr((char *) *(atts +1),"node") != NULL)
97                    new->type |= NODE;
98            } else if(strcmp((char *) *(atts), "k") == 0) {
99                new->key = g_strsplit((char *) *(atts +1), "|", 0);
100                for(c=0;c<g_strv_length(new->key);c++) {
101                    char *tmp;
102                    tmp = *(new->key+c);
103                    *(new->key+c) = g_tree_lookup(keyStrings, tmp);
104                    if(*(new->key+c) == NULL) {
105                        g_tree_insert(keyStrings, tmp, tmp);
106                        *(new->key+c) = tmp;
107                    } else  {
108                      g_free(tmp);
109                    }
110                }
111            } else if(strcmp((char *) *(atts), "v") == 0) {
112                new->value = g_strsplit((char *) *(atts +1), "|", 0);
113                for(c=0;c<g_strv_length(new->value);c++) {
114                    char *tmp;
115                    tmp = *(new->value+c);
116                    *(new->value+c) = g_tree_lookup(valStrings, tmp);
117                    if(*(new->value+c) == NULL) {
118                        g_tree_insert(valStrings, tmp, tmp);
119                        *(new->value+c) = tmp;
120                    } else  {
121                      g_free(tmp);
122                    }
123                }
124            }
125            atts+=2;
126        }
127
128        // Insert Rule to chain
129        if(ruleset->rule == NULL)
130            ruleset->rule = new;
131        else
132            currentRule->next = new;
133        currentRule = new;
134
135        // Adding to stack
136        ruleStack[ruleset->depth] = currentRule;
137
138    }
139    // Parsing Else
140    else if (strcmp(name, "else") == 0) {
141        ruleset->cntElse++;
142        ruleset->depth++;
143    }
144    // Parsing Polygone, etc.
145    else if (
146        strcmp(name, "polygone") == 0 ||
147        strcmp(name, "line") == 0 ||
148        strcmp(name, "text") == 0
149    ) {
150        // Create Draw
151        cfgDraw *new;
152        new = g_new(cfgDraw, 1);
153        new->pattern = NULL;
154        new->minlayer = 0;
155        new->maxlayer = 99;
156
157        // Populate Draw
158        if (strcmp(name, "polygone") == 0)
159            new->type = POLYGONE;
160        else if (strcmp(name, "line") == 0)
161            new->type = LINE;
162        else if (strcmp(name, "text") == 0)
163            new->type = TEXT;
164
165        while (*atts != NULL) {
166            if(strcmp((char *) *(atts), "color") == 0) {
167                sscanf((char *) *(atts+1),"#%2x%2x%2x",
168                                            (unsigned int *)&new->color[0],
169                                            (unsigned int *)&new->color[1],
170                                            (unsigned int *)&new->color[2]);
171            } else if(strcmp((char *) *(atts), "width") == 0) {
172                sscanf((char *) *(atts+1),"%f",&new->width);
173            } else if(strcmp((char *) *(atts), "pattern") == 0) {
174                new->pattern = g_tree_lookup(patternStrings, (char *) *(atts+1));
175                if(new->pattern == NULL) {
176                    new->pattern = g_strdup((char *) *(atts+1));
177                    g_tree_insert(patternStrings, (char *) *(atts+1), new->pattern);
178                }
179            } else if(strcmp((char *) *(atts), "layer") == 0) {
180                sscanf((char *) *(atts+1),"%hi:%hi",
181                                            &new->minlayer,
182                                            &new->maxlayer);
183            }
184            atts+=2;
185        }
186
187        // Insert Draw
188        if(currentRule->parent == 0)
189            LL_APPEND(new,ruleStack[ruleset->depth]->draw);
190        else
191            LL_APPEND(new,ruleStack[ruleset->depth]->ndraw);
192    }
193}
194
195/**
196 * cfgEndElement:
197 * @userdata:   cfgRules struct to work with
198 * @name:       The element name
199 *
200 * Called when the end of an element has been detected.
201 */
202static void XMLCALL
203cfgEndElement(void *userData, const char *name) {
204    cfgRules *ruleset = (cfgRules *)userData;
205    if (opts->debug > 1)
206        fprintf(stdout,"cfgEndElement\n");
207
208    if (strcmp(name, "rule") == 0) {
209        // Fetching Parrent from stack
210        if(ruleset->depth > 0) {
211            if (ruleStack[ruleset->depth-1]->parent == NULL) {
212                ruleStack[ruleset->depth]->parent = ruleStack[ruleset->depth-1];
213            } else {   // If parent allready closed we are else.
214                ruleStack[ruleset->depth]->nparent = ruleStack[ruleset->depth-1];
215            }
216        }
217
218        ruleset->depth--;
219    } else if (strcmp(name, "else") == 0) {
220        ruleset->depth--;
221    }
222}
223
224/**
225 * rulesetRead:
226 * @filename:   Filename of the rule file
227 *
228 * Called to parse rules in the rulefile. Returns a cfgRules struct.
229 */
230cfgRules* rulesetRead(char *filename) {
231    if (opts->debug > 1)
232        fprintf(stdout,"rulesetRead\n");
233
234    // Local Vars
235    GTimer *tRulesetRead = g_timer_new();
236    unsigned int size;
237    unsigned int read = 0;
238    struct stat filestat;
239    int         len;
240    int         done;
241    char        *buf;
242    cfgRules    *ruleset = NULL;
243
244    // NULL rule stack
245    for (len=0;len<MAXDEPTH;len++) {
246        ruleStack[len] = NULL;
247    }
248   
249    // Test file
250    if (!g_file_test (filename, G_FILE_TEST_IS_REGULAR)) {
251        fprintf(stderr,"Error: \"%s\" is not a file.\n",filename);
252        return NULL;
253    }
254   
255    g_stat(filename, &filestat);
256    size = (int) filestat.st_size;
257
258    // Open file
259    FILE *fd = fopen(filename,"r");
260    if(fd == NULL) {
261        fprintf(stderr,"Error: Can't open file \"%s\"\n",filename);
262        return NULL;
263    }
264
265    ruleset = g_new(cfgRules, 1);
266    ruleset->depth = -1;
267    ruleset->cntRule = 0;
268    ruleset->cntElse = 0;
269
270    if (opts->debug > 0) {
271        fprintf(stdout," Ruleset parsing   0%%");
272        fflush(stdout);
273    }
274
275    // Create XML Parser
276    XML_Parser parser = XML_ParserCreate(NULL);
277    XML_SetElementHandler(parser, cfgStartElement, cfgEndElement);
278
279    XML_SetUserData(parser, ruleset);
280
281    // Create Buffer
282    buf = g_malloc(BUFFSIZE*sizeof(char));
283
284    // Looping over XML
285    while(!feof(fd)) {
286         len = (int)fread(buf, 1, BUFFSIZE, fd);
287         if (ferror(fd)) {
288            fprintf(stderr, "Read error\n");
289            return NULL;;
290        }
291        read += len;
292        if (opts->debug > 0) {
293            fprintf(stdout,"\r Ruleset parsing % 3i%%", (int)((read*100)/size));
294            fflush(stdout);
295        }
296        done = len < sizeof(buf);
297        if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
298            fprintf(stderr, "Parse error at line %iu:\n%s\n",
299                (int) XML_GetCurrentLineNumber(parser),
300                XML_ErrorString(XML_GetErrorCode(parser)));
301            exit(-1);
302        }
303    }
304
305    // Cleaning Memory
306    XML_ParserFree(parser);
307    g_free(buf);
308    fclose(fd);
309
310    if (opts->debug > 0)
311        fprintf(stdout,"\r Ruleset parsing done. (%i/%i) [%fs]\n",
312                ruleset->cntRule,  ruleset->cntElse,
313                g_timer_elapsed(tRulesetRead,NULL));
314   
315    g_timer_destroy(tRulesetRead);
316
317    return(ruleset);
318}
319
320void rulesetFree(cfgRules * ruleset) {
321    cfgRule *rule, *lrule;
322    cfgDraw *draw, *ldraw;
323   
324    for(rule=ruleset->rule,lrule=NULL;rule;lrule=rule,rule=rule->next) {
325        for(draw=rule->draw,ldraw=NULL;draw;ldraw=draw,draw=draw->next) {
326            if(draw->pattern)
327                g_tree_replace(patternStrings, draw->pattern, draw->pattern);
328            if(ldraw)
329                g_free(ldraw);
330        }
331        if(ldraw)
332            g_free(ldraw);
333        for(draw=rule->ndraw,ldraw=NULL;draw;ldraw=draw,draw=draw->next) {
334            if(draw->pattern)
335                g_tree_replace(patternStrings, draw->pattern, draw->pattern);
336            if(ldraw)
337                g_free(ldraw);
338        }
339        if(ldraw)
340            g_free(ldraw);
341       
342        while (*rule->key != NULL) {
343            g_tree_replace(keyStrings, *rule->key, *rule->key);
344            rule->key++;
345        }
346        while (*rule->value != NULL) {
347            g_tree_replace(keyStrings, *rule->value, *rule->value);
348            rule->value++;
349        }
350       
351        if(lrule)
352            g_free(lrule);
353    }
354    g_free(lrule);
355    g_free(ruleset);
356};
357
358/*
359 * vim: expandtab shiftwidth=4 tabstop=4:
360 */
361
Note: See TracBrowser for help on using the repository browser.