xref: /trueos/lib/libasl/asl_msg_list.c (revision e0d5dc4e99cb0cffad102c7a22a16d828ef86ae5)
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 
34 asl_msg_list_t *
asl_msg_list_new(void)35 asl_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 
46 asl_msg_list_t *
asl_msg_list_new_count(uint32_t n)47 asl_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 
66 asl_msg_list_t *
asl_msg_list_retain(asl_msg_list_t * list)67 asl_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 
74 void
asl_msg_list_release(asl_msg_list_t * list)75 asl_msg_list_release(asl_msg_list_t *list)
76 {
77 	if (list == NULL) return;
78 	asl_release((asl_object_t)list);
79 }
80 
81 char *
asl_msg_list_to_string(asl_msg_list_t * list,uint32_t * len)82 asl_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 
111 asl_string_t *
asl_msg_list_to_asl_string(asl_msg_list_t * list,uint32_t encoding)112 asl_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 
138 asl_msg_list_t *
asl_msg_list_from_string(const char * buf)139 asl_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 
180 void
asl_msg_list_insert(asl_msg_list_t * list,uint32_t x,void * obj)181 asl_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 
230 void
asl_msg_list_append(asl_msg_list_t * list,void * obj)231 asl_msg_list_append(asl_msg_list_t *list, void *obj)
232 {
233 	asl_msg_list_insert(list, UINT32_MAX, obj);
234 }
235 
236 void
asl_msg_list_prepend(asl_msg_list_t * list,void * obj)237 asl_msg_list_prepend(asl_msg_list_t *list, void *obj)
238 {
239 	asl_msg_list_insert(list, 0, obj);
240 }
241 
242 size_t
asl_msg_list_count(asl_msg_list_t * list)243 asl_msg_list_count(asl_msg_list_t *list)
244 {
245 	if (list == NULL) return 0;
246 	return list->count;
247 }
248 
249 asl_msg_t *
asl_msg_list_get_index(asl_msg_list_t * list,size_t index)250 asl_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 
267 void
asl_msg_list_remove_index(asl_msg_list_t * list,size_t index)268 asl_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 
294 asl_msg_t *
asl_msg_list_next(asl_msg_list_t * list)295 asl_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 
313 asl_msg_t *
asl_msg_list_prev(asl_msg_list_t * list)314 asl_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 
334 void
asl_msg_list_reset_iteration(asl_msg_list_t * list,size_t position)335 asl_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 
343 asl_msg_list_t *
asl_msg_list_search(asl_msg_list_t * list,asl_msg_t * query)344 asl_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 
375 asl_msg_list_t *
asl_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)376 asl_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 
465 static asl_object_private_t *
_jump_alloc(uint32_t type)466 _jump_alloc(uint32_t type)
467 {
468 	return (asl_object_private_t *)asl_msg_list_new();
469 }
470 
471 static void
_jump_dealloc(asl_object_private_t * obj)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 
487 static size_t
_jump_count(asl_object_private_t * obj)488 _jump_count(asl_object_private_t *obj)
489 {
490 	return asl_msg_list_count((asl_msg_list_t *)obj);
491 }
492 
493 static asl_object_private_t *
_jump_next(asl_object_private_t * obj)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 
499 static asl_object_private_t *
_jump_prev(asl_object_private_t * obj)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 
505 static asl_object_private_t *
_jump_get_object_at_index(asl_object_private_t * obj,size_t n)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 
511 static void
_jump_set_iteration_index(asl_object_private_t * obj,size_t n)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 
517 static void
_jump_remove_object_at_index(asl_object_private_t * obj,size_t n)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 
523 static void
_jump_append(asl_object_private_t * obj,asl_object_private_t * newobj)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 
532 static void
_jump_prepend(asl_object_private_t * obj,asl_object_private_t * newobj)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 
541 static asl_object_private_t *
_jump_search(asl_object_private_t * obj,asl_object_private_t * query)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 
553 static asl_object_private_t *
_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)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 *
asl_msg_list_jump_table()564 asl_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