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

Revision 22371, 5.9 KB checked in by mazdermind, 4 years ago (diff)

add hstore-column option, which allows to create specific hstore columns for sub tags. '--hstore-column name:' will for example create a column "name:" with all the values of name:xx tags ind the form of xx=>Value for any name:xx tagged to an element. This changeset also includes changes to the regular hstore code by moving it to a separate function and also extending keyvals.c/h with an inline wrapper-function.

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*/
288inline void keyval2hstore(char *hstring, struct keyval *tags)
289{
290  keyval2hstore_manual(hstring, tags->key, tags->value);
291}
292
293void keyval2hstore_manual(char *hstring, char *key, char *value)
294{
295  static char* str=NULL;
296  static size_t stlen=0;
297  size_t len;
298 
299  len=strlen(value);
300  if (len>stlen) {
301    stlen=len;
302    str=realloc(str,1+stlen*2);
303  }
304
305  len=strlen(key);
306  if (len>stlen) {
307    stlen=len;
308    str=realloc(str,1+stlen*2);
309  }
310
311  escape4hstore(str,key); 
312  hstring+=sprintf(hstring,"\"%s\"=>",str);
313  escape4hstore(str,value);
314  sprintf(hstring,"\"%s\"",str); 
315}
316
Note: See TracBrowser for help on using the repository browser.