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

Last change on this file since 30195 was 5038, checked in by jonb, 12 years ago

planetdiff: Update to 0.5. Improve efficiency by only escaping values when we are about to output them in the diff

File size: 3.8 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
116
117static struct keyval *popItemInternal(struct keyval *head)
118{
119    struct keyval *p;
120
121    if (!head) 
122        return NULL;
123 
124    p = head->next;
125    if (p == head)
126        return NULL;
127
128    head->next = p->next;
129    p->next->prev = head;
130
131    p->next = NULL;
132    p->prev = NULL;
133
134    return p;
135}       
136
137struct keyval *popItem(struct keyval *head)
138{
139    struct keyval *p = popItemInternal(head);
140    char *k, *v;
141
142    if (!p) 
143        return NULL;
144
145    // Lazy escaping (only escape values which actually get output)
146    k = p->key;
147    p->key = escape(k);
148    free(k);
149
150    v = p->value;
151    p->value = escape(v);
152    free(v);
153
154    return p;
155}       
156
157
158void pushItem(struct keyval *head, struct keyval *item)
159{
160    assert(head);
161    assert(item);
162 
163    item->next = head;
164    item->prev = head->prev;
165    head->prev->next = item;
166    head->prev = item;
167}       
168
169int addItem(struct keyval *head, const char *name, const char *value, int noDupe)
170{
171    struct keyval *item;
172
173    assert(head);
174    assert(name);
175    assert(value);
176
177    if (noDupe) {
178        item = head->next;
179        while (item != head) {
180            if (!strcmp(item->value, value) && !strcmp(item->key, name))
181                return 1;
182            item = item->next;
183        }
184    }
185
186    item = malloc(sizeof(struct keyval));
187
188    if (!item) {
189        fprintf(stderr, "Error allocating keyval\n");
190        return 2;
191    }
192
193    item->key   = strdup(name);
194    item->value = strdup(value);
195
196#if 0
197    item->next = head->next;
198    item->prev = head;
199    head->next->prev = item;
200    head->next = item;
201#else
202    pushItem(head, item);
203#endif
204
205    return 0;
206}
207
208void resetList(struct keyval *head) 
209{
210    struct keyval *item;
211       
212    while((item = popItemInternal(head))) 
213        freeItem(item);
214}
215
Note: See TracBrowser for help on using the repository browser.