1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23 #include "curl_setup.h" 24 25 #include <curl/curl.h> 26 27 #include "llist.h" 28 #include "curl_memory.h" 29 30 /* this must be the last include file */ 31 #include "memdebug.h" 32 33 /* 34 * @unittest: 1300 35 */ 36 static void 37 llist_init(struct curl_llist *l, curl_llist_dtor dtor) 38 { 39 l->size = 0; 40 l->dtor = dtor; 41 l->head = NULL; 42 l->tail = NULL; 43 } 44 45 struct curl_llist * 46 Curl_llist_alloc(curl_llist_dtor dtor) 47 { 48 struct curl_llist *list; 49 50 list = malloc(sizeof(struct curl_llist)); 51 if(!list) 52 return NULL; 53 54 llist_init(list, dtor); 55 56 return list; 57 } 58 59 /* 60 * Curl_llist_insert_next() 61 * 62 * Inserts a new list element after the given one 'e'. If the given existing 63 * entry is NULL and the list already has elements, the new one will be 64 * inserted first in the list. 65 * 66 * Returns: 1 on success and 0 on failure. 67 * 68 * @unittest: 1300 69 */ 70 int 71 Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e, 72 const void *p) 73 { 74 struct curl_llist_element *ne = malloc(sizeof(struct curl_llist_element)); 75 if(!ne) 76 return 0; 77 78 ne->ptr = (void *) p; 79 if(list->size == 0) { 80 list->head = ne; 81 list->head->prev = NULL; 82 list->head->next = NULL; 83 list->tail = ne; 84 } 85 else { 86 /* if 'e' is NULL here, we insert the new element first in the list */ 87 ne->next = e?e->next:list->head; 88 ne->prev = e; 89 if(!e) { 90 list->head->prev = ne; 91 list->head = ne; 92 } 93 else if(e->next) { 94 e->next->prev = ne; 95 } 96 else { 97 list->tail = ne; 98 } 99 if(e) 100 e->next = ne; 101 } 102 103 ++list->size; 104 105 return 1; 106 } 107 108 /* 109 * @unittest: 1300 110 */ 111 int 112 Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, 113 void *user) 114 { 115 if(e == NULL || list->size == 0) 116 return 1; 117 118 if(e == list->head) { 119 list->head = e->next; 120 121 if(list->head == NULL) 122 list->tail = NULL; 123 else 124 e->next->prev = NULL; 125 } 126 else { 127 e->prev->next = e->next; 128 if(!e->next) 129 list->tail = e->prev; 130 else 131 e->next->prev = e->prev; 132 } 133 134 list->dtor(user, e->ptr); 135 136 e->ptr = NULL; 137 e->prev = NULL; 138 e->next = NULL; 139 140 free(e); 141 --list->size; 142 143 return 1; 144 } 145 146 void 147 Curl_llist_destroy(struct curl_llist *list, void *user) 148 { 149 if(list) { 150 while(list->size > 0) 151 Curl_llist_remove(list, list->tail, user); 152 153 free(list); 154 } 155 } 156 157 size_t 158 Curl_llist_count(struct curl_llist *list) 159 { 160 return list->size; 161 } 162 163 /* 164 * @unittest: 1300 165 */ 166 int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e, 167 struct curl_llist *to_list, 168 struct curl_llist_element *to_e) 169 { 170 /* Remove element from list */ 171 if(e == NULL || list->size == 0) 172 return 0; 173 174 if(e == list->head) { 175 list->head = e->next; 176 177 if(list->head == NULL) 178 list->tail = NULL; 179 else 180 e->next->prev = NULL; 181 } 182 else { 183 e->prev->next = e->next; 184 if(!e->next) 185 list->tail = e->prev; 186 else 187 e->next->prev = e->prev; 188 } 189 190 --list->size; 191 192 /* Add element to to_list after to_e */ 193 if(to_list->size == 0) { 194 to_list->head = e; 195 to_list->head->prev = NULL; 196 to_list->head->next = NULL; 197 to_list->tail = e; 198 } 199 else { 200 e->next = to_e->next; 201 e->prev = to_e; 202 if(to_e->next) { 203 to_e->next->prev = e; 204 } 205 else { 206 to_list->tail = e; 207 } 208 to_e->next = e; 209 } 210 211 ++to_list->size; 212 213 return 1; 214 } 215