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