1/*
2 * Copyright (c) 2007-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#include <asl_object.h>
24#include <asl_core.h>
25#include <asl_private.h>
26#include <asl_msg.h>
27#include <asl_msg_list.h>
28#include <asl_client.h>
29#include <asl_store.h>
30#include <asl_file.h>
31#include <dispatch/dispatch.h>
32#include <libkern/OSAtomic.h>
33
34static const asl_jump_table_t *asl_jump[ASL_TYPE_COUNT];
35static dispatch_once_t asl_object_once;
36
37static void
38_asl_object_init(void)
39{
40	asl_jump[ASL_TYPE_MSG] = asl_msg_jump_table();
41	asl_jump[ASL_TYPE_QUERY] = asl_msg_jump_table();
42	asl_jump[ASL_TYPE_LIST] = asl_msg_list_jump_table();
43	asl_jump[ASL_TYPE_FILE] = asl_file_jump_table();
44	asl_jump[ASL_TYPE_STORE] = asl_store_jump_table();
45	asl_jump[ASL_TYPE_CLIENT] = asl_client_jump_table();
46}
47
48#pragma mark -
49#pragma mark asl_object
50
51int
52asl_object_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op)
53{
54	if (obj == NULL) return -1;
55	if (obj->asl_type >= ASL_TYPE_COUNT) return -1;
56
57	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
58	if (asl_jump[obj->asl_type]->set_key_val_op == NULL) return -1;
59	return asl_jump[obj->asl_type]->set_key_val_op(obj, key, val, op);
60}
61
62void
63asl_object_unset_key(asl_object_private_t *obj, const char *key)
64{
65	if (obj == NULL) return;
66	if (obj->asl_type >= ASL_TYPE_COUNT) return;
67
68	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
69	if (asl_jump[obj->asl_type]->unset_key == NULL) return;
70	asl_jump[obj->asl_type]->unset_key(obj, key);
71}
72
73int
74asl_object_get_val_op_for_key(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op)
75{
76	if (obj == NULL) return -1;
77	if (obj->asl_type >= ASL_TYPE_COUNT) return -1;
78
79	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
80	if (asl_jump[obj->asl_type]->get_val_op_for_key == NULL) return -1;
81	return asl_jump[obj->asl_type]->get_val_op_for_key(obj, key, val, op);
82}
83
84int
85asl_object_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op)
86{
87	if (obj == NULL) return -1;
88	if (obj->asl_type >= ASL_TYPE_COUNT) return -1;
89
90	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
91	if (asl_jump[obj->asl_type]->get_key_val_op_at_index == NULL) return -1;
92	return asl_jump[obj->asl_type]->get_key_val_op_at_index(obj, n, key, val, op);
93}
94
95size_t
96asl_object_count(asl_object_private_t *obj)
97{
98	if (obj == NULL) return 0;
99	if (obj->asl_type >= ASL_TYPE_COUNT) return 0;
100
101	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
102	if (asl_jump[obj->asl_type]->count == NULL) return 0;
103	return asl_jump[obj->asl_type]->count(obj);
104}
105
106asl_object_private_t *
107asl_object_next(asl_object_private_t *obj)
108{
109	if (obj == NULL) return NULL;
110	if (obj->asl_type >= ASL_TYPE_COUNT) return NULL;
111
112	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
113	if (asl_jump[obj->asl_type]->next == NULL) return NULL;
114	return asl_jump[obj->asl_type]->next(obj);
115}
116
117asl_object_private_t *
118asl_object_prev(asl_object_private_t *obj)
119{
120	if (obj == NULL) return NULL;
121	if (obj->asl_type >= ASL_TYPE_COUNT) return NULL;
122
123	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
124	if (asl_jump[obj->asl_type]->prev == NULL) return NULL;
125	return asl_jump[obj->asl_type]->prev(obj);
126}
127
128asl_object_private_t *
129asl_object_get_object_at_index(asl_object_private_t *obj, size_t n)
130{
131	if (obj == NULL) return NULL;
132	if (obj->asl_type >= ASL_TYPE_COUNT) return NULL;
133
134	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
135	if (asl_jump[obj->asl_type]->get_object_at_index == NULL) return NULL;
136	return asl_jump[obj->asl_type]->get_object_at_index(obj, n);
137}
138
139void
140asl_object_set_iteration_index(asl_object_private_t *obj, size_t n)
141{
142	if (obj == NULL) return;
143	if (obj->asl_type >= ASL_TYPE_COUNT) return;
144
145	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
146	if (asl_jump[obj->asl_type]->set_iteration_index == NULL) return;
147	return asl_jump[obj->asl_type]->set_iteration_index(obj, n);
148}
149
150void
151asl_object_remove_object_at_index(asl_object_private_t *obj, size_t n)
152{
153	if (obj == NULL) return;
154	if (obj->asl_type >= ASL_TYPE_COUNT) return;
155
156	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
157	if (asl_jump[obj->asl_type]->remove_object_at_index == NULL) return;
158	return asl_jump[obj->asl_type]->remove_object_at_index(obj, n);
159}
160
161void
162asl_object_append(asl_object_private_t *obj, asl_object_private_t *newobj)
163{
164	int type = ASL_TYPE_CLIENT;
165
166	if (obj != NULL) type = obj->asl_type;
167	if (type >= ASL_TYPE_COUNT) return;
168
169	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
170	if (asl_jump[type]->append == NULL) return;
171	return asl_jump[type]->append(obj, newobj);
172}
173
174void
175asl_object_prepend(asl_object_private_t *obj, asl_object_private_t *newobj)
176{
177	if (obj == NULL) return;
178	if (obj->asl_type >= ASL_TYPE_COUNT) return;
179
180	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
181	if (asl_jump[obj->asl_type]->prepend == NULL) return;
182	return asl_jump[obj->asl_type]->prepend(obj, newobj);
183}
184
185asl_object_private_t *
186asl_object_search(asl_object_private_t *obj, asl_object_private_t *query)
187{
188	/* default to asl_client_search for obj == NULL */
189	if (obj == NULL) return (asl_object_private_t *)asl_client_search(NULL, (asl_msg_t *)query);
190	if (obj->asl_type >= ASL_TYPE_COUNT) return NULL;
191
192	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
193	if (asl_jump[obj->asl_type]->search == NULL) return NULL;
194	return asl_jump[obj->asl_type]->search(obj, query);
195}
196
197asl_object_private_t *
198asl_object_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)
199{
200	/* default to asl_client_match for obj == NULL */
201	if (obj == NULL) return (asl_object_private_t *)asl_client_match(NULL, (asl_msg_list_t *)qlist, last, start, count, duration, dir);
202	if (obj->asl_type >= ASL_TYPE_COUNT) return NULL;
203
204	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
205	if (asl_jump[obj->asl_type]->match == NULL) return NULL;
206	return asl_jump[obj->asl_type]->match(obj, qlist, last, start, count, duration, dir);
207}
208
209asl_object_t
210asl_retain(asl_object_t obj)
211{
212	asl_object_private_t *oo = (asl_object_private_t *)obj;
213	if (oo == NULL) return NULL;
214
215	OSAtomicIncrement32Barrier(&(oo->refcount));
216	return obj;
217}
218
219void
220asl_release(asl_object_t obj)
221{
222	asl_object_private_t *oo = (asl_object_private_t *)obj;
223	if (oo == NULL) return;
224	if (oo->asl_type >= ASL_TYPE_COUNT) return;
225
226	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
227	if (OSAtomicDecrement32Barrier(&(oo->refcount)) != 0) return;
228	if (asl_jump[oo->asl_type]->dealloc != NULL) asl_jump[oo->asl_type]->dealloc(oo);
229}
230
231asl_object_t
232asl_new(uint32_t type)
233{
234	if (type >= ASL_TYPE_COUNT) return NULL;
235
236	dispatch_once(&asl_object_once, ^{ _asl_object_init(); });
237	if (asl_jump[type]->alloc == NULL) return NULL;
238	asl_object_t out = (asl_object_t)asl_jump[type]->alloc(type);
239	return out;
240}
241
242#pragma mark -
243#pragma mark utilities
244
245uint32_t
246asl_get_type(asl_object_t obj)
247{
248	asl_object_private_t *oo = (asl_object_private_t *)obj;
249
250	if (oo == NULL) return ASL_TYPE_UNDEF;
251	return (int)oo->asl_type;
252}
253
254const char *
255asl_get_value_for_key(asl_object_t obj, const char *key)
256{
257	const char *val = NULL;
258	uint16_t op;
259
260	asl_object_get_val_op_for_key((asl_object_private_t *)obj, key, &val, &op);
261	return val;
262}
263
264int
265asl_set(asl_object_t obj, const char *key, const char *val)
266{
267	asl_object_private_t *oo = (asl_object_private_t *)obj;
268	uint16_t op = 0;
269
270	if (oo == NULL) return -1;
271	if (oo->asl_type == ASL_TYPE_QUERY) op = (uint32_t)-1;
272
273	return asl_object_set_key_val_op(oo, key, val, op);
274}
275
276int
277asl_unset_key(asl_object_t obj, const char *key)
278{
279	asl_object_unset_key((asl_object_private_t *)obj, key);
280	return 0;
281}
282
283int
284asl_set_key_val_op(asl_object_t obj, const char *key, const char *val, uint16_t op)
285{
286	return asl_object_set_key_val_op((asl_object_private_t *)obj, key, val, op);
287}
288
289size_t
290asl_count(asl_object_t obj)
291{
292	return asl_object_count((asl_object_private_t *)obj);
293}
294
295asl_object_t
296asl_get_index(asl_object_t list, size_t index)
297{
298	return (asl_object_t)asl_object_get_object_at_index((asl_object_private_t *)list, index);
299}
300
301asl_object_t
302asl_next(asl_object_t obj)
303{
304	return (asl_object_t)asl_object_next((asl_object_private_t *)obj);
305}
306
307asl_object_t
308asl_prev(asl_object_t obj)
309{
310	return (asl_object_t)asl_object_prev((asl_object_private_t *)obj);
311}
312
313void
314asl_append(asl_object_t a, asl_object_t b)
315{
316	asl_object_append((asl_object_private_t *)a, (asl_object_private_t *)b);
317}
318
319void
320asl_prepend(asl_object_t a, asl_object_t b)
321{
322	asl_object_prepend((asl_object_private_t *)a, (asl_object_private_t *)b);
323}
324
325/* asl_send is implemented as asl_append */
326int
327asl_send(asl_object_t a, asl_object_t b)
328{
329	asl_object_append((asl_object_private_t *)a, (asl_object_private_t *)b);
330	return 0;
331}
332
333const char *
334asl_key(asl_object_t obj, uint32_t n)
335{
336	const char *key = NULL;
337	size_t sn = n;
338
339	if (asl_object_get_key_val_op_at_index((asl_object_private_t *)obj, sn, &key, NULL, NULL) != 0) return NULL;
340	return key;
341}
342
343const char *
344asl_get(asl_object_t obj, const char *key)
345{
346	const char *val = NULL;
347
348	if (asl_object_get_val_op_for_key((asl_object_private_t *)obj, key, &val, NULL) != 0) return NULL;
349	return val;
350}
351
352int
353asl_fetch_key_val_op(asl_object_t obj, uint32_t n, const char **key, const char **val, uint32_t *op)
354{
355	uint16_t op16;
356	size_t sn = n;
357	int status = asl_object_get_key_val_op_at_index((asl_object_private_t *)obj, sn, key, val, &op16);
358	if (status != 0) return status;
359	if (op != NULL) *op = op16;
360	return 0;
361}
362
363int
364asl_set_query(asl_object_t obj, const char *key, const char *val, uint32_t op)
365{
366	uint16_t op16 = op;
367	return asl_object_set_key_val_op((asl_object_private_t *)obj, key, val, op16);
368}
369
370int
371asl_unset(asl_object_t obj, const char *key)
372{
373	asl_object_unset_key((asl_object_private_t *)obj, key);
374	return 0;
375}
376
377void
378asl_reset_iteration(asl_object_t obj, size_t position)
379{
380	asl_object_set_iteration_index((asl_object_private_t *)obj, position);
381}
382
383asl_object_t
384asl_search(asl_object_t data, asl_object_t query)
385{
386	return (asl_object_t)asl_object_search((asl_object_private_t *)data, (asl_object_private_t *)query);
387}
388
389asl_object_t
390asl_match(asl_object_t data, asl_object_t qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t direction)
391{
392	return (asl_object_t)asl_object_match((asl_object_private_t *)data, (asl_object_private_t *)qlist, last, start, count, duration, direction);
393}
394
395void
396asl_free(asl_object_t obj)
397{
398	asl_release(obj);
399}
400
401void
402aslresponse_free(asl_object_t obj)
403{
404	asl_release(obj);
405}
406
407asl_object_t
408aslresponse_next(asl_object_t obj)
409{
410	return (asl_object_t)asl_object_next((asl_object_private_t *)obj);
411}
412
413asl_object_t
414asl_list_from_string(const char *buf)
415{
416	return (asl_object_t)asl_msg_list_from_string(buf);
417}
418
419char *
420asl_format(asl_object_t obj, const char *msg_fmt, const char *time_fmt, uint32_t text_encoding)
421{
422	uint32_t len;
423	uint32_t type = asl_get_type(obj);
424	if (type != ASL_TYPE_MSG) return NULL;
425	return asl_format_message((asl_msg_t *)obj, msg_fmt, time_fmt, text_encoding, &len);
426}
427