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