1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "atf-c/error.h" 34 #include "atf-c/utils.h" 35 36 #include "list.h" 37 #include "sanity.h" 38 39 /* --------------------------------------------------------------------- 40 * Auxiliary functions. 41 * --------------------------------------------------------------------- */ 42 43 struct list_entry { 44 struct list_entry *m_prev; 45 struct list_entry *m_next; 46 void *m_object; 47 bool m_managed; 48 }; 49 50 static 51 atf_list_citer_t 52 entry_to_citer(const atf_list_t *l, const struct list_entry *le) 53 { 54 atf_list_citer_t iter; 55 iter.m_list = l; 56 iter.m_entry = le; 57 return iter; 58 } 59 60 static 61 atf_list_iter_t 62 entry_to_iter(atf_list_t *l, struct list_entry *le) 63 { 64 atf_list_iter_t iter; 65 iter.m_list = l; 66 iter.m_entry = le; 67 return iter; 68 } 69 70 static 71 struct list_entry * 72 new_entry(void *object, bool managed) 73 { 74 struct list_entry *le; 75 76 le = (struct list_entry *)malloc(sizeof(*le)); 77 if (le != NULL) { 78 le->m_prev = le->m_next = NULL; 79 le->m_object = object; 80 le->m_managed = managed; 81 } else 82 free(object); 83 84 return le; 85 } 86 87 static 88 void 89 delete_entry(struct list_entry *le) 90 { 91 if (le->m_managed) 92 free(le->m_object); 93 94 free(le); 95 } 96 97 static 98 struct list_entry * 99 new_entry_and_link(void *object, bool managed, struct list_entry *prev, 100 struct list_entry *next) 101 { 102 struct list_entry *le; 103 104 le = new_entry(object, managed); 105 if (le != NULL) { 106 le->m_prev = prev; 107 le->m_next = next; 108 109 prev->m_next = le; 110 next->m_prev = le; 111 } 112 113 return le; 114 } 115 116 /* --------------------------------------------------------------------- 117 * The "atf_list_citer" type. 118 * --------------------------------------------------------------------- */ 119 120 /* 121 * Getters. 122 */ 123 124 const void * 125 atf_list_citer_data(const atf_list_citer_t citer) 126 { 127 const struct list_entry *le = citer.m_entry; 128 PRE(le != NULL); 129 return le->m_object; 130 } 131 132 atf_list_citer_t 133 atf_list_citer_next(const atf_list_citer_t citer) 134 { 135 const struct list_entry *le = citer.m_entry; 136 atf_list_citer_t newciter; 137 138 PRE(le != NULL); 139 140 newciter = citer; 141 newciter.m_entry = le->m_next; 142 143 return newciter; 144 } 145 146 bool 147 atf_equal_list_citer_list_citer(const atf_list_citer_t i1, 148 const atf_list_citer_t i2) 149 { 150 return i1.m_list == i2.m_list && i1.m_entry == i2.m_entry; 151 } 152 153 /* --------------------------------------------------------------------- 154 * The "atf_list_iter" type. 155 * --------------------------------------------------------------------- */ 156 157 /* 158 * Getters. 159 */ 160 161 void * 162 atf_list_iter_data(const atf_list_iter_t iter) 163 { 164 const struct list_entry *le = iter.m_entry; 165 PRE(le != NULL); 166 return le->m_object; 167 } 168 169 atf_list_iter_t 170 atf_list_iter_next(const atf_list_iter_t iter) 171 { 172 const struct list_entry *le = iter.m_entry; 173 atf_list_iter_t newiter; 174 175 PRE(le != NULL); 176 177 newiter = iter; 178 newiter.m_entry = le->m_next; 179 180 return newiter; 181 } 182 183 bool 184 atf_equal_list_iter_list_iter(const atf_list_iter_t i1, 185 const atf_list_iter_t i2) 186 { 187 return i1.m_list == i2.m_list && i1.m_entry == i2.m_entry; 188 } 189 190 /* --------------------------------------------------------------------- 191 * The "atf_list" type. 192 * --------------------------------------------------------------------- */ 193 194 /* 195 * Constructors and destructors. 196 */ 197 198 atf_error_t 199 atf_list_init(atf_list_t *l) 200 { 201 struct list_entry *lebeg, *leend; 202 203 lebeg = new_entry(NULL, false); 204 if (lebeg == NULL) { 205 return atf_no_memory_error(); 206 } 207 208 leend = new_entry(NULL, false); 209 if (leend == NULL) { 210 free(lebeg); 211 return atf_no_memory_error(); 212 } 213 214 lebeg->m_next = leend; 215 lebeg->m_prev = NULL; 216 217 leend->m_next = NULL; 218 leend->m_prev = lebeg; 219 220 l->m_size = 0; 221 l->m_begin = lebeg; 222 l->m_end = leend; 223 224 return atf_no_error(); 225 } 226 227 void 228 atf_list_fini(atf_list_t *l) 229 { 230 struct list_entry *le; 231 size_t freed; 232 233 le = (struct list_entry *)l->m_begin; 234 freed = 0; 235 while (le != NULL) { 236 struct list_entry *lenext; 237 238 lenext = le->m_next; 239 delete_entry(le); 240 le = lenext; 241 242 freed++; 243 } 244 INV(freed == l->m_size + 2); 245 } 246 247 /* 248 * Getters. 249 */ 250 251 atf_list_iter_t 252 atf_list_begin(atf_list_t *l) 253 { 254 struct list_entry *le = l->m_begin; 255 return entry_to_iter(l, le->m_next); 256 } 257 258 atf_list_citer_t 259 atf_list_begin_c(const atf_list_t *l) 260 { 261 const struct list_entry *le = l->m_begin; 262 return entry_to_citer(l, le->m_next); 263 } 264 265 atf_list_iter_t 266 atf_list_end(atf_list_t *l) 267 { 268 return entry_to_iter(l, l->m_end); 269 } 270 271 atf_list_citer_t 272 atf_list_end_c(const atf_list_t *l) 273 { 274 return entry_to_citer(l, l->m_end); 275 } 276 277 void * 278 atf_list_index(atf_list_t *list, const size_t idx) 279 { 280 atf_list_iter_t iter; 281 282 PRE(idx < atf_list_size(list)); 283 284 iter = atf_list_begin(list); 285 { 286 size_t pos = 0; 287 while (pos < idx && 288 !atf_equal_list_iter_list_iter((iter), atf_list_end(list))) { 289 iter = atf_list_iter_next(iter); 290 pos++; 291 } 292 } 293 return atf_list_iter_data(iter); 294 } 295 296 const void * 297 atf_list_index_c(const atf_list_t *list, const size_t idx) 298 { 299 atf_list_citer_t iter; 300 301 PRE(idx < atf_list_size(list)); 302 303 iter = atf_list_begin_c(list); 304 { 305 size_t pos = 0; 306 while (pos < idx && 307 !atf_equal_list_citer_list_citer((iter), 308 atf_list_end_c(list))) { 309 iter = atf_list_citer_next(iter); 310 pos++; 311 } 312 } 313 return atf_list_citer_data(iter); 314 } 315 316 size_t 317 atf_list_size(const atf_list_t *l) 318 { 319 return l->m_size; 320 } 321 322 char ** 323 atf_list_to_charpp(const atf_list_t *l) 324 { 325 char **array; 326 atf_list_citer_t iter; 327 size_t i; 328 329 array = malloc(sizeof(char *) * (atf_list_size(l) + 1)); 330 if (array == NULL) 331 goto out; 332 333 i = 0; 334 atf_list_for_each_c(iter, l) { 335 array[i] = strdup((const char *)atf_list_citer_data(iter)); 336 if (array[i] == NULL) { 337 atf_utils_free_charpp(array); 338 array = NULL; 339 goto out; 340 } 341 342 i++; 343 } 344 array[i] = NULL; 345 346 out: 347 return array; 348 } 349 350 /* 351 * Modifiers. 352 */ 353 354 atf_error_t 355 atf_list_append(atf_list_t *l, void *data, bool managed) 356 { 357 struct list_entry *le, *next, *prev; 358 atf_error_t err; 359 360 next = (struct list_entry *)l->m_end; 361 prev = next->m_prev; 362 le = new_entry_and_link(data, managed, prev, next); 363 if (le == NULL) 364 err = atf_no_memory_error(); 365 else { 366 l->m_size++; 367 err = atf_no_error(); 368 } 369 370 return err; 371 } 372 373 void 374 atf_list_append_list(atf_list_t *l, atf_list_t *src) 375 { 376 struct list_entry *e1, *e2, *ghost1, *ghost2; 377 378 ghost1 = (struct list_entry *)l->m_end; 379 ghost2 = (struct list_entry *)src->m_begin; 380 381 e1 = ghost1->m_prev; 382 e2 = ghost2->m_next; 383 384 delete_entry(ghost1); 385 delete_entry(ghost2); 386 387 e1->m_next = e2; 388 e2->m_prev = e1; 389 390 l->m_end = src->m_end; 391 l->m_size += src->m_size; 392 } 393