diff options
| author | Mattias Andrée <m@maandree.se> | 2025-02-09 15:04:27 +0100 |
|---|---|---|
| committer | Mattias Andrée <m@maandree.se> | 2025-02-09 15:04:27 +0100 |
| commit | ed004cba0e8d1d383def76f795b1e63ba0aaa89a (patch) | |
| tree | b12e5f23329f631b66c19b932551e4dff5aa477f | |
| download | liblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.gz liblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.bz2 liblog-ed004cba0e8d1d383def76f795b1e63ba0aaa89a.tar.xz | |
First commit (everything was written 2024)
Signed-off-by: Mattias Andrée <m@maandree.se>
99 files changed, 5808 insertions, 0 deletions
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 @@ -0,0 +1,15 @@ +ISC License + +© 2024 Mattias Andrée <m@maandree.se> + +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 @@ -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 <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> + + +#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 <stdarg.h> +#include <stddef.h> +#include <stdio.h> + + + +#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(); + } +} |
