Fixed bug calling reformDate twice. Since it returns a pointer to static data, it...
[planetdump.git] / keyvals.c
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 "keyvals.h"
14
15 #ifdef USE_TREE
16 #include "text-tree.h"
17 #endif
18
19 void initList(struct keyval *head)
20 {
21     assert(head);
22
23     head->next = head;
24     head->prev = head;
25     head->key = NULL;
26     head->value = NULL;
27 }
28
29 void freeItem(struct keyval *p)
30 {
31     if (!p) 
32         return;
33
34 #ifdef USE_TREE
35     text_release(tree_ctx, p->key);
36     text_release(tree_ctx, p->value);
37 #else
38     free(p->key);
39     free(p->value);
40 #endif
41     free(p);
42 }
43
44
45 unsigned int countList(struct keyval *head) 
46 {
47     struct keyval *p;
48     unsigned int count = 0;     
49
50     if (!head) 
51         return 0;
52
53     p = head->next;
54     while(p != head) {
55         count++;
56         p = p->next;
57     }
58     return count;
59 }
60
61 int listHasData(struct keyval *head) 
62 {
63     if (!head) 
64         return 0;
65
66     return (head->next != head);
67 }
68
69
70 char *getItem(struct keyval *head, const char *name)
71 {
72     struct keyval *p;
73
74     if (!head) 
75         return NULL;
76
77     p = head->next;
78     while(p != head) {
79         if (!strcmp(p->key, name))
80             return p->value;
81         p = p->next;
82     }
83     return NULL;
84 }       
85
86 /* Pulls all items from list which match this prefix
87  * note: they are removed from the original list an returned in a new one
88  */
89 struct keyval *getMatches(struct keyval *head, const char *name)
90 {
91     struct keyval *out = NULL;
92     struct keyval *p;
93
94     if (!head) 
95         return NULL;
96
97     out = malloc(sizeof(struct keyval));
98     if (!out)
99         return NULL;
100
101     initList(out);
102     p = head->next;
103     while(p != head) {
104         struct keyval *next = p->next;
105         if (!strncmp(p->key, name, strlen(name))) {
106             //printf("match: %s=%s\n", p->key, p->value);
107             p->next->prev = p->prev;
108             p->prev->next = p->next;
109             pushItem(out, p);
110         }
111         p = next;
112     }
113
114     if (listHasData(out))
115         return out;
116
117     free(out);
118     return NULL;
119 }
120
121 void updateItem(struct keyval *head, const char *name, const char *value)
122 {
123     struct keyval *item;
124
125     if (!head) 
126         return;
127
128     item = head->next;
129     while(item != head) {
130         if (!strcmp(item->key, name)) {
131 #ifdef USE_TREE
132             text_release(tree_ctx, item->value);
133             item->value = (char *)text_get(tree_ctx,value);
134 #else
135             free(item->value);
136             item->value = strdup(value);
137 #endif
138             return;
139         }
140         item = item->next;
141     }
142     addItem(head, name, value, 0);
143 }
144
145
146 struct keyval *popItem(struct keyval *head)
147 {
148     struct keyval *p;
149
150     if (!head) 
151         return NULL;
152  
153     p = head->next;
154     if (p == head)
155         return NULL;
156
157     head->next = p->next;
158     p->next->prev = head;
159
160     p->next = NULL;
161     p->prev = NULL;
162
163     return p;
164 }       
165
166
167 void pushItem(struct keyval *head, struct keyval *item)
168 {
169     assert(head);
170     assert(item);
171  
172     item->next = head;
173     item->prev = head->prev;
174     head->prev->next = item;
175     head->prev = item;
176 }       
177
178 int addItem(struct keyval *head, const char *name, const char *value, int noDupe)
179 {
180     struct keyval *item;
181
182     assert(head);
183     assert(name);
184     assert(value);
185
186     if (noDupe) {
187         item = head->next;
188         while (item != head) {
189             if (!strcmp(item->value, value) && !strcmp(item->key, name))
190                 return 1;
191             item = item->next;
192         }
193     }
194
195     item = malloc(sizeof(struct keyval));
196
197     if (!item) {
198         fprintf(stderr, "Error allocating keyval\n");
199         return 2;
200     }
201
202 #ifdef USE_TREE
203     item->key   = (char *)text_get(tree_ctx,name);
204     item->value = (char *)text_get(tree_ctx,value);
205 #else
206     item->key   = strdup(name);
207     item->value = strdup(value);
208 #endif
209
210 #if 0
211     item->next = head->next;
212     item->prev = head;
213     head->next->prev = item;
214     head->next = item;
215 #else
216     item->next = head;
217     item->prev = head->prev;
218     head->prev->next = item;
219     head->prev = item;
220 #endif
221     return 0;
222 }
223
224 void resetList(struct keyval *head) 
225 {
226     struct keyval *item;
227         
228     while((item = popItem(head))) 
229         freeItem(item);
230 }
231