[PATCH] MAP: pass user_data to the callback correctly
by Angus Salkeld
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qbmap.h | 4 +++-
lib/hashtable.c | 17 +++++++++--------
lib/map.c | 4 ++--
lib/map_int.h | 4 +++-
lib/skiplist.c | 13 +++++++------
lib/trie.c | 15 ++++++++-------
tests/check_map.c | 30 +++++++++++++++++++++++++-----
7 files changed, 57 insertions(+), 30 deletions(-)
diff --git a/include/qb/qbmap.h b/include/qb/qbmap.h
index 9ebd2c0..364c483 100644
--- a/include/qb/qbmap.h
+++ b/include/qb/qbmap.h
@@ -89,6 +89,7 @@ qb_map_t* qb_trie_create(void);
* @param key the key (or prefix) to attach the notification to.
* @param fn the callback
* @param events the type of events to register for.
+ * @param user_data a pointer to be passed into the callback
*
* @note QB_MAP_NOTIFY_INSERTED is only valid on tries.
* @note you can use key prefixes with trie maps.
@@ -97,7 +98,8 @@ qb_map_t* qb_trie_create(void);
* @retval -errno failure
*/
int32_t qb_map_notify_add(qb_map_t* m, const char* key,
- qb_map_notify_fn fn, int32_t events);
+ qb_map_notify_fn fn, int32_t events,
+ void *user_data);
/**
* Delete a notifier from the map.
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 3f83c37..835e318 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -56,7 +56,7 @@ struct hashtable_iter {
static void hashtable_notify(struct hash_table *t, struct hash_node *n,
uint32_t event, const char *key,
- void *old_value, void *value, void *user_data);
+ void *old_value, void *value);
static uint32_t
hash_fnv(const void *value, uint32_t valuelen, uint32_t order)
@@ -126,7 +126,7 @@ hashtable_node_deref(struct qb_map *map, struct hash_node *hash_node)
}
hashtable_notify(t, hash_node,
QB_MAP_NOTIFY_DELETED,
- hash_node->key, hash_node->value, NULL, NULL);
+ hash_node->key, hash_node->value, NULL);
qb_list_del(&hash_node->list);
free(hash_node);
}
@@ -204,7 +204,7 @@ hashtable_put(struct qb_map *map, const char *key, const void *value)
hashtable_notify(hash_table, hash_node,
QB_MAP_NOTIFY_INSERTED,
- hash_node->key, hash_node->value, NULL, NULL);
+ hash_node->key, hash_node->value, NULL);
} else {
char *old_k = (char *)hash_node->key;
char *old_v = (void *)hash_node->value;
@@ -213,14 +213,14 @@ hashtable_put(struct qb_map *map, const char *key, const void *value)
hashtable_notify(hash_table, hash_node,
QB_MAP_NOTIFY_REPLACED,
- old_k, old_v, hash_node->value, NULL);
+ old_k, old_v, hash_node->value);
}
}
static void
hashtable_notify(struct hash_table *t, struct hash_node *n,
uint32_t event, const char *key,
- void *old_value, void *value, void *user_data)
+ void *old_value, void *value)
{
struct qb_list_head *list;
struct qb_map_notifier *tn;
@@ -231,7 +231,7 @@ hashtable_notify(struct hash_table *t, struct hash_node *n,
if (tn->events & event) {
tn->callback(event, (char *)key, old_value, value,
- user_data);
+ tn->user_data);
}
}
for (list = t->notifier_head.next;
@@ -240,14 +240,14 @@ hashtable_notify(struct hash_table *t, struct hash_node *n,
if (tn->events & event) {
tn->callback(event, (char *)key, old_value, value,
- user_data);
+ tn->user_data);
}
}
}
static int32_t
hashtable_notify_add(qb_map_t * m, const char *key,
- qb_map_notify_fn fn, int32_t events)
+ qb_map_notify_fn fn, int32_t events, void *user_data)
{
struct hash_table *t = (struct hash_table *)m;
struct qb_map_notifier *f;
@@ -276,6 +276,7 @@ hashtable_notify_add(qb_map_t * m, const char *key,
f = malloc(sizeof(struct qb_map_notifier));
f->events = events;
+ f->user_data = user_data;
f->callback = fn;
qb_list_init(&f->list);
qb_list_add(&f->list, head);
diff --git a/lib/map.c b/lib/map.c
index 5e92906..43f665e 100644
--- a/lib/map.c
+++ b/lib/map.c
@@ -90,10 +90,10 @@ qb_map_iter_free(qb_map_iter_t * i)
int32_t
qb_map_notify_add(qb_map_t * m, const char *key, qb_map_notify_fn fn,
- int32_t events)
+ int32_t events, void *user_data)
{
if (m->notify_add) {
- return m->notify_add(m, key, fn, events);
+ return m->notify_add(m, key, fn, events, user_data);
} else {
return -ENOSYS;
}
diff --git a/lib/map_int.h b/lib/map_int.h
index 5e670e2..2b262e8 100644
--- a/lib/map_int.h
+++ b/lib/map_int.h
@@ -37,7 +37,8 @@ typedef const char* (*qb_map_iter_next_func)(qb_map_iter_t* i, void** value);
typedef void (*qb_map_iter_free_func)(qb_map_iter_t* i);
typedef int32_t (*qb_map_notify_add_func)(qb_map_t* m, const char* key,
- qb_map_notify_fn fn, int32_t events);
+ qb_map_notify_fn fn, int32_t events,
+ void *user_data);
typedef int32_t (*qb_map_notify_del_func)(qb_map_t* m, const char* key,
qb_map_notify_fn fn, int32_t events);
@@ -62,6 +63,7 @@ struct qb_map_notifier {
struct qb_list_head list;
qb_map_notify_fn callback;
int32_t events;
+ void *user_data;
};
diff --git a/lib/skiplist.c b/lib/skiplist.c
index bf1c567..60e962d 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -185,7 +185,7 @@ skiplist_lookup(struct skiplist *list, const char *key)
static void
skiplist_notify(struct skiplist *l, struct skiplist_node *n,
uint32_t event,
- char *key, void *old_value, void *value, void *user_data)
+ char *key, void *old_value, void *value)
{
struct qb_list_head *list;
struct qb_map_notifier *tn;
@@ -197,7 +197,7 @@ skiplist_notify(struct skiplist *l, struct skiplist_node *n,
tn = qb_list_entry(list, struct qb_map_notifier, list);
if (tn->events & event) {
- tn->callback(event, key, old_value, value, user_data);
+ tn->callback(event, key, old_value, value, tn->user_data);
}
}
/* global callbacks
@@ -207,7 +207,7 @@ skiplist_notify(struct skiplist *l, struct skiplist_node *n,
tn = qb_list_entry(list, struct qb_map_notifier, list);
if (tn->events & event) {
- tn->callback(event, key, old_value, value, user_data);
+ tn->callback(event, key, old_value, value, tn->user_data);
}
}
@@ -218,7 +218,7 @@ skiplist_node_destroy(struct skiplist_node *node, struct skiplist *list)
{
skiplist_notify(list, node,
QB_MAP_NOTIFY_DELETED,
- (char *)node->key, node->value, NULL, NULL);
+ (char *)node->key, node->value, NULL);
free(node->forward);
free(node);
@@ -235,7 +235,7 @@ skiplist_node_deref(struct skiplist_node *node, struct skiplist *list)
static int32_t
skiplist_notify_add(qb_map_t * m, const char *key,
- qb_map_notify_fn fn, int32_t events)
+ qb_map_notify_fn fn, int32_t events, void *user_data)
{
struct skiplist *t = (struct skiplist *)m;
struct qb_map_notifier *f;
@@ -249,6 +249,7 @@ skiplist_notify_add(qb_map_t * m, const char *key,
if (n) {
f = malloc(sizeof(struct qb_map_notifier));
f->events = events;
+ f->user_data = user_data;
f->callback = fn;
qb_list_init(&f->list);
qb_list_add(&f->list, &n->notifier_head);
@@ -308,7 +309,7 @@ skiplist_put(struct qb_map *map, const char *key, const void *value)
fwd_node->key = (void *)key;
skiplist_notify(list, fwd_node,
QB_MAP_NOTIFY_REPLACED,
- old_k, old_v, fwd_node->value, NULL);
+ old_k, old_v, fwd_node->value);
return;
case OP_GOTO_NEXT_NODE:
diff --git a/lib/trie.c b/lib/trie.c
index 888f3bc..19521ce 100644
--- a/lib/trie.c
+++ b/lib/trie.c
@@ -52,7 +52,7 @@ struct trie {
};
static void trie_notify(struct trie_node *n, uint32_t event, const char *key,
- void *old_value, void *value, void *user_data);
+ void *old_value, void *value);
/*
* characters are stored in reverse to make accessing the
@@ -122,7 +122,7 @@ keep_going:
static void
trie_node_destroy(struct trie *t, struct trie_node *n)
{
- trie_notify(n, QB_MAP_NOTIFY_DELETED, n->key, n->value, NULL, NULL);
+ trie_notify(n, QB_MAP_NOTIFY_DELETED, n->key, n->value, NULL);
n->key = NULL;
n->value = NULL;
@@ -233,11 +233,11 @@ trie_put(struct qb_map *map, const char *key, const void *value)
n->refcount++;
t->length++;
trie_notify(n, QB_MAP_NOTIFY_INSERTED,
- n->key, NULL, n->value, NULL);
+ n->key, NULL, n->value);
} else {
trie_notify(n, QB_MAP_NOTIFY_REPLACED,
(char *)old_key, (void *)old_value,
- (void *)value, NULL);
+ (void *)value);
}
}
}
@@ -271,7 +271,7 @@ trie_get(struct qb_map *map, const char *key)
static void
trie_notify(struct trie_node *n,
uint32_t event,
- const char *key, void *old_value, void *value, void *user_data)
+ const char *key, void *old_value, void *value)
{
struct trie_node *c = n;
struct qb_list_head *list;
@@ -286,7 +286,7 @@ trie_notify(struct trie_node *n,
((tn->events & QB_MAP_NOTIFY_RECURSIVE) ||
(n == c))) {
tn->callback(event, (char *)key, old_value,
- value, user_data);
+ value, tn->user_data);
}
}
c = c->parent;
@@ -295,7 +295,7 @@ trie_notify(struct trie_node *n,
static int32_t
trie_notify_add(qb_map_t * m, const char *key,
- qb_map_notify_fn fn, int32_t events)
+ qb_map_notify_fn fn, int32_t events, void *user_data)
{
struct trie *t = (struct trie *)m;
struct qb_map_notifier *f;
@@ -309,6 +309,7 @@ trie_notify_add(qb_map_t * m, const char *key,
if (n) {
f = malloc(sizeof(struct qb_map_notifier));
f->events = events;
+ f->user_data = user_data;
f->callback = fn;
qb_list_init(&f->list);
if (events & QB_MAP_NOTIFY_RECURSIVE) {
diff --git a/tests/check_map.c b/tests/check_map.c
index d3ea622..95a7a12 100644
--- a/tests/check_map.c
+++ b/tests/check_map.c
@@ -42,6 +42,7 @@ const char *chars2[] = {
static char *notified_key = NULL;
static void *notified_value = NULL;
static void *notified_new_value = NULL;
+static void *notified_user_data = NULL;
static void
test_map_simple(qb_map_t *m, const char *name)
@@ -188,6 +189,7 @@ my_map_notification(uint32_t event,
notified_key = key;
notified_value = old_value;
notified_new_value = value;
+ notified_user_data = user_data;
}
static void
@@ -201,7 +203,8 @@ test_map_remove(qb_map_t *m)
i = qb_map_notify_add(m, NULL, my_map_notification,
(QB_MAP_NOTIFY_DELETED|
QB_MAP_NOTIFY_REPLACED|
- QB_MAP_NOTIFY_RECURSIVE));
+ QB_MAP_NOTIFY_RECURSIVE),
+ m);
ck_assert_int_eq(i, 0);
for (i = 0; chars[i]; i++) {
@@ -212,21 +215,26 @@ test_map_remove(qb_map_t *m)
qb_map_put(m, a, a);
ck_assert(notified_key == chars[0]);
ck_assert(notified_value == chars[0]);
+ ck_assert(notified_user_data == m);
notified_key = NULL;
notified_value = NULL;
+ notified_user_data = NULL;
b = "5";
removed = qb_map_rm(m, b);
ck_assert(removed);
ck_assert(notified_key == chars[5]);
ck_assert(notified_value == chars[5]);
+ ck_assert(notified_user_data == m);
notified_key = NULL;
notified_value = NULL;
+ notified_user_data = NULL;
d = "1";
qb_map_put(m, d, d);
ck_assert(notified_key == chars[1]);
ck_assert(notified_value == chars[1]);
+ ck_assert(notified_user_data == m);
notified_key = NULL;
notified_value = NULL;
@@ -257,24 +265,28 @@ test_map_notifications(qb_map_t *m)
(QB_MAP_NOTIFY_INSERTED|
QB_MAP_NOTIFY_DELETED|
QB_MAP_NOTIFY_REPLACED|
- QB_MAP_NOTIFY_RECURSIVE));
+ QB_MAP_NOTIFY_RECURSIVE),
+ m);
ck_assert_int_eq(i, 0);
/* insert */
qb_map_put(m, "garden", "grow");
ck_assert_str_eq(notified_key, "garden");
ck_assert_str_eq(notified_new_value, "grow");
+ ck_assert(notified_user_data == m);
/* update */
qb_map_put(m, "garden", "green");
ck_assert_str_eq(notified_key, "garden");
ck_assert_str_eq(notified_value, "grow");
ck_assert_str_eq(notified_new_value, "green");
+ ck_assert(notified_user_data == m);
/* delete */
qb_map_rm(m, "garden");
ck_assert_str_eq(notified_key, "garden");
ck_assert_str_eq(notified_value, "green");
+ ck_assert(notified_user_data == m);
/* no event with notifier removed */
i = qb_map_notify_del(m, NULL, my_map_notification,
@@ -292,19 +304,20 @@ test_map_notifications(qb_map_t *m)
ck_assert(notified_new_value == NULL);
-/* with prefic notifier */
-
+/* with prefix notifier */
i = qb_map_notify_add(m, "add", my_map_notification,
(QB_MAP_NOTIFY_INSERTED|
QB_MAP_NOTIFY_DELETED|
QB_MAP_NOTIFY_REPLACED|
- QB_MAP_NOTIFY_RECURSIVE));
+ QB_MAP_NOTIFY_RECURSIVE),
+ &i);
ck_assert_int_eq(i, 0);
/* insert */
qb_map_put(m, "adder", "snake");
ck_assert_str_eq(notified_key, "adder");
ck_assert_str_eq(notified_new_value, "snake");
+ ck_assert(notified_user_data == &i);
/* insert (no match) */
notified_key = NULL;
@@ -326,6 +339,13 @@ test_map_notifications(qb_map_t *m)
ck_assert_str_eq(notified_key, "adder");
ck_assert_str_eq(notified_value, "+++");
+/* deleting a non-existing notification */
+ i = qb_map_notify_del(m, "a", my_map_notification,
+ (QB_MAP_NOTIFY_INSERTED|
+ QB_MAP_NOTIFY_DELETED|
+ QB_MAP_NOTIFY_REPLACED|
+ QB_MAP_NOTIFY_RECURSIVE));
+ ck_assert_int_eq(i, -ENOENT);
}
static void
--
1.7.6
12 years, 7 months
[PATCH 1/2] MAP: add prefix iteration for the trie
by Angus Salkeld
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qbmap.h | 9 ++++++++
lib/hashtable.c | 2 +-
lib/map.c | 8 ++++++-
lib/map_int.h | 10 ++++++--
lib/skiplist.c | 2 +-
lib/trie.c | 37 ++++++++++++++++++++++++---------
tests/check_map.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 109 insertions(+), 16 deletions(-)
diff --git a/include/qb/qbmap.h b/include/qb/qbmap.h
index a99ba2a..51e2212 100644
--- a/include/qb/qbmap.h
+++ b/include/qb/qbmap.h
@@ -126,6 +126,15 @@ void qb_map_foreach(qb_map_t *map, qb_transverse_func func, void* user_data);
qb_map_iter_t* qb_map_iter_create(qb_map_t *map);
/**
+ * Create a prefix iterator.
+ *
+ * This will iterate over all items with the given
+ * prefix.
+ * @note this is only supported by the trie.
+ */
+qb_map_iter_t* qb_map_pref_iter_create(qb_map_t *map, const char* prefix);
+
+/**
* Get the next item
*
* @param i the iterator
diff --git a/lib/hashtable.c b/lib/hashtable.c
index b17e02f..d45badf 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -181,7 +181,7 @@ hashtable_count_get(struct qb_map *map)
}
static qb_map_iter_t*
-hashtable_iter_create(struct qb_map * map)
+hashtable_iter_create(struct qb_map * map, const char* prefix)
{
struct hashtable_iter *i = malloc(sizeof(struct hashtable_iter));
i->i.m = map;
diff --git a/lib/map.c b/lib/map.c
index 2d356b4..a3b9466 100644
--- a/lib/map.c
+++ b/lib/map.c
@@ -68,7 +68,13 @@ clean_up:
qb_map_iter_t*
qb_map_iter_create(struct qb_map *map)
{
- return map->iter_create(map);
+ return map->iter_create(map, NULL);
+}
+
+qb_map_iter_t*
+qb_map_pref_iter_create(qb_map_t *map, const char* prefix)
+{
+ return map->iter_create(map, prefix);
}
const char*
diff --git a/lib/map_int.h b/lib/map_int.h
index 46bb67c..f9cdd16 100644
--- a/lib/map_int.h
+++ b/lib/map_int.h
@@ -23,13 +23,17 @@
struct qb_map;
-typedef void (*qb_map_put_func)(struct qb_map *map, const char* key, const void* value);
+typedef void (*qb_map_put_func)(struct qb_map *map, const char* key,
+ const void* value);
typedef void* (*qb_map_get_func)(struct qb_map *map, const char* key);
typedef int32_t (*qb_map_rm_func)(struct qb_map *map, const char* key);
typedef size_t (*qb_map_count_get_func)(struct qb_map *map);
-typedef void (*qb_map_foreach_func)(struct qb_map *map, qb_transverse_func func, void* user_data);
+typedef void (*qb_map_foreach_func)(struct qb_map *map,
+ qb_transverse_func func,
+ void* user_data);
typedef void (*qb_map_destroy_func)(struct qb_map *map);
-typedef qb_map_iter_t* (*qb_map_iter_create_func)(struct qb_map *map);
+typedef qb_map_iter_t* (*qb_map_iter_create_func)(struct qb_map *map,
+ const char* prefix);
typedef const char* (*qb_map_iter_next_func)(qb_map_iter_t* i, void** value);
typedef void (*qb_map_iter_free_func)(qb_map_iter_t* i);
diff --git a/lib/skiplist.c b/lib/skiplist.c
index 42c0e7f..b11d211 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -338,7 +338,7 @@ skiplist_get(struct qb_map *map, const char *key)
}
static qb_map_iter_t*
-skiplist_iter_create(struct qb_map * map)
+skiplist_iter_create(struct qb_map * map, const char* prefix)
{
struct skiplist_iter *i = malloc(sizeof(struct skiplist_iter));
struct skiplist *list = (struct skiplist *)map;
diff --git a/lib/trie.c b/lib/trie.c
index 2000953..fd50e94 100644
--- a/lib/trie.c
+++ b/lib/trie.c
@@ -27,8 +27,9 @@
struct trie_iter {
struct qb_map_iter i;
- const char *key;
+ const char *prefix;
struct trie_node *n;
+ struct trie_node *root;
};
struct trie_node {
@@ -57,7 +58,7 @@ static int32_t trie_rm(struct qb_map *list, const char *key);
#define TRIE_CHAR2INDEX(ch) (126 - ch)
static struct trie_node *
-trie_node_next(struct trie_node *node)
+trie_node_next(struct trie_node *node, struct trie_node *root)
{
struct trie_node *c = node;
struct trie_node *n;
@@ -83,7 +84,7 @@ keep_going:
}
}
// sibling/parent
- if (c->parent == NULL) {
+ if (c == root) {
return NULL;
}
p = c;
@@ -97,13 +98,13 @@ keep_going:
if (n == NULL) {
p = p->parent;
}
- } while (n == NULL && p->parent);
+ } while (n == NULL && p != root);
if (n) {
if (n->value) {
return n;
}
- if (n->parent == NULL) {
+ if (n == root) {
return NULL;
}
c = n;
@@ -260,12 +261,14 @@ trie_get(struct qb_map *map, const char *key)
}
static qb_map_iter_t*
-trie_iter_create(struct qb_map * map)
+trie_iter_create(struct qb_map * map, const char* prefix)
{
struct trie_iter *i = malloc(sizeof(struct trie_iter));
- struct trie *list = (struct trie *)map;
+ struct trie *t = (struct trie *)map;
i->i.m = map;
- i->n = list->header;
+ i->prefix = prefix;
+ i->n = t->header;
+ i->root = t->header;
i->n->refcount++;
return (qb_map_iter_t*)i;
}
@@ -275,16 +278,30 @@ trie_iter_next(qb_map_iter_t* i, void** value)
{
struct trie_iter *si = (struct trie_iter*)i;
struct trie_node *p = si->n;
+ struct trie *t = (struct trie *)(i->m);
if (p == NULL) {
return NULL;
}
- si->n = trie_node_next(p);
- trie_node_deref((struct trie *)i->m, p);
+
+ if (p->parent == NULL && si->prefix) {
+ si->root = trie_lookup(t, si->prefix, QB_FALSE);
+ if (si->root == NULL) {
+ si->n = NULL;
+ } else if (si->root->value == NULL) {
+ si->n = trie_node_next(si->root, si->root);
+ } else {
+ si->n = si->root;
+ }
+ } else {
+ si->n = trie_node_next(p, si->root);
+ }
if (si->n == NULL) {
+ trie_node_deref((struct trie *)i->m, p);
return NULL;
}
si->n->refcount++;
+ trie_node_deref((struct trie *)i->m, p);
*value = si->n->value;
return si->n->key;
}
diff --git a/tests/check_map.c b/tests/check_map.c
index e2022c3..2665622 100644
--- a/tests/check_map.c
+++ b/tests/check_map.c
@@ -325,6 +325,61 @@ test_map_iter_safety(qb_map_t *m, int32_t ordered)
qb_map_destroy(m);
}
+static void
+test_map_iter_prefix(qb_map_t *m)
+{
+ void *data;
+ const char *p;
+ qb_map_iter_t *it;
+ int count;
+
+ qb_map_put(m, "aaaa", "aye");
+ qb_map_put(m, "facc", "nope");
+ qb_map_put(m, "abbb", "bee");
+ qb_map_put(m, "a.ac", "nope");
+ qb_map_put(m, "aacc", "yip");
+ qb_map_put(m, "cacc", "nope");
+ qb_map_put(m, "c", "----");
+
+ count = 0;
+ it = qb_map_pref_iter_create(m, "aa");
+ while ((p = qb_map_iter_next(it, &data)) != NULL) {
+ printf("1: %s == %s\n", p, (char*)data);
+ count++;
+ }
+ qb_map_iter_free(it);
+ ck_assert_int_eq(count, 2);
+
+ count = 0;
+ it = qb_map_pref_iter_create(m, "a");
+ while ((p = qb_map_iter_next(it, &data)) != NULL) {
+ printf("2: %s == %s\n", p, (char*)data);
+ count++;
+ }
+ qb_map_iter_free(it);
+ ck_assert_int_eq(count, 4);
+
+ count = 0;
+ it = qb_map_pref_iter_create(m, "zz");
+ while ((p = qb_map_iter_next(it, &data)) != NULL) {
+ printf("??: %s == %s\n", p, (char*)data);
+ count++;
+ }
+ qb_map_iter_free(it);
+ ck_assert_int_eq(count, 0);
+
+ count = 0;
+ it = qb_map_pref_iter_create(m, "c");
+ while ((p = qb_map_iter_next(it, &data)) != NULL) {
+ printf("3: %s == %s\n", p, (char*)data);
+ count++;
+ }
+ qb_map_iter_free(it);
+ ck_assert_int_eq(count, 2);
+
+ qb_map_destroy(m);
+}
+
static void
test_map_traverse_unordered(qb_map_t *m)
@@ -525,6 +580,8 @@ START_TEST(test_trie_traverse)
test_map_traverse_unordered(m);
m = qb_trie_create(NULL, NULL);
test_map_iter_safety(m, QB_FALSE);
+ m = qb_trie_create(NULL, NULL);
+ test_map_iter_prefix(m);
}
END_TEST
--
1.7.6
12 years, 7 months
[PATCH 1/5] TESTS: improve the map tests
by Angus Salkeld
- add a iterator to test_map_simple()
- improve the test output
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
tests/check_map.c | 50 ++++++++++++++++++++++++++++++++++++--------------
1 files changed, 36 insertions(+), 14 deletions(-)
diff --git a/tests/check_map.c b/tests/check_map.c
index 9e6c51e..e2022c3 100644
--- a/tests/check_map.c
+++ b/tests/check_map.c
@@ -43,18 +43,34 @@ static void *destroyed_key = NULL;
static void *destroyed_value = NULL;
static void
-test_map_simple(qb_map_t *m)
+test_map_simple(qb_map_t *m, const char *name)
{
+ int i;
+ char *p;
+ void *data;
+ qb_map_iter_t *it;
+
qb_map_put(m, "k1", "one");
qb_map_put(m, "k2", "two");
qb_map_put(m, "k3", "three");
ck_assert_int_eq(qb_map_count_get(m), 3);
qb_map_put(m, "k4", "four");
-
ck_assert_int_eq(qb_map_count_get(m), 4);
+ it = qb_map_iter_create(m);
+ i = 0;
+ for (p = qb_map_iter_next(it, &data);
+ p;
+ p = qb_map_iter_next(it, &data)) {
+ printf("%25s(%d) %s > %s\n", name, i, p, (char*)data);
+ i++;
+ }
+ qb_map_iter_free(it);
+ ck_assert_int_eq(i, 4);
+
ck_assert_str_eq(qb_map_get(m, "k3"), "three");
ck_assert_str_eq(qb_map_get(m, "k1"), "one");
+ ck_assert_str_eq(qb_map_get(m, "k2"), "two");
ck_assert_str_eq(qb_map_get(m, "k4"), "four");
qb_map_rm(m, "k2");
@@ -340,6 +356,7 @@ test_map_load(qb_map_t *m, const char* test_name)
int32_t count;
int32_t count2;
float ops;
+ float secs;
void *value;
qb_util_stopwatch_t *sw;
@@ -362,8 +379,9 @@ test_map_load(qb_map_t *m, const char* test_name)
ck_assert_int_eq(qb_map_count_get(m), count);
fclose(fp);
- ops = count / qb_util_stopwatch_sec_elapsed_get(sw);
- qb_log(LOG_INFO, "%s %9.3f puts/sec\n", test_name, ops);
+ secs = qb_util_stopwatch_sec_elapsed_get(sw);
+ ops = (float)count / secs;
+ qb_log(LOG_INFO, "%25s %12.2f puts/sec (%d/%fs)\n", test_name, ops, count, secs);
/*
* Verify dictionary produces correct values
@@ -380,8 +398,9 @@ test_map_load(qb_map_t *m, const char* test_name)
qb_util_stopwatch_stop(sw);
fclose(fp);
- ops = count / qb_util_stopwatch_sec_elapsed_get(sw);
- qb_log(LOG_INFO, "%s %9.3f gets/sec\n", test_name, ops);
+ secs = qb_util_stopwatch_sec_elapsed_get(sw);
+ ops = (float)count2 / secs;
+ qb_log(LOG_INFO, "%25s %12.2f gets/sec (%d/%fs)\n", test_name, ops, count2, secs);
/*
* time the iteration
@@ -390,8 +409,10 @@ test_map_load(qb_map_t *m, const char* test_name)
qb_util_stopwatch_start(sw);
qb_map_foreach(m, my_counter_traverse, &count2);
qb_util_stopwatch_stop(sw);
- ops = count2 / qb_util_stopwatch_sec_elapsed_get(sw);
- qb_log(LOG_INFO, "%s %9.3f iterations/sec\n", test_name, ops);
+ ck_assert_int_eq(qb_map_count_get(m), count2);
+ secs = qb_util_stopwatch_sec_elapsed_get(sw);
+ ops = (float)count2 / secs;
+ qb_log(LOG_INFO, "%25s %12.2f iters/sec (%d/%fs)\n", test_name, ops, count2, secs);
/*
* Delete all dictionary entries
@@ -405,32 +426,33 @@ test_map_load(qb_map_t *m, const char* test_name)
ck_assert_int_eq(res, QB_TRUE);
count2++;
}
- ck_assert_int_eq(qb_map_count_get(m), 0);
qb_util_stopwatch_stop(sw);
+ ck_assert_int_eq(qb_map_count_get(m), 0);
fclose(fp);
- ops = count / qb_util_stopwatch_sec_elapsed_get(sw);
- qb_log(LOG_INFO, "%s %9.3f deletes/sec\n", test_name, ops);
+ secs = qb_util_stopwatch_sec_elapsed_get(sw);
+ ops = (float)count2 / secs;
+ qb_log(LOG_INFO, "%25s %12.2f dels/sec (%d/%fs)\n", test_name, ops, count2, secs);
}
START_TEST(test_skiplist_simple)
{
qb_map_t *m = qb_skiplist_create(NULL, NULL);
- test_map_simple(m);
+ test_map_simple(m, __func__);
}
END_TEST
START_TEST(test_hashtable_simple)
{
qb_map_t *m = qb_hashtable_create(NULL, NULL, 32);
- test_map_simple(m);
+ test_map_simple(m, __func__);
}
END_TEST
START_TEST(test_trie_simple)
{
qb_map_t *m = qb_trie_create(NULL, NULL);
- test_map_simple(m);
+ test_map_simple(m, __func__);
}
END_TEST
--
1.7.6
12 years, 7 months
[PATCH] MAP: add a trie implementation
by Angus Salkeld
http://en.wikipedia.org/wiki/Trie
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qbmap.h | 8 ++
lib/Makefile.am | 2 +-
lib/trie.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/check_map.c | 64 +++++++++++
4 files changed, 394 insertions(+), 1 deletions(-)
create mode 100644 lib/trie.c
diff --git a/include/qb/qbmap.h b/include/qb/qbmap.h
index b430d8b..ce02e0e 100644
--- a/include/qb/qbmap.h
+++ b/include/qb/qbmap.h
@@ -69,6 +69,14 @@ qb_map_t* qb_skiplist_create(qb_destroy_notifier_func key_destroy_func,
qb_destroy_notifier_func value_destroy_func);
/**
+ *
+ */
+qb_map_t*
+qb_trie_create(qb_destroy_notifier_func key_destroy_func,
+ qb_destroy_notifier_func value_destroy_func);
+
+
+/**
* Inserts a new key and value into a qb_map_t.
*
* If the key already exists in the qb_map_t, it gets replaced by the new key.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 519db69..8541062 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -43,7 +43,7 @@ source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c array.c \
ipcc.c ipcs.c ipc_posix_mq.c ipc_sysv_mq.c ipc_shm.c ipc_us.c \
log.c log_thread.c log_blackbox.c log_file.c \
log_syslog.c log_dcs.c log_format.c \
- map.c skiplist.c hashtable.c
+ map.c skiplist.c hashtable.c trie.c
libqb_la_SOURCES = $(source_to_lint)
if USE_TIMERFD
diff --git a/lib/trie.c b/lib/trie.c
new file mode 100644
index 0000000..f388c5e
--- /dev/null
+++ b/lib/trie.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * Author: Angus Salkeld <asalkeld(a)redhat.com>
+ *
+ * This file is part of libqb.
+ *
+ * libqb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * libqb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libqb. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <os_base.h>
+#include <assert.h>
+
+#include <qb/qbdefs.h>
+#include <qb/qbmap.h>
+#include "map_int.h"
+
+struct trie_iter {
+ struct qb_map_iter i;
+ const char *key;
+ struct trie_node *n;
+};
+
+struct trie_node {
+ char key_ch;
+ char *key;
+ void *value;
+ struct trie_node **children;
+ uint32_t num_children;
+ int32_t refcount;
+ struct trie_node *parent;
+};
+
+struct trie {
+ struct qb_map map;
+
+ size_t length;
+ struct trie_node *header;
+};
+
+static int32_t trie_rm(struct qb_map *list, const char *key);
+
+static struct trie_node *
+trie_node_next(struct trie_node *node)
+{
+ struct trie_node *c = node;
+ struct trie_node *n;
+ struct trie_node *p;
+ int i;
+
+keep_going:
+ n = NULL;
+
+ // child/outward
+ for (i = 0; i < c->num_children; i++) {
+ if (c->children[i]) {
+ n = c->children[i];
+ break;
+ }
+ }
+ if (n) {
+ if (n->value) {
+ return n;
+ } else {
+ c = n;
+ goto keep_going;
+ }
+ }
+ // sibling/parent
+ if (c->parent == NULL) {
+ return NULL;
+ }
+ p = c;
+ do {
+ for (i = (p->key_ch + 1); i < p->parent->num_children; i++) {
+ if (p->parent->children[i]) {
+ n = p->parent->children[i];
+ break;
+ }
+ }
+ if (n == NULL) {
+ p = p->parent;
+ }
+ } while (n == NULL && p->parent);
+
+ if (n) {
+ if (n->value) {
+ return n;
+ }
+ if (n->parent == NULL) {
+ return NULL;
+ }
+ c = n;
+ goto keep_going;
+ }
+
+ return n;
+}
+
+static void
+trie_node_destroy(struct trie *t, struct trie_node *node)
+{
+ if (t->map.value_destroy_func && node != t->header) {
+ t->map.value_destroy_func(node->value);
+ }
+
+ if (t->map.key_destroy_func && node != t->header) {
+ t->map.key_destroy_func((void*)node->key);
+ }
+ node->key = NULL;
+ node->value = NULL;
+}
+
+static void
+trie_node_deref(struct trie *t, struct trie_node *node)
+{
+ node->refcount--;
+ if (node->refcount == 0) {
+ trie_node_destroy(t, node);
+ }
+}
+
+static void
+trie_destroy(struct qb_map *map)
+{
+ struct trie *list = (struct trie *)map;
+#if 0
+ struct trie_node *cur_node = list->header;
+ struct trie_node *fwd_node;
+
+ do {
+ fwd_node = trie_node_next(cur_node);
+ trie_node_destroy(cur_node, list);
+ } while ((cur_node = fwd_node));
+#endif
+ free(list);
+}
+
+static struct trie_node*
+trie_new_node(struct trie * t, struct trie_node* parent)
+{
+ struct trie_node* new_node = calloc(1, sizeof(struct trie_node));
+
+ new_node->parent = parent;
+
+ return new_node;
+}
+
+static struct trie_node*
+trie_lookup(struct trie * t, const char *key, int32_t create_path)
+{
+ struct trie_node* cur_node = t->header;
+ struct trie_node* new_node;
+ int old_max_idx;
+ int i;
+ char *cur = (char*)key;
+ int idx = key[0];
+
+ do {
+ if (idx >= cur_node->num_children) {
+ if (!create_path) {
+ return NULL;
+ }
+ if (cur_node->num_children == 0) {
+ old_max_idx = 0;
+ } else {
+ old_max_idx = cur_node->num_children;
+ }
+ cur_node->num_children = idx + 1;
+ cur_node->children = realloc(cur_node->children,
+ (cur_node->num_children *
+ sizeof(struct trie_node*)));
+ //printf("%s(%d) %d %d\n", __func__, idx, old_max_idx, cur_node->num_children);
+ for (i = old_max_idx; i < cur_node->num_children; i++) {
+ cur_node->children[i] = NULL;
+ }
+ }
+ if (cur_node->children[idx] == NULL) {
+ if (!create_path) {
+ return NULL;
+ }
+ new_node = trie_new_node(t, cur_node);
+ new_node->key_ch = *cur;
+ cur_node->children[idx] = new_node;
+ }
+ cur_node = cur_node->children[idx];
+ cur++;
+ idx = *cur;
+ } while (*cur != '\0');
+
+ return cur_node;
+}
+
+static void
+trie_put(struct qb_map * map, const char *key, const void *value)
+{
+ struct trie *t = (struct trie *)map;
+ struct trie_node *n = trie_lookup(t, key, QB_TRUE);
+ if (n) {
+ if (n->value == NULL) {
+ t->length++;
+ } else {
+ if (t->map.value_destroy_func && n != t->header) {
+ t->map.value_destroy_func(n->value);
+ }
+
+ if (t->map.key_destroy_func && n != t->header) {
+ t->map.key_destroy_func((void*)n->key);
+ }
+ }
+ n->key = (char*)key;
+ n->value = (void*)value;
+ n->refcount++;
+ }
+}
+
+static int32_t
+trie_rm(struct qb_map *map, const char *key)
+{
+ struct trie *t = (struct trie *)map;
+ struct trie_node *n = trie_lookup(t, key, QB_FALSE);
+ if (n) {
+ trie_node_deref(t, n);
+ t->length--;
+ return QB_TRUE;
+ } else {
+ return QB_FALSE;
+ }
+}
+
+static void *
+trie_get(struct qb_map *map, const char *key)
+{
+ struct trie *t = (struct trie *)map;
+ struct trie_node *n = trie_lookup(t, key, QB_FALSE);
+ if (n) {
+ return n->value;
+ }
+
+ return NULL;
+}
+
+static qb_map_iter_t*
+trie_iter_create(struct qb_map * map)
+{
+ struct trie_iter *i = malloc(sizeof(struct trie_iter));
+ struct trie *list = (struct trie *)map;
+ i->i.m = map;
+ i->n = list->header;
+ i->n->refcount++;
+ return (qb_map_iter_t*)i;
+}
+
+static const char*
+trie_iter_next(qb_map_iter_t* i, void** value)
+{
+ struct trie_iter *si = (struct trie_iter*)i;
+ struct trie_node *p = si->n;
+
+ if (p == NULL) {
+ return NULL;
+ }
+ si->n = trie_node_next(p);
+ trie_node_deref((struct trie *)i->m, p);
+ if (si->n == NULL) {
+ return NULL;
+ }
+ si->n->refcount++;
+ *value = si->n->value;
+ return si->n->key;
+}
+
+static void
+trie_iter_free(qb_map_iter_t* i)
+{
+ free(i);
+}
+
+static size_t
+trie_count_get(struct qb_map * map)
+{
+ struct trie *list = (struct trie *)map;
+ return list->length;
+}
+
+qb_map_t *
+qb_trie_create(qb_destroy_notifier_func key_destroy_func,
+ qb_destroy_notifier_func value_destroy_func)
+{
+ struct trie *sl = calloc(1, sizeof(struct trie));
+
+ srand(time(NULL));
+
+ sl->map.key_destroy_func = key_destroy_func;
+ sl->map.value_destroy_func = value_destroy_func;
+
+ sl->map.put = trie_put;
+ sl->map.get = trie_get;
+ sl->map.rm = trie_rm;
+ sl->map.count_get = trie_count_get;
+ sl->map.iter_create = trie_iter_create;
+ sl->map.iter_next = trie_iter_next;
+ sl->map.iter_free = trie_iter_free;
+ sl->map.destroy = trie_destroy;
+
+ sl->length = 0;
+ sl->header = trie_new_node(sl, NULL);
+
+ return (qb_map_t *) sl;
+}
+
diff --git a/tests/check_map.c b/tests/check_map.c
index b66497d..9e6c51e 100644
--- a/tests/check_map.c
+++ b/tests/check_map.c
@@ -427,6 +427,13 @@ START_TEST(test_hashtable_simple)
}
END_TEST
+START_TEST(test_trie_simple)
+{
+ qb_map_t *m = qb_trie_create(NULL, NULL);
+ test_map_simple(m);
+}
+END_TEST
+
START_TEST(test_skiplist_search)
{
qb_map_t *m = qb_skiplist_create(NULL, NULL);
@@ -434,6 +441,13 @@ START_TEST(test_skiplist_search)
}
END_TEST
+START_TEST(test_trie_search)
+{
+ qb_map_t *m = qb_trie_create(NULL, NULL);
+ test_map_search(m);
+}
+END_TEST
+
START_TEST(test_skiplist_remove)
{
qb_map_t *m = qb_skiplist_create(my_key_destroy,
@@ -450,6 +464,14 @@ START_TEST(test_hashtable_remove)
}
END_TEST
+START_TEST(test_trie_remove)
+{
+ qb_map_t *m = qb_trie_create(my_key_destroy,
+ my_value_destroy);
+ test_map_remove(m);
+}
+END_TEST
+
START_TEST(test_skiplist_traverse)
{
qb_map_t *m;
@@ -474,6 +496,16 @@ START_TEST(test_hashtable_traverse)
}
END_TEST
+START_TEST(test_trie_traverse)
+{
+ qb_map_t *m;
+ m = qb_trie_create(NULL, NULL);
+ test_map_traverse_unordered(m);
+ m = qb_trie_create(NULL, NULL);
+ test_map_iter_safety(m, QB_FALSE);
+}
+END_TEST
+
START_TEST(test_skiplist_load)
{
qb_map_t *m;
@@ -498,6 +530,18 @@ START_TEST(test_hashtable_load)
}
END_TEST
+START_TEST(test_trie_load)
+{
+ qb_map_t *m;
+ if (access("/usr/share/dict/words", R_OK) != 0) {
+ printf("no dict/words - not testing\n");
+ return;
+ }
+ m = qb_trie_create(NULL, NULL);
+ test_map_load(m, __func__);
+}
+END_TEST
+
static Suite *
map_suite(void)
{
@@ -512,6 +556,10 @@ map_suite(void)
tcase_add_test(tc, test_hashtable_simple);
suite_add_tcase(s, tc);
+ tc = tcase_create("trie_simple");
+ tcase_add_test(tc, test_trie_simple);
+ suite_add_tcase(s, tc);
+
tc = tcase_create("skiplist_remove");
tcase_add_test(tc, test_skiplist_remove);
suite_add_tcase(s, tc);
@@ -520,6 +568,10 @@ map_suite(void)
tcase_add_test(tc, test_hashtable_remove);
suite_add_tcase(s, tc);
+ tc = tcase_create("trie_remove");
+ tcase_add_test(tc, test_trie_remove);
+ suite_add_tcase(s, tc);
+
tc = tcase_create("skiplist_search");
tcase_add_test(tc, test_skiplist_search);
suite_add_tcase(s, tc);
@@ -528,6 +580,9 @@ map_suite(void)
* No hashtable_search as it assumes an ordered
* collection
*/
+ tc = tcase_create("trie_search");
+ tcase_add_test(tc, test_trie_search);
+ suite_add_tcase(s, tc);
tc = tcase_create("skiplist_traverse");
tcase_add_test(tc, test_skiplist_traverse);
@@ -537,6 +592,10 @@ map_suite(void)
tcase_add_test(tc, test_hashtable_traverse);
suite_add_tcase(s, tc);
+ tc = tcase_create("trie_traverse");
+ tcase_add_test(tc, test_trie_traverse);
+ suite_add_tcase(s, tc);
+
tc = tcase_create("skiplist_load");
tcase_add_test(tc, test_skiplist_load);
tcase_set_timeout(tc, 30);
@@ -547,6 +606,11 @@ map_suite(void)
tcase_set_timeout(tc, 30);
suite_add_tcase(s, tc);
+ tc = tcase_create("trie_load");
+ tcase_add_test(tc, test_trie_load);
+ tcase_set_timeout(tc, 30);
+ suite_add_tcase(s, tc);
+
return s;
}
--
1.7.6
12 years, 7 months
[PATCH] LOG: allow large priorities
by Angus Salkeld
They will be printed as trace, it's mainly to make
filtering more flexible
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
lib/log.c | 1 -
tests/check_log.c | 3 ---
tests/simple-log.c | 3 ++-
3 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/lib/log.c b/lib/log.c
index dfaea9b..13996b4 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -552,7 +552,6 @@ qb_log_filter_ctl2(int32_t t, enum qb_log_filter_conf c,
return -EBADF;
}
if (text == NULL ||
- low_priority > LOG_TRACE ||
low_priority < high_priority ||
type > QB_LOG_FILTER_FORMAT ||
c > QB_LOG_TAG_CLEAR_ALL) {
diff --git a/tests/check_log.c b/tests/check_log.c
index c7bd678..b9efd03 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -121,9 +121,6 @@ START_TEST(test_log_stupid_inputs)
/* crap values to filter_ctl() */
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
- QB_LOG_FILTER_FILE, "bla", 45);
- ck_assert_int_eq(rc, -EINVAL);
- rc = qb_log_filter_ctl(QB_LOG_SYSLOG, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, NULL, LOG_INFO);
ck_assert_int_eq(rc, -EINVAL);
rc = qb_log_filter_ctl(QB_LOG_SYSLOG, 56,
diff --git a/tests/simple-log.c b/tests/simple-log.c
index 37a5475..ef57503 100644
--- a/tests/simple-log.c
+++ b/tests/simple-log.c
@@ -36,6 +36,7 @@ static void func_one(void)
qb_enter();
qb_logt(LOG_DEBUG, MY_TAG_TWO, "arf arf?");
qb_logt(LOG_CRIT, MY_TAG_THREE, "arrrg!");
+ qb_logt(134, MY_TAG_THREE, "big priority");
qb_logt(LOG_ERR, MY_TAG_THREE, "oops, I did it again");
qb_log(LOG_INFO, "are you aware ...");
@@ -176,7 +177,7 @@ int32_t main(int32_t argc, char *argv[])
qb_log_format_set(tracer, "%4g: %n() %b");
qb_log_filter_ctl2(tracer, QB_LOG_FILTER_ADD,
QB_LOG_FILTER_FILE, __FILE__,
- LOG_TRACE, LOG_TRACE);
+ LOG_TRACE, 200);
}
if (do_blackbox) {
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
--
1.7.6
12 years, 7 months
[PATCH] LOG: add qb_log_filter_ctl2() so we can filter a range of priorities
by Angus Salkeld
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qblog.h | 10 ++++++-
lib/log.c | 81 ++++++++++++++++++++++++++++++++++++----------------
lib/log_int.h | 3 +-
tests/simple-log.c | 25 +++++++++++++++-
4 files changed, 90 insertions(+), 29 deletions(-)
diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index 098e8f1..5231daf 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -451,7 +451,15 @@ int32_t qb_log_ctl(int32_t target, enum qb_log_conf conf_type, int32_t arg);
*/
int32_t qb_log_filter_ctl(int32_t value, enum qb_log_filter_conf c,
enum qb_log_filter_type type, const char * text,
- uint8_t priority);
+ uint8_t low_priority);
+
+
+/**
+ * This extends qb_log_filter_ctl() by been able to provide a high_priority.
+ */
+int32_t qb_log_filter_ctl2(int32_t value, enum qb_log_filter_conf c,
+ enum qb_log_filter_type type, const char * text,
+ uint8_t high_priority, uint8_t low_priority);
/**
* Set the callback to map the 'tags' bit map to a string.
diff --git a/lib/log.c b/lib/log.c
index 6129614..dfaea9b 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -55,11 +55,13 @@ static void _log_target_disable(struct qb_log_target *t);
static void _log_filter_apply(struct callsite_section *sect,
uint32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
- const char *text, uint8_t priority);
+ const char *text,
+ uint8_t high_priority, uint8_t low_priority);
static void _log_filter_apply_to_cs(struct qb_log_callsite *cs,
uint32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
- const char *text, uint8_t priority);
+ const char *text,
+ uint8_t high_priority, uint8_t low_priority);
/* deprecated method of getting internal log messages */
static qb_util_log_fn_t old_internal_log_fn = NULL;
@@ -72,11 +74,14 @@ qb_util_set_log_function(qb_util_log_fn_t fn)
static int32_t
_cs_matches_filter_(struct qb_log_callsite *cs,
enum qb_log_filter_type type,
- const char *text, uint8_t priority)
+ const char *text,
+ uint8_t high_priority,
+ uint8_t low_priority)
{
int32_t match = QB_FALSE;
- if (cs->priority > priority) {
+ if (cs->priority > low_priority ||
+ cs->priority < high_priority) {
return QB_FALSE;
}
if (strcmp(text, "*") == 0) {
@@ -253,14 +258,16 @@ void qb_log_from_external_source_va(const char *function,
for (f_item = t->filter_head.next; f_item != &t->filter_head; f_item = f_item->next) {
flt = qb_list_entry(f_item, struct qb_log_filter, list);
_log_filter_apply_to_cs(cs, t->pos, flt->conf, flt->type,
- flt->text, flt->priority);
+ flt->text, flt->high_priority,
+ flt->low_priority);
}
}
if (tags == 0) {
for (f_item = tags_head.next; f_item != &tags_head; f_item = f_item->next) {
flt = qb_list_entry(f_item, struct qb_log_filter, list);
_log_filter_apply_to_cs(cs, flt->new_value, flt->conf, flt->type,
- flt->text, flt->priority);
+ flt->text, flt->high_priority,
+ flt->low_priority);
}
} else {
cs->tags = tags;
@@ -328,12 +335,14 @@ qb_log_callsites_register(struct qb_log_callsite *_start,
}
qb_list_for_each_entry(flt, &t->filter_head, list) {
_log_filter_apply(sect, t->pos, flt->conf,
- flt->type, flt->text, flt->priority);
+ flt->type, flt->text,
+ flt->high_priority, flt->low_priority);
}
}
qb_list_for_each_entry(flt, &tags_head, list) {
_log_filter_apply(sect, flt->new_value, flt->conf,
- flt->type, flt->text, flt->priority);
+ flt->type, flt->text,
+ flt->high_priority, flt->low_priority);
}
pthread_rwlock_unlock(&_listlock);
@@ -368,13 +377,17 @@ qb_log_callsites_dump(void)
static int32_t
_log_filter_exists(struct qb_list_head *list_head,
enum qb_log_filter_type type,
- const char *text, uint8_t priority, uint32_t new_value)
+ const char *text,
+ uint8_t high_priority,
+ uint8_t low_priority,
+ uint32_t new_value)
{
struct qb_log_filter *flt;
qb_list_for_each_entry(flt, list_head, list) {
if (flt->type == type &&
- flt->priority == priority &&
+ flt->high_priority == high_priority &&
+ flt->low_priority == low_priority &&
flt->new_value == new_value &&
strcmp(flt->text, text) == 0) {
return QB_TRUE;
@@ -386,7 +399,9 @@ _log_filter_exists(struct qb_list_head *list_head,
static int32_t
_log_filter_store(uint32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
- const char *text, uint8_t priority)
+ const char *text,
+ uint8_t high_priority,
+ uint8_t low_priority)
{
struct qb_log_filter *flt;
struct qb_list_head *iter;
@@ -413,7 +428,8 @@ _log_filter_store(uint32_t t, enum qb_log_filter_conf c,
if (text == NULL) {
return -EINVAL;
}
- if (_log_filter_exists(list_head, type, text, priority, t)) {
+ if (_log_filter_exists(list_head, type, text,
+ high_priority, low_priority, t)) {
return -EEXIST;
}
flt = calloc(1, sizeof(struct qb_log_filter));
@@ -428,14 +444,16 @@ _log_filter_store(uint32_t t, enum qb_log_filter_conf c,
free(flt);
return -ENOMEM;
}
- flt->priority = priority;
+ flt->high_priority = high_priority;
+ flt->low_priority = low_priority;
flt->new_value = t;
qb_list_add_tail(&flt->list, list_head);
} else if (c == QB_LOG_FILTER_REMOVE || c == QB_LOG_TAG_CLEAR) {
qb_list_for_each_safe(iter, next, list_head) {
flt = qb_list_entry(iter, struct qb_log_filter, list);
if (flt->type == type &&
- flt->priority <= priority &&
+ flt->low_priority == low_priority &&
+ flt->high_priority == high_priority &&
strcmp(flt->text, text) == 0) {
qb_list_del(iter);
free(flt->text);
@@ -459,7 +477,8 @@ static void
_log_filter_apply(struct callsite_section *sect,
uint32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
- const char *text, uint8_t priority)
+ const char *text,
+ uint8_t high_priority, uint8_t low_priority)
{
struct qb_log_callsite *cs;
@@ -467,7 +486,8 @@ _log_filter_apply(struct callsite_section *sect,
if (cs->lineno == 0) {
break;
}
- _log_filter_apply_to_cs(cs, t, c, type, text, priority);
+ _log_filter_apply_to_cs(cs, t, c, type, text,
+ high_priority, low_priority);
}
}
@@ -476,7 +496,8 @@ static void
_log_filter_apply_to_cs(struct qb_log_callsite *cs,
uint32_t t, enum qb_log_filter_conf c,
enum qb_log_filter_type type,
- const char *text, uint8_t priority)
+ const char *text,
+ uint8_t high_priority, uint8_t low_priority)
{
if (c == QB_LOG_FILTER_CLEAR_ALL) {
@@ -487,7 +508,7 @@ _log_filter_apply_to_cs(struct qb_log_callsite *cs,
return;
}
- if (_cs_matches_filter_(cs, type, text, priority)) {
+ if (_cs_matches_filter_(cs, type, text, high_priority, low_priority)) {
#ifdef _QB_FILTER_DEBUGGING_
uint32_t old_targets = cs->targets;
uint32_t old_tags = cs->tags;
@@ -516,9 +537,9 @@ _log_filter_apply_to_cs(struct qb_log_callsite *cs,
}
int32_t
-qb_log_filter_ctl(int32_t t, enum qb_log_filter_conf c,
- enum qb_log_filter_type type,
- const char *text, uint8_t priority)
+qb_log_filter_ctl2(int32_t t, enum qb_log_filter_conf c,
+ enum qb_log_filter_type type, const char * text,
+ uint8_t high_priority, uint8_t low_priority)
{
struct callsite_section *sect;
int32_t rc;
@@ -531,24 +552,34 @@ qb_log_filter_ctl(int32_t t, enum qb_log_filter_conf c,
return -EBADF;
}
if (text == NULL ||
- priority > LOG_TRACE ||
- type > QB_LOG_FILTER_FORMAT || c > QB_LOG_TAG_CLEAR_ALL) {
+ low_priority > LOG_TRACE ||
+ low_priority < high_priority ||
+ type > QB_LOG_FILTER_FORMAT ||
+ c > QB_LOG_TAG_CLEAR_ALL) {
return -EINVAL;
}
pthread_rwlock_rdlock(&_listlock);
- rc = _log_filter_store(t, c, type, text, priority);
+ rc = _log_filter_store(t, c, type, text, high_priority, low_priority);
if (rc < 0) {
pthread_rwlock_unlock(&_listlock);
return rc;
}
qb_list_for_each_entry(sect, &callsite_sections, list) {
- _log_filter_apply(sect, t, c, type, text, priority);
+ _log_filter_apply(sect, t, c, type, text, high_priority, low_priority);
}
pthread_rwlock_unlock(&_listlock);
return 0;
}
+int32_t
+qb_log_filter_ctl(int32_t t, enum qb_log_filter_conf c,
+ enum qb_log_filter_type type,
+ const char *text, uint8_t priority)
+{
+ return qb_log_filter_ctl2(t, c, type, text, LOG_EMERG, priority);
+}
+
#ifdef QB_HAVE_ATTRIBUTE_SECTION
static int32_t
_log_so_walk_callback(struct dl_phdr_info *info, size_t size, void *data)
diff --git a/lib/log_int.h b/lib/log_int.h
index 25bc52c..1e311db 100644
--- a/lib/log_int.h
+++ b/lib/log_int.h
@@ -50,7 +50,8 @@ struct qb_log_filter {
enum qb_log_filter_conf conf;
enum qb_log_filter_type type;
char *text;
- uint8_t priority;
+ uint8_t high_priority;
+ uint8_t low_priority;
uint32_t new_value;
struct qb_list_head list;
};
diff --git a/tests/simple-log.c b/tests/simple-log.c
index 617c658..37a5475 100644
--- a/tests/simple-log.c
+++ b/tests/simple-log.c
@@ -102,10 +102,22 @@ static const char *my_tags_stringify(uint32_t tags)
}
}
+static void
+trace_logger(int32_t t,
+ struct qb_log_callsite *cs,
+ time_t timestamp,
+ const char *msg)
+{
+ char output_buffer[QB_LOG_MAX_LEN];
+ qb_log_target_format(t, cs, timestamp, msg, output_buffer);
+ fprintf(stderr, "%s\n", output_buffer);
+}
+
int32_t main(int32_t argc, char *argv[])
{
const char *options = "vhtebdf:";
int32_t opt;
+ int32_t tracer;
int32_t priority = LOG_WARNING;
int32_t do_stderr = QB_FALSE;
int32_t do_dump_blackbox = QB_FALSE;
@@ -151,11 +163,20 @@ int32_t main(int32_t argc, char *argv[])
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_THREADED, do_threaded);
qb_log_tags_stringify_fn_set(my_tags_stringify);
+ tracer = qb_log_custom_open(trace_logger, NULL, NULL, NULL);
+
if (do_stderr) {
- qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
- QB_LOG_FILTER_FILE, __FILE__, priority);
+ qb_log_filter_ctl2(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
+ QB_LOG_FILTER_FILE, __FILE__,
+ LOG_ALERT, QB_MIN(LOG_DEBUG, priority));
qb_log_format_set(QB_LOG_STDERR, "%4g: %f:%l [%p] %b");
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
+
+ qb_log_ctl(tracer, QB_LOG_CONF_ENABLED, QB_TRUE);
+ qb_log_format_set(tracer, "%4g: %n() %b");
+ qb_log_filter_ctl2(tracer, QB_LOG_FILTER_ADD,
+ QB_LOG_FILTER_FILE, __FILE__,
+ LOG_TRACE, LOG_TRACE);
}
if (do_blackbox) {
qb_log_filter_ctl(QB_LOG_BLACKBOX, QB_LOG_FILTER_ADD,
--
1.7.6
12 years, 7 months
[PATCH] LOG: fix QB_LOG_INIT_DATA
by Angus Salkeld
this is weird, but now it actually works
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qblog.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index 2736aa3..098e8f1 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -241,7 +241,7 @@ extern struct qb_log_callsite __stop___verbose[];
#define QB_LOG_INIT_DATA(name) \
void name(void); \
- void name(void) { assert(__start___verbose != __stop___verbose); } \
+ void name(void) { if (__start___verbose != __stop___verbose) {assert(1);} } \
void __attribute__ ((constructor)) name(void);
#else
#define QB_LOG_INIT_DATA(name)
--
1.7.6
12 years, 7 months
[PATCH] LOG: add a way of getting the target state
by Angus Salkeld
This is so we can do the following:
for (t = 0; t < QB_LOG_TARGET_MAX; t++) {
if (qb_log_ctl(t, QB_LOG_CONF_STATE_GET, 0) == QB_LOG_STATE_ENABLED) {
// bla bla
}
}
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qblog.h | 17 ++++++++++++++---
lib/log.c | 26 +++++++++++++++++---------
lib/log_int.h | 8 +-------
tests/check_log.c | 10 ++++++++++
4 files changed, 42 insertions(+), 19 deletions(-)
diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index 8d7276c..2736aa3 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -349,6 +349,14 @@ void qb_log_from_external_source_va(const char *function,
#define QB_LOG_STDERR 1
#define QB_LOG_BLACKBOX 2
+#define QB_LOG_TARGET_MAX 32
+
+enum qb_log_target_state {
+ QB_LOG_STATE_UNUSED = 1,
+ QB_LOG_STATE_DISABLED = 2,
+ QB_LOG_STATE_ENABLED = 3,
+};
+
enum qb_log_conf {
QB_LOG_CONF_ENABLED,
QB_LOG_CONF_FACILITY,
@@ -356,6 +364,7 @@ enum qb_log_conf {
QB_LOG_CONF_SIZE,
QB_LOG_CONF_THREADED,
QB_LOG_CONF_PRIORITY_BUMP,
+ QB_LOG_CONF_STATE_GET,
};
enum qb_log_filter_type {
@@ -426,14 +435,16 @@ void qb_log_callsites_dump(void);
/**
* Main logging control function.
*
- * @param t QB_LOG_SYSLOG, QB_LOG_STDERR or result from qb_log_file_open()
- * @param c what to configure
+ * @param target QB_LOG_SYSLOG, QB_LOG_STDERR or result from qb_log_file_open()
+ * @param conf_type what to configure
* @param arg the new value
* @see qb_log_conf
+ *
* @retval -errno on error
* @retval 0 on success
+ * @retval qb_log_target_state for QB_LOG_CONF_STATE_GET
*/
-int32_t qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg);
+int32_t qb_log_ctl(int32_t target, enum qb_log_conf conf_type, int32_t arg);
/**
* This allows you modify the 'tags' and 'targets' callsite fields at runtime.
diff --git a/lib/log.c b/lib/log.c
index 998ad6e..6129614 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -34,7 +34,7 @@
#include "log_int.h"
#include "util_int.h"
-static struct qb_log_target conf[32];
+static struct qb_log_target conf[QB_LOG_TARGET_MAX];
static uint32_t conf_used_max = 0;
static uint32_t conf_active_max = 0;
static int32_t in_logger = QB_FALSE;
@@ -526,7 +526,8 @@ qb_log_filter_ctl(int32_t t, enum qb_log_filter_conf c,
if (!logger_inited) {
return -EINVAL;
}
- if (t < 0 || t >= 32 || conf[t].state == QB_LOG_STATE_UNUSED) {
+ if (t < 0 || t >= QB_LOG_TARGET_MAX ||
+ conf[t].state == QB_LOG_STATE_UNUSED) {
return -EBADF;
}
if (text == NULL ||
@@ -590,7 +591,7 @@ done:
#endif /* QB_HAVE_ATTRIBUTE_SECTION */
static void
-_log_target_state_set(struct qb_log_target *t, enum qb_log_state s)
+_log_target_state_set(struct qb_log_target *t, enum qb_log_target_state s)
{
int32_t i;
int32_t a_set = QB_FALSE;
@@ -618,7 +619,7 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
i = pthread_rwlock_init(&_listlock, NULL);
assert(i == 0);
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < QB_LOG_TARGET_MAX; i++) {
conf[i].pos = i;
conf[i].debug = QB_FALSE;
conf[i].state = QB_LOG_STATE_UNUSED;
@@ -697,7 +698,7 @@ struct qb_log_target *
qb_log_target_alloc(void)
{
int32_t i;
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < QB_LOG_TARGET_MAX; i++) {
if (conf[i].state == QB_LOG_STATE_UNUSED) {
_log_target_state_set(&conf[i], QB_LOG_STATE_DISABLED);
return &conf[i];
@@ -730,7 +731,8 @@ qb_log_target_user_data_get(int32_t t)
errno = -EINVAL;
return NULL;
}
- if (t < 0 || t >= 32 || conf[t].state == QB_LOG_STATE_UNUSED) {
+ if (t < 0 || t >= QB_LOG_TARGET_MAX ||
+ conf[t].state == QB_LOG_STATE_UNUSED) {
errno = -EBADF;
return NULL;
}
@@ -744,7 +746,8 @@ qb_log_target_user_data_set(int32_t t, void *user_data)
if (!logger_inited) {
return -EINVAL;
}
- if (t < 0 || t >= 32 || conf[t].state == QB_LOG_STATE_UNUSED) {
+ if (t < 0 || t >= QB_LOG_TARGET_MAX ||
+ conf[t].state == QB_LOG_STATE_UNUSED) {
return -EBADF;
}
@@ -783,7 +786,8 @@ qb_log_custom_close(int32_t t)
if (!logger_inited) {
return;
}
- if (t < 0 || t >= 32 || conf[t].state == QB_LOG_STATE_UNUSED) {
+ if (t < 0 || t >= QB_LOG_TARGET_MAX ||
+ conf[t].state == QB_LOG_STATE_UNUSED) {
return;
}
@@ -839,7 +843,8 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
if (!logger_inited) {
return -EINVAL;
}
- if (t < 0 || t >= 32 || conf[t].state == QB_LOG_STATE_UNUSED) {
+ if (t < 0 || t >= QB_LOG_TARGET_MAX ||
+ conf[t].state == QB_LOG_STATE_UNUSED) {
return -EBADF;
}
switch (c) {
@@ -850,6 +855,9 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
_log_target_disable(&conf[t]);
}
break;
+ case QB_LOG_CONF_STATE_GET:
+ rc = conf[t].state;
+ break;
case QB_LOG_CONF_FACILITY:
conf[t].facility = arg;
if (t == QB_LOG_SYSLOG) {
diff --git a/lib/log_int.h b/lib/log_int.h
index f8cb033..25bc52c 100644
--- a/lib/log_int.h
+++ b/lib/log_int.h
@@ -25,17 +25,11 @@
#include <qb/qblog.h>
#include <qb/qbrb.h>
-enum qb_log_state {
- QB_LOG_STATE_UNUSED,
- QB_LOG_STATE_DISABLED,
- QB_LOG_STATE_ENABLED,
-};
-
struct qb_log_target;
struct qb_log_target {
uint32_t pos;
- enum qb_log_state state;
+ enum qb_log_target_state state;
char name[PATH_MAX];
struct qb_list_head filter_head;
int32_t facility;
diff --git a/tests/check_log.c b/tests/check_log.c
index 153f254..c7bd678 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -311,9 +311,19 @@ END_TEST
START_TEST(test_log_enable)
{
int32_t t;
+ int32_t state;
qb_log_init("test", LOG_USER, LOG_DEBUG);
+ state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
+ ck_assert_int_eq(state, QB_LOG_STATE_ENABLED);
+ state = qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_STATE_GET, 0);
+ ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
+ state = qb_log_ctl(QB_LOG_BLACKBOX, QB_LOG_CONF_STATE_GET, 0);
+ ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
+
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
+ state = qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_STATE_GET, 0);
+ ck_assert_int_eq(state, QB_LOG_STATE_DISABLED);
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
--
1.7.6
12 years, 7 months
[PATCH] LOG: support comma seperated lists of file and function filters
by Angus Salkeld
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
lib/log.c | 29 +++++++++++++++++++++--------
tests/check_log.c | 21 +++++++++++++++++++++
2 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/lib/log.c b/lib/log.c
index 2997eac..998ad6e 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -82,14 +82,27 @@ _cs_matches_filter_(struct qb_log_callsite *cs,
if (strcmp(text, "*") == 0) {
return QB_TRUE;
}
- if (type == QB_LOG_FILTER_FILE) {
- if (strstr(cs->filename, text)) {
- match = QB_TRUE;
- }
- } else if (type == QB_LOG_FILTER_FUNCTION) {
- if (strstr(cs->function, text)) {
- match = QB_TRUE;
- }
+ if (type == QB_LOG_FILTER_FILE ||
+ type == QB_LOG_FILTER_FUNCTION) {
+ char token[500];
+ const char *offset = NULL;
+ const char *next = text;
+
+ do {
+ offset = next;
+ next = strchrnul(offset, ',');
+ snprintf(token, 499, "%.*s", (int)(next - offset), offset);
+
+ if (type == QB_LOG_FILTER_FILE) {
+ match = (strstr(cs->filename, token) != NULL);
+ } else {
+ match = (strstr(cs->function, token) != NULL);
+ }
+ if (!match && next[0] != 0) {
+ next++;
+ }
+
+ } while (match == QB_FALSE && next != NULL && next[0] != 0);
} else if (type == QB_LOG_FILTER_FORMAT) {
if (strstr(cs->format, text)) {
match = QB_TRUE;
diff --git a/tests/check_log.c b/tests/check_log.c
index c17b787..153f254 100644
--- a/tests/check_log.c
+++ b/tests/check_log.c
@@ -158,6 +158,16 @@ _test_logger(int32_t t,
num_msgs++;
}
+static void log_also(void)
+{
+ qb_log(LOG_INFO, "yes please");
+}
+
+static void log_and_this_too(void)
+{
+ qb_log(LOG_INFO, "this too please");
+}
+
static void log_it_please(void)
{
qb_enter();
@@ -228,6 +238,17 @@ START_TEST(test_log_basic)
ck_assert_int_eq(num_msgs, 0);
qb_log(LOG_DEBUG, "try if you: log_it_please()");
ck_assert_int_eq(num_msgs, 1);
+
+ qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL,
+ QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
+ qb_log_filter_ctl(t, QB_LOG_FILTER_ADD,
+ QB_LOG_FILTER_FUNCTION,
+ "log_also,log_and_this_too",
+ LOG_DEBUG);
+ num_msgs = 0;
+ log_also();
+ log_and_this_too();
+ ck_assert_int_eq(num_msgs, 2);
}
END_TEST
--
1.7.6
12 years, 7 months
[PATCH 1/3] LOG: add facility conversion functions
by Angus Salkeld
Signed-off-by: Angus Salkeld <asalkeld(a)redhat.com>
---
include/qb/qblog.h | 11 ++++++++++
lib/log_format.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 67 insertions(+), 0 deletions(-)
diff --git a/include/qb/qblog.h b/include/qb/qblog.h
index 15e1316..8d7276c 100644
--- a/include/qb/qblog.h
+++ b/include/qb/qblog.h
@@ -536,6 +536,17 @@ void qb_log_target_format(int32_t target,
time_t timestamp,
const char* formatted_message,
char *output_buffer);
+
+/**
+ * Convert string "auth" to equivalent number "LOG_AUTH" etc.
+ */
+int32_t qb_log_facility2int(const char *fname);
+
+/**
+ * Convert number "LOG_AUTH" to equivalent string "auth" etc.
+ */
+const char * qb_log_facility2str(int32_t fnum);
+
/* *INDENT-OFF* */
#ifdef __cplusplus
}
diff --git a/lib/log_format.c b/lib/log_format.c
index 0cd07c7..b4032d9 100644
--- a/lib/log_format.c
+++ b/lib/log_format.c
@@ -49,11 +49,67 @@ static struct syslog_names prioritynames[] = {
{NULL, -1}
};
+struct syslog_names facilitynames[] = {
+ {"auth", LOG_AUTH},
+ {"authpriv", LOG_AUTHPRIV},
+ {"cron", LOG_CRON},
+ {"daemon", LOG_DAEMON},
+ {"ftp", LOG_FTP},
+ {"kern", LOG_KERN},
+ {"lpr", LOG_LPR},
+ {"mail", LOG_MAIL},
+ {"news", LOG_NEWS},
+ {"syslog", LOG_SYSLOG},
+ {"user", LOG_USER},
+ {"uucp", LOG_UUCP},
+ {"local0", LOG_LOCAL0},
+ {"local1", LOG_LOCAL1},
+ {"local2", LOG_LOCAL2},
+ {"local3", LOG_LOCAL3},
+ {"local4", LOG_LOCAL4},
+ {"local5", LOG_LOCAL5},
+ {"local6", LOG_LOCAL6},
+ {"local7", LOG_LOCAL7},
+ {NULL, -1}
+};
+
static const char log_month_name[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
+/* Convert string "auth" to equivalent number "LOG_AUTH" etc. */
+int32_t
+qb_log_facility2int(const char *fname)
+{
+ int32_t i;
+
+ if (fname == NULL) {
+ return -EINVAL;
+ }
+
+ for (i = 0; facilitynames[i].c_name != NULL; i++) {
+ if (strcmp(fname, facilitynames[i].c_name) == 0) {
+ return facilitynames[i].c_val;
+ }
+ }
+ return -EINVAL;
+}
+
+/* Convert number "LOG_AUTH" to equivalent string "auth" etc. */
+const char *
+qb_log_facility2str(int32_t fnum)
+{
+ int32_t i;
+
+ for (i = 0; facilitynames[i].c_name != NULL; i++) {
+ if (facilitynames[i].c_val == fnum) {
+ return facilitynames[i].c_name;
+ }
+ }
+ return NULL;
+}
+
void
qb_log_tags_stringify_fn_set(qb_log_tags_stringify_fn fn)
{
--
1.7.6
12 years, 7 months