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 <asl_client.h> 
  42 #include <sys/types.h> 
  43 #include <libkern/OSAtomic.h> 
  45 #include <asl_msg_list.h> 
  60 #define SEC_PER_HOUR 3600 
  64 #define forever for(;;) 
  66 #ifndef ASL_QUERY_OP_FALSE 
  67 #define ASL_QUERY_OP_FALSE 0 
  70 #define AUX_0_TIME      0x00000001 
  71 #define AUX_0_TIME_NSEC 0x00000002 
  72 #define AUX_0_HOST      0x00000004 
  73 #define AUX_0_SENDER    0x00000008 
  74 #define AUX_0_FACILITY  0x00000010 
  75 #define AUX_0_PID       0x00000020 
  76 #define AUX_0_UID       0x00000040 
  77 #define AUX_0_GID       0x00000080 
  78 #define AUX_0_MSG       0x00000100 
  79 #define AUX_0_OPTION    0x00000200 
  80 #define AUX_0_LEVEL     0x00000400 
  83 int asl_is_utf8(const char *str
); 
  84 uint8_t *asl_b64_encode(const uint8_t *buf
, size_t len
); 
  86 void _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t 
*msg
); 
  89 #pragma mark standard message keys 
  91 static const char *ASLStandardKey
[] = 
 114 static const char *MTStandardKey
[] = 
 116         "com.apple.message.domain", 
 117         "com.apple.message.domain_scope", 
 118         "com.apple.message.result", 
 119         "com.apple.message.signature", 
 120         "com.apple.message.signature2", 
 121         "com.apple.message.signature3", 
 122         "com.apple.message.success", 
 123         "com.apple.message.uuid", 
 124         "com.apple.message.value", 
 125         "com.apple.message.value2", 
 126         "com.apple.message.value3", 
 127         "com.apple.message.value4", 
 128         "com.apple.message.value5" 
 132 _asl_msg_std_key(const char *s
, uint32_t len
) 
 134         if ((len 
> 18) && (streq_len(s
, "com.apple.message.", 18))) 
 136                 if (streq(s 
+ 18, "domain")) return ASL_MT_KEY_DOMAIN
; 
 137                 else if (streq(s 
+ 18, "domain_scope")) return ASL_MT_KEY_SCOPE
; 
 138                 else if (streq(s 
+ 18, "result")) return ASL_MT_KEY_RESULT
; 
 139                 else if (streq(s 
+ 18, "signature")) return ASL_MT_KEY_SIG
; 
 140                 else if (streq(s 
+ 18, "signature2")) return ASL_MT_KEY_SIG2
; 
 141                 else if (streq(s 
+ 18, "signature3")) return ASL_MT_KEY_SIG3
; 
 142                 else if (streq(s 
+ 18, "success")) return ASL_MT_KEY_SUCCESS
; 
 143                 else if (streq(s 
+ 18, "uuid")) return ASL_MT_KEY_UUID
; 
 144                 else if (streq(s 
+ 18, "value")) return ASL_MT_KEY_VAL
; 
 145                 else if (streq(s 
+ 18, "value2")) return ASL_MT_KEY_VAL2
; 
 146                 else if (streq(s 
+ 18, "value3")) return ASL_MT_KEY_VAL3
; 
 147                 else if (streq(s 
+ 18, "value4")) return ASL_MT_KEY_VAL4
; 
 148                 else if (streq(s 
+ 18, "value5")) return ASL_MT_KEY_VAL5
; 
 157                         if streq(s
, ASL_KEY_PID
) return ASL_STD_KEY_PID
; 
 158                         else if streq(s
, ASL_KEY_UID
) return ASL_STD_KEY_UID
; 
 159                         else if streq(s
, ASL_KEY_GID
) return ASL_STD_KEY_GID
; 
 163                         if streq(s
, ASL_KEY_TIME
) return ASL_STD_KEY_TIME
; 
 164                         else if streq(s
, ASL_KEY_HOST
) return ASL_STD_KEY_HOST
; 
 168                         if streq(s
, ASL_KEY_LEVEL
) return ASL_STD_KEY_LEVEL
; 
 172                         if streq(s
, ASL_KEY_SENDER
) return ASL_STD_KEY_SENDER
; 
 173                         else if streq(s
, ASL_KEY_REF_PID
) return ASL_STD_KEY_REF_PID
; 
 177                         if streq(s
, ASL_KEY_MSG
) return ASL_STD_KEY_MESSAGE
; 
 178                         else if streq(s
, ASL_KEY_SESSION
) return ASL_STD_KEY_SESSION
; 
 179                         else if streq(s
, ASL_KEY_READ_UID
) return ASL_STD_KEY_READ_UID
; 
 180                         else if streq(s
, ASL_KEY_READ_GID
) return ASL_STD_KEY_READ_GID
; 
 181                         else if streq(s
, ASL_KEY_REF_PROC
) return ASL_STD_KEY_REF_PROC
; 
 185                         if streq(s
, ASL_KEY_FACILITY
) return ASL_STD_KEY_FACILITY
; 
 189                         if streq(s
, ASL_KEY_OPTION
) return ASL_STD_KEY_OPTION
; 
 193                         if streq(s
, ASL_KEY_TIME_NSEC
) return ASL_STD_KEY_NANO
; 
 197                         if streq(s
, ASL_KEY_MSG_ID
) return ASL_STD_KEY_MSG_ID
; 
 201                         if streq(s
, ASL_KEY_EXPIRE_TIME
) return ASL_STD_KEY_EXPIRE
; 
 205                         if streq(s
, ASL_KEY_FREE_NOTE
) return ASL_STD_KEY_FREE_NOTE
; 
 220 _slot_count(asl_msg_t 
*m
) 
 222         if (m 
== NULL
) return 0; 
 223         if (m
->asl_type 
== ASL_TYPE_MSG
) return ASL_MSG_KVO_MSG_SLOTS
; 
 224         if (m
->asl_type 
== ASL_TYPE_QUERY
) return ASL_MSG_KVO_QUERY_SLOTS
; 
 230 _get_slot_key(asl_msg_t 
*m
, uint32_t slot
) 
 232         if (m 
== NULL
) return 0; 
 234         if (m
->asl_type 
== ASL_TYPE_MSG
) 
 236                 if (slot 
< ASL_MSG_KVO_MSG_SLOTS
) return m
->kvo
[slot
]; 
 240         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 242                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot
]; 
 251 _set_slot_key(asl_msg_t 
*m
, uint32_t slot
, uint16_t x
) 
 253         if (m 
== NULL
) return; 
 255         if (m
->asl_type 
== ASL_TYPE_MSG
) 
 257                 if (slot 
< ASL_MSG_KVO_MSG_SLOTS
) m
->kvo
[slot
] = x
; 
 261         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 263                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot
] = x
; 
 270 _get_slot_val(asl_msg_t 
*m
, uint32_t slot
) 
 272         if (m 
== NULL
) return 0; 
 273         if (m
->asl_type 
== ASL_TYPE_MSG
) 
 275                 if (slot 
< ASL_MSG_KVO_MSG_SLOTS
) return m
->kvo
[slot 
+ ASL_MSG_KVO_MSG_SLOTS
]; 
 279         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 281                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot 
+ ASL_MSG_KVO_QUERY_SLOTS
]; 
 289 _set_slot_val(asl_msg_t 
*m
, uint32_t slot
, uint16_t x
) 
 291         if (m 
== NULL
) return; 
 293         if (m
->asl_type 
== ASL_TYPE_MSG
) 
 295                 if (slot 
< ASL_MSG_KVO_MSG_SLOTS
) m
->kvo
[slot 
+ ASL_MSG_KVO_MSG_SLOTS
] = x
; 
 299         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 301                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot 
+ ASL_MSG_KVO_QUERY_SLOTS
] = x
; 
 307 _get_slot_op(asl_msg_t 
*m
, uint32_t slot
) 
 309         if (m 
== NULL
) return 0; 
 311         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 313                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) return m
->kvo
[slot 
+ (ASL_MSG_KVO_QUERY_SLOTS 
* 2)]; 
 321 _set_slot_op(asl_msg_t 
*m
, uint32_t slot
, uint16_t x
) 
 323         if (m 
== NULL
) return; 
 325         if (m
->asl_type 
== ASL_TYPE_QUERY
) 
 327                 if (slot 
< ASL_MSG_KVO_QUERY_SLOTS
) m
->kvo
[slot 
+ (ASL_MSG_KVO_QUERY_SLOTS 
* 2)] = x
; 
 332 _asl_msg_make_page(uint32_t type
) 
 335         asl_msg_t 
*out 
= (asl_msg_t 
*)calloc(1, sizeof(asl_msg_t
)); 
 336         if (out 
== NULL
) return NULL
; 
 338         if (type 
== ASL_TYPE_MSG
) n 
= ASL_MSG_KVO_MSG_SLOTS 
* 2; 
 339         else if (type 
== ASL_TYPE_QUERY
) n 
= ASL_MSG_KVO_QUERY_SLOTS 
* 2; 
 341         for (i 
= 0; i 
< n
; i
++) out
->kvo
[i
] = ASL_MSG_SLOT_FREE
; 
 343         out
->mem_size 
= sizeof(asl_msg_t
); 
 344         out
->asl_type 
= type
; 
 350 asl_msg_retain(asl_msg_t 
*msg
) 
 352         if (msg 
== NULL
) return NULL
; 
 353         asl_retain((asl_object_t
)msg
); 
 358 asl_msg_release(asl_msg_t 
*msg
) 
 360         if (msg 
== NULL
) return; 
 361         asl_release((asl_object_t
)msg
); 
 365 _asl_msg_slot_key(asl_msg_t 
*page
, uint32_t slot
) 
 370         if (page 
== NULL
) return NULL
; 
 372         if ((page
->asl_type 
== ASL_TYPE_MSG
) && (slot 
>= ASL_MSG_KVO_MSG_SLOTS
)) return NULL
; 
 373         else if ((page
->asl_type 
== ASL_TYPE_QUERY
) && (slot 
>= ASL_MSG_KVO_QUERY_SLOTS
)) return NULL
; 
 375         k 
= _get_slot_key(page
, slot
); 
 377         if (k 
== ASL_MSG_SLOT_FREE
) return NULL
; 
 379         switch (k 
& ASL_MSG_KV_MASK
) 
 381                 case ASL_MSG_KV_INLINE
: 
 383                         return page
->data 
+ k
; 
 385                 case ASL_MSG_KV_DICT
: 
 387                         if ((k 
> ASL_STD_KEY_BASE
) && (k 
<= ASL_STD_KEY_LAST
)) 
 389                                 x 
= k 
- ASL_STD_KEY_BASE 
- 1; 
 390                                 return ASLStandardKey
[x
]; 
 392                         else if ((k 
> ASL_MT_KEY_BASE
) && (k 
<= ASL_MT_KEY_LAST
)) 
 394                                 x 
= k 
- ASL_MT_KEY_BASE 
- 1; 
 395                                 return MTStandardKey
[x
]; 
 400                 case ASL_MSG_KV_EXTERN
: 
 402                         x 
= k 
& ASL_MSG_OFFSET_MASK
; 
 403                         memcpy(&out
, page
->data 
+ x
, sizeof(char *)); 
 412 _asl_msg_slot_val(asl_msg_t 
*page
, uint32_t slot
) 
 417         if (page 
== NULL
) return NULL
; 
 419         if ((page
->asl_type 
== ASL_TYPE_MSG
) && (slot 
>= ASL_MSG_KVO_MSG_SLOTS
)) return NULL
; 
 420         else if ((page
->asl_type 
== ASL_TYPE_QUERY
) && (slot 
>= ASL_MSG_KVO_QUERY_SLOTS
)) return NULL
; 
 422         v 
= _get_slot_val(page
, slot
); 
 424         if (v 
== ASL_MSG_SLOT_FREE
) return NULL
; 
 426         type 
= v 
& ASL_MSG_KV_MASK
; 
 428         if (type 
== ASL_MSG_KV_INLINE
) 
 430                 return page
->data 
+ v
; 
 432         else if (type 
== ASL_MSG_KV_EXTERN
) 
 434                 x 
= v 
& ASL_MSG_OFFSET_MASK
; 
 435                 memcpy(&out
, page
->data 
+ x
, sizeof(char *)); 
 443  * asl_new: create a new log message. 
 446 asl_msg_new(uint32_t type
) 
 450         out 
= _asl_msg_make_page(type
); 
 451         if (out 
== NULL
) return NULL
; 
 453         out
->asl_type 
= type
; 
 460 _asl_msg_free_page(asl_msg_t 
*page
) 
 465         if (page 
== NULL
) return; 
 467         mslots 
= _slot_count(page
); 
 469         for (i 
= 0; i 
< mslots
; i
++) 
 471                 uint16_t k 
= _get_slot_key(page
, i
); 
 472                 uint16_t v 
= _get_slot_val(page
, i
); 
 474                 if (k 
== ASL_STD_KEY_FREE_NOTE
) 
 476                         const char *x 
= _asl_msg_slot_val(page
, i
); 
 477                         if (x 
!= NULL
) notify_post(x
); 
 480                 if ((k 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
 482                         memcpy(&p
, page
->data 
+ (k 
& ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
 486                 if ((v 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
 488                         memcpy(&p
, page
->data 
+ (v 
& ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
 497 asl_msg_type(asl_msg_t 
*msg
) 
 499         if (msg 
== NULL
) return 0; 
 500         return msg
->asl_type
; 
 504 asl_msg_count(asl_msg_t 
*msg
) 
 510         for (; msg 
!= NULL
; msg 
= msg
->next
) total 
+= msg
->count
; 
 515 _asl_msg_dump_kv(FILE *f
, asl_msg_t 
*msg
, uint16_t x
) 
 517         if (x 
== ASL_MSG_SLOT_FREE
) 
 519                 fprintf(f
, "-free-"); 
 523         if ((x 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
) 
 527                         case ASL_STD_KEY_TIME
: fprintf(f
, "(dict: Time)"); return; 
 528                         case ASL_STD_KEY_NANO
: fprintf(f
, "(dict: Nano)"); return; 
 529                         case ASL_STD_KEY_HOST
: fprintf(f
, "(dict: Host)"); return; 
 530                         case ASL_STD_KEY_SENDER
: fprintf(f
, "(dict: Sender)"); return; 
 531                         case ASL_STD_KEY_FACILITY
: fprintf(f
, "(dict: Facility)"); return; 
 532                         case ASL_STD_KEY_PID
: fprintf(f
, "(dict: PID)"); return; 
 533                         case ASL_STD_KEY_UID
: fprintf(f
, "(dict: UID)"); return; 
 534                         case ASL_STD_KEY_GID
: fprintf(f
, "(dict: GID)"); return; 
 535                         case ASL_STD_KEY_LEVEL
: fprintf(f
, "(dict: Level)"); return; 
 536                         case ASL_STD_KEY_MESSAGE
: fprintf(f
, "(dict: Message)"); return; 
 537                         case ASL_STD_KEY_READ_UID
: fprintf(f
, "(dict: ReadUID)"); return; 
 538                         case ASL_STD_KEY_READ_GID
: fprintf(f
, "(dict: ReadGID)"); return; 
 539                         case ASL_STD_KEY_SESSION
: fprintf(f
, "(dict: Session)"); return; 
 540                         case ASL_STD_KEY_REF_PID
: fprintf(f
, "(dict: PID)"); return; 
 541                         case ASL_STD_KEY_REF_PROC
: fprintf(f
, "(dict: RefProc)"); return; 
 542                         case ASL_STD_KEY_MSG_ID
: fprintf(f
, "(dict: ASLMessageID)"); return; 
 543                         case ASL_STD_KEY_EXPIRE
: fprintf(f
, "(dict: Expire)"); return; 
 544                         case ASL_STD_KEY_OPTION
: fprintf(f
, "(dict: ASLOption)"); return; 
 545                         case ASL_MT_KEY_DOMAIN
: fprintf(f
, "(dict: com.apple.message.domain)"); return; 
 546                         case ASL_MT_KEY_SCOPE
: fprintf(f
, "(dict: com.apple.message.domain_scope)"); return; 
 547                         case ASL_MT_KEY_RESULT
: fprintf(f
, "(dict: com.apple.message.result)"); return; 
 548                         case ASL_MT_KEY_SIG
: fprintf(f
, "(dict: com.apple.message.signature)"); return; 
 549                         case ASL_MT_KEY_SIG2
: fprintf(f
, "(dict: com.apple.message.signature2)"); return; 
 550                         case ASL_MT_KEY_SIG3
: fprintf(f
, "(dict: com.apple.message.signature3)"); return; 
 551                         case ASL_MT_KEY_SUCCESS
: fprintf(f
, "(dict: com.apple.message.success)"); return; 
 552                         case ASL_MT_KEY_UUID
: fprintf(f
, "(dict: com.apple.message.uuid)"); return; 
 553                         case ASL_MT_KEY_VAL
: fprintf(f
, "(dict: com.apple.message.value)"); return; 
 554                         case ASL_MT_KEY_VAL2
: fprintf(f
, "(dict: com.apple.message.value2)"); return; 
 555                         case ASL_MT_KEY_VAL3
: fprintf(f
, "(dict: com.apple.message.value3)"); return; 
 556                         case ASL_MT_KEY_VAL4
: fprintf(f
, "(dict: com.apple.message.value4)"); return; 
 557                         case ASL_MT_KEY_VAL5
: fprintf(f
, "(dict: com.apple.message.value5)"); return; 
 560                 fprintf(f
, "(dict: -unknown-)"); 
 564         if ((x 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
 567                 size_t z 
= x 
& ASL_MSG_OFFSET_MASK
; 
 568                 memcpy(&c
, msg
->data 
+ z
, sizeof(char *)); 
 569                 fprintf(f
, "(extern: %s)", c
); 
 573         fprintf(f
, "%s", msg
->data 
+ x
); 
 577 _asl_msg_dump(FILE *f
, const char *comment
, asl_msg_t 
*msg
) 
 579         uint32_t i
, mslots
, page1 
= 1; 
 581         if (f 
== NULL
) return; 
 584                 fprintf(f
, "asl_msg %s: NULL\n", comment
); 
 588         mslots 
= _slot_count(msg
); 
 594                         fprintf(f
, "asl_msg %s: %p\n", comment
, msg
); 
 595                         fprintf(f
, "    refcount: %u\n", msg
->refcount
); 
 596                         fprintf(f
, "    asl_type: %u\n", msg
->asl_type
); 
 601                         fprintf(f
, "  page: %p\n", msg
); 
 604                 fprintf(f
, "    count: %u\n", msg
->count
); 
 605                 fprintf(f
, "    data_size: %u\n", msg
->data_size
); 
 606                 fprintf(f
, "    mem_size: %llu\n", msg
->mem_size
); 
 607                 fprintf(f
, "    next: %p\n", msg
->next
); 
 609                 for (i 
= 0; i 
< mslots
; i
++) 
 611                         fprintf(f
, "    slot[%d]: ", i
); 
 612                         _asl_msg_dump_kv(f
, msg
, _get_slot_key(msg
, i
)); 
 614                         _asl_msg_dump_kv(f
, msg
, _get_slot_val(msg
, i
)); 
 615                         if (msg
->asl_type 
== ASL_TYPE_QUERY
) fprintf(f
, " 0x%04x\n", _get_slot_op(msg
, i
)); 
 623 #pragma mark fetching contents 
 626  * Find the slot and page for an input key. 
 629 _asl_msg_index(asl_msg_t 
*msg
, const char *key
, uint32_t *oslot
, asl_msg_t 
**opage
) 
 631         uint32_t i
, len
, slot
, mslots
; 
 636         if (msg 
== NULL
) return IndexNull
; 
 637         if (key 
== NULL
) return IndexNull
; 
 641         mslots 
= _slot_count(msg
); 
 643         if (oslot 
!= NULL
) *oslot 
= slot
; 
 646         if (opage 
!= NULL
) *opage 
= page
; 
 649         kx 
= _asl_msg_std_key(key
, len
); 
 653                 if (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
) 
 657                                 if (_get_slot_key(page
, slot
) == kx
) return i
; 
 659                         else if ((_get_slot_key(page
, slot
) & ASL_MSG_KV_MASK
) == ASL_MSG_KV_DICT
) 
 661                                 /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */ 
 663                         else if ((_get_slot_key(page
, slot
) & ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
 665                                 memcpy(&kp
, page
->data 
+ (_get_slot_key(page
, slot
) & ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
 666                                 if (streq(key
, kp
)) return i
; 
 670                                 kp 
= page
->data 
+ _get_slot_key(page
, slot
); 
 671                                 if (streq(key
, kp
)) return i
; 
 677                 if (oslot 
!= NULL
) *oslot 
= slot
; 
 681                         if (page
->next 
== NULL
) return IndexNull
; 
 684                         if (oslot 
!= NULL
) *oslot 
= slot
; 
 687                         if (opage 
!= NULL
) *opage 
= page
; 
 695  * Find page and slot for an "index". 
 698 _asl_msg_resolve_index(asl_msg_t 
*msg
, uint32_t n
, asl_msg_t 
**page
, uint32_t *slot
) 
 700         uint32_t i
, sx
, mslots
; 
 703         if (msg 
== NULL
) return -1; 
 708         mslots 
= _slot_count(msg
); 
 713         for (px 
= msg
; px 
!= NULL
; px 
= px
->next
) 
 715                 if (n 
> (sx 
+ px
->count
)) 
 724                 for (i 
= 0; i 
< mslots
; i
++) 
 726                         if (px
->kvo
[i
] != ASL_MSG_SLOT_FREE
) 
 743  * asl_msg_fetch: iterate over entries 
 744  * initial value of n should be 0.  Subseqent calls should use the last 
 745  * returned value.  Returns IndexNull when there are no more entries 
 746  * Sets the pointers for the next key, value, and op in the msg. 
 747  * The iterator encodes a page number and a slot number. 
 751 asl_msg_fetch(asl_msg_t 
*msg
, uint32_t x
, const char **keyout
, const char **valout
, uint16_t *opout
) 
 753         uint32_t p
, xpn
, xsn
, mslots
; 
 754         asl_msg_t 
*page 
= NULL
; 
 756         if (msg 
== NULL
) return IndexNull
; 
 758         mslots 
= _slot_count(msg
); 
 761         xpn 
= x 
& 0x00ffffff; 
 763         /* slot number 0xff means we have run out entries */ 
 764         if (xsn 
== 0x000000ff) return IndexNull
; 
 767         for (p 
= 0; p 
< xpn
; p
++) 
 770                 if (page 
== NULL
) return IndexNull
; 
 773         if (keyout 
!= NULL
) *keyout 
= _asl_msg_slot_key(page
, xsn
); 
 774         if (valout 
!= NULL
) *valout 
= _asl_msg_slot_val(page
, xsn
); 
 775         if (opout 
!= NULL
) *opout 
= _get_slot_op(page
, xsn
); 
 777         /* advance to the next slot */ 
 784                         if (page
->next 
== NULL
) return 0xff000000; 
 790                 if (page
->kvo
[xsn
] != ASL_MSG_SLOT_FREE
) return ((xsn 
<< 24) | xpn
); 
 797 asl_msg_lookup(asl_msg_t 
*msg
, const char *key
, const char **valout
, uint16_t *opout
) 
 802         if (msg 
== NULL
) return -1; 
 803         if (valout 
!= NULL
) *valout 
= NULL
; 
 804         if (opout 
!= NULL
) *opout 
= 0; 
 809         i 
= _asl_msg_index(msg
, key
, &slot
, &page
); 
 810         if (i 
== IndexNull
) return -1; 
 812         if (valout 
!= NULL
) *valout 
= _asl_msg_slot_val(page
, slot
); 
 813         if (opout 
!= NULL
) *opout 
= _get_slot_op(page
, slot
); 
 819 asl_msg_get_val_for_key(asl_msg_t 
*msg
, const char *key
) 
 824         if (msg 
== NULL
) return NULL
; 
 829         if (_asl_msg_index(msg
, key
, &slot
, &page
) == IndexNull
) return NULL
; 
 831         return _asl_msg_slot_val(page
, slot
); 
 835 asl_msg_key(asl_msg_t 
*msg
, uint32_t n
) 
 837         uint32_t slot
, i
, mslots
; 
 840         if (msg 
== NULL
) return NULL
; 
 842         mslots 
= _slot_count(msg
); 
 845         for (page 
= msg
; page 
!= NULL
; page 
= page
->next
) 
 847                 for (slot 
= 0; slot 
< mslots
; slot
++) 
 849                         if (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
) 
 851                                 if (i 
== n
) return _asl_msg_slot_key(page
, slot
); 
 861 #pragma mark adding and replacing contents 
 864 _asl_msg_new_key_val_op(asl_msg_t 
*msg
, const char *key
, const char *val
, uint32_t op
) 
 866         uint32_t slot
, keylen
, vallen
, total
, mslots
; 
 868         uint16_t kx
, k
, v
, o
; 
 869         asl_msg_t 
*page
, *last
; 
 870         char *extkey
, *extval
; 
 872         if (msg 
== NULL
) return -1; 
 873         if (key 
== NULL
) return -1; 
 875         mslots 
= _slot_count(msg
); 
 881         keylen 
= strlen(key
); 
 883         kx 
= _asl_msg_std_key(key
, keylen
); 
 885         if (kx 
== 0) keylen
++; 
 893                 vallen 
= strlen(val
) + 1; 
 898         /* check if one or both of key and value must be "external" (in its own malloced space) */ 
 899         if (keylen 
> ASL_MSG_PAGE_DATA_SIZE
) 
 901                 extkey 
= strdup(key
); 
 902                 keylen 
= sizeof(char *); 
 905         if (vallen 
> ASL_MSG_PAGE_DATA_SIZE
) 
 907                 extval 
= strdup(val
); 
 908                 vallen 
= sizeof(char *); 
 911         total 
= keylen 
+ vallen
; 
 912         if ((total 
> ASL_MSG_PAGE_DATA_SIZE
) && (extval 
== NULL
) && (keylen 
> 0)) 
 914                 extval 
= strdup(val
); 
 915                 vallen 
= sizeof(char *); 
 916                 total 
= keylen 
+ vallen
; 
 919         if ((total 
> ASL_MSG_PAGE_DATA_SIZE
) && (extkey 
== NULL
)) 
 921                 extkey 
= strdup(key
); 
 922                 keylen 
= sizeof(char *); 
 923                 total 
= keylen 
+ vallen
; 
 926         if (total 
> ASL_MSG_PAGE_DATA_SIZE
) 
 928                 /* can't happen, but... */ 
 929                 if (extkey 
!= NULL
) free(extkey
); 
 930                 if (extval 
!= NULL
) free(extval
); 
 934         /* find a page with space for the key and value and a free slot*/ 
 938         for (page 
= msg
; page 
!= NULL
; page 
= page
->next
) 
 942                 if (total 
<= (ASL_MSG_PAGE_DATA_SIZE 
- page
->data_size
)) 
 944                         /* check for a free slot */ 
 945                         for (slot 
= 0; (slot 
< mslots
) && (_get_slot_key(page
, slot
) != ASL_MSG_SLOT_FREE
); slot
++); 
 946                         if (slot 
< mslots
) break; 
 952                 /* allocate a new page and attach it */ 
 953                 page 
= _asl_msg_make_page(msg
->asl_type
); 
 956                         if (extkey 
!= NULL
) free(extkey
); 
 957                         if (extval 
!= NULL
) free(extval
); 
 965         /* copy key or external key pointer into page data */ 
 970         else if (extkey 
== NULL
) 
 973                 memcpy(page
->data 
+ page
->data_size
, key
, keylen
); 
 977                 k 
= page
->data_size 
| ASL_MSG_KV_EXTERN
; 
 978                 memcpy(page
->data 
+ page
->data_size
, &extkey
, keylen
); 
 979                 page
->mem_size 
+= klen
; 
 982         _set_slot_key(page
, slot
, k
); 
 983         page
->data_size 
+= keylen
; 
 985         /* copy val or external val pointer into page data */ 
 987         v 
= ASL_MSG_SLOT_FREE
; 
 994                         memcpy(page
->data 
+ page
->data_size
, val
, vallen
); 
 998                         v 
= page
->data_size 
| ASL_MSG_KV_EXTERN
; 
 999                         memcpy(page
->data 
+ page
->data_size
, &extval
, vallen
); 
1000                         page
->mem_size 
+= vlen
; 
1003                 _set_slot_val(page
, slot
, v
); 
1004                 page
->data_size 
+= vallen
; 
1008         _set_slot_op(page
, slot
, o
); 
1010         /* update page count */ 
1017  * Most of the code in asl_msg_set_key_val_op is concerned with trying to re-use 
1018  * space in an asl_msg_t page when given a new value for an existing key. 
1019  * If the key is new, we just call _asl_msg_new_key_val_op. 
1021  * Note that queries can have duplicate keys, so for ASL_TYPE_QUERY we just 
1022  * call through to _asl_msg_new_key_val_op. 
1025 _asl_msg_set_kvo(asl_msg_t 
*msg
, const char *key
, const char *val
, uint32_t op
) 
1027         uint32_t i
, slot
, mslots
, newexternal
; 
1029         uint32_t intvallen
, extvallen
, newvallen
; 
1030         char *intval
, *extval
, *newval
; 
1033         if (msg 
== NULL
) return -1; 
1034         if (key 
== NULL
) return -1; 
1036         mslots 
= _slot_count(msg
); 
1043         if ((msg
->asl_type 
== ASL_TYPE_QUERY
) || (IndexNull 
== _asl_msg_index(msg
, key
, &slot
, &page
))) 
1046                 return _asl_msg_new_key_val_op(msg
, key
, val
, op
); 
1055         v 
= _get_slot_val(page
, slot
); 
1057         if (v 
!= ASL_MSG_SLOT_FREE
) 
1059                 if ((v 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
1061                         i 
= v 
& ASL_MSG_OFFSET_MASK
; 
1062                         memcpy(&extval
, page
->data 
+ i
, sizeof(char *)); 
1063                         extvallen 
= sizeof(char *); 
1067                         intval 
= page
->data 
+ v
; 
1068                         intvallen 
= strlen(intval
) + 1; 
1072         /* replace val and op for existing entry */ 
1074         /* easy case  - remove val */ 
1079                         page
->mem_size 
-= (strlen(extval
) + 1); 
1083                 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
); 
1084                 if (op 
!= IndexNull
) _set_slot_op(page
, slot
, o
); 
1088         /* trivial case - internal val doesn't change */ 
1089         if ((intval 
!= NULL
) && (streq(val
, intval
))) 
1091                 if (op 
!= IndexNull
) _set_slot_op(page
, slot
, o
); 
1095         /* trivial case - external val doesn't change */ 
1096         if ((extval 
!= NULL
) && (streq(val
, extval
))) 
1098                 if (op 
!= IndexNull
) _set_slot_op(page
, slot
, o
); 
1103          * special case: we generally don't compress out holes in the data 
1104          * space, but if this is the last string in the currently used data space 
1105          * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots]) 
1107         i 
= v 
& ASL_MSG_OFFSET_MASK
; 
1108         if ((intval 
!= NULL
) && ((i 
+ intvallen
) == page
->data_size
)) 
1110                 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
); 
1111                 page
->data_size 
-= intvallen
; 
1115         else if ((extval 
!= NULL
) && ((i 
+ extvallen
) == page
->data_size
)) 
1117                 _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
); 
1118                 page
->data_size 
-= extvallen
; 
1119                 page
->mem_size 
-= (strlen(extval
) + 1); 
1125         /* val changes - see if it needs to be external */ 
1126         newvallen 
= strlen(val
) + 1; 
1129         if (newvallen 
> ASL_MSG_PAGE_DATA_SIZE
) 
1132                 newvallen 
= sizeof(char *); 
1135         /* check if there is room to change val in place */ 
1136         if (((extval 
!= NULL
) && (newvallen 
<= extvallen
)) || ((extval 
== NULL
) && (newvallen 
<= intvallen
))) 
1140                         page
->mem_size 
-= (strlen(extval
) + 1); 
1146                 /* we can re-use the space of the old value */ 
1147                 i 
= v 
& ASL_MSG_OFFSET_MASK
; 
1149                 if (newexternal 
== 1) 
1151                         /* create an external val and copy in the new pointer */ 
1152                         newval 
= strdup(val
); 
1153                         if (newval 
== NULL
) return -1; 
1155                         page
->mem_size 
+= (strlen(newval
) + 1); 
1156                         _set_slot_val(page
, slot
, i 
| ASL_MSG_KV_EXTERN
); 
1157                         memcpy(page
->data 
+ i
, &newval
, sizeof(char *)); 
1161                         /* new internal value */ 
1162                         _set_slot_val(page
, slot
, i
); 
1163                         memcpy(page
->data 
+ i
, val
, newvallen
); 
1166                 if (op 
!= IndexNull
) _set_slot_op(page
, slot
, o
); 
1170         /* we're done with the old value if it is external - free it now */ 
1173                 page
->mem_size 
-= (strlen(extval
) + 1); 
1179         if (newvallen 
<= (ASL_MSG_PAGE_DATA_SIZE 
- page
->data_size
)) 
1181                 /* can't re-use the old space, but there's room on the page */ 
1182                 i 
= page
->data_size
; 
1183                 page
->data_size 
+= newvallen
; 
1185                 if (newexternal 
== 1) 
1187                         /* create an external val and copy in the new pointer */ 
1188                         newval 
= strdup(val
); 
1189                         if (newval 
== NULL
) return -1; 
1191                         page
->mem_size 
+= (strlen(newval
) + 1); 
1192                         _set_slot_val(page
, slot
, i 
| ASL_MSG_KV_EXTERN
); 
1193                         memcpy(page
->data 
+ i
, &newval
, sizeof(char *)); 
1197                         /* new internal value */ 
1198                         _set_slot_val(page
, slot
, i
); 
1199                         memcpy(page
->data 
+ i
, val
, newvallen
); 
1202                 if (op 
!= IndexNull
) _set_slot_op(page
, slot
, o
); 
1207         /* no room on this page - free up existing entry and treat this as a new entry */ 
1208         if ((k 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
1210                 memcpy(&extval
, page
->data 
+ (k 
& ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
1211                 page
->mem_size 
-= (strlen(extval
) + 1); 
1215         _set_slot_key(page
, slot
, ASL_MSG_SLOT_FREE
); 
1216         _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
); 
1217         _set_slot_op(page
, slot
, 0); 
1219         return _asl_msg_new_key_val_op(msg
, key
, val
, op
); 
1223 asl_msg_set_key_val_op(asl_msg_t 
*msg
, const char *key
, const char *val
, uint32_t op
) 
1225         char *special
, buf
[512]; 
1229         if (msg 
== NULL
) return -1; 
1230         if (key 
== NULL
) return -1; 
1232         /* Special case handling */ 
1235         /* if query modifier is set but op is zero, default to equality test */ 
1236         if ((op 
!= 0) && ((op 
& ASL_QUERY_OP_TRUE
) == 0)) op 
|= ASL_QUERY_OP_EQUAL
; 
1238         /* convert "Level" values to "0" through "7" */ 
1239         if (streq(key
, ASL_KEY_LEVEL
)) 
1241                 if (val 
== NULL
) val 
= "7"; 
1242                 else if ((val
[0] >= '0') && (val
[0] <= '7') && (val
[1] == '\0')) /* do nothing */; 
1243                 else if (strcaseeq(val
, ASL_STRING_EMERG
)) val 
= "0"; 
1244                 else if (strcaseeq(val
, ASL_STRING_ALERT
)) val 
= "1"; 
1245                 else if (strcaseeq(val
, ASL_STRING_CRIT
)) val 
= "2"; 
1246                 else if (strcaseeq(val
, ASL_STRING_ERR
)) val 
= "3"; 
1247                 else if (strcaseeq(val
, ASL_STRING_WARNING
)) val 
= "4"; 
1248                 else if (strcaseeq(val
, ASL_STRING_NOTICE
)) val 
= "5"; 
1249                 else if (strcaseeq(val
, ASL_STRING_INFO
)) val 
= "6"; 
1250                 else if (strcaseeq(val
, ASL_STRING_DEBUG
)) val 
= "7"; 
1254         /* strip trailing newlines from "Message" values */ 
1255         if ((streq(key
, ASL_KEY_MSG
)) && (val 
!= NULL
)) 
1259                 while ((i 
> 0) && (val
[i 
- 1] == '\n')) i
--; 
1260                 if (i 
== 0) val 
= NULL
; 
1263                         /* use buf if it is big enough, else malloc a temporary buffer */ 
1264                         if (i 
< sizeof(buf
)) 
1266                                 memcpy(buf
, val
, i
); 
1268                                 val 
= (const char *)buf
; 
1272                                 special 
= malloc(i 
+ 1); 
1273                                 if (special 
== NULL
) return -1; 
1274                                 memcpy(special
, val
, i
); 
1276                                 val 
= (const char *)special
; 
1281         status 
= _asl_msg_set_kvo(msg
, key
, val
, op
); 
1283         if (special 
!= NULL
) free(special
); 
1288 asl_msg_set_key_val(asl_msg_t 
*msg
, const char *key
, const char *val
) 
1290         return asl_msg_set_key_val_op(msg
, key
, val
, 0); 
1294 _asl_msg_unset_page_slot(asl_msg_t 
*page
, uint32_t slot
) 
1299         if (page 
== NULL
) return; 
1301         if (slot 
>= _slot_count(page
)) return; 
1303         k 
= _get_slot_key(page
, slot
); 
1304         v 
= _get_slot_val(page
, slot
); 
1306         if (k 
== ASL_MSG_SLOT_FREE
) return; 
1308         if ((k 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
1310                 memcpy(&ext
, page
->data 
+ (k 
& ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
1311                 page
->mem_size 
-= (strlen(ext
) + 1); 
1315         if ((v 
& ASL_MSG_KV_MASK
) == ASL_MSG_KV_EXTERN
) 
1317                 memcpy(&ext
, page
->data 
+ (v 
& ASL_MSG_OFFSET_MASK
), sizeof(char *)); 
1318                 page
->mem_size 
-= (strlen(ext
) + 1); 
1322         _set_slot_key(page
, slot
, ASL_MSG_SLOT_FREE
); 
1323         _set_slot_val(page
, slot
, ASL_MSG_SLOT_FREE
); 
1324         _set_slot_op(page
, slot
, 0); 
1331  * Frees external key and val strings, but does not try to reclaim data space. 
1334 asl_msg_unset(asl_msg_t 
*msg
, const char *key
) 
1339         if (msg 
== NULL
) return; 
1340         if (key 
== NULL
) return; 
1345         i 
= _asl_msg_index(msg
, key
, &slot
, &page
); 
1346         if (i 
== IndexNull
) return; 
1348         _asl_msg_unset_page_slot(page
, slot
); 
1352 asl_msg_unset_index(asl_msg_t 
*msg
, uint32_t n
) 
1354         uint32_t slot 
= IndexNull
; 
1355         asl_msg_t 
*page 
= NULL
; 
1357         if (msg 
== NULL
) return; 
1359         if  (0 != _asl_msg_resolve_index(msg
, n
, &page
, &slot
)) return; 
1360         _asl_msg_unset_page_slot(page
, slot
); 
1364 #pragma mark copy and merge 
1367  * Merge a key / val into a message (only ASL_TYPE_MSG). 
1368  * Adds the key / val if the key is not found. 
1369  * Does not replace the value if the key is found. 
1372 _asl_msg_merge_key_val_op(asl_msg_t 
*msg
, const char *key
, const char *val
, uint16_t op
) 
1377         if (msg 
== NULL
) return; 
1378         if (key 
== NULL
) return; 
1383         i 
= _asl_msg_index(msg
, key
, &slot
, &page
); 
1384         if (i 
!= IndexNull
) return; 
1386         asl_msg_set_key_val_op(msg
, key
, val
, op
); 
1390  * Merge msg into target (does not replace existing keys). 
1391  * Creates a new asl_msg_t if target is NULL. 
1395 asl_msg_merge(asl_msg_t 
*target
, asl_msg_t 
*msg
) 
1397         uint32_t x
, type
, isnew 
= 0; 
1399         const char *key
, *val
; 
1401         if (msg 
== NULL
) return target
; 
1403         type 
= asl_get_type((asl_object_t
)msg
); 
1408                 target 
= asl_msg_new(type
); 
1411         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x 
!= IndexNull
; x 
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
)) 
1413                 if (type 
== ASL_TYPE_MSG
) op 
= 0; 
1414                 if (isnew 
== 1) asl_msg_set_key_val_op(target
, key
, val
, op
); 
1415                 else _asl_msg_merge_key_val_op(target
, key
, val
, op
); 
1422  * replace key/value pairs from msg in target 
1423  * Creates a new asl_msg_t if target is NULL. 
1427 asl_msg_replace(asl_msg_t 
*target
, asl_msg_t 
*msg
) 
1431         const char *key
, *val
; 
1433         if (msg 
== NULL
) return target
; 
1435         type 
= asl_get_type((asl_object_t
)msg
); 
1437         if (target 
== NULL
) target 
= asl_msg_new(type
); 
1439         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x 
!= IndexNull
; x 
=asl_msg_fetch(msg
, x
, &key
, &val
, &op
)) 
1441                 if (type 
== ASL_TYPE_MSG
) op 
= 0; 
1442                 asl_msg_set_key_val_op(target
, key
, val
, op
); 
1453 asl_msg_copy(asl_msg_t 
*msg
) 
1455         return asl_msg_merge(NULL
, msg
); 
1459 #pragma mark compare and test 
1465 _asl_msg_equal(asl_msg_t 
*a
, asl_msg_t 
*b
) 
1469         const char *key
, *va
, *vb
; 
1471         if (asl_msg_count(a
) != asl_msg_count(b
)) return 0; 
1477         for (x 
= asl_msg_fetch(a
, 0, &key
, &va
, &oa
); x 
!= IndexNull
; x 
= asl_msg_fetch(a
, x
, &key
, &va
, &oa
)) 
1479                 if (asl_msg_lookup(b
, key
, &vb
, &ob
) != 0) return 0; 
1480                 if (strcmp(va
, vb
)) return 0; 
1481                 if ((a
->asl_type 
== ASL_TYPE_QUERY
) && (oa 
!= ob
)) return 0; 
1488 _asl_isanumber(const char *s
) 
1492         if (s 
== NULL
) return 0; 
1495         if ((s
[0] == '-') || (s
[0] == '+')) i 
= 1; 
1497         if (s
[i
] == '\0') return 0; 
1499         for (; s
[i
] != '\0'; i
++) 
1501                 if (!isdigit(s
[i
])) return 0; 
1508 _asl_msg_basic_test(uint32_t op
, const char *q
, const char *m
, uint32_t n
) 
1516         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1518         /* NULL value from query or message string fails */ 
1519         if ((q 
== NULL
) || (m 
== NULL
)) return (t 
& ASL_QUERY_OP_NOT_EQUAL
); 
1521         if (op 
& ASL_QUERY_OP_REGEX
) 
1523                 /* greater than or less than make no sense in substring search */ 
1524                 if ((t 
== ASL_QUERY_OP_GREATER
) || (t 
== ASL_QUERY_OP_LESS
)) return 0; 
1526                 memset(&rex
, 0, sizeof(regex_t
)); 
1528                 rflags 
= REG_EXTENDED 
| REG_NOSUB
; 
1529                 if (op 
& ASL_QUERY_OP_CASEFOLD
) rflags 
|= REG_ICASE
; 
1531                 /* A bad reqular expression matches nothing */ 
1532                 if (regcomp(&rex
, q
, rflags
) != 0) return (t 
& ASL_QUERY_OP_NOT_EQUAL
); 
1534                 cmp 
= regexec(&rex
, m
, 0, NULL
, 0); 
1537                 if (t 
== ASL_QUERY_OP_NOT_EQUAL
) return (cmp 
!= 0); 
1541         if (op 
& ASL_QUERY_OP_NUMERIC
) 
1543                 if (_asl_isanumber(q
) == 0) return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1544                 if (_asl_isanumber(m
) == 0) return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1551                         case ASL_QUERY_OP_EQUAL
: return (nm 
== nq
); 
1552                         case ASL_QUERY_OP_GREATER
: return (nm 
> nq
); 
1553                         case ASL_QUERY_OP_GREATER_EQUAL
: return (nm 
>= nq
); 
1554                         case ASL_QUERY_OP_LESS
: return (nm 
< nq
); 
1555                         case ASL_QUERY_OP_LESS_EQUAL
: return (nm 
<= nq
); 
1556                         case ASL_QUERY_OP_NOT_EQUAL
: return (nm 
!= nq
); 
1557                         default: return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1562         if (op 
& ASL_QUERY_OP_CASEFOLD
) 
1564                 if (n 
== 0) cmp 
= strcasecmp(m
, q
); 
1565                 else cmp 
= strncasecmp(m
, q
, n
); 
1569                 if (n 
== 0) cmp 
= strcmp(m
, q
); 
1570                 else cmp 
= strncmp(m
, q
, n
); 
1575                 case ASL_QUERY_OP_EQUAL
: return (cmp 
== 0); 
1576                 case ASL_QUERY_OP_GREATER
: return (cmp 
> 0); 
1577                 case ASL_QUERY_OP_GREATER_EQUAL
: return (cmp 
>= 0); 
1578                 case ASL_QUERY_OP_LESS
: return (cmp 
< 0); 
1579                 case ASL_QUERY_OP_LESS_EQUAL
: return (cmp 
<= 0); 
1580                 case ASL_QUERY_OP_NOT_EQUAL
: return (cmp 
!= 0); 
1583         return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1587 _asl_msg_test_substring(uint32_t op
, const char *q
, const char *m
) 
1589         uint32_t t
, i
, d
, lm
, lq
, match
, newop
; 
1591         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1594         if (m 
!= NULL
) lm 
= strlen(m
); 
1597         if (q 
!= NULL
) lq 
= strlen(q
); 
1599         /* NULL is a substring of any string */ 
1600         if (lq 
== 0) return (t 
& ASL_QUERY_OP_EQUAL
); 
1602         /* A long string is defined to be not equal to a short string */ 
1603         if (lq 
> lm
) return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1605         /* greater than or less than make no sense in substring search */ 
1606         if ((t 
== ASL_QUERY_OP_GREATER
) || (t 
== ASL_QUERY_OP_LESS
)) return 0; 
1609          * We scan the string doing an equality test. 
1610          * If the input test is equality, we stop as soon as we hit a match. 
1611          * Otherwise we keep scanning the whole message string. 
1614         newop 
|= ASL_QUERY_OP_EQUAL
; 
1618         for (i 
= 0; i 
<= d
; i
++) 
1620                 if (_asl_msg_basic_test(newop
, q
, m 
+ i
, lq
) != 0) 
1622                         if (t 
& ASL_QUERY_OP_EQUAL
) return 1; 
1627         /* If the input test was for equality, no matches were found */ 
1628         if (t 
& ASL_QUERY_OP_EQUAL
) return 0; 
1630         /* The input test was for not equal.  Return true if no matches were found */ 
1631         return (match 
== 0); 
1635 _asl_msg_test_prefix(uint32_t op
, const char *q
, const char *m
) 
1639         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1642         if (m 
!= NULL
) lm 
= strlen(m
); 
1645         if (q 
!= NULL
) lq 
= strlen(q
); 
1647         /* NULL is a prefix of any string */ 
1648         if (lq 
== 0) return (t 
& ASL_QUERY_OP_EQUAL
); 
1650         /* A long string is defined to be not equal to a short string */ 
1651         if (lq 
> lm
) return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1653         /* Compare two equal-length strings */ 
1654         return _asl_msg_basic_test(op
, q
, m
, lq
); 
1658 _asl_msg_test_suffix(uint32_t op
, const char *q
, const char *m
) 
1660         uint32_t lm
, lq
, d
, t
; 
1662         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1665         if (m 
!= NULL
) lm 
= strlen(m
); 
1668         if (q 
!= NULL
) lq 
= strlen(q
); 
1670         /* NULL is a suffix of any string */ 
1671         if (lq 
== 0) return (t 
& ASL_QUERY_OP_EQUAL
); 
1673         /* A long string is defined to be not equal to a short string */ 
1674         if (lq 
> lm
) return (t 
== ASL_QUERY_OP_NOT_EQUAL
); 
1676         /* Compare two equal-length strings */ 
1678         return _asl_msg_basic_test(op
, q
, m 
+ d
, lq
); 
1682  * Splits out prefix, suffix, and substring tests. 
1683  * Sends the rest to _asl_msg_basic_test(). 
1686 _asl_msg_test_expression(uint32_t op
, const char *q
, const char *m
) 
1690         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1691         if (t 
== ASL_QUERY_OP_TRUE
) return 1; 
1693         if (op 
& ASL_QUERY_OP_PREFIX
) 
1695                 if (op 
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_substring(op
, q
, m
); 
1696                 return _asl_msg_test_prefix(op
, q
, m
); 
1698         if (op 
& ASL_QUERY_OP_SUFFIX
) return _asl_msg_test_suffix(op
, q
, m
); 
1700         return _asl_msg_basic_test(op
, q
, m
, 0); 
1704  * Special case for comparing time values. 
1705  * If both inputs are time strings, this compares the time 
1706  * value in seconds.  Otherwise it just does normal matching. 
1709 _asl_msg_test_time_expression(uint32_t op
, const char *q
, const char *m
) 
1714         if ((op 
& ASL_QUERY_OP_PREFIX
) || (op 
& ASL_QUERY_OP_SUFFIX
) || (op 
& ASL_QUERY_OP_REGEX
)) return _asl_msg_test_expression(op
, q
, m
); 
1715         if ((q 
== NULL
) || (m 
== NULL
)) return _asl_msg_test_expression(op
, q
, m
); 
1717         tq 
= asl_core_parse_time(q
, NULL
); 
1718         if (tq 
< 0) return _asl_msg_test_expression(op
, q
, m
); 
1720         tm 
= asl_core_parse_time(m
, NULL
); 
1721         if (tm 
< 0) return _asl_msg_test_expression(op
, q
, m
); 
1723         t 
= op 
& ASL_QUERY_OP_TRUE
; 
1727                 case ASL_QUERY_OP_FALSE
: 
1731                 case ASL_QUERY_OP_EQUAL
: 
1733                         if (tm 
== tq
) return 1; 
1736                 case ASL_QUERY_OP_GREATER
: 
1738                         if (tm 
> tq
) return 1; 
1741                 case ASL_QUERY_OP_GREATER_EQUAL
: 
1743                         if (tm 
>= tq
) return 1; 
1746                 case ASL_QUERY_OP_LESS
: 
1748                         if (tm 
< tq
) return 1; 
1751                 case ASL_QUERY_OP_LESS_EQUAL
: 
1753                         if (tm 
<= tq
) return 1; 
1756                 case ASL_QUERY_OP_NOT_EQUAL
: 
1758                         if (tm 
!= tq
) return 1; 
1761                 case ASL_QUERY_OP_TRUE
: 
1771 /* test a query against a message */ 
1772 __private_extern__ 
int 
1773 _asl_msg_test(asl_msg_t 
*q
, asl_msg_t 
*m
) 
1778         const char *kq
, *vq
, *vm
; 
1781          * Check each simple expression (key op val) separately. 
1782          * The query suceeds (returns 1) if all simple expressions 
1783          * succeed (i.e. AND the simple expressions). 
1790         for (x 
= asl_msg_fetch(q
, 0, &kq
, &vq
, &op
); x 
!= IndexNull
; x 
= asl_msg_fetch(q
, x
, &kq
, &vq
, &op
)) 
1792                 /* Find query key in the message */ 
1794                 i 
= asl_msg_lookup(m
, kq
, &vm
, NULL
); 
1796                 /* ASL_QUERY_OP_TRUE tests if key is present in the message */ 
1797                 t 
= op 
& ASL_QUERY_OP_TRUE
; 
1798                 if (t 
== ASL_QUERY_OP_TRUE
) 
1800                         if (i 
!= 0) return 0; 
1804                 /* ASL_QUERY_OP_FALSE tests if the key is NOT present in the message */ 
1805                 if (t 
== ASL_QUERY_OP_FALSE
) 
1807                         if (i 
== 0) return 0; 
1813                         /* the message does NOT have query key - fail unless we are testing not equal */ 
1814                         if (t 
== ASL_QUERY_OP_NOT_EQUAL
) continue; 
1819                 if (streq(kq
, ASL_KEY_TIME
)) 
1821                         cmp 
= _asl_msg_test_time_expression(op
, vq
, vm
); 
1825                         cmp 
= _asl_msg_test_expression(op
, vq
, vm
); 
1828                 if (cmp 
== 0) return 0; 
1834 /* returns 1 if a and b match, 0 otherwise */ 
1836 asl_msg_cmp(asl_msg_t 
*a
, asl_msg_t 
*b
) 
1839         if (a 
== NULL
) return 0; 
1840         if (b 
== NULL
) return 0; 
1842         if (a
->asl_type 
== b
->asl_type
) return _asl_msg_equal(a
, b
); 
1843         if (a
->asl_type 
== ASL_TYPE_QUERY
) return _asl_msg_test(a
, b
); 
1844         return _asl_msg_test(b
, a
); 
1848  * Test a message against a query list. 
1849  * Returns 1 if msg matches any query in the list, 0 otherwise. 
1850  * Returns 1 if the query list is NULL or empty. 
1853 asl_msg_cmp_list(asl_msg_t 
*msg
, asl_msg_list_t 
*list
) 
1857         if (msg 
== NULL
) return 0; 
1858         if (list 
== NULL
) return 1; 
1859         if (list
->count 
== 0) return 1; 
1861         for (i 
= 0; i 
< list
->count
; i
++) 
1863                 if (_asl_msg_test(list
->msg
[i
], msg
)) return 1; 
1870 #pragma mark string representation 
1873 _asl_time_string(const char *infmt
, const char *str
, const char *nano
) 
1877         char *ltime
, *out
, *p
, *q
; 
1878         char ltbuf
[32], nanobuf
[16], fmt
[32], zstr
[8]; 
1880         uint32_t subsec 
= 0; 
1884         memset(zstr
, 0, sizeof(zstr
)); 
1891          * The longest infmt string we understand is "-hh:mm.N" (8 chars), so 
1892          * it is safe to ignore the input if it doesn't fit in the temp buffer. 
1893          * The default is local time zone format. 
1897                 snprintf(fmt
, sizeof(fmt
), "local"); 
1899         else if (strlen(infmt
) >= sizeof (fmt
)) 
1901                 snprintf(fmt
, sizeof(fmt
), "local"); 
1905                 snprintf(fmt
, sizeof(fmt
), "%s", infmt
); 
1908                 q 
= strchr(fmt
, '.'); 
1913                         if (q 
!= '\0') subsec 
= atoi(q
); 
1922                 if (nano 
!= NULL
) nsec 
= atoi(nano
); 
1923                 snprintf(nanobuf
, sizeof(nanobuf
), ".%09u", nsec
); 
1924                 if (subsec 
> 9) subsec 
= 9; 
1925                 nanobuf
[subsec 
+ 1] = '\0'; 
1929         if (str 
!= NULL
) tick 
= asl_core_parse_time(str
, NULL
); 
1931         if ((!strcasecmp(fmt
, "lcl")) || (!strcasecmp(fmt
, "local"))) 
1933                 ltime 
= ctime_r(&tick
, ltbuf
); 
1934                 if (ltime 
== NULL
) return NULL
; 
1936                 asprintf(&out
, "%s%s", ltime 
+ 4, nanobuf
); 
1940         if ((!strcasecmp(fmt
, "jz")) || (!strcasecmp(fmt
, "iso8601")) || (!strcasecmp(fmt
, "iso8601e"))) 
1943                 if (!strncasecmp(fmt
, "iso8601", 7)) sep 
= 'T'; 
1945                 if (NULL 
== localtime_r(&tick
, &stm
)) return NULL
; 
1947                 off 
= stm
.tm_gmtoff
; 
1948                 if ((neg 
= (off 
< 0))) off 
*= -1; 
1953                 if (zm 
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg 
? '-' : '+', (long long) zh
); 
1954                 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg 
? '-' : '+', (long long) zh
, (long long) zm
); 
1956                 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
); 
1960         if (!strcasecmp(fmt
, "iso8601b")) 
1962                 if (NULL 
== localtime_r(&tick
, &stm
)) return NULL
; 
1964                 off 
= stm
.tm_gmtoff
; 
1965                 if ((neg 
= (off 
< 0))) off 
*= -1; 
1970                 if (zm 
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg 
? '-' : '+', (long long) zh
); 
1971                 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg 
? '-' : '+', (long long) zh
, (long long) zm
); 
1973                 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
); 
1977         if ((!strcasecmp(fmt
, "sec")) || (!strcasecmp(fmt
, "raw"))) 
1979                 asprintf(&out
, "%llu%s", (unsigned long long) tick
, nanobuf
); 
1983         if (!strcasecmp(fmt
, "j")) 
1985                 if (NULL 
== localtime_r(&tick
, &stm
)) return NULL
; 
1986                 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
); 
1990         if ((!strcasecmp(fmt
, "utc")) || (!strcasecmp(fmt
, "zulu")) || (!strcasecmp(fmt
, "iso8601z")) || (!strcasecmp(fmt
, "iso8601ez"))) 
1993                 if (!strncasecmp(fmt
, "iso8601", 7)) sep 
= 'T'; 
1995                 if (NULL 
== gmtime_r(&tick
, &stm
)) return NULL
; 
1996                 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
); 
2000         if (!strcasecmp(fmt
, "iso8601bz")) 
2002                 if (NULL 
== gmtime_r(&tick
, &stm
)) return NULL
; 
2003                 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
); 
2007         if ((fmt
[1] == '\0') && (((fmt
[0] >= 'a') && (fmt
[0] <= 'z')) || ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z')))) 
2010                 if (z 
>= 'a') z 
-= 32; 
2012                 if (z 
== 'Z') off 
= 0; 
2013                 else if ((z 
>= 'A') && (z 
<= 'I')) off 
= ((z 
- 'A') + 1) * SEC_PER_HOUR
; 
2014                 else if ((z 
>= 'K') && (z 
<= 'M')) off 
= (z 
- 'A') * SEC_PER_HOUR
; 
2015                 else if ((z 
>= 'N') && (z 
<= 'Y')) off 
= ('M' - z
) * SEC_PER_HOUR
; 
2020                 if (fmt
[0] == '-') neg 
= true; 
2021                 if ((*p 
== '-') || (*p 
== '+')) p
++; 
2022                 if ((*p
) >= '0' && (*p 
<= '9')) 
2027                         if (p 
!= NULL
) zm 
= atoi(p 
+ 1); 
2034                 off 
= (zh 
* 3600) + (zm 
* 60); 
2037                 if (zm 
== 0) snprintf(zstr
, sizeof(zstr
), "%c%02lld", neg 
? '-' : '+', (long long) zh
); 
2038                 else snprintf(zstr
, sizeof(zstr
), "%c%02lld:%02lld", neg 
? '-' : '+', (long long) zh
, (long long) zm
); 
2044         memset(&stm
, 0, sizeof (struct tm
)); 
2045         if (NULL 
== gmtime_r(&tick
, &stm
)) return NULL
; 
2047         if ((fmt
[0] >= 'A') && (fmt
[0] <= 'Z')) 
2049                 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]); 
2051         else if ((fmt
[0] >= 'a') && (fmt
[0] <= 'z')) 
2053                 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); 
2057                 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
); 
2064 /* called from asl_format_message and _asl_send_message */ 
2065 __private_extern__ asl_string_t 
* 
2066 asl_msg_to_string_raw(uint32_t encoding
, asl_msg_t 
*msg
, const char *tfmt
) 
2068         uint32_t i
, x
, count
; 
2069         const char *key
, *val
, *nano
; 
2072         if (msg 
== NULL
) return NULL
; 
2074         count 
= asl_msg_count(msg
); 
2075         if (count 
== 0) return NULL
; 
2077         str 
= asl_string_new(encoding
); 
2078         if (str 
== NULL
) return NULL
; 
2085         asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
); 
2087         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x 
!= IndexNull
; x 
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
)) 
2089                 if (key 
== NULL
) continue; 
2091                 if (i 
> 0) asl_string_append_char_no_encoding(str
, ' '); 
2093                 asl_string_append_char_no_encoding(str
, '['); 
2094                 asl_string_append_asl_key(str
, key
); 
2096                 if (!strcmp(key
, ASL_KEY_TIME
)) 
2099                         asl_string_append_char_no_encoding(str
, ' '); 
2101                         if (val 
!= NULL
) vtime 
= _asl_time_string(tfmt
, val
, nano
); 
2105                                 asl_string_append_no_encoding(str
, vtime
); 
2110                                 asl_string_append_char_no_encoding(str
, '0'); 
2113                 else if (val 
!= NULL
) 
2115                         asl_string_append_char_no_encoding(str
, ' '); 
2116                         asl_string_append(str
, val
); 
2119                 asl_string_append_char_no_encoding(str
, ']'); 
2128 asl_string_append_asl_msg(asl_string_t 
*str
, asl_msg_t 
*msg
) 
2130         const char *key
, *val
; 
2134         if (msg 
== NULL
) return str
; 
2136         if (msg
->asl_type 
== ASL_TYPE_QUERY
) asl_string_append(str
, "Q "); 
2139         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, &op
); x 
!= IndexNull
; x 
= asl_msg_fetch(msg
, x
, &key
, &val
, &op
)) 
2141                 if (i 
!= 0)     asl_string_append_char_no_encoding(str
, ' '); 
2144                 asl_string_append_char_no_encoding(str
, '['); 
2146                 if (msg
->asl_type 
== ASL_TYPE_QUERY
) 
2148                         asl_string_append_op(str
, op
); 
2149                         asl_string_append_char_no_encoding(str
, ' '); 
2152                 asl_string_append_asl_key(str
, key
); 
2156                         asl_string_append_char_no_encoding(str
, ' '); 
2157                         asl_string_append(str
, val
); 
2160                 asl_string_append_char_no_encoding(str
, ']'); 
2167 asl_msg_to_string(asl_msg_t 
*msg
, uint32_t *len
) 
2170         asl_string_t 
*str 
= asl_string_new(ASL_ENCODE_ASL
); 
2171         if (str 
== NULL
) return NULL
; 
2173         str 
= asl_string_append_asl_msg(str
, msg
); 
2174         *len 
= asl_string_length(str
); 
2175         out 
= asl_string_release_return_bytes(str
); 
2180 _asl_msg_op_from_string(char *o
) 
2184         op 
= ASL_QUERY_OP_NULL
; 
2186         if (o 
== NULL
) return op
; 
2188         for (i 
= 0; o
[i
] != '\0'; i
++) 
2190                 if (o
[i
] == '.') return ASL_QUERY_OP_NULL
; 
2191                 if (o
[i
] == 'C') op 
|= ASL_QUERY_OP_CASEFOLD
; 
2192                 if (o
[i
] == 'R') op 
|= ASL_QUERY_OP_REGEX
; 
2193                 if (o
[i
] == 'N') op 
|= ASL_QUERY_OP_NUMERIC
; 
2194                 if (o
[i
] == 'S') op 
|= ASL_QUERY_OP_SUBSTRING
; 
2195                 if (o
[i
] == 'A') op 
|= ASL_QUERY_OP_PREFIX
; 
2196                 if (o
[i
] == 'Z') op 
|= ASL_QUERY_OP_SUFFIX
; 
2197                 if (o
[i
] == '<') op 
|= ASL_QUERY_OP_LESS
; 
2198                 if (o
[i
] == '>') op 
|= ASL_QUERY_OP_GREATER
; 
2199                 if (o
[i
] == '=') op 
|= ASL_QUERY_OP_EQUAL
; 
2200                 if (o
[i
] == '!') op 
|= ASL_QUERY_OP_NOT_EQUAL
; 
2201                 if (o
[i
] == 'T') op 
|= ASL_QUERY_OP_TRUE
; 
2208 _asl_msg_get_next_word(char **p
, uint32_t *tt
, uint32_t spacedel
) 
2210         char *str
, *out
, c
, oval
; 
2211         uint32_t i
, len
, n
, outlen
; 
2215         if (p 
== NULL
) return NULL
; 
2216         if (*p 
== NULL
) return NULL
; 
2217         if (**p 
== '\0') return NULL
; 
2219         /* skip one space if it's there (word separator) */ 
2220         if (**p 
== ' ') (*p
)++; 
2222         /* skip leading white space */ 
2225                 while ((**p 
== ' ') || (**p 
== '\t')) (*p
)++; 
2228         if (**p 
== '\0') return NULL
; 
2229         if (**p 
== '\n') return NULL
; 
2240                 if (out 
== NULL
) return NULL
; 
2247         /* scan for token and calulate it's length (input and decoded output len) */ 
2255                 /* stop scanning when we hit a delimiter */ 
2256                 if (((spacedel 
!= 0) && (c 
== ' ')) || (c 
== ']') || (c 
== '\0')) break; 
2262                         if ((c 
== 'a') || (c 
== 'b') || (c 
== 't') || (c 
== 'n') || (c 
== 'v') || (c 
== 'f') || (c 
== 'r') || (c 
== 's') || (c 
== '[') || (c 
== '\\') || (c 
== ']')) 
2267                                 if (str
[++len
] == '\0') return NULL
; 
2271                                 if (str
[++len
] == '\0') return NULL
; 
2272                                 if (str
[++len
] == '\0') return NULL
; 
2274                         else if ((c 
>= '0') && (c 
<= '3')) 
2276                                 if (str
[++len
] == '\0') return NULL
; 
2277                                 if (str
[++len
] == '\0') return NULL
; 
2291         if ((len 
== 0) && (**p 
== ']')) 
2296                 if (out 
== NULL
) return NULL
; 
2305         out 
= malloc(outlen 
+ 1); 
2306         if (out 
== NULL
) return NULL
; 
2309         for (i 
= 0; i 
< len
; i
++) 
2366                                 if (str
[i
] == '?') out
[n
++] = 127; 
2367                                 else out
[n
++] = str
[i
] - 64; 
2376                                         if (str
[i
] == '?') out
[n
++] = 255; 
2377                                         else out
[n
++] = str
[i
] + 64; 
2382                                         out
[n
++] = str
[i
] + 128; 
2392                         else if ((c 
>= '0') && (c 
<= '3')) 
2394                                 oval 
= (c 
- '0') * 64; 
2398                                 if ((c 
< '0') || (c 
> '7')) 
2405                                 oval 
+= ((c 
- '0') * 8); 
2409                                 if ((c 
< '0') || (c 
> '7')) 
2430                         if ((c 
< '0') || (c 
> '9')) *tt 
= TOKEN_WORD
; 
2441 asl_msg_from_string(const char *buf
) 
2443         uint32_t tt
, type
, op
; 
2444         char *k
, *v
, *o
, *p
; 
2447         if (buf 
== NULL
) return NULL
; 
2449         type 
= ASL_TYPE_MSG
; 
2452         k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2453         if (k 
== NULL
) return NULL
; 
2457                 type 
= ASL_TYPE_QUERY
; 
2460                 k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2462         else if (tt 
== TOKEN_INT
) 
2464                 /* Leading integer is a string length - skip it */ 
2466                 k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2467                 if (k 
== NULL
) return NULL
; 
2470         out 
= asl_msg_new(ASL_TYPE_MSG
); 
2471         if (out 
== NULL
) return NULL
; 
2473         out
->asl_type 
= type
; 
2475         /* OPEN WORD [WORD [WORD]] CLOSE */ 
2478                 op 
= ASL_QUERY_OP_NULL
; 
2480                 if (tt 
!= TOKEN_OPEN
) 
2482                         asl_msg_release(out
); 
2488                 /* get op for query type */ 
2489                 if (type 
== ASL_TYPE_QUERY
) 
2491                         o 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2492                         if ((o 
== NULL
) || (tt 
!= TOKEN_WORD
)) 
2494                                 if (o 
!= NULL
) free(o
); 
2495                                 asl_msg_release(out
); 
2499                         op 
= _asl_msg_op_from_string(o
); 
2503                 k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2504                 if (tt 
== TOKEN_INT
) tt 
= TOKEN_WORD
; 
2505                 if ((k 
== NULL
) || (tt 
!= TOKEN_WORD
)) 
2507                         if (k 
!= NULL
) free(k
); 
2508                         asl_msg_release(out
); 
2512                 v 
= _asl_msg_get_next_word(&p
, &tt
, 0); 
2513                 if (tt 
== TOKEN_INT
) tt 
= TOKEN_WORD
; 
2516                         asl_msg_set_key_val_op(out
, k
, NULL
, op
); 
2521                 if (tt 
== TOKEN_CLOSE
) 
2523                         asl_msg_set_key_val_op(out
, k
, NULL
, op
); 
2525                 else if (tt 
== TOKEN_WORD
) 
2527                         asl_msg_set_key_val_op(out
, k
, v
, op
); 
2531                         if (k 
!= NULL
) free(k
); 
2532                         if (v 
!= NULL
) free(v
); 
2533                         asl_msg_release(out
); 
2537                 if (k 
!= NULL
) free(k
); 
2538                 if (v 
!= NULL
) free(v
); 
2540                 if (tt 
!= TOKEN_CLOSE
) 
2542                         k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2543                         if (k 
== NULL
) break; 
2545                         if (tt 
!= TOKEN_CLOSE
) 
2547                                 asl_msg_release(out
); 
2554                 k 
= _asl_msg_get_next_word(&p
, &tt
, 1); 
2555                 if (k 
== NULL
) break; 
2562 _asl_level_string(int level
) 
2564         if (level 
== ASL_LEVEL_EMERG
) return ASL_STRING_EMERG
; 
2565         if (level 
== ASL_LEVEL_ALERT
) return ASL_STRING_ALERT
; 
2566         if (level 
== ASL_LEVEL_CRIT
) return ASL_STRING_CRIT
; 
2567         if (level 
== ASL_LEVEL_ERR
) return ASL_STRING_ERR
; 
2568         if (level 
== ASL_LEVEL_WARNING
) return ASL_STRING_WARNING
; 
2569         if (level 
== ASL_LEVEL_NOTICE
) return ASL_STRING_NOTICE
; 
2570         if (level 
== ASL_LEVEL_INFO
) return ASL_STRING_INFO
; 
2571         if (level 
== ASL_LEVEL_DEBUG
) return ASL_STRING_DEBUG
; 
2576 _asl_level_char(int level
) 
2578         if (level 
== ASL_LEVEL_EMERG
) return "P"; 
2579         if (level 
== ASL_LEVEL_ALERT
) return "A"; 
2580         if (level 
== ASL_LEVEL_CRIT
) return "C"; 
2581         if (level 
== ASL_LEVEL_ERR
) return "E"; 
2582         if (level 
== ASL_LEVEL_WARNING
) return "W"; 
2583         if (level 
== ASL_LEVEL_NOTICE
) return "N"; 
2584         if (level 
== ASL_LEVEL_INFO
) return "I"; 
2585         if (level 
== ASL_LEVEL_DEBUG
) return "D"; 
2590  * Find the value for a key in a message and append a formatted value to str. 
2591  * kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)). 
2592  * WARNING: modifies kf! 
2594 static asl_string_t 
* 
2595 _asl_string_append_value_for_key_format(asl_string_t 
*str
, asl_msg_t 
*msg
, char *kf
, const char *tfmt
) 
2597         uint32_t i
, get_fmt
; 
2600         const char *mval
, *nano
; 
2602         if (str 
== NULL
) return NULL
; 
2603         if (msg 
== NULL
) return str
; 
2604         if (kf 
== NULL
) return str
; 
2610         for (i 
= 0; kf
[i
] != '\0'; i
++) 
2617                 else if (kf
[i
] != '(') 
2619                         if (key 
== NULL
) key 
= kf 
+ i
; 
2620                         else if ((get_fmt 
== 1) && (fmt 
== NULL
)) fmt 
= kf 
+ i
; 
2624         if (key 
== NULL
) return str
; 
2627         asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
); 
2629         status 
= asl_msg_lookup(msg
, key
, &mval
, NULL
); 
2630         if ((status 
!= 0) || (mval 
== NULL
)) return str
; 
2632         if (!strcmp(key
, ASL_KEY_TIME
)) 
2636                 /* format in $((Time)(fmt)) overrides tfmt */ 
2639                         fval 
= _asl_time_string(tfmt
, mval
, nano
); 
2643                         fval 
= _asl_time_string(fmt
, mval
, nano
); 
2648                         asl_string_append_no_encoding(str
, fval
); 
2653                         asl_string_append_char_no_encoding(str
, '0'); 
2659         /* Level: num str */ 
2660         if (!strcmp(key
, ASL_KEY_LEVEL
)) 
2664                         asl_string_append_no_encoding(str
, mval
); 
2666                 else if (!strcmp(fmt
, "str")) 
2668                         mval 
= _asl_level_string(atoi(mval
)); 
2669                         asl_string_append_no_encoding(str
, mval
); 
2671                 else if (!strcmp(fmt
, "char")) 
2673                         mval 
= _asl_level_char(atoi(mval
)); 
2674                         asl_string_append_no_encoding(str
, mval
); 
2678                         asl_string_append_no_encoding(str
, mval
); 
2684         return asl_string_append(str
, mval
); 
2688  * format a message for printing 
2689  * out parameter len returns string length including trailing NUL 
2692 asl_format_message(asl_msg_t 
*msg
, const char *mfmt
, const char *tfmt
, uint32_t text_encoding
, uint32_t *len
) 
2694         char *out
, *vtime
, *k
, c
, skey
[512], tfmt_ext
[16]; 
2695         const char *vhost
, *vpid
, *vsender
, *vmessage
, *vlevel
, *vrefproc
, *vrefpid
, *v
, *key
, *val
, *nano
; 
2696         int i
, j
, l
, mf
, paren
, oval
, level
; 
2704         if (msg 
== NULL
) return NULL
; 
2708         if (mfmt 
== NULL
) mf 
= MFMT_RAW
; 
2709         else if (!strcmp(mfmt
, ASL_MSG_FMT_RAW
)) mf 
= MFMT_RAW
; 
2710         else if (!strcmp(mfmt
, ASL_MSG_FMT_STD
)) mf 
= MFMT_STD
; 
2711         else if (!strcmp(mfmt
, ASL_MSG_FMT_BSD
)) mf 
= MFMT_BSD
; 
2712         else if (!strcmp(mfmt
, ASL_MSG_FMT_XML
)) mf 
= MFMT_XML
; 
2713         else if (!strcmp(mfmt
, ASL_MSG_FMT_MSG
)) mf 
= MFMT_MSG
; 
2714         else if ((!strncmp(mfmt
, ASL_MSG_FMT_RAW
, 3)) && (mfmt
[3] == '.')) 
2717                 if ((tfmt 
== NULL
) && (mfmt
[4] != '\0')) 
2719                         snprintf(tfmt_ext
, sizeof(tfmt_ext
), "sec.%s", mfmt 
+ 4); 
2720                         tfmt 
= (const char *)tfmt_ext
; 
2723         else if ((!strncmp(mfmt
, ASL_MSG_FMT_STD
, 3)) && (mfmt
[3] == '.')) 
2726                 if ((tfmt 
== NULL
) && (mfmt
[4] != '\0')) 
2728                         snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt 
+ 4); 
2729                         tfmt 
= (const char *)tfmt_ext
; 
2732         else if ((!strncmp(mfmt
, ASL_MSG_FMT_BSD
, 3)) && (mfmt
[3] == '.')) 
2735                 if ((tfmt 
== NULL
) && (mfmt
[4] != '\0')) 
2737                         snprintf(tfmt_ext
, sizeof(tfmt_ext
), "lcl.%s", mfmt 
+ 4); 
2738                         tfmt 
= (const char *)tfmt_ext
; 
2744         asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
); 
2748                 str 
= asl_msg_to_string_raw(text_encoding
, msg
, tfmt
); 
2749                 asl_string_append_char_no_encoding(str
, '\n'); 
2751                 *len 
= asl_string_length(str
); 
2752                 out 
= asl_string_release_return_bytes(str
); 
2760                 if (asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
) != 0) return NULL
; 
2762                 str 
= asl_string_new(text_encoding
); 
2763                 if (str 
== NULL
) return NULL
; 
2765                 asl_string_append(str
, vmessage
); 
2766                 asl_string_append_char_no_encoding(str
, '\n'); 
2768                 *len 
= asl_string_length(str
); 
2769                 out 
= asl_string_release_return_bytes(str
); 
2773         if ((mf 
== MFMT_STD
) || (mf 
== MFMT_BSD
)) 
2775                 /* COMMON:  Mth dd hh:mm:ss host sender[pid] (refproc[refpid])*/ 
2776                 /* BSD:  <COMMON>: message */ 
2777                 /* STD:  <COMMON> <Level>: message */ 
2789                 if (asl_msg_lookup(msg
, ASL_KEY_TIME
, &v
, NULL
) == 0) 
2791                         vtime 
= _asl_time_string(tfmt
, v
, nano
); 
2795                 if (asl_msg_lookup(msg
, ASL_KEY_LEVEL
, &vlevel
, NULL
) == 0) 
2797                         if (vlevel 
!= NULL
) level 
= atoi(vlevel
); 
2800                 if (asl_msg_lookup(msg
, ASL_KEY_HOST
, &vhost
, NULL
) == 0) 
2802                         if (vhost 
== NULL
) vhost 
= "unknown"; 
2805                 if (asl_msg_lookup(msg
, ASL_KEY_SENDER
, &vsender
, NULL
) == 0) 
2807                         if (vsender 
== NULL
) vsender 
= "unknown"; 
2810                 asl_msg_lookup(msg
, ASL_KEY_PID
, &vpid
, NULL
); 
2811                 asl_msg_lookup(msg
, ASL_KEY_MSG
, &vmessage
, NULL
); 
2812                 asl_msg_lookup(msg
, ASL_KEY_REF_PROC
, &vrefproc
, NULL
); 
2813                 asl_msg_lookup(msg
, ASL_KEY_REF_PID
, &vrefpid
, NULL
); 
2816                 str 
= asl_string_new(text_encoding
); 
2817                 if (str 
== NULL
) return NULL
; 
2821                         asl_string_append(str
, vtime
); 
2826                         asl_string_append_char_no_encoding(str
, '0'); 
2829                 asl_string_append_char_no_encoding(str
, ' '); 
2830                 asl_string_append(str
, vhost
); 
2831                 asl_string_append_char_no_encoding(str
, ' '); 
2832                 asl_string_append(str
, vsender
); 
2834                 if ((vpid 
!= NULL
) && (strcmp(vpid
, "-1"))) 
2836                         asl_string_append_char_no_encoding(str
, '['); 
2837                         asl_string_append(str
, vpid
); 
2838                         asl_string_append_char_no_encoding(str
, ']'); 
2841                 if ((vrefproc 
!= NULL
) || (vrefpid 
!= NULL
)) asl_string_append_no_encoding(str
, " ("); 
2843                 if (vrefproc 
!= NULL
) asl_string_append(str
, vrefproc
); 
2844                 if (vrefpid 
!= NULL
) 
2846                         asl_string_append_char_no_encoding(str
, '['); 
2847                         asl_string_append(str
, vrefpid
); 
2848                         asl_string_append_char_no_encoding(str
, ']'); 
2851                 if ((vrefproc 
!= NULL
) || (vrefpid 
!= NULL
)) asl_string_append_char_no_encoding(str
, ')'); 
2855                         asl_string_append_no_encoding(str
, " <"); 
2856                         asl_string_append(str
, _asl_level_string(level
)); 
2857                         asl_string_append_char_no_encoding(str
, '>'); 
2860                 asl_string_append_no_encoding(str
, ": "); 
2861                 if (vmessage 
!= NULL
) asl_string_append(str
, vmessage
); 
2862                 asl_string_append_char_no_encoding(str
, '\n'); 
2864                 *len 
= asl_string_length(str
); 
2865                 out 
= asl_string_release_return_bytes(str
); 
2871                 str 
= asl_string_new(text_encoding
); 
2872                 if (str 
== NULL
) return NULL
; 
2874                 asl_string_append_char_no_encoding(str
, '\t'); 
2875                 asl_string_append_no_encoding(str
, "<dict>"); 
2876                 asl_string_append_char_no_encoding(str
, '\n'); 
2878                 for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x 
!= IndexNull
; x 
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
)) 
2880                         if (asl_is_utf8(key
) == 1) 
2882                                 asl_string_append_xml_tag(str
, "key", key
); 
2883                                 if (!strcmp(key
, ASL_KEY_TIME
)) 
2885                                         vtime 
= _asl_time_string(tfmt
, val
, nano
); 
2888                                                 asl_string_append_xml_tag(str
, "string", vtime
); 
2893                                                 asl_string_append_xml_tag(str
, "string", "0"); 
2898                                         if (asl_is_utf8(val
) == 1) asl_string_append_xml_tag(str
, "string", val
); 
2901                                                 b64 
= asl_b64_encode((uint8_t *)val
, strlen(val
)); 
2902                                                 asl_string_append_xml_tag(str
, "data", (char *)b64
); 
2909                 asl_string_append_char_no_encoding(str
, '\t'); 
2910                 asl_string_append_no_encoding(str
, "</dict>"); 
2911                 asl_string_append_char_no_encoding(str
, '\n'); 
2913                 *len 
= asl_string_length(str
); 
2914                 out 
= asl_string_release_return_bytes(str
); 
2920          * The format string may contain arbitrary characters. 
2921          * Keys are identified by $Key or $(Key).  The value for 
2922          * that key is substituted.  If there are alterate formats 
2923          * for the value (for example a time may be formatted as 
2924          * raw seconds, in UTC, or a local timezone), then the 
2925          * key may be $((Key)(Format)).  "\$" prints a plain "$". 
2928         str 
= asl_string_new(text_encoding
); 
2929         if (str 
== NULL
) return NULL
; 
2932          * We need enough space to copy any keys found in mfmt. 
2933          * The key obviously can't be longer than strlen(mfmt), 
2934          * in fact, keys must be shorter, since there's at least a '$' 
2935          * in front of the key, so we allocate a buffer with strlen(mfmt). 
2936          * If strlen(mfmt) <= sizeof(skey), we use skey to avoid a malloc. 
2940         if (x 
<= sizeof(skey
)) 
2947                 if (k 
== NULL
) return NULL
; 
2952         for (i 
= 0; mfmt
[i
] != '\0'; i
++) 
2958                         /* scan key, (key) or ((key)(format)) */ 
2959                         for (j 
= i 
+ 1; mfmt
[j
] != 0; j
++) 
2965                                 else if (mfmt
[j
] == ')') 
2967                                         if (paren 
> 0) paren
--; 
2974                                 else if (((mfmt
[j
] == ' ') || (mfmt
[j
] == '\t')) && (paren 
== 0)) break; 
2977                         /* mfmt[i + 1] is the first char of the key or a '('. mfmt[j] is one char past the end. */ 
2979                         memcpy(k
, mfmt
+i
+1, l
); 
2981                         _asl_string_append_value_for_key_format(str
, msg
, k
, tfmt
); 
2987                 if (mfmt
[i
] == '\\') 
2990                         if (mfmt
[i
] == '$') asl_string_append_char_no_encoding(str
, '$'); 
2991                         else if (mfmt
[i
] == 'e') asl_string_append_char_no_encoding(str
, '\e'); 
2992                         else if (mfmt
[i
] == 's') asl_string_append_char_no_encoding(str
, ' '); 
2993                         else if (mfmt
[i
] == 'a') asl_string_append_char_no_encoding(str
, '\a'); 
2994                         else if (mfmt
[i
] == 'b') asl_string_append_char_no_encoding(str
, '\b'); 
2995                         else if (mfmt
[i
] == 'f') asl_string_append_char_no_encoding(str
, '\f'); 
2996                         else if (mfmt
[i
] == 'n') asl_string_append_char_no_encoding(str
, '\n'); 
2997                         else if (mfmt
[i
] == 'r') asl_string_append_char_no_encoding(str
, '\r'); 
2998                         else if (mfmt
[i
] == 't') asl_string_append_char_no_encoding(str
, '\t'); 
2999                         else if (mfmt
[i
] == 'v') asl_string_append_char_no_encoding(str
, '\v'); 
3000                         else if (mfmt
[i
] == '\'') asl_string_append_char_no_encoding(str
, '\''); 
3001                         else if (mfmt
[i
] == '\\') asl_string_append_char_no_encoding(str
, '\\'); 
3002                         else if (isdigit(mfmt
[i
])) 
3004                                 oval 
= mfmt
[i
] - '0'; 
3005                                 if (isdigit(mfmt
[i
+1])) 
3008                                         oval 
= (oval 
* 8) + (mfmt
[i
] - '0'); 
3009                                         if (isdigit(mfmt
[i
+1])) 
3012                                                 oval 
= (oval 
* 8) + (mfmt
[i
] - '0'); 
3016                                 asl_string_append_char_no_encoding(str
, c
); 
3021                 if (mfmt
[i
] == '\0') break; 
3022                 asl_string_append_char_no_encoding(str
, mfmt
[i
]); 
3025         if (k 
!= skey
) free(k
); 
3027         asl_string_append_char_no_encoding(str
, '\n'); 
3029         *len 
= asl_string_length(str
); 
3030         out 
= asl_string_release_return_bytes(str
); 
3035 #pragma mark xpc conversion 
3038 _asl_msg_to_xpc(asl_msg_t 
*msg
, xpc_object_t dict
) 
3041         const char *key
, *val
, *nano
; 
3044         if (msg 
== NULL
) return; 
3045         if (dict 
== NULL
) return; 
3048         asl_msg_lookup(msg
, ASL_KEY_TIME_NSEC
, &nano
, NULL
); 
3050         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x 
!= IndexNull
; x 
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
)) 
3052                 if (key 
== NULL
) continue; 
3055                 kx 
= _asl_msg_std_key(key
, len
); 
3059                         xpc_object_t obj 
= xpc_null_create(); 
3060                         xpc_dictionary_set_value(dict
, key
, obj
); 
3065                         if (streq(key
, ASL_KEY_SENDER_MACH_UUID
)) 
3068                                 if (uuid_parse(val
, v
) == 0) 
3070                                         xpc_object_t obj 
= xpc_uuid_create(v
); 
3071                                         xpc_dictionary_set_value(dict
, key
, obj
); 
3077                                 xpc_object_t obj 
= xpc_string_create(val
); 
3078                                 xpc_dictionary_set_value(dict
, key
, obj
); 
3082                 else if (kx 
== ASL_STD_KEY_TIME
) 
3084                         uint64_t t 
= NSEC_PER_SEC 
* asl_core_parse_time(val
, NULL
); 
3085                         if (nano 
!= NULL
) t 
+= atoll(nano
); 
3086                         xpc_object_t obj 
= xpc_date_create(t
); 
3087                         xpc_dictionary_set_value(dict
, key
, obj
); 
3090                 else if (kx 
== ASL_STD_KEY_NANO
) 
3092                         /* handled with ASL_STD_KEY_TIME */ 
3094                 else if ((kx 
== ASL_STD_KEY_PID
) || (kx 
== ASL_STD_KEY_REF_PID
)) 
3096                         int64_t v 
= atoll(val
); 
3097                         xpc_object_t obj 
= xpc_int64_create(v
); 
3098                         xpc_dictionary_set_value(dict
, key
, obj
); 
3101                 else if ((kx 
== ASL_STD_KEY_UID
) || (kx 
== ASL_STD_KEY_GID
)) 
3103                         int64_t v 
= atoll(val
); 
3104                         xpc_object_t obj 
= xpc_int64_create(v
); 
3105                         xpc_dictionary_set_value(dict
, key
, obj
); 
3108                 else if (kx 
== ASL_STD_KEY_LEVEL
) 
3110                         int64_t v 
= atoll(val
); 
3111                         xpc_object_t obj 
= xpc_int64_create(v
); 
3112                         xpc_dictionary_set_value(dict
, key
, obj
); 
3115                 else if ((kx 
== ASL_STD_KEY_READ_UID
) || (kx 
== ASL_STD_KEY_READ_GID
)) 
3117                         int64_t v 
= atoll(val
); 
3118                         xpc_object_t obj 
= xpc_int64_create(v
); 
3119                         xpc_dictionary_set_value(dict
, key
, obj
); 
3122                 else if (kx 
== ASL_STD_KEY_MSG_ID
) 
3128                         xpc_object_t obj 
= xpc_string_create(val
); 
3129                         xpc_dictionary_set_value(dict
, key
, obj
); 
3136 _asl_log_args_to_xpc(asl_object_t client
, asl_object_t msg
, xpc_object_t dict
) 
3138         _asl_msg_to_xpc(asl_client_kvdict((asl_client_t 
*)client
), dict
); 
3139         _asl_msg_to_xpc((asl_msg_t 
*)msg
, dict
); 
3143 #pragma mark asl_object support 
3145 static asl_object_private_t 
* 
3146 _jump_alloc(uint32_t type
) 
3148         return (asl_object_private_t 
*)asl_msg_new(type
); 
3152 _jump_dealloc(asl_object_private_t 
*obj
) 
3154         asl_msg_t 
*msg 
= (asl_msg_t 
*)obj
; 
3157                 asl_msg_t 
*next 
= msg
->next
; 
3158                 _asl_msg_free_page(msg
); 
3164 _jump_set_key_val_op(asl_object_private_t 
*obj
, const char *key
, const char *val
, uint16_t op
) 
3167         int status 
= asl_msg_set_key_val_op((asl_msg_t 
*)obj
, key
, val
, op32
); 
3168         return (status 
== ASL_STATUS_OK
) ? 0 : -1; 
3172 _jump_unset_key(asl_object_private_t 
*obj
, const char *key
) 
3174         asl_msg_unset((asl_msg_t 
*)obj
, key
); 
3178 _jump_get_val_op_for_key(asl_object_private_t 
*obj
, const char *key
, const char **val
, uint16_t *op
) 
3180         return asl_msg_lookup((asl_msg_t 
*)obj
, key
, val
, op
); 
3184 _jump_get_key_val_op_at_index(asl_object_private_t 
*obj
, size_t n
, const char **key
, const char **val
, uint16_t *op
) 
3186         uint32_t slot 
= IndexNull
; 
3187         asl_msg_t 
*page 
= NULL
; 
3189         if  (0 != _asl_msg_resolve_index((asl_msg_t 
*)obj
, n
, &page
, &slot
)) return -1; 
3191         if (key 
!= NULL
) *key 
= _asl_msg_slot_key(page
, slot
); 
3192         if (val 
!= NULL
) *val 
= _asl_msg_slot_val(page
, slot
); 
3193         if (op 
!= NULL
) *op 
= _get_slot_op(page
, slot
); 
3199 _jump_count(asl_object_private_t 
*obj
) 
3201         size_t count 
= asl_msg_count((asl_msg_t 
*)obj
); 
3206 _jump_append(asl_object_private_t 
*obj
, asl_object_private_t 
*newobj
) 
3208         int type 
= asl_get_type((asl_object_t
)newobj
); 
3209         if ((type 
!= ASL_TYPE_QUERY
) && (type 
!= ASL_TYPE_MSG
)) return; 
3211         asl_msg_merge((asl_msg_t 
*)obj
, (asl_msg_t 
*)newobj
); 
3215 _jump_prepend(asl_object_private_t 
*obj
, asl_object_private_t 
*newobj
) 
3217         if (obj 
== NULL
) return; 
3219         int type 
= asl_get_type((asl_object_t
)newobj
); 
3220         if ((type 
!= ASL_TYPE_QUERY
) && (type 
!= ASL_TYPE_MSG
)) return; 
3222         asl_msg_replace((asl_msg_t 
*)obj
, (asl_msg_t 
*)newobj
); 
3225 static asl_object_private_t 
* 
3226 _jump_search(asl_object_private_t 
*obj
, asl_object_private_t 
*query
) 
3228         if (obj 
== NULL
) return NULL
; 
3232                 /* NULL matches any message */ 
3233                 asl_msg_list_t 
*out 
= asl_msg_list_new(); 
3234                 asl_msg_list_append(out
, obj
); 
3235                 return (asl_object_private_t 
*)out
; 
3238         if ((query
->asl_type 
!= ASL_TYPE_MSG
) && (query
->asl_type 
!= ASL_TYPE_QUERY
)) return NULL
; 
3240         if (asl_msg_cmp((asl_msg_t 
*)obj
, (asl_msg_t 
*)query
) == 1) 
3242                 asl_msg_list_t 
*out 
= asl_msg_list_new(); 
3243                 asl_msg_list_append(out
, obj
); 
3244                 return (asl_object_private_t 
*)out
; 
3250 static asl_object_private_t 
* 
3251 _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
) 
3253         if (obj 
== NULL
) return NULL
; 
3257                 /* NULL matches any message */ 
3258                 asl_msg_list_t 
*out 
= asl_msg_list_new(); 
3259                 asl_msg_list_append(out
, obj
); 
3260                 return (asl_object_private_t 
*)out
; 
3263         if (asl_msg_cmp_list((asl_msg_t 
*)obj
, (asl_msg_list_t 
*)qlist
) == 0) return NULL
; 
3265         asl_msg_list_t 
*out 
= asl_msg_list_new(); 
3266         asl_msg_list_append(out
, obj
); 
3267         return (asl_object_private_t 
*)out
; 
3271 __private_extern__ 
const asl_jump_table_t 
* 
3272 asl_msg_jump_table() 
3274         static const asl_jump_table_t jump 
= 
3276                 .alloc 
= &_jump_alloc
, 
3277                 .dealloc 
= &_jump_dealloc
, 
3278                 .set_key_val_op 
= &_jump_set_key_val_op
, 
3279                 .unset_key 
= &_jump_unset_key
, 
3280                 .get_val_op_for_key 
= &_jump_get_val_op_for_key
, 
3281                 .get_key_val_op_at_index 
= &_jump_get_key_val_op_at_index
, 
3282                 .count 
= &_jump_count
, 
3285                 .get_object_at_index 
= NULL
, 
3286                 .set_iteration_index 
= NULL
, 
3287                 .remove_object_at_index 
= NULL
, 
3288                 .append 
= &_jump_append
, 
3289                 .prepend 
= &_jump_prepend
, 
3290                 .search 
= &_jump_search
, 
3291                 .match 
= &_jump_match