1 /*============================================================================ 2 epub2txt v2 3 list.c 4 Copyright (c)2000-2020 Kevin Boone, GPL v3.0 5 ============================================================================*/ 6 7 8 #include 9 #include 10 #include 11 12 #if !defined(__MACH__) 13 #include 14 #endif 15 16 #include 17 #include "list.h" 18 19 typedef struct _ListItem 20 { 21 struct _ListItem *next; 22 void *data; 23 } ListItem; 24 25 struct _List 26 { 27 pthread_mutex_t mutex; 28 ListItemFreeFn free_fn; 29 ListItem *head; 30 }; 31 32 /*========================================================================== 33 list_create 34 *==========================================================================*/ 35 List *list_create (ListItemFreeFn free_fn) 36 { 37 List *list = malloc (sizeof (List)); 38 memset (list, 0, sizeof (List)); 39 list->free_fn = free_fn; 40 pthread_mutex_init (&list->mutex, NULL); 41 return list; 42 } 43 44 /*========================================================================== 45 list_create_strings 46 *==========================================================================*/ 47 List *list_create_strings (void) 48 { 49 return list_create (free); 50 } 51 52 /*========================================================================== 53 list_destroy 54 *==========================================================================*/ 55 void list_destroy (List *self) 56 { 57 if (!self) return; 58 59 pthread_mutex_lock (&self->mutex); 60 ListItem *l = self->head; 61 while (l) 62 { 63 if (self->free_fn) 64 self->free_fn (l->data); 65 ListItem *temp = l; 66 l = l->next; 67 free (temp); 68 } 69 70 pthread_mutex_unlock (&self->mutex); 71 pthread_mutex_destroy (&self->mutex); 72 free (self); 73 } 74 75 76 /*========================================================================== 77 list_prepend 78 Note that the caller must not modify or free the item added to the list. It 79 will remain on the list until free'd by the list itself, by calling 80 the supplied free function 81 *==========================================================================*/ 82 void list_prepend (List *self, void *item) 83 { 84 pthread_mutex_lock (&self->mutex); 85 ListItem *i = malloc (sizeof (ListItem)); 86 i->data = item; 87 i->next = NULL; 88 89 if (self->head) 90 { 91 i->next = self->head; 92 self->head = i; 93 } 94 else 95 { 96 self->head = i; 97 } 98 pthread_mutex_unlock (&self->mutex); 99 } 100 101 102 /*========================================================================== 103 list_append 104 Note that the caller must not modify or free the item added to the list. It 105 will remain on the list until free'd by the list itself, by calling 106 the supplied free function 107 *==========================================================================*/ 108 void list_append (List *self, void *item) 109 { 110 pthread_mutex_lock (&self->mutex); 111 ListItem *i = malloc (sizeof (ListItem)); 112 i->data = item; 113 i->next = NULL; 114 115 if (self->head) 116 { 117 ListItem *l = self->head; 118 while (l->next) 119 l = l->next; 120 l->next = i; 121 } 122 else 123 { 124 self->head = i; 125 } 126 pthread_mutex_unlock (&self->mutex); 127 } 128 129 130 /*========================================================================== 131 list_length 132 *==========================================================================*/ 133 int list_length (List *self) 134 { 135 if (!self) return 0; 136 137 pthread_mutex_lock (&self->mutex); 138 ListItem *l = self->head; 139 int i = 0; 140 while (l != NULL) 141 { 142 l = l->next; 143 i++; 144 } 145 146 pthread_mutex_unlock (&self->mutex); 147 return i; 148 } 149 150 /*========================================================================== 151 list_get 152 *==========================================================================*/ 153 void *list_get (List *self, int index) 154 { 155 if (!self) return NULL; 156 157 pthread_mutex_lock (&self->mutex); 158 ListItem *l = self->head; 159 int i = 0; 160 while (l != NULL && i != index) 161 { 162 l = l->next; 163 i++; 164 } 165 pthread_mutex_unlock (&self->mutex); 166 167 return l->data; 168 } 169 170 171 /*========================================================================== 172 list_dump 173 *==========================================================================*/ 174 void list_dump (List *self) 175 { 176 int i, l = list_length (self); 177 for (i = 0; i < l; i++) 178 { 179 const char *s = list_get (self, i); 180 printf ("%s\n", s); 181 } 182 } 183 184 185 /*========================================================================== 186 list_contains 187 *==========================================================================*/ 188 BOOL list_contains (List *self, const void *item, ListCompareFn fn) 189 { 190 if (!self) return FALSE; 191 pthread_mutex_lock (&self->mutex); 192 ListItem *l = self->head; 193 BOOL found = FALSE; 194 while (l != NULL && !found) 195 { 196 if (fn (l->data, item) == 0) found = TRUE; 197 l = l->next; 198 } 199 pthread_mutex_unlock (&self->mutex); 200 return found; 201 } 202 203 204 /*========================================================================== 205 list_contains_string 206 *==========================================================================*/ 207 BOOL list_contains_string (List *self, const char *item) 208 { 209 return list_contains (self, item, (ListCompareFn)strcmp); 210 } 211 212 213 /*========================================================================== 214 list_remove 215 IMPORTANT -- The "item" argument cannot be a direct reference to an 216 item already in the list. If that items is removed from the list its 217 memory will be freed. The "item" argument will this be an invalid 218 memory reference, and the program will crash. It is necessary 219 to copy the item first. 220 *==========================================================================*/ 221 void list_remove (List *self, const void *item, ListCompareFn fn) 222 { 223 if (!self) return; 224 pthread_mutex_lock (&self->mutex); 225 ListItem *l = self->head; 226 ListItem *last_good = NULL; 227 while (l != NULL) 228 { 229 if (fn (l->data, item) == 0) 230 { 231 if (l == self->head) 232 { 233 self->head = l->next; // l-> next might be null 234 } 235 else 236 { 237 if (last_good) last_good->next = l->next; 238 } 239 self->free_fn (l->data); 240 ListItem *temp = l->next; 241 free (l); 242 l = temp; 243 } 244 else 245 { 246 last_good = l; 247 l = l->next; 248 } 249 } 250 pthread_mutex_unlock (&self->mutex); 251 } 252 253 /*========================================================================== 254 list_remove_string 255 *==========================================================================*/ 256 void list_remove_string (List *self, const char *item) 257 { 258 list_remove (self, item, (ListCompareFn)strcmp); 259 } 260 261 262 /*========================================================================== 263 list_clone 264 *==========================================================================*/ 265 List *list_clone (List *self, ListCopyFn copyFn) 266 { 267 ListItemFreeFn free_fn = self->free_fn; 268 List *new = list_create (free_fn); 269 270 pthread_mutex_lock (&self->mutex); 271 ListItem *l = self->head; 272 while (l != NULL) 273 { 274 void *data = copyFn (l->data); 275 list_append (new, data); 276 l = l->next; 277 } 278 pthread_mutex_unlock (&self->mutex); 279 280 return new; 281 } 282 283 284