From 551cf378a93588d42732983ec30716e14afef945 Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Sat, 10 Jun 2017 18:11:25 +0100 Subject: Initial version --- .gitignore | 2 + COPYING | 19 +++++++ Makefile | 55 ++++++++++++++++++ README | 40 ++++++++++++++ include/nslog/nslog.h | 108 ++++++++++++++++++++++++++++++++++++ libnslog.pc.in | 10 ++++ src/Makefile | 3 + src/core.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++ test/Makefile | 3 + test/basic.c | 33 +++++++++++ test/runtest.sh | 12 ++++ 11 files changed, 435 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 Makefile create mode 100644 README create mode 100644 include/nslog/nslog.h create mode 100644 libnslog.pc.in create mode 100644 src/Makefile create mode 100644 src/core.c create mode 100644 test/Makefile create mode 100644 test/basic.c create mode 100755 test/runtest.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8039af5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +build-* diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0bedd97 --- /dev/null +++ b/COPYING @@ -0,0 +1,19 @@ +Copyright 2014 Vincent Sanders + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..184f9d4 --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +#!/bin/make +# +# Makefile for libnslog +# +# Copyright 2014-1015 Vincent Sanders +# Copyright 2017 Daniel Silverstone + +# Component settings +COMPONENT := nslog +COMPONENT_VERSION := 0.0.0 +# Default to a static library +COMPONENT_TYPE ?= lib-static + +# Setup the tooling +PREFIX ?= /opt/netsurf +NSSHARED ?= $(PREFIX)/share/netsurf-buildsystem +include $(NSSHARED)/makefiles/Makefile.tools + +# Reevaluate when used, as BUILDDIR won't be defined yet +TESTRUNNER = test/runtest.sh $(BUILDDIR) $(EXEEXT) + +# Toolchain flags +WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \ + -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \ + -Wmissing-declarations -Wnested-externs + +CFLAGS := -D_GNU_SOURCE -D_DEFAULT_SOURCE \ + -I$(CURDIR)/include/ -I$(CURDIR)/src $(WARNFLAGS) $(CFLAGS) +ifneq ($(GCCVER),2) + CFLAGS := $(CFLAGS) -std=c99 +else + # __inline__ is a GCCism + CFLAGS := $(CFLAGS) -Dinline="__inline__" +endif +CFLAGS := $(CFLAGS) -D_POSIX_C_SOURCE=200809L + +REQUIRED_LIBS := nslog + +# Strictly the requirement for rt is dependant on both the clib and if +# the build is using rt features like clock_gettime() but this check +# will suffice +ifeq ($(HOST),x86_64-linux-gnu) + REQUIRED_LIBS := $(REQUIRED_LIBS) rt +endif + +TESTCFLAGS := -g -O2 +TESTLDFLAGS := -lm -l$(COMPONENT) $(TESTLDFLAGS) + +include $(NSBUILD)/Makefile.top + +# Extra installation rules +I := /$(INCLUDEDIR)/nslog +INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/nslog/nslog.h +INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR)/pkgconfig:lib$(COMPONENT).pc.in +INSTALL_ITEMS := $(INSTALL_ITEMS) /$(LIBDIR):$(OUTPUT) diff --git a/README b/README new file mode 100644 index 0000000..45e0a12 --- /dev/null +++ b/README @@ -0,0 +1,40 @@ +Libnsutils - NetSurf utility functions +====================================== + +Overview +-------- + + Libnsutils provides a small number of useful utility routines which + require platform-specific implementations. + +Requirements +------------ + + Libnsutils requires the following tools: + + + A C99 capable C compiler + + GNU make or compatible + + Pkg-config + +Compilation +----------- + + If necessary, modify the toolchain settings in the Makefile. + Invoke make: + $ make + +Verification +------------ + + To verify that the library is working, it is necessary to specify a + different makefile target than that used for normal compilation, thus: + + $ make test + +API documentation +----------------- + + Currently, there is none. However, the code is well commented and the + public API may be found in the "include" directory. The testcase sources + may also be of use in working out how to use it. + diff --git a/include/nslog/nslog.h b/include/nslog/nslog.h new file mode 100644 index 0000000..fff31a7 --- /dev/null +++ b/include/nslog/nslog.h @@ -0,0 +1,108 @@ +/* + * Copyright 2017 Daniel Silverstone + * + * This file is part of libnslog. + * + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + */ + +/** + * \file + * NetSurf Logging + */ + +#ifndef NSLOG_NSLOG_H_ +#define NSLOG_NSLOG_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; + +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 + +#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; +} nslog_category_t; + +typedef struct nslog_entry_s { + nslog_category_t *category; + nslog_level level; + const char *filename; + const char *funcname; + int lineno; + char message[0]; /* NUL terminated */ +} nslog_entry_t; + +#define NSLOG_DECLARE_CATEGORY(catname) \ + extern nslog_category_t __nslog_category_##catname + +#define NSLOG_DEFINE_CATEGORY(catname, description) \ + nslog_category_t __nslog_category_##catname = { \ + #catname, \ + description, \ + NULL, \ + NULL, \ + NULL, \ + } + +#define NSLOG_DEFINE_SUBCATEGORY(parentcatname, catname, description) \ + nslog_category_t __nslog_category_##catname = { \ + #catname, \ + description, \ + &__nslog_category_##parentcatname, \ + NULL, \ + NULL, \ + } + +#define NSLOG(catname, level, logmsg, args...) \ + if (NSLOG_LEVEL_##level >= NSLOG_COMPILED_MIN_LEVEL) { \ + nslog__log(&__nslog_category_##catname, \ + NSLOG_LEVEL_##level, \ + __FILE__, \ + __LINE__, \ + __PRETTY_FUNCTION__, \ + logmsg, \ + ##args); \ + } + +void nslog__log(nslog_category_t *category, + nslog_level level, + const char *filename, + int lineno, + const char *funcname, + const char *pattern, + ...) __attribute__ ((format (printf, 6, 7))); + +typedef enum { + NSLOG_NO_ERROR = 0, + NSLOG_NO_MEMORY = 1, +} nslog_error; + +typedef void (*nslog_callback)(void *context, nslog_entry_t *msg); + +nslog_error nslog_set_render_callback(nslog_callback cb, void *context); + +nslog_error nslog_uncork(void); + +#endif /* NSLOG_NSLOG_H_ */ diff --git a/libnslog.pc.in b/libnslog.pc.in new file mode 100644 index 0000000..d382216 --- /dev/null +++ b/libnslog.pc.in @@ -0,0 +1,10 @@ +prefix=PREFIX +exec_prefix=${prefix} +libdir=${exec_prefix}/LIBDIR +includedir=${prefix}/INCLUDEDIR + +Name: libnslog +Description: NetSurf Logging sublayer +Version: VERSION +Libs: -L${libdir} LIBRARIES +Cflags: -I${includedir} diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..45ecb90 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,3 @@ +DIR_SOURCES := core.c + +include $(NSBUILD)/Makefile.subdir diff --git a/src/core.c b/src/core.c new file mode 100644 index 0000000..0665195 --- /dev/null +++ b/src/core.c @@ -0,0 +1,150 @@ +/* + * Copyright 2017 Daniel Silverstone + * + * This file is part of libnslog. + * + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + */ + +/** + * \file + * NetSurf Logging Core + */ + +#include "nslog/nslog.h" + +#include +#include +#include +#include +#include + +static bool nslog__corked = true; + +static struct nslog_cork_chain { + struct nslog_cork_chain *next; + nslog_entry_t *entry; +} *nslog__cork_chain = NULL; + +static nslog_callback nslog__cb = NULL; +static void *nslog__cb_ctx = NULL; + +static nslog_category_t *nslog__all_categories = NULL; + +const char *nslog_level_name(nslog_level level) +{ + switch (level) { + case NSLOG_LEVEL_DEEPDEBUG: + return "DEEPDEBUG"; + case NSLOG_LEVEL_DEBUG: + return "DEBUG"; + case NSLOG_LEVEL_VERBOSE: + return "VERBOSE"; + case NSLOG_LEVEL_INFO: + return "INFO"; + case NSLOG_LEVEL_WARNING: + return "WARNING"; + case NSLOG_LEVEL_ERROR: + return "ERROR"; + case NSLOG_LEVEL_CRITICAL: + return "CRITICAL"; + }; + + return "**UNKNOWN**"; +} + + +static void nslog__normalise_category(nslog_category_t *cat) +{ + if (cat->parent == NULL) { + cat->name = strdup(cat->cat_name); + } else { + nslog__normalise_category(cat->parent); + cat->name = malloc(strlen(cat->parent->name) + strlen(cat->cat_name) + 2); + strcpy(cat->name, cat->parent->name); + strcat(cat->name, "/"); + strcat(cat->name, cat->cat_name); + cat->next = nslog__all_categories; + nslog__all_categories = cat; + } +} + +static void nslog__deliver(nslog_entry_t *entry) +{ + /* TODO: Add filtering here */ + if (nslog__cb != NULL) { + if (entry->category->name == NULL) { + nslog__normalise_category(entry->category); + } + (*nslog__cb)(nslog__cb_ctx, entry); + } +} + +void nslog__log(nslog_category_t *category, + nslog_level level, + const char *filename, + int lineno, + const char *funcname, + const char *pattern, + ...) +{ + va_list ap; + va_start(ap, pattern); + va_list ap2; + va_copy(ap2, ap); + int slen = vsnprintf(NULL, 0, pattern, ap); + va_end(ap); + nslog_entry_t *entry = malloc(sizeof(nslog_entry_t) + slen + 1); + if (entry == NULL) { + /* We're at ENOMEM! log entry is lost */ + va_end(ap2); + return; + } + entry->category = category; + entry->level = level; + entry->filename = filename; + entry->funcname = funcname; + entry->lineno = lineno; + vsprintf(entry->message, pattern, ap2); + va_end(ap2); + if (nslog__corked) { + struct nslog_cork_chain *chained = malloc(sizeof(struct nslog_cork_chain)); + if (chained == NULL) { + /* ENOMEM during corked operation! wow */ + free(entry); + return; + } + chained->next = nslog__cork_chain; + chained->entry = entry; + nslog__cork_chain = chained; + } else { + /* Not corked */ + nslog__deliver(entry); + free(entry); + } +} + +nslog_error nslog_set_render_callback(nslog_callback cb, void *context) +{ + nslog__cb = cb; + nslog__cb_ctx = context; + + return NSLOG_NO_ERROR; +} + +nslog_error nslog_uncork() +{ + if (nslog__corked) { + while (nslog__cork_chain != NULL) { + struct nslog_cork_chain *ent = nslog__cork_chain; + nslog__cork_chain = ent->next; + nslog__deliver(ent->entry); + free(ent->entry); + free(ent); + } + nslog__corked = false; + } + return NSLOG_NO_ERROR; +} + diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..0cebdaa --- /dev/null +++ b/test/Makefile @@ -0,0 +1,3 @@ +DIR_TEST_ITEMS := basic:basic.c + +include $(NSBUILD)/Makefile.subdir diff --git a/test/basic.c b/test/basic.c new file mode 100644 index 0000000..fd40633 --- /dev/null +++ b/test/basic.c @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Daniel Silverstone + * + * This file is part of libnslog. + * + * Licensed under the MIT License, + * http://www.opensource.org/licenses/mit-license.php + */ + +#include "nslog/nslog.h" + +#include + +NSLOG_DEFINE_CATEGORY(test, "Test category"); + +static void test_render_function(void *ctx, nslog_entry_t *log) +{ + (void)ctx; + fprintf(stderr, "%s %s:%d [%s] %s() %s\n", + nslog_level_name(log->level), + log->filename, log->lineno, + log->category->name, + log->funcname, + log->message); +} + +int main(int argc, char **argv) +{ + nslog_set_render_callback(test_render_function, NULL); + nslog_uncork(); + NSLOG(test, WARN, "argc=%d", argc); + return 0; +} diff --git a/test/runtest.sh b/test/runtest.sh new file mode 100755 index 0000000..1b67a97 --- /dev/null +++ b/test/runtest.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e + +TEST_PATH=$1 +TEST_PFX=$4 + +for TEST in basic; do + ${TEST_PATH}/${TEST_PFX}${TEST} +done + +exit 0 -- cgit v1.2.3