1 /*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21 */
22
23
24 #include <stdlib.h>
25 #include <stdio.h> /* FILE */
26 #include <string.h> /* strncmp */
27 #include <limits.h>
28 #include <assert.h>
29
30 #include "../ows/ows.h"
31
32
33 /*
34 * Initialize a list structure
35 */
list_init()36 list *list_init()
37 {
38 list *l = NULL;
39
40 l = malloc(sizeof(list));
41 assert(l);
42
43 l->first = NULL;
44 l->last = NULL;
45 l->size = 0;
46
47 return l;
48 }
49
50
51 /*
52 * Free a list structure
53 */
list_free(list * l)54 void list_free(list * l)
55 {
56 assert(l);
57
58 while (l->first) list_node_free(l, l->first);
59
60 l->last = NULL;
61 free(l);
62 l = NULL;
63 }
64
65
66 /*
67 * Add a given buffer to the end of a list
68 * Careful buffer is passed by reference,
69 * and must be free with list_free()
70 */
list_add(list * l,buffer * value)71 void list_add(list * l, buffer * value)
72 {
73 list_node *ln;
74
75 assert(l);
76 assert(value);
77 assert(l->size < UINT_MAX);
78
79 ln = list_node_init();
80
81 ln->value = value;
82
83 if (!l->first) {
84 ln->prev = NULL;
85 l->first = ln;
86 } else {
87 ln->prev = l->last;
88 l->last->next = ln;
89 }
90
91 l->last = ln;
92 l->last->next = NULL;
93 l->size++;
94 }
95
96
97 /*
98 * Add a given buffer to the end of a list
99 * Careful buffer is passed by reference,
100 * and must be free with list_free()
101 */
list_add_str(list * l,char * value)102 void list_add_str(list * l, char *value)
103 {
104 list_node *ln;
105
106 assert(l);
107 assert(value);
108 assert(l->size < UINT_MAX);
109
110 ln = list_node_init();
111
112 ln->value = buffer_init();
113 buffer_add_str(ln->value, value);
114
115 if (!l->first) {
116 ln->prev = NULL;
117 l->first = ln;
118 } else {
119 ln->prev = l->last;
120 l->last->next = ln;
121 }
122
123 l->last = ln;
124 l->last->next = NULL;
125 l->size++;
126 }
127
128
list_pop(list * l)129 void list_pop(list *l)
130 {
131 list_node *ln;
132
133 assert(l);
134 if (l->size == 0) return;
135
136 ln = l->last->prev;
137 list_node_free(l, l->last);
138 ln->next = NULL;
139 l->last = ln;
140 l->size--;
141
142 if (l->size == 0) l->first = l->last = NULL;
143 if (l->size == 1) l->first = l->last = ln;
144 }
145
146
147 /*
148 * Add a given list to the end of a list
149 * Careful list is passed by reference,
150 * and must be free with list_free()
151 */
list_add_list(list * l,list * l_to_add)152 void list_add_list(list * l, list * l_to_add)
153 {
154 list_node *ln, *ln_parse;
155
156 assert(l);
157 assert(l_to_add);
158
159 for (ln_parse = l_to_add->first ; ln_parse ; ln_parse = ln_parse->next) {
160 if (!in_list(l, ln_parse->value)) {
161 ln = list_node_init();
162
163 ln->value = buffer_init();
164 buffer_copy(ln->value, ln_parse->value);
165
166 if (!l->first) {
167 ln->prev = NULL;
168 l->first = ln;
169 } else {
170 ln->prev = l->last;
171 l->last->next = ln;
172 }
173
174 l->last = ln;
175 l->last->next = NULL;
176 l->size++;
177 }
178 }
179 }
180
181
182 /*
183 * Add a given buffer by copy to the end of a list
184 * Careful buffer is passed by reference,
185 * and must be free with list_free()
186 */
list_add_by_copy(list * l,buffer * value)187 void list_add_by_copy(list * l, buffer * value)
188 {
189 list_node *ln;
190 buffer *tmp;
191
192 assert(l);
193 assert(value);
194 assert(l->size < UINT_MAX);
195
196 ln = list_node_init();
197 tmp = buffer_init();
198
199 buffer_copy(tmp, value);
200 ln->value = tmp;
201
202 if (!l->first) {
203 ln->prev = NULL;
204 l->first = ln;
205 } else {
206 ln->prev = l->last;
207 l->last->next = ln;
208 }
209
210 l->last = ln;
211 l->last->next = NULL;
212 l->size++;
213 }
214
215
216 /*
217 * Initialize a list node
218 */
list_node_init()219 list_node *list_node_init()
220 {
221 list_node *ln;
222
223 ln = malloc(sizeof(list_node));
224 assert(ln);
225
226 ln->value = NULL;
227 ln->prev = NULL;
228 ln->next = NULL;
229
230 return ln;
231 }
232
233
234 /*
235 * Free a list node
236 */
list_node_free(list * l,list_node * ln)237 void list_node_free(list * l, list_node * ln)
238 {
239 assert(ln);
240
241 if (ln->prev) ln->prev = NULL;
242 if (ln->next) {
243 if (l) l->first = ln->next;
244 ln->next = NULL;
245 } else {
246 if (l) l->first = NULL;
247 }
248
249 if (ln->value) buffer_free(ln->value);
250
251 free(ln);
252 ln = NULL;
253 }
254
255
256 /*
257 * Check if a given buffer value is or not in the list
258 */
in_list(const list * l,const buffer * value)259 bool in_list(const list * l, const buffer * value)
260 {
261 list_node *ln;
262
263 assert(l);
264 assert(value);
265
266 for (ln = l->first ; ln ; ln = ln->next)
267 if (value->use == ln->value->use)
268 if (buffer_cmp(value, ln->value->buf))
269 return true;
270
271 return false;
272 }
273
274
275 /*
276 * Check if a given buffer value is or not in the list
277 */
in_list_str(const list * l,const char * value)278 bool in_list_str(const list * l, const char * value)
279 {
280 list_node *ln;
281
282 assert(l);
283 assert(value);
284
285 for (ln = l->first ; ln ; ln = ln->next)
286 if (!strcmp(value, ln->value->buf)) return true;
287
288 return false;
289 }
290
291
292 /*
293 * Trunk an initial buffer into several pieces upon a separator char
294 * Careful returned list must then be free with list_free()
295 */
list_explode(char separator,const buffer * value)296 list *list_explode(char separator, const buffer * value)
297 {
298 size_t i;
299 list *l;
300 buffer *buf;
301
302 assert(value);
303
304 l = list_init();
305 buf = buffer_init();
306
307 for (i = 0 ; i < value->use ; i++)
308 if (value->buf[i] == separator) {
309 list_add(l, buf); /* Add the buffer to the list */
310 buf = buffer_init();
311 } else buffer_add(buf, value->buf[i]);
312
313 list_add(l, buf);
314
315 return l;
316 }
317
318
319 /*
320 * Trunk an initial buffer into two pieces upon a separator char
321 * (reverse could be use to begin string parse from the end)
322 * Careful returned list must then be free with list_free()
323 */
list_split(char separator,const buffer * value,bool reverse)324 list *list_split(char separator, const buffer * value, bool reverse)
325 {
326 long int s;
327 list *l;
328 buffer *buf1, *buf2;
329
330 assert(value);
331
332 l = list_init();
333 buf1 = buffer_init();
334 buffer_copy(buf1, value);
335
336 if (reverse)
337 s = buffer_rchr(value, separator);
338 else
339 s = buffer_chr(value, separator);
340
341 if (s <= 0 || s == value->use) {
342 list_add(l, buf1);
343 return l;
344 }
345
346 buf2 = buffer_init();
347 buffer_add_nstr(buf2, value->buf, s);
348 buffer_shift(buf1, s + 1);
349
350 if (reverse) {
351 list_add(l, buf1);
352 list_add(l, buf2);
353 } else {
354 list_add(l, buf2);
355 list_add(l, buf1);
356 }
357
358 return l;
359 }
360
361
362 /*
363 * Trunk an initial buffer into several pieces upon two separators
364 * Careful returned list must then be free with list_free()
365 */
list_explode_start_end(char separator_start,char separator_end,buffer * value)366 list *list_explode_start_end(char separator_start, char separator_end, buffer * value)
367 {
368 list *l;
369 size_t i;
370 buffer *buf;
371
372 assert(value);
373
374 l = list_init();
375
376 /* If first char doesn't match separator, list contains only one element */
377 if (value->buf[0] != separator_start) {
378 list_add_by_copy(l, value);
379 return l;
380 }
381
382 buf = buffer_init();
383
384 for (i = 1 ; i < value->use ; i++)
385 if (value->buf[i] == separator_end) {
386 list_add(l, buf);
387 } else if (value->buf[i] != separator_start) {
388 buffer_add(buf, value->buf[i]);
389 } else { /* separator_start */
390 buf = buffer_init();
391 }
392
393 return l;
394 }
395
396
397 /*
398 * Trunk an initial string into several pieces upon a separator char
399 * Careful returned list must then be free with list_free()
400 */
list_explode_str(char separator,const char * value)401 list *list_explode_str(char separator, const char *value)
402 {
403 size_t i;
404 list *l;
405 buffer *buf;
406
407 assert(value);
408
409 l = list_init();
410 buf = buffer_init();
411
412 for (i = 0; value[i] != '\0'; i++)
413 if (value[i] == separator) {
414 /* add the buffer to the list */
415 list_add(l, buf);
416 buf = buffer_init();
417 } else
418 buffer_add(buf, value[i]);
419
420 list_add(l, buf);
421
422 return l;
423 }
424
425
426 /*
427 * Trunk an initial string into several pieces upon a separator char
428 * Careful returned list must then be free with list_free()
429 */
list_explode_str_trim(char separator,const char * value)430 list *list_explode_str_trim(char separator, const char *value)
431 {
432 size_t i;
433 list *l;
434 buffer *buf;
435
436 assert(value);
437
438 l = list_init();
439 buf = buffer_init();
440
441 for (i = 0; value[i] != '\0'; i++)
442 if (value[i] == separator) {
443 /* add the buffer to the list */
444 list_add(l, buf);
445 buf = buffer_init();
446 } else {
447 if(value[i] != ' ') {
448 buffer_add(buf, value[i]);
449 }
450 }
451
452 list_add(l, buf);
453
454 return l;
455 }
456
457
458 /*
459 * Join list to a given bufer
460 */
list_implode(buffer * buf,const char * separator,const list * l)461 void list_implode(buffer * buf, const char * separator, const list * l)
462 {
463 list_node *ln;
464
465 assert(buf);
466 assert(l);
467
468 for (ln = l->first ; ln ; ln = ln->next) {
469 buffer_add_str(buf, ln->value->buf);
470 if (ln->next)
471 buffer_add_str(buf, separator);
472 }
473 }
474
475
476 #ifdef OWS_DEBUG
477 /*
478 * Flush a list to a given file
479 * (mainly to debug purpose)
480 */
list_flush(const list * l,FILE * output)481 void list_flush(const list * l, FILE * output)
482 {
483 list_node *ln;
484
485 assert(l);
486 assert(output);
487
488 for (ln = l->first ; ln ; ln = ln->next) {
489 fprintf(output, "[");
490 buffer_flush(ln->value, output);
491 fprintf(output, "]\n");
492 }
493 }
494 #endif
495
496
497 /*
498 * vim: expandtab sw=4 ts=4
499 */
500