Indentation, CRLF->LF, Tab-> Space
[privoxy.git] / list.c
1 const char list_rcs[] = "$Id: list.c,v 1.4 2001/06/29 13:30:22 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/list.c,v $
5  *
6  * Purpose     :  Declares functions to handle lists.
7  *                Functions declared include:
8  *                   `destroy_list', `enlist' and `list_to_text'
9  *
10  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
11  *                IJBSWA team.  http://ijbswa.sourceforge.net
12  *
13  *                Based on the Internet Junkbuster originally written
14  *                by and Copyright (C) 1997 Anonymous Coders and 
15  *                Junkbusters Corporation.  http://www.junkbusters.com
16  *
17  *                This program is free software; you can redistribute it 
18  *                and/or modify it under the terms of the GNU General
19  *                Public License as published by the Free Software
20  *                Foundation; either version 2 of the License, or (at
21  *                your option) any later version.
22  *
23  *                This program is distributed in the hope that it will
24  *                be useful, but WITHOUT ANY WARRANTY; without even the
25  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
26  *                PARTICULAR PURPOSE.  See the GNU General Public
27  *                License for more details.
28  *
29  *                The GNU General Public License should be included with
30  *                this file.  If not, you can view it at
31  *                http://www.gnu.org/copyleft/gpl.html
32  *                or write to the Free Software Foundation, Inc., 59
33  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  *
35  * Revisions   :
36  *    $Log: list.c,v $
37  *    Revision 1.4  2001/06/29 13:30:22  oes
38  *    - Added Convenience function enlist_unique_header(),
39  *      which takes the Header name and value as separate
40  *      arguments and thus saves the pain of sprintf()ing
41  *      and determining the Header name length to enlist_unique
42  *    - Improved comments
43  *    - Removed logentry from cancelled commit
44  *
45  *    Revision 1.3  2001/06/03 19:12:24  oes
46  *    functions for new struct map, extended enlist_unique
47  *
48  *    Revision 1.2  2001/06/01 18:49:17  jongfoster
49  *    Replaced "list_share" with "list" - the tiny memory gain was not
50  *    worth the extra complexity.
51  *
52  *    Revision 1.1  2001/05/31 21:11:53  jongfoster
53  *    - Moved linked list support to new "list.c" file.
54  *      Structure definitions are still in project.h,
55  *      function prototypes are now in "list.h".
56  *    - Added support for "struct list_share", which is identical
57  *      to "struct list" except it saves memory by not duplicating
58  *      the strings.  Obviously, this only works if there is some
59  *      other way of managing the memory used by the strings.
60  *      (These list_share lists are used for lists which last
61  *      for only 1 request, and where all the list entries are
62  *      just coming directly from entries in the actionsfile.)
63  *      Note that you still need to destroy list_share lists
64  *      properly to free the nodes - it's only the strings
65  *      which are shared.
66  *
67  *
68  *********************************************************************/
69 \f
70
71 #include "config.h"
72
73 #include <stdio.h>
74 #include <sys/types.h>
75 #include <stdlib.h>
76 #include <ctype.h>
77 #include <string.h>
78
79 #ifndef _WIN32
80 #include <unistd.h>
81 #endif
82
83 #include "project.h"
84 #include "jcc.h"
85 #include "list.h"
86 #include "miscutil.h"
87
88 const char list_h_rcs[] = LIST_H_VERSION;
89
90 /*********************************************************************
91  *
92  * Function    :  enlist
93  *
94  * Description :  Append a string into a specified string list.
95  *
96  * Parameters  :
97  *          1  :  header = pointer to list 'dummy' header
98  *          2  :  str = string to add to the list (maybe NULL)
99  *
100  * Returns     :  N/A
101  *
102  *********************************************************************/
103 void enlist(struct list *header, const char *str)
104 {
105    struct list *cur = (struct list *)malloc(sizeof(*cur));
106    struct list *last;
107
108    if (cur)
109    {
110       cur->str  = (str ? strdup(str) : NULL);
111       cur->next = NULL;
112
113       last = header->last;
114       if (last == NULL)
115       {
116          last = header;
117       }
118
119       last->next   = cur;
120       header->last = cur;
121    }
122
123 }
124
125
126 /*********************************************************************
127  *
128  * Function    :  enlist_first
129  *
130  * Description :  Append a string as first element into a specified
131  *                string list.
132  *
133  * Parameters  :
134  *          1  :  header = pointer to list 'dummy' header
135  *          2  :  str = string to add to the list (maybe NULL)
136  *
137  * Returns     :  N/A
138  *
139  *********************************************************************/
140 void enlist_first(struct list *header, const char *str)
141 {
142    struct list *cur = (struct list *)malloc(sizeof(*cur));
143
144    if (cur)
145    {
146       cur->str  = (str ? strdup(str) : NULL);
147       cur->next = header->next;
148
149       header->next = cur;
150       if (header->last == NULL)
151       {
152          header->last = cur;
153       }
154    }
155
156 }
157
158
159 /*********************************************************************
160  *
161  * Function    :  enlist_unique
162  *
163  * Description :  Append a string into a specified string list,
164  *                if & only if it's not there already.
165  *                If the n argument is nonzero, only compare up to
166  *                the nth character. 
167  *
168  * Parameters  :
169  *          1  :  header = pointer to list 'dummy' header
170  *          2  :  str = string to add to the list (maybe NULL)
171  *          3  :  n = number of chars to use for uniqueness test
172  *
173  * Returns     :  N/A
174  *
175  *********************************************************************/
176 void enlist_unique(struct list *header, const char *str, int n)
177 {
178    struct list *last;
179    struct list *cur = header->next;
180
181    while (cur != NULL)
182    {
183       if ((cur->str != NULL) && (
184          (n && (0 == strncmp(str, cur->str, n))) || 
185          (!n && (0 == strcmp(str, cur->str)))))
186       {
187          /* Already there */
188          return;
189       }
190       cur = cur->next;
191    }
192
193    cur = (struct list *)malloc(sizeof(*cur));
194
195    if (cur != NULL)
196    {
197       cur->str  = (str ? strdup(str) : NULL); /* FIXME check retval */
198       cur->next = NULL;
199
200       last = header->last;
201       if (last == NULL)
202       {
203          last = header;
204       }
205       last->next   = cur;
206       header->last = cur;
207    }
208 }
209
210
211 /*********************************************************************
212  *
213  * Function    :  enlist_unique_header
214  *
215  * Description :  Make a HTTP header from the two strings name and value,
216  *                and append the result into a specified string list,
217  *                if & only if there isn't already a header with that name.
218  *
219  * Parameters  :
220  *          1  :  header = pointer to list 'dummy' header
221  *          2  :  first = first string to add to the list (maybe NULL)
222  *          3  :  second = number of chars to use for uniqueness test
223  *
224  * Returns     :  N/A
225  *
226  *********************************************************************/
227 void enlist_unique_header(struct list *header, const char *name, const char *value)
228 {
229    struct list *last;
230    struct list *cur = header->next;
231    int length;
232    char *dummy;
233
234    if (name == NULL || value == NULL) return;
235
236    dummy = strdup(name);
237    dummy = strsav(dummy, ": ");
238    length = strlen(dummy);
239
240    while (cur != NULL)
241    {
242       if ((cur->str != NULL) && 
243                 (0 == strncmp(dummy, cur->str, length)))
244       {
245          /* Already there */
246          return;
247       }
248       cur = cur->next;
249    }
250
251    cur = (struct list *)malloc(sizeof(*cur));
252
253    if (cur != NULL)
254    {
255       cur->str  = strsav(dummy, value);
256       cur->next = NULL;
257
258       last = header->last;
259       if (last == NULL)
260       {
261          last = header;
262       }
263       last->next   = cur;
264       header->last = cur;
265    }
266 }
267
268
269 /*********************************************************************
270  *
271  * Function    :  destroy_list
272  *
273  * Description :  Destroy a string list (opposite of enlist)
274  *
275  * Parameters  :
276  *          1  :  header = pointer to list 'dummy' header
277  *
278  * Returns     :  N/A
279  *
280  *********************************************************************/
281 void destroy_list(struct list *header)
282 {
283    struct list *p, *n;
284
285    for (p = header->next; p ; p = n)
286    {
287       n = p->next;
288       freez(p->str);
289       free(p);
290    }
291
292    memset(header, '\0', sizeof(*header));
293
294 }
295
296
297 /*********************************************************************
298  *
299  * Function    :  list_to_text
300  *
301  * Description :  "Flaten" a string list into 1 long \r\n delimited string.
302  *
303  * Parameters  :
304  *          1  :  h = pointer to list 'dummy' header
305  *
306  * Returns     :  NULL on malloc error, else new long string.
307  *
308  *********************************************************************/
309 char *list_to_text(struct list *h)
310 {
311    struct list *p;
312    char *ret = NULL;
313    char *s;
314    int size;
315
316    size = 0;
317
318    for (p = h->next; p ; p = p->next)
319    {
320       if (p->str)
321       {
322          size += strlen(p->str) + 2;
323       }
324    }
325
326    if ((ret = (char *)malloc(size + 1)) == NULL)
327    {
328       return(NULL);
329    }
330
331    ret[size] = '\0';
332
333    s = ret;
334
335    for (p = h->next; p ; p = p->next)
336    {
337       if (p->str)
338       {
339          strcpy(s, p->str);
340          s += strlen(s);
341          *s++ = '\r'; *s++ = '\n';
342       }
343    }
344
345    return(ret);
346
347 }
348
349
350 /*********************************************************************
351  *
352  * Function    :  list_remove_item
353  *
354  * Description :  Remove a string from a specified string list.
355  *
356  * Parameters  :
357  *          1  :  header = pointer to list 'dummy' header
358  *          2  :  str = string to remove from the list
359  *
360  * Returns     :  Number of times it was removed.
361  *
362  *********************************************************************/
363 int list_remove_item(struct list *header, const char *str)
364 {
365    struct list *prev = header;
366    struct list *cur = prev->next;
367    int count = 0;
368
369    while (cur != NULL)
370    {
371       if ((cur->str != NULL) && (0 == strcmp(str, cur->str)))
372       {
373          count++;
374
375          prev->next = cur->next;
376          free(cur->str);
377          free(cur);
378       }
379       else
380       {
381          prev = cur;
382       }
383       cur = prev->next;
384    }
385
386    header->last = prev;
387
388    return count;
389 }
390
391
392 /*********************************************************************
393  *
394  * Function    :  list_remove_list
395  *
396  * Description :  Remove all strings in one list from another list.
397  *                This is currently a brute-force algorithm
398  *                (it compares every pair of strings).
399  *
400  * Parameters  :
401  *          1  :  dest = list to change
402  *          2  :  src = list of strings to remove
403  *
404  * Returns     :  Total number of strings removed.
405  *
406  *********************************************************************/
407 int list_remove_list(struct list *dest, const struct list *src)
408 {
409    struct list *cur = src->next;
410    int count = 0;
411
412    while (cur != NULL)
413    {
414       if (cur->str != NULL)
415       {
416          count += list_remove_item(dest, cur->str);
417       }
418       cur = cur->next;
419    }
420
421    return count;
422 }
423
424
425 /*********************************************************************
426  *
427  * Function    :  list_duplicate
428  *
429  * Description :  Duplicate a string list
430  *
431  * Parameters  :
432  *          1  :  dest = pointer to destination for copy.  Caller allocs.
433  *          2  :  src = pointer to source for copy.
434  *
435  * Returns     :  N/A
436  *
437  *********************************************************************/
438 void list_duplicate(struct list *dest, const struct list *src)
439 {
440    struct list * cur_src = src->next;
441    struct list * cur_dest = dest;
442
443    memset(dest, '\0', sizeof(*dest));
444
445    while (cur_src)
446    {
447       cur_dest = cur_dest->next = (struct list *)zalloc(sizeof(*cur_dest));
448       if (cur_dest == NULL)
449       {
450          return;
451       }
452       cur_dest->str = strdup(cur_src->str);
453       cur_src = cur_src->next;
454    }
455
456    dest->last = cur_dest;
457
458 }
459
460
461 /*********************************************************************
462  *
463  * Function    :  list_append_list_unique
464  *
465  * Description :  Append a string list to another list.
466  *                Duplicate items are not added.
467  *
468  * Parameters  :
469  *          1  :  dest = pointer to destination for merge.  Caller allocs.
470  *          2  :  src = pointer to source for merge.
471  *
472  * Returns     :  N/A
473  *
474  *********************************************************************/
475 void list_append_list_unique(struct list *dest, const struct list *src)
476 {
477    struct list * cur = src->next;
478
479    while (cur)
480    {
481       enlist_unique(dest, cur->str, 0);
482       cur = cur->next;
483    }
484 }
485
486
487 /*********************************************************************
488  *
489  * Function    :  map
490  *
491  * Description :  Add a mapping from given name to given value to a
492  *                given map.
493  *
494  *                Note: Since all strings will be free()d in free_map()
495  *                      later, use the copy flags for constants or
496  *                      strings that will be independantly free()d.
497  *
498  * Parameters  :
499  *          1  :  map = map to add to
500  *          2  :  name = name to add
501  *          3  :  nc = flag set if a copy of name should be used
502  *          4  :  value = value to add
503  *          5  :  vc = flag set if a copy of value should be used
504  *
505  * Returns     :  pointer to extended map, or NULL if failiure
506  *
507  *********************************************************************/
508 struct map *map(struct map *map, char *name, int nc, char *value, int vc)
509 {
510    struct map *cur;
511
512    if (NULL == (cur = zalloc(sizeof(*cur))))
513    {
514       return(NULL);
515    }
516
517    cur->name  = nc ? strdup(name) : name;
518    cur->value = vc ? strdup(value) : value;
519    cur->next = map;
520
521    return(cur);
522
523 }
524
525
526 /*********************************************************************
527  *
528  * Function    :  lookup
529  *
530  * Description :  Look up an item with a given name in a map, and
531  *                return its value
532  *
533  * Parameters  :
534  *          1  :  name = name parameter to look for
535  *
536  * Returns     :  the value if found, else the empty string
537  *
538  *********************************************************************/
539 char *lookup(struct map *map, char *name)
540 {
541    struct map *p = map;
542
543    while (p)
544    {
545       if (!strcmp(name, p->name))
546       {
547          return p->value;
548       }
549       p = p->next;
550    }
551    return "";
552
553 }
554
555
556 /*********************************************************************
557  *
558  * Function    :  free_map
559  *
560  * Description :  Free the memory occupied by a map and its
561  *                depandant strings
562  *
563  * Parameters  :
564  *          1  :  list = list to bee freed
565  *
566  * Returns     :  N/A
567  *
568  *********************************************************************/
569 void free_map(struct map *map)
570 {
571    struct map *p = map;
572
573    while (p)
574    {
575       free(p->name);
576       free(p->value);
577
578       map = p->next;
579       free(p);
580       p = map;
581    }
582
583 }
584
585
586 /*
587   Local Variables:
588   tab-width: 3
589   end:
590 */