source: subversion/applications/utils/planetdiff/keyvals.c @ 2605

Last change on this file since 2605 was 2406, checked in by jonb, 13 years ago

planetdiff & planetpatch tool - Allows incremental planet.osm updates using a custom XML diff format

File size: 3.5 KB
Line 
1/* Common key-value list processing
2 *
3 * Used as a small general purpose store for
4 * tags, segment lists etc
5 *
6 */
7#include <stdio.h>
8#include <malloc.h>
9#include <string.h>
10#include <assert.h>
11#include "keyvals.h"
12
13static char *escape(const char *in)
14{
15    // XML character escaping as per http://www.w3.org/TR/REC-xml/
16    const struct { char c; char *out; } codes[] = {
17        { '&',  "&amp;"  },
18     /* { '\'', "&apos;" }, -- It seems this isn't encoded in the planet.osm */
19        { '<',  "&lt;"   },
20        { '>',  "&gt;"   },
21        { '"', "&quot;"  }
22    };
23
24    const char *p;
25    char *out;
26    int l, i;
27   
28    for(l=0,p=in;*p;p++,l++)  {
29        for (i=0; i<sizeof(codes)/sizeof(codes[0]); i++) {
30            if (*p == codes[i].c) {
31                l += strlen(codes[i].out)-1;
32            }
33        }
34    }
35    out = malloc(l+1);
36    if (out) {
37        out[0] = '\0';
38        for(l=0,p=in;*p;p++,l++)  {
39            out[l] = *p;
40            for (i=0; i<sizeof(codes)/sizeof(codes[0]); i++) {
41                if (*p == codes[i].c) {
42                    memcpy(&out[l], codes[i].out, strlen(codes[i].out));
43                    l += strlen(codes[i].out)-1;
44                }
45            }
46        }
47        out[l] = '\0';
48    }
49    return out;
50}
51
52
53void initList(struct keyval *head)
54{
55    assert(head);
56
57    head->next = head;
58    head->prev = head;
59    head->key = NULL;
60    head->value = NULL;
61}
62
63void freeItem(struct keyval *p)
64{
65    if (!p) 
66        return;
67
68    free(p->key);
69    free(p->value);
70    free(p);
71}
72
73
74unsigned int countList(struct keyval *head) 
75{
76    struct keyval *p;
77    unsigned int count = 0;     
78
79    if (!head) 
80        return 0;
81
82    p = head->next;
83    while(p != head) {
84        count++;
85        p = p->next;
86    }
87    return count;
88}
89
90int listHasData(struct keyval *head) 
91{
92    if (!head) 
93        return 0;
94
95    return (head->next != head);
96}
97
98
99char *getItem(struct keyval *head, const char *name)
100{
101    struct keyval *p;
102
103    if (!head) 
104        return NULL;
105
106    p = head->next;
107    while(p != head) {
108        if (!strcmp(p->key, name))
109            return p->value;
110        p = p->next;
111    }
112    return NULL;
113}       
114
115
116struct keyval *popItem(struct keyval *head)
117{
118    struct keyval *p;
119
120    if (!head) 
121        return NULL;
122 
123    p = head->next;
124    if (p == head)
125        return NULL;
126
127    head->next = p->next;
128    p->next->prev = head;
129
130    p->next = NULL;
131    p->prev = NULL;
132
133    return p;
134}       
135
136
137void pushItem(struct keyval *head, struct keyval *item)
138{
139    assert(head);
140    assert(item);
141 
142    item->next = head;
143    item->prev = head->prev;
144    head->prev->next = item;
145    head->prev = item;
146}       
147
148int addItem(struct keyval *head, const char *key, const char *value, int noDupe)
149{
150    struct keyval *item;
151    char *k = escape(key);
152    char *v = escape(value);
153
154    if (noDupe) {
155        item = head->next;
156        while (item != head) {
157            if (!strcmp(item->value, v) && !strcmp(item->key, k)) {
158                free(k);
159                free(v);
160                return 1;
161            }
162            item = item->next;
163        }
164    }
165
166    item = malloc(sizeof(struct keyval));
167
168    if (!item) {
169        fprintf(stderr, "Error allocating keyval\n");
170        free(k);
171        free(v);
172        return 2;
173    }
174
175    item->key   = k;
176    item->value = v;
177
178#if 0
179    item->next = head->next;
180    item->prev = head;
181    head->next->prev = item;
182    head->next = item;
183#else
184    pushItem(head, item);
185#endif
186
187    return 0;
188}
189
190void resetList(struct keyval *head) 
191{
192    struct keyval *item;
193       
194    while((item = popItem(head))) 
195        freeItem(item);
196}
197
Note: See TracBrowser for help on using the repository browser.