* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
#include <stdarg.h>
#include <regex.h>
#include <syslog.h>
+#include <notify.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <asl.h>
+#include <asl_object.h>
#include <asl_private.h>
#include <asl_core.h>
+#include <asl_client.h>
#include <sys/types.h>
#include <libkern/OSAtomic.h>
-#include <assert.h>
-#include "asl_msg.h"
+#include <asl_msg.h>
+#include <asl_msg_list.h>
#define TOKEN_NULL 0
#define TOKEN_OPEN 1
#define SEC_PER_HOUR 3600
-#define forever for(;;)
-
-#define streq(A, B) (strcmp(A, B) == 0)
-#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
-#define strneq(A, B) (strcmp(A, B) != 0)
-#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
-#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
+#define PAGE_OBJECT 1
-#ifndef ASL_KEY_OPTION
-#define ASL_KEY_OPTION "ASLOption"
-#endif
+#define forever for(;;)
#ifndef ASL_QUERY_OP_FALSE
#define ASL_QUERY_OP_FALSE 0
#define AUX_0_OPTION 0x00000200
#define AUX_0_LEVEL 0x00000400
-extern time_t asl_parse_time(const char *in);
-
/* from asl_util.c */
int asl_is_utf8(const char *str);
uint8_t *asl_b64_encode(const uint8_t *buf, size_t len);
+void _asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg);
+
+#pragma mark -
+#pragma mark standard message keys
+
static const char *ASLStandardKey[] =
{
ASL_KEY_TIME,
ASL_KEY_REF_PROC,
ASL_KEY_MSG_ID,
ASL_KEY_EXPIRE_TIME,
- ASL_KEY_OPTION
+ ASL_KEY_OPTION,
+ ASL_KEY_FREE_NOTE
};
static const char *MTStandardKey[] =
{
if streq(s, ASL_KEY_EXPIRE_TIME) return ASL_STD_KEY_EXPIRE;
}
+ case 14:
+ {
+ if streq(s, ASL_KEY_FREE_NOTE) return ASL_STD_KEY_FREE_NOTE;
+ }
default:
{
return 0;
return 0;
}
-static asl_msg_t *
-_asl_msg_make_page()
+#pragma mark -
+#pragma mark asl_msg
+
+static uint32_t
+_slot_count(asl_msg_t *m)
{
- asl_msg_t *out;
- int i;
+ if (m == NULL) return 0;
+ if (m->asl_type == ASL_TYPE_MSG) return ASL_MSG_KVO_MSG_SLOTS;
+ if (m->asl_type == ASL_TYPE_QUERY) return ASL_MSG_KVO_QUERY_SLOTS;
+ return 0;
+}
+
+
+static uint16_t
+_get_slot_key(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot];
+ return 0;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot];
+ return 0;
+ }
+
+ return 0;
+}
+
+
+static void
+_set_slot_key(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot] = x;
+ return;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot] = x;
+ return;
+ }
+}
- out = calloc(1, sizeof(asl_msg_t));
- if (out == NULL) return NULL;
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+static uint16_t
+_get_slot_val(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) return m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS];
+ return 0;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
{
- out->key[i] = ASL_MSG_SLOT_FREE;
- out->val[i] = ASL_MSG_SLOT_FREE;
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS];
+ return 0;
}
+ return 0;
+}
+
+static void
+_set_slot_val(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_MSG)
+ {
+ if (slot < ASL_MSG_KVO_MSG_SLOTS) m->kvo[slot + ASL_MSG_KVO_MSG_SLOTS] = x;
+ return;
+ }
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + ASL_MSG_KVO_QUERY_SLOTS] = x;
+ return;
+ }
+}
+
+static uint16_t
+_get_slot_op(asl_msg_t *m, uint32_t slot)
+{
+ if (m == NULL) return 0;
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) return m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)];
+ return 0;
+ }
+
+ return 0;
+}
+
+static void
+_set_slot_op(asl_msg_t *m, uint32_t slot, uint16_t x)
+{
+ if (m == NULL) return;
+
+ if (m->asl_type == ASL_TYPE_QUERY)
+ {
+ if (slot < ASL_MSG_KVO_QUERY_SLOTS) m->kvo[slot + (ASL_MSG_KVO_QUERY_SLOTS * 2)] = x;
+ }
+}
+
+static asl_msg_t *
+_asl_msg_make_page(uint32_t type)
+{
+ uint32_t i, n = 0;
+ asl_msg_t *out = (asl_msg_t *)calloc(1, sizeof(asl_msg_t));
+ if (out == NULL) return NULL;
+
+ if (type == ASL_TYPE_MSG) n = ASL_MSG_KVO_MSG_SLOTS * 2;
+ else if (type == ASL_TYPE_QUERY) n = ASL_MSG_KVO_QUERY_SLOTS * 2;
+
+ for (i = 0; i < n; i++) out->kvo[i] = ASL_MSG_SLOT_FREE;
+
+ out->mem_size = sizeof(asl_msg_t);
+ out->asl_type = type;
+
return out;
}
+asl_msg_t *
+asl_msg_retain(asl_msg_t *msg)
+{
+ if (msg == NULL) return NULL;
+ asl_retain((asl_object_t)msg);
+ return msg;
+}
+
+void
+asl_msg_release(asl_msg_t *msg)
+{
+ if (msg == NULL) return;
+ asl_release((asl_object_t)msg);
+}
+
static const char *
_asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
{
const char *out;
- uint16_t x;
+ uint16_t x, k;
if (page == NULL) return NULL;
- if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
- if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL;
+ if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+ else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
- switch (page->key[slot] & ASL_MSG_KV_MASK)
+ k = _get_slot_key(page, slot);
+
+ if (k == ASL_MSG_SLOT_FREE) return NULL;
+
+ switch (k & ASL_MSG_KV_MASK)
{
case ASL_MSG_KV_INLINE:
{
- return page->data + page->key[slot];
+ return page->data + k;
}
case ASL_MSG_KV_DICT:
{
- if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST))
+ if ((k > ASL_STD_KEY_BASE) && (k <= ASL_STD_KEY_LAST))
{
- x = page->key[slot] - ASL_STD_KEY_BASE - 1;
+ x = k - ASL_STD_KEY_BASE - 1;
return ASLStandardKey[x];
}
- else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST))
+ else if ((k > ASL_MT_KEY_BASE) && (k <= ASL_MT_KEY_LAST))
{
- x = page->key[slot] - ASL_MT_KEY_BASE - 1;
+ x = k - ASL_MT_KEY_BASE - 1;
return MTStandardKey[x];
}
}
case ASL_MSG_KV_EXTERN:
{
- x = page->key[slot] & ASL_MSG_OFFSET_MASK;
+ x = k & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
_asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
{
const char *out;
- uint16_t x, type;
+ uint16_t x, v, type;
if (page == NULL) return NULL;
- if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
- if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL;
+ if ((page->asl_type == ASL_TYPE_MSG) && (slot >= ASL_MSG_KVO_MSG_SLOTS)) return NULL;
+ else if ((page->asl_type == ASL_TYPE_QUERY) && (slot >= ASL_MSG_KVO_QUERY_SLOTS)) return NULL;
+
+ v = _get_slot_val(page, slot);
- type = page->val[slot] & ASL_MSG_KV_MASK;
+ if (v == ASL_MSG_SLOT_FREE) return NULL;
+
+ type = v & ASL_MSG_KV_MASK;
if (type == ASL_MSG_KV_INLINE)
{
- return page->data + page->val[slot];
+ return page->data + v;
}
else if (type == ASL_MSG_KV_EXTERN)
{
- x = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ x = v & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
{
asl_msg_t *out;
- out = _asl_msg_make_page();
+ out = _asl_msg_make_page(type);
if (out == NULL) return NULL;
- out->type = type;
+ out->asl_type = type;
out->refcount = 1;
return out;
}
-asl_msg_t *
-asl_msg_retain(asl_msg_t *msg)
-{
- int32_t new;
-
- if (msg == NULL) return NULL;
-
- new = OSAtomicIncrement32Barrier(&msg->refcount);
- assert(new >= 1);
-
- return msg;
-}
-
static void
-_asl_msg_free(asl_msg_t *page)
+_asl_msg_free_page(asl_msg_t *page)
{
- uint32_t i;
+ uint32_t i, mslots;
char *p;
if (page == NULL) return;
- for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
+ mslots = _slot_count(page);
+
+ for (i = 0; i < mslots; i++)
{
- if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ uint16_t k = _get_slot_key(page, i);
+ uint16_t v = _get_slot_val(page, i);
+
+ if (k == ASL_STD_KEY_FREE_NOTE)
{
- memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ const char *x = _asl_msg_slot_val(page, i);
+ if (x != NULL) notify_post(x);
+ }
+
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ {
+ memcpy(&p, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
- if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&p, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
}
free(page);
}
-void
-asl_msg_release(asl_msg_t *msg)
+uint32_t
+asl_msg_type(asl_msg_t *msg)
{
- int32_t new;
- asl_msg_t *next;
+ if (msg == NULL) return 0;
+ return msg->asl_type;
+}
- if (msg == NULL) return;
+uint32_t
+asl_msg_count(asl_msg_t *msg)
+{
+ uint32_t total;
+
+ total = 0;
- new = OSAtomicDecrement32Barrier(&msg->refcount);
- assert(new >= 0);
+ for (; msg != NULL; msg = msg->next) total += msg->count;
+ return total;
+}
+
+static void
+_asl_msg_dump_kv(FILE *f, asl_msg_t *msg, uint16_t x)
+{
+ if (x == ASL_MSG_SLOT_FREE)
+ {
+ fprintf(f, "-free-");
+ return;
+ }
+
+ if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
+ {
+ switch (x)
+ {
+ case ASL_STD_KEY_TIME: fprintf(f, "(dict: Time)"); return;
+ case ASL_STD_KEY_NANO: fprintf(f, "(dict: Nano)"); return;
+ case ASL_STD_KEY_HOST: fprintf(f, "(dict: Host)"); return;
+ case ASL_STD_KEY_SENDER: fprintf(f, "(dict: Sender)"); return;
+ case ASL_STD_KEY_FACILITY: fprintf(f, "(dict: Facility)"); return;
+ case ASL_STD_KEY_PID: fprintf(f, "(dict: PID)"); return;
+ case ASL_STD_KEY_UID: fprintf(f, "(dict: UID)"); return;
+ case ASL_STD_KEY_GID: fprintf(f, "(dict: GID)"); return;
+ case ASL_STD_KEY_LEVEL: fprintf(f, "(dict: Level)"); return;
+ case ASL_STD_KEY_MESSAGE: fprintf(f, "(dict: Message)"); return;
+ case ASL_STD_KEY_READ_UID: fprintf(f, "(dict: ReadUID)"); return;
+ case ASL_STD_KEY_READ_GID: fprintf(f, "(dict: ReadGID)"); return;
+ case ASL_STD_KEY_SESSION: fprintf(f, "(dict: Session)"); return;
+ case ASL_STD_KEY_REF_PID: fprintf(f, "(dict: PID)"); return;
+ case ASL_STD_KEY_REF_PROC: fprintf(f, "(dict: RefProc)"); return;
+ case ASL_STD_KEY_MSG_ID: fprintf(f, "(dict: ASLMessageID)"); return;
+ case ASL_STD_KEY_EXPIRE: fprintf(f, "(dict: Expire)"); return;
+ case ASL_STD_KEY_OPTION: fprintf(f, "(dict: ASLOption)"); return;
+ case ASL_MT_KEY_DOMAIN: fprintf(f, "(dict: com.apple.message.domain)"); return;
+ case ASL_MT_KEY_SCOPE: fprintf(f, "(dict: com.apple.message.domain_scope)"); return;
+ case ASL_MT_KEY_RESULT: fprintf(f, "(dict: com.apple.message.result)"); return;
+ case ASL_MT_KEY_SIG: fprintf(f, "(dict: com.apple.message.signature)"); return;
+ case ASL_MT_KEY_SIG2: fprintf(f, "(dict: com.apple.message.signature2)"); return;
+ case ASL_MT_KEY_SIG3: fprintf(f, "(dict: com.apple.message.signature3)"); return;
+ case ASL_MT_KEY_SUCCESS: fprintf(f, "(dict: com.apple.message.success)"); return;
+ case ASL_MT_KEY_UUID: fprintf(f, "(dict: com.apple.message.uuid)"); return;
+ case ASL_MT_KEY_VAL: fprintf(f, "(dict: com.apple.message.value)"); return;
+ case ASL_MT_KEY_VAL2: fprintf(f, "(dict: com.apple.message.value2)"); return;
+ case ASL_MT_KEY_VAL3: fprintf(f, "(dict: com.apple.message.value3)"); return;
+ case ASL_MT_KEY_VAL4: fprintf(f, "(dict: com.apple.message.value4)"); return;
+ case ASL_MT_KEY_VAL5: fprintf(f, "(dict: com.apple.message.value5)"); return;
+ }
+
+ fprintf(f, "(dict: -unknown-)");
+ return;
+ }
+
+ if ((x & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ {
+ const char *c;
+ size_t z = x & ASL_MSG_OFFSET_MASK;
+ memcpy(&c, msg->data + z, sizeof(char *));
+ fprintf(f, "(extern: %s)", c);
+ return;
+ }
+
+ fprintf(f, "%s", msg->data + x);
+}
+
+void
+_asl_msg_dump(FILE *f, const char *comment, asl_msg_t *msg)
+{
+ uint32_t i, mslots, page1 = 1;
- if (new > 0) return;
+ if (f == NULL) return;
+ if (msg == NULL)
+ {
+ fprintf(f, "asl_msg %s: NULL\n", comment);
+ return;
+ }
+
+ mslots = _slot_count(msg);
while (msg != NULL)
{
- next = msg->next;
- _asl_msg_free(msg);
- msg = next;
+ if (page1 == 1)
+ {
+ fprintf(f, "asl_msg %s: %p\n", comment, msg);
+ fprintf(f, " refcount: %u\n", msg->refcount);
+ fprintf(f, " asl_type: %u\n", msg->asl_type);
+ page1 = 0;
+ }
+ else
+ {
+ fprintf(f, " page: %p\n", msg);
+ }
+
+ fprintf(f, " count: %u\n", msg->count);
+ fprintf(f, " data_size: %u\n", msg->data_size);
+ fprintf(f, " mem_size: %llu\n", msg->mem_size);
+ fprintf(f, " next: %p\n", msg->next);
+
+ for (i = 0; i < mslots; i++)
+ {
+ fprintf(f, " slot[%d]: ", i);
+ _asl_msg_dump_kv(f, msg, _get_slot_key(msg, i));
+ fprintf(f, " ");
+ _asl_msg_dump_kv(f, msg, _get_slot_val(msg, i));
+ if (msg->asl_type == ASL_TYPE_QUERY) fprintf(f, " 0x%04x\n", _get_slot_op(msg, i));
+ }
+
+ msg = msg->next;
}
}
+#pragma mark -
+#pragma mark fetching contents
+
+/*
+ * Find the slot and page for an input key.
+ */
static uint32_t
_asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
{
- uint32_t i, len, slot;
+ uint32_t i, len, slot, mslots;
uint16_t kx;
asl_msg_t *page;
const char *kp;
i = 0;
slot = 0;
+ mslots = _slot_count(msg);
+
if (oslot != NULL) *oslot = slot;
page = msg;
forever
{
- if (page->key[slot] != ASL_MSG_SLOT_FREE)
+ if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
{
if (kx != 0)
{
- if (page->key[slot] == kx) return i;
+ if (_get_slot_key(page, slot) == kx) return i;
}
- else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
+ else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
{
- /* page->key[slot] is a dictionary key, but key is not (kx == 0) so skip this slot */
+ /* _get_slot_key(page, slot) is a dictionary key, but key is not (kx == 0) so skip this slot */
}
- else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ else if ((_get_slot_key(page, slot) & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&kp, page->data + (_get_slot_key(page, slot) & ASL_MSG_OFFSET_MASK), sizeof(char *));
if (streq(key, kp)) return i;
}
else
{
- kp = page->data + page->key[slot];
+ kp = page->data + _get_slot_key(page, slot);
if (streq(key, kp)) return i;
}
}
slot++;
if (oslot != NULL) *oslot = slot;
- if (slot >= ASL_MSG_PAGE_SLOTS)
+ if (slot >= mslots)
{
if (page->next == NULL) return IndexNull;
}
/*
- * asl_msg_key: iterate over entries
- * initial value of n should be 0
- * after that, the value of n should be previously returned value
- * sets the pointers for the next key, value, and op in the msgionary
- * returns IndexNull when there are no more entries
+ * Find page and slot for an "index".
*/
-static uint32_t
-_asl_msg_fetch_internal(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout, asl_msg_t **outpage, uint32_t *outslot)
+static int
+_asl_msg_resolve_index(asl_msg_t *msg, uint32_t n, asl_msg_t **page, uint32_t *slot)
{
- uint32_t slot;
- asl_msg_t *page;
+ uint32_t i, sx, mslots;
+ asl_msg_t *px;
+
+ if (msg == NULL) return -1;
+
+ *slot = IndexNull;
+ *page = NULL;
+
+ mslots = _slot_count(msg);
+
+ sx = 0;
+
+ /* find page */
+ for (px = msg; px != NULL; px = px->next)
+ {
+ if (n > (sx + px->count))
+ {
+ sx += px->count;
+ continue;
+ }
+
+ *page = px;
+
+ /* find slot */
+ for (i = 0; i < mslots; i++)
+ {
+ if (px->kvo[i] != ASL_MSG_SLOT_FREE)
+ {
+ if (sx == n)
+ {
+ *slot = i;
+ return 0;
+ }
+
+ sx++;
+ }
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * asl_msg_fetch: iterate over entries
+ * initial value of n should be 0. Subseqent calls should use the last
+ * returned value. Returns IndexNull when there are no more entries
+ * Sets the pointers for the next key, value, and op in the msg.
+ * The iterator encodes a page number and a slot number.
+ */
+
+uint32_t
+asl_msg_fetch(asl_msg_t *msg, uint32_t x, const char **keyout, const char **valout, uint16_t *opout)
+{
+ uint32_t p, xpn, xsn, mslots;
+ asl_msg_t *page = NULL;
if (msg == NULL) return IndexNull;
- if (outpage != NULL) *outpage = NULL;
- if (outslot != NULL) *outslot = IndexNull;
- slot = n;
- page = msg;
+ mslots = _slot_count(msg);
+
+ xsn = x >> 24;
+ xpn = x & 0x00ffffff;
+
+ /* slot number 0xff means we have run out entries */
+ if (xsn == 0x000000ff) return IndexNull;
- while (slot >= ASL_MSG_PAGE_SLOTS)
+ page = msg;
+ for (p = 0; p < xpn; p++)
{
- if (page->next == NULL) return IndexNull;
page = page->next;
- slot -= ASL_MSG_PAGE_SLOTS;
+ if (page == NULL) return IndexNull;
}
- while (page->key[slot] == ASL_MSG_SLOT_FREE)
+ if (keyout != NULL) *keyout = _asl_msg_slot_key(page, xsn);
+ if (valout != NULL) *valout = _asl_msg_slot_val(page, xsn);
+ if (opout != NULL) *opout = _get_slot_op(page, xsn);
+
+ /* advance to the next slot */
+ forever
{
- slot++;
- n++;
+ xsn++;
- if (slot >= ASL_MSG_PAGE_SLOTS)
+ if (xsn >= mslots)
{
- if (page->next == NULL) return IndexNull;
+ if (page->next == NULL) return 0xff000000;
+ xsn = 0;
page = page->next;
- slot = 0;
+ xpn++;
}
+
+ if (page->kvo[xsn] != ASL_MSG_SLOT_FREE) return ((xsn << 24) | xpn);
}
- n++;
+ return IndexNull;
+}
+
+int
+asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint16_t *opout)
+{
+ uint32_t i, slot;
+ asl_msg_t *page;
+
+ if (msg == NULL) return -1;
+ if (valout != NULL) *valout = NULL;
+ if (opout != NULL) *opout = 0;
+
+ slot = IndexNull;
+ page = NULL;
+
+ i = _asl_msg_index(msg, key, &slot, &page);
+ if (i == IndexNull) return -1;
- if (keyout != NULL) *keyout = _asl_msg_slot_key(page, slot);
if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
- if (opout != NULL) *opout = page->op[slot];
+ if (opout != NULL) *opout = _get_slot_op(page, slot);
+
+ return 0;
+}
- if (outpage != NULL) *outpage = page;
- if (outslot != NULL) *outslot = slot;
+const char *
+asl_msg_get_val_for_key(asl_msg_t *msg, const char *key)
+{
+ uint32_t slot;
+ asl_msg_t *page;
+
+ if (msg == NULL) return NULL;
- return n;
+ slot = IndexNull;
+ page = NULL;
+
+ if (_asl_msg_index(msg, key, &slot, &page) == IndexNull) return NULL;
+
+ return _asl_msg_slot_val(page, slot);
}
-uint32_t
-asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout)
+const char *
+asl_msg_key(asl_msg_t *msg, uint32_t n)
{
- return _asl_msg_fetch_internal(msg, n, keyout, valout, opout, NULL, NULL);
+ uint32_t slot, i, mslots;
+ asl_msg_t *page;
+
+ if (msg == NULL) return NULL;
+
+ mslots = _slot_count(msg);
+
+ i = 0;
+ for (page = msg; page != NULL; page = page->next)
+ {
+ for (slot = 0; slot < mslots; slot++)
+ {
+ if (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE)
+ {
+ if (i == n) return _asl_msg_slot_key(page, slot);
+ i++;
+ }
+ }
+ }
+
+ return NULL;
}
+#pragma mark -
+#pragma mark adding and replacing contents
+
static int
_asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
- uint32_t slot, keylen, vallen, total;
- uint16_t kx;
+ uint32_t slot, keylen, vallen, total, mslots;
+ uint64_t klen, vlen;
+ uint16_t kx, k, v, o;
asl_msg_t *page, *last;
char *extkey, *extval;
if (msg == NULL) return -1;
if (key == NULL) return -1;
+ mslots = _slot_count(msg);
+
+ o = op;
extkey = NULL;
extval = NULL;
keylen = strlen(key);
+ klen = keylen;
kx = _asl_msg_std_key(key, keylen);
if (kx == 0) keylen++;
if (val != NULL)
{
vallen = strlen(val) + 1;
+ vlen = vallen;
total += vallen;
}
if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
{
/* check for a free slot */
- for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++);
- if (slot < ASL_MSG_PAGE_SLOTS) break;
+ for (slot = 0; (slot < mslots) && (_get_slot_key(page, slot) != ASL_MSG_SLOT_FREE); slot++);
+ if (slot < mslots) break;
}
}
if (page == NULL)
{
/* allocate a new page and attach it */
- page = _asl_msg_make_page();
+ page = _asl_msg_make_page(msg->asl_type);
if (page == NULL)
{
if (extkey != NULL) free(extkey);
/* copy key or external key pointer into page data */
if (kx != 0)
{
- page->key[slot] = kx;
+ k = kx;
}
else if (extkey == NULL)
{
- page->key[slot] = page->data_size;
+ k = page->data_size;
memcpy(page->data + page->data_size, key, keylen);
}
else
{
- page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+ k = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extkey, keylen);
+ page->mem_size += klen;
}
+ _set_slot_key(page, slot, k);
page->data_size += keylen;
/* copy val or external val pointer into page data */
- page->val[slot] = ASL_MSG_SLOT_FREE;
+
+ v = ASL_MSG_SLOT_FREE;
if (val != NULL)
{
if (extval == NULL)
{
- page->val[slot] = page->data_size;
+ v = page->data_size;
memcpy(page->data + page->data_size, val, vallen);
}
else
{
- page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN;
+ v = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extval, vallen);
+ page->mem_size += vlen;
}
+ _set_slot_val(page, slot, v);
page->data_size += vallen;
}
/* set op */
- page->op[slot] = op;
+ _set_slot_op(page, slot, o);
/* update page count */
page->count++;
static int
_asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
- uint32_t i, slot, newexternal;
+ uint32_t i, slot, mslots, newexternal;
asl_msg_t *page;
uint32_t intvallen, extvallen, newvallen;
char *intval, *extval, *newval;
+ uint16_t k, v, o;
if (msg == NULL) return -1;
if (key == NULL) return -1;
+ mslots = _slot_count(msg);
+
slot = IndexNull;
page = NULL;
- if ((msg->type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
+ o = op;
+
+ if ((msg->asl_type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
{
/* add key */
return _asl_msg_new_key_val_op(msg, key, val, op);
extval = NULL;
extvallen = 0;
- if (page->val[slot] != ASL_MSG_SLOT_FREE)
+ v = _get_slot_val(page, slot);
+
+ if (v != ASL_MSG_SLOT_FREE)
{
- if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
memcpy(&extval, page->data + i, sizeof(char *));
extvallen = sizeof(char *);
}
else
{
- intval = page->data + page->val[slot];
+ intval = page->data + v;
intvallen = strlen(intval) + 1;
}
}
/* easy case - remove val */
if (val == NULL)
{
- if (extval != NULL) free(extval);
- page->val[slot] = ASL_MSG_SLOT_FREE;
- if (op != IndexNull) page->op[slot] = op;
+ if (extval != NULL)
+ {
+ page->mem_size -= (strlen(extval) + 1);
+ free(extval);
+ }
+
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* trivial case - internal val doesn't change */
if ((intval != NULL) && (streq(val, intval)))
{
- if (op != IndexNull) page->op[slot] = op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* trivial case - external val doesn't change */
if ((extval != NULL) && (streq(val, extval)))
{
- if (op != IndexNull) page->op[slot] = op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/*
* special case: we generally don't compress out holes in the data
* space, but if this is the last string in the currently used data space
- * we can just back up the data_size and reset page->val[slot]
+ * we can just back up the data_size and reset page->val[slot] (a.k.a. page->kvo[slot + mslots])
*/
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
if ((intval != NULL) && ((i + intvallen) == page->data_size))
{
- page->val[slot] = ASL_MSG_SLOT_FREE;
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
page->data_size -= intvallen;
intval = NULL;
intvallen = 0;
}
else if ((extval != NULL) && ((i + extvallen) == page->data_size))
{
- page->val[slot] = ASL_MSG_SLOT_FREE;
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
page->data_size -= extvallen;
+ page->mem_size -= (strlen(extval) + 1);
free(extval);
extval = NULL;
extvallen = 0;
/* check if there is room to change val in place */
if (((extval != NULL) && (newvallen <= extvallen)) || ((extval == NULL) && (newvallen <= intvallen)))
{
- if (extval != NULL) free(extval);
+ if (extval != NULL)
+ {
+ page->mem_size -= (strlen(extval) + 1);
+ free(extval);
+ }
+
extval = NULL;
/* we can re-use the space of the old value */
- i = page->val[slot] & ASL_MSG_OFFSET_MASK;
+ i = v & ASL_MSG_OFFSET_MASK;
if (newexternal == 1)
{
newval = strdup(val);
if (newval == NULL) return -1;
- page->val[slot] = i | ASL_MSG_KV_EXTERN;
+ page->mem_size += (strlen(newval) + 1);
+ _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
/* new internal value */
- page->val[slot] = i;
+ _set_slot_val(page, slot, i);
memcpy(page->data + i, val, newvallen);
}
- if (op != IndexNull) page->op[slot] = op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* we're done with the old value if it is external - free it now */
- if (extval != NULL) free(extval);
+ if (extval != NULL)
+ {
+ page->mem_size -= (strlen(extval) + 1);
+ free(extval);
+ }
+
extval = NULL;
if (newvallen <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
newval = strdup(val);
if (newval == NULL) return -1;
- page->val[slot] = i | ASL_MSG_KV_EXTERN;
+ page->mem_size += (strlen(newval) + 1);
+ _set_slot_val(page, slot, i | ASL_MSG_KV_EXTERN);
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
/* new internal value */
- page->val[slot] = i;
+ _set_slot_val(page, slot, i);
memcpy(page->data + i, val, newvallen);
}
- if (op != IndexNull) page->op[slot] = op;
+ if (op != IndexNull) _set_slot_op(page, slot, o);
return 0;
}
/* no room on this page - free up existing entry and treat this as a new entry */
- if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
- memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ memcpy(&extval, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ page->mem_size -= (strlen(extval) + 1);
free(extval);
}
- page->key[slot] = ASL_MSG_SLOT_FREE;
- page->val[slot] = ASL_MSG_SLOT_FREE;
- page->op[slot] = 0;
+ _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_op(page, slot, 0);
return _asl_msg_new_key_val_op(msg, key, val, op);
}
uint32_t i, len;
int status;
+ if (msg == NULL) return -1;
+ if (key == NULL) return -1;
+
/* Special case handling */
special = NULL;
return asl_msg_set_key_val_op(msg, key, val, 0);
}
+static void
+_asl_msg_unset_page_slot(asl_msg_t *page, uint32_t slot)
+{
+ char *ext;
+ uint16_t k, v;
+
+ if (page == NULL) return;
+
+ if (slot >= _slot_count(page)) return;
+
+ k = _get_slot_key(page, slot);
+ v = _get_slot_val(page, slot);
+
+ if (k == ASL_MSG_SLOT_FREE) return;
+
+ if ((k & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ {
+ memcpy(&ext, page->data + (k & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ page->mem_size -= (strlen(ext) + 1);
+ free(ext);
+ }
+
+ if ((v & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ {
+ memcpy(&ext, page->data + (v & ASL_MSG_OFFSET_MASK), sizeof(char *));
+ page->mem_size -= (strlen(ext) + 1);
+ free(ext);
+ }
+
+ _set_slot_key(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_val(page, slot, ASL_MSG_SLOT_FREE);
+ _set_slot_op(page, slot, 0);
+
+ page->count--;
+}
+
/*
- * Merge a key / val into a message (only ASL_TYPE_MSG).
- * Adds the key / val if the key is not found.
- * Does not replace the value if the key is found.
+ * asl_msg_unset
+ * Frees external key and val strings, but does not try to reclaim data space.
*/
-static void
-_asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
+void
+asl_msg_unset(asl_msg_t *msg, const char *key)
{
uint32_t i, slot;
asl_msg_t *page;
page = NULL;
i = _asl_msg_index(msg, key, &slot, &page);
- if (i != IndexNull) return;
+ if (i == IndexNull) return;
- asl_msg_set_key_val_op(msg, key, val, op);
+ _asl_msg_unset_page_slot(page, slot);
+}
+
+void
+asl_msg_unset_index(asl_msg_t *msg, uint32_t n)
+{
+ uint32_t slot = IndexNull;
+ asl_msg_t *page = NULL;
+
+ if (msg == NULL) return;
+
+ if (0 != _asl_msg_resolve_index(msg, n, &page, &slot)) return;
+ _asl_msg_unset_page_slot(page, slot);
}
+#pragma mark -
+#pragma mark copy and merge
+
/*
- * Merge msg into target (does not replace existing keys).
- * Creates a new asl_msg_t if target is NULL.
- * Returns target.
+ * Merge a key / val into a message (only ASL_TYPE_MSG).
+ * Adds the key / val if the key is not found.
+ * Does not replace the value if the key is found.
*/
-asl_msg_t *
-asl_msg_merge(asl_msg_t *target, asl_msg_t *msg)
+static void
+_asl_msg_merge_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint16_t op)
{
- uint32_t x, slot, op, isnew = 0;
- const char *key, *val;
+ uint32_t i, slot;
asl_msg_t *page;
- if (msg == NULL) return target;
+ if (msg == NULL) return;
+ if (key == NULL) return;
- if (target == NULL)
- {
- isnew = 1;
- target = asl_msg_new(msg->type);
- }
+ slot = IndexNull;
+ page = NULL;
- for (x = _asl_msg_fetch_internal(msg, 0, &key, &val, &op, &page, &slot); x != IndexNull; x = _asl_msg_fetch_internal(msg, x, &key, &val, &op, &page, &slot))
- {
- if (msg->type == ASL_TYPE_MSG) op = 0;
- if (isnew == 1) asl_msg_set_key_val_op(target, key, val, op);
- else _asl_msg_merge_key_val_op(target, key, val, op);
- }
+ i = _asl_msg_index(msg, key, &slot, &page);
+ if (i != IndexNull) return;
- return target;
+ asl_msg_set_key_val_op(msg, key, val, op);
}
/*
- * Copy msg.
+ * Merge msg into target (does not replace existing keys).
+ * Creates a new asl_msg_t if target is NULL.
+ * Returns target.
*/
asl_msg_t *
-asl_msg_copy(asl_msg_t *msg)
-{
- return asl_msg_merge(NULL, msg);
-}
-
-/*
- * asl_msg_unset
- * Frees external key and val strings, but does not try to reclaim data space.
- */
-void
-asl_msg_unset(asl_msg_t *msg, const char *key)
+asl_msg_merge(asl_msg_t *target, asl_msg_t *msg)
{
- uint32_t i, slot;
- asl_msg_t *page;
- char *ext;
-
- if (msg == NULL) return;
- if (key == NULL) return;
+ uint32_t x, type, isnew = 0;
+ uint16_t op;
+ const char *key, *val;
- slot = IndexNull;
- page = NULL;
+ if (msg == NULL) return target;
- i = _asl_msg_index(msg, key, &slot, &page);
- if (i == IndexNull) return;
+ type = asl_get_type((asl_object_t)msg);
- if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ if (target == NULL)
{
- memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
- free(ext);
+ isnew = 1;
+ target = asl_msg_new(type);
}
- if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
+ for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op))
{
- memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
- free(ext);
+ if (type == ASL_TYPE_MSG) op = 0;
+ if (isnew == 1) asl_msg_set_key_val_op(target, key, val, op);
+ else _asl_msg_merge_key_val_op(target, key, val, op);
}
- page->key[slot] = ASL_MSG_SLOT_FREE;
- page->val[slot] = ASL_MSG_SLOT_FREE;
- page->op[slot] = 0;
-
- page->count--;
+ return target;
}
-int
-asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint32_t *opout)
+/*
+ * replace key/value pairs from msg in target
+ * Creates a new asl_msg_t if target is NULL.
+ * Returns target.
+ */
+static asl_msg_t *
+asl_msg_replace(asl_msg_t *target, asl_msg_t *msg)
{
- uint32_t i, slot;
- asl_msg_t *page;
+ uint32_t x, type;
+ uint16_t op;
+ const char *key, *val;
- if (valout != NULL) *valout = NULL;
- if (opout != NULL) *opout = 0;
+ if (msg == NULL) return target;
- slot = IndexNull;
- page = NULL;
+ type = asl_get_type((asl_object_t)msg);
- i = _asl_msg_index(msg, key, &slot, &page);
- if (i == IndexNull) return -1;
+ if (target == NULL) target = asl_msg_new(type);
- if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
- if (opout != NULL) *opout = page->op[slot];
+ for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x =asl_msg_fetch(msg, x, &key, &val, &op))
+ {
+ if (type == ASL_TYPE_MSG) op = 0;
+ asl_msg_set_key_val_op(target, key, val, op);
+ }
- return 0;
+ return target;
}
-uint32_t
-asl_msg_type(asl_msg_t *msg)
-{
- if (msg == NULL) return 0;
- return msg->type;
-}
-uint32_t
-asl_msg_count(asl_msg_t *msg)
+/*
+ * Copy msg.
+ */
+asl_msg_t *
+asl_msg_copy(asl_msg_t *msg)
{
- uint32_t total;
-
- total = 0;
-
- for (; msg != NULL; msg = msg->next) total += msg->count;
- return total;
+ return asl_msg_merge(NULL, msg);
}
+#pragma mark -
+#pragma mark compare and test
+
/*
* Compare messages
*/
static int
_asl_msg_equal(asl_msg_t *a, asl_msg_t *b)
{
- uint32_t x, oa, ob;
+ uint32_t x;
+ uint16_t oa, ob;
const char *key, *va, *vb;
if (asl_msg_count(a) != asl_msg_count(b)) return 0;
{
if (asl_msg_lookup(b, key, &vb, &ob) != 0) return 0;
if (strcmp(va, vb)) return 0;
- if ((a->type == ASL_TYPE_QUERY) && (oa != ob)) return 0;
+ if ((a->asl_type == ASL_TYPE_QUERY) && (oa != ob)) return 0;
}
return 1;
if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX)) return _asl_msg_test_expression(op, q, m);
if ((q == NULL) || (m == NULL)) return _asl_msg_test_expression(op, q, m);
- tq = asl_parse_time(q);
+ tq = asl_core_parse_time(q, NULL);
if (tq < 0) return _asl_msg_test_expression(op, q, m);
- tm = asl_parse_time(m);
+ tm = asl_core_parse_time(m, NULL);
if (tm < 0) return _asl_msg_test_expression(op, q, m);
t = op & ASL_QUERY_OP_TRUE;
}
/* test a query against a message */
-static int
+__private_extern__ int
_asl_msg_test(asl_msg_t *q, asl_msg_t *m)
{
- uint32_t i, t, x, op;
+ uint32_t i, t, x;
+ uint16_t op;
int cmp;
const char *kq, *vq, *vm;
return 1;
}
+/* returns 1 if a and b match, 0 otherwise */
int
asl_msg_cmp(asl_msg_t *a, asl_msg_t *b)
{
if (a == NULL) return 0;
if (b == NULL) return 0;
- if (a->type == b->type) return _asl_msg_equal(a, b);
- if (a->type == ASL_TYPE_QUERY) return _asl_msg_test(a, b);
+ if (a->asl_type == b->asl_type) return _asl_msg_equal(a, b);
+ if (a->asl_type == ASL_TYPE_QUERY) return _asl_msg_test(a, b);
return _asl_msg_test(b, a);
}
+/*
+ * Test a message against a query list.
+ * Returns 1 if msg matches any query in the list, 0 otherwise.
+ * Returns 1 if the query list is NULL or empty.
+ */
+int
+asl_msg_cmp_list(asl_msg_t *msg, asl_msg_list_t *list)
+{
+ uint32_t i;
+
+ if (msg == NULL) return 0;
+ if (list == NULL) return 1;
+ if (list->count == 0) return 1;
+
+ for (i = 0; i < list->count; i++)
+ {
+ if (_asl_msg_test(list->msg[i], msg)) return 1;
+ }
+
+ return 0;
+}
+
+#pragma mark -
+#pragma mark string representation
static char *
_asl_time_string(const char *infmt, const char *str, const char *nano)
}
tick = 0;
- if (str != NULL) tick = asl_parse_time(str);
+ if (str != NULL) tick = asl_core_parse_time(str, NULL);
if ((!strcasecmp(fmt, "lcl")) || (!strcasecmp(fmt, "local")))
{
off %= 3600;
zm = off / 60;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
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);
return out;
off %= 3600;
zm = off / 60;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
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);
return out;
if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
{
- asprintf(&out, "%lu%s", tick, nanobuf);
+ asprintf(&out, "%llu%s", (unsigned long long) tick, nanobuf);
return out;
}
{
char sep = ' ';
if (!strncasecmp(fmt, "iso8601", 7)) sep = 'T';
-
+
if (NULL == gmtime_r(&tick, &stm)) return NULL;
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);
return out;
off = (zh * 3600) + (zm * 60);
if (neg) off *= -1;
- if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02ld", neg ? '-' : '+', zh);
- else snprintf(zstr, sizeof(zstr), "%c%02ld:%02ld", neg ? '-' : '+', zh, zm);
+ if (zm == 0) snprintf(zstr, sizeof(zstr), "%c%02lld", neg ? '-' : '+', (long long) zh);
+ else snprintf(zstr, sizeof(zstr), "%c%02lld:%02lld", neg ? '-' : '+', (long long) zh, (long long) zm);
}
return out;
}
+
/* called from asl_format_message and _asl_send_message */
__private_extern__ asl_string_t *
asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt)
return str;
}
-static asl_string_t *
-_asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg)
+asl_string_t *
+asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg)
{
const char *key, *val;
- uint32_t i, op, n;
+ uint32_t i, x;
+ uint16_t op;
if (msg == NULL) return str;
- if (msg->type == ASL_TYPE_QUERY) asl_string_append(str, "Q ");
+ if (msg->asl_type == ASL_TYPE_QUERY) asl_string_append(str, "Q ");
i = 0;
- n = 0;
-
- forever
+ for (x = asl_msg_fetch(msg, 0, &key, &val, &op); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, &op))
{
- key = NULL;
- val = NULL;
-
- i = asl_msg_fetch(msg, i, &key, &val, &op);
- if (key != NULL)
- {
- if (n != 0) asl_string_append_char_no_encoding(str, ' ');
- n++;
-
- asl_string_append_char_no_encoding(str, '[');
+ if (i != 0) asl_string_append_char_no_encoding(str, ' ');
+ i++;
- if (msg->type == ASL_TYPE_QUERY)
- {
- asl_string_append_op(str, op);
- asl_string_append_char_no_encoding(str, ' ');
- }
+ asl_string_append_char_no_encoding(str, '[');
- asl_string_append_asl_key(str, key);
+ if (msg->asl_type == ASL_TYPE_QUERY)
+ {
+ asl_string_append_op(str, op);
+ asl_string_append_char_no_encoding(str, ' ');
+ }
- if (val != NULL)
- {
- asl_string_append_char_no_encoding(str, ' ');
- asl_string_append(str, val);
- }
+ asl_string_append_asl_key(str, key);
- asl_string_append_char_no_encoding(str, ']');
+ if (val != NULL)
+ {
+ asl_string_append_char_no_encoding(str, ' ');
+ asl_string_append(str, val);
}
- if (i == IndexNull) break;
+ asl_string_append_char_no_encoding(str, ']');
}
return str;
asl_string_t *str = asl_string_new(ASL_ENCODE_ASL);
if (str == NULL) return NULL;
- str = _asl_string_append_asl_msg(str, msg);
+ str = asl_string_append_asl_msg(str, msg);
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
out = asl_msg_new(ASL_TYPE_MSG);
if (out == NULL) return NULL;
- out->type = type;
+ out->asl_type = type;
/* OPEN WORD [WORD [WORD]] CLOSE */
while (k != NULL)
return out;
}
-char *
-asl_list_to_string(asl_search_result_t *list, uint32_t *len)
-{
- uint32_t i;
- char tmp[16];
- char *out;
- asl_string_t *str;
-
- if (list == NULL) return NULL;
- if (list->count == 0) return NULL;
- if (list->msg == NULL) return NULL;
-
- str = asl_string_new(ASL_ENCODE_ASL);
- if (str == NULL) return NULL;
-
- snprintf(tmp, sizeof(tmp), "%u", list->count);
- asl_string_append(str, tmp);
- asl_string_append_char_no_encoding(str, '\n');
-
- for (i = 0; i < list->count; i++)
- {
- _asl_string_append_asl_msg(str, list->msg[i]);
- asl_string_append_char_no_encoding(str, '\n');
- }
-
- *len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
- return out;
-}
-
-asl_search_result_t *
-asl_list_from_string(const char *buf)
-{
- uint32_t i, n;
- const char *p;
- asl_search_result_t *out;
- asl_msg_t *m;
-
- if (buf == NULL) return NULL;
- p = buf;
-
- n = atoi(buf);
- if (n == 0) return NULL;
-
- out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
- if (out == NULL) return NULL;
-
- out->msg = (asl_msg_t **)calloc(n, sizeof(asl_msg_t *));
- if (out->msg == NULL)
- {
- free(out);
- return NULL;
- }
-
- for (i = 0; i < n; i++)
- {
- p = strchr(p, '\n');
- if (p == NULL)
- {
- aslresponse_free((aslresponse)out);
- return NULL;
- }
-
- p++;
-
- m = asl_msg_from_string(p);
- if (m == NULL)
- {
- aslresponse_free((aslresponse)out);
- return NULL;
- }
-
- out->msg[i] = (asl_msg_t *)m;
- out->count += 1;
- }
-
- return out;
-}
-
static const char *
_asl_level_string(int level)
{
return "unknown";
}
+static const char *
+_asl_level_char(int level)
+{
+ if (level == ASL_LEVEL_EMERG) return "P";
+ if (level == ASL_LEVEL_ALERT) return "A";
+ if (level == ASL_LEVEL_CRIT) return "C";
+ if (level == ASL_LEVEL_ERR) return "E";
+ if (level == ASL_LEVEL_WARNING) return "W";
+ if (level == ASL_LEVEL_NOTICE) return "N";
+ if (level == ASL_LEVEL_INFO) return "I";
+ if (level == ASL_LEVEL_DEBUG) return "D";
+ return "?";
+}
+
/*
* Find the value for a key in a message and append a formatted value to str.
* kf may be a simple (no embedded white space) key, or one of (key) or ((key)(format)).
mval = _asl_level_string(atoi(mval));
asl_string_append_no_encoding(str, mval);
}
+ else if (!strcmp(fmt, "char"))
+ {
+ mval = _asl_level_char(atoi(mval));
+ asl_string_append_no_encoding(str, mval);
+ }
else
{
asl_string_append_no_encoding(str, mval);
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
- out = asl_string_free_return_bytes(str);
+ out = asl_string_release_return_bytes(str);
return out;
}
-/*
- * OLD ASLMSG COMPATIBILITY
- */
-const char *
-asl_key(aslmsg msg, uint32_t n)
+#pragma mark -
+#pragma mark xpc conversion
+
+static void
+_asl_msg_to_xpc(asl_msg_t *msg, xpc_object_t dict)
{
- uint32_t slot, i;
- asl_msg_t *page;
+ uint32_t x, len;
+ const char *key, *val, *nano;
+ uint16_t kx;
- i = 0;
- for (page = (asl_msg_t *)msg; page != NULL; page = page->next)
+ if (msg == NULL) return;
+ if (dict == NULL) return;
+
+ nano = NULL;
+ asl_msg_lookup(msg, ASL_KEY_TIME_NSEC, &nano, NULL);
+
+ for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
{
- for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++)
+ if (key == NULL) continue;
+
+ len = strlen(key);
+ kx = _asl_msg_std_key(key, len);
+
+ if (val == NULL)
+ {
+ xpc_object_t obj = xpc_null_create();
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == 0)
{
- if (page->key[slot] != ASL_MSG_SLOT_FREE)
+ if (streq(key, ASL_KEY_SENDER_MACH_UUID))
{
- if (i == n) return _asl_msg_slot_key(page, slot);
- i++;
+ uuid_t v;
+ if (uuid_parse(val, v) == 0)
+ {
+ xpc_object_t obj = xpc_uuid_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ }
+ else
+ {
+ xpc_object_t obj = xpc_string_create(val);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
}
}
+ else if (kx == ASL_STD_KEY_TIME)
+ {
+ uint64_t t = NSEC_PER_SEC * asl_core_parse_time(val, NULL);
+ if (nano != NULL) t += atoll(nano);
+ xpc_object_t obj = xpc_date_create(t);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_NANO)
+ {
+ /* handled with ASL_STD_KEY_TIME */
+ }
+ else if ((kx == ASL_STD_KEY_PID) || (kx == ASL_STD_KEY_REF_PID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if ((kx == ASL_STD_KEY_UID) || (kx == ASL_STD_KEY_GID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_LEVEL)
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if ((kx == ASL_STD_KEY_READ_UID) || (kx == ASL_STD_KEY_READ_GID))
+ {
+ int64_t v = atoll(val);
+ xpc_object_t obj = xpc_int64_create(v);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
+ else if (kx == ASL_STD_KEY_MSG_ID)
+ {
+ /* ignore */
+ }
+ else
+ {
+ xpc_object_t obj = xpc_string_create(val);
+ xpc_dictionary_set_value(dict, key, obj);
+ xpc_release(obj);
+ }
}
+}
- return NULL;
+void
+_asl_log_args_to_xpc(asl_object_t client, asl_object_t msg, xpc_object_t dict)
+{
+ _asl_msg_to_xpc(asl_client_kvdict((asl_client_t *)client), dict);
+ _asl_msg_to_xpc((asl_msg_t *)msg, dict);
}
-aslmsg
-asl_new(uint32_t type)
+#pragma mark -
+#pragma mark asl_object support
+
+static asl_object_private_t *
+_jump_alloc(uint32_t type)
{
- return (aslmsg)asl_msg_new(type);
+ return (asl_object_private_t *)asl_msg_new(type);
}
-int
-asl_set(aslmsg msg, const char *key, const char *value)
+static void
+_jump_dealloc(asl_object_private_t *obj)
+{
+ asl_msg_t *msg = (asl_msg_t *)obj;
+ while (msg != NULL)
+ {
+ asl_msg_t *next = msg->next;
+ _asl_msg_free_page(msg);
+ msg = next;
+ }
+}
+
+static int
+_jump_set_key_val_op(asl_object_private_t *obj, const char *key, const char *val, uint16_t op)
{
- return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, IndexNull);
+ uint32_t op32 = op;
+ int status = asl_msg_set_key_val_op((asl_msg_t *)obj, key, val, op32);
+ return (status == ASL_STATUS_OK) ? 0 : -1;
}
-int
-asl_set_query(aslmsg msg, const char *key, const char *value, uint32_t op)
+static void
+_jump_unset_key(asl_object_private_t *obj, const char *key)
{
- return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, op);
+ asl_msg_unset((asl_msg_t *)obj, key);
}
-int
-asl_unset(aslmsg msg, const char *key)
+static int
+_jump_get_val_op_for_key(asl_object_private_t *obj, const char *key, const char **val, uint16_t *op)
{
- asl_msg_unset((asl_msg_t *)msg, key);
- return 0;
+ return asl_msg_lookup((asl_msg_t *)obj, key, val, op);
}
-const char *
-asl_get(aslmsg msg, const char *key)
+static int
+_jump_get_key_val_op_at_index(asl_object_private_t *obj, size_t n, const char **key, const char **val, uint16_t *op)
{
- const char *val;
- int status;
+ uint32_t slot = IndexNull;
+ asl_msg_t *page = NULL;
- val = NULL;
- status = asl_msg_lookup((asl_msg_t *)msg, key, &val, NULL);
- if (status != 0) return NULL;
- return val;
+ if (0 != _asl_msg_resolve_index((asl_msg_t *)obj, n, &page, &slot)) return -1;
+
+ if (key != NULL) *key = _asl_msg_slot_key(page, slot);
+ if (val != NULL) *val = _asl_msg_slot_val(page, slot);
+ if (op != NULL) *op = _get_slot_op(page, slot);
+
+ return 0;
}
-void
-asl_free(aslmsg msg)
+static size_t
+_jump_count(asl_object_private_t *obj)
{
- asl_msg_release((asl_msg_t *)msg);
+ size_t count = asl_msg_count((asl_msg_t *)obj);
+ return count;
}
-/* aslresponse */
+static void
+_jump_append(asl_object_private_t *obj, asl_object_private_t *newobj, void *addr)
+{
+ int type = asl_get_type((asl_object_t)newobj);
+ if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return;
-/*
- * aslresponse_next: Iterate over responses returned from asl_search()
- * a: a response returned from asl_search();
- * returns: The next log message (an aslmsg) or NULL on failure
- */
-aslmsg
-aslresponse_next(aslresponse r)
+ asl_msg_merge((asl_msg_t *)obj, (asl_msg_t *)newobj);
+}
+
+static void
+_jump_prepend(asl_object_private_t *obj, asl_object_private_t *newobj)
+{
+ if (obj == NULL) return;
+
+ int type = asl_get_type((asl_object_t)newobj);
+ if ((type != ASL_TYPE_QUERY) && (type != ASL_TYPE_MSG)) return;
+
+ asl_msg_replace((asl_msg_t *)obj, (asl_msg_t *)newobj);
+}
+
+static asl_object_private_t *
+_jump_search(asl_object_private_t *obj, asl_object_private_t *query)
{
- asl_search_result_t *res;
- asl_msg_t *m;
+ if (obj == NULL) return NULL;
+
+ if (query == NULL)
+ {
+ /* NULL matches any message */
+ asl_msg_list_t *out = asl_msg_list_new();
+ asl_msg_list_append(out, obj);
+ return (asl_object_private_t *)out;
+ }
- res = (asl_search_result_t *)r;
- if (res == NULL) return NULL;
+ if ((query->asl_type != ASL_TYPE_MSG) && (query->asl_type != ASL_TYPE_QUERY)) return NULL;
- if (res->curr >= res->count) return NULL;
- m = res->msg[res->curr];
- res->curr++;
+ if (asl_msg_cmp((asl_msg_t *)obj, (asl_msg_t *)query) == 1)
+ {
+ asl_msg_list_t *out = asl_msg_list_new();
+ asl_msg_list_append(out, obj);
+ return (asl_object_private_t *)out;
+ }
- return (aslmsg)m;
+ return NULL;
}
-/*
- * aslresponse_free: Free a response returned from asl_search()
- * a: a response returned from asl_search()
- */
-void
-aslresponse_free(aslresponse r)
+static asl_object_private_t *
+_jump_match(asl_object_private_t *obj, asl_object_private_t *qlist, size_t *last, size_t start, size_t count, uint32_t duration, int32_t dir)
{
- asl_search_result_t *res;
- uint32_t i;
+ if (obj == NULL) return NULL;
+
+ if (qlist == NULL)
+ {
+ /* NULL matches any message */
+ asl_msg_list_t *out = asl_msg_list_new();
+ asl_msg_list_append(out, obj);
+ return (asl_object_private_t *)out;
+ }
- res = (asl_search_result_t *)r;
- if (res == NULL) return;
+ if (asl_msg_cmp_list((asl_msg_t *)obj, (asl_msg_list_t *)qlist) == 0) return NULL;
- for (i = 0; i < res->count; i++) asl_msg_release(res->msg[i]);
- free(res->msg);
- free(res);
+ asl_msg_list_t *out = asl_msg_list_new();
+ asl_msg_list_append(out, obj);
+ return (asl_object_private_t *)out;
+}
+
+
+__private_extern__ const asl_jump_table_t *
+asl_msg_jump_table()
+{
+ static const asl_jump_table_t jump =
+ {
+ .alloc = &_jump_alloc,
+ .dealloc = &_jump_dealloc,
+ .set_key_val_op = &_jump_set_key_val_op,
+ .unset_key = &_jump_unset_key,
+ .get_val_op_for_key = &_jump_get_val_op_for_key,
+ .get_key_val_op_at_index = &_jump_get_key_val_op_at_index,
+ .count = &_jump_count,
+ .next = NULL,
+ .prev = NULL,
+ .get_object_at_index = NULL,
+ .set_iteration_index = NULL,
+ .remove_object_at_index = NULL,
+ .append = &_jump_append,
+ .prepend = &_jump_prepend,
+ .search = &_jump_search,
+ .match = &_jump_match
+ };
+
+ return &jump;
}