2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
38 #include <asl_object.h>
39 #include <asl_private.h>
41 #include <sys/types.h>
42 #include <libkern/OSAtomic.h>
44 #include <asl_msg_list.h>
59 #define SEC_PER_HOUR 3600
63 #define forever for(;;)
65 #define streq(A, B) (strcmp(A, B) == 0)
66 #define streq_len(A, B, C) (strncmp(A, B, C) == 0)
67 #define strneq(A, B) (strcmp(A, B) != 0)
68 #define strcaseeq(A, B) (strcasecmp(A, B) == 0)
69 #define strcaseneq(A, B) (strcasecmp(A, B) != 0)
71 #ifndef ASL_QUERY_OP_FALSE
72 #define ASL_QUERY_OP_FALSE 0
75 #define AUX_0_TIME 0x00000001
76 #define AUX_0_TIME_NSEC 0x00000002
77 #define AUX_0_HOST 0x00000004
78 #define AUX_0_SENDER 0x00000008
79 #define AUX_0_FACILITY 0x00000010
80 #define AUX_0_PID 0x00000020
81 #define AUX_0_UID 0x00000040
82 #define AUX_0_GID 0x00000080
83 #define AUX_0_MSG 0x00000100
84 #define AUX_0_OPTION 0x00000200
85 #define AUX_0_LEVEL 0x00000400
88 int asl_is_utf8(const char *str
);
89 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
);
91 void _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t
*msg
);
94 #pragma mark standard message keys
96 static const char *ASLStandardKey
[] =
119 static const char *MTStandardKey
[] =
121 "com.apple.message.domain",
122 "com.apple.message.domain_scope",
123 "com.apple.message.result",
124 "com.apple.message.signature",
125 "com.apple.message.signature2",
126 "com.apple.message.signature3",
127 "com.apple.message.success",
128 "com.apple.message.uuid",
129 "com.apple.message.value",
130 "com.apple.message.value2",
131 "com.apple.message.value3",
132 "com.apple.message.value4",
133 "com.apple.message.value5"
137 _asl_msg_std_key(const char *s
, uint32_t len
)
139 if ((len
> 18) && (streq_len(s
, "com.apple.message.", 18)))
141 if (streq(s
+ 18, "domain")) return ASL_MT_KEY_DOMAIN
;
142 else if (streq(s
+ 18, "domain_scope")) return ASL_MT_KEY_SCOPE
;
143 else if (streq(s
+ 18, "result")) return ASL_MT_KEY_RESULT
;
144 else if (streq(s
+ 18, "signature")) return ASL_MT_KEY_SIG
;
145 else if (streq(s
+ 18, "signature2")) return ASL_MT_KEY_SIG2
;
146 else if (streq(s
+ 18, "signature3")) return ASL_MT_KEY_SIG3
;
147 else if (streq(s
+ 18, "success")) return ASL_MT_KEY_SUCCESS
;
148 else if (streq(s
+ 18, "uuid")) return ASL_MT_KEY_UUID
;
149 else if (streq(s
+ 18, "value")) return ASL_MT_KEY_VAL
;
150 else if (streq(s
+ 18, "value2")) return ASL_MT_KEY_VAL2
;
151 else if (streq(s
+ 18, "value3")) return ASL_MT_KEY_VAL3
;
152 else if (streq(s
+ 18, "value4")) return ASL_MT_KEY_VAL4
;
153 else if (streq(s
+ 18, "value5")) return ASL_MT_KEY_VAL5
;
162 if streq(s
, ASL_KEY_PID
) return ASL_STD_KEY_PID
;
163 else if streq(s
, ASL_KEY_UID
) return ASL_STD_KEY_UID
;
164 else if streq(s
, ASL_KEY_GID
) return ASL_STD_KEY_GID
;
168 if streq(s
, ASL_KEY_TIME
) return ASL_STD_KEY_TIME
;
169 else if streq(s
, ASL_KEY_HOST
) return ASL_STD_KEY_HOST
;
173 if streq(s
, ASL_KEY_LEVEL
) return ASL_STD_KEY_LEVEL
;
177 if streq(s
, ASL_KEY_SENDER
) return ASL_STD_KEY_SENDER
;
178 else if streq(s
, ASL_KEY_REF_PID
) return ASL_STD_KEY_REF_PID
;
182 if streq(s
, ASL_KEY_MSG
) return ASL_STD_KEY_MESSAGE
;
183 else if streq(s
, ASL_KEY_SESSION
) return ASL_STD_KEY_SESSION
;
184 else if streq(s
, ASL_KEY_READ_UID
) return ASL_STD_KEY_READ_UID
;
185 else if streq(s
, ASL_KEY_READ_GID
) return ASL_STD_KEY_READ_GID
;
186 else if streq(s
, ASL_KEY_REF_PROC
) return ASL_STD_KEY_REF_PROC
;
190 if streq(s
, ASL_KEY_FACILITY
) return ASL_STD_KEY_FACILITY
;
194 if streq(s
, ASL_KEY_OPTION
) return ASL_STD_KEY_OPTION
;
198 if streq(s
, ASL_KEY_TIME_NSEC
) return ASL_STD_KEY_NANO
;
202 if streq(s
, ASL_KEY_MSG_ID
) return ASL_STD_KEY_MSG_ID
;
206 if streq(s
, ASL_KEY_EXPIRE_TIME
) return ASL_STD_KEY_EXPIRE
;
210 if streq(s
, ASL_KEY_FREE_NOTE
) return ASL_STD_KEY_FREE_NOTE
;
225 _asl_msg_make_page(void)
228 asl_msg_t
*out
= (asl_msg_t
*)calloc(1, sizeof(asl_msg_t
));
230 if (out
== NULL
) return NULL
;
232 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
234 out
->key
[i
] = ASL_MSG_SLOT_FREE
;
235 out
->val
[i
] = ASL_MSG_SLOT_FREE
;
238 out
->mem_size
= sizeof(asl_msg_t
);
244 asl_msg_retain(asl_msg_t
*msg
)
246 if (msg
== NULL
) return NULL
;
247 asl_retain((asl_object_t
)msg
);
252 asl_msg_release(asl_msg_t
*msg
)
254 if (msg
== NULL
) return;
255 asl_release((asl_object_t
)msg
);
259 _asl_msg_slot_key(asl_msg_t
*page
, uint32_t slot
)
264 if (page
== NULL
) return NULL
;
265 if (slot
>= ASL_MSG_PAGE_SLOTS
) return NULL
;
266 if (page
->key
[slot
] == ASL_MSG_SLOT_FREE
) return NULL
;
268 switch (page
->key
[slot
] & ASL_MSG_KV_MASK
)
270 case ASL_MSG_KV_INLINE
:
272 return page
->data
+ page
->key
[slot
];
274 case ASL_MSG_KV_DICT
:
276 if ((page
->key
[slot
] > ASL_STD_KEY_BASE
) && (page
->key
[slot
] <= ASL_STD_KEY_LAST
))
278 x
= page
->key
[slot
] - ASL_STD_KEY_BASE
- 1;
279 return ASLStandardKey
[x
];
281 else if ((page
->key
[slot
] > ASL_MT_KEY_BASE
) && (page
->key
[slot
] <= ASL_MT_KEY_LAST
))
283 x
= page
->key
[slot
] - ASL_MT_KEY_BASE
- 1;
284 return MTStandardKey
[x
];
289 case ASL_MSG_KV_EXTERN
:
291 x
= page
->key
[slot
] & ASL_MSG_OFFSET_MASK
;
292 memcpy(&out
, page
->data
+ x
, sizeof(char *));
301 _asl_msg_slot_val(asl_msg_t
*page
, uint32_t slot
)
306 if (page
== NULL
) return NULL
;
307 if (slot
>= ASL_MSG_PAGE_SLOTS
) return NULL
;
309 if (page
->val
[slot
] == ASL_MSG_SLOT_FREE
) return NULL
;
311 type
= page
->val
[slot
] & ASL_MSG_KV_MASK
;
313 if (type
== ASL_MSG_KV_INLINE
)
315 return page
->data
+ page
->val
[slot
];
317 else if (type
== ASL_MSG_KV_EXTERN
)
319 x
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
320 memcpy(&out
, page
->data
+ x
, sizeof(char *));
328 * asl_new: create a new log message.
331 asl_msg_new(uint32_t type
)
335 out
= _asl_msg_make_page();
336 if (out
== NULL
) return NULL
;
338 out
->asl_type
= type
;
345 _asl_msg_free_page(asl_msg_t
*page
)
350 if (page
== NULL
) return;
352 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
354 if (page
->key
[i
] == ASL_STD_KEY_FREE_NOTE
)
356 const char *x
= _asl_msg_slot_val(page
, i
);
357 if (x
!= NULL
) notify_post(x
);
360 if ((page
->key
[i
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
362 memcpy(&p
, page
->data
+ (page
->key
[i
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
366 if ((page
->val
[i
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
368 memcpy(&p
, page
->data
+ (page
->val
[i
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
377 asl_msg_type(asl_msg_t
*msg
)
379 if (msg
== NULL
) return 0;
380 return msg
->asl_type
;
384 asl_msg_count(asl_msg_t
*msg
)
390 for (; msg
!= NULL
; msg
= msg
->next
) total
+= msg
->count
;
395 _asl_msg_dump_kv(FILE *f
, asl_msg_t
*msg
, uint16_t x
)
397 if (x
== ASL_MSG_SLOT_FREE
)
399 fprintf(f
, "-free-");
403 if ((x
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
)
407 case ASL_STD_KEY_TIME
: fprintf(f
, "(dict: Time)"); return;
408 case ASL_STD_KEY_NANO
: fprintf(f
, "(dict: Nano)"); return;
409 case ASL_STD_KEY_HOST
: fprintf(f
, "(dict: Host)"); return;
410 case ASL_STD_KEY_SENDER
: fprintf(f
, "(dict: Sender)"); return;
411 case ASL_STD_KEY_FACILITY
: fprintf(f
, "(dict: Facility)"); return;
412 case ASL_STD_KEY_PID
: fprintf(f
, "(dict: PID)"); return;
413 case ASL_STD_KEY_UID
: fprintf(f
, "(dict: UID)"); return;
414 case ASL_STD_KEY_GID
: fprintf(f
, "(dict: GID)"); return;
415 case ASL_STD_KEY_LEVEL
: fprintf(f
, "(dict: Level)"); return;
416 case ASL_STD_KEY_MESSAGE
: fprintf(f
, "(dict: Message)"); return;
417 case ASL_STD_KEY_READ_UID
: fprintf(f
, "(dict: ReadUID)"); return;
418 case ASL_STD_KEY_READ_GID
: fprintf(f
, "(dict: ReadGID)"); return;
419 case ASL_STD_KEY_SESSION
: fprintf(f
, "(dict: Session)"); return;
420 case ASL_STD_KEY_REF_PID
: fprintf(f
, "(dict: PID)"); return;
421 case ASL_STD_KEY_REF_PROC
: fprintf(f
, "(dict: RefProc)"); return;
422 case ASL_STD_KEY_MSG_ID
: fprintf(f
, "(dict: ASLMessageID)"); return;
423 case ASL_STD_KEY_EXPIRE
: fprintf(f
, "(dict: Expire)"); return;
424 case ASL_STD_KEY_OPTION
: fprintf(f
, "(dict: ASLOption)"); return;
425 case ASL_MT_KEY_DOMAIN
: fprintf(f
, "(dict: com.apple.message.domain)"); return;
426 case ASL_MT_KEY_SCOPE
: fprintf(f
, "(dict: com.apple.message.domain_scope)"); return;
427 case ASL_MT_KEY_RESULT
: fprintf(f
, "(dict: com.apple.message.result)"); return;
428 case ASL_MT_KEY_SIG
: fprintf(f
, "(dict: com.apple.message.signature)"); return;
429 case ASL_MT_KEY_SIG2
: fprintf(f
, "(dict: com.apple.message.signature2)"); return;
430 case ASL_MT_KEY_SIG3
: fprintf(f
, "(dict: com.apple.message.signature3)"); return;
431 case ASL_MT_KEY_SUCCESS
: fprintf(f
, "(dict: com.apple.message.success)"); return;
432 case ASL_MT_KEY_UUID
: fprintf(f
, "(dict: com.apple.message.uuid)"); return;
433 case ASL_MT_KEY_VAL
: fprintf(f
, "(dict: com.apple.message.value)"); return;
434 case ASL_MT_KEY_VAL2
: fprintf(f
, "(dict: com.apple.message.value2)"); return;
435 case ASL_MT_KEY_VAL3
: fprintf(f
, "(dict: com.apple.message.value3)"); return;
436 case ASL_MT_KEY_VAL4
: fprintf(f
, "(dict: com.apple.message.value4)"); return;
437 case ASL_MT_KEY_VAL5
: fprintf(f
, "(dict: com.apple.message.value5)"); return;
440 fprintf(f
, "(dict: -unknown-)");
444 if ((x
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
447 size_t z
= x
& ASL_MSG_OFFSET_MASK
;
448 memcpy(&c
, msg
->data
+ z
, sizeof(char *));
449 fprintf(f
, "(extern: %s)", c
);
453 fprintf(f
, "%s", msg
->data
+ x
);
457 _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t
*msg
)
461 if (f
== NULL
) return;
464 fprintf(f
, "asl_msg %s: NULL\n", comment
);
472 fprintf(f
, "asl_msg %s: %p\n", comment
, msg
);
473 fprintf(f
, " refcount: %u\n", msg
->refcount
);
474 fprintf(f
, " asl_type: %u\n", msg
->asl_type
);
479 fprintf(f
, " page: %p\n", msg
);
482 fprintf(f
, " count: %u\n", msg
->count
);
483 fprintf(f
, " data_size: %u\n", msg
->data_size
);
484 fprintf(f
, " mem_size: %llu\n", msg
->mem_size
);
485 fprintf(f
, " next: %p\n", msg
->next
);
487 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
489 fprintf(f
, " slot[%d]: ", i
);
490 _asl_msg_dump_kv(f
, msg
, msg
->key
[i
]);
492 _asl_msg_dump_kv(f
, msg
, msg
->val
[i
]);
493 fprintf(f
, " 0x%04x\n", msg
->op
[i
]);
501 #pragma mark fetching contents
504 * Find the slot and page for an input key.
507 _asl_msg_index(asl_msg_t
*msg
, const char *key
, uint32_t *oslot
, asl_msg_t
**opage
)
509 uint32_t i
, len
, slot
;
514 if (msg
== NULL
) return IndexNull
;
515 if (key
== NULL
) return IndexNull
;
519 if (oslot
!= NULL
) *oslot
= slot
;
522 if (opage
!= NULL
) *opage
= page
;
525 kx
= _asl_msg_std_key(key
, len
);
529 if (page
->key
[slot
] != ASL_MSG_SLOT_FREE
)
533 if (page
->key
[slot
] == kx
) return i
;
535 else if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
)
537 /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
539 else if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
541 memcpy(&kp
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
542 if (streq(key
, kp
)) return i
;
546 kp
= page
->data
+ page
->key
[slot
];
547 if (streq(key
, kp
)) return i
;
553 if (oslot
!= NULL
) *oslot
= slot
;
555 if (slot
>= ASL_MSG_PAGE_SLOTS
)
557 if (page
->next
== NULL
) return IndexNull
;
560 if (oslot
!= NULL
) *oslot
= slot
;
563 if (opage
!= NULL
) *opage
= page
;
571 * Find page and slot for an "index".
574 _asl_msg_resolve_index(asl_msg_t
*msg
, uint32_t n
, asl_msg_t
**page
, uint32_t *slot
)
579 if (msg
== NULL
) return -1;
587 for (px
= msg
; px
!= NULL
; px
= px
->next
)
589 if (n
> (sx
+ px
->count
))
598 for (i
= 0; i
< ASL_MSG_PAGE_SLOTS
; i
++)
600 if (px
->key
[i
] != ASL_MSG_SLOT_FREE
)
617 * asl_msg_fetch: iterate over entries
618 * initial value of n should be 0. Subseqent calls should use the last
619 * returned value. Returns IndexNull when there are no more entries
620 * Sets the pointers for the next key, value, and op in the msg.
621 * The iterator encodes a page number and a slot number.
625 asl_msg_fetch(asl_msg_t
*msg
, uint32_t x
, const char **keyout
, const char **valout
, uint16_t *opout
)
627 uint32_t p
, xpn
, xsn
;
628 asl_msg_t
*page
= NULL
;
630 if (msg
== NULL
) return IndexNull
;
633 xpn
= x
& 0x00ffffff;
635 /* slot number 0xff means we have run out entries */
636 if (xsn
== 0x000000ff) return IndexNull
;
639 for (p
= 0; p
< xpn
; p
++)
642 if (page
== NULL
) return IndexNull
;
645 if (keyout
!= NULL
) *keyout
= _asl_msg_slot_key(page
, xsn
);
646 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, xsn
);
647 if (opout
!= NULL
) *opout
= (uint32_t)(page
->op
[xsn
]);
649 /* advance to the next slot */
654 if (xsn
>= ASL_MSG_PAGE_SLOTS
)
656 if (page
->next
== NULL
) return 0xff000000;
662 if (page
->key
[xsn
] != ASL_MSG_SLOT_FREE
) return ((xsn
<< 24) | xpn
);
669 asl_msg_lookup(asl_msg_t
*msg
, const char *key
, const char **valout
, uint16_t *opout
)
674 if (msg
== NULL
) return -1;
675 if (valout
!= NULL
) *valout
= NULL
;
676 if (opout
!= NULL
) *opout
= 0;
681 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
682 if (i
== IndexNull
) return -1;
684 if (valout
!= NULL
) *valout
= _asl_msg_slot_val(page
, slot
);
685 if (opout
!= NULL
) *opout
= (uint32_t)(page
->op
[slot
]);
691 asl_msg_get_val_for_key(asl_msg_t
*msg
, const char *key
)
696 if (msg
== NULL
) return NULL
;
701 if (_asl_msg_index(msg
, key
, &slot
, &page
) == IndexNull
) return NULL
;
703 return _asl_msg_slot_val(page
, slot
);
707 asl_msg_key(asl_msg_t
*msg
, uint32_t n
)
712 if (msg
== NULL
) return NULL
;
715 for (page
= msg
; page
!= NULL
; page
= page
->next
)
717 for (slot
= 0; slot
< ASL_MSG_PAGE_SLOTS
; slot
++)
719 if (page
->key
[slot
] != ASL_MSG_SLOT_FREE
)
721 if (i
== n
) return _asl_msg_slot_key(page
, slot
);
731 #pragma mark adding and replacing contents
734 _asl_msg_new_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
736 uint32_t slot
, keylen
, vallen
, total
;
739 asl_msg_t
*page
, *last
;
740 char *extkey
, *extval
;
742 if (msg
== NULL
) return -1;
743 if (key
== NULL
) return -1;
748 keylen
= strlen(key
);
750 kx
= _asl_msg_std_key(key
, keylen
);
752 if (kx
== 0) keylen
++;
760 vallen
= strlen(val
) + 1;
765 /* check if one or both of key and value must be "external" (in its own malloced space) */
766 if (keylen
> ASL_MSG_PAGE_DATA_SIZE
)
768 extkey
= strdup(key
);
769 keylen
= sizeof(char *);
772 if (vallen
> ASL_MSG_PAGE_DATA_SIZE
)
774 extval
= strdup(val
);
775 vallen
= sizeof(char *);
778 total
= keylen
+ vallen
;
779 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extval
== NULL
) && (keylen
> 0))
781 extval
= strdup(val
);
782 vallen
= sizeof(char *);
783 total
= keylen
+ vallen
;
786 if ((total
> ASL_MSG_PAGE_DATA_SIZE
) && (extkey
== NULL
))
788 extkey
= strdup(key
);
789 keylen
= sizeof(char *);
790 total
= keylen
+ vallen
;
793 if (total
> ASL_MSG_PAGE_DATA_SIZE
)
795 /* can't happen, but... */
796 if (extkey
!= NULL
) free(extkey
);
797 if (extval
!= NULL
) free(extval
);
801 /* find a page with space for the key and value and a free slot*/
805 for (page
= msg
; page
!= NULL
; page
= page
->next
)
809 if (total
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
811 /* check for a free slot */
812 for (slot
= 0; (slot
< ASL_MSG_PAGE_SLOTS
) && (page
->key
[slot
] != ASL_MSG_SLOT_FREE
); slot
++);
813 if (slot
< ASL_MSG_PAGE_SLOTS
) break;
819 /* allocate a new page and attach it */
820 page
= _asl_msg_make_page();
823 if (extkey
!= NULL
) free(extkey
);
824 if (extval
!= NULL
) free(extval
);
832 /* copy key or external key pointer into page data */
835 page
->key
[slot
] = kx
;
837 else if (extkey
== NULL
)
839 page
->key
[slot
] = page
->data_size
;
840 memcpy(page
->data
+ page
->data_size
, key
, keylen
);
844 page
->key
[slot
] = page
->data_size
| ASL_MSG_KV_EXTERN
;
845 memcpy(page
->data
+ page
->data_size
, &extkey
, keylen
);
846 page
->mem_size
+= klen
;
849 page
->data_size
+= keylen
;
851 /* copy val or external val pointer into page data */
852 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
858 page
->val
[slot
] = page
->data_size
;
859 memcpy(page
->data
+ page
->data_size
, val
, vallen
);
863 page
->val
[slot
] = page
->data_size
| ASL_MSG_KV_EXTERN
;
864 memcpy(page
->data
+ page
->data_size
, &extval
, vallen
);
865 page
->mem_size
+= vlen
;
868 page
->data_size
+= vallen
;
872 page
->op
[slot
] = (uint16_t)op
;
874 /* update page count */
881 * Most of the code in asl_msg_set_key_val_op is concerned with trying to re-use
882 * space in an asl_msg_t page when given a new value for an existing key.
883 * If the key is new, we just call _asl_msg_new_key_val_op.
885 * Note that queries can have duplicate keys, so for ASL_TYPE_QUERY we just
886 * call through to _asl_msg_new_key_val_op.
889 _asl_msg_set_kvo(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
891 uint32_t i
, slot
, newexternal
;
893 uint32_t intvallen
, extvallen
, newvallen
;
894 char *intval
, *extval
, *newval
;
896 if (msg
== NULL
) return -1;
897 if (key
== NULL
) return -1;
902 if ((msg
->asl_type
== ASL_TYPE_QUERY
) || (IndexNull
== _asl_msg_index(msg
, key
, &slot
, &page
)))
905 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
914 if (page
->val
[slot
] != ASL_MSG_SLOT_FREE
)
916 if ((page
->val
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
918 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
919 memcpy(&extval
, page
->data
+ i
, sizeof(char *));
920 extvallen
= sizeof(char *);
924 intval
= page
->data
+ page
->val
[slot
];
925 intvallen
= strlen(intval
) + 1;
929 /* replace val and op for existing entry */
931 /* easy case - remove val */
936 page
->mem_size
-= (strlen(extval
) + 1);
940 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
941 if (op
!= IndexNull
) page
->op
[slot
] = (uint16_t)op
;
945 /* trivial case - internal val doesn't change */
946 if ((intval
!= NULL
) && (streq(val
, intval
)))
948 if (op
!= IndexNull
) page
->op
[slot
] = (uint16_t)op
;
952 /* trivial case - external val doesn't change */
953 if ((extval
!= NULL
) && (streq(val
, extval
)))
955 if (op
!= IndexNull
) page
->op
[slot
] = (uint16_t)op
;
960 * special case: we generally don't compress out holes in the data
961 * space, but if this is the last string in the currently used data space
962 * we can just back up the data_size and reset page->val[slot]
964 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
965 if ((intval
!= NULL
) && ((i
+ intvallen
) == page
->data_size
))
967 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
968 page
->data_size
-= intvallen
;
972 else if ((extval
!= NULL
) && ((i
+ extvallen
) == page
->data_size
))
974 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
975 page
->data_size
-= extvallen
;
976 page
->mem_size
-= (strlen(extval
) + 1);
982 /* val changes - see if it needs to be external */
983 newvallen
= strlen(val
) + 1;
986 if (newvallen
> ASL_MSG_PAGE_DATA_SIZE
)
989 newvallen
= sizeof(char *);
992 /* check if there is room to change val in place */
993 if (((extval
!= NULL
) && (newvallen
<= extvallen
)) || ((extval
== NULL
) && (newvallen
<= intvallen
)))
997 page
->mem_size
-= (strlen(extval
) + 1);
1003 /* we can re-use the space of the old value */
1004 i
= page
->val
[slot
] & ASL_MSG_OFFSET_MASK
;
1006 if (newexternal
== 1)
1008 /* create an external val and copy in the new pointer */
1009 newval
= strdup(val
);
1010 if (newval
== NULL
) return -1;
1012 page
->mem_size
+= (strlen(newval
) + 1);
1013 page
->val
[slot
] = i
| ASL_MSG_KV_EXTERN
;
1014 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
1018 /* new internal value */
1019 page
->val
[slot
] = i
;
1020 memcpy(page
->data
+ i
, val
, newvallen
);
1023 if (op
!= IndexNull
) page
->op
[slot
] = (uint16_t)op
;
1027 /* we're done with the old value if it is external - free it now */
1030 page
->mem_size
-= (strlen(extval
) + 1);
1036 if (newvallen
<= (ASL_MSG_PAGE_DATA_SIZE
- page
->data_size
))
1038 /* can't re-use the old space, but there's room on the page */
1039 i
= page
->data_size
;
1040 page
->data_size
+= newvallen
;
1042 if (newexternal
== 1)
1044 /* create an external val and copy in the new pointer */
1045 newval
= strdup(val
);
1046 if (newval
== NULL
) return -1;
1048 page
->mem_size
+= (strlen(newval
) + 1);
1049 page
->val
[slot
] = i
| ASL_MSG_KV_EXTERN
;
1050 memcpy(page
->data
+ i
, &newval
, sizeof(char *));
1054 /* new internal value */
1055 page
->val
[slot
] = i
;
1056 memcpy(page
->data
+ i
, val
, newvallen
);
1059 if (op
!= IndexNull
) page
->op
[slot
] = (uint16_t)op
;
1064 /* no room on this page - free up existing entry and treat this as a new entry */
1065 if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1067 memcpy(&extval
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
1068 page
->mem_size
-= (strlen(extval
) + 1);
1072 page
->key
[slot
] = ASL_MSG_SLOT_FREE
;
1073 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
1076 return _asl_msg_new_key_val_op(msg
, key
, val
, op
);
1080 asl_msg_set_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint32_t op
)
1082 char *special
, buf
[512];
1086 /* Special case handling */
1089 /* if query modifier is set but op is zero, default to equality test */
1090 if ((op
!= 0) && ((op
& ASL_QUERY_OP_TRUE
) == 0)) op
|= ASL_QUERY_OP_EQUAL
;
1092 /* convert "Level" values to "0" through "7" */
1093 if (streq(key
, ASL_KEY_LEVEL
))
1095 if (val
== NULL
) val
= "7";
1096 else if ((val
[0] >= '0') && (val
[0] <= '7') && (val
[1] == '\0')) /* do nothing */;
1097 else if (strcaseeq(val
, ASL_STRING_EMERG
)) val
= "0";
1098 else if (strcaseeq(val
, ASL_STRING_ALERT
)) val
= "1";
1099 else if (strcaseeq(val
, ASL_STRING_CRIT
)) val
= "2";
1100 else if (strcaseeq(val
, ASL_STRING_ERR
)) val
= "3";
1101 else if (strcaseeq(val
, ASL_STRING_WARNING
)) val
= "4";
1102 else if (strcaseeq(val
, ASL_STRING_NOTICE
)) val
= "5";
1103 else if (strcaseeq(val
, ASL_STRING_INFO
)) val
= "6";
1104 else if (strcaseeq(val
, ASL_STRING_DEBUG
)) val
= "7";
1108 /* strip trailing newlines from "Message" values */
1109 if ((streq(key
, ASL_KEY_MSG
)) && (val
!= NULL
))
1113 while ((i
> 0) && (val
[i
- 1] == '\n')) i
--;
1114 if (i
== 0) val
= NULL
;
1117 /* use buf if it is big enough, else malloc a temporary buffer */
1118 if (i
< sizeof(buf
))
1120 memcpy(buf
, val
, i
);
1122 val
= (const char *)buf
;
1126 special
= malloc(i
+ 1);
1127 if (special
== NULL
) return -1;
1128 memcpy(special
, val
, i
);
1130 val
= (const char *)special
;
1135 status
= _asl_msg_set_kvo(msg
, key
, val
, op
);
1137 if (special
!= NULL
) free(special
);
1142 asl_msg_set_key_val(asl_msg_t
*msg
, const char *key
, const char *val
)
1144 return asl_msg_set_key_val_op(msg
, key
, val
, 0);
1148 _asl_msg_unset_page_slot(asl_msg_t
*page
, uint32_t slot
)
1152 if (page
== NULL
) return;
1153 if (slot
>= ASL_MSG_PAGE_SLOTS
) return;
1154 if (page
->key
[slot
] == ASL_MSG_SLOT_FREE
) return;
1156 if ((page
->key
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1158 memcpy(&ext
, page
->data
+ (page
->key
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
1159 page
->mem_size
-= (strlen(ext
) + 1);
1163 if ((page
->val
[slot
] & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
)
1165 memcpy(&ext
, page
->data
+ (page
->val
[slot
] & ASL_MSG_OFFSET_MASK
), sizeof(char *));
1166 page
->mem_size
-= (strlen(ext
) + 1);
1170 page
->key
[slot
] = ASL_MSG_SLOT_FREE
;
1171 page
->val
[slot
] = ASL_MSG_SLOT_FREE
;
1179 * Frees external key and val strings, but does not try to reclaim data space.
1182 asl_msg_unset(asl_msg_t
*msg
, const char *key
)
1187 if (msg
== NULL
) return;
1188 if (key
== NULL
) return;
1193 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
1194 if (i
== IndexNull
) return;
1196 _asl_msg_unset_page_slot(page
, slot
);
1200 asl_msg_unset_index(asl_msg_t
*msg
, uint32_t n
)
1202 uint32_t slot
= IndexNull
;
1203 asl_msg_t
*page
= NULL
;
1205 if (msg
== NULL
) return;
1207 if (0 != _asl_msg_resolve_index(msg
, n
, &page
, &slot
)) return;
1208 _asl_msg_unset_page_slot(page
, slot
);
1212 #pragma mark copy and merge
1215 * Merge a key / val into a message (only ASL_TYPE_MSG).
1216 * Adds the key / val if the key is not found.
1217 * Does not replace the value if the key is found.
1220 _asl_msg_merge_key_val_op(asl_msg_t
*msg
, const char *key
, const char *val
, uint16_t op
)
1225 if (msg
== NULL
) return;
1226 if (key
== NULL
) return;
1231 i
= _asl_msg_index(msg
, key
, &slot
, &page
);
1232 if (i
!= IndexNull
) return;
1234 asl_msg_set_key_val_op(msg
, key
, val
, op
);
1238 * Merge msg into target (does not replace existing keys).
1239 * Creates a new asl_msg_t if target is NULL.
1243 asl_msg_merge(asl_msg_t
*target
, asl_msg_t
*msg
)
1245 uint32_t x
, type
, isnew
= 0;
1247 const char *key
, *val
;
1249 if (msg
== NULL
) return target
;
1251 type
= asl_get_type((asl_object_t
)msg
);
1256 target
= asl_msg_new(type
);
1259 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
1261 if (type
== ASL_TYPE_MSG
) op
= 0;
1262 if (isnew
== 1) asl_msg_set_key_val_op(target
, key
, val
, op
);
1263 else _asl_msg_merge_key_val_op(target
, key
, val
, op
);
1270 * replace key/value pairs from msg in target
1271 * Creates a new asl_msg_t if target is NULL.
1275 asl_msg_replace(asl_msg_t
*target
, asl_msg_t
*msg
)
1279 const char *key
, *val
;
1281 if (msg
== NULL
) return target
;
1283 type
= asl_get_type((asl_object_t
)msg
);
1285 if (target
== NULL
) target
= asl_msg_new(type
);
1287 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
1289 if (type
== ASL_TYPE_MSG
) op
= 0;
1290 asl_msg_set_key_val_op(target
, key
, val
, op
);
1301 asl_msg_copy(asl_msg_t
*msg
)
1303 return asl_msg_merge(NULL
, msg
);
1307 #pragma mark compare and test
1313 _asl_msg_equal(asl_msg_t
*a
, asl_msg_t
*b
)
1317 const char *key
, *va
, *vb
;
1319 if (asl_msg_count(a
) != asl_msg_count(b
)) return 0;
1325 for (x
= asl_msg_fetch(a
, 0, &key
, &va
, &oa
); x
!= IndexNull
; x
= asl_msg_fetch(a
, x
, &key
, &va
, &oa
))
1327 if (asl_msg_lookup(b
, key
, &vb
, &ob
) != 0) return 0;
1328 if (strcmp(va
, vb
)) return 0;
1329 if ((a
->asl_type
== ASL_TYPE_QUERY
) && (oa
!= ob
)) return 0;
1336 _asl_isanumber(const char *s
)
1340 if (s
== NULL
) return 0;
1343 if ((s
[0] == '-') || (s
[0] == '+')) i
= 1;
1345 if (s
[i
] == '\0') return 0;
1347 for (; s
[i
] != '\0'; i
++)
1349 if (!isdigit(s
[i
])) return 0;
1356 _asl_msg_basic_test(uint32_t op
, const char *q
, const char *m
, uint32_t n
)
1364 t
= op
& ASL_QUERY_OP_TRUE
;
1366 /* NULL value from query or message string fails */
1367 if ((q
== NULL
) || (m
== NULL
)) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1369 if (op
& ASL_QUERY_OP_REGEX
)
1371 /* greater than or less than make no sense in substring search */
1372 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1374 memset(&rex
, 0, sizeof(regex_t
));
1376 rflags
= REG_EXTENDED
| REG_NOSUB
;
1377 if (op
& ASL_QUERY_OP_CASEFOLD
) rflags
|= REG_ICASE
;
1379 /* A bad reqular expression matches nothing */
1380 if (regcomp(&rex
, q
, rflags
) != 0) return (t
& ASL_QUERY_OP_NOT_EQUAL
);
1382 cmp
= regexec(&rex
, m
, 0, NULL
, 0);
1385 if (t
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp
!= 0);
1389 if (op
& ASL_QUERY_OP_NUMERIC
)
1391 if (_asl_isanumber(q
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1392 if (_asl_isanumber(m
) == 0) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1399 case ASL_QUERY_OP_EQUAL
: return (nm
== nq
);
1400 case ASL_QUERY_OP_GREATER
: return (nm
> nq
);
1401 case ASL_QUERY_OP_GREATER_EQUAL
: return (nm
>= nq
);
1402 case ASL_QUERY_OP_LESS
: return (nm
< nq
);
1403 case ASL_QUERY_OP_LESS_EQUAL
: return (nm
<= nq
);
1404 case ASL_QUERY_OP_NOT_EQUAL
: return (nm
!= nq
);
1405 default: return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1410 if (op
& ASL_QUERY_OP_CASEFOLD
)
1412 if (n
== 0) cmp
= strcasecmp(m
, q
);
1413 else cmp
= strncasecmp(m
, q
, n
);
1417 if (n
== 0) cmp
= strcmp(m
, q
);
1418 else cmp
= strncmp(m
, q
, n
);
1423 case ASL_QUERY_OP_EQUAL
: return (cmp
== 0);
1424 case ASL_QUERY_OP_GREATER
: return (cmp
> 0);
1425 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp
>= 0);
1426 case ASL_QUERY_OP_LESS
: return (cmp
< 0);
1427 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp
<= 0);
1428 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp
!= 0);
1431 return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1435 _asl_msg_test_substring(uint32_t op
, const char *q
, const char *m
)
1437 uint32_t t
, i
, d
, lm
, lq
, match
, newop
;
1439 t
= op
& ASL_QUERY_OP_TRUE
;
1442 if (m
!= NULL
) lm
= strlen(m
);
1445 if (q
!= NULL
) lq
= strlen(q
);
1447 /* NULL is a substring of any string */
1448 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1450 /* A long string is defined to be not equal to a short string */
1451 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1453 /* greater than or less than make no sense in substring search */
1454 if ((t
== ASL_QUERY_OP_GREATER
) || (t
== ASL_QUERY_OP_LESS
)) return 0;
1457 * We scan the string doing an equality test.
1458 * If the input test is equality, we stop as soon as we hit a match.
1459 * Otherwise we keep scanning the whole message string.
1462 newop
|= ASL_QUERY_OP_EQUAL
;
1466 for (i
= 0; i
<= d
; i
++)
1468 if (_asl_msg_basic_test(newop
, q
, m
+ i
, lq
) != 0)
1470 if (t
& ASL_QUERY_OP_EQUAL
) return 1;
1475 /* If the input test was for equality, no matches were found */
1476 if (t
& ASL_QUERY_OP_EQUAL
) return 0;
1478 /* The input test was for not equal. Return true if no matches were found */
1479 return (match
== 0);
1483 _asl_msg_test_prefix(uint32_t op
, const char *q
, const char *m
)
1487 t
= op
& ASL_QUERY_OP_TRUE
;
1490 if (m
!= NULL
) lm
= strlen(m
);
1493 if (q
!= NULL
) lq
= strlen(q
);
1495 /* NULL is a prefix of any string */
1496 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1498 /* A long string is defined to be not equal to a short string */
1499 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1501 /* Compare two equal-length strings */
1502 return _asl_msg_basic_test(op
, q
, m
, lq
);
1506 _asl_msg_test_suffix(uint32_t op
, const char *q
, const char *m
)
1508 uint32_t lm
, lq
, d
, t
;
1510 t
= op
& ASL_QUERY_OP_TRUE
;
1513 if (m
!= NULL
) lm
= strlen(m
);
1516 if (q
!= NULL
) lq
= strlen(q
);
1518 /* NULL is a suffix of any string */
1519 if (lq
== 0) return (t
& ASL_QUERY_OP_EQUAL
);
1521 /* A long string is defined to be not equal to a short string */
1522 if (lq
> lm
) return (t
== ASL_QUERY_OP_NOT_EQUAL
);
1524 /* Compare two equal-length strings */
1526 return _asl_msg_basic_test(op
, q
, m
+ d
, lq
);
1530 * Splits out prefix, suffix, and substring tests.
1531 * Sends the rest to _asl_msg_basic_test().
1534 _asl_msg_test_expression(uint32_t op
, const char *q
, const char *m
)
1538 t
= op
& ASL_QUERY_OP_TRUE
;
1539 if (t
== ASL_QUERY_OP_TRUE
) return 1;
1541 if (op
& ASL_QUERY_OP_PREFIX
)
1543 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
);
1544 return _asl_msg_test_prefix(op
, q
, m
);
1546 if (op
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
);
1548 return _asl_msg_basic_test(op
, q
, m
, 0);
1552 * Special case for comparing time values.
1553 * If both inputs are time strings, this compares the time
1554 * value in seconds. Otherwise it just does normal matching.
1557 _asl_msg_test_time_expression(uint32_t op
, const char *q
, const char *m
)
1562 if ((op
& ASL_QUERY_OP_PREFIX
) || (op
& ASL_QUERY_OP_SUFFIX
) || (op
& ASL_QUERY_OP_REGEX
)) return _asl_msg_test_expression(op
, q
, m
);
1563 if ((q
== NULL
) || (m
== NULL
)) return _asl_msg_test_expression(op
, q
, m
);
1565 tq
= asl_core_parse_time(q
, NULL
);
1566 if (tq
< 0) return _asl_msg_test_expression(op
, q
, m
);
1568 tm
= asl_core_parse_time(m
, NULL
);
1569 if (tm
< 0) return _asl_msg_test_expression(op
, q
, m
);
1571 t
= op
& ASL_QUERY_OP_TRUE
;
1575 case ASL_QUERY_OP_FALSE
:
1579 case ASL_QUERY_OP_EQUAL
:
1581 if (tm
== tq
) return 1;
1584 case ASL_QUERY_OP_GREATER
:
1586 if (tm
> tq
) return 1;
1589 case ASL_QUERY_OP_GREATER_EQUAL
:
1591 if (tm
>= tq
) return 1;
1594 case ASL_QUERY_OP_LESS
:
1596 if (tm
< tq
) return 1;
1599 case ASL_QUERY_OP_LESS_EQUAL
:
1601 if (tm
<= tq
) return 1;
1604 case ASL_QUERY_OP_NOT_EQUAL
:
1606 if (tm
!= tq
) return 1;
1609 case ASL_QUERY_OP_TRUE
:
1619 /* test a query against a message */
1620 __private_extern__
int
1621 _asl_msg_test(asl_msg_t
*q
, asl_msg_t
*m
)
1626 const char *kq
, *vq
, *vm
;
1629 * Check each simple expression (key op val) separately.
1630 * The query suceeds (returns 1) if all simple expressions
1631 * succeed (i.e. AND the simple expressions).
1638 for (x
= asl_msg_fetch(q
, 0, &kq
, &vq
, &op
); x
!= IndexNull
; x
= asl_msg_fetch(q
, x
, &kq
, &vq
, &op
))
1640 /* Find query key in the message */
1642 i
= asl_msg_lookup(m
, kq
, &vm
, NULL
);
1644 /* ASL_QUERY_OP_TRUE tests if key is present in the message */
1645 t
= op
& ASL_QUERY_OP_TRUE
;
1646 if (t
== ASL_QUERY_OP_TRUE
)
1648 if (i
!= 0) return 0;
1652 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */
1653 if (t
== ASL_QUERY_OP_FALSE
)
1655 if (i
== 0) return 0;
1661 /* the message does NOT have query key - fail unless we are testing not equal */
1662 if (t
== ASL_QUERY_OP_NOT_EQUAL
) continue;
1667 if (streq(kq
, ASL_KEY_TIME
))
1669 cmp
= _asl_msg_test_time_expression(op
, vq
, vm
);
1673 cmp
= _asl_msg_test_expression(op
, vq
, vm
);
1676 if (cmp
== 0) return 0;
1682 /* returns 1 if a and b match, 0 otherwise */
1684 asl_msg_cmp(asl_msg_t
*a
, asl_msg_t
*b
)
1687 if (a
== NULL
) return 0;
1688 if (b
== NULL
) return 0;
1690 if (a
->asl_type
== b
->asl_type
) return _asl_msg_equal(a
, b
);
1691 if (a
->asl_type
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
);
1692 return _asl_msg_test(b
, a
);
1696 * Test a message against a query list.
1697 * Returns 1 if msg matches any query in the list, 0 otherwise.
1698 * Returns 1 if the query list is NULL or empty.
1701 asl_msg_cmp_list(asl_msg_t
*msg
, asl_msg_list_t
*list
)
1705 if (msg
== NULL
) return 0;
1706 if (list
== NULL
) return 1;
1707 if (list
->count
== 0) return 1;
1709 for (i
= 0; i
< list
->count
; i
++)
1711 if (_asl_msg_test(list
->msg
[i
], msg
)) return 1;
1718 #pragma mark string representation
1721 _asl_time_string(const char *infmt
, const char *str
, const char *nano
)
1725 char *ltime
, *out
, *p
, *q
;
1726 char ltbuf
[32], nanobuf
[16], fmt
[32], zstr
[8];
1728 uint32_t subsec
= 0;
1732 memset(zstr
, 0, sizeof(zstr
));
1739 * The longest infmt string we understand is "-hh:mm.N" (8 chars), so
1740 * it is safe to ignore the input if it doesn't fit in the temp buffer.
1741 * The default is local time zone format.
1745 snprintf(fmt
, sizeof(fmt
), "local");
1747 else if (strlen(infmt
) >= sizeof (fmt
))
1749 snprintf(fmt
, sizeof(fmt
), "local");
1753 snprintf(fmt
, sizeof(fmt
), "%s", infmt
);
1756 q
= strchr(fmt
, '.');
1761 if (q
!= '\0') subsec
= atoi(q
);
1770 if (nano
!= NULL
) nsec
= atoi(nano
);
1771 snprintf(nanobuf
, sizeof(nanobuf
), ".%09u", nsec
);
1772 if (subsec
> 9) subsec
= 9;
1773 nanobuf
[subsec
+ 1] = '\0';
1777 if (str
!= NULL
) tick
= asl_core_parse_time(str
, NULL
);
1779 if ((!strcasecmp(fmt
, "lcl")) || (!strcasecmp(fmt
, "local")))
1781 ltime
= ctime_r(&tick
, ltbuf
);
1782 if (ltime
== NULL
) return NULL
;
1784 asprintf(&out
, "%s%s", ltime
+ 4, nanobuf
);
1788 if ((!strcasecmp(fmt
, "jz")) || (!strcasecmp(fmt
, "iso8601")) || (!strcasecmp(fmt
, "iso8601e")))
1791 if (!strncasecmp(fmt
, "iso8601", 7)) sep
= 'T';
1793 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1795 off
= stm
.tm_gmtoff
;
1796 if ((neg
= (off
< 0))) off
*= -1;
1801 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02ld", neg
? '-' : '+', zh
);
1802 else snprintf(zstr
, sizeof(zstr
), "%c%02ld:%02ld", neg
? '-' : '+', zh
, zm
);
1804 asprintf(&out
, "%d-%02d-%02d%c%02d:%02d:%02d%s%s", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, sep
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
, zstr
);
1808 if (!strcasecmp(fmt
, "iso8601b"))
1810 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1812 off
= stm
.tm_gmtoff
;
1813 if ((neg
= (off
< 0))) off
*= -1;
1818 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02ld", neg
? '-' : '+', zh
);
1819 else snprintf(zstr
, sizeof(zstr
), "%c%02ld:%02ld", neg
? '-' : '+', zh
, zm
);
1821 asprintf(&out
, "%d%02d%02dT%02d%02d%02d%s%s", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
, zstr
);
1825 if ((!strcasecmp(fmt
, "sec")) || (!strcasecmp(fmt
, "raw")))
1827 asprintf(&out
, "%lu%s", tick
, nanobuf
);
1831 if (!strcasecmp(fmt
, "j"))
1833 if (NULL
== localtime_r(&tick
, &stm
)) return NULL
;
1834 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%s", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
);
1838 if ((!strcasecmp(fmt
, "utc")) || (!strcasecmp(fmt
, "zulu")) || (!strcasecmp(fmt
, "iso8601z")) || (!strcasecmp(fmt
, "iso8601ez")))
1841 if (!strncasecmp(fmt
, "iso8601", 7)) sep
= 'T';
1843 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1844 asprintf(&out
, "%d-%02d-%02d%c%02d:%02d:%02d%sZ", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, sep
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
);
1848 if (!strcasecmp(fmt
, "iso8601bz"))
1850 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1851 asprintf(&out
, "%d%02d%02dT%02d%02d%02d%sZ", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
);
1855 if ((fmt
[1] == '\0') && (((fmt
[0] >= 'a') && (fmt
[0] <= 'z')) || ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))))
1858 if (z
>= 'a') z
-= 32;
1860 if (z
== 'Z') off
= 0;
1861 else if ((z
>= 'A') && (z
<= 'I')) off
= ((z
- 'A') + 1) * SEC_PER_HOUR
;
1862 else if ((z
>= 'K') && (z
<= 'M')) off
= (z
- 'A') * SEC_PER_HOUR
;
1863 else if ((z
>= 'N') && (z
<= 'Y')) off
= ('M' - z
) * SEC_PER_HOUR
;
1868 if (fmt
[0] == '-') neg
= true;
1869 if ((*p
== '-') || (*p
== '+')) p
++;
1870 if ((*p
) >= '0' && (*p
<= '9'))
1875 if (p
!= NULL
) zm
= atoi(p
+ 1);
1882 off
= (zh
* 3600) + (zm
* 60);
1885 if (zm
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02ld", neg
? '-' : '+', zh
);
1886 else snprintf(zstr
, sizeof(zstr
), "%c%02ld:%02ld", neg
? '-' : '+', zh
, zm
);
1892 memset(&stm
, 0, sizeof (struct tm
));
1893 if (NULL
== gmtime_r(&tick
, &stm
)) return NULL
;
1895 if ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z'))
1897 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%s%c", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
, fmt
[0]);
1899 else if ((fmt
[0] >= 'a') && (fmt
[0] <= 'z'))
1901 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%s%c", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
, fmt
[0] - 32);
1905 asprintf(&out
, "%d-%02d-%02d %02d:%02d:%02d%s%s", stm
.tm_year
+ 1900, stm
.tm_mon
+ 1, stm
.tm_mday
, stm
.tm_hour
, stm
.tm_min
, stm
.tm_sec
, nanobuf
, zstr
);
1912 /* called from asl_format_message and _asl_send_message */
1913 __private_extern__ asl_string_t
*
1914 asl_msg_to_string_raw(uint32_t encoding
, asl_msg_t
*msg
, const char *tfmt
)
1916 uint32_t i
, x
, count
;
1917 const char *key
, *val
, *nano
;
1920 if (msg
== NULL
) return NULL
;
1922 count
= asl_msg_count(msg
);
1923 if (count
== 0) return NULL
;
1925 str
= asl_string_new(encoding
);
1926 if (str
== NULL
) return NULL
;
1933 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
1935 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
1937 if (key
== NULL
) continue;
1939 if (i
> 0) asl_string_append_char_no_encoding(str
, ' ');
1941 asl_string_append_char_no_encoding(str
, '[');
1942 asl_string_append_asl_key(str
, key
);
1944 if (!strcmp(key
, ASL_KEY_TIME
))
1947 asl_string_append_char_no_encoding(str
, ' ');
1949 if (val
!= NULL
) vtime
= _asl_time_string(tfmt
, val
, nano
);
1953 asl_string_append_no_encoding(str
, vtime
);
1958 asl_string_append_char_no_encoding(str
, '0');
1961 else if (val
!= NULL
)
1963 asl_string_append_char_no_encoding(str
, ' ');
1964 asl_string_append(str
, val
);
1967 asl_string_append_char_no_encoding(str
, ']');
1976 asl_string_append_asl_msg(asl_string_t
*str
, asl_msg_t
*msg
)
1978 const char *key
, *val
;
1982 if (msg
== NULL
) return str
;
1984 if (msg
->asl_type
== ASL_TYPE_QUERY
) asl_string_append(str
, "Q ");
1987 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, &op
))
1989 if (i
!= 0) asl_string_append_char_no_encoding(str
, ' ');
1992 asl_string_append_char_no_encoding(str
, '[');
1994 if (msg
->asl_type
== ASL_TYPE_QUERY
)
1996 asl_string_append_op(str
, op
);
1997 asl_string_append_char_no_encoding(str
, ' ');
2000 asl_string_append_asl_key(str
, key
);
2004 asl_string_append_char_no_encoding(str
, ' ');
2005 asl_string_append(str
, val
);
2008 asl_string_append_char_no_encoding(str
, ']');
2015 asl_msg_to_string(asl_msg_t
*msg
, uint32_t *len
)
2018 asl_string_t
*str
= asl_string_new(ASL_ENCODE_ASL
);
2019 if (str
== NULL
) return NULL
;
2021 str
= asl_string_append_asl_msg(str
, msg
);
2022 *len
= asl_string_length(str
);
2023 out
= asl_string_release_return_bytes(str
);
2028 _asl_msg_op_from_string(char *o
)
2032 op
= ASL_QUERY_OP_NULL
;
2034 if (o
== NULL
) return op
;
2036 for (i
= 0; o
[i
] != '\0'; i
++)
2038 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
;
2039 if (o
[i
] == 'C') op
|= ASL_QUERY_OP_CASEFOLD
;
2040 if (o
[i
] == 'R') op
|= ASL_QUERY_OP_REGEX
;
2041 if (o
[i
] == 'N') op
|= ASL_QUERY_OP_NUMERIC
;
2042 if (o
[i
] == 'S') op
|= ASL_QUERY_OP_SUBSTRING
;
2043 if (o
[i
] == 'A') op
|= ASL_QUERY_OP_PREFIX
;
2044 if (o
[i
] == 'Z') op
|= ASL_QUERY_OP_SUFFIX
;
2045 if (o
[i
] == '<') op
|= ASL_QUERY_OP_LESS
;
2046 if (o
[i
] == '>') op
|= ASL_QUERY_OP_GREATER
;
2047 if (o
[i
] == '=') op
|= ASL_QUERY_OP_EQUAL
;
2048 if (o
[i
] == '!') op
|= ASL_QUERY_OP_NOT_EQUAL
;
2049 if (o
[i
] == 'T') op
|= ASL_QUERY_OP_TRUE
;
2056 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
)
2058 char *str
, *out
, c
, oval
;
2059 uint32_t i
, len
, n
, outlen
;
2063 if (p
== NULL
) return NULL
;
2064 if (*p
== NULL
) return NULL
;
2065 if (**p
== '\0') return NULL
;
2067 /* skip one space if it's there (word separator) */
2068 if (**p
== ' ') (*p
)++;
2070 /* skip leading white space */
2073 while ((**p
== ' ') || (**p
== '\t')) (*p
)++;
2076 if (**p
== '\0') return NULL
;
2077 if (**p
== '\n') return NULL
;
2088 if (out
== NULL
) return NULL
;
2095 /* scan for token and calulate it's length (input and decoded output len) */
2103 /* stop scanning when we hit a delimiter */
2104 if (((spacedel
!= 0) && (c
== ' ')) || (c
== ']') || (c
== '\0')) break;
2110 if ((c
== 'a') || (c
== 'b') || (c
== 't') || (c
== 'n') || (c
== 'v') || (c
== 'f') || (c
== 'r') || (c
== 's') || (c
== '[') || (c
== '\\') || (c
== ']'))
2115 if (str
[++len
] == '\0') return NULL
;
2119 if (str
[++len
] == '\0') return NULL
;
2120 if (str
[++len
] == '\0') return NULL
;
2122 else if ((c
>= '0') && (c
<= '3'))
2124 if (str
[++len
] == '\0') return NULL
;
2125 if (str
[++len
] == '\0') return NULL
;
2139 if ((len
== 0) && (**p
== ']'))
2144 if (out
== NULL
) return NULL
;
2153 out
= malloc(outlen
+ 1);
2154 if (out
== NULL
) return NULL
;
2157 for (i
= 0; i
< len
; i
++)
2214 if (str
[i
] == '?') out
[n
++] = 127;
2215 else out
[n
++] = str
[i
] - 64;
2224 if (str
[i
] == '?') out
[n
++] = 255;
2225 else out
[n
++] = str
[i
] + 64;
2230 out
[n
++] = str
[i
] + 128;
2240 else if ((c
>= '0') && (c
<= '3'))
2242 oval
= (c
- '0') * 64;
2246 if ((c
< '0') || (c
> '7'))
2253 oval
+= ((c
- '0') * 8);
2257 if ((c
< '0') || (c
> '7'))
2278 if ((c
< '0') || (c
> '9')) *tt
= TOKEN_WORD
;
2289 asl_msg_from_string(const char *buf
)
2291 uint32_t tt
, type
, op
;
2292 char *k
, *v
, *o
, *p
;
2295 if (buf
== NULL
) return NULL
;
2297 type
= ASL_TYPE_MSG
;
2300 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2301 if (k
== NULL
) return NULL
;
2305 type
= ASL_TYPE_QUERY
;
2308 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2310 else if (tt
== TOKEN_INT
)
2312 /* Leading integer is a string length - skip it */
2314 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2315 if (k
== NULL
) return NULL
;
2318 out
= asl_msg_new(ASL_TYPE_MSG
);
2319 if (out
== NULL
) return NULL
;
2321 out
->asl_type
= type
;
2323 /* OPEN WORD [WORD [WORD]] CLOSE */
2326 op
= ASL_QUERY_OP_NULL
;
2328 if (tt
!= TOKEN_OPEN
)
2330 asl_msg_release(out
);
2336 /* get op for query type */
2337 if (type
== ASL_TYPE_QUERY
)
2339 o
= _asl_msg_get_next_word(&p
, &tt
, 1);
2340 if ((o
== NULL
) || (tt
!= TOKEN_WORD
))
2342 if (o
!= NULL
) free(o
);
2343 asl_msg_release(out
);
2347 op
= _asl_msg_op_from_string(o
);
2351 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2352 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
2353 if ((k
== NULL
) || (tt
!= TOKEN_WORD
))
2355 if (k
!= NULL
) free(k
);
2356 asl_msg_release(out
);
2360 v
= _asl_msg_get_next_word(&p
, &tt
, 0);
2361 if (tt
== TOKEN_INT
) tt
= TOKEN_WORD
;
2364 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
2369 if (tt
== TOKEN_CLOSE
)
2371 asl_msg_set_key_val_op(out
, k
, NULL
, op
);
2373 else if (tt
== TOKEN_WORD
)
2375 asl_msg_set_key_val_op(out
, k
, v
, op
);
2379 if (k
!= NULL
) free(k
);
2380 if (v
!= NULL
) free(v
);
2381 asl_msg_release(out
);
2385 if (k
!= NULL
) free(k
);
2386 if (v
!= NULL
) free(v
);
2388 if (tt
!= TOKEN_CLOSE
)
2390 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2391 if (k
== NULL
) break;
2393 if (tt
!= TOKEN_CLOSE
)
2395 asl_msg_release(out
);
2402 k
= _asl_msg_get_next_word(&p
, &tt
, 1);
2403 if (k
== NULL
) break;
2410 _asl_level_string(int level
)
2412 if (level
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
;
2413 if (level
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
;
2414 if (level
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
;
2415 if (level
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
;
2416 if (level
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
;
2417 if (level
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
;
2418 if (level
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
;
2419 if (level
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
;
2424 _asl_level_char(int level
)
2426 if (level
== ASL_LEVEL_EMERG
) return "P";
2427 if (level
== ASL_LEVEL_ALERT
) return "A";
2428 if (level
== ASL_LEVEL_CRIT
) return "C";
2429 if (level
== ASL_LEVEL_ERR
) return "E";
2430 if (level
== ASL_LEVEL_WARNING
) return "W";
2431 if (level
== ASL_LEVEL_NOTICE
) return "N";
2432 if (level
== ASL_LEVEL_INFO
) return "I";
2433 if (level
== ASL_LEVEL_DEBUG
) return "D";
2438 * Find the value for a key in a message and append a formatted value to str.
2439 * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)).
2440 * WARNING: modifies kf!
2442 static asl_string_t
*
2443 _asl_string_append_value_for_key_format(asl_string_t
*str
, asl_msg_t
*msg
, char *kf
, const char *tfmt
)
2445 uint32_t i
, get_fmt
;
2448 const char *mval
, *nano
;
2450 if (str
== NULL
) return NULL
;
2451 if (msg
== NULL
) return str
;
2452 if (kf
== NULL
) return str
;
2458 for (i
= 0; kf
[i
] != '\0'; i
++)
2465 else if (kf
[i
] != '(')
2467 if (key
== NULL
) key
= kf
+ i
;
2468 else if ((get_fmt
== 1) && (fmt
== NULL
)) fmt
= kf
+ i
;
2472 if (key
== NULL
) return str
;
2475 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
2477 status
= asl_msg_lookup(msg
, key
, &mval
, NULL
);
2478 if ((status
!= 0) || (mval
== NULL
)) return str
;
2480 if (!strcmp(key
, ASL_KEY_TIME
))
2484 /* format in $((Time)(fmt)) overrides tfmt */
2487 fval
= _asl_time_string(tfmt
, mval
, nano
);
2491 fval
= _asl_time_string(fmt
, mval
, nano
);
2496 asl_string_append_no_encoding(str
, fval
);
2501 asl_string_append_char_no_encoding(str
, '0');
2507 /* Level: num str */
2508 if (!strcmp(key
, ASL_KEY_LEVEL
))
2512 asl_string_append_no_encoding(str
, mval
);
2514 else if (!strcmp(fmt
, "str"))
2516 mval
= _asl_level_string(atoi(mval
));
2517 asl_string_append_no_encoding(str
, mval
);
2519 else if (!strcmp(fmt
, "char"))
2521 mval
= _asl_level_char(atoi(mval
));
2522 asl_string_append_no_encoding(str
, mval
);
2526 asl_string_append_no_encoding(str
, mval
);
2532 return asl_string_append(str
, mval
);
2536 * format a message for printing
2537 * out parameter len returns string length including trailing NUL
2540 asl_format_message(asl_msg_t
*msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
)
2542 char *out
, *vtime
, *k
, c
, skey
[512], tfmt_ext
[16];
2543 const char *vhost
, *vpid
, *vsender
, *vmessage
, *vlevel
, *vrefproc
, *vrefpid
, *v
, *key
, *val
, *nano
;
2544 int i
, j
, l
, mf
, paren
, oval
, level
;
2552 if (msg
== NULL
) return NULL
;
2556 if (mfmt
== NULL
) mf
= MFMT_RAW
;
2557 else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf
= MFMT_RAW
;
2558 else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf
= MFMT_STD
;
2559 else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf
= MFMT_BSD
;
2560 else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf
= MFMT_XML
;
2561 else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf
= MFMT_MSG
;
2562 else if ((!strncmp(mfmt
, ASL_MSG_FMT_RAW
, 3)) && (mfmt
[3] == '.'))
2565 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2567 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "sec.%s", mfmt
+ 4);
2568 tfmt
= (const char *)tfmt_ext
;
2571 else if ((!strncmp(mfmt
, ASL_MSG_FMT_STD
, 3)) && (mfmt
[3] == '.'))
2574 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2576 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt
+ 4);
2577 tfmt
= (const char *)tfmt_ext
;
2580 else if ((!strncmp(mfmt
, ASL_MSG_FMT_BSD
, 3)) && (mfmt
[3] == '.'))
2583 if ((tfmt
== NULL
) && (mfmt
[4] != '\0'))
2585 snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt
+ 4);
2586 tfmt
= (const char *)tfmt_ext
;
2592 asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
);
2596 str
= asl_msg_to_string_raw(text_encoding
, msg
, tfmt
);
2597 asl_string_append_char_no_encoding(str
, '\n');
2599 *len
= asl_string_length(str
);
2600 out
= asl_string_release_return_bytes(str
);
2608 if (asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
) != 0) return NULL
;
2610 str
= asl_string_new(text_encoding
);
2611 if (str
== NULL
) return NULL
;
2613 asl_string_append(str
, vmessage
);
2614 asl_string_append_char_no_encoding(str
, '\n');
2616 *len
= asl_string_length(str
);
2617 out
= asl_string_release_return_bytes(str
);
2621 if ((mf
== MFMT_STD
) || (mf
== MFMT_BSD
))
2623 /* COMMON: Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/
2624 /* BSD: <COMMON>: message */
2625 /* STD: <COMMON> <Level>: message */
2637 if (asl_msg_lookup(msg
, ASL_KEY_TIME
, &v
, NULL
) == 0)
2639 vtime
= _asl_time_string(tfmt
, v
, nano
);
2643 if (asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &vlevel
, NULL
) == 0)
2645 if (vlevel
!= NULL
) level
= atoi(vlevel
);
2648 if (asl_msg_lookup(msg
, ASL_KEY_HOST
, &vhost
, NULL
) == 0)
2650 if (vhost
== NULL
) vhost
= "unknown";
2653 if (asl_msg_lookup(msg
, ASL_KEY_SENDER
, &vsender
, NULL
) == 0)
2655 if (vsender
== NULL
) vsender
= "unknown";
2658 asl_msg_lookup(msg
, ASL_KEY_PID
, &vpid
, NULL
);
2659 asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
);
2660 asl_msg_lookup(msg
, ASL_KEY_REF_PROC
, &vrefproc
, NULL
);
2661 asl_msg_lookup(msg
, ASL_KEY_REF_PID
, &vrefpid
, NULL
);
2664 str
= asl_string_new(text_encoding
);
2665 if (str
== NULL
) return NULL
;
2669 asl_string_append(str
, vtime
);
2674 asl_string_append_char_no_encoding(str
, '0');
2677 asl_string_append_char_no_encoding(str
, ' ');
2678 asl_string_append(str
, vhost
);
2679 asl_string_append_char_no_encoding(str
, ' ');
2680 asl_string_append(str
, vsender
);
2682 if ((vpid
!= NULL
) && (strcmp(vpid
, "-1")))
2684 asl_string_append_char_no_encoding(str
, '[');
2685 asl_string_append(str
, vpid
);
2686 asl_string_append_char_no_encoding(str
, ']');
2689 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_no_encoding(str
, " (");
2691 if (vrefproc
!= NULL
) asl_string_append(str
, vrefproc
);
2692 if (vrefpid
!= NULL
)
2694 asl_string_append_char_no_encoding(str
, '[');
2695 asl_string_append(str
, vrefpid
);
2696 asl_string_append_char_no_encoding(str
, ']');
2699 if ((vrefproc
!= NULL
) || (vrefpid
!= NULL
)) asl_string_append_char_no_encoding(str
, ')');
2703 asl_string_append_no_encoding(str
, " <");
2704 asl_string_append(str
, _asl_level_string(level
));
2705 asl_string_append_char_no_encoding(str
, '>');
2708 asl_string_append_no_encoding(str
, ": ");
2709 if (vmessage
!= NULL
) asl_string_append(str
, vmessage
);
2710 asl_string_append_char_no_encoding(str
, '\n');
2712 *len
= asl_string_length(str
);
2713 out
= asl_string_release_return_bytes(str
);
2719 str
= asl_string_new(text_encoding
);
2720 if (str
== NULL
) return NULL
;
2722 asl_string_append_char_no_encoding(str
, '\t');
2723 asl_string_append_no_encoding(str
, "<dict>");
2724 asl_string_append_char_no_encoding(str
, '\n');
2726 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
2728 if (asl_is_utf8(key
) == 1)
2730 asl_string_append_xml_tag(str
, "key", key
);
2731 if (!strcmp(key
, ASL_KEY_TIME
))
2733 vtime
= _asl_time_string(tfmt
, val
, nano
);
2736 asl_string_append_xml_tag(str
, "string", vtime
);
2741 asl_string_append_xml_tag(str
, "string", "0");
2746 if (asl_is_utf8(val
) == 1) asl_string_append_xml_tag(str
, "string", val
);
2749 b64
= asl_b64_encode((uint8_t *)val
, strlen(val
));
2750 asl_string_append_xml_tag(str
, "data", (char *)b64
);
2757 asl_string_append_char_no_encoding(str
, '\t');
2758 asl_string_append_no_encoding(str
, "</dict>");
2759 asl_string_append_char_no_encoding(str
, '\n');
2761 *len
= asl_string_length(str
);
2762 out
= asl_string_release_return_bytes(str
);
2768 * The format string may contain arbitrary characters.
2769 * Keys are identified by $Key or $(Key). The value for
2770 * that key is substituted. If there are alterate formats
2771 * for the value (for example a time may be formatted as
2772 * raw seconds, in UTC, or a local timezone), then the
2773 * key may be $((Key)(Format)). "\$" prints a plain "$".
2776 str
= asl_string_new(text_encoding
);
2777 if (str
== NULL
) return NULL
;
2780 * We need enough space to copy any keys found in mfmt.
2781 * The key obviously can't be longer than strlen(mfmt),
2782 * in fact, keys must be shorter, since there's at least a '$'
2783 * in front of the key, so we allocate a buffer with strlen(mfmt).
2784 * If strlen(mfmt) <= sizeof(skey), we use skey to avoid a malloc.
2788 if (x
<= sizeof(skey
))
2795 if (k
== NULL
) return NULL
;
2800 for (i
= 0; mfmt
[i
] != '\0'; i
++)
2806 /* scan key, (key) or ((key)(format)) */
2807 for (j
= i
+ 1; mfmt
[j
] != 0; j
++)
2813 else if (mfmt
[j
] == ')')
2815 if (paren
> 0) paren
--;
2822 else if (((mfmt
[j
] == ' ') || (mfmt
[j
] == '\t')) && (paren
== 0)) break;
2825 /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */
2827 memcpy(k
, mfmt
+i
+1, l
);
2829 _asl_string_append_value_for_key_format(str
, msg
, k
, tfmt
);
2835 if (mfmt
[i
] == '\\')
2838 if (mfmt
[i
] == '$') asl_string_append_char_no_encoding(str
, '$');
2839 else if (mfmt
[i
] == 'e') asl_string_append_char_no_encoding(str
, '\e');
2840 else if (mfmt
[i
] == 's') asl_string_append_char_no_encoding(str
, ' ');
2841 else if (mfmt
[i
] == 'a') asl_string_append_char_no_encoding(str
, '\a');
2842 else if (mfmt
[i
] == 'b') asl_string_append_char_no_encoding(str
, '\b');
2843 else if (mfmt
[i
] == 'f') asl_string_append_char_no_encoding(str
, '\f');
2844 else if (mfmt
[i
] == 'n') asl_string_append_char_no_encoding(str
, '\n');
2845 else if (mfmt
[i
] == 'r') asl_string_append_char_no_encoding(str
, '\r');
2846 else if (mfmt
[i
] == 't') asl_string_append_char_no_encoding(str
, '\t');
2847 else if (mfmt
[i
] == 'v') asl_string_append_char_no_encoding(str
, '\v');
2848 else if (mfmt
[i
] == '\'') asl_string_append_char_no_encoding(str
, '\'');
2849 else if (mfmt
[i
] == '\\') asl_string_append_char_no_encoding(str
, '\\');
2850 else if (isdigit(mfmt
[i
]))
2852 oval
= mfmt
[i
] - '0';
2853 if (isdigit(mfmt
[i
+1]))
2856 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2857 if (isdigit(mfmt
[i
+1]))
2860 oval
= (oval
* 8) + (mfmt
[i
] - '0');
2864 asl_string_append_char_no_encoding(str
, c
);
2869 if (mfmt
[i
] == '\0') break;
2870 asl_string_append_char_no_encoding(str
, mfmt
[i
]);
2873 if (k
!= skey
) free(k
);
2875 asl_string_append_char_no_encoding(str
, '\n');
2877 *len
= asl_string_length(str
);
2878 out
= asl_string_release_return_bytes(str
);
2883 #pragma mark asl_object support
2885 static asl_object_private_t
*
2886 _jump_alloc(uint32_t type
)
2888 return (asl_object_private_t
*)asl_msg_new(type
);
2892 _jump_dealloc(asl_object_private_t
*obj
)
2894 asl_msg_t
*msg
= (asl_msg_t
*)obj
;
2897 asl_msg_t
*next
= msg
->next
;
2898 _asl_msg_free_page(msg
);
2904 _jump_set_key_val_op(asl_object_private_t
*obj
, const char *key
, const char *val
, uint16_t op
)
2907 int status
= asl_msg_set_key_val_op((asl_msg_t
*)obj
, key
, val
, op32
);
2908 return (status
== ASL_STATUS_OK
) ? 0 : -1;
2912 _jump_unset_key(asl_object_private_t
*obj
, const char *key
)
2914 asl_msg_unset((asl_msg_t
*)obj
, key
);
2918 _jump_get_val_op_for_key(asl_object_private_t
*obj
, const char *key
, const char **val
, uint16_t *op
)
2920 return asl_msg_lookup((asl_msg_t
*)obj
, key
, val
, op
);
2924 _jump_get_key_val_op_at_index(asl_object_private_t
*obj
, size_t n
, const char **key
, const char **val
, uint16_t *op
)
2926 uint32_t slot
= IndexNull
;
2927 asl_msg_t
*page
= NULL
;
2929 if (0 != _asl_msg_resolve_index((asl_msg_t
*)obj
, n
, &page
, &slot
)) return -1;
2931 if (key
!= NULL
) *key
= _asl_msg_slot_key(page
, slot
);
2932 if (val
!= NULL
) *val
= _asl_msg_slot_val(page
, slot
);
2933 if (op
!= NULL
) *op
= page
->op
[slot
];
2938 _jump_count(asl_object_private_t
*obj
)
2940 size_t count
= asl_msg_count((asl_msg_t
*)obj
);
2945 _jump_append(asl_object_private_t
*obj
, asl_object_private_t
*newobj
)
2947 int type
= asl_get_type((asl_object_t
)newobj
);
2948 if ((type
!= ASL_TYPE_QUERY
) && (type
!= ASL_TYPE_MSG
)) return;
2950 asl_msg_merge((asl_msg_t
*)obj
, (asl_msg_t
*)newobj
);
2954 _jump_prepend(asl_object_private_t
*obj
, asl_object_private_t
*newobj
)
2956 if (obj
== NULL
) return;
2958 int type
= asl_get_type((asl_object_t
)newobj
);
2959 if ((type
!= ASL_TYPE_QUERY
) && (type
!= ASL_TYPE_MSG
)) return;
2961 asl_msg_replace((asl_msg_t
*)obj
, (asl_msg_t
*)newobj
);
2964 static asl_object_private_t
*
2965 _jump_search(asl_object_private_t
*obj
, asl_object_private_t
*query
)
2967 if (obj
== NULL
) return NULL
;
2971 /* NULL matches any message */
2972 asl_msg_list_t
*out
= asl_msg_list_new();
2973 asl_msg_list_append(out
, obj
);
2974 return (asl_object_private_t
*)out
;
2977 if ((query
->asl_type
!= ASL_TYPE_MSG
) && (query
->asl_type
!= ASL_TYPE_QUERY
)) return NULL
;
2979 if (asl_msg_cmp((asl_msg_t
*)obj
, (asl_msg_t
*)query
) == 1)
2981 asl_msg_list_t
*out
= asl_msg_list_new();
2982 asl_msg_list_append(out
, obj
);
2983 return (asl_object_private_t
*)out
;
2989 static asl_object_private_t
*
2990 _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
)
2992 if (obj
== NULL
) return NULL
;
2996 /* NULL matches any message */
2997 asl_msg_list_t
*out
= asl_msg_list_new();
2998 asl_msg_list_append(out
, obj
);
2999 return (asl_object_private_t
*)out
;
3002 if (asl_msg_cmp_list((asl_msg_t
*)obj
, (asl_msg_list_t
*)qlist
) == 0) return NULL
;
3004 asl_msg_list_t
*out
= asl_msg_list_new();
3005 asl_msg_list_append(out
, obj
);
3006 return (asl_object_private_t
*)out
;
3010 __private_extern__
const asl_jump_table_t
*
3011 asl_msg_jump_table()
3013 static const asl_jump_table_t jump
=
3015 .alloc
= &_jump_alloc
,
3016 .dealloc
= &_jump_dealloc
,
3017 .set_key_val_op
= &_jump_set_key_val_op
,
3018 .unset_key
= &_jump_unset_key
,
3019 .get_val_op_for_key
= &_jump_get_val_op_for_key
,
3020 .get_key_val_op_at_index
= &_jump_get_key_val_op_at_index
,
3021 .count
= &_jump_count
,
3024 .get_object_at_index
= NULL
,
3025 .set_iteration_index
= NULL
,
3026 .remove_object_at_index
= NULL
,
3027 .append
= &_jump_append
,
3028 .prepend
= &_jump_prepend
,
3029 .search
= &_jump_search
,
3030 .match
= &_jump_match