1/* 2 * Copyright (c) 2012-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <string.h> 25#include <stdio.h> 26#include <stdbool.h> 27#include <time.h> 28#include <sys/time.h> 29#include <asl.h> 30#include <asl_core.h> 31#include <asl_msg.h> 32#include <asl_msg_list.h> 33 34asl_msg_list_t * 35asl_msg_list_new(void) 36{ 37 asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); 38 if (out == NULL) return NULL; 39 40 out->asl_type = ASL_TYPE_LIST; 41 out->refcount = 1; 42 43 return out; 44} 45 46asl_msg_list_t * 47asl_msg_list_new_count(uint32_t n) 48{ 49 asl_msg_list_t *out = (asl_msg_list_t *)calloc(1, sizeof(asl_msg_list_t)); 50 if (out == NULL) return NULL; 51 52 out->asl_type = ASL_TYPE_LIST; 53 out->refcount = 1; 54 out->count = n; 55 56 out->msg = (asl_msg_t **)reallocf(out->msg, out->count * sizeof(asl_msg_t *)); 57 if (out->msg == NULL) 58 { 59 free(out); 60 return NULL; 61 } 62 63 return out; 64} 65 66asl_msg_list_t * 67asl_msg_list_retain(asl_msg_list_t *list) 68{ 69 if (list == NULL) return NULL; 70 asl_retain((asl_object_t)list); 71 return list; 72} 73 74void 75asl_msg_list_release(asl_msg_list_t *list) 76{ 77 if (list == NULL) return; 78 asl_release((asl_object_t)list); 79} 80 81char * 82asl_msg_list_to_string(asl_msg_list_t *list, uint32_t *len) 83{ 84 uint32_t i; 85 char tmp[16]; 86 char *out; 87 asl_string_t *str; 88 89 if (list == NULL) return NULL; 90 if (list->count == 0) return NULL; 91 if (list->msg == NULL) return NULL; 92 93 str = asl_string_new(ASL_ENCODE_ASL); 94 if (str == NULL) return NULL; 95 96 snprintf(tmp, sizeof(tmp), "%u", list->count); 97 asl_string_append(str, tmp); 98 asl_string_append_char_no_encoding(str, '\n'); 99 100 for (i = 0; i < list->count; i++) 101 { 102 asl_string_append_asl_msg(str, list->msg[i]); 103 asl_string_append_char_no_encoding(str, '\n'); 104 } 105 106 *len = asl_string_length(str); 107 out = asl_string_release_return_bytes(str); 108 return out; 109} 110 111asl_string_t * 112asl_msg_list_to_asl_string(asl_msg_list_t *list, uint32_t encoding) 113{ 114 uint32_t i; 115 char tmp[16]; 116 asl_string_t *str; 117 118 if (list == NULL) return NULL; 119 if (list->count == 0) return NULL; 120 if (list->msg == NULL) return NULL; 121 122 str = asl_string_new(encoding); 123 if (str == NULL) return NULL; 124 125 snprintf(tmp, sizeof(tmp), "%u", list->count); 126 asl_string_append(str, tmp); 127 asl_string_append_char_no_encoding(str, '\n'); 128 129 for (i = 0; i < list->count; i++) 130 { 131 asl_string_append_asl_msg(str, list->msg[i]); 132 asl_string_append_char_no_encoding(str, '\n'); 133 } 134 135 return str; 136} 137 138asl_msg_list_t * 139asl_msg_list_from_string(const char *buf) 140{ 141 uint32_t i, n; 142 const char *p; 143 asl_msg_list_t *out; 144 asl_msg_t *m; 145 146 if (buf == NULL) return NULL; 147 p = buf; 148 149 n = atoi(buf); 150 if (n == 0) return NULL; 151 152 out = asl_msg_list_new(); 153 if (out == NULL) return NULL; 154 155 for (i = 0; i < n; i++) 156 { 157 p = strchr(p, '\n'); 158 if (p == NULL) 159 { 160 asl_msg_list_release(out); 161 return NULL; 162 } 163 164 p++; 165 166 m = asl_msg_from_string(p); 167 if (m == NULL) 168 { 169 asl_msg_list_release(out); 170 return NULL; 171 } 172 173 asl_msg_list_append(out, m); 174 asl_msg_release(m); 175 } 176 177 return out; 178} 179 180void 181asl_msg_list_insert(asl_msg_list_t *list, uint32_t x, void *obj) 182{ 183 uint32_t i, j; 184 asl_object_private_t *oo = (asl_object_private_t *)obj; 185 186 if (list == NULL) return; 187 if (obj == NULL) return; 188 if (list->count == UINT32_MAX) return; 189 190 if (x >= list->count) x = list->count; 191 192 uint32_t type = asl_get_type((asl_object_t)oo); 193 uint32_t count = 0; 194 195 if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) count = 1; 196 else count = asl_object_count(oo); 197 198 if (count == 0) return; 199 200 uint64_t check = list->count; 201 check += count; 202 if (check > UINT32_MAX) return; 203 204 list->msg = (asl_msg_t **)reallocf(list->msg, (list->count + count) * sizeof(asl_msg_t *)); 205 if (list->msg == NULL) 206 { 207 list->count = 0; 208 list->curr = 0; 209 return; 210 } 211 212 for (i = list->count, j = i - 1; i > x; i--, j--) list->msg[i] = list->msg[j]; 213 214 asl_object_set_iteration_index(oo, 0); 215 216 if ((type == ASL_TYPE_MSG) || (type == ASL_TYPE_QUERY)) 217 { 218 list->msg[x] = (asl_msg_t *)asl_retain((asl_object_t)oo); 219 } 220 else 221 { 222 for (i = x, j = 0; j < count; i++, j++) list->msg[i] = (asl_msg_t *)asl_object_next(oo); 223 } 224 225 asl_object_set_iteration_index(oo, 0); 226 227 list->count += count; 228} 229 230void 231asl_msg_list_append(asl_msg_list_t *list, void *obj) 232{ 233 asl_msg_list_insert(list, UINT32_MAX, obj); 234} 235 236void 237asl_msg_list_prepend(asl_msg_list_t *list, void *obj) 238{ 239 asl_msg_list_insert(list, 0, obj); 240} 241 242size_t 243asl_msg_list_count(asl_msg_list_t *list) 244{ 245 if (list == NULL) return 0; 246 return list->count; 247} 248 249asl_msg_t * 250asl_msg_list_get_index(asl_msg_list_t *list, size_t index) 251{ 252 asl_msg_t *out; 253 254 if (list == NULL) return NULL; 255 if (index >= list->count) return NULL; 256 if (list->msg == NULL) 257 { 258 list->curr = 0; 259 list->count = 0; 260 return NULL; 261 } 262 263 out = list->msg[index]; 264 return out; 265} 266 267void 268asl_msg_list_remove_index(asl_msg_list_t *list, size_t index) 269{ 270 uint32_t i, j; 271 272 if (list == NULL) return; 273 if (index >= list->count) return; 274 if (list->msg == NULL) 275 { 276 list->curr = 0; 277 list->count = 0; 278 return; 279 } 280 281 asl_msg_release(list->msg[index]); 282 283 for (i = index + 1, j = index; i < list->count; i++) list->msg[j] = list->msg[i]; 284 list->count--; 285 286 list->msg = (asl_msg_t **)reallocf(list->msg, list->count * sizeof(asl_msg_t *)); 287 if (list->msg == NULL) 288 { 289 list->count = 0; 290 list->curr = 0; 291 } 292} 293 294asl_msg_t * 295asl_msg_list_next(asl_msg_list_t *list) 296{ 297 asl_msg_t *out; 298 299 if (list == NULL) return NULL; 300 if (list->curr >= list->count) return NULL; 301 if (list->msg == NULL) 302 { 303 list->curr = 0; 304 list->count = 0; 305 return NULL; 306 } 307 308 out = list->msg[list->curr]; 309 list->curr++; 310 return out; 311} 312 313asl_msg_t * 314asl_msg_list_prev(asl_msg_list_t *list) 315{ 316 asl_msg_t *out; 317 318 if (list == NULL) return NULL; 319 if (list->curr == 0) return NULL; 320 if (list->msg == NULL) 321 { 322 list->curr = 0; 323 list->count = 0; 324 return NULL; 325 } 326 327 if (list->curr > list->count) list->curr = list->count; 328 329 list->curr--; 330 out = list->msg[list->curr]; 331 return out; 332} 333 334void 335asl_msg_list_reset_iteration(asl_msg_list_t *list, size_t position) 336{ 337 if (list == NULL) return; 338 339 if (position > list->count) position = SIZE_MAX; 340 list->curr = position; 341} 342 343asl_msg_list_t * 344asl_msg_list_search(asl_msg_list_t *list, asl_msg_t *query) 345{ 346 uint32_t i; 347 asl_msg_list_t *out = NULL; 348 349 if (list == NULL) return NULL; 350 351 if (list->msg == NULL) 352 { 353 list->curr = 0; 354 list->count = 0; 355 return NULL; 356 } 357 358 for (i = 0; i < list->count; i++) 359 { 360 int match = 0; 361 if (query == NULL) match = 1; 362 else match = asl_msg_cmp(query, list->msg[i]); 363 364 if (match != 0) 365 { 366 if (out == NULL) out = asl_msg_list_new(); 367 if (out == NULL) return NULL; 368 asl_msg_list_append(out, list->msg[i]); 369 } 370 } 371 372 return out; 373} 374 375asl_msg_list_t * 376asl_msg_list_match(asl_msg_list_t *list, asl_msg_list_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction) 377{ 378 uint32_t i, end, n = 0; 379 struct timeval now, finish; 380 asl_msg_list_t *out = NULL; 381 382 if (list == NULL) return NULL; 383 if (list->msg == NULL) 384 { 385 list->curr = 0; 386 list->count = 0; 387 return NULL; 388 } 389 390 /* start the timer if a timeout was specified */ 391 memset(&finish, 0, sizeof(struct timeval)); 392 if (duration != 0) 393 { 394 if (gettimeofday(&finish, NULL) == 0) 395 { 396 finish.tv_sec += (duration / USEC_PER_SEC); 397 finish.tv_usec += (duration % USEC_PER_SEC); 398 if (finish.tv_usec > USEC_PER_SEC) 399 { 400 finish.tv_usec -= USEC_PER_SEC; 401 finish.tv_sec += 1; 402 } 403 } 404 else 405 { 406 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ 407 memset(&finish, 0, sizeof(struct timeval)); 408 } 409 } 410 411 end = list->count - 1; 412 if (direction >= 0) 413 { 414 if (start >= list->count) 415 { 416 if (last != NULL) *last = list->count; 417 return 0; 418 } 419 420 direction = 1; 421 } 422 else 423 { 424 if (start >= list->count) start = list->count - 1; 425 end = 0; 426 direction = -1; 427 } 428 429 i = start; 430 431 do 432 { 433 int match = 0; 434 if (qlist == NULL) match = 1; 435 else match = asl_msg_cmp_list(list->msg[i], qlist); 436 437 if (last != NULL) *last = i; 438 439 if (match != 0) 440 { 441 if (out == NULL) out = asl_msg_list_new(); 442 if (out == NULL) return NULL; 443 444 asl_msg_list_append(out, list->msg[i]); 445 n++; 446 } 447 448 if (n >= count) return n; 449 450 /* check the timer */ 451 if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0)) 452 { 453 if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) return n; 454 } 455 456 i += direction; 457 } while (i != end); 458 459 return out; 460} 461 462#pragma mark - 463#pragma mark asl_object support 464 465static asl_object_private_t * 466_jump_alloc(uint32_t type) 467{ 468 return (asl_object_private_t *)asl_msg_list_new(); 469} 470 471static void 472_jump_dealloc(asl_object_private_t *obj) 473{ 474 asl_msg_list_t *list = (asl_msg_list_t *)obj; 475 476 if (list == NULL) return; 477 if (list->msg != NULL) 478 { 479 uint32_t i; 480 for (i = 0; i < list->count; i++) asl_msg_release(list->msg[i]); 481 free(list->msg); 482 } 483 484 free(list); 485} 486 487static size_t 488_jump_count(asl_object_private_t *obj) 489{ 490 return asl_msg_list_count((asl_msg_list_t *)obj); 491} 492 493static asl_object_private_t * 494_jump_next(asl_object_private_t *obj) 495{ 496 return (asl_object_private_t *)asl_msg_list_next((asl_msg_list_t *)obj); 497} 498 499static asl_object_private_t * 500_jump_prev(asl_object_private_t *obj) 501{ 502 return (asl_object_private_t *)asl_msg_list_prev((asl_msg_list_t *)obj); 503} 504 505static asl_object_private_t * 506_jump_get_object_at_index(asl_object_private_t *obj, size_t n) 507{ 508 return (asl_object_private_t *)asl_msg_list_get_index((asl_msg_list_t *)obj, n); 509} 510 511static void 512_jump_set_iteration_index(asl_object_private_t *obj, size_t n) 513{ 514 asl_msg_list_reset_iteration((asl_msg_list_t *)obj, n); 515} 516 517static void 518_jump_remove_object_at_index(asl_object_private_t *obj, size_t n) 519{ 520 asl_msg_list_remove_index((asl_msg_list_t *)obj, n); 521} 522 523static void 524_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj) 525{ 526 int type = asl_get_type((asl_object_t)newobj); 527 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; 528 529 asl_msg_list_append((asl_msg_list_t *)obj, newobj); 530} 531 532static void 533_jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj) 534{ 535 int type = asl_get_type((asl_object_t)newobj); 536 if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return; 537 538 asl_msg_list_prepend((asl_msg_list_t *)obj, newobj); 539} 540 541static asl_object_private_t * 542_jump_search(asl_object_private_t *obj, asl_object_private_t *query) 543{ 544 int type = asl_get_type((asl_object_t)query); 545 546 if ((query != NULL) && (type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return NULL; 547 548 asl_msg_list_t *out = asl_msg_list_search((asl_msg_list_t *)obj, (asl_msg_t *)query); 549 if (out == NULL) return NULL; 550 return (asl_object_private_t *)out; 551} 552 553static asl_object_private_t * 554_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir) 555{ 556 int type = asl_get_type((asl_object_t)qlist); 557 558 if ((qlist != NULL) && (type != ASL_TYPE_LIST)) return NULL; 559 560 return (asl_object_private_t *)asl_msg_list_match((asl_msg_list_t *)obj, (asl_msg_list_t *)qlist, last, start, count, duration, dir); 561} 562 563__private_extern__ const asl_jump_table_t * 564asl_msg_list_jump_table() 565{ 566 static const asl_jump_table_t jump = 567 { 568 .alloc = &_jump_alloc, 569 .dealloc = &_jump_dealloc, 570 .set_key_val_op = NULL, 571 .unset_key = NULL, 572 .get_val_op_for_key = NULL, 573 .get_key_val_op_at_index = NULL, 574 .count = &_jump_count, 575 .next = &_jump_next, 576 .prev = &_jump_prev, 577 .get_object_at_index = &_jump_get_object_at_index, 578 .set_iteration_index = &_jump_set_iteration_index, 579 .remove_object_at_index = &_jump_remove_object_at_index, 580 .append = &_jump_append, 581 .prepend = &_jump_prepend, 582 .search = &_jump_search, 583 .match = &_jump_match 584 }; 585 586 return &jump; 587} 588