From ed004cba0e8d1d383def76f795b1e63ba0aaa89a Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 9 Feb 2025 15:04:27 +0100 Subject: First commit (everything was written 2024) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 16 + LICENSE | 15 + Makefile | 182 +++++ TODO | 2 + common.h | 316 ++++++++ config.mk | 8 + liblog.h | 1583 +++++++++++++++++++++++++++++++++++++++ liblog_alert.c | 23 + liblog_alert_cork.c | 23 + liblog_apply_env_mask.c | 22 + liblog_clear_mask.c | 29 + liblog_critical.c | 23 + liblog_critical_cork.c | 23 + liblog_debug.c | 23 + liblog_debug_cork.c | 23 + liblog_destroy_context.c | 32 + liblog_destroy_output.c | 40 + liblog_dump_backtrace.c | 25 + liblog_dump_backtrace_cork.c | 25 + liblog_emergency.c | 23 + liblog_emergency_cork.c | 23 + liblog_error.c | 23 + liblog_error_cork.c | 23 + liblog_flush__.c | 18 + liblog_info.c | 23 + liblog_info_cork.c | 23 + liblog_init_context.c | 24 + liblog_log.c | 25 + liblog_log_cork.c | 25 + liblog_log_no_backtrace.c | 25 + liblog_log_no_backtrace_cork.c | 25 + liblog_logmask__.c | 198 +++++ liblog_mask_level.c | 113 +++ liblog_mask_range.c | 412 ++++++++++ liblog_mask_verbose.c | 111 +++ liblog_notice.c | 23 + liblog_notice_cork.c | 23 + liblog_trace.c | 23 + liblog_trace__.c | 25 + liblog_trace_cork.c | 23 + liblog_uncork.c | 25 + liblog_unmask_level.c | 113 +++ liblog_unmask_range.c | 412 ++++++++++ liblog_unmask_verbose.c | 111 +++ liblog_use_fd.c | 11 + liblog_use_fd_for_range.c | 12 + liblog_use_file.c | 32 + liblog_use_file_for_range.c | 33 + liblog_use_output.c | 54 ++ liblog_use_stderr.c | 11 + liblog_use_stderr_for_range.c | 12 + liblog_use_stream.c | 11 + liblog_use_stream_for_range.c | 12 + liblog_use_syslog.c | 99 +++ liblog_use_syslog_for_range.c | 12 + liblog_valert.c | 23 + liblog_valert_cork.c | 23 + liblog_vcritical.c | 23 + liblog_vcritical_cork.c | 23 + liblog_vdebug.c | 23 + liblog_vdebug_cork.c | 23 + liblog_vemergency.c | 23 + liblog_vemergency_cork.c | 23 + liblog_verror.c | 23 + liblog_verror_cork.c | 23 + liblog_vinfo.c | 23 + liblog_vinfo_cork.c | 23 + liblog_vlog.c | 25 + liblog_vlog_cork.c | 25 + liblog_vlog_no_backtrace.c | 25 + liblog_vlog_no_backtrace_cork.c | 25 + liblog_vnotice.c | 23 + liblog_vnotice_cork.c | 23 + liblog_vtrace.c | 23 + liblog_vtrace_cork.c | 23 + liblog_vwarning.c | 23 + liblog_vwarning_cork.c | 23 + liblog_vxlog.c | 121 +++ liblog_warning.c | 23 + liblog_warning_cork.c | 23 + liblog_whence__.c | 24 + liblog_xlog.c | 25 + mk/linux.mk | 6 + mk/macos.mk | 6 + mk/windows.mk | 6 + test-alert.h | 6 + test-critical.h | 6 + test-debug.h | 6 + test-emergency.h | 6 + test-error.h | 6 + test-info.h | 6 + test-level.c | 4 + test-level_cork.c | 4 + test-notice.h | 6 + test-trace.h | 6 + test-vlevel.c | 4 + test-vlevel_cork.c | 4 + test-warning.h | 6 + testhelp.c | 366 +++++++++ 99 files changed, 5808 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 TODO create mode 100644 common.h create mode 100644 config.mk create mode 100644 liblog.h create mode 100644 liblog_alert.c create mode 100644 liblog_alert_cork.c create mode 100644 liblog_apply_env_mask.c create mode 100644 liblog_clear_mask.c create mode 100644 liblog_critical.c create mode 100644 liblog_critical_cork.c create mode 100644 liblog_debug.c create mode 100644 liblog_debug_cork.c create mode 100644 liblog_destroy_context.c create mode 100644 liblog_destroy_output.c create mode 100644 liblog_dump_backtrace.c create mode 100644 liblog_dump_backtrace_cork.c create mode 100644 liblog_emergency.c create mode 100644 liblog_emergency_cork.c create mode 100644 liblog_error.c create mode 100644 liblog_error_cork.c create mode 100644 liblog_flush__.c create mode 100644 liblog_info.c create mode 100644 liblog_info_cork.c create mode 100644 liblog_init_context.c create mode 100644 liblog_log.c create mode 100644 liblog_log_cork.c create mode 100644 liblog_log_no_backtrace.c create mode 100644 liblog_log_no_backtrace_cork.c create mode 100644 liblog_logmask__.c create mode 100644 liblog_mask_level.c create mode 100644 liblog_mask_range.c create mode 100644 liblog_mask_verbose.c create mode 100644 liblog_notice.c create mode 100644 liblog_notice_cork.c create mode 100644 liblog_trace.c create mode 100644 liblog_trace__.c create mode 100644 liblog_trace_cork.c create mode 100644 liblog_uncork.c create mode 100644 liblog_unmask_level.c create mode 100644 liblog_unmask_range.c create mode 100644 liblog_unmask_verbose.c create mode 100644 liblog_use_fd.c create mode 100644 liblog_use_fd_for_range.c create mode 100644 liblog_use_file.c create mode 100644 liblog_use_file_for_range.c create mode 100644 liblog_use_output.c create mode 100644 liblog_use_stderr.c create mode 100644 liblog_use_stderr_for_range.c create mode 100644 liblog_use_stream.c create mode 100644 liblog_use_stream_for_range.c create mode 100644 liblog_use_syslog.c create mode 100644 liblog_use_syslog_for_range.c create mode 100644 liblog_valert.c create mode 100644 liblog_valert_cork.c create mode 100644 liblog_vcritical.c create mode 100644 liblog_vcritical_cork.c create mode 100644 liblog_vdebug.c create mode 100644 liblog_vdebug_cork.c create mode 100644 liblog_vemergency.c create mode 100644 liblog_vemergency_cork.c create mode 100644 liblog_verror.c create mode 100644 liblog_verror_cork.c create mode 100644 liblog_vinfo.c create mode 100644 liblog_vinfo_cork.c create mode 100644 liblog_vlog.c create mode 100644 liblog_vlog_cork.c create mode 100644 liblog_vlog_no_backtrace.c create mode 100644 liblog_vlog_no_backtrace_cork.c create mode 100644 liblog_vnotice.c create mode 100644 liblog_vnotice_cork.c create mode 100644 liblog_vtrace.c create mode 100644 liblog_vtrace_cork.c create mode 100644 liblog_vwarning.c create mode 100644 liblog_vwarning_cork.c create mode 100644 liblog_vxlog.c create mode 100644 liblog_warning.c create mode 100644 liblog_warning_cork.c create mode 100644 liblog_whence__.c create mode 100644 liblog_xlog.c create mode 100644 mk/linux.mk create mode 100644 mk/macos.mk create mode 100644 mk/windows.mk create mode 100644 test-alert.h create mode 100644 test-critical.h create mode 100644 test-debug.h create mode 100644 test-emergency.h create mode 100644 test-error.h create mode 100644 test-info.h create mode 100644 test-level.c create mode 100644 test-level_cork.c create mode 100644 test-notice.h create mode 100644 test-trace.h create mode 100644 test-vlevel.c create mode 100644 test-vlevel_cork.c create mode 100644 test-warning.h create mode 100644 testhelp.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42c07ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*\#* +*~ +*.o +*.a +*.lo +*.su +*.so +*.so.* +*.dll +*.dylib +*.gch +*.gcov +*.gcno +*.gcda +*.to +*.test diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f930ea6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +© 2024 Mattias Andrée + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cef8c52 --- /dev/null +++ b/Makefile @@ -0,0 +1,182 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OS = linux +# Linux: linux +# Mac OS: macos +# Windows: windows +include mk/$(OS).mk + + +LIB_MAJOR = 1 +LIB_MINOR = 0 +LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) +LIB_NAME = log + + +OBJ =\ + liblog_alert.o\ + liblog_alert_cork.o\ + liblog_apply_env_mask.o\ + liblog_clear_mask.o\ + liblog_critical.o\ + liblog_critical_cork.o\ + liblog_debug.o\ + liblog_debug_cork.o\ + liblog_destroy_context.o\ + liblog_destroy_output.o\ + liblog_dump_backtrace.o\ + liblog_dump_backtrace_cork.o\ + liblog_emergency.o\ + liblog_emergency_cork.o\ + liblog_error.o\ + liblog_error_cork.o\ + liblog_flush__.o\ + liblog_info.o\ + liblog_info_cork.o\ + liblog_init_context.o\ + liblog_log.o\ + liblog_log_cork.o\ + liblog_log_no_backtrace.o\ + liblog_log_no_backtrace_cork.o\ + liblog_logmask__.o\ + liblog_mask_level.o\ + liblog_mask_range.o\ + liblog_mask_verbose.o\ + liblog_notice.o\ + liblog_notice_cork.o\ + liblog_trace.o\ + liblog_trace__.o\ + liblog_trace_cork.o\ + liblog_uncork.o\ + liblog_unmask_level.o\ + liblog_unmask_range.o\ + liblog_unmask_verbose.o\ + liblog_use_fd.o\ + liblog_use_fd_for_range.o\ + liblog_use_file.o\ + liblog_use_file_for_range.o\ + liblog_use_output.o\ + liblog_use_stderr.o\ + liblog_use_stderr_for_range.o\ + liblog_use_stream.o\ + liblog_use_stream_for_range.o\ + liblog_use_syslog.o\ + liblog_use_syslog_for_range.o\ + liblog_valert.o\ + liblog_valert_cork.o\ + liblog_vcritical.o\ + liblog_vcritical_cork.o\ + liblog_vdebug.o\ + liblog_vdebug_cork.o\ + liblog_vemergency.o\ + liblog_vemergency_cork.o\ + liblog_verror.o\ + liblog_verror_cork.o\ + liblog_vinfo.o\ + liblog_vinfo_cork.o\ + liblog_vlog.o\ + liblog_vlog_cork.o\ + liblog_vlog_no_backtrace.o\ + liblog_vlog_no_backtrace_cork.o\ + liblog_vnotice.o\ + liblog_vnotice_cork.o\ + liblog_vtrace.o\ + liblog_vtrace_cork.o\ + liblog_vwarning.o\ + liblog_vwarning_cork.o\ + liblog_vxlog.o\ + liblog_warning.o\ + liblog_warning_cork.o\ + liblog_whence__.o\ + liblog_xlog.o + +HDR =\ + liblog.h\ + common.h + +LOBJ = $(OBJ:.o=.lo) +TOBJ = $(OBJ:.o=.to) +TEST = $(OBJ:.o=.test) + + +all: liblog.a liblog.$(LIBEXT) $(TEST) +$(OBJ): $(HDR) +$(LOBJ): $(HDR) +$(TOBJ): $(HDR) +$(TEST): testhelp.o liblog.a +liblog_alert_cork.to liblog_critical_cork.to liblog_debug_cork.to liblog_emergency_cork.to liblog_error_cork.to liblog_notice_cork.to liblog_trace_cork.to liblog_warning_cork.to: test-level_cork.c +liblog_valert_cork.to liblog_vcritical_cork.to liblog_vdebug_cork.to liblog_vemergency_cork.to liblog_verror_cork.to liblog_vnotice_cork.to liblog_vtrace_cork.to liblog_vwarning_cork.to: test-vlevel_cork.c +liblog_alert.to liblog_critical.to liblog_debug.to liblog_emergency.to liblog_error.to liblog_notice.to liblog_trace.to liblog_warning.to: test-level.c +liblog_valert.to liblog_vcritical.to liblog_vdebug.to liblog_vemergency.to liblog_verror.to liblog_vnotice.to liblog_vtrace.to liblog_vwarning.to: test-vlevel.c +liblog_alert_cork.to liblog_valert_cork.to liblog_alert.to liblog_valert.to: test-alert.h +liblog_critical_cork.to liblog_vcritical_cork.to liblog_critical.to liblog_vcritical.to: test-critical.h +liblog_debug_cork.to liblog_vdebug_cork.to liblog_debug.to liblog_vdebug.to: test-debug.h +liblog_emergency_cork.to liblog_vemergency_cork.to liblog_emergency.to liblog_vemergency.to: test-emergency.h +liblog_error_cork.to liblog_verror_cork.to liblog_error.to liblog_verror.to: test-error.h +liblog_notice_cork.to liblog_vnotice_cork.to liblog_notice.to liblog_vnotice.to: test-notice.h +liblog_trace_cork.to liblog_vtrace_cork.to liblog_trace.to liblog_vtrace.to: test-trace.h +liblog_warning_cork.to liblog_vwarning_cork.to liblog_warning.to liblog_vwarning.to: test-warning.h + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.lo: + $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.to: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) -DTEST + +.to.test: + $(CC) -o $@ $< testhelp.o liblog.a $(LDFLAGS) + +liblog.a: $(OBJ) + @rm -f -- $@ + $(AR) rc $@ $(OBJ) + $(AR) ts $@ > /dev/null + +liblog.$(LIBEXT): $(LOBJ) + $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS) + +check: $(TEST) + @set -e;\ + status=0;\ + for t in $(TEST); do\ + if test -n "$(CHECK_PREFIX)"; then\ + printf '%s\n' "$(CHECK_PREFIX) ./$$t";\ + else\ + printf '%s\n' "./$$t";\ + fi;\ + if ! $(CHECK_PREFIX) ./$$t; then\ + status=1;\ + fi;\ + done;\ + exit $$status + +install: liblog.a liblog.$(LIBEXT) + mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" + mkdir -p -- "$(DESTDIR)$(PREFIX)/include" + cp -- liblog.a "$(DESTDIR)$(PREFIX)/lib/" + cp -- liblog.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBMINOREXT)" + $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBMINOREXT)" + ln -sf -- liblog.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBMAJOREXT)" + ln -sf -- liblog.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBEXT)" + cp -- liblog.h "$(DESTDIR)$(PREFIX)/include/" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/liblog.a" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBMAJOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBMINOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/liblog.$(LIBEXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/include/liblog.h" + +clean: + -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib *.to *.test + -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) + +.SUFFIXES: +.SUFFIXES: .lo .o .c .to .test + +.PHONY: all check install uninstall clean diff --git a/TODO b/TODO new file mode 100644 index 0000000..dc72593 --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +Add man pages +Add README diff --git a/common.h b/common.h new file mode 100644 index 0000000..277c3d5 --- /dev/null +++ b/common.h @@ -0,0 +1,316 @@ +/* See LICENSE file for copyright and license details. */ +#include "liblog.h" + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEFAULT_PREFIXFMT "%[argv0] [%[pid]] [%{utime:%F %T%}.%[milli]Z] [%level]: %[file]:%[line] (%[function]): " + + +#if defined(__GNUC__) +# define WEAK_LINKING __attribute__((__weak__)) +#else +# define WEAK_LINKING +# define WEAK_LINKING_FAILED +#endif + + +#define MIN(A, B) ((A) < (B) ? (A) : (B)) +#define MAX(A, B) ((A) > (B) ? (A) : (B)) +#define NEXT_LOGLEVEL(LVL) ((enum liblog_level)(LVL) + (enum liblog_level)100) + +#define XLOG_NOT_INLINE 0x0100 + + +struct messagebuf { + char *prefix; /* TODO for each output channel; also get arguments for each channel */ + char *text; + size_t len; + size_t size; +}; + +#define MESSAGEBUF_INIT ((struct messagebuf){NULL, NULL, 0, 0}) + +struct liblog_context_internal_state { + struct messagebuf msg; +}; + + +extern const char *argv0; + + +int liblog_flush__(struct liblog_context *ctx, const struct messagebuf *msg); +WEAK_LINKING int liblog_trace__(char **textp, size_t *offsetp, size_t *allocsizep, size_t skip, void *saved_trace); +WEAK_LINKING int liblog_whence__(char **file_out, off_t *line_out, char **function_out, size_t skip, void **trace_savep); + + +#ifdef TEST +# if defined(__GNUC__) +# if defined(__clang__) +# pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +# endif +# define main __attribute__((__const__)) main +# endif +#endif + + + + +#ifdef TEST +# define TESTED_ELSEWHERE LIBEXEC_CONST__ int main(void) { return 0; } + +enum assert_type { + ASSERT_ENUM, + ASSERT_UINT, + ASSERT_INT, + ASSERT_NULL, + ASSERT_PTR, + ASSERT_STR, + ASSERT_STR_REV +}; + +enum assert_how { + ASSERT_EQ, + ASSERT_NE, + ASSERT_LT, + ASSERT_LE, + ASSERT_GT, + ASSERT_GE, + ASSERT_CONTAINS_ALL, + ASSERT_CONTAINS_ANY, + ASSERT_CONTAINS_NOT_ALL, + ASSERT_CONTAINS_NOT_ANY, + ASSERT_IS_IN, + ASSERT_NOT_IN, + ASSERT_NOT_LT, + ASSERT_NOT_LE, + ASSERT_NOT_GT, + ASSERT_NOT_GE +}; + +void test_assert(const char *file, int line, enum assert_type type, enum assert_how how, + const char *have_string, const char *expect_string, const void *have, const void *expect); + +#define ASSERT_EQ_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_EQ, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_NE_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_NE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_LT_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_LT, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_GT_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_GT, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_LE_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_LE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_GE_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_GE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_ALL_OF_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_CONTAINS_ALL, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_SOME_OF_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_CONTAINS_ANY, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_NONE_OF_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_CONTAINS_NOT_ANY, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_NOT_ALL_OF_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_CONTAINS_NOT_ALL, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_IS_IN_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_IS_IN, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_NOT_IN_ENUM(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_ENUM, ASSERT_NOT_IN, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_EQ_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_EQ, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_NE_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_NE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_LT_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_LT, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_GT_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_GT, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_LE_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_LE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_GE_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_GE, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_ALL_OF_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_CONTAINS_ALL, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_SOME_OF_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_CONTAINS_ANY, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_NONE_OF_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_CONTAINS_NOT_ANY, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_CONTAINS_NOT_ALL_OF_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_CONTAINS_NOT_ALL, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_IS_IN_UINT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_UINT, ASSERT_IS_IN, #HAVE, #EXPECT,\ + &(uintmax_t){(uintmax_t)(HAVE)}, &(uintmax_t){(uintmax_t)(EXPECT)}) + +#define ASSERT_EQ_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_EQ, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_NE_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_NE, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_LT_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_LT, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_GT_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_GT, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_LE_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_LE, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_GE_INT(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_INT, ASSERT_GE, #HAVE, #EXPECT,\ + &(intmax_t){(intmax_t)(HAVE)}, &(intmax_t){(intmax_t)(EXPECT)}) + +#define ASSERT_EQ_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_EQ, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_NE_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_STARTS_WITH_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_GE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_EXTENDS_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_GT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_TRUNCATES_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_LT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_BEGINNING_BOUNDED_TO_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_LE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_ENDS_WITH_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_GE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_EXTENDS_END_OF_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_GT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_TRUNCATES_END_OF_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_LT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_ENDING_BOUNDED_TO_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_LE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_STARTS_WITH_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NOT_GE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_EXTENDS_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NOT_GT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_TRUNCATES_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NOT_LT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_BEGINNING_NOT_BOUNDED_TO_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NOT_LE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_ENDS_WITH_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_NOT_GE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_EXTENDS_END_OF_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_NOT_GT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_TRUNCATES_END_OF_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_NOT_LT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_ENDING_NOT_BOUNDED_TO_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR_REV, ASSERT_NOT_LE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_CONTAINS_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_CONTAINS_ALL, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_DOES_NOT_CONTAIN_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_CONTAINS_NOT_ALL, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_IS_IN_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_IS_IN, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_NOT_IN_STR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_STR, ASSERT_NOT_IN, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_IS_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_EQ, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_NOT_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_NE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_BEFORE_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_LT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_AFTER_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_GT, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_BEFORE_OR_IS_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_LE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_AFTER_OR_IS_PTR(HAVE, EXPECT)\ + test_assert(__FILE__, __LINE__, ASSERT_PTR, ASSERT_GE, #HAVE, #EXPECT, (HAVE), (EXPECT)) + +#define ASSERT_IS_NULL(HAVE)\ + test_assert(__FILE__, __LINE__, ASSERT_NULL, ASSERT_EQ, #HAVE, "NULL", (HAVE), NULL) + +#define ASSERT_NOT_NULL(HAVE)\ + test_assert(__FILE__, __LINE__, ASSERT_NULL, ASSERT_NE, #HAVE, "NULL", (HAVE), NULL) + +#define ASSERT_IS_TRUE(HAVE)\ + ASSERT_NE_INT(HAVE, 0) + +#define ASSERT_IS_FALSE(HAVE)\ + ASSERT_EQ_INT(HAVE, 0) + +#define ASSERT_ZERO(HAVE)\ + ASSERT_EQ_INT(HAVE, 0) + +#endif diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f4adf12 --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = +LDFLAGS = diff --git a/liblog.h b/liblog.h new file mode 100644 index 0000000..5e2fad1 --- /dev/null +++ b/liblog.h @@ -0,0 +1,1583 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBLOG_H +#define LIBLOG_H + +#include +#include +#include + + + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wformat-nonliteral" +# pragma clang diagnostic ignored "-Wpadded" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + + +/** + * Mark the message as incomplete an deferred + * printing until LIBLOG_XLOG_UNCORK is used. + */ +#define LIBLOG_XLOG_CORK 0x0001 + +/** + * Output message printed since the first + * LIBLOG_XLOG_CORK (after the last + * LIBLOG_XLOG_UNCORK if any) as one complete + * message. + */ +#define LIBLOG_XLOG_UNCORK 0x0002 + +/** + * Output a backtrace even if the it is not + * configured that backtraces should be printed + * for the selected log level. + */ +#define LIBLOG_XLOG_BACKTRACE 0x0004 + +/** + * Do not output a backtrace even if the it is + * configured that backtraces should be printed + * for the selected log level. + */ +#define LIBLOG_XLOG_NO_BACKTRACE 0x0008 + +/** + * Do not output any new text (apport from potential + * backtrace); allowing `fmt` to be `NULL`. + */ +#define LIBLOG_XLOG_NO_TEXT 0x0010 + + +/** + * Opaque data type for the internal state + * of a `struct liblog_context` + */ +struct liblog_context_internal_state; + +/** + * Log levels + */ +enum liblog_level { + /** + * System is unusable + */ + LIBLOG_EMERGENCY = 0, + + /** + * Action must be taken immediately + */ + LIBLOG_ALERT = 100, + + /** + * Critical condition + */ + LIBLOG_CRITICAL = 200, + + /** + * Error condition + */ + LIBLOG_ERROR = 300, + + /** + * Warning condition + */ + LIBLOG_WARNING = 400, + + /** + * Normal, but significant, condition + */ + LIBLOG_NOTICE = 500, + + /** + * Informational message + */ + LIBLOG_INFO = 600, + + /** + * Less verbose debug-level message: what is happening on a high level + */ + LIBLOG_TRACE = 700, + + /** + * More verbose debug-level message: detailed information about what is going on + */ + LIBLOG_DEBUG = 800 +}; + +/** + * Log channel types + */ +enum liblog_sink { + /** + * Output to syslog + */ + LIBLOG_SYSLOG, + + /** + * Output to a file descriptor + */ + LIBLOG_FILE, + + /** + * Output to a `FILE` + */ + LIBLOG_STREAM +}; + +/** + * Log output configurations; mapping of log levels to log channels + * + * Destroy with `liblog_destroy_output` if destroying manually + */ +struct liblog_output { + /** + * User defined data + * + * This could for example be a path name to the output + * file so that the application knows which file that + * should be subject to rotation when online log rotation + * is performed + */ + void *userdata; + + /** + * The prefix for each log line + * + * A string where the following special symbols will be replaced + * - %{ltime: %} span that marks formatting of the current local time with strftime(3) + * - %{utime: %} span that marks formatting of the current UTC time with strftime(3) + * - %[nano] the nanoseconds of the current time, printed with 9 digits + * - %[micro] the microseconds of the current time, printed with 6 digits + * - %[milli] the milliseconds of the current time, printed with 3 digits + * - %[centi] the centiseconds of the current time, printed with 2 digits + * - %[deci] the deciseconds of the current time, printed with 1 digit + * - %[function] function where the log message is being printed from + * - %[file] file where the log message is being printed from + * - %[line] line in file where the log message is being printed from + * - %[level] log level for the message rounded down to a predefined value + * (printed as string) + * - %[xlevel] the exact log level for the message, printed as the name of + * of the log level rounded down to a predfined value, followed + * by an adjustment + * - %[tid] the process's thread ID + * - %[pid] the process's thread group ID (process ID) + * - %[ppid] the process's parent process ID + * - %[pgid] the process's process group ID + * - %[sid] the process's session ID + * - %[uid] the real user ID of the process + * - %[euid] the effective user ID of the process + * - %[gid] the real group ID of the process + * - %[egid] the effective group ID of the process + * - %[name] the name of process + * - %[argv0] the value of the global `const char *argv0` + * - %% a literal % + * + * If `NULL`, this with be replace with a default format + */ + const char *prefixfmt; + + /** + * If set `.lowest_verbosity` is treated as set to + * the lowest possible value + */ + unsigned lowest_verbosity_unlimited : 1; + + /** + * If set `.higest_verbosity` is treated as set to + * the highest possible value + */ + unsigned highest_verbosity_unlimited : 1; + + /** + * If set, each log message will be prefixed with + * a backtrace + */ + unsigned use_backtrace : 1; + + unsigned : 0; + + /** + * The lowest log level, in regards to verbosity + * but higest in regard to criticality, for which + * this log output channel shall be used + * + * Must not be greater than `.highest_verbosity` + */ + enum liblog_level lowest_verbosity; + + /** + * The higest log level, in regards to verbosity + * but lowest in regard to criticality, for which + * this log output channel shall be used + * + * Must not be less than `.lowest_verbosity` + */ + enum liblog_level highest_verbosity; + + /** + * The output channel type + */ + enum liblog_sink sink_type; + + /** + * The output channel + */ + union { + /** + * Used when `.sink_type` is `LIBLOG_SYSLOG` + * + * The application is responsible for opening and closing syslog + */ + struct { + /** + * The syslog log level to use + */ + int level; + } syslog; + + /** + * Used when `.sink_type` is `LIBLOG_FILE` + */ + struct { + /** + * The file descriptor to write to + */ + int fd; + + /** + * Whether the library shall close the file descriptor + * when destroying the `struct liblog_output` object + */ + unsigned owns_fd : 1; + } file; + + /** + * Used when `.sink_type` is `LIBLOG_STREAM` + */ + struct { + /** + * The stream to write to + */ + FILE *stream; + + /** + * Whether the library shall close the stream + * when destroying the `struct liblog_output` object + */ + unsigned owns_stream : 1; + } stream; + } sink; +}; + +/** + * Logging configurations and state + * + * Initialise with `liblog_init_context`, and then + * configure output using any of the follow functions: + * - liblog_use_fd + * - liblog_use_fd_for_range + * - liblog_use_file + * - liblog_use_file_for_range + * - liblog_use_stderr + * - liblog_use_stderr_for_range + * - liblog_use_stream + * - liblog_use_stream_for_range + * - liblog_use_syslog + * - liblog_use_syslog_for_range + * - liblog_use_output + * + * Destroy with `liblog_destroy_context` + */ +struct liblog_context { + /** + * Opaque state + */ + struct liblog_context_internal_state *internal_state; + + /** + * Log output configurations; mapping of log levels to log channels + */ + struct liblog_output *outputs; + + /** + * Number of elements in noutputs + */ + size_t noutputs; + + /** + * Mask of log level groups to exclude when logging + */ + unsigned logmask; +}; +/* TODO add multithreading support */ + + + +/* for internal use { */ +#define LIBLOG_VA__(FUNC, ...)\ + int ret;\ + va_list args;\ + va_start(args, fmt);\ + ret = FUNC(__VA_ARGS__, args);\ + va_end(args);\ + return ret + +#define LIBLOG_OUTPUT_UNRANGED__(...)\ + (&(struct liblog_output){\ + .userdata = NULL,\ + .prefixfmt = prefixfmt,\ + .lowest_verbosity_unlimited = 1U,\ + .highest_verbosity_unlimited = 1U,\ + .use_backtrace = (use_backtrace ? 1U : 0U),\ + __VA_ARGS__\ + }) + +#define LIBLOG_OUTPUT_RANGED__(...)\ + (&(struct liblog_output){\ + .userdata = NULL,\ + .prefixfmt = prefixfmt,\ + .lowest_verbosity_unlimited = 0U,\ + .highest_verbosity_unlimited = 0U,\ + .use_backtrace = (use_backtrace ? 1U : 0U),\ + .lowest_verbosity = least_verbose,\ + .highest_verbosity = most_verbose,\ + __VA_ARGS__\ + }) + +#if defined(__clang__) +# define LIBLOG_PRINTF__(FMTIDX) __attribute__((__format__(__printf__, (FMTIDX), (FMTIDX) + 1))) +# define LIBLOG_VPRINTF__(FMTIDX) __attribute__((__format__(__printf__, (FMTIDX), 0))) +#elif defined(__GNUC__) +# define LIBLOG_PRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), (FMTIDX) + 1))) +# define LIBLOG_VPRINTF__(FMTIDX) __attribute__((__format__(__gnu_printf__, (FMTIDX), 0))) +#else +# define LIBLOG_PRINTF__(FMTIDX) +# define LIBLOG_VPRINTF__(FMTIDX) +#endif + +#if defined(__GNUC__) +# define LIBLOG_CONST__ __attribute__((__const__)) +#else +# define LIBLOG_CONST__ +#endif + +LIBLOG_CONST__ unsigned liblog_logmask__(enum liblog_level least_verbose, enum liblog_level most_verbose); +/* } */ + + + +/** + * Initialise a `struct liblog_context` + * + * @param ctx That object to initialise + * @return 0 on success, -1 on failure + */ +int liblog_init_context(struct liblog_context *ctx); + +/** + * Destroy a `struct liblog_context` + * + * @param ctx That object to destroy + * @return 0 on success, -1 on failure (object will + * still be completely destroyed) + */ +int liblog_destroy_context(struct liblog_context *ctx); + +/** + * Destroy a `struct liblog_output` + * + * @param output That object to destroy + * @return 0 on success, -1 on failure (object will + * still be completely destroyed) + */ +int liblog_destroy_output(struct liblog_output *output); + + +/** + * Remove log level mask, causing all log messages, that + * have an output configured, to be printed + * + * @param ctx Logging configurations and state + */ +inline void +liblog_clear_mask(struct liblog_context *ctx) +{ if (ctx) ctx->logmask = 0U; } + +/** + * Apply log level mask that is configured in the + * process's environment variable "LIBLOG_LOGMASK" + * + * This is done automatically by `liblog_init_context` + * + * If the LIBLOG_LOGMASK environment variable is + * unset or empty, anything more verbose than a + * some specific level (currently `LIBLOG_WARNING`) + * will be filtered. + * + * @param ctx Logging configurations and state + */ +void liblog_apply_env_mask(struct liblog_context *ctx); + +/** + * Stop log messages within a certain range of + * log levels from being printed + * + * @param ctx Logging configurations and state + * @param least_verbose The lowest (least verbose, most critical) log level + * to filter out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + * @param most_verbose The highest (most verbose, least critical) log level + * to filter out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + * + * This function has no effect if, after rounding, `least_verbose > most_verbose` + */ +inline void +liblog_mask_range(struct liblog_context *ctx, enum liblog_level least_verbose, enum liblog_level most_verbose) +{ if (ctx) ctx->logmask |= liblog_logmask__(least_verbose, most_verbose); } + +/** + * Stop log messages with a certain log level or + * higher (more verbose, less critical) from being printed + * + * @param ctx Logging configurations and state + * @param least The lowest (least verbose, most critical) log level to + * filter out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + */ +inline void +liblog_mask_verbose(struct liblog_context *ctx, enum liblog_level least) +{ liblog_mask_range(ctx, least, LIBLOG_DEBUG); } + +/** + * Stop log messages with a certain log level group + * (all levels up to but excluding the next predefined + * log level) from being printed + * + * @param ctx Logging configurations and state + * @param group The log level to filter out; will be rounded + * up or down (unspecified which) to the closest + * predefined log level value + */ +inline void +liblog_mask_level(struct liblog_context *ctx, enum liblog_level group) +{ liblog_mask_range(ctx, group, group); } + +/** + * Stop filtering out log messages within a certain + * range of log levels from being printed + * + * @param ctx Logging configurations and state + * @param least_verbose The lowest (least verbose, most critical) log level to + * stop filtering out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + * @param most_verbose The highest (most verbose, least critical) log level to + * filtering out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + * + * This function has no effect if, after rounding, `least_verbose > most_verbose` + */ +inline void +liblog_unmask_range(struct liblog_context *ctx, enum liblog_level least_verbose, enum liblog_level most_verbose) +{ if (ctx) ctx->logmask &= ~liblog_logmask__(least_verbose, most_verbose); } + +/** + * Stop filtering out log messages with a certain log level or + * higher (more verbose, less critical) from being printed + * + * @param ctx Logging configurations and state + * @param least The lowest (least verbose, most critical) log level to + * stop filtering out; will be rounded up or down (unspecified + * which) to the closest predefined log level value + */ +inline void +liblog_unmask_verbose(struct liblog_context *ctx, enum liblog_level least) +{ liblog_unmask_range(ctx, least, LIBLOG_DEBUG); } + +/** + * Stop filtering out log messages with a certain log level + * group (all levels up to but excluding the next predefined + * log level) from being printed + * + * @param ctx Logging configurations and state + * @param group The log level to stop filtering out; will be + * rounded up or down (unspecified which) to the + * closest predefined log level value + */ +inline void +liblog_unmask_level(struct liblog_context *ctx, enum liblog_level group) +{ liblog_unmask_range(ctx, group, group); } + + +/** + * Add a log output + * + * @param ctx Logging configurations and state + * @param output The configurations for the additional output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +struct liblog_output *liblog_use_output(struct liblog_context *ctx, const struct liblog_output *output); + +/** + * Set up logging with syslog(3) + * + * @param ctx Logging configurations and state + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @return 0 on success, -1 on failure + * + * This function adds multi new output configurations to `ctx` + */ +int liblog_use_syslog(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace); + +/** + * Set up logging with syslog(3) + * + * @param ctx Logging configurations and state + * @param syslog_level The syslog(3) log level that shall be used + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_syslog_for_range(struct liblog_context *ctx, int syslog_level, const char *prefixfmt, int use_backtrace, + enum liblog_level least_verbose, enum liblog_level most_verbose) +{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_SYSLOG, .sink.syslog = {syslog_level})); } + +/** + * Set up logging to a file descriptor + * + * @param ctx Logging configurations and state + * @param fd The file descriptor to log to + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_fd(struct liblog_context *ctx, int fd, const char *prefixfmt, int use_backtrace) +{ return liblog_use_output(ctx, LIBLOG_OUTPUT_UNRANGED__(.sink_type = LIBLOG_FILE, .sink.file = {fd, 0})); } + +/** + * Set up logging to a file descriptor + * + * @param ctx Logging configurations and state + * @param fd The file descriptor to log to + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_fd_for_range(struct liblog_context *ctx, int fd, const char *prefixfmt, int use_backtrace, + enum liblog_level least_verbose, enum liblog_level most_verbose) +{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_FILE, .sink.file = {fd, 0})); } + +/** + * Set up logging to an output stream + * + * @param ctx Logging configurations and state + * @param stream The stream to log to + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_stream(struct liblog_context *ctx, FILE *stream, const char *prefixfmt, int use_backtrace) +{ return liblog_use_output(ctx, LIBLOG_OUTPUT_UNRANGED__(.sink_type = LIBLOG_STREAM, .sink.stream = {stream, 0})); } + +/** + * Set up logging to an output stream + * + * @param ctx Logging configurations and state + * @param stream The stream to log to + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_stream_for_range(struct liblog_context *ctx, FILE *stream, const char *prefixfmt, int use_backtrace, + enum liblog_level least_verbose, enum liblog_level most_verbose) +{ return liblog_use_output(ctx, LIBLOG_OUTPUT_RANGED__(.sink_type = LIBLOG_STREAM, .sink.stream = {stream, 0})); } + +/** + * Set up logging to a file + * + * @param ctx Logging configurations and state + * @param dirfd File descriptor to the directory `path` is relative to if + * it is a relative path, or -1 to for the path to be absolute, + * failing with EINVAL if it is relative); AT_FDCWD for the + * current working directory + * @param path The path of the file to write to, if `NULL` or `""` + * dirfd will be used as the file descriptor to write to; + * if the file exists, it is opened in append mode, otherwise + * it is created to readable by every user but only writable + * by the current user + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +struct liblog_output *liblog_use_file(struct liblog_context *ctx, int dirfd, const char *path, + const char *prefixfmt, int use_backtrace); + +/** + * Set up logging to a file + * + * @param ctx Logging configurations and state + * @param dirfd File descriptor to the directory `path` is relative to if + * it is a relative path, or -1 to for the path to be absolute, + * failing with EINVAL if it is relative); AT_FDCWD for the + * current working directory + * @param path The path of the file to write to, if `NULL` or `""` + * dirfd will be used as the file descriptor to write to; + * if the file exists, it is opened in append mode, otherwise + * it is created to readable by every user but only writable + * by the current user + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +struct liblog_output *liblog_use_file_for_range(struct liblog_context *ctx, int dirfd, const char *path, + const char *prefixfmt, int use_backtrace, + enum liblog_level least_verbose, enum liblog_level most_verbose); + +/** + * Set up logging to the standard output + * + * @param ctx Logging configurations and state + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_stderr(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace) +{ return liblog_use_fd(ctx, 2, prefixfmt, use_backtrace); } + +/** + * Set up logging to the standard output + * + * @param ctx Logging configurations and state + * @param prefixfmt See `.prefixfmt` in `struct liblog_output` + * @param use_backtrace Whether each log message should be prefix with a log backtrace + * @param least_verbose Lower (in regard to verbosity, upper in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @param most_verbose Upper (in regard to verbosity, lower in regards to criticality), + * inclusive bound for the range liblog log level for which log + * messages should be output to the new output + * @return The new output configuration (this is an object + * owned by `ctx` and should not be deallocated, + * it is returned so that changes can be made) + * on success, `NULL` on failure + */ +inline struct liblog_output * +liblog_use_stderr_for_range(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace, + enum liblog_level least_verbose, enum liblog_level most_verbose) +{ return liblog_use_fd_for_range(ctx, 2, prefixfmt, use_backtrace, least_verbose, most_verbose); } + + +/** + * Write a log message with a custom log level + * + * This function's behaviour is customisable + * using its `flags` parameter + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param flags Modifications the the function's behaviour; + * may be 0 or the OR of any of the following values: + * - LIBLOG_XLOG_CORK: + * Mark the message as incomplete an deferred + * printing until LIBLOG_XLOG_UNCORK is used. + * - LIBLOG_XLOG_UNCORK: + * Output message printed since the first + * LIBLOG_XLOG_CORK (after the last + * LIBLOG_XLOG_UNCORK if any) as one complete + * message. + * - LIBLOG_XLOG_BACKTRACE: + * Output a backtrace even if the it is not + * configured that backtraces should be printed + * for the selected log level. + * - LIBLOG_XLOG_NO_BACKTRACE: + * Do not output a backtrace even if the it is + * configured that backtraces should be printed + * for the selected log level. + * - LIBLOG_XLOG_NO_TEXT: + * Do not output any new text (apport from potential + * backtrace); allowing `fmt` to be `NULL`. + * However, LIBLOG_XLOG_CORK and LIBLOG_XLOG_UNCORK + * cannot be combined, nor can LIBLOG_XLOG_BACKTRACE + * and LIBLOG_XLOG_NO_BACKTRACE be combined + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(4) int +liblog_vxlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, va_list args); + +/** + * Write a log message with a custom log level + * + * This function's behaviour is customisable + * using its `flags` parameter + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param flags Modifications the the function's behaviour; + * may be 0 or the OR of any of the following values: + * - LIBLOG_XLOG_CORK: + * Mark the message as incomplete an deferred + * printing until LIBLOG_XLOG_UNCORK is used + * - LIBLOG_XLOG_UNCORK: + * Output message printed since the first + * LIBLOG_XLOG_CORK (after the last + * LIBLOG_XLOG_UNCORK if any) as one complete + * message + * - LIBLOG_XLOG_BACKTRACE: + * Output a backtrace even if the it is not + * configured that backtraces should be printed + * for the selected log level + * - LIBLOG_XLOG_NO_BACKTRACE: + * Do not output a backtrace even if the it is + * configured that backtraces should be printed + * for the selected log level + * - LIBLOG_XLOG_NO_TEXT: + * Do not output any new text (apport from potential + * backtrace); allowing `fmt` to be `NULL`. + * However, LIBLOG_XLOG_CORK and LIBLOG_XLOG_UNCORK + * cannot be combined, nor can LIBLOG_XLOG_BACKTRACE + * and LIBLOG_XLOG_NO_BACKTRACE be combined + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(4) inline int +liblog_xlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, flags, fmt); } + + +/** + * If there is an incomplete log message being constructed, + * terminate it and print it + * + * @param ctx Logging configurations and state + * @return 0 on success, -1 on failure + * + * @seealso liblog_xlog + * @seealso liblog_dump_backtrace_cork + * @seealso liblog_log_cork + * @seealso liblog_log_no_backtrace_cork + * @seealso liblog_emergency_cork + * @seealso liblog_alert_cork + * @seealso liblog_critical_cork + * @seealso liblog_error_cork + * @seealso liblog_warning_cork + * @seealso liblog_notice_cork + * @seealso liblog_info_cork + * @seealso liblog_trace_cork + * @seealso liblog_debug_cork + */ +inline int +liblog_uncork(struct liblog_context *ctx) +{ return liblog_xlog(ctx, 0, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_UNCORK, NULL); } + + +/** + * Write the backtrace as a log message with a custom log level + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @return 0 on success, -1 on failure + */ +inline int +liblog_dump_backtrace(struct liblog_context *ctx, enum liblog_level level) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT, NULL); } + +/** + * Write the backtrace as a log message with a custom log level + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * The backtrace will be terminated by a new line + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @return 0 on success, -1 on failure + */ +inline int +liblog_dump_backtrace_cork(struct liblog_context *ctx, enum liblog_level level) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_CORK, NULL); } + + +/** + * Write a log message with a custom log level + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(3) inline int +liblog_vlog(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, 0, fmt, args); } + +/** + * Write a log message with a custom log level + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(3) inline int +liblog_log(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vlog, ctx, level, fmt); } + +/** + * Write a log message with a custom log level + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(3) inline int +liblog_vlog_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_CORK, fmt, args); } + +/** + * Write a log message with a custom log level + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(3) inline int +liblog_log_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vlog_cork, ctx, level, fmt); } + + +/** + * Write a log message with a custom log level + * + * Even if configured that backtraces should be printed for the + * the specificed log level, no backtrace will be printed + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(3) inline int +liblog_vlog_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE, fmt, args); } + +/** + * Write a log message with a custom log level + * + * Even if configured that backtraces should be printed for the + * the specificed log level, no backtrace will be printed + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(3) inline int +liblog_log_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vlog_no_backtrace, ctx, level, fmt); } + +/** + * Write a log message with a custom log level + * + * Even if configured that backtraces should be printed for the + * the specificed log level, no backtrace will be printed + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(3) inline int +liblog_vlog_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_CORK, fmt, args); } + +/** + * Write a log message with a custom log level + * + * Even if configured that backtraces should be printed for the + * the specificed log level, no backtrace will be printed + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param level The log level for the message; does not have to + * be predefined in `enum liblog_level` + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(3) inline int +liblog_log_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vlog_no_backtrace_cork, ctx, level, fmt); } + + +/* Everything from this point onwards is just for convenience */ + + +/** + * Write a log message with log level `LIBLOG_EMERGENCY` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vemergency(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_EMERGENCY, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_EMERGENCY` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_emergency(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vemergency, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_EMERGENCY` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vemergency_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_EMERGENCY, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_EMERGENCY` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_emergency_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vemergency_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_ALERT` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_valert(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_ALERT, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_ALERT` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_alert(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_valert, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_ALERT` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_valert_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_ALERT, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_ALERT` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_alert_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_valert_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_CRITICAL` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vcritical(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_CRITICAL, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_CRITICAL` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_critical(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vcritical, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_CRITICAL` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vcritical_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_CRITICAL, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_CRITICAL` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_critical_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vcritical_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_ERROR` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_verror(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_ERROR, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_ERROR` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_error(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_verror, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_ERROR` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_verror_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_ERROR, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_ERROR` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_error_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_verror_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_WARNING` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vwarning(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_WARNING, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_WARNING` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_warning(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vwarning, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_WARNING` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vwarning_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_WARNING, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_WARNING` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_warning_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vwarning_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_NOTICE` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vnotice(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_NOTICE, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_NOTICE` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_notice(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vnotice, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_NOTICE` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vnotice_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_NOTICE, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_NOTICE` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_notice_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vnotice_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_INFO` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vinfo(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_INFO, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_INFO` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_info(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vinfo, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_INFO` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vinfo_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_INFO, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_INFO` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_info_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vinfo_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_TRACE` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vtrace(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_TRACE, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_TRACE` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_trace(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vtrace, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_TRACE` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vtrace_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_TRACE, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_TRACE` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_trace_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vtrace_cork, ctx, fmt); } + + +/** + * Write a log message with log level `LIBLOG_DEBUG` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vdebug(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog(ctx, LIBLOG_DEBUG, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_DEBUG` + * + * The log message is printed immediately as one complete log message + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_debug(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vdebug, ctx, fmt); } + +/** + * Write a log message with log level `LIBLOG_DEBUG` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param args Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_VPRINTF__(2) inline int +liblog_vdebug_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vlog_cork(ctx, LIBLOG_DEBUG, fmt, args); } + +/** + * Write a log message with log level `LIBLOG_DEBUG` + * + * The log message is treated as incomplete, and can be extended using + * any log message writing function using the same `ctx`, and will be + * printed once `liblog_uncork` is called using the same `ctx` + * + * @param ctx Logging configurations and state + * @param fmt printf(3) format string for the log message + * @param ... Arguments for `fmt` + * @return 0 on success, -1 on failure + */ +LIBLOG_PRINTF__(2) inline int +liblog_debug_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vdebug_cork, ctx, fmt); } + + + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + +#endif diff --git a/liblog_alert.c b/liblog_alert.c new file mode 100644 index 0000000..ef0412c --- /dev/null +++ b/liblog_alert.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_alert(struct liblog_context *, const char *, ...); + +# else +# define liblog_alert liblog__dont_want__ +# include "common.h" +# undef liblog_alert + +LIBLOG_PRINTF__(2) int +liblog_alert(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_ALERT, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-alert.h" +# include "test-level.c" +#endif diff --git a/liblog_alert_cork.c b/liblog_alert_cork.c new file mode 100644 index 0000000..4583d9b --- /dev/null +++ b/liblog_alert_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_alert_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_alert_cork liblog__dont_want__ +# include "common.h" +# undef liblog_alert_cork + +LIBLOG_PRINTF__(2) int +liblog_alert_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_ALERT, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-alert.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_apply_env_mask.c b/liblog_apply_env_mask.c new file mode 100644 index 0000000..1fceae0 --- /dev/null +++ b/liblog_apply_env_mask.c @@ -0,0 +1,22 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +void +liblog_apply_env_mask(struct liblog_context *ctx) +{ + const char *env = getenv("LIBLOG_LOGMASK"); + + if (*env || !*env) { + liblog_mask_verbose(ctx, NEXT_LOGLEVEL(LIBLOG_WARNING)); + return; + } + + /* TODO implement and document format */ +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_clear_mask.c b/liblog_clear_mask.c new file mode 100644 index 0000000..4bd27ce --- /dev/null +++ b/liblog_clear_mask.c @@ -0,0 +1,29 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_clear_mask(struct liblog_context *); + +#else + +int +main(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_clear_mask(&ctx); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 1U; + liblog_clear_mask(&ctx); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_clear_mask(&ctx); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + return 0; +} + +#endif diff --git a/liblog_critical.c b/liblog_critical.c new file mode 100644 index 0000000..c35dee9 --- /dev/null +++ b/liblog_critical.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_critical(struct liblog_context *, const char *, ...); + +# else +# define liblog_critical liblog__dont_want__ +# include "common.h" +# undef liblog_critical + +LIBLOG_PRINTF__(2) int +liblog_critical(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_CRITICAL, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-critical.h" +# include "test-level.c" +#endif diff --git a/liblog_critical_cork.c b/liblog_critical_cork.c new file mode 100644 index 0000000..61547df --- /dev/null +++ b/liblog_critical_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_critical_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_critical_cork liblog__dont_want__ +# include "common.h" +# undef liblog_critical_cork + +LIBLOG_PRINTF__(2) int +liblog_critical_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_CRITICAL, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-critical.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_debug.c b/liblog_debug.c new file mode 100644 index 0000000..b91b4bb --- /dev/null +++ b/liblog_debug.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_debug(struct liblog_context *, const char *, ...); + +# else +# define liblog_debug liblog__dont_want__ +# include "common.h" +# undef liblog_debug + +LIBLOG_PRINTF__(2) int +liblog_debug(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_DEBUG, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-debug.h" +# include "test-level.c" +#endif diff --git a/liblog_debug_cork.c b/liblog_debug_cork.c new file mode 100644 index 0000000..adac9a9 --- /dev/null +++ b/liblog_debug_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_debug_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_debug_cork liblog__dont_want__ +# include "common.h" +# undef liblog_debug_cork + +LIBLOG_PRINTF__(2) int +liblog_debug_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_DEBUG, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-debug.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_destroy_context.c b/liblog_destroy_context.c new file mode 100644 index 0000000..57192ac --- /dev/null +++ b/liblog_destroy_context.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +int +liblog_destroy_context(struct liblog_context *ctx) +{ + int ret = 0; + + if (!ctx) + return 0; + + while (ctx->noutputs) + ret |= liblog_destroy_output(&ctx->outputs[--ctx->noutputs]); + free(ctx->outputs); + ctx->outputs = NULL; + + if (ctx->internal_state) { + free(ctx->internal_state->msg.prefix); + free(ctx->internal_state->msg.text); + free(ctx->internal_state); + ctx->internal_state = NULL; + } + + return ret; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_destroy_output.c b/liblog_destroy_output.c new file mode 100644 index 0000000..98bb2dd --- /dev/null +++ b/liblog_destroy_output.c @@ -0,0 +1,40 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +int +liblog_destroy_output(struct liblog_output *output) +{ + int saved_errno = 0; /* initialised to silence false warning */ + int ret = 0; + + if (!output) + return 0; + + if (output->sink_type == LIBLOG_FILE && output->sink.file.owns_fd) { + saved_errno = errno; + ret = close(output->sink.file.fd); + output->sink.file.fd = -1; + } else if (output->sink_type == LIBLOG_STREAM && output->sink.stream.owns_stream) { + saved_errno = errno; + ret = fclose(output->sink.stream.stream); + output->sink.stream.stream = NULL; +#if EOF != -1 + if (ret == EOF) + ret = -1; +#endif + } + + if (ret && errno != EINTR) { + ret = 0; + errno = saved_errno; + } + + return ret; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_dump_backtrace.c b/liblog_dump_backtrace.c new file mode 100644 index 0000000..54af846 --- /dev/null +++ b/liblog_dump_backtrace.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_dump_backtrace(struct liblog_context *, enum liblog_level); + +# else +# define liblog_dump_backtrace liblog__dont_want__ +# include "common.h" +# undef liblog_dump_backtrace + +int +liblog_dump_backtrace(struct liblog_context *ctx, enum liblog_level level) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT | XLOG_NOT_INLINE, NULL); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_dump_backtrace_cork.c b/liblog_dump_backtrace_cork.c new file mode 100644 index 0000000..b44b4f1 --- /dev/null +++ b/liblog_dump_backtrace_cork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_dump_backtrace_cork(struct liblog_context *, enum liblog_level); + +# else +# define liblog_dump_backtrace_cork liblog__dont_want__ +# include "common.h" +# undef liblog_dump_backtrace_cork + +int +liblog_dump_backtrace_cork(struct liblog_context *ctx, enum liblog_level level) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, NULL); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_emergency.c b/liblog_emergency.c new file mode 100644 index 0000000..1ae80fa --- /dev/null +++ b/liblog_emergency.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_emergency(struct liblog_context *, const char *, ...); + +# else +# define liblog_emergency liblog__dont_want__ +# include "common.h" +# undef liblog_emergency + +LIBLOG_PRINTF__(2) int +liblog_emergency(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_EMERGENCY, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-emergency.h" +# include "test-level.c" +#endif diff --git a/liblog_emergency_cork.c b/liblog_emergency_cork.c new file mode 100644 index 0000000..34f36d7 --- /dev/null +++ b/liblog_emergency_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_emergency_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_emergency_cork liblog__dont_want__ +# include "common.h" +# undef liblog_emergency_cork + +LIBLOG_PRINTF__(2) int +liblog_emergency_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_EMERGENCY, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-emergency.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_error.c b/liblog_error.c new file mode 100644 index 0000000..e1bc858 --- /dev/null +++ b/liblog_error.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_error(struct liblog_context *, const char *, ...); + +# else +# define liblog_error liblog__dont_want__ +# include "common.h" +# undef liblog_error + +LIBLOG_PRINTF__(2) int +liblog_error(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_ERROR, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-error.h" +# include "test-level.c" +#endif diff --git a/liblog_error_cork.c b/liblog_error_cork.c new file mode 100644 index 0000000..9ffa96c --- /dev/null +++ b/liblog_error_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_error_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_error_cork liblog__dont_want__ +# include "common.h" +# undef liblog_error_cork + +LIBLOG_PRINTF__(2) int +liblog_error_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_ERROR, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-error.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_flush__.c b/liblog_flush__.c new file mode 100644 index 0000000..a0a1cb2 --- /dev/null +++ b/liblog_flush__.c @@ -0,0 +1,18 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +__attribute__((__const__)) +int +liblog_flush__(struct liblog_context *ctx, const struct messagebuf *msg) /* TODO impl */ +{ + (void) ctx; + (void) msg; + return 0; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_info.c b/liblog_info.c new file mode 100644 index 0000000..9bf301f --- /dev/null +++ b/liblog_info.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_info(struct liblog_context *, const char *, ...); + +# else +# define liblog_info liblog__dont_want__ +# include "common.h" +# undef liblog_info + +LIBLOG_PRINTF__(2) int +liblog_info(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_INFO, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-info.h" +# include "test-level.c" +#endif diff --git a/liblog_info_cork.c b/liblog_info_cork.c new file mode 100644 index 0000000..83f8969 --- /dev/null +++ b/liblog_info_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_info_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_info_cork liblog__dont_want__ +# include "common.h" +# undef liblog_info_cork + +LIBLOG_PRINTF__(2) int +liblog_info_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_INFO, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-info.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_init_context.c b/liblog_init_context.c new file mode 100644 index 0000000..0137248 --- /dev/null +++ b/liblog_init_context.c @@ -0,0 +1,24 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +int +liblog_init_context(struct liblog_context *ctx) +{ + if (!ctx) { + errno = EINVAL; + return -1; + } + ctx->internal_state = NULL; + ctx->outputs = NULL; + ctx->noutputs = 0; + ctx->logmask = 0; + liblog_apply_env_mask(ctx); + return 0; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_log.c b/liblog_log.c new file mode 100644 index 0000000..5601736 --- /dev/null +++ b/liblog_log.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_log(struct liblog_context *, enum liblog_level, const char *, ...); + +# else +# define liblog_log liblog__dont_want__ +# include "common.h" +# undef liblog_log + +LIBLOG_PRINTF__(3) int +liblog_log(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_log_cork.c b/liblog_log_cork.c new file mode 100644 index 0000000..09f8f73 --- /dev/null +++ b/liblog_log_cork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_log_cork(struct liblog_context *, enum liblog_level, const char *, ...); + +# else +# define liblog_log_cork liblog__dont_want__ +# include "common.h" +# undef liblog_log_cork + +LIBLOG_PRINTF__(3) int +liblog_log_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_log_no_backtrace.c b/liblog_log_no_backtrace.c new file mode 100644 index 0000000..0767a3f --- /dev/null +++ b/liblog_log_no_backtrace.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_log_no_backtrace(struct liblog_context *, enum liblog_level, const char *, ...); + +# else +# define liblog_log_no_backtrace liblog__dont_want__ +# include "common.h" +# undef liblog_log_no_backtrace + +LIBLOG_PRINTF__(3) int +liblog_log_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, LIBLOG_XLOG_NO_BACKTRACE | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_log_no_backtrace_cork.c b/liblog_log_no_backtrace_cork.c new file mode 100644 index 0000000..25e5223 --- /dev/null +++ b/liblog_log_no_backtrace_cork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_log_no_backtrace_cork(struct liblog_context *, enum liblog_level, const char *, ...); + +# else +# define liblog_log_no_backtrace_cork liblog__dont_want__ +# include "common.h" +# undef liblog_log_no_backtrace_cork + +LIBLOG_PRINTF__(3) int +liblog_log_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_logmask__.c b/liblog_logmask__.c new file mode 100644 index 0000000..2a55850 --- /dev/null +++ b/liblog_logmask__.c @@ -0,0 +1,198 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +unsigned +liblog_logmask__(enum liblog_level least_verbose, enum liblog_level most_verbose) +{ + unsigned min, max; + + least_verbose = MAX(least_verbose, 0); + least_verbose = MIN(least_verbose, LIBLOG_DEBUG); + most_verbose = MAX(most_verbose, 0); + most_verbose = MIN(most_verbose, LIBLOG_DEBUG); + + min = (unsigned)least_verbose / (unsigned)NEXT_LOGLEVEL(0); + max = (unsigned)most_verbose / (unsigned)NEXT_LOGLEVEL(0); + + if (min > max) + return 0; + + min = 1U << min; + max = 2U << max; + return (max - 1U) ^ (min - 1U); +} + +#else + +static void +check_singletons(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_EMERGENCY), 0x0001); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_ALERT), 0x0002); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_CRITICAL), 0x0004); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_ERROR), 0x0008); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_WARNING), 0x0010); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_NOTICE), 0x0020); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_INFO), 0x0040); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_TRACE), 0x0080); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_DEBUG), 0x0100); +} + +static void +check_custom(void) +{ + unsigned logmask = liblog_logmask__(LIBLOG_NOTICE + 1, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(logmask == 0x0020 || logmask == 0x0040); +} + +static void +check_from_emergency(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_ALERT), 0x0003U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_CRITICAL), 0x0007U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_ERROR), 0x000FU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_WARNING), 0x001FU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_NOTICE), 0x003FU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_INFO), 0x007FU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_TRACE), 0x00FFU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_EMERGENCY, LIBLOG_DEBUG), 0x01FFU); +} + +static void +check_from_alert(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_CRITICAL), 0x0006U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_ERROR), 0x000EU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_WARNING), 0x001EU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_NOTICE), 0x003EU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_INFO), 0x007EU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_TRACE), 0x00FEU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ALERT, LIBLOG_DEBUG), 0x01FEU); +} + +static void +check_from_critical(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_ERROR), 0x000CU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_WARNING), 0x001CU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_NOTICE), 0x003CU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_INFO), 0x007CU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_TRACE), 0x00FCU); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_CRITICAL, LIBLOG_DEBUG), 0x01FCU); +} + +static void +check_from_error(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_WARNING), 0x0018U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_NOTICE), 0x0038U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_INFO), 0x0078U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_TRACE), 0x00F8U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_ERROR, LIBLOG_DEBUG), 0x01F8U); +} + +static void +check_from_warning(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_ERROR), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_NOTICE), 0x0030U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_INFO), 0x0070U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_TRACE), 0x00F0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_WARNING, LIBLOG_DEBUG), 0x01F0U); +} + +static void +check_from_notice(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_ERROR), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_WARNING), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_INFO), 0x0060U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_TRACE), 0x00E0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_NOTICE, LIBLOG_DEBUG), 0x01E0U); +} + +static void +check_from_info(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_ERROR), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_WARNING), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_NOTICE), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_TRACE), 0x00C0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_INFO, LIBLOG_DEBUG), 0x01C0U); +} + +static void +check_from_trace(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_ERROR), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_WARNING), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_NOTICE), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_INFO), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_TRACE, LIBLOG_DEBUG), 0x0180U); +} + +static void +check_from_debug(void) +{ + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_EMERGENCY), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_ALERT), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_CRITICAL), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_ERROR), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_WARNING), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_NOTICE), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_INFO), 0U); + ASSERT_EQ_UINT(liblog_logmask__(LIBLOG_DEBUG, LIBLOG_TRACE), 0U); +} + +static void +check_negative(void) +{ + if ((enum liblog_level)-1 < 0) + ASSERT_EQ_UINT(liblog_logmask__((enum liblog_level)-10, (enum liblog_level)-10), 1U); +} + +static void +check_hyperverbose(void) +{ + ASSERT_EQ_UINT(liblog_logmask__((enum liblog_level)0x7FFF, (enum liblog_level)0x7FFF), 0x0100U); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_from_emergency(); + check_from_alert(); + check_from_critical(); + check_from_error(); + check_from_warning(); + check_from_notice(); + check_from_info(); + check_from_trace(); + check_from_debug(); + check_negative(); + check_hyperverbose(); + return 0; +} + +#endif diff --git a/liblog_mask_level.c b/liblog_mask_level.c new file mode 100644 index 0000000..5989f7d --- /dev/null +++ b/liblog_mask_level.c @@ -0,0 +1,113 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_mask_level(struct liblog_context *, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0001U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0002U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0x0004U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x0008U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x0010U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x0020U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x0040U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x0080U); + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_level(&ctx, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == 0x0020U || ctx.logmask == 0x0040U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = 0U; + liblog_mask_level(&ctx, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, 1U); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_level(&ctx, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + + liblog_mask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0001U); + liblog_mask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0001U); + liblog_mask_level(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0101U); + liblog_mask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0103U); + liblog_mask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0103U); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_mask_range.c b/liblog_mask_range.c new file mode 100644 index 0000000..4eae18a --- /dev/null +++ b/liblog_mask_range.c @@ -0,0 +1,412 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_mask_range(struct liblog_context *, enum liblog_level, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0001U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0002U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0x0004U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x0008U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x0010U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x0020U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x0040U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x0080U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE + 1, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == 0x0020U || ctx.logmask == 0x0040U); +} + +static void +check_from_emergency(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0003U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0x0007U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x000FU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x001FU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x003FU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x007FU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00FFU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01FFU); +} + +static void +check_from_alert(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0x0006U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x000EU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x001EU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x003EU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x007EU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00FEU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ALERT, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01FEU); +} + +static void +check_from_critical(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x000CU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x001CU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x003CU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x007CU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00FCU); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01FCU); +} + +static void +check_from_error(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x0018U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x0038U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x0078U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00F8U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_ERROR, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01F8U); +} + +static void +check_from_warning(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x0030U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x0070U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00F0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_WARNING, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01F0U); +} + +static void +check_from_notice(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x0060U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00E0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_NOTICE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01E0U); +} + +static void +check_from_info(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x00C0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_INFO, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01C0U); +} + +static void +check_from_trace(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0180U); +} + +static void +check_from_debug(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = 0U; + liblog_mask_range(&ctx, (enum liblog_level)-10, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, 1U); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_range(&ctx, (enum liblog_level)0x7FFF, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); + + ctx.logmask = 0U; + liblog_mask_range(&ctx, (enum liblog_level)0, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, 0x01FFU); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0001U); + liblog_mask_range(&ctx, LIBLOG_TRACE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0181U); + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x0183U); + liblog_mask_range(&ctx, LIBLOG_DEBUG, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x0183U); + liblog_mask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01FFU); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_from_emergency(); + check_from_alert(); + check_from_critical(); + check_from_error(); + check_from_warning(); + check_from_notice(); + check_from_info(); + check_from_trace(); + check_from_debug(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_mask_verbose.c b/liblog_mask_verbose.c new file mode 100644 index 0000000..3218b66 --- /dev/null +++ b/liblog_mask_verbose.c @@ -0,0 +1,111 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_mask_verbose(struct liblog_context *, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, 0x01FFU); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, 0x01FEU); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, 0x01FCU); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x01F8U); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, 0x01F0U); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, 0x01E0U); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x01C0U); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, 0x0180U); + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == 0x01E0U || ctx.logmask == 0x01C0U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, 0x01FFU); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + liblog_mask_verbose(&ctx, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = 0U; + + liblog_mask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x0100U); + liblog_mask_verbose(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, 0x01F8U); + liblog_mask_verbose(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, 0x01F8U); + liblog_mask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, 0x01F8U); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_notice.c b/liblog_notice.c new file mode 100644 index 0000000..28d9f0e --- /dev/null +++ b/liblog_notice.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_notice(struct liblog_context *, const char *, ...); + +# else +# define liblog_notice liblog__dont_want__ +# include "common.h" +# undef liblog_notice + +LIBLOG_PRINTF__(2) int +liblog_notice(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_NOTICE, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-notice.h" +# include "test-level.c" +#endif diff --git a/liblog_notice_cork.c b/liblog_notice_cork.c new file mode 100644 index 0000000..66e653f --- /dev/null +++ b/liblog_notice_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_notice_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_notice_cork liblog__dont_want__ +# include "common.h" +# undef liblog_notice_cork + +LIBLOG_PRINTF__(2) int +liblog_notice_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_NOTICE, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-notice.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_trace.c b/liblog_trace.c new file mode 100644 index 0000000..b44d5b1 --- /dev/null +++ b/liblog_trace.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_trace(struct liblog_context *, const char *, ...); + +# else +# define liblog_trace liblog__dont_want__ +# include "common.h" +# undef liblog_trace + +LIBLOG_PRINTF__(2) int +liblog_trace(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_TRACE, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-trace.h" +# include "test-level.c" +#endif diff --git a/liblog_trace__.c b/liblog_trace__.c new file mode 100644 index 0000000..3ed9462 --- /dev/null +++ b/liblog_trace__.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#ifdef WEAK_LINKING_FAILED +# warning Do not know how to create weak linking, backtrace (liblog_trace__) will not be replacable +#endif + +__attribute__((__const__)) +int +liblog_trace__(char **textp, size_t *offsetp, size_t *allocsizep, size_t skip, void *saved_trace) /* (TODO impl) */ +{ + (void) textp; + (void) offsetp; + (void) allocsizep; + (void) skip; + (void) saved_trace; + return 0; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_trace_cork.c b/liblog_trace_cork.c new file mode 100644 index 0000000..c8713d7 --- /dev/null +++ b/liblog_trace_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_trace_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_trace_cork liblog__dont_want__ +# include "common.h" +# undef liblog_trace_cork + +LIBLOG_PRINTF__(2) int +liblog_trace_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_TRACE, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-trace.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_uncork.c b/liblog_uncork.c new file mode 100644 index 0000000..3e52f75 --- /dev/null +++ b/liblog_uncork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_uncork(struct liblog_context *); + +# else +# define liblog_uncork liblog__dont_want__ +# include "common.h" +# undef liblog_uncork + +int +liblog_uncork(struct liblog_context *ctx) +{ return liblog_xlog(ctx, 0, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_NO_TEXT | LIBLOG_XLOG_UNCORK | XLOG_NOT_INLINE, NULL); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_unmask_level.c b/liblog_unmask_level.c new file mode 100644 index 0000000..9d3f691 --- /dev/null +++ b/liblog_unmask_level.c @@ -0,0 +1,113 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_unmask_level(struct liblog_context *, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0001U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0002U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0x0004U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x0008U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x0010U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0020U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x0040U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0080U); + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == ~0x0020U || ctx.logmask == ~0x0040U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, ~1U); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_level(&ctx, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + + liblog_unmask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0001U); + liblog_unmask_level(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0001U); + liblog_unmask_level(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0101U); + liblog_unmask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0103U); + liblog_unmask_level(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0103U); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_unmask_range.c b/liblog_unmask_range.c new file mode 100644 index 0000000..62b7895 --- /dev/null +++ b/liblog_unmask_range.c @@ -0,0 +1,412 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_unmask_range(struct liblog_context *, enum liblog_level, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0001U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0002U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0x0004U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x0008U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x0010U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0020U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x0040U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0080U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE + 1, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == ~0x0020U || ctx.logmask == ~0x0040U); +} + +static void +check_from_emergency(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0003U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0x0007U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x000FU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x001FU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x003FU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x007FU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00FFU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FFU); +} + +static void +check_from_alert(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0x0006U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x000EU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x001EU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x003EU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x007EU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00FEU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ALERT, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FEU); +} + +static void +check_from_critical(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x000CU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x001CU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x003CU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x007CU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00FCU); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_CRITICAL, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FCU); +} + +static void +check_from_error(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x0018U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0038U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x0078U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00F8U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_ERROR, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F8U); +} + +static void +check_from_warning(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0030U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x0070U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00F0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_WARNING, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F0U); +} + +static void +check_from_notice(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x0060U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00E0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_NOTICE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01E0U); +} + +static void +check_from_info(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x00C0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_INFO, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01C0U); +} + +static void +check_from_trace(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0180U); +} + +static void +check_from_debug(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, (enum liblog_level)-10, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, ~1U); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, (enum liblog_level)0x7FFF, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); + + ctx.logmask = ~0U; + liblog_unmask_range(&ctx, (enum liblog_level)0, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FFU); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0001U); + liblog_unmask_range(&ctx, LIBLOG_TRACE, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0181U); + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x0183U); + liblog_unmask_range(&ctx, LIBLOG_DEBUG, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x0183U); + liblog_unmask_range(&ctx, LIBLOG_EMERGENCY, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FFU); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_from_emergency(); + check_from_alert(); + check_from_critical(); + check_from_error(); + check_from_warning(); + check_from_notice(); + check_from_info(); + check_from_trace(); + check_from_debug(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_unmask_verbose.c b/liblog_unmask_verbose.c new file mode 100644 index 0000000..67ac221 --- /dev/null +++ b/liblog_unmask_verbose.c @@ -0,0 +1,111 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline void liblog_unmask_verbose(struct liblog_context *, enum liblog_level); + +#else + +static void +check_singletons(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_EMERGENCY); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FFU); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_ALERT); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FEU); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_CRITICAL); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FCU); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F8U); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_WARNING); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F0U); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_NOTICE); + ASSERT_EQ_UINT(ctx.logmask, ~0x01E0U); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x01C0U); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_TRACE); + ASSERT_EQ_UINT(ctx.logmask, ~0x0180U); + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); +} + +static void +check_custom(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, LIBLOG_NOTICE + 1); + ASSERT_IS_TRUE(ctx.logmask == ~0x01E0U || ctx.logmask == ~0x01C0U); +} + +static void +check_negative(void) +{ + struct liblog_context ctx; + + if ((enum liblog_level)-1 < 0) { + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, (enum liblog_level)-10); + ASSERT_EQ_UINT(ctx.logmask, ~0x01FFU); + } +} + +static void +check_hyperverbose(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + liblog_unmask_verbose(&ctx, (enum liblog_level)0x7FFF); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); +} + +static void +check_series(void) +{ + struct liblog_context ctx; + + ctx.logmask = ~0U; + + liblog_unmask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x0100U); + liblog_unmask_verbose(&ctx, LIBLOG_ERROR); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F8U); + liblog_unmask_verbose(&ctx, LIBLOG_INFO); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F8U); + liblog_unmask_verbose(&ctx, LIBLOG_DEBUG); + ASSERT_EQ_UINT(ctx.logmask, ~0x01F8U); +} + +int +main(void) +{ + check_singletons(); + check_custom(); + check_negative(); + check_hyperverbose(); + check_series(); + return 0; +} + +#endif diff --git a/liblog_use_fd.c b/liblog_use_fd.c new file mode 100644 index 0000000..52687c7 --- /dev/null +++ b/liblog_use_fd.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_fd(struct liblog_context *, int, const char *, int); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_fd_for_range.c b/liblog_use_fd_for_range.c new file mode 100644 index 0000000..8460d5e --- /dev/null +++ b/liblog_use_fd_for_range.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_fd_for_range(struct liblog_context *, int, const char *, int, + enum liblog_level, enum liblog_level); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_file.c b/liblog_use_file.c new file mode 100644 index 0000000..3083f1a --- /dev/null +++ b/liblog_use_file.c @@ -0,0 +1,32 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +struct liblog_output * +liblog_use_file(struct liblog_context *ctx, int dirfd, const char *path, const char *prefixfmt, int use_backtrace) +{ + struct liblog_output *ret; + int fd; + if (!path || !*path) + return liblog_use_fd(ctx, dirfd, prefixfmt, use_backtrace); + if (dirfd == -1 && *path != '/') { + errno = EINVAL; + return NULL; + } + fd = openat(dirfd, path, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (fd < 0) + return NULL; + ret = liblog_use_fd(ctx, fd, prefixfmt, use_backtrace); + if (!ret) { + close(fd); + return NULL; + } + ret->sink.file.owns_fd = 1; + return ret; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_file_for_range.c b/liblog_use_file_for_range.c new file mode 100644 index 0000000..e312c4b --- /dev/null +++ b/liblog_use_file_for_range.c @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +struct liblog_output * +liblog_use_file_for_range(struct liblog_context *ctx, int dirfd, const char *path, const char *prefixfmt, + int use_backtrace, enum liblog_level least_verbose, enum liblog_level most_verbose) +{ + struct liblog_output *ret; + int fd; + if (!path || !*path) + return liblog_use_fd_for_range(ctx, dirfd, prefixfmt, use_backtrace, least_verbose, most_verbose); + if (dirfd == -1 && *path != '/') { + errno = EINVAL; + return NULL; + } + fd = openat(dirfd, path, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (fd < 0) + return NULL; + ret = liblog_use_fd_for_range(ctx, fd, prefixfmt, use_backtrace, least_verbose, most_verbose); + if (!ret) { + close(fd); + return NULL; + } + ret->sink.file.owns_fd = 1; + return ret; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_output.c b/liblog_use_output.c new file mode 100644 index 0000000..3471722 --- /dev/null +++ b/liblog_use_output.c @@ -0,0 +1,54 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +struct liblog_output * +liblog_use_output(struct liblog_context *ctx, const struct liblog_output *output) +{ + void *new; + + if (!ctx || !output) + goto einval; + + if (output->lowest_verbosity_unlimited && output->highest_verbosity_unlimited) + if (output->lowest_verbosity > output->highest_verbosity) + goto einval; + + if (output->sink_type == LIBLOG_STREAM) { + if (!output->sink.stream.stream) + goto einval; + } else if (output->sink_type != LIBLOG_SYSLOG && output->sink_type != LIBLOG_FILE) { + /* + * We do not want to validate syslog level, + * nor do we want to validate file descriptor, + * indeed the user may want to output to a negative + * file descriptor so that it only visible during + * system call tracing + */ + einval: + errno = EINVAL; + return NULL; + } + + if (ctx->noutputs > SIZE_MAX / sizeof(*ctx->outputs) - 1) + goto enomem; + new = realloc(ctx->outputs, (ctx->noutputs + 1) * sizeof(*ctx->outputs)); + if (!new) { + enomem: + errno = ENOMEM; + return NULL; + } + + memcpy(&ctx->outputs[ctx->noutputs], output, sizeof(*output)); + + if (!ctx->outputs[ctx->noutputs].prefixfmt) + ctx->outputs[ctx->noutputs].prefixfmt = DEFAULT_PREFIXFMT; + + return &ctx->outputs[ctx->noutputs++]; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_stderr.c b/liblog_use_stderr.c new file mode 100644 index 0000000..f66d953 --- /dev/null +++ b/liblog_use_stderr.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_stderr(struct liblog_context *, const char *, int); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_stderr_for_range.c b/liblog_use_stderr_for_range.c new file mode 100644 index 0000000..1ffaee1 --- /dev/null +++ b/liblog_use_stderr_for_range.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_stderr_for_range(struct liblog_context *, const char *, int, + enum liblog_level, enum liblog_level); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_stream.c b/liblog_use_stream.c new file mode 100644 index 0000000..c415627 --- /dev/null +++ b/liblog_use_stream.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_stream(struct liblog_context *, FILE *, const char *, int); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_stream_for_range.c b/liblog_use_stream_for_range.c new file mode 100644 index 0000000..6749b26 --- /dev/null +++ b/liblog_use_stream_for_range.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_stream_for_range(struct liblog_context *, FILE *, const char *, int, + enum liblog_level, enum liblog_level); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_syslog.c b/liblog_use_syslog.c new file mode 100644 index 0000000..09b6ca9 --- /dev/null +++ b/liblog_use_syslog.c @@ -0,0 +1,99 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wassign-enum" +#endif + +int +liblog_use_syslog(struct liblog_context *ctx, const char *prefixfmt, int use_backtrace) +{ + void *new; + size_t old_noutputs = ctx->noutputs; + struct liblog_output output = { + .userdata = NULL, + .prefixfmt = prefixfmt, + .lowest_verbosity_unlimited = 1U, + .highest_verbosity_unlimited = 0U, + .use_backtrace = (use_backtrace ? 1U : 0U), + .lowest_verbosity = 0, + .highest_verbosity = LIBLOG_ALERT - 1, + .sink_type = LIBLOG_SYSLOG, + .sink.syslog.level = LOG_EMERG + }; + + if (!ctx) { + errno = EINVAL; + return -1; + } + + if (ctx->noutputs > SIZE_MAX / sizeof(*ctx->outputs) - 8) + goto enomem; + new = realloc(ctx->outputs, (ctx->noutputs + 8) * sizeof(*ctx->outputs)); + if (!new) { + enomem: + errno = ENOMEM; + return -1; + } + ctx->outputs = new; + + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity_unlimited = 0; + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_CRITICAL - 1; + output.sink.syslog.level = LOG_ALERT; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_ERROR - 1; + output.sink.syslog.level = LOG_CRIT; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_WARNING - 1; + output.sink.syslog.level = LOG_ERR; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_NOTICE - 1; + output.sink.syslog.level = LOG_WARNING; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_INFO - 1; + output.sink.syslog.level = LOG_NOTICE; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity = LIBLOG_TRACE - 1; + output.sink.syslog.level = LOG_INFO; + if (liblog_use_output(ctx, &output)) + goto fail; + + output.lowest_verbosity = output.highest_verbosity + 1; + output.highest_verbosity_unlimited = 1; + output.sink.syslog.level = LOG_DEBUG; + if (liblog_use_output(ctx, &output)) + goto fail; + + return 0; + +fail: + while (ctx->noutputs > old_noutputs) + liblog_destroy_output(&ctx->outputs[--ctx->noutputs]); + return -1; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_use_syslog_for_range.c b/liblog_use_syslog_for_range.c new file mode 100644 index 0000000..014b6fa --- /dev/null +++ b/liblog_use_syslog_for_range.c @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline struct liblog_output *liblog_use_syslog_for_range(struct liblog_context *, int, const char *, int, + enum liblog_level, enum liblog_level); + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_valert.c b/liblog_valert.c new file mode 100644 index 0000000..308fa8d --- /dev/null +++ b/liblog_valert.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_valert(struct liblog_context *, const char *, va_list); + +# else +# define liblog_valert liblog__dont_want__ +# include "common.h" +# undef liblog_valert + +LIBLOG_VPRINTF__(2) int +liblog_valert(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_ALERT, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-alert.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_valert_cork.c b/liblog_valert_cork.c new file mode 100644 index 0000000..288b098 --- /dev/null +++ b/liblog_valert_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_valert_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_valert_cork liblog__dont_want__ +# include "common.h" +# undef liblog_valert_cork + +LIBLOG_VPRINTF__(2) int +liblog_valert_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_ALERT, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-alert.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vcritical.c b/liblog_vcritical.c new file mode 100644 index 0000000..0c921e9 --- /dev/null +++ b/liblog_vcritical.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vcritical(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vcritical liblog__dont_want__ +# include "common.h" +# undef liblog_vcritical + +LIBLOG_VPRINTF__(2) int +liblog_vcritical(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_CRITICAL, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-critical.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vcritical_cork.c b/liblog_vcritical_cork.c new file mode 100644 index 0000000..1467c4b --- /dev/null +++ b/liblog_vcritical_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vcritical_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vcritical_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vcritical_cork + +LIBLOG_VPRINTF__(2) int +liblog_vcritical_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_CRITICAL, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-critical.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vdebug.c b/liblog_vdebug.c new file mode 100644 index 0000000..fe2d276 --- /dev/null +++ b/liblog_vdebug.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vdebug(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vdebug liblog__dont_want__ +# include "common.h" +# undef liblog_vdebug + +LIBLOG_VPRINTF__(2) int +liblog_vdebug(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_DEBUG, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-debug.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vdebug_cork.c b/liblog_vdebug_cork.c new file mode 100644 index 0000000..e6bde45 --- /dev/null +++ b/liblog_vdebug_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vdebug_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vdebug_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vdebug_cork + +LIBLOG_VPRINTF__(2) int +liblog_vdebug_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_DEBUG, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-debug.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vemergency.c b/liblog_vemergency.c new file mode 100644 index 0000000..b194f6d --- /dev/null +++ b/liblog_vemergency.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vemergency(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vemergency liblog__dont_want__ +# include "common.h" +# undef liblog_vemergency + +LIBLOG_VPRINTF__(2) int +liblog_vemergency(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_EMERGENCY, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-emergency.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vemergency_cork.c b/liblog_vemergency_cork.c new file mode 100644 index 0000000..1d91fcb --- /dev/null +++ b/liblog_vemergency_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vemergency_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vemergency_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vemergency_cork + +LIBLOG_VPRINTF__(2) int +liblog_vemergency_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_EMERGENCY, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-emergency.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_verror.c b/liblog_verror.c new file mode 100644 index 0000000..503caed --- /dev/null +++ b/liblog_verror.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_verror(struct liblog_context *, const char *, va_list); + +# else +# define liblog_verror liblog__dont_want__ +# include "common.h" +# undef liblog_verror + +LIBLOG_VPRINTF__(2) int +liblog_verror(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_ERROR, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-error.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_verror_cork.c b/liblog_verror_cork.c new file mode 100644 index 0000000..5903ee9 --- /dev/null +++ b/liblog_verror_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_verror_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_verror_cork liblog__dont_want__ +# include "common.h" +# undef liblog_verror_cork + +LIBLOG_VPRINTF__(2) int +liblog_verror_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_ERROR, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-error.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vinfo.c b/liblog_vinfo.c new file mode 100644 index 0000000..7db76f2 --- /dev/null +++ b/liblog_vinfo.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vinfo(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vinfo liblog__dont_want__ +# include "common.h" +# undef liblog_vinfo + +LIBLOG_VPRINTF__(2) int +liblog_vinfo(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_INFO, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-info.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vinfo_cork.c b/liblog_vinfo_cork.c new file mode 100644 index 0000000..b4150c6 --- /dev/null +++ b/liblog_vinfo_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vinfo_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vinfo_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vinfo_cork + +LIBLOG_VPRINTF__(2) int +liblog_vinfo_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_INFO, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-info.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vlog.c b/liblog_vlog.c new file mode 100644 index 0000000..7396fc1 --- /dev/null +++ b/liblog_vlog.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vlog(struct liblog_context *, enum liblog_level, const char *, va_list); + +# else +# define liblog_vlog liblog__dont_want__ +# include "common.h" +# undef liblog_vlog + +LIBLOG_VPRINTF__(3) int +liblog_vlog(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, level, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_vlog_cork.c b/liblog_vlog_cork.c new file mode 100644 index 0000000..f7bf4e9 --- /dev/null +++ b/liblog_vlog_cork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vlog_cork(struct liblog_context *, enum liblog_level, const char *, va_list); + +# else +# define liblog_vlog_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vlog_cork + +LIBLOG_VPRINTF__(3) int +liblog_vlog_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_vlog_no_backtrace.c b/liblog_vlog_no_backtrace.c new file mode 100644 index 0000000..c545f15 --- /dev/null +++ b/liblog_vlog_no_backtrace.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vlog_no_backtrace(struct liblog_context *, enum liblog_level, const char *, va_list); + +# else +# define liblog_vlog_no_backtrace liblog__dont_want__ +# include "common.h" +# undef liblog_vlog_no_backtrace + +LIBLOG_VPRINTF__(3) int +liblog_vlog_no_backtrace(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_vlog_no_backtrace_cork.c b/liblog_vlog_no_backtrace_cork.c new file mode 100644 index 0000000..a18b220 --- /dev/null +++ b/liblog_vlog_no_backtrace_cork.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vlog_no_backtrace_cork(struct liblog_context *, enum liblog_level, const char *, va_list); + +# else +# define liblog_vlog_no_backtrace_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vlog_no_backtrace_cork + +LIBLOG_VPRINTF__(3) int +liblog_vlog_no_backtrace_cork(struct liblog_context *ctx, enum liblog_level level, const char *fmt, va_list args) +{ return liblog_xlog(ctx, level, LIBLOG_XLOG_NO_BACKTRACE | LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_vnotice.c b/liblog_vnotice.c new file mode 100644 index 0000000..2c6bc79 --- /dev/null +++ b/liblog_vnotice.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vnotice(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vnotice liblog__dont_want__ +# include "common.h" +# undef liblog_vnotice + +LIBLOG_VPRINTF__(2) int +liblog_vnotice(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_NOTICE, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-notice.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vnotice_cork.c b/liblog_vnotice_cork.c new file mode 100644 index 0000000..1c14e9e --- /dev/null +++ b/liblog_vnotice_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vnotice_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vnotice_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vnotice_cork + +LIBLOG_VPRINTF__(2) int +liblog_vnotice_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_NOTICE, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-notice.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vtrace.c b/liblog_vtrace.c new file mode 100644 index 0000000..7f8c025 --- /dev/null +++ b/liblog_vtrace.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vtrace(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vtrace liblog__dont_want__ +# include "common.h" +# undef liblog_vtrace + +LIBLOG_VPRINTF__(2) int +liblog_vtrace(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_TRACE, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-trace.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vtrace_cork.c b/liblog_vtrace_cork.c new file mode 100644 index 0000000..0e5a38c --- /dev/null +++ b/liblog_vtrace_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vtrace_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vtrace_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vtrace_cork + +LIBLOG_VPRINTF__(2) int +liblog_vtrace_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_TRACE, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-trace.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vwarning.c b/liblog_vwarning.c new file mode 100644 index 0000000..74c2c68 --- /dev/null +++ b/liblog_vwarning.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vwarning(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vwarning liblog__dont_want__ +# include "common.h" +# undef liblog_vwarning + +LIBLOG_VPRINTF__(2) int +liblog_vwarning(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_WARNING, XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-warning.h" +# include "test-vlevel.c" +#endif diff --git a/liblog_vwarning_cork.c b/liblog_vwarning_cork.c new file mode 100644 index 0000000..4200517 --- /dev/null +++ b/liblog_vwarning_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_vwarning_cork(struct liblog_context *, const char *, va_list); + +# else +# define liblog_vwarning_cork liblog__dont_want__ +# include "common.h" +# undef liblog_vwarning_cork + +LIBLOG_VPRINTF__(2) int +liblog_vwarning_cork(struct liblog_context *ctx, const char *fmt, va_list args) +{ return liblog_vxlog(ctx, LIBLOG_WARNING, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt, args); } + +# endif + +#else +# include "test-warning.h" +# include "test-vlevel_cork.c" +#endif diff --git a/liblog_vxlog.c b/liblog_vxlog.c new file mode 100644 index 0000000..4093c59 --- /dev/null +++ b/liblog_vxlog.c @@ -0,0 +1,121 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wformat-nonliteral" +#endif + +static int +ensure_fit(struct messagebuf *msg, size_t extent) +{ + size_t new_size; + void *new; + if (extent >= msg->size - msg->len) { + new_size = msg->len + extent + 1; + new = realloc(msg->text, new_size); + if (!new) + return -1; + msg->text = new; + msg->size = new_size; + } + return 0; +} + +int +liblog_vxlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, va_list args) +{ + /* TODO optionally avoid allocating and deallocating for each call */ + /* TODO respect logmask */ + + struct messagebuf msgbuf = MESSAGEBUF_INIT, *msg; + int corked; + size_t old_len; + + if (!ctx || (level & (enum liblog_level)~0x001F)) { + einval: + errno = EINVAL; + return -1; + } + if (!fmt && !(flags & (XLOG_NOT_INLINE - 1U) & LIBLOG_XLOG_NO_TEXT)) + goto einval; + if ((flags & (LIBLOG_XLOG_CORK | LIBLOG_XLOG_UNCORK)) == (LIBLOG_XLOG_CORK | LIBLOG_XLOG_UNCORK)) + goto einval; + if ((flags & (LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_BACKTRACE)) == (LIBLOG_XLOG_BACKTRACE | LIBLOG_XLOG_NO_BACKTRACE)) + goto einval; + + msg = ctx->internal_state ? &ctx->internal_state->msg : &msgbuf; + corked = !!msg->prefix; + old_len = msg->len; + + /* TODO ctx->internal_state must be allocated */ + + if (!msg->prefix) { + /* TODO implement: prefix */ + } + + if (!(flags & LIBLOG_XLOG_NO_BACKTRACE)) { + if (flags & LIBLOG_XLOG_BACKTRACE) { + unsigned levels = (flags / XLOG_NOT_INLINE) + 1U; + if (liblog_trace__(&msg->text, &msg->len, &msg->size, (size_t)levels, NULL)) + return -1; + } + } + + if (!(flags & LIBLOG_XLOG_NO_TEXT)) { + int len; + va_list args2; + va_copy(args2, args); + len = snprintf(NULL, 0, fmt, args2); + va_end(args2); + if (len < 0) + return -1; + if (ensure_fit(msg, (size_t)len)) + return -1; + if (snprintf(&msg->text[msg->len], (size_t)len + 1, fmt, args) != len) + abort(); + msg->len += (size_t)len; + } + + if (flags & LIBLOG_XLOG_UNCORK) { + if (msg == &ctx->internal_state->msg) { + memcpy(&msgbuf, msg, sizeof(*msg)); + ctx->internal_state->msg = MESSAGEBUF_INIT; + msg = &msgbuf; + } + goto output; + } else if (flags & LIBLOG_XLOG_CORK) { + if (msg != &ctx->internal_state->msg) + memcpy(&ctx->internal_state->msg, msg, sizeof(*msg)); + } else if (corked) { + /* do nothing, internal state already set */ + } else { + output: + if (msg->len && msg->text[msg->len - 1] != '\n') { + if (ensure_fit(msg, 0)) + goto fail; + msg->text[msg->len++] = '\n'; + } + if (liblog_flush__(ctx, msg)) + goto fail; + free(msg->prefix); + free(msg->text); + *msg = MESSAGEBUF_INIT; + } + + return 0; + +fail: + if (msg != &ctx->internal_state->msg) { + free(msg->prefix); + free(msg->text); + } + msg->len = old_len; + return -1; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_warning.c b/liblog_warning.c new file mode 100644 index 0000000..abdbc69 --- /dev/null +++ b/liblog_warning.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_warning(struct liblog_context *, const char *, ...); + +# else +# define liblog_warning liblog__dont_want__ +# include "common.h" +# undef liblog_warning + +LIBLOG_PRINTF__(2) int +liblog_warning(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_WARNING, XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-warning.h" +# include "test-level.c" +#endif diff --git a/liblog_warning_cork.c b/liblog_warning_cork.c new file mode 100644 index 0000000..6630ff1 --- /dev/null +++ b/liblog_warning_cork.c @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_warning_cork(struct liblog_context *, const char *, ...); + +# else +# define liblog_warning_cork liblog__dont_want__ +# include "common.h" +# undef liblog_warning_cork + +LIBLOG_PRINTF__(2) int +liblog_warning_cork(struct liblog_context *ctx, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, LIBLOG_WARNING, LIBLOG_XLOG_CORK | XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "test-warning.h" +# include "test-level_cork.c" +#endif diff --git a/liblog_whence__.c b/liblog_whence__.c new file mode 100644 index 0000000..767987d --- /dev/null +++ b/liblog_whence__.c @@ -0,0 +1,24 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +#ifdef WEAK_LINKING_FAILED +# warning Do not know how to create weak linking, source determination (liblog_whence__) will not be replacable +#endif + +int +liblog_whence__(char **file_out, off_t *line_out, char **function_out, size_t skip, void **trace_save_out) /* (TODO impl) */ +{ + *file_out = NULL; + *line_out = -1; + *function_out = NULL; + (void) skip; + *trace_save_out = NULL; + return 0; +} + +#else + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/liblog_xlog.c b/liblog_xlog.c new file mode 100644 index 0000000..12640ef --- /dev/null +++ b/liblog_xlog.c @@ -0,0 +1,25 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef TEST + +# ifdef USE_EXTERN_INLINE +# include "common.h" + +extern inline int liblog_xlog(struct liblog_context *, enum liblog_level, unsigned, const char *, ...); + +# else +# define liblog_xlog liblog__dont_want__ +# include "common.h" +# undef liblog_xlog + +LIBLOG_PRINTF__(4) int +liblog_xlog(struct liblog_context *ctx, enum liblog_level level, unsigned flags, const char *fmt, ...) +{ LIBLOG_VA__(liblog_vxlog, ctx, level, flags + XLOG_NOT_INLINE, fmt); } + +# endif + +#else +# include "common.h" + +int main(void) {return 0;} /* TODO test */ + +#endif diff --git a/mk/linux.mk b/mk/linux.mk new file mode 100644 index 0000000..ad58f69 --- /dev/null +++ b/mk/linux.mk @@ -0,0 +1,6 @@ +LIBEXT = so +LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR) +LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR) +LIBMINOREXT = $(LIBEXT).$(LIB_VERSION) + +FIX_INSTALL_NAME = : diff --git a/mk/macos.mk b/mk/macos.mk new file mode 100644 index 0000000..3d19dde --- /dev/null +++ b/mk/macos.mk @@ -0,0 +1,6 @@ +LIBEXT = dylib +LIBFLAGS = -dynamiclib -Wl,-compatibility_version,$(LIB_MAJOR) -Wl,-current_version,$(LIB_VERSION) +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = install_name_tool -id "$(PREFIX)/lib/liblog.$(LIBMAJOREXT)" diff --git a/mk/windows.mk b/mk/windows.mk new file mode 100644 index 0000000..ed5ec8d --- /dev/null +++ b/mk/windows.mk @@ -0,0 +1,6 @@ +LIBEXT = dll +LIBFLAGS = -shared +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = : diff --git a/test-alert.h b/test-alert.h new file mode 100644 index 0000000..62b12b4 --- /dev/null +++ b/test-alert.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_ALERT +#define test_level liblog_alert +#define test_vlevel liblog_valert +#define test_level_cork liblog_alert_cork +#define test_vlevel_cork liblog_valert_cork diff --git a/test-critical.h b/test-critical.h new file mode 100644 index 0000000..8730c67 --- /dev/null +++ b/test-critical.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_CRITICAL +#define test_level liblog_critical +#define test_vlevel liblog_vcritical +#define test_level_cork liblog_critical_cork +#define test_vlevel_cork liblog_vcritical_cork diff --git a/test-debug.h b/test-debug.h new file mode 100644 index 0000000..fdbe009 --- /dev/null +++ b/test-debug.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_DEBUG +#define test_level liblog_debug +#define test_vlevel liblog_vdebug +#define test_level_cork liblog_debug_cork +#define test_vlevel_cork liblog_vdebug_cork diff --git a/test-emergency.h b/test-emergency.h new file mode 100644 index 0000000..22630a3 --- /dev/null +++ b/test-emergency.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_EMERGENCY +#define test_level liblog_emergency +#define test_vlevel liblog_vemergency +#define test_level_cork liblog_emergency_cork +#define test_vlevel_cork liblog_vemergency_cork diff --git a/test-error.h b/test-error.h new file mode 100644 index 0000000..8e529c9 --- /dev/null +++ b/test-error.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_ERROR +#define test_level liblog_error +#define test_vlevel liblog_verror +#define test_level_cork liblog_error_cork +#define test_vlevel_cork liblog_verror_cork diff --git a/test-info.h b/test-info.h new file mode 100644 index 0000000..3d62454 --- /dev/null +++ b/test-info.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_INFO +#define test_level liblog_info +#define test_vlevel liblog_vinfo +#define test_level_cork liblog_info_cork +#define test_vlevel_cork liblog_vinfo_cork diff --git a/test-level.c b/test-level.c new file mode 100644 index 0000000..ec134ca --- /dev/null +++ b/test-level.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int main(void) {return 0;} /* TODO test */ diff --git a/test-level_cork.c b/test-level_cork.c new file mode 100644 index 0000000..ec134ca --- /dev/null +++ b/test-level_cork.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int main(void) {return 0;} /* TODO test */ diff --git a/test-notice.h b/test-notice.h new file mode 100644 index 0000000..69a20ba --- /dev/null +++ b/test-notice.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_NOTICE +#define test_level liblog_notice +#define test_vlevel liblog_vnotice +#define test_level_cork liblog_notice_cork +#define test_vlevel_cork liblog_vnotice_cork diff --git a/test-trace.h b/test-trace.h new file mode 100644 index 0000000..d7ef3b6 --- /dev/null +++ b/test-trace.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_TRACE +#define test_level liblog_trace +#define test_vlevel liblog_vtrace +#define test_level_cork liblog_trace_cork +#define test_vlevel_cork liblog_vtrace_cork diff --git a/test-vlevel.c b/test-vlevel.c new file mode 100644 index 0000000..ec134ca --- /dev/null +++ b/test-vlevel.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int main(void) {return 0;} /* TODO test */ diff --git a/test-vlevel_cork.c b/test-vlevel_cork.c new file mode 100644 index 0000000..ec134ca --- /dev/null +++ b/test-vlevel_cork.c @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + +int main(void) {return 0;} /* TODO test */ diff --git a/test-warning.h b/test-warning.h new file mode 100644 index 0000000..de05a8d --- /dev/null +++ b/test-warning.h @@ -0,0 +1,6 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST_LEVEL LIBLOG_WARNING +#define test_level liblog_warning +#define test_vlevel liblog_vwarning +#define test_level_cork liblog_warning_cork +#define test_vlevel_cork liblog_vwarning_cork diff --git a/testhelp.c b/testhelp.c new file mode 100644 index 0000000..74997eb --- /dev/null +++ b/testhelp.c @@ -0,0 +1,366 @@ +/* See LICENSE file for copyright and license details. */ +#define TEST +#include "common.h" + + +#if defined(__GNUC__) +# pragma GCC diagnostic ignored "-Wswitch" +# pragma GCC diagnostic ignored "-Wswitch-enum" +#endif + + +static char * +quote(const char *s, char **out) +{ + char *ret, *p; + int safe = 1; + *out = p = ret = malloc(strlen(s) * 4 + 3); + if (!ret) { + fprintf(stderr, "ran out of memory during printing of assertion failure\n"); + exit(1); + } + *p++ = '"'; + for (; *s; s++) { + if (*s == '\r') + p = stpcpy(p, "\\r"), safe = 1; + else if (*s == '\t') + p = stpcpy(p, "\\t"), safe = 1; + else if (*s == '\a') + p = stpcpy(p, "\\a"), safe = 1; + else if (*s == '\f') + p = stpcpy(p, "\\f"), safe = 1; + else if (*s == '\v') + p = stpcpy(p, "\\v"), safe = 1; + else if (*s == '\b') + p = stpcpy(p, "\\b"), safe = 1; + else if (*s == '\n') + p = stpcpy(p, "\\n"), safe = 1; + else if (*s == '\"') + p = stpcpy(p, "\\\""), safe = 1; + else if (*s == '\\') + p = stpcpy(p, "\\\\"), safe = 1; + else if (*s < ' ' || *s >= 127) + p += sprintf(p, "\\x%02X", (unsigned char)*s), safe = 0; + else if (*s == '?' && p[-1] == '?') + p += sprintf(p, "\"\"?"), safe = 1; + else if (isxdigit(*s) && !safe) + p += sprintf(p, "\"\"%c", *s), safe = 1; + else + *p++ = *s, safe = 1; + } + *p++ = '"'; + *p++ = '\0'; + return ret; +} + + +#define CASE(HOW, OP)\ + case HOW:\ + if ((*have) OP (*expect))\ + return;\ + symbol = #OP;\ + break + + +#define CASE_LOGIC(HOW, OP1, OP2, OPERAND3_IS_EXPECT)\ + case HOW:\ + if (((*have) OP1 (*expect)) OP2 (OPERAND3_IS_EXPECT ? (*expect) : 0))\ + return;\ + symbol = #OP1;\ + symbol2 = #OP2;\ + operand3_is_expect = (OPERAND3_IS_EXPECT);\ + break + + +static void +test_assert_uint(const char *file, int line, enum assert_how how, const char *have_string, + const char *expect_string, const uintmax_t *have, const uintmax_t *expect) +{ + const char *symbol; + const char *symbol2 = NULL; + int operand3_is_expect; + switch (how) { + case ASSERT_NOT_LT: how = ASSERT_NOT_GE; break; + case ASSERT_NOT_LE: how = ASSERT_NOT_GT; break; + case ASSERT_NOT_GT: how = ASSERT_NOT_LE; break; + case ASSERT_NOT_GE: how = ASSERT_NOT_LT; break; + } + switch (how) { + CASE(ASSERT_EQ, ==); + CASE(ASSERT_NE, !=); + CASE(ASSERT_LT, <); + CASE(ASSERT_LE, <=); + CASE(ASSERT_GT, >); + CASE(ASSERT_GE, >=); + CASE_LOGIC(ASSERT_CONTAINS_ALL, &, ==, 1); + CASE_LOGIC(ASSERT_CONTAINS_ANY, &, !=, 0); + CASE_LOGIC(ASSERT_CONTAINS_NOT_ALL, &, !=, 1); + CASE_LOGIC(ASSERT_CONTAINS_NOT_ANY, &, ==, 0); + CASE_LOGIC(ASSERT_IS_IN, &~, ==, 0); + CASE_LOGIC(ASSERT_NOT_IN, &~, !=, 0); + default: + abort(); + } + if (!symbol2) + fprintf(stderr, "TEST FAILED at %s:%i: asserting (%s) %s (%s), actualised as %ju %s %ju\n", + file, line, have_string, symbol, expect_string, *have, symbol, *expect); + else if (!operand3_is_expect) + fprintf(stderr, "TEST FAILED at %s:%i: asserting ((%s) %s (%s)) %s 0, actualised as (%#jx %s %#jx) %s 0\n", + file, line, have_string, symbol, expect_string, symbol2, *have, symbol, *expect, symbol2); + else + fprintf(stderr, "TEST FAILED at %s:%i: asserting ((%s) %s (%s)) %s (%s), actualised as (%#jx %s %#jx) %s %#jx\n", + file, line, have_string, symbol, expect_string, symbol2, expect_string, + *have, symbol, *expect, symbol2, *expect); + exit(1); +} + + +static void +test_assert_int(const char *file, int line, enum assert_how how, const char *have_string, + const char *expect_string, const intmax_t *have, const intmax_t *expect) +{ + const char *symbol; + switch (how) { + case ASSERT_NOT_LT: how = ASSERT_NOT_GE; break; + case ASSERT_NOT_LE: how = ASSERT_NOT_GT; break; + case ASSERT_NOT_GT: how = ASSERT_NOT_LE; break; + case ASSERT_NOT_GE: how = ASSERT_NOT_LT; break; + } + switch (how) { + CASE(ASSERT_EQ, ==); + CASE(ASSERT_NE, !=); + CASE(ASSERT_LT, <); + CASE(ASSERT_LE, <=); + CASE(ASSERT_GT, >); + CASE(ASSERT_GE, >=); + default: + test_assert_uint(file, line, how, have_string, expect_string, + (const uintmax_t *)have, (const uintmax_t *)expect); + return; + } + fprintf(stderr, "TEST FAILED at %s:%i: asserting (%s) %s (%s), actualised as %ji %s %ji\n", + file, line, have_string, symbol, expect_string, *have, symbol, *expect); + exit(1); +} + + +#define PTR_CASE(HOW, OP)\ + case HOW:\ + if ((have) OP (expect))\ + return;\ + symbol = #OP;\ + break + + +static void +test_assert_ptr(const char *file, int line, enum assert_how how, const char *have_string, + const char *expect_string, const char *have, const char *expect) +{ + const char *symbol; + switch (how) { + case ASSERT_NOT_LT: how = ASSERT_NOT_GE; break; + case ASSERT_NOT_LE: how = ASSERT_NOT_GT; break; + case ASSERT_NOT_GT: how = ASSERT_NOT_LE; break; + case ASSERT_NOT_GE: how = ASSERT_NOT_LT; break; + } + switch (how) { + PTR_CASE(ASSERT_EQ, ==); + PTR_CASE(ASSERT_NE, !=); + PTR_CASE(ASSERT_LT, <); + PTR_CASE(ASSERT_LE, <=); + PTR_CASE(ASSERT_GT, >); + PTR_CASE(ASSERT_GE, >=); + default: + abort(); + } + fprintf(stderr, "TEST FAILED at %s:%i: asserting (%s) %s (%s), actualised as %p %s %p\n", + file, line, have_string, symbol, expect_string, have, symbol, expect); + exit(1); +} + + +#define STR_CASE(HOW, FUNC)\ + case HOW:\ + if (FUNC(have, expect))\ + return;\ + function = #FUNC;\ + break + +#define SWAP_STR_CASE(HOW, NEW_HOW)\ + case HOW:\ + test_assert_str(file, line, how, expect_string, have_string, expect, have, rev);\ + return + + +static void +test_assert_str(const char *file, int line, enum assert_how how, const char *have_string, + const char *expect_string, const char *have, const char *expect, int rev) +{ + const char *function; + size_t have_len; + size_t expect_len; + char *have_quote = NULL; + char *expect_quote = NULL; + + if (!have && !expect) + fprintf(stderr, "TEST FAILED at %s:%i: asserting failed because (%s) and (%s) are NULL\n", + file, line, have_string, expect_string); + else if (!have) + fprintf(stderr, "TEST FAILED at %s:%i: asserting failed because (%s) was NULL\n", + file, line, have_string); + else if (!expect) + fprintf(stderr, "TEST FAILED at %s:%i: asserting failed because (%s) was NULL\n", + file, line, expect_string); + if (!have || !expect) + exit(1); + + switch (how) { + STR_CASE(ASSERT_EQ, !strcmp); + STR_CASE(ASSERT_NE, strcmp); + STR_CASE(ASSERT_IS_IN, strstr); + STR_CASE(ASSERT_NOT_IN, !strstr); + SWAP_STR_CASE(ASSERT_CONTAINS_ALL, ASSERT_IS_IN); + SWAP_STR_CASE(ASSERT_CONTAINS_NOT_ALL, ASSERT_NOT_INT); + SWAP_STR_CASE(ASSERT_LE, ASSERT_GE); + SWAP_STR_CASE(ASSERT_LT, ASSERT_GT); + SWAP_STR_CASE(ASSERT_NOT_LE, ASSERT_NOT_GE); + SWAP_STR_CASE(ASSERT_NOT_LT, ASSERT_NOT_GT); + default: + have_len = strlen(have); + expect_len = strlen(expect); + if (rev) + goto assert_end; + else + goto assert_start; + } + fprintf(stderr, "TEST FAILED at %s:%i: asserting %s(%s, %s), actualised as %s(%s, %s)\n", + file, line, function, have_string, expect_string, + function, quote(have, &have_quote), quote(expect, &expect_quote)); +free_and_exit: + free(have_quote); + free(expect_quote); + exit(1); + +assert_start: + switch (how) { + case ASSERT_GE: + if (have_len >= expect_len && !strncmp(have, expect, expect_len)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) >= strlen(%s) && !strncmp(%s, %s, strlen(%s)), " + "actualised as %zu >= %zu && !strncmp(%s, %s, %zu)\n", + file, line, have_string, expect_string, have_string, expect_string, expect_string, + have_len, expect_len, quote(have, &have_quote), quote(expect, &expect_quote), expect_len); + break; + case ASSERT_NOT_GE: + if (have_len < expect_len || strncmp(have, expect, expect_len)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) < strlen(%s) || strncmp(%s, %s, strlen(%s)), " + "actualised as %zu < %zu && !strncmp(%s, %s, %zu)\n", + file, line, have_string, expect_string, have_string, expect_string, expect_string, + have_len, expect_len, quote(have, &have_quote), quote(expect, &expect_quote), expect_len); + break; + case ASSERT_GT: + if (have_len > expect_len && !strncmp(have, expect, expect_len)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) > strlen(%s) && !strncmp(%s, %s, strlen(%s)), " + "actualised as %zu > %zu && !strncmp(%s, %s, %zu)\n", + file, line, have_string, expect_string, have_string, expect_string, expect_string, + have_len, expect_len, quote(have, &have_quote), quote(expect, &expect_quote), expect_len); + break; + case ASSERT_NOT_GT: + if (have_len <= expect_len || strncmp(have, expect, expect_len)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) <= strlen(%s) || strncmp(%s, %s, strlen(%s)), " + "actualised as %zu <= %zu || strncmp(%s, %s, %zu)\n", + file, line, have_string, expect_string, have_string, expect_string, expect_string, + have_len, expect_len, quote(have, &have_quote), quote(expect, &expect_quote), expect_len); + break; + default: + abort(); + } + goto free_and_exit; + +assert_end: + switch (how) { + case ASSERT_GE: + if (have_len >= expect_len && !strcmp(&have[have_len - expect_len], expect)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) >= strlen(%s) && !strcmp(&(%s)[strlen(%s) - strlen(%s)], %s), " + "actualised as %zu >= %zu && !strcmp(&%s[%ti], %s)\n", + file, line, have_string, expect_string, have_string, have_string, expect_string, + expect_string, have_len, expect_len, quote(have, &have_quote), + (ptrdiff_t)have_len - (ptrdiff_t)expect_len, quote(expect, &expect_quote)); + break; + case ASSERT_NOT_GE: + if (have_len > expect_len || strcmp(&have[have_len - expect_len], expect)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) < strlen(%s) || strcmp(&(%s)[strlen(%s) - strlen(%s)], %s), " + "actualised as %zu < %zu && !strcmp(&%s[%ti], %s)\n", + file, line, have_string, expect_string, have_string, have_string, expect_string, + expect_string, have_len, expect_len, quote(have, &have_quote), + (ptrdiff_t)have_len - (ptrdiff_t)expect_len, quote(expect, &expect_quote)); + break; + case ASSERT_GT: + if (have_len > expect_len && !strcmp(&have[have_len - expect_len], expect)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) > strlen(%s) && !strcmp(&(%s)[strlen(%s) - strlen(%s)], %s), " + "actualised as %zu > %zu && !strcmp(&%s[%ti], %s)\n", + file, line, have_string, expect_string, have_string, have_string, expect_string, + expect_string, have_len, expect_len, quote(have, &have_quote), + (ptrdiff_t)have_len - (ptrdiff_t)expect_len, quote(expect, &expect_quote)); + break; + case ASSERT_NOT_GT: + if (have_len <= expect_len || strcmp(&have[have_len - expect_len], expect)) + return; + fprintf(stderr, "TEST FAILED at %s:%i: " + "asserting strlen(%s) <= strlen(%s) || strcmp(&(%s)[strlen(%s) - strlen(%s)], %s), " + "actualised as %zu <= %zu || strcmp(&%s[%ti], %s)\n", + file, line, have_string, expect_string, have_string, have_string, expect_string, + expect_string, have_len, expect_len, quote(have, &have_quote), + (ptrdiff_t)have_len - (ptrdiff_t)expect_len, quote(expect, &expect_quote)); + break; + default: + abort(); + } + goto free_and_exit; +} + + +void +test_assert(const char *file, int line, enum assert_type type, enum assert_how how, + const char *have_string, const char *expect_string, const void *have, const void *expect) +{ + switch (type) { + case ASSERT_ENUM: + case ASSERT_UINT: + test_assert_uint(file, line, how, have_string, expect_string, have, expect); + break; + + case ASSERT_INT: + test_assert_int(file, line, how, have_string, expect_string, have, expect); + break; + + case ASSERT_NULL: + case ASSERT_PTR: + test_assert_ptr(file, line, how, have_string, expect_string, have, expect); + break; + + case ASSERT_STR: + test_assert_str(file, line, how, have_string, expect_string, have, expect, 0); + break; + + case ASSERT_STR_REV: + test_assert_str(file, line, how, have_string, expect_string, have, expect, 1); + break; + + default: + abort(); + } +} -- cgit v1.2.3-70-g09d2