LCOV - code coverage report
Current view: top level - fuzz - list.c (source / functions) Hit Total Coverage
Test: trace.lcov_info_final Lines: 239 297 80.5 %
Date: 2021-02-22 04:51:02 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*********************************************************************
       2             :  *
       3             :  * File        :  $Source: /cvsroot/ijbswa/current/list.c,v $
       4             :  *
       5             :  * Purpose     :  Declares functions to handle lists.
       6             :  *
       7             :  * Copyright   :  Written by and Copyright (C) 2001-2007 members of the
       8             :  *                Privoxy team. https://www.privoxy.org/
       9             :  *
      10             :  *                Based on the Internet Junkbuster originally written
      11             :  *                by and Copyright (C) 1997 Anonymous Coders and
      12             :  *                Junkbusters Corporation.  http://www.junkbusters.com
      13             :  *
      14             :  *                This program is free software; you can redistribute it
      15             :  *                and/or modify it under the terms of the GNU General
      16             :  *                Public License as published by the Free Software
      17             :  *                Foundation; either version 2 of the License, or (at
      18             :  *                your option) any later version.
      19             :  *
      20             :  *                This program is distributed in the hope that it will
      21             :  *                be useful, but WITHOUT ANY WARRANTY; without even the
      22             :  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
      23             :  *                PARTICULAR PURPOSE.  See the GNU General Public
      24             :  *                License for more details.
      25             :  *
      26             :  *                The GNU General Public License should be included with
      27             :  *                this file.  If not, you can view it at
      28             :  *                http://www.gnu.org/copyleft/gpl.html
      29             :  *                or write to the Free Software Foundation, Inc., 59
      30             :  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
      31             :  *
      32             :  *********************************************************************/
      33             : 
      34             : 
      35             : #include "config.h"
      36             : 
      37             : #ifndef _WIN32
      38             : /* FIXME: The following headers are not needed for Win32.  Are they
      39             :  * needed on other platforms?
      40             :  */
      41             : #include <stdio.h>
      42             : #include <sys/types.h>
      43             : #include <stdlib.h>
      44             : #include <ctype.h>
      45             : #endif
      46             : #include <string.h>
      47             : 
      48             : #if !defined(_WIN32)
      49             : #include <unistd.h>
      50             : #endif
      51             : 
      52             : #include <assert.h>
      53             : 
      54             : #include "project.h"
      55             : #include "list.h"
      56             : #include "miscutil.h"
      57             : 
      58             : static int list_is_valid (const struct list *the_list);
      59             : 
      60             : 
      61             : /*********************************************************************
      62             :  *
      63             :  * Function    :  init_list
      64             :  *
      65             :  * Description :  Create a new, empty list in user-allocated memory.
      66             :  *                Caller should allocate a "struct list" variable,
      67             :  *                then pass it to this function.
      68             :  *                (Implementation note:  Rather than calling this
      69             :  *                function, you can also just memset the memory to
      70             :  *                zero, e.g. if you have a larger structure you
      71             :  *                want to initialize quickly.  However, that isn't
      72             :  *                really good design.)
      73             :  *
      74             :  * Parameters  :
      75             :  *          1  :  the_list = pointer to list
      76             :  *
      77             :  * Returns     :  N/A
      78             :  *
      79             :  *********************************************************************/
      80       67016 : void init_list(struct list *the_list)
      81             : {
      82       67016 :    memset(the_list, '\0', sizeof(*the_list));
      83       67016 : }
      84             : 
      85             : 
      86             : /*********************************************************************
      87             :  *
      88             :  * Function    :  destroy_list
      89             :  *
      90             :  * Description :  Destroy a string list (opposite of list_init).
      91             :  *                On return, the memory used by the list entries has
      92             :  *                been freed, but not the memory used by the_list
      93             :  *                itself.  You should not re-use the_list without
      94             :  *                calling list_init().
      95             :  *
      96             :  *                (Implementation note:  You *can* reuse the_list
      97             :  *                without calling list_init(), but please don't.
      98             :  *                If you want to remove all entries from a list
      99             :  *                and still have a usable list, then use
     100             :  *                list_remove_all().)
     101             :  *
     102             :  * Parameters  :
     103             :  *          1  :  the_list = pointer to list
     104             :  *
     105             :  * Returns     :  N/A
     106             :  *
     107             :  *********************************************************************/
     108     1766188 : void destroy_list (struct list *the_list)
     109             : {
     110             :    struct list_entry *cur_entry, *next_entry;
     111             : 
     112     1766188 :    assert(the_list);
     113             : 
     114     2795531 :    for (cur_entry = the_list->first; cur_entry ; cur_entry = next_entry)
     115             :    {
     116     1029343 :       next_entry = cur_entry->next;
     117     1029343 :       freez(cur_entry->str);
     118     1029343 :       free(cur_entry);
     119             :    }
     120             : 
     121     1766188 :    the_list->first = NULL;
     122     1766188 :    the_list->last = NULL;
     123     1766188 : }
     124             : 
     125             : 
     126             : /*********************************************************************
     127             :  *
     128             :  * Function    :  list_is_valid
     129             :  *
     130             :  * Description :  Check that a string list is valid.  The intended
     131             :  *                usage is "assert(list_is_valid(the_list))".
     132             :  *                Currently this checks that "the_list->last"
     133             :  *                is correct, and that the list doesn't contain
     134             :  *                circular references.  It is likely to crash if
     135             :  *                it's passed complete garbage.
     136             :  *
     137             :  * Parameters  :
     138             :  *          1  :  the_list = pointer to list.  Must be non-null.
     139             :  *
     140             :  * Returns     :  1 if list is valid, 0 otherwise.
     141             :  *
     142             :  *********************************************************************/
     143    13594983 : static int list_is_valid (const struct list *the_list)
     144             : {
     145             :    /*
     146             :     * If you don't want this check, just change the line below
     147             :     * from "#if 1" to "#if 0".
     148             :     */
     149             : #if 1
     150             :    const struct list_entry *cur_entry;
     151    13594983 :    const struct list_entry *last_entry = NULL;
     152    13594983 :    int entry = 0;
     153             : 
     154    13594983 :    assert(the_list);
     155             : 
     156   102311916 :    for (cur_entry = the_list->first; cur_entry ; cur_entry = cur_entry->next)
     157             :    {
     158    88716933 :       last_entry = cur_entry;
     159             : 
     160    88716933 :       if (cur_entry->str)
     161             :       {
     162             :          /*
     163             :           * Just check that this string can be accessed - i.e. it's a valid
     164             :           * pointer.
     165             :           */
     166    88324658 :          (void)strlen(cur_entry->str);
     167             :       }
     168             : 
     169             :       /*
     170             :        * Check for looping back to first
     171             :        */
     172    88716933 :       if ((entry++ != 0) && (cur_entry == the_list->first))
     173             :       {
     174           0 :          return 0;
     175             :       }
     176             : 
     177             :       /*
     178             :        * Arbitrarily limit list length to prevent infinite loops.
     179             :        * Note that the 1000 limit was hit by a real user in tracker 911950;
     180             :        * removing it for now.  Real circular references should eventually
     181             :        * be caught by the check above, anyway.
     182             :        */
     183             :       /*
     184             :       if (entry > 1000)
     185             :       {
     186             :          return 0;
     187             :       }
     188             :       */
     189             : 
     190             :       /*
     191             :        * Check this isn't marked as the last entry, unless of course it's
     192             :        * *really* the last entry.
     193             :        */
     194    88716933 :       if ((the_list->last == cur_entry) && (cur_entry->next != NULL))
     195             :       {
     196             :          /* This is the last entry, but there's data after it !!?? */
     197           0 :          return 0;
     198             :       }
     199             :    }
     200             : 
     201    13594983 :    return (the_list->last == last_entry);
     202             : #else
     203             :    return 1;
     204             : #endif
     205             : }
     206             : 
     207             : /*********************************************************************
     208             :  *
     209             :  * Function    :  enlist
     210             :  *
     211             :  * Description :  Append a string into a specified string list.
     212             :  *
     213             :  * Parameters  :
     214             :  *          1  :  the_list = pointer to list
     215             :  *          2  :  str = string to add to the list (maybe NULL)
     216             :  *
     217             :  * Returns     :  JB_ERR_OK on success
     218             :  *                JB_ERR_MEMORY on out-of-memory error.
     219             :  *                On error, the_list will be unchanged.
     220             :  *
     221             :  *********************************************************************/
     222     1969220 : jb_err enlist(struct list *the_list, const char *str)
     223             : {
     224             :    struct list_entry *cur;
     225             : 
     226     1969220 :    assert(the_list);
     227     1969220 :    assert(list_is_valid(the_list));
     228             : 
     229     1969220 :    if (NULL == (cur = (struct list_entry *)zalloc(sizeof(*cur))))
     230             :    {
     231           0 :       return JB_ERR_MEMORY;
     232             :    }
     233             : 
     234     1969220 :    if (str)
     235             :    {
     236     1969220 :       if (NULL == (cur->str = strdup(str)))
     237             :       {
     238           0 :          free(cur);
     239           0 :          return JB_ERR_MEMORY;
     240             :       }
     241             :    }
     242             :    /* else { cur->str = NULL; }  - implied by zalloc */
     243             : 
     244             :    /* cur->next = NULL;  - implied by zalloc */
     245             : 
     246     1969220 :    if (the_list->last)
     247             :    {
     248     1538868 :       the_list->last->next = cur;
     249     1538868 :       the_list->last = cur;
     250             :    }
     251             :    else
     252             :    {
     253      430352 :       the_list->first = cur;
     254      430352 :       the_list->last = cur;
     255             :    }
     256             : 
     257     1969220 :    assert(list_is_valid(the_list));
     258     1969220 :    return JB_ERR_OK;
     259             : }
     260             : 
     261             : 
     262             : /*********************************************************************
     263             :  *
     264             :  * Function    :  enlist_first
     265             :  *
     266             :  * Description :  Append a string as first element into a specified
     267             :  *                string list.
     268             :  *
     269             :  * Parameters  :
     270             :  *          1  :  the_list = pointer to list
     271             :  *          2  :  str = string to add to the list (maybe NULL)
     272             :  *
     273             :  * Returns     :  JB_ERR_OK on success
     274             :  *                JB_ERR_MEMORY on out-of-memory error.
     275             :  *                On error, the_list will be unchanged.
     276             :  *
     277             :  *********************************************************************/
     278       26436 : jb_err enlist_first(struct list *the_list, const char *str)
     279             : {
     280             :    struct list_entry *cur;
     281             : 
     282       26436 :    assert(the_list);
     283       26436 :    assert(list_is_valid(the_list));
     284             : 
     285       26436 :    if (NULL == (cur = (struct list_entry *)zalloc(sizeof(*cur))))
     286             :    {
     287           0 :       return JB_ERR_MEMORY;
     288             :    }
     289             : 
     290       26436 :    if (str)
     291             :    {
     292       26436 :       if (NULL == (cur->str = strdup(str)))
     293             :       {
     294           0 :          free(cur);
     295           0 :          return JB_ERR_MEMORY;
     296             :       }
     297             :    }
     298             :    /* else { cur->str = NULL; }  - implied by zalloc */
     299             : 
     300       26436 :    cur->next = the_list->first;
     301             : 
     302       26436 :    the_list->first = cur;
     303       26436 :    if (the_list->last == NULL)
     304             :    {
     305           0 :       the_list->last = cur;
     306             :    }
     307             : 
     308       26436 :    assert(list_is_valid(the_list));
     309       26436 :    return JB_ERR_OK;
     310             : }
     311             : 
     312             : 
     313             : /*********************************************************************
     314             :  *
     315             :  * Function    :  enlist_unique
     316             :  *
     317             :  * Description :  Append a string into a specified string list,
     318             :  *                if & only if it's not there already.
     319             :  *                If the num_significant_chars argument is nonzero,
     320             :  *                only compare up to the nth character.
     321             :  *
     322             :  * Parameters  :
     323             :  *          1  :  the_list = pointer to list
     324             :  *          2  :  str = string to add to the list
     325             :  *          3  :  num_significant_chars = number of chars to use
     326             :  *                for uniqueness test, or 0 to require an exact match.
     327             :  *
     328             :  * Returns     :  JB_ERR_OK on success
     329             :  *                JB_ERR_MEMORY on out-of-memory error.
     330             :  *                On error, the_list will be unchanged.
     331             :  *                "Success" does not indicate whether or not the
     332             :  *                item was already in the list.
     333             :  *
     334             :  *********************************************************************/
     335      997409 : jb_err enlist_unique(struct list *the_list, const char *str,
     336             :                      size_t num_significant_chars)
     337             : {
     338             :    struct list_entry *cur_entry;
     339             : 
     340      997409 :    assert(the_list);
     341      997409 :    assert(list_is_valid(the_list));
     342      997409 :    assert(str);
     343             :    assert(num_significant_chars >= 0);
     344      997409 :    assert(num_significant_chars <= strlen(str));
     345             : 
     346      997409 :    if (num_significant_chars > 0)
     347             :    {
     348     1557782 :       for (cur_entry = the_list->first; cur_entry != NULL; cur_entry = cur_entry->next)
     349             :       {
     350     1313340 :          if ((cur_entry->str != NULL)
     351     1312879 :            && (0 == strncmp(str, cur_entry->str, num_significant_chars)))
     352             :          {
     353             :             /* Already there */
     354        1709 :             return JB_ERR_OK;
     355             :          }
     356             :       }
     357             :    }
     358             :    else
     359             :    {
     360             :       /* Test whole string */
     361     3610198 :       for (cur_entry = the_list->first; cur_entry != NULL; cur_entry = cur_entry->next)
     362             :       {
     363     2886328 :          if ((cur_entry->str != NULL) && (0 == strcmp(str, cur_entry->str)))
     364             :          {
     365             :             /* Already there */
     366       27388 :             return JB_ERR_OK;
     367             :          }
     368             :       }
     369             :    }
     370             : 
     371      968312 :    return enlist(the_list, str);
     372             : }
     373             : 
     374             : 
     375             : /*********************************************************************
     376             :  *
     377             :  * Function    :  enlist_unique_header
     378             :  *
     379             :  * Description :  Make a HTTP header from the two strings name and value,
     380             :  *                and append the result into a specified string list,
     381             :  *                if & only if there isn't already a header with that name.
     382             :  *
     383             :  * Parameters  :
     384             :  *          1  :  the_list = pointer to list
     385             :  *          2  :  name = HTTP header name (e.g. "Content-type")
     386             :  *          3  :  value = HTTP header value (e.g. "text/html")
     387             :  *
     388             :  * Returns     :  JB_ERR_OK on success
     389             :  *                JB_ERR_MEMORY on out-of-memory error.
     390             :  *                On error, the_list will be unchanged.
     391             :  *                "Success" does not indicate whether or not the
     392             :  *                header was already in the list.
     393             :  *
     394             :  *********************************************************************/
     395      223738 : jb_err enlist_unique_header(struct list *the_list, const char *name,
     396             :                             const char *value)
     397             : {
     398      223738 :    jb_err result = JB_ERR_MEMORY;
     399             :    char *header;
     400             :    size_t header_size;
     401             : 
     402      223738 :    assert(the_list);
     403      223738 :    assert(list_is_valid(the_list));
     404      223738 :    assert(name);
     405      223738 :    assert(value);
     406             : 
     407             :    /* + 2 for the ': ', + 1 for the \0 */
     408      223738 :    header_size = strlen(name) + 2 + strlen(value) + 1;
     409      223738 :    header = (char *)malloc(header_size);
     410             : 
     411      223738 :    if (NULL != header)
     412             :    {
     413      223738 :       const size_t bytes_to_compare = strlen(name) + 2;
     414      223738 :       char *p = header;
     415             : 
     416      223738 :       snprintf(header, header_size, "%s: %s", name, value);
     417             :       /*
     418             :        * The trailing "\r\n" is added by list_to_text(),
     419             :        * if the caller passed them anyway, cut the header
     420             :        * at the first one or dump core if this is a debug
     421             :        * build.
     422             :        */
     423             :       do
     424             :       {
     425     7861285 :          if ((*p == '\r') || (*p == '\n'))
     426             :          {
     427           0 :             assert(*p != '\r');
     428           0 :             assert(*p != '\n');
     429           0 :             *p = '\0';
     430             :          }
     431     7861285 :       } while (*p++);
     432      223738 :       result = enlist_unique(the_list, header, bytes_to_compare);
     433      223738 :       free(header);
     434      223738 :       assert(list_is_valid(the_list));
     435             :    }
     436             : 
     437      223738 :    return result;
     438             : 
     439             : }
     440             : 
     441             : 
     442             : /*********************************************************************
     443             :  *
     444             :  * Function    :  list_remove_all
     445             :  *
     446             :  * Description :  Remove all entries from a list.  On return, the_list
     447             :  *                is a valid, empty list.  Note that this is similar
     448             :  *                to destroy_list(), but the difference is that this
     449             :  *                function guarantees that the list structure is still
     450             :  *                valid after the call.
     451             :  *
     452             :  * Parameters  :
     453             :  *          1  :  the_list = pointer to list
     454             :  *
     455             :  * Returns     :  N/A
     456             :  *
     457             :  *********************************************************************/
     458       86736 : void list_remove_all(struct list *the_list)
     459             : {
     460             :    struct list_entry *cur_entry;
     461             :    struct list_entry *next_entry;
     462             : 
     463       86736 :    assert(the_list);
     464       86736 :    assert(list_is_valid(the_list));
     465             : 
     466      815753 :    for (cur_entry = the_list->first; cur_entry ; cur_entry = next_entry)
     467             :    {
     468      729017 :       next_entry = cur_entry->next;
     469      729017 :       freez(cur_entry->str);
     470      729017 :       free(cur_entry);
     471             :    }
     472             : 
     473       86736 :    the_list->first = the_list->last = NULL;
     474             : 
     475       86736 :    assert(list_is_valid(the_list));
     476       86736 : }
     477             : 
     478             : 
     479             : /*********************************************************************
     480             :  *
     481             :  * Function    :  list_to_text
     482             :  *
     483             :  * Description :  "Flatten" a string list into 1 long \r\n delimited string,
     484             :  *                adding an empty line at the end.  NULL entries are ignored.
     485             :  *                This function does not change the_list.
     486             :  *
     487             :  *                XXX: Should probably be renamed as it's only
     488             :  *                useful (and used) to flatten header lists.
     489             :  *
     490             :  * Parameters  :
     491             :  *          1  :  the_list = pointer to list
     492             :  *
     493             :  * Returns     :  NULL on malloc error, else new long string.
     494             :  *                Caller must free() it.
     495             :  *
     496             :  *********************************************************************/
     497       43519 : char *list_to_text(const struct list *the_list)
     498             : {
     499             :    struct list_entry *cur_entry;
     500             :    char *text;
     501             :    size_t text_length;
     502             :    char *cursor;
     503             :    size_t bytes_left;
     504             : 
     505       43519 :    assert(the_list);
     506       43519 :    assert(list_is_valid(the_list));
     507             : 
     508             :    /*
     509             :     * Calculate the length of the final text.
     510             :     * '2' because of the '\r\n' at the end of
     511             :     * each string and at the end of the text.
     512             :     */
     513       43519 :    text_length = 2;
     514      531031 :    for (cur_entry = the_list->first; cur_entry; cur_entry = cur_entry->next)
     515             :    {
     516      487512 :       if (cur_entry->str)
     517             :       {
     518      479630 :          text_length += strlen(cur_entry->str) + 2;
     519             :       }
     520             :    }
     521             : 
     522       43519 :    bytes_left = text_length + 1;
     523             : 
     524       43519 :    text = (char *)malloc(bytes_left);
     525       43519 :    if (NULL == text)
     526             :    {
     527           0 :       return NULL;
     528             :    }
     529             : 
     530       43519 :    cursor = text;
     531             : 
     532      531031 :    for (cur_entry = the_list->first; cur_entry; cur_entry = cur_entry->next)
     533             :    {
     534      487512 :       if (cur_entry->str)
     535             :       {
     536      479630 :          const int written = snprintf(cursor, bytes_left, "%s\r\n", cur_entry->str);
     537             : 
     538      479630 :          assert(written > 0);
     539      479630 :          assert(written < bytes_left);
     540             : 
     541      479630 :          bytes_left -= (size_t)written;
     542      479630 :          cursor += (size_t)written;
     543             :       }
     544             :    }
     545             : 
     546       43519 :    assert(bytes_left == 3);
     547             : 
     548       43519 :    *cursor++ = '\r';
     549       43519 :    *cursor++ = '\n';
     550       43519 :    *cursor   = '\0';
     551             : 
     552       43519 :    assert(text_length == cursor - text);
     553       43519 :    assert(text[text_length] == '\0');
     554             : 
     555       43519 :    return text;
     556             : }
     557             : 
     558             : 
     559             : /*********************************************************************
     560             :  *
     561             :  * Function    :  list_remove_item
     562             :  *
     563             :  * Description :  Remove a string from a specified string list.
     564             :  *
     565             :  * Parameters  :
     566             :  *          1  :  the_list = pointer to list
     567             :  *          2  :  str = string to remove from the list - non-NULL
     568             :  *
     569             :  * Returns     :  Number of times it was removed.
     570             :  *
     571             :  *********************************************************************/
     572       88717 : int list_remove_item(struct list *the_list, const char *str)
     573             : {
     574       88717 :    struct list_entry *prev = NULL;
     575             :    struct list_entry *cur;
     576             :    struct list_entry *next;
     577       88717 :    int count = 0;
     578             : 
     579       88717 :    assert(the_list);
     580       88717 :    assert(list_is_valid(the_list));
     581       88717 :    assert(str);
     582             : 
     583       88717 :    cur = the_list->first;
     584             : 
     585       89198 :    while (cur != NULL)
     586             :    {
     587         481 :       next = cur->next;
     588             : 
     589         481 :       if ((cur->str != NULL) && (0 == strcmp(str, cur->str)))
     590             :       {
     591          45 :          count++;
     592             : 
     593          45 :          if (prev != NULL)
     594             :          {
     595          19 :             prev->next = next;
     596             :          }
     597             :          else
     598             :          {
     599          26 :             the_list->first = next;
     600             :          }
     601          45 :          free((char *)cur->str);
     602          45 :          free(cur);
     603             :       }
     604             :       else
     605             :       {
     606         436 :          prev = cur;
     607             :       }
     608         481 :       cur = next;
     609             :    }
     610             : 
     611       88717 :    the_list->last = prev;
     612             : 
     613       88717 :    assert(list_is_valid(the_list));
     614             : 
     615       88717 :    return count;
     616             : }
     617             : 
     618             : 
     619             : /*********************************************************************
     620             :  *
     621             :  * Function    :  list_remove_list
     622             :  *
     623             :  * Description :  Remove all strings in one list from another list.
     624             :  *                This is currently a brute-force algorithm
     625             :  *                (it compares every pair of strings).
     626             :  *
     627             :  * Parameters  :
     628             :  *          1  :  dest = list to change
     629             :  *          2  :  src = list of strings to remove
     630             :  *
     631             :  * Returns     :  Total number of strings removed.
     632             :  *
     633             :  *********************************************************************/
     634      798799 : int list_remove_list(struct list *dest, const struct list *src)
     635             : {
     636             :    struct list_entry *cur;
     637      798799 :    int count = 0;
     638             : 
     639      798799 :    assert(src);
     640      798799 :    assert(dest);
     641      798799 :    assert(list_is_valid(src));
     642      798799 :    assert(list_is_valid(dest));
     643             : 
     644      798799 :    for (cur = src->first; cur != NULL; cur = cur->next)
     645             :    {
     646           0 :       if (cur->str != NULL)
     647             :       {
     648           0 :          count += list_remove_item(dest, cur->str);
     649             :       }
     650             :    }
     651             : 
     652      798799 :    assert(list_is_valid(src));
     653      798799 :    assert(list_is_valid(dest));
     654             : 
     655      798799 :    return count;
     656             : }
     657             : 
     658             : 
     659             : /*********************************************************************
     660             :  *
     661             :  * Function    :  list_duplicate
     662             :  *
     663             :  * Description :  Copy a string list
     664             :  *
     665             :  * Parameters  :
     666             :  *          1  :  dest = Destination list.  Must be a valid list.
     667             :  *                       All existing entries will be removed.
     668             :  *          1  :  src = pointer to source list for copy.
     669             :  *
     670             :  * Returns     :  JB_ERR_OK on success
     671             :  *                JB_ERR_MEMORY on out-of-memory error.
     672             :  *                On error, dest will be empty.
     673             :  *
     674             :  *********************************************************************/
     675        2489 : jb_err list_duplicate(struct list *dest, const struct list *src)
     676             : {
     677             :    struct list_entry * cur_src;
     678             :    struct list_entry * cur_dest;
     679             : 
     680        2489 :    assert(src);
     681        2489 :    assert(dest);
     682        2489 :    assert(list_is_valid(src));
     683        2489 :    assert(list_is_valid(dest));
     684             : 
     685        2489 :    list_remove_all(dest);
     686             : 
     687             :    /* Need to process first entry specially so we can set dest->first */
     688        2489 :    cur_src = src->first;
     689        2489 :    if (cur_src)
     690             :    {
     691           0 :       cur_dest = dest->first = (struct list_entry *)zalloc(sizeof(*cur_dest));
     692           0 :       if (cur_dest == NULL)
     693             :       {
     694           0 :          destroy_list(dest);
     695             : 
     696           0 :          assert(list_is_valid(src));
     697           0 :          assert(list_is_valid(dest));
     698             : 
     699           0 :          return JB_ERR_MEMORY;
     700             :       }
     701             : 
     702           0 :       if (cur_src->str)
     703             :       {
     704           0 :          cur_dest->str = strdup(cur_src->str);
     705           0 :          if (cur_dest->str == NULL)
     706             :          {
     707           0 :             destroy_list(dest);
     708             : 
     709           0 :             assert(list_is_valid(src));
     710           0 :             assert(list_is_valid(dest));
     711             : 
     712           0 :             return JB_ERR_MEMORY;
     713             :          }
     714             :       }
     715             :       /* else { cur_dest->str = NULL; }  - implied by zalloc */
     716             : 
     717             :       /* Now process the rest */
     718           0 :       for (cur_src = cur_src->next; cur_src; cur_src = cur_src->next)
     719             :       {
     720           0 :          cur_dest = cur_dest->next = (struct list_entry *)zalloc(sizeof(*cur_dest));
     721           0 :          if (cur_dest == NULL)
     722             :          {
     723           0 :             destroy_list(dest);
     724             : 
     725           0 :             assert(list_is_valid(src));
     726           0 :             assert(list_is_valid(dest));
     727             : 
     728           0 :             return JB_ERR_MEMORY;
     729             :          }
     730           0 :          if (cur_src->str)
     731             :          {
     732           0 :             cur_dest->str = strdup(cur_src->str);
     733           0 :             if (cur_dest->str == NULL)
     734             :             {
     735           0 :                destroy_list(dest);
     736             : 
     737           0 :                assert(list_is_valid(src));
     738           0 :                assert(list_is_valid(dest));
     739             : 
     740           0 :                return JB_ERR_MEMORY;
     741             :             }
     742             :          }
     743             :          /* else { cur_dest->str = NULL; }  - implied by zalloc */
     744             :       }
     745             : 
     746           0 :       dest->last = cur_dest;
     747             :    }
     748             : 
     749        2489 :    assert(list_is_valid(src));
     750        2489 :    assert(list_is_valid(dest));
     751             : 
     752        2489 :    return JB_ERR_OK;
     753             : }
     754             : 
     755             : 
     756             : /*********************************************************************
     757             :  *
     758             :  * Function    :  list_append_list_unique
     759             :  *
     760             :  * Description :  Append a string list to another list.
     761             :  *                Duplicate items are not added.
     762             :  *
     763             :  * Parameters  :
     764             :  *          1  :  dest = pointer to destination list for merge.
     765             :  *          2  :  src = pointer to source for merge.
     766             :  *
     767             :  * Returns     :  JB_ERR_OK on success
     768             :  *                JB_ERR_MEMORY on out-of-memory error.
     769             :  *                On error, some (but not all) of src might have
     770             :  *                been copied into dest.
     771             :  *
     772             :  *********************************************************************/
     773      918793 : jb_err list_append_list_unique(struct list *dest, const struct list *src)
     774             : {
     775             :    struct list_entry * cur;
     776             : 
     777      918793 :    assert(src);
     778      918793 :    assert(dest);
     779      918793 :    assert(list_is_valid(src));
     780      918793 :    assert(list_is_valid(dest));
     781             : 
     782     1583679 :    for (cur = src->first; cur; cur = cur->next)
     783             :    {
     784      664886 :       if (cur->str)
     785             :       {
     786      664886 :          if (enlist_unique(dest, cur->str, 0))
     787             :          {
     788           0 :             assert(list_is_valid(src));
     789           0 :             assert(list_is_valid(dest));
     790             : 
     791           0 :             return JB_ERR_MEMORY;
     792             :          }
     793             :       }
     794             :    }
     795             : 
     796      918793 :    assert(list_is_valid(src));
     797      918793 :    assert(list_is_valid(dest));
     798             : 
     799      918793 :    return JB_ERR_OK;
     800             : }
     801             : 
     802             : 
     803             : /*********************************************************************
     804             :  *
     805             :  * Function    :  list_is_empty
     806             :  *
     807             :  * Description :  Test whether a list is empty.  Does not change the list.
     808             :  *
     809             :  * Parameters  :
     810             :  *          1  :  the_list = pointer to list to test.
     811             :  *
     812             :  * Returns     :  Nonzero if the list contains no entries.
     813             :  *
     814             :  *********************************************************************/
     815      851388 : int list_is_empty(const struct list *the_list)
     816             : {
     817      851388 :    assert(the_list);
     818      851388 :    assert(list_is_valid(the_list));
     819             : 
     820      851388 :    return (the_list->first == NULL);
     821             : }
     822             : 
     823             : 
     824             : /*********************************************************************
     825             :  *
     826             :  * Function    :  list_contains_item
     827             :  *
     828             :  * Description :  Tests whether a list item is already set.
     829             :  *                Does not change the list.
     830             :  *
     831             :  * Parameters  :
     832             :  *          1  :  the_list = list to search in
     833             :  *          2  :  str = string to search for
     834             :  *
     835             :  * Returns     :  TRUE if the item was found,
     836             :  *                FALSE otherwise.
     837             :  *
     838             :  *********************************************************************/
     839       32649 : int list_contains_item(const struct list *the_list, const char *str)
     840             : {
     841             :    struct list_entry *entry;
     842             : 
     843       32649 :    assert(the_list);
     844       32649 :    assert(list_is_valid(the_list));
     845       32649 :    assert(str);
     846             : 
     847       44412 :    for (entry = the_list->first; entry != NULL; entry = entry->next)
     848             :    {
     849       22723 :       if (entry->str == NULL)
     850             :       {
     851             :          /*
     852             :           * NULL pointers are allowed in some lists.
     853             :           * For example for csp->headers in case a
     854             :           * header was removed.
     855             :           */
     856           0 :          continue;
     857             :       }
     858             : 
     859       22723 :       if (0 == strcmp(str, entry->str))
     860             :       {
     861             :          /* Item found */
     862       10960 :          return TRUE;
     863             :       }
     864             :    }
     865             : 
     866       21689 :    return FALSE;
     867             : }
     868             : 
     869             : 
     870             : /*********************************************************************
     871             :  *
     872             :  * Function    :  new_map
     873             :  *
     874             :  * Description :  Create a new, empty map.
     875             :  *                Causes program exit if the memory allocation fails.
     876             :  *
     877             :  * Parameters  :  N/A
     878             :  *
     879             :  * Returns     :  A new, empty map
     880             :  *
     881             :  *********************************************************************/
     882      103117 : struct map *new_map(void)
     883             : {
     884      103117 :    struct map *empty_map = zalloc(sizeof(struct map));
     885             : 
     886      103117 :    if (NULL == empty_map)
     887             :    {
     888           0 :       exit(1);
     889             :    }
     890             : 
     891      103117 :    return empty_map;
     892             : 
     893             : }
     894             : 
     895             : 
     896             : /*********************************************************************
     897             :  *
     898             :  * Function    :  free_map
     899             :  *
     900             :  * Description :  Free the memory occupied by a map and its
     901             :  *                dependent strings
     902             :  *
     903             :  * Parameters  :
     904             :  *          1  :  the_map = map to be freed.  May be NULL.
     905             :  *
     906             :  * Returns     :  N/A
     907             :  *
     908             :  *********************************************************************/
     909      103117 : void free_map(struct map *the_map)
     910             : {
     911             :    struct map_entry *cur_entry;
     912             :    struct map_entry *next_entry;
     913             : 
     914      103117 :    if (the_map == NULL)
     915             :    {
     916           0 :       return;
     917             :    }
     918             : 
     919     1013049 :    for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = next_entry)
     920             :    {
     921      909932 :       freez(cur_entry->name);
     922      909932 :       freez(cur_entry->value);
     923             : 
     924      909932 :       next_entry = cur_entry->next;
     925      909932 :       free(cur_entry);
     926             :    }
     927             : 
     928      103117 :    the_map->first = the_map->last = NULL;
     929             : 
     930      103117 :    free(the_map);
     931             : }
     932             : 
     933             : 
     934             : /*********************************************************************
     935             :  *
     936             :  * Function    :  map
     937             :  *
     938             :  * Description :  Add a mapping from given name to given value to a
     939             :  *                given map.
     940             :  *
     941             :  *                Note: Since all strings will be free()d in free_map()
     942             :  *                      later, set the copy flags for constants or
     943             :  *                      strings that will be independently free()d.
     944             :  *
     945             :  *                Note2: This function allows NULL parameters - it
     946             :  *                       returns JB_ERR_MEMORY in that case.
     947             :  *
     948             :  *                Note3: If this function returns JB_ERR_MEMORY,
     949             :  *                       it will free(name) unless you specify
     950             :  *                       name_needs_copying, and similarly it will
     951             :  *                       free(value) unless you specify
     952             :  *                       value_needs_copying.
     953             :  *
     954             :  *                Due to Note2 and Note3 above, the following code
     955             :  *                is legal, and will never crash or leak memory even
     956             :  *                if the system runs out of memory:
     957             :  *
     958             :  *                    err = map(mymap, "xyz", 1, html_encode(somestring), 0);
     959             :  *
     960             :  *                err will be set to JB_ERR_MEMORY if either call runs
     961             :  *                out-of-memory.  Without these features, you would
     962             :  *                need to check the return value of html_encode in the
     963             :  *                above example for NULL, which (at least) doubles the
     964             :  *                amount of error-checking code needed.
     965             :  *
     966             :  * Parameters  :
     967             :  *          1  :  the_map = map to add to
     968             :  *          2  :  name = name to add
     969             :  *          3  :  name_needs_copying = flag set if a copy of name should be used
     970             :  *          4  :  value = value to add
     971             :  *          5  :  value_needs_copying = flag set if a copy of value should be used
     972             :  *
     973             :  * Returns     :  JB_ERR_OK on success
     974             :  *                JB_ERR_MEMORY on out-of-memory error.
     975             :  *
     976             :  *********************************************************************/
     977      910187 : jb_err map(struct map *the_map,
     978             :            const char *name, int name_needs_copying,
     979             :            const char *value, int value_needs_copying)
     980             : {
     981             :    struct map_entry *new_entry;
     982             : 
     983      910187 :    assert(the_map);
     984             : 
     985      910187 :    if ( (NULL == value)
     986      910079 :      || (NULL == name)
     987      910079 :      || (NULL == (new_entry = zalloc(sizeof(*new_entry)))))
     988             :    {
     989         108 :       if ((name != NULL) && (!name_needs_copying))
     990             :       {
     991           0 :           free((char *)name);
     992             :       }
     993         108 :       if ((value != NULL) && (!value_needs_copying))
     994             :       {
     995           0 :           free((char *)value);
     996             :       }
     997         108 :       return JB_ERR_MEMORY;
     998             :    }
     999             : 
    1000      910079 :    if (name_needs_copying)
    1001             :    {
    1002      831879 :       if (NULL == (name = strdup(name)))
    1003             :       {
    1004           0 :          free(new_entry);
    1005           0 :          if (!value_needs_copying)
    1006             :          {
    1007           0 :              free((char *)value);
    1008             :          }
    1009           0 :          return JB_ERR_MEMORY;
    1010             :       }
    1011             :    }
    1012             : 
    1013      910079 :    if (value_needs_copying)
    1014             :    {
    1015      508112 :       if (NULL == (value = strdup(value)))
    1016             :       {
    1017           0 :          free((char *)name);
    1018           0 :          free(new_entry);
    1019           0 :          return JB_ERR_MEMORY;
    1020             :       }
    1021             :    }
    1022             : 
    1023      910079 :    new_entry->name = name;
    1024      910079 :    new_entry->value = value;
    1025             :    /* new_entry->next = NULL;  - implied by zalloc */
    1026             : 
    1027      910079 :    if (the_map->last)
    1028             :    {
    1029      817011 :       the_map->last->next = new_entry;
    1030      817011 :       the_map->last = new_entry;
    1031             :    }
    1032             :    else
    1033             :    {
    1034       93068 :       the_map->first = new_entry;
    1035       93068 :       the_map->last = new_entry;
    1036             :    }
    1037             : 
    1038      910079 :    return JB_ERR_OK;
    1039             : }
    1040             : 
    1041             : 
    1042             : /*********************************************************************
    1043             :  *
    1044             :  * Function    :  unmap
    1045             :  *
    1046             :  * Description :  Remove all map_entry structs with a given name from
    1047             :  *                a given map.
    1048             :  *
    1049             :  * Parameters  :
    1050             :  *          1  :  the_map = map to look in
    1051             :  *          2  :  name = name to unmap
    1052             :  *
    1053             :  * Returns     :  JB_ERR_OK
    1054             :  *
    1055             :  *********************************************************************/
    1056         246 : jb_err unmap(struct map *the_map, const char *name)
    1057             : {
    1058             :    struct map_entry *cur_entry, *last_entry;
    1059             : 
    1060         246 :    assert(the_map);
    1061         246 :    assert(name);
    1062             : 
    1063         246 :    last_entry = NULL;
    1064             : 
    1065         996 :    for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = cur_entry->next)
    1066             :    {
    1067         827 :       if (!strcmp(name, cur_entry->name))
    1068             :       {
    1069             :          /*
    1070             :           * Update the incoming pointer
    1071             :           */
    1072         147 :          if (cur_entry == the_map->first)
    1073             :          {
    1074          77 :             the_map->first = cur_entry->next;
    1075             :          }
    1076             :          else
    1077             :          {
    1078          70 :             last_entry->next = cur_entry->next;
    1079             :          }
    1080             : 
    1081             :          /*
    1082             :           * Update the map's last pointer
    1083             :           */
    1084         147 :          if (cur_entry == the_map->last)
    1085             :          {
    1086          81 :             the_map->last = last_entry;
    1087             :          }
    1088             : 
    1089             :          /*
    1090             :           * Free the map_entry
    1091             :           */
    1092         147 :          freez(cur_entry->name);
    1093         147 :          freez(cur_entry->value);
    1094         147 :          freez(cur_entry);
    1095         147 :          if (last_entry == NULL)
    1096             :          {
    1097             :             /* The map only had a single entry which has just been removed. */
    1098          77 :             break;
    1099             :          }
    1100          70 :          cur_entry = last_entry;
    1101             :       }
    1102             :       else
    1103             :       {
    1104         680 :          last_entry = cur_entry;
    1105             :       }
    1106             :    }
    1107         246 :    return JB_ERR_OK;
    1108             : }
    1109             : 
    1110             : 
    1111             : /*********************************************************************
    1112             :  *
    1113             :  * Function    :  lookup
    1114             :  *
    1115             :  * Description :  Look up an item with a given name in a map, and
    1116             :  *                return its value
    1117             :  *
    1118             :  * Parameters  :
    1119             :  *          1  :  the_map = map to look in
    1120             :  *          2  :  name = name parameter to look for
    1121             :  *
    1122             :  * Returns     :  the value if found, else the empty string.
    1123             :  *                Return value is allocated as part of the map, so
    1124             :  *                it is freed when the map is destroyed.  Caller
    1125             :  *                must not free or modify it.
    1126             :  *
    1127             :  *********************************************************************/
    1128       60133 : const char *lookup(const struct map *the_map, const char *name)
    1129             : {
    1130             :    const struct map_entry *cur_entry;
    1131             : 
    1132       60133 :    assert(the_map);
    1133       60133 :    assert(name);
    1134             : 
    1135     2304792 :    for (cur_entry = the_map->first; cur_entry != NULL; cur_entry = cur_entry->next)
    1136             :    {
    1137     2267783 :       if (!strcmp(name, cur_entry->name))
    1138             :       {
    1139       23124 :          return cur_entry->value;
    1140             :       }
    1141             :    }
    1142       37009 :    return "";
    1143             : }
    1144             : 
    1145             : 
    1146             : /*
    1147             :   Local Variables:
    1148             :   tab-width: 3
    1149             :   end:
    1150             : */

Generated by: LCOV version 1.14