summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2017-06-11 09:08:37 (GMT)
committer Daniel Silverstone <dsilvers@digital-scurf.org>2017-06-11 09:08:37 (GMT)
commit8b4ce0ba86d0396bde2546dd248c863876da4106 (patch)
tree72ac2147cda97ddac20144a60e7b0644a0cc303f
parent8052642eadfb95b244f978b10889dff51f9133f5 (diff)
downloadlibnslog-8b4ce0ba86d0396bde2546dd248c863876da4106.tar.gz
libnslog-8b4ce0ba86d0396bde2546dd248c863876da4106.tar.bz2
Another step toward filters working
-rw-r--r--.editorconfig19
-rw-r--r--include/nslog/nslog.h82
-rw-r--r--src/Makefile2
-rw-r--r--src/core.c28
-rw-r--r--src/filter.c310
-rw-r--r--src/nslog_internal.h29
-rw-r--r--test/Makefile2
-rw-r--r--test/basic.c10
-rw-r--r--test/explicitfilter.c50
-rwxr-xr-xtest/runtest.sh2
10 files changed, 488 insertions, 46 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..f24cd50
--- a/dev/null
+++ b/.editorconfig
@@ -0,0 +1,19 @@
+# This is an EditorConfig file
+# Learn more at http://editorconfig.org
+
+root = true
+
+# All files are UNIX-style and UTF-8
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+trim_trailing_whitespace = true
+
+# Makefiles use tabs
+[Makefile]
+indent_style = tab
+
+# C code uses tabs
+[*.{c,h}]
+indent_style = tab
diff --git a/include/nslog/nslog.h b/include/nslog/nslog.h
index ffa87bd..550bffb 100644
--- a/include/nslog/nslog.h
+++ b/include/nslog/nslog.h
@@ -4,7 +4,7 @@
* This file is part of libnslog.
*
* Licensed under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/mit-license.php
*/
/**
@@ -18,41 +18,44 @@
#include <stdarg.h>
typedef enum {
- NSLOG_LEVEL_DEEPDEBUG = 0,
- NSLOG_LEVEL_DEBUG = 1,
- NSLOG_LEVEL_VERBOSE = 2,
- NSLOG_LEVEL_INFO = 3,
- NSLOG_LEVEL_WARNING = 4,
- NSLOG_LEVEL_ERROR = 5,
- NSLOG_LEVEL_CRITICAL = 6,
+ NSLOG_LEVEL_DEEPDEBUG = 0,
+ NSLOG_LEVEL_DEBUG = 1,
+ NSLOG_LEVEL_VERBOSE = 2,
+ NSLOG_LEVEL_INFO = 3,
+ NSLOG_LEVEL_WARNING = 4,
+ NSLOG_LEVEL_ERROR = 5,
+ NSLOG_LEVEL_CRITICAL = 6,
} nslog_level;
const char *nslog_level_name(nslog_level level);
-#define NSLOG_LEVEL_DD NSLOG_LEVEL_DEEPDEBUG
-#define NSLOG_LEVEL_CHAT NSLOG_LEVEL_VERBOSE
-#define NSLOG_LEVEL_WARN NSLOG_LEVEL_WARNING
-#define NSLOG_LEVEL_ERR NSLOG_LEVEL_ERROR
-#define NSLOG_LEVEL_CRIT NSLOG_LEVEL_CRITICAL
+#define NSLOG_LEVEL_DD NSLOG_LEVEL_DEEPDEBUG
+#define NSLOG_LEVEL_CHAT NSLOG_LEVEL_VERBOSE
+#define NSLOG_LEVEL_WARN NSLOG_LEVEL_WARNING
+#define NSLOG_LEVEL_ERR NSLOG_LEVEL_ERROR
+#define NSLOG_LEVEL_CRIT NSLOG_LEVEL_CRITICAL
#ifndef NSLOG_COMPILED_MIN_LEVEL
#define NSLOG_COMPILED_MIN_LEVEL NSLOG_LEVEL_DEBUG
#endif
typedef struct nslog_category_s {
- const char *cat_name;
- const char *description;
- struct nslog_category_s *parent;
- char *name;
- struct nslog_category_s *next;
+ const char *cat_name;
+ const char *description;
+ struct nslog_category_s *parent;
+ char *name;
+ int namelen;
+ struct nslog_category_s *next;
} nslog_category_t;
typedef struct nslog_entry_context_s {
- nslog_category_t *category;
- nslog_level level;
- const char *filename;
+ nslog_category_t *category;
+ nslog_level level;
+ const char *filename;
+ int filenamelen;
const char *funcname;
- int lineno;
+ int funcnamelen;
+ int lineno;
} nslog_entry_context_t;
#define NSLOG_DECLARE_CATEGORY(catname) \
@@ -64,6 +67,7 @@ typedef struct nslog_entry_context_s {
description, \
NULL, \
NULL, \
+ 0, \
NULL, \
}
@@ -73,6 +77,7 @@ typedef struct nslog_entry_context_s {
description, \
&__nslog_category_##parentcatname, \
NULL, \
+ 0, \
NULL, \
}
@@ -83,7 +88,9 @@ typedef struct nslog_entry_context_s {
&__nslog_category_##catname, \
NSLOG_LEVEL_##level, \
__FILE__, \
+ sizeof(__FILE__) - 1, \
__PRETTY_FUNCTION__, \
+ sizeof(__PRETTY_FUNCTION__) - 1, \
__LINE__, \
}; \
nslog__log(&ctx, logmsg, ##args); \
@@ -106,4 +113,35 @@ nslog_error nslog_set_render_callback(nslog_callback cb, void *context);
nslog_error nslog_uncork(void);
+typedef struct nslog_filter_s nslog_filter_t;
+
+nslog_error nslog_filter_category_new(const char *catname,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_level_new(nslog_level level,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_filename_new(const char *filename,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_dirname_new(const char *dirname,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_funcname_new(const char *funcname,
+ nslog_filter_t **filter);
+
+nslog_error nslog_filter_and_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_or_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_xor_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter);
+nslog_error nslog_filter_not_new(nslog_filter_t *input,
+ nslog_filter_t **filter);
+
+nslog_filter_t *nslog_filter_ref(nslog_filter_t *filter);
+nslog_filter_t *nslog_filter_unref(nslog_filter_t *filter);
+
+nslog_error nslog_filter_set_active(nslog_filter_t *filter,
+ nslog_filter_t **prev);
+
#endif /* NSLOG_NSLOG_H_ */
diff --git a/src/Makefile b/src/Makefile
index 45ecb90..7fbad1c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1,3 +1,3 @@
-DIR_SOURCES := core.c
+DIR_SOURCES := core.c filter.c
include $(NSBUILD)/Makefile.subdir
diff --git a/src/core.c b/src/core.c
index ee5f2bc..978f169 100644
--- a/src/core.c
+++ b/src/core.c
@@ -4,7 +4,7 @@
* This file is part of libnslog.
*
* Licensed under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/mit-license.php
*/
/**
@@ -12,21 +12,14 @@
* NetSurf Logging Core
*/
-#include "nslog/nslog.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-
+#include "nslog_internal.h"
static bool nslog__corked = true;
static struct nslog_cork_chain {
struct nslog_cork_chain *next;
nslog_entry_context_t context;
- char message[0]; /* NUL terminated */
+ char message[0]; /* NUL terminated */
} *nslog__cork_chain = NULL, *nslog__cork_chain_last = NULL;
static nslog_callback nslog__cb = NULL;
@@ -52,7 +45,7 @@ const char *nslog_level_name(nslog_level level)
case NSLOG_LEVEL_CRITICAL:
return "CRITICAL";
};
-
+
return "**UNKNOWN**";
}
@@ -61,6 +54,7 @@ static void nslog__normalise_category(nslog_category_t *cat)
{
if (cat->parent == NULL) {
cat->name = strdup(cat->cat_name);
+ cat->namelen = strlen(cat->name);
} else {
nslog__normalise_category(cat->parent);
cat->name = malloc(strlen(cat->parent->name) + strlen(cat->cat_name) + 2);
@@ -68,6 +62,7 @@ static void nslog__normalise_category(nslog_category_t *cat)
strcat(cat->name, "/");
strcat(cat->name, cat->cat_name);
cat->next = nslog__all_categories;
+ cat->namelen = strlen(cat->name);
nslog__all_categories = cat;
}
}
@@ -102,7 +97,8 @@ static void nslog__log_uncorked(nslog_entry_context_t *ctx,
if (ctx->category->name == NULL) {
nslog__normalise_category(ctx->category);
}
- (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args);
+ if (nslog__filter_matches(ctx))
+ (*nslog__cb)(nslog__cb_ctx, ctx, fmt, args);
}
}
@@ -129,7 +125,7 @@ nslog_error nslog_set_render_callback(nslog_callback cb, void *context)
{
nslog__cb = cb;
nslog__cb_ctx = context;
-
+
return NSLOG_NO_ERROR;
}
@@ -155,12 +151,12 @@ nslog_error nslog_uncork()
if (ent->context.category->name == NULL) {
nslog__normalise_category(ent->context.category);
}
- __nslog__deliver_corked_entry(&ent->context,
- "%s", ent->message);
+ if (nslog__filter_matches(&ent->context))
+ __nslog__deliver_corked_entry(&ent->context,
+ "%s", ent->message);
free(ent);
}
nslog__corked = false;
}
return NSLOG_NO_ERROR;
}
-
diff --git a/src/filter.c b/src/filter.c
new file mode 100644
index 0000000..1dc4e81
--- a/dev/null
+++ b/src/filter.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright 2017 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of libnslog.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * NetSurf Logging Filters
+ */
+
+#include "nslog_internal.h"
+
+typedef enum {
+ /* Fundamentals */
+ NSLFK_CATEGORY = 0,
+ NSLFK_LEVEL,
+ NSLFK_FILENAME,
+ NSLFK_DIRNAME,
+ NSLFK_FUNCNAME,
+ /* logical operations */
+ NSLFK_AND,
+ NSLFK_OR,
+ NSLFK_XOR,
+ NSLFK_NOT,
+} nslog_filter_kind;
+
+struct nslog_filter_s {
+ nslog_filter_kind kind;
+ int refcount;
+ union {
+ struct {
+ char *ptr;
+ int len;
+ } str;
+ nslog_level level;
+ nslog_filter_t *unary_input;
+ struct {
+ nslog_filter_t *input1;
+ nslog_filter_t *input2;
+ } binary;
+ } params;
+};
+
+static nslog_filter_t *nslog__active_filter = NULL;
+
+nslog_error nslog_filter_category_new(const char *catname,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_CATEGORY;
+ ret->refcount = 1;
+ ret->params.str.ptr = strdup(catname);
+ ret->params.str.len = strlen(catname);
+ if (ret->params.str.ptr == NULL) {
+ free(ret);
+ return NSLOG_NO_MEMORY;
+ }
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_level_new(nslog_level level,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_LEVEL;
+ ret->refcount = 1;
+ ret->params.level = level;
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_filename_new(const char *filename,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_FILENAME;
+ ret->refcount = 1;
+ ret->params.str.ptr = strdup(filename);
+ ret->params.str.len = strlen(filename);
+ if (ret->params.str.ptr == NULL) {
+ free(ret);
+ return NSLOG_NO_MEMORY;
+ }
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_dirname_new(const char *dirname,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_DIRNAME;
+ ret->refcount = 1;
+ ret->params.str.ptr = strdup(dirname);
+ ret->params.str.len = strlen(dirname);
+ if (ret->params.str.ptr == NULL) {
+ free(ret);
+ return NSLOG_NO_MEMORY;
+ }
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_funcname_new(const char *funcname,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_FUNCNAME;
+ ret->refcount = 1;
+ ret->params.str.ptr = strdup(funcname);
+ ret->params.str.len = strlen(funcname);
+ if (ret->params.str.ptr == NULL) {
+ free(ret);
+ return NSLOG_NO_MEMORY;
+ }
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+
+nslog_error nslog_filter_and_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_AND;
+ ret->refcount = 1;
+ ret->params.binary.input1 = nslog_filter_ref(left);
+ ret->params.binary.input2 = nslog_filter_ref(right);
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_or_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_OR;
+ ret->refcount = 1;
+ ret->params.binary.input1 = nslog_filter_ref(left);
+ ret->params.binary.input2 = nslog_filter_ref(right);
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_xor_new(nslog_filter_t *left,
+ nslog_filter_t *right,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_XOR;
+ ret->refcount = 1;
+ ret->params.binary.input1 = nslog_filter_ref(left);
+ ret->params.binary.input2 = nslog_filter_ref(right);
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+nslog_error nslog_filter_not_new(nslog_filter_t *input,
+ nslog_filter_t **filter)
+{
+ nslog_filter_t *ret = calloc(sizeof(*ret), 1);
+ if (ret == NULL)
+ return NSLOG_NO_MEMORY;
+ ret->kind = NSLFK_NOT;
+ ret->refcount = 1;
+ ret->params.unary_input = nslog_filter_ref(input);
+ *filter = ret;
+ return NSLOG_NO_ERROR;
+}
+
+
+nslog_filter_t *nslog_filter_ref(nslog_filter_t *filter)
+{
+ if (filter != NULL)
+ filter->refcount++;
+
+ return filter;
+}
+
+nslog_filter_t *nslog_filter_unref(nslog_filter_t *filter)
+{
+ if (filter != NULL && filter->refcount-- == 1) {
+ switch(filter->kind) {
+ case NSLFK_CATEGORY:
+ case NSLFK_FILENAME:
+ case NSLFK_DIRNAME:
+ case NSLFK_FUNCNAME:
+ free(filter->params.str.ptr);
+ break;
+ case NSLFK_AND:
+ case NSLFK_OR:
+ case NSLFK_XOR:
+ nslog_filter_unref(filter->params.binary.input1);
+ nslog_filter_unref(filter->params.binary.input2);
+ break;
+ case NSLFK_NOT:
+ nslog_filter_unref(filter->params.unary_input);
+ break;
+ default:
+ /* Nothing to do for the other kind(s) */
+ break;
+ }
+ free(filter);
+ }
+
+ return NULL;
+}
+
+nslog_error nslog_filter_set_active(nslog_filter_t *filter,
+ nslog_filter_t **prev)
+{
+ if (prev != NULL)
+ *prev = nslog__active_filter;
+ else
+ nslog_filter_unref(nslog__active_filter);
+
+ nslog__active_filter = nslog_filter_ref(filter);
+
+ return NSLOG_NO_ERROR;
+}
+
+static bool _nslog__filter_matches(nslog_entry_context_t *ctx,
+ nslog_filter_t *filter)
+{
+ switch (filter->kind) {
+ case NSLFK_CATEGORY:
+ if (filter->params.str.len > ctx->category->namelen)
+ return false;
+ if (ctx->category->name[filter->params.str.len] != '\0' &&
+ ctx->category->name[filter->params.str.len] != '/')
+ return false;
+ return (strncmp(filter->params.str.ptr,
+ ctx->category->name,
+ filter->params.str.len) == 0);
+
+ case NSLFK_LEVEL:
+ return (ctx->level >= filter->params.level);
+ case NSLFK_FILENAME:
+ if (filter->params.str.len > ctx->filenamelen)
+ return false;
+ if ((filter->params.str.len == ctx->filenamelen) &&
+ (strcmp(filter->params.str.ptr, ctx->filename) == 0))
+ return true;
+ if ((ctx->filename[ctx->filenamelen - filter->params.str.len - 1] == '/')
+ && (strcmp(filter->params.str.ptr,
+ ctx->filename + ctx->filenamelen - filter->params.str.len) == 0))
+ return true;
+ return false;
+ case NSLFK_DIRNAME:
+ if (filter->params.str.len >= ctx->filenamelen)
+ return false;
+ if ((ctx->filename[filter->params.str.len] == '/')
+ && (strncmp(filter->params.str.ptr,
+ ctx->filename,
+ filter->params.str.len) == 0))
+ return true;
+ return false;
+ case NSLFK_FUNCNAME:
+ return (filter->params.str.len == ctx->funcnamelen &&
+ strcmp(ctx->funcname, filter->params.str.ptr) == 0);
+ case NSLFK_AND:
+ return (_nslog__filter_matches(ctx, filter->params.binary.input1)
+ &&
+ _nslog__filter_matches(ctx, filter->params.binary.input2));
+ case NSLFK_OR:
+ return (_nslog__filter_matches(ctx, filter->params.binary.input1)
+ ||
+ _nslog__filter_matches(ctx, filter->params.binary.input2));
+ case NSLFK_XOR:
+ return (_nslog__filter_matches(ctx, filter->params.binary.input1)
+ ^
+ _nslog__filter_matches(ctx, filter->params.binary.input2));
+ case NSLFK_NOT:
+ return !_nslog__filter_matches(ctx, filter->params.unary_input);
+ default:
+ /* unknown */
+ assert("Unknown filter kind" == NULL);
+ return false;
+ }
+}
+
+bool nslog__filter_matches(nslog_entry_context_t *ctx)
+{
+ if (nslog__active_filter == NULL)
+ return true;
+ return _nslog__filter_matches(ctx, nslog__active_filter);
+}
diff --git a/src/nslog_internal.h b/src/nslog_internal.h
new file mode 100644
index 0000000..d5519e7
--- a/dev/null
+++ b/src/nslog_internal.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2017 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of libnslog.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+/**
+ * \file
+ * NetSurf Logging
+ */
+
+#ifndef NSLOG_INTERNAL_H_
+#define NSLOG_INTERNAL_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#include "nslog/nslog.h"
+
+bool nslog__filter_matches(nslog_entry_context_t *ctx);
+
+#endif /* NSLOG_INTERNAL_H_ */
diff --git a/test/Makefile b/test/Makefile
index 0cebdaa..033033f 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,3 +1,3 @@
-DIR_TEST_ITEMS := basic:basic.c
+DIR_TEST_ITEMS := basic:basic.c explicitfilter:explicitfilter.c
include $(NSBUILD)/Makefile.subdir
diff --git a/test/basic.c b/test/basic.c
index 7626dd8..d514814 100644
--- a/test/basic.c
+++ b/test/basic.c
@@ -4,7 +4,7 @@
* This file is part of libnslog.
*
* Licensed under the MIT License,
- * http://www.opensource.org/licenses/mit-license.php
+ * http://www.opensource.org/licenses/mit-license.php
*/
#include "nslog/nslog.h"
@@ -18,10 +18,10 @@ static void test_render_function(
const char *fmt, va_list args)
{
(void)ctx;
- fprintf(stderr, "%s %s:%d [%s] %s() ",
- nslog_level_name(ctx->level),
- ctx->filename, ctx->lineno,
- ctx->category->name,
+ fprintf(stderr, "%s %s:%d [%s] %s() ",
+ nslog_level_name(ctx->level),
+ ctx->filename, ctx->lineno,
+ ctx->category->name,
ctx->funcname);
vfprintf(stderr, fmt, args);
fprintf(stderr, "\n");
diff --git a/test/explicitfilter.c b/test/explicitfilter.c
new file mode 100644
index 0000000..c7aca8a
--- a/dev/null
+++ b/test/explicitfilter.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ *
+ * This file is part of libnslog.
+ *
+ * Licensed under the MIT License,
+ * http://www.opensource.org/licenses/mit-license.php
+ */
+
+#include "nslog/nslog.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+NSLOG_DEFINE_CATEGORY(test, "Test category");
+
+static void test_render_function(
+ void *_ctx, nslog_entry_context_t *ctx,
+ const char *fmt, va_list args)
+{
+ (void)ctx;
+ fprintf(stderr, "%s %s:%d [%s] %s() ",
+ nslog_level_name(ctx->level),
+ ctx->filename, ctx->lineno,
+ ctx->category->name,
+ ctx->funcname);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+}
+
+int main(int argc, char **argv)
+{
+ nslog_set_render_callback(test_render_function, NULL);
+ nslog_uncork();
+
+ nslog_filter_t *cat_test, *cat_another;
+
+ assert(nslog_filter_category_new("test", &cat_test) == NSLOG_NO_ERROR);
+ assert(nslog_filter_category_new("another", &cat_another) == NSLOG_NO_ERROR);
+
+ NSLOG(test, INFO, "Hurrah, a message!");
+ assert(nslog_filter_set_active(cat_test, NULL) == NSLOG_NO_ERROR);
+ NSLOG(test, INFO, "You should see me.");
+ assert(nslog_filter_set_active(cat_another, NULL) == NSLOG_NO_ERROR);
+ NSLOG(test, INFO, "You should not see me!");
+ assert(nslog_filter_set_active(NULL, NULL) == NSLOG_NO_ERROR);
+ NSLOG(test, INFO, "You should see this one though.");
+
+ return 0;
+}
diff --git a/test/runtest.sh b/test/runtest.sh
index 1b67a97..3bf903e 100755
--- a/test/runtest.sh
+++ b/test/runtest.sh
@@ -5,7 +5,7 @@ set -e
TEST_PATH=$1
TEST_PFX=$4
-for TEST in basic; do
+for TEST in basic explicitfilter; do
${TEST_PATH}/${TEST_PFX}${TEST}
done