source: subversion/applications/utils/export/osm2pgsql-intarray/keyvals.c @ 28719

Last change on this file since 28719 was 25786, checked in by giggls, 9 years ago

Fix bug in hstore rework.

Bad idea to remove the k/v pairs from the linked list after
writing their colum, as write_wkts is called more than once.

So flag them to have their own column.

Afterwords check this flag to see if a given
k/v pair should be written to the hstore or not.

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