source: subversion/applications/utils/export/osm2pgsql/keyvals.c @ 21054

Last change on this file since 21054 was 20775, checked in by giggls, 10 years ago

change "char sql[2048]" to "static char *sql" and do dynamic allocation

the reason is, that hstore rows can get really long,

thus dynamic allocation prevents them to get cut and (hopefully)
also prevents likely buffer overflows as well.

File size: 5.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#define USE_TREE
8
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <assert.h>
13#include <string.h>
14#include "keyvals.h"
15
16#ifdef USE_TREE
17#include "text-tree.h"
18#endif
19
20void initList(struct keyval *head)
21{
22    assert(head);
23
24    head->next = head;
25    head->prev = head;
26    head->key = NULL;
27    head->value = NULL;
28}
29
30void freeItem(struct keyval *p)
31{
32    if (!p) 
33        return;
34
35#ifdef USE_TREE
36    text_release(tree_ctx, p->key);
37    text_release(tree_ctx, p->value);
38#else
39    free(p->key);
40    free(p->value);
41#endif
42    free(p);
43}
44
45
46unsigned int countList(struct keyval *head) 
47{
48    struct keyval *p;
49    unsigned int count = 0;     
50
51    if (!head) 
52        return 0;
53
54    p = head->next;
55    while(p != head) {
56        count++;
57        p = p->next;
58    }
59    return count;
60}
61
62int listHasData(struct keyval *head) 
63{
64    if (!head) 
65        return 0;
66
67    return (head->next != head);
68}
69
70
71char *getItem(struct keyval *head, const char *name)
72{
73    struct keyval *p;
74
75    if (!head) 
76        return NULL;
77
78    p = head->next;
79    while(p != head) {
80        if (!strcmp(p->key, name))
81            return p->value;
82        p = p->next;
83    }
84    return NULL;
85}       
86
87struct keyval *firstItem(struct keyval *head)
88{
89    if (head == NULL || head == head->next)
90        return NULL;
91
92    return head->next;
93}
94
95struct keyval *nextItem(struct keyval *head, struct keyval *item)
96{
97    if (item->next == head)
98        return NULL;
99
100    return item->next;
101}
102
103/* Pulls all items from list which match this prefix
104 * note: they are removed from the original list an returned in a new one
105 */
106struct keyval *getMatches(struct keyval *head, const char *name)
107{
108    struct keyval *out = NULL;
109    struct keyval *p;
110
111    if (!head) 
112        return NULL;
113
114    out = malloc(sizeof(struct keyval));
115    if (!out)
116        return NULL;
117
118    initList(out);
119    p = head->next;
120    while(p != head) {
121        struct keyval *next = p->next;
122        if (!strncmp(p->key, name, strlen(name))) {
123            //printf("match: %s=%s\n", p->key, p->value);
124            p->next->prev = p->prev;
125            p->prev->next = p->next;
126            pushItem(out, p);
127        }
128        p = next;
129    }
130
131    if (listHasData(out))
132        return out;
133
134    free(out);
135    return NULL;
136}
137
138void updateItem(struct keyval *head, const char *name, const char *value)
139{
140    struct keyval *item;
141
142    if (!head) 
143        return;
144
145    item = head->next;
146    while(item != head) {
147        if (!strcmp(item->key, name)) {
148#ifdef USE_TREE
149            text_release(tree_ctx, item->value);
150            item->value = (char *)text_get(tree_ctx,value);
151#else
152            free(item->value);
153            item->value = strdup(value);
154#endif
155            return;
156        }
157        item = item->next;
158    }
159    addItem(head, name, value, 0);
160}
161
162
163struct keyval *popItem(struct keyval *head)
164{
165    struct keyval *p;
166
167    if (!head) 
168        return NULL;
169 
170    p = head->next;
171    if (p == head)
172        return NULL;
173
174    head->next = p->next;
175    p->next->prev = head;
176
177    p->next = NULL;
178    p->prev = NULL;
179
180    return p;
181}       
182
183
184void pushItem(struct keyval *head, struct keyval *item)
185{
186    assert(head);
187    assert(item);
188 
189    item->next = head;
190    item->prev = head->prev;
191    head->prev->next = item;
192    head->prev = item;
193}       
194
195int addItem(struct keyval *head, const char *name, const char *value, int noDupe)
196{
197    struct keyval *item;
198
199    assert(head);
200    assert(name);
201    assert(value);
202
203    if (noDupe) {
204        item = head->next;
205        while (item != head) {
206            if (!strcmp(item->value, value) && !strcmp(item->key, name))
207                return 1;
208            item = item->next;
209        }
210    }
211
212    item = malloc(sizeof(struct keyval));
213
214    if (!item) {
215        fprintf(stderr, "Error allocating keyval\n");
216        return 2;
217    }
218
219#ifdef USE_TREE
220    item->key   = (char *)text_get(tree_ctx,name);
221    item->value = (char *)text_get(tree_ctx,value);
222#else
223    item->key   = strdup(name);
224    item->value = strdup(value);
225#endif
226
227#if 1
228    // Add to head
229    item->next = head->next;
230    item->prev = head;
231    head->next->prev = item;
232    head->next = item;
233#else
234    // Add to tail
235    item->prev = head->prev;
236    item->next = head;
237    head->prev->next = item;
238    head->prev = item;
239#endif
240    return 0;
241}
242
243void resetList(struct keyval *head) 
244{
245    struct keyval *item;
246       
247    while((item = popItem(head))) 
248        freeItem(item);
249}
250
251void cloneList( struct keyval *target, struct keyval *source )
252{
253  struct keyval *ptr;
254  for( ptr = source->next; ptr != source; ptr=ptr->next )
255    addItem( target, ptr->key, ptr->value, 0 );
256}
257
258
259/* create an escaped version of the string for hstore table insert */
260/* make shure dst is 2*strlen(src) */
261static void escape4hstore(char *dst, char *src) {
262  size_t i,j;
263
264  j=0;
265  for (i=0;i<strlen(src);i++) {
266    switch(src[i]) {
267      case '\\':
268        dst[j]='\\';j++;dst[j]='\\';j++;dst[j]='\\';j++;dst[j]='\\'; break;
269      case '"':
270        dst[j]='\\';j++;dst[j]='\\';j++;dst[j]='"'; break;
271      case '\t':
272        dst[j]='\\';j++;dst[j]='\t'; break;
273      case '\r':
274        dst[j]='\\';j++;dst[j]='\r'; break;
275      case '\n':
276        dst[j]='\\';j++;dst[j]='\n'; break;
277      default:
278        dst[j]=src[i];
279      }
280    j++;
281  }
282  dst[j]='\0';
283}
284
285/* print struct keyval in syntax for pgsql hstore import
286   \ and " need to be escaped
287*/
288void keyval2hstore(char *hstring, struct keyval *tags)
289{
290  static char* str=NULL;
291  static size_t stlen=0;
292  size_t len;
293 
294  len=strlen(tags->value);
295  if (len>stlen) {
296    stlen=len;
297    str=realloc(str,1+stlen*2);
298  }
299
300  len=strlen(tags->key);
301  if (len>stlen) {
302    stlen=len;
303    str=realloc(str,1+stlen*2);
304  }
305
306  escape4hstore(str,tags->key); 
307  hstring+=sprintf(hstring,"\"%s\"=>",str);
308  escape4hstore(str,tags->value);
309  sprintf(hstring,"\"%s\"",str); 
310}
311
Note: See TracBrowser for help on using the repository browser.