diff --git a/lib/pinelog/.gitignore b/lib/pinelog/.gitignore new file mode 100644 index 0000000..3cd4832 --- /dev/null +++ b/lib/pinelog/.gitignore @@ -0,0 +1,38 @@ +# Compiled object files +*.o + +# Generated objects (source, executables, tarballs, etc.) + +# Vim swap files +.*.swp + +# Autotools objects +.deps +.dirstamp +.libs +ar-lib +autom4te.cache +m4 +compile +config.* +!config.h.in +configure +depcomp +install-sh +libtool +ltmain.sh +missing +Makefile +Makefile.in +*.la +*.lo +*.m4 +stamp-h1 +tap-driver.sh +test-driver +*.log +*.trs +*.pc + +# Build directory +/build/ diff --git a/lib/pinelog/LICENSE b/lib/pinelog/LICENSE new file mode 100644 index 0000000..ff3c685 --- /dev/null +++ b/lib/pinelog/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Nirenjan Krishnan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/lib/pinelog/Makefile.am b/lib/pinelog/Makefile.am new file mode 100644 index 0000000..ba23573 --- /dev/null +++ b/lib/pinelog/Makefile.am @@ -0,0 +1,84 @@ +# Top level Automake for pinelog +# +# Copyright (C) 2012-2018 Nirenjan Krishnan (nirenjan@nirenjan.org) +# +# SPDX-License-Identifier: MIT + +ACLOCAL_AMFLAGS = -I m4 + +# Extra files that need to be in the distribution +EXTRA_DIST = \ + LICENSE \ + README.md \ + pinelog.h + +noinst_LTLIBRARIES = libpinelog.la + +# pinelog logging library +libpinelog_la_SOURCES = pinelog.c +libpinelog_la_CFLAGS = @PINELOG_CFLAGS@ $(WARN_CFLAGS) -I $(top_builddir) +libpinelog_la_LDFLAGS = $(WARN_LDFLAGS) + +test_SRCFILES = test_pinelog.c $(libpinelog_la_SOURCES) +test_CFLAGS = \ + -DPINELOG_FATAL_STR='"F"' \ + -DPINELOG_ERROR_STR='"E"' \ + -DPINELOG_WARNING_STR='"W"' \ + -DPINELOG_INFO_STR='"I"' \ + -DPINELOG_DEBUG_STR='"D"' \ + -DPINELOG_TRACE_STR='"T"' \ + -DPINELOG_DEFAULT_LEVEL=PINELOG_LVL_TRACE \ + -DPINELOG_DEFAULT_STREAM=stderr \ + -DPINELOG_TEST -I $(top_builddir) + +LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh +TESTS = \ + test_ts_lvl_tr \ + test_ts_lvl_notr \ + test_ts_nolvl_tr \ + test_ts_nolvl_notr \ + test_nots_lvl_tr \ + test_nots_lvl_notr \ + test_nots_nolvl_tr \ + test_nots_nolvl_notr + +check_PROGRAMS = $(TESTS) +test_ts_lvl_tr_SOURCES = $(test_SRCFILES) +test_ts_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 +test_ts_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) + +test_ts_lvl_notr_SOURCES = $(test_SRCFILES) +test_ts_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 +test_ts_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) + +test_ts_nolvl_tr_SOURCES = $(test_SRCFILES) +test_ts_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 +test_ts_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) + +test_ts_nolvl_notr_SOURCES = $(test_SRCFILES) +test_ts_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=1 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 +test_ts_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) + +test_nots_lvl_tr_SOURCES = $(test_SRCFILES) +test_nots_lvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=1 +test_nots_lvl_tr_LDFLAGS = $(WARN_LDFLAGS) + +test_nots_lvl_notr_SOURCES = $(test_SRCFILES) +test_nots_lvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_BACKTRACE=0 +test_nots_lvl_notr_LDFLAGS = $(WARN_LDFLAGS) + +test_nots_nolvl_tr_SOURCES = $(test_SRCFILES) +test_nots_nolvl_tr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=1 +test_nots_nolvl_tr_LDFLAGS = $(WARN_LDFLAGS) + +test_nots_nolvl_notr_SOURCES = $(test_SRCFILES) +test_nots_nolvl_notr_CFLAGS = $(WARN_CFLAGS) $(test_CFLAGS) \ + -DPINELOG_SHOW_DATE=0 -DPINELOG_SHOW_LEVEL=0 -DPINELOG_SHOW_BACKTRACE=0 +test_nots_nolvl_notr_LDFLAGS = $(WARN_LDFLAGS) diff --git a/lib/pinelog/README.md b/lib/pinelog/README.md new file mode 100644 index 0000000..01923d6 --- /dev/null +++ b/lib/pinelog/README.md @@ -0,0 +1,134 @@ +Pinelog - a lightweight logging API +=================================== + +Pinelog is a lightweight logging API for C programs that's designed to be +included in your program source code. Parameters for Pinelog are configured at +build time by means of preprocessor flags. + +# Usage +## Logging macros + +Pinelog uses `printf` style formatting, using the following list of macros. The +macro indicates the level at which the message is logged. + +* `PINELOG_FATAL` +* `PINELOG_ERROR` +* `PINELOG_WARN` +* `PINELOG_INFO` +* `PINELOG_DEBUG` +* `PINELOG_TRACE` + +**Note:** `PINELOG_FATAL` is used when the program encounters a fatal condition +and needs to abort. This will log the fatal message and terminate the program +with an exit code of 1. + +### Example + +```C +PINELOG_INFO("configuration file %s not found, using defaults", config_file); +``` + +## Logging levels + +The default logging level is `ERROR`, and this can be controlled by the +preprocessor flag `PINELOG_DEFAULT_LEVEL`. + +The program can control the level at which messages can be logged at runtime, +by using the `pinelog_set_level` function. This function takes in the level +definition, which is one of the following, in increasing order of priority. + +* `PINELOG_LVL_TRACE` +* `PINELOG_LVL_DEBUG` +* `PINELOG_LVL_INFO` +* `PINELOG_LVL_WARNING` +* `PINELOG_LVL_ERROR` +* `PINELOG_LVL_FATAL` +* `PINELOG_LVL_NONE` + +Setting the level to a given priority suppresses all log messages of lower +priority, i.e., if the level is set to `PINELOG_LVL_ERROR`, messages at +`WARNING` level and below will be suppressed, but `ERROR` and `FATAL` messages +will be logged. + +**Note:** `PINELOG_LVL_NONE` suppresses all log messages, but `PINELOG_FATAL` +will still terminate the program, even though nothing is logged. + +### Example + +```C +pinelog_set_level(PINELOG_LVL_WARNING); +``` + +``` +-DPINELOG_DEFAULT_LEVEL=PINELOG_LVL_WARNING +``` + +## Output redirection + +Pinelog defaults to writing the log messages to standard output, and this can +be controlled by the preprocessor flag `PINELOG_DEFAULT_STREAM`. + +However, the application can redirect log messages at runtime to a different +`FILE *` stream, or to a file by using one of the following two methods: + +```C +FILE *out = fopen("/run/app.fifo", "w"); +pinelog_set_output_stream(out); +pinelog_set_output_file("/var/log/app.log"); +``` + +``` +-DPINELOG_DEFAULT_STREAM=stderr +``` + +## Logging format + +Pinelog uses an opinionated logging format that is fixed as follows. Fields +within `[]` are optional and controlled by build time flags. + + [2021-07-14 11:08:04 ][ERROR: ][./test_pinelog.c:108 ]formatted message. + +The program can be controlled by the following preprocessor flags, all of which +default to `0` (disabled). Set the flag to `1` to enable it. + +* `PINELOG_SHOW_DATE` - Display the ISO 8601 date and time when the message is + logged. +* `PINELOG_SHOW_LEVEL` - Display the level at which the message is logged. +* `PINELOG_SHOW_BACKTRACE` - Display the file and line where the message is + logged. + +Set these flags by using the `-D` compiler argument, .e.g. +`-DPINELOG_SHOW_LEVEL=1 -DPINELOG_SHOW_DATE=1` + +### Level strings + +The application can control the level strings displayed by means of preprocessor +flags, if the application wishes to display the log messages in a language other +than English. This can be achieved by means of the following preprocessor +definitions. + +* `PINELOG_FATAL_STR` +* `PINELOG_ERROR_STR` +* `PINELOG_WARNING_STR` +* `PINELOG_INFO_STR` +* `PINELOG_DEBUG_STR` +* `PINELOG_TRACE_STR` + +### Example + +``` +-DPINELOG_ERROR_STR=\"E\" -DPINELOG_FATAL_STR=\"F\" +``` + +# Integrating Pinelog + +Pinelog is intended to be integrated into your application source tree, either +by means of including the sources directly, or by including the repository as +a Git submodule or subtree. + +The default build of Pinelog uses an autotools generated `config.h` file, which +includes checks for the following GCC attributes. If you don't care about these, +then either create a dummy config.h which includes the macros +`HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR` and `HAVE_FUNC_ATTRIBUTE_FORMAT`, or use the +`AX_GCC_FUNC_ATTRIBUTE` macro to check for the `constructor` and `format` +attributes in your application's `configure.ac` file. diff --git a/lib/pinelog/autogen.sh b/lib/pinelog/autogen.sh new file mode 100755 index 0000000..e10d140 --- /dev/null +++ b/lib/pinelog/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh -x + +autoreconf --install diff --git a/lib/pinelog/config.h.in b/lib/pinelog/config.h.in new file mode 100644 index 0000000..392d9b0 --- /dev/null +++ b/lib/pinelog/config.h.in @@ -0,0 +1,67 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if the system has the `constructor' function attribute */ +#undef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR + +/* Define to 1 if the system has the `format' function attribute */ +#undef HAVE_FUNC_ATTRIBUTE_FORMAT + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION diff --git a/lib/pinelog/configure.ac b/lib/pinelog/configure.ac new file mode 100644 index 0000000..133e102 --- /dev/null +++ b/lib/pinelog/configure.ac @@ -0,0 +1,28 @@ +# Autoconf settings for pinelog +# +# Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) +# +# SPDX-License-Identifier: MIT + +AC_INIT([pinelog], [1.0.0], [nirenjan@nirenjan.org]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) +AC_REQUIRE_AUX_FILE([tap-driver.sh]) +AC_PROG_CC +AC_PROG_CC_STDC +AC_PROG_AWK +AM_PROG_AR +LT_INIT +PKG_PROG_PKG_CONFIG +PKG_INSTALLDIR +AX_COMPILER_FLAGS +AX_GCC_FUNC_ATTRIBUTE([constructor]) +AX_GCC_FUNC_ATTRIBUTE([format]) + +AC_SUBST([PINELOG_CFLAGS]) + +# Configuration headers +AC_CONFIG_HEADERS([config.h]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/lib/pinelog/m4/ax_append_compile_flags.m4 b/lib/pinelog/m4/ax_append_compile_flags.m4 new file mode 100644 index 0000000..9c85635 --- /dev/null +++ b/lib/pinelog/m4/ax_append_compile_flags.m4 @@ -0,0 +1,46 @@ +# ============================================================================ +# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the compiler works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. During the check the flag is always added to the +# current language's flags. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and +# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with +# AX_APPEND_LINK_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_APPEND_COMPILE_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) +done +])dnl AX_APPEND_COMPILE_FLAGS diff --git a/lib/pinelog/m4/ax_append_flag.m4 b/lib/pinelog/m4/ax_append_flag.m4 new file mode 100644 index 0000000..dd6d8b6 --- /dev/null +++ b/lib/pinelog/m4/ax_append_flag.m4 @@ -0,0 +1,50 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/lib/pinelog/m4/ax_append_link_flags.m4 b/lib/pinelog/m4/ax_append_link_flags.m4 new file mode 100644 index 0000000..99b9fa5 --- /dev/null +++ b/lib/pinelog/m4/ax_append_link_flags.m4 @@ -0,0 +1,44 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the linker works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is +# used. During the check the flag is always added to the linker's flags. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. +# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 7 + +AC_DEFUN([AX_APPEND_LINK_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4]) +done +])dnl AX_APPEND_LINK_FLAGS diff --git a/lib/pinelog/m4/ax_check_compile_flag.m4 b/lib/pinelog/m4/ax_check_compile_flag.m4 new file mode 100644 index 0000000..bd753b3 --- /dev/null +++ b/lib/pinelog/m4/ax_check_compile_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/lib/pinelog/m4/ax_check_link_flag.m4 b/lib/pinelog/m4/ax_check_link_flag.m4 new file mode 100644 index 0000000..03a30ce --- /dev/null +++ b/lib/pinelog/m4/ax_check_link_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/lib/pinelog/m4/ax_compiler_flags.m4 b/lib/pinelog/m4/ax_compiler_flags.m4 new file mode 100644 index 0000000..ddb0456 --- /dev/null +++ b/lib/pinelog/m4/ax_compiler_flags.m4 @@ -0,0 +1,158 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_FLAGS([CFLAGS-VARIABLE], [LDFLAGS-VARIABLE], [IS-RELEASE], [EXTRA-BASE-CFLAGS], [EXTRA-YES-CFLAGS], [UNUSED], [UNUSED], [UNUSED], [EXTRA-BASE-LDFLAGS], [EXTRA-YES-LDFLAGS], [UNUSED], [UNUSED], [UNUSED]) +# +# DESCRIPTION +# +# Check for the presence of an --enable-compile-warnings option to +# configure, defaulting to "error" in normal operation, or "yes" if +# IS-RELEASE is equal to "yes". Return the value in the variable +# $ax_enable_compile_warnings. +# +# Depending on the value of --enable-compile-warnings, different compiler +# warnings are checked to see if they work with the current compiler and, +# if so, are appended to CFLAGS-VARIABLE and LDFLAGS-VARIABLE. This +# allows a consistent set of baseline compiler warnings to be used across +# a code base, irrespective of any warnings enabled locally by individual +# developers. By standardising the warnings used by all developers of a +# project, the project can commit to a zero-warnings policy, using -Werror +# to prevent compilation if new warnings are introduced. This makes +# catching bugs which are flagged by warnings a lot easier. +# +# By providing a consistent --enable-compile-warnings argument across all +# projects using this macro, continuous integration systems can easily be +# configured the same for all projects. Automated systems or build +# systems aimed at beginners may want to pass the --disable-Werror +# argument to unconditionally prevent warnings being fatal. +# +# --enable-compile-warnings can take the values: +# +# * no: Base compiler warnings only; not even -Wall. +# * yes: The above, plus a broad range of useful warnings. +# * error: The above, plus -Werror so that all warnings are fatal. +# Use --disable-Werror to override this and disable fatal +# warnings. +# +# The set of base and enabled flags can be augmented using the +# EXTRA-*-CFLAGS and EXTRA-*-LDFLAGS variables, which are tested and +# appended to the output variable if --enable-compile-warnings is not +# "no". Flags should not be disabled using these arguments, as the entire +# point of AX_COMPILER_FLAGS is to enforce a consistent set of useful +# compiler warnings on code, using warnings which have been chosen for low +# false positive rates. If a compiler emits false positives for a +# warning, a #pragma should be used in the code to disable the warning +# locally. See: +# +# https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/Diagnostic-Pragmas.html#Diagnostic-Pragmas +# +# The EXTRA-* variables should only be used to supply extra warning flags, +# and not general purpose compiler flags, as they are controlled by +# configure options such as --disable-Werror. +# +# IS-RELEASE can be used to disable -Werror when making a release, which +# is useful for those hairy moments when you just want to get the release +# done as quickly as possible. Set it to "yes" to disable -Werror. By +# default, it uses the value of $ax_is_release, so if you are using the +# AX_IS_RELEASE macro, there is no need to pass this parameter. For +# example: +# +# AX_IS_RELEASE([git-directory]) +# AX_COMPILER_FLAGS() +# +# CFLAGS-VARIABLE defaults to WARN_CFLAGS, and LDFLAGS-VARIABLE defaults +# to WARN_LDFLAGS. Both variables are AC_SUBST-ed by this macro, but must +# be manually added to the CFLAGS and LDFLAGS variables for each target in +# the code base. +# +# If C++ language support is enabled with AC_PROG_CXX, which must occur +# before this macro in configure.ac, warning flags for the C++ compiler +# are AC_SUBST-ed as WARN_CXXFLAGS, and must be manually added to the +# CXXFLAGS variables for each target in the code base. EXTRA-*-CFLAGS can +# be used to augment the base and enabled flags. +# +# Warning flags for g-ir-scanner (from GObject Introspection) are +# AC_SUBST-ed as WARN_SCANNERFLAGS. This variable must be manually added +# to the SCANNERFLAGS variable for each GIR target in the code base. If +# extra g-ir-scanner flags need to be enabled, the AX_COMPILER_FLAGS_GIR +# macro must be invoked manually. +# +# AX_COMPILER_FLAGS may add support for other tools in future, in addition +# to the compiler and linker. No extra EXTRA-* variables will be added +# for those tools, and all extra support will still use the single +# --enable-compile-warnings configure option. For finer grained control +# over the flags for individual tools, use AX_COMPILER_FLAGS_CFLAGS, +# AX_COMPILER_FLAGS_LDFLAGS and AX_COMPILER_FLAGS_* for new tools. +# +# The UNUSED variables date from a previous version of this macro, and are +# automatically appended to the preceding non-UNUSED variable. They should +# be left empty in new uses of the macro. +# +# LICENSE +# +# Copyright (c) 2014, 2015 Philip Withnall +# Copyright (c) 2015 David King +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 14 + +# _AX_COMPILER_FLAGS_LANG([LANGNAME]) +m4_defun([_AX_COMPILER_FLAGS_LANG], +[m4_ifdef([_AX_COMPILER_FLAGS_LANG_]$1[_enabled], [], + [m4_define([_AX_COMPILER_FLAGS_LANG_]$1[_enabled], [])dnl + AX_REQUIRE_DEFINED([AX_COMPILER_FLAGS_]$1[FLAGS])])dnl +]) + +AC_DEFUN([AX_COMPILER_FLAGS],[ + # C support is enabled by default. + _AX_COMPILER_FLAGS_LANG([C]) + # Only enable C++ support if AC_PROG_CXX is called. The redefinition of + # AC_PROG_CXX is so that a fatal error is emitted if this macro is called + # before AC_PROG_CXX, which would otherwise cause no C++ warnings to be + # checked. + AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AX_COMPILER_FLAGS_LANG([CXX])], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AX_COMPILER_FLAGS_LANG([CXX])])]) + AX_REQUIRE_DEFINED([AX_COMPILER_FLAGS_LDFLAGS]) + + # Default value for IS-RELEASE is $ax_is_release + ax_compiler_flags_is_release=m4_tolower(m4_normalize(ifelse([$3],, + [$ax_is_release], + [$3]))) + + AC_ARG_ENABLE([compile-warnings], + AS_HELP_STRING([--enable-compile-warnings=@<:@no/yes/error@:>@], + [Enable compiler warnings and errors]),, + [AS_IF([test "$ax_compiler_flags_is_release" = "yes"], + [enable_compile_warnings="yes"], + [enable_compile_warnings="error"])]) + AC_ARG_ENABLE([Werror], + AS_HELP_STRING([--disable-Werror], + [Unconditionally make all compiler warnings non-fatal]),, + [enable_Werror=maybe]) + + # Return the user's chosen warning level + AS_IF([test "$enable_Werror" = "no" -a \ + "$enable_compile_warnings" = "error"],[ + enable_compile_warnings="yes" + ]) + + ax_enable_compile_warnings=$enable_compile_warnings + + AX_COMPILER_FLAGS_CFLAGS([$1],[$ax_compiler_flags_is_release], + [$4],[$5 $6 $7 $8]) + m4_ifdef([_AX_COMPILER_FLAGS_LANG_CXX_enabled], + [AX_COMPILER_FLAGS_CXXFLAGS([WARN_CXXFLAGS], + [$ax_compiler_flags_is_release], + [$4],[$5 $6 $7 $8])]) + AX_COMPILER_FLAGS_LDFLAGS([$2],[$ax_compiler_flags_is_release], + [$9],[$10 $11 $12 $13]) + AX_COMPILER_FLAGS_GIR([WARN_SCANNERFLAGS],[$ax_compiler_flags_is_release]) +])dnl AX_COMPILER_FLAGS diff --git a/lib/pinelog/m4/ax_compiler_flags_cflags.m4 b/lib/pinelog/m4/ax_compiler_flags_cflags.m4 new file mode 100644 index 0000000..916f918 --- /dev/null +++ b/lib/pinelog/m4/ax_compiler_flags_cflags.m4 @@ -0,0 +1,161 @@ +# ============================================================================= +# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_cflags.html +# ============================================================================= +# +# SYNOPSIS +# +# AX_COMPILER_FLAGS_CFLAGS([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS]) +# +# DESCRIPTION +# +# Add warning flags for the C compiler to VARIABLE, which defaults to +# WARN_CFLAGS. VARIABLE is AC_SUBST-ed by this macro, but must be +# manually added to the CFLAGS variable for each target in the code base. +# +# This macro depends on the environment set up by AX_COMPILER_FLAGS. +# Specifically, it uses the value of $ax_enable_compile_warnings to decide +# which flags to enable. +# +# LICENSE +# +# Copyright (c) 2014, 2015 Philip Withnall +# Copyright (c) 2017, 2018 Reini Urban +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 17 + +AC_DEFUN([AX_COMPILER_FLAGS_CFLAGS],[ + AC_REQUIRE([AC_PROG_SED]) + AX_REQUIRE_DEFINED([AX_APPEND_COMPILE_FLAGS]) + AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) + AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) + + # Variable names + m4_define([ax_warn_cflags_variable], + [m4_normalize(ifelse([$1],,[WARN_CFLAGS],[$1]))]) + + AC_LANG_PUSH([C]) + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ + [#ifndef __cplusplus + #error "no C++" + #endif]])], + [ax_compiler_cxx=yes;], + [ax_compiler_cxx=no;]) + + # Always pass -Werror=unknown-warning-option to get Clang to fail on bad + # flags, otherwise they are always appended to the warn_cflags variable, and + # Clang warns on them for every compilation unit. + # If this is passed to GCC, it will explode, so the flag must be enabled + # conditionally. + AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[ + ax_compiler_flags_test="-Werror=unknown-warning-option" + ],[ + ax_compiler_flags_test="" + ]) + + # Check that -Wno-suggest-attribute=format is supported + AX_CHECK_COMPILE_FLAG([-Wno-suggest-attribute=format],[ + ax_compiler_no_suggest_attribute_flags="-Wno-suggest-attribute=format" + ],[ + ax_compiler_no_suggest_attribute_flags="" + ]) + + # Base flags + AX_APPEND_COMPILE_FLAGS([ dnl + -fno-strict-aliasing dnl + $3 dnl + ],ax_warn_cflags_variable,[$ax_compiler_flags_test]) + + AS_IF([test "$ax_enable_compile_warnings" != "no"],[ + if test "$ax_compiler_cxx" = "no" ; then + # C-only flags. Warn in C++ + AX_APPEND_COMPILE_FLAGS([ dnl + -Wnested-externs dnl + -Wmissing-prototypes dnl + -Wstrict-prototypes dnl + -Wdeclaration-after-statement dnl + -Wimplicit-function-declaration dnl + -Wold-style-definition dnl + -Wjump-misses-init dnl + ],ax_warn_cflags_variable,[$ax_compiler_flags_test]) + fi + + # "yes" flags + AX_APPEND_COMPILE_FLAGS([ dnl + -Wall dnl + -Wextra dnl + -Wundef dnl + -Wwrite-strings dnl + -Wpointer-arith dnl + -Wmissing-declarations dnl + -Wredundant-decls dnl + -Wno-unused-parameter dnl + -Wno-missing-field-initializers dnl + -Wformat=2 dnl + -Wcast-align dnl + -Wformat-nonliteral dnl + -Wformat-security dnl + -Wsign-compare dnl + -Wstrict-aliasing dnl + -Wshadow dnl + -Winline dnl + -Wpacked dnl + -Wmissing-format-attribute dnl + -Wmissing-noreturn dnl + -Winit-self dnl + -Wredundant-decls dnl + -Wmissing-include-dirs dnl + -Wunused-but-set-variable dnl + -Warray-bounds dnl + -Wreturn-type dnl + -Wswitch-enum dnl + -Wswitch-default dnl + -Wduplicated-cond dnl + -Wduplicated-branches dnl + -Wlogical-op dnl + -Wrestrict dnl + -Wnull-dereference dnl + -Wdouble-promotion dnl + $4 dnl + $5 dnl + $6 dnl + $7 dnl + ],ax_warn_cflags_variable,[$ax_compiler_flags_test]) + ]) + AS_IF([test "$ax_enable_compile_warnings" = "error"],[ + # "error" flags; -Werror has to be appended unconditionally because + # it's not possible to test for + # + # suggest-attribute=format is disabled because it gives too many false + # positives + AX_APPEND_FLAG([-Werror],ax_warn_cflags_variable) + + AX_APPEND_COMPILE_FLAGS([ dnl + [$ax_compiler_no_suggest_attribute_flags] dnl + ],ax_warn_cflags_variable,[$ax_compiler_flags_test]) + ]) + + # In the flags below, when disabling specific flags, always add *both* + # -Wno-foo and -Wno-error=foo. This fixes the situation where (for example) + # we enable -Werror, disable a flag, and a build bot passes CFLAGS=-Wall, + # which effectively turns that flag back on again as an error. + for flag in $ax_warn_cflags_variable; do + AS_CASE([$flag], + [-Wno-*=*],[], + [-Wno-*],[ + AX_APPEND_COMPILE_FLAGS([-Wno-error=$(AS_ECHO([$flag]) | $SED 's/^-Wno-//')], + ax_warn_cflags_variable, + [$ax_compiler_flags_test]) + ]) + done + + AC_LANG_POP([C]) + + # Substitute the variables + AC_SUBST(ax_warn_cflags_variable) +])dnl AX_COMPILER_FLAGS diff --git a/lib/pinelog/m4/ax_compiler_flags_gir.m4 b/lib/pinelog/m4/ax_compiler_flags_gir.m4 new file mode 100644 index 0000000..5b4924a --- /dev/null +++ b/lib/pinelog/m4/ax_compiler_flags_gir.m4 @@ -0,0 +1,60 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_gir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_FLAGS_GIR([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS]) +# +# DESCRIPTION +# +# Add warning flags for the g-ir-scanner (from GObject Introspection) to +# VARIABLE, which defaults to WARN_SCANNERFLAGS. VARIABLE is AC_SUBST-ed +# by this macro, but must be manually added to the SCANNERFLAGS variable +# for each GIR target in the code base. +# +# This macro depends on the environment set up by AX_COMPILER_FLAGS. +# Specifically, it uses the value of $ax_enable_compile_warnings to decide +# which flags to enable. +# +# LICENSE +# +# Copyright (c) 2015 Philip Withnall +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_COMPILER_FLAGS_GIR],[ + AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) + + # Variable names + m4_define([ax_warn_scannerflags_variable], + [m4_normalize(ifelse([$1],,[WARN_SCANNERFLAGS],[$1]))]) + + # Base flags + AX_APPEND_FLAG([$3],ax_warn_scannerflags_variable) + + AS_IF([test "$ax_enable_compile_warnings" != "no"],[ + # "yes" flags + AX_APPEND_FLAG([ dnl + --warn-all dnl + $4 dnl + $5 dnl + $6 dnl + $7 dnl + ],ax_warn_scannerflags_variable) + ]) + AS_IF([test "$ax_enable_compile_warnings" = "error"],[ + # "error" flags + AX_APPEND_FLAG([ dnl + --warn-error dnl + ],ax_warn_scannerflags_variable) + ]) + + # Substitute the variables + AC_SUBST(ax_warn_scannerflags_variable) +])dnl AX_COMPILER_FLAGS diff --git a/lib/pinelog/m4/ax_compiler_flags_ldflags.m4 b/lib/pinelog/m4/ax_compiler_flags_ldflags.m4 new file mode 100644 index 0000000..976d119 --- /dev/null +++ b/lib/pinelog/m4/ax_compiler_flags_ldflags.m4 @@ -0,0 +1,111 @@ +# ============================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_flags_ldflags.html +# ============================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_FLAGS_LDFLAGS([VARIABLE], [IS-RELEASE], [EXTRA-BASE-FLAGS], [EXTRA-YES-FLAGS]) +# +# DESCRIPTION +# +# Add warning flags for the linker to VARIABLE, which defaults to +# WARN_LDFLAGS. VARIABLE is AC_SUBST-ed by this macro, but must be +# manually added to the LDFLAGS variable for each target in the code base. +# +# This macro depends on the environment set up by AX_COMPILER_FLAGS. +# Specifically, it uses the value of $ax_enable_compile_warnings to decide +# which flags to enable. +# +# LICENSE +# +# Copyright (c) 2014, 2015 Philip Withnall +# Copyright (c) 2017, 2018 Reini Urban +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 9 + +AC_DEFUN([AX_COMPILER_FLAGS_LDFLAGS],[ + AX_REQUIRE_DEFINED([AX_APPEND_LINK_FLAGS]) + AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) + AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) + AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) + + # Variable names + m4_define([ax_warn_ldflags_variable], + [m4_normalize(ifelse([$1],,[WARN_LDFLAGS],[$1]))]) + + # Always pass -Werror=unknown-warning-option to get Clang to fail on bad + # flags, otherwise they are always appended to the warn_ldflags variable, + # and Clang warns on them for every compilation unit. + # If this is passed to GCC, it will explode, so the flag must be enabled + # conditionally. + AX_CHECK_COMPILE_FLAG([-Werror=unknown-warning-option],[ + ax_compiler_flags_test="-Werror=unknown-warning-option" + ],[ + ax_compiler_flags_test="" + ]) + + AX_CHECK_LINK_FLAG([-Wl,--as-needed], [ + AX_APPEND_LINK_FLAGS([-Wl,--as-needed], + [AM_LDFLAGS],[$ax_compiler_flags_test]) + ]) + AX_CHECK_LINK_FLAG([-Wl,-z,relro], [ + AX_APPEND_LINK_FLAGS([-Wl,-z,relro], + [AM_LDFLAGS],[$ax_compiler_flags_test]) + ]) + AX_CHECK_LINK_FLAG([-Wl,-z,now], [ + AX_APPEND_LINK_FLAGS([-Wl,-z,now], + [AM_LDFLAGS],[$ax_compiler_flags_test]) + ]) + AX_CHECK_LINK_FLAG([-Wl,-z,noexecstack], [ + AX_APPEND_LINK_FLAGS([-Wl,-z,noexecstack], + [AM_LDFLAGS],[$ax_compiler_flags_test]) + ]) + # textonly, retpolineplt not yet + + # macOS and cygwin linker do not have --as-needed + AX_CHECK_LINK_FLAG([-Wl,--no-as-needed], [ + ax_compiler_flags_as_needed_option="-Wl,--no-as-needed" + ], [ + ax_compiler_flags_as_needed_option="" + ]) + + # macOS linker speaks with a different accent + ax_compiler_flags_fatal_warnings_option="" + AX_CHECK_LINK_FLAG([-Wl,--fatal-warnings], [ + ax_compiler_flags_fatal_warnings_option="-Wl,--fatal-warnings" + ]) + AX_CHECK_LINK_FLAG([-Wl,-fatal_warnings], [ + ax_compiler_flags_fatal_warnings_option="-Wl,-fatal_warnings" + ]) + + # Base flags + AX_APPEND_LINK_FLAGS([ dnl + $ax_compiler_flags_as_needed_option dnl + $3 dnl + ],ax_warn_ldflags_variable,[$ax_compiler_flags_test]) + + AS_IF([test "$ax_enable_compile_warnings" != "no"],[ + # "yes" flags + AX_APPEND_LINK_FLAGS([$4 $5 $6 $7], + ax_warn_ldflags_variable, + [$ax_compiler_flags_test]) + ]) + AS_IF([test "$ax_enable_compile_warnings" = "error"],[ + # "error" flags; -Werror has to be appended unconditionally because + # it's not possible to test for + # + # suggest-attribute=format is disabled because it gives too many false + # positives + AX_APPEND_LINK_FLAGS([ dnl + $ax_compiler_flags_fatal_warnings_option dnl + ],ax_warn_ldflags_variable,[$ax_compiler_flags_test]) + ]) + + # Substitute the variables + AC_SUBST(ax_warn_ldflags_variable) +])dnl AX_COMPILER_FLAGS diff --git a/lib/pinelog/m4/ax_gcc_func_attribute.m4 b/lib/pinelog/m4/ax_gcc_func_attribute.m4 new file mode 100644 index 0000000..fa4e089 --- /dev/null +++ b/lib/pinelog/m4/ax_gcc_func_attribute.m4 @@ -0,0 +1,242 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE) +# +# DESCRIPTION +# +# This macro checks if the compiler supports one of GCC's function +# attributes; many other compilers also provide function attributes with +# the same syntax. Compiler warnings are used to detect supported +# attributes as unsupported ones are ignored by default so quieting +# warnings when using this macro will yield false positives. +# +# The ATTRIBUTE parameter holds the name of the attribute to be checked. +# +# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_. +# +# The macro caches its result in the ax_cv_have_func_attribute_ +# variable. +# +# The macro currently supports the following function attributes: +# +# alias +# aligned +# alloc_size +# always_inline +# artificial +# cold +# const +# constructor +# constructor_priority for constructor attribute with priority +# deprecated +# destructor +# dllexport +# dllimport +# error +# externally_visible +# fallthrough +# flatten +# format +# format_arg +# gnu_format +# gnu_inline +# hot +# ifunc +# leaf +# malloc +# noclone +# noinline +# nonnull +# noreturn +# nothrow +# optimize +# pure +# sentinel +# sentinel_position +# unused +# used +# visibility +# warning +# warn_unused_result +# weak +# weakref +# +# Unsupported function attributes will be tested with a prototype +# returning an int and not accepting any arguments and the result of the +# check might be wrong or meaningless so use with care. +# +# LICENSE +# +# Copyright (c) 2013 Gabriele Svelto +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 13 + +AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [ + AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1]) + + AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [ + AC_LINK_IFELSE([AC_LANG_PROGRAM([ + m4_case([$1], + [alias], [ + int foo( void ) { return 0; } + int bar( void ) __attribute__(($1("foo"))); + ], + [aligned], [ + int foo( void ) __attribute__(($1(32))); + ], + [alloc_size], [ + void *foo(int a) __attribute__(($1(1))); + ], + [always_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [artificial], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [cold], [ + int foo( void ) __attribute__(($1)); + ], + [const], [ + int foo( void ) __attribute__(($1)); + ], + [constructor_priority], [ + int foo( void ) __attribute__((__constructor__(65535/2))); + ], + [constructor], [ + int foo( void ) __attribute__(($1)); + ], + [deprecated], [ + int foo( void ) __attribute__(($1(""))); + ], + [destructor], [ + int foo( void ) __attribute__(($1)); + ], + [dllexport], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [dllimport], [ + int foo( void ) __attribute__(($1)); + ], + [error], [ + int foo( void ) __attribute__(($1(""))); + ], + [externally_visible], [ + int foo( void ) __attribute__(($1)); + ], + [fallthrough], [ + void foo( int x ) {switch (x) { case 1: __attribute__(($1)); case 2: break ; }}; + ], + [flatten], [ + int foo( void ) __attribute__(($1)); + ], + [format], [ + int foo(const char *p, ...) __attribute__(($1(printf, 1, 2))); + ], + [gnu_format], [ + int foo(const char *p, ...) __attribute__((format(gnu_printf, 1, 2))); + ], + [format_arg], [ + char *foo(const char *p) __attribute__(($1(1))); + ], + [gnu_inline], [ + inline __attribute__(($1)) int foo( void ) { return 0; } + ], + [hot], [ + int foo( void ) __attribute__(($1)); + ], + [ifunc], [ + int my_foo( void ) { return 0; } + static int (*resolve_foo(void))(void) { return my_foo; } + int foo( void ) __attribute__(($1("resolve_foo"))); + ], + [leaf], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [malloc], [ + void *foo( void ) __attribute__(($1)); + ], + [noclone], [ + int foo( void ) __attribute__(($1)); + ], + [noinline], [ + __attribute__(($1)) int foo( void ) { return 0; } + ], + [nonnull], [ + int foo(char *p) __attribute__(($1(1))); + ], + [noreturn], [ + void foo( void ) __attribute__(($1)); + ], + [nothrow], [ + int foo( void ) __attribute__(($1)); + ], + [optimize], [ + __attribute__(($1(3))) int foo( void ) { return 0; } + ], + [pure], [ + int foo( void ) __attribute__(($1)); + ], + [sentinel], [ + int foo(void *p, ...) __attribute__(($1)); + ], + [sentinel_position], [ + int foo(void *p, ...) __attribute__(($1(1))); + ], + [returns_nonnull], [ + void *foo( void ) __attribute__(($1)); + ], + [unused], [ + int foo( void ) __attribute__(($1)); + ], + [used], [ + int foo( void ) __attribute__(($1)); + ], + [visibility], [ + int foo_def( void ) __attribute__(($1("default"))); + int foo_hid( void ) __attribute__(($1("hidden"))); + int foo_int( void ) __attribute__(($1("internal"))); + int foo_pro( void ) __attribute__(($1("protected"))); + ], + [warning], [ + int foo( void ) __attribute__(($1(""))); + ], + [warn_unused_result], [ + int foo( void ) __attribute__(($1)); + ], + [weak], [ + int foo( void ) __attribute__(($1)); + ], + [weakref], [ + static int foo( void ) { return 0; } + static int bar( void ) __attribute__(($1("foo"))); + ], + [ + m4_warn([syntax], [Unsupported attribute $1, the test may fail]) + int foo( void ) __attribute__(($1)); + ] + )], []) + ], + dnl GCC doesn't exit with an error if an unknown attribute is + dnl provided but only outputs a warning, so accept the attribute + dnl only if no warning were issued. + [AS_IF([grep -- -Wattributes conftest.err], + [AS_VAR_SET([ac_var], [no])], + [AS_VAR_SET([ac_var], [yes])])], + [AS_VAR_SET([ac_var], [no])]) + ]) + + AS_IF([test yes = AS_VAR_GET([ac_var])], + [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1, + [Define to 1 if the system has the `$1' function attribute])], []) + + AS_VAR_POPDEF([ac_var]) +]) diff --git a/lib/pinelog/m4/ax_require_defined.m4 b/lib/pinelog/m4/ax_require_defined.m4 new file mode 100644 index 0000000..17c3eab --- /dev/null +++ b/lib/pinelog/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED diff --git a/lib/pinelog/pinelog.c b/lib/pinelog/pinelog.c new file mode 100644 index 0000000..1c793c5 --- /dev/null +++ b/lib/pinelog/pinelog.c @@ -0,0 +1,208 @@ +/* + * Pinelog lightweight logging library + * + * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: MIT + */ + +#include "config.h" +#include +#include +#include +#include + +#include "pinelog.h" + +/********************************************************************** + * Configure defaults + *********************************************************************/ +#ifndef PINELOG_DEFAULT_STREAM +#define PINELOG_DEFAULT_STREAM stdout +#endif + +#ifndef PINELOG_DEFAULT_LEVEL +#define PINELOG_DEFAULT_LEVEL PINELOG_LVL_ERROR +#endif + +/********************************************************************** + * Configure logging parameters + *********************************************************************/ +#ifndef PINELOG_SHOW_DATE +#define PINELOG_SHOW_DATE 0 +#endif + +#ifndef PINELOG_SHOW_LEVEL +#define PINELOG_SHOW_LEVEL 0 +#endif + +#ifndef PINELOG_SHOW_BACKTRACE +#define PINELOG_SHOW_BACKTRACE 0 +#endif + +/********************************************************************** + * Configure level strings + *********************************************************************/ +#ifndef PINELOG_FATAL_STR +#define PINELOG_FATAL_STR "FATAL" +#endif + +#ifndef PINELOG_ERROR_STR +#define PINELOG_ERROR_STR "ERROR" +#endif + +#ifndef PINELOG_WARNING_STR +#define PINELOG_WARNING_STR "WARNING" +#endif + +#ifndef PINELOG_INFO_STR +#define PINELOG_INFO_STR "INFO" +#endif + +#ifndef PINELOG_DEBUG_STR +#define PINELOG_DEBUG_STR "DEBUG" +#endif + +#ifndef PINELOG_TRACE_STR +#define PINELOG_TRACE_STR "TRACE" +#endif + +/********************************************************************** + * Global variables + *********************************************************************/ + +/** Stream buffer */ +static FILE *output_stream = NULL; + +/** Default logging level */ +static int log_level = PINELOG_DEFAULT_LEVEL; + +/* Initialize defaults */ +#if HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR +__attribute__((constructor)) +#endif +void pinelog_set_defaults(void) +{ + output_stream = PINELOG_DEFAULT_STREAM; + log_level = PINELOG_DEFAULT_LEVEL; +} + +int pinelog_set_output_stream(FILE *stream) +{ + if (stream == NULL) { + return EINVAL; + } + + /* If current output stream is not stdout or stderr, then close it */ + if (output_stream != stdout && output_stream != stderr) { + fclose(output_stream); + } + + setlinebuf(stream); + output_stream = stream; + return 0; +} + +#ifdef PINELOG_TEST +FILE * pinelog_get_output_stream(void) +{ + return output_stream; +} +#endif + +int pinelog_set_output_file(const char *file) +{ + FILE *stream; + if (file == NULL) { + return EINVAL; + } + + errno = 0; + stream = fopen(file, "w"); + if (stream == NULL) { + return errno; + } + + return pinelog_set_output_stream(stream); +} + +int pinelog_get_level(void) +{ + return log_level; +} + +int pinelog_set_level(int level) +{ + if (level < PINELOG_LVL_NONE || level > PINELOG_LVL_TRACE) { + return EINVAL; + } + + log_level = level; + return 0; +} + +/********************************************************************** + * Log the message to the output stream + *********************************************************************/ +void pinelog_log_message(int level, const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + /* Don't log anything if the level is not severe enough */ + if (level > log_level || level < 0) { + return; + } + + /* Cap the log level */ + if (level > PINELOG_LVL_TRACE) { + level = PINELOG_LVL_TRACE; + } + + #if !HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR + /* + * Validate and set output stream. Only necessary if the compiler doesn't + * support the constructor attribute + */ + if (output_stream == NULL) { + output_stream = PINELOG_DEFAULT_STREAM; + } + #endif + + #if PINELOG_SHOW_DATE + do { + time_t t; + struct tm *tmp; + char date_string[30]; + t = time(NULL); + tmp = localtime(&t); + strftime(date_string, sizeof(date_string), "%F %T ", tmp); + fputs(date_string, output_stream); + } while (0); + #endif + + #if PINELOG_SHOW_LEVEL + do { + static const char *level_strings[] = { + PINELOG_FATAL_STR, + PINELOG_ERROR_STR, + PINELOG_WARNING_STR, + PINELOG_INFO_STR, + PINELOG_DEBUG_STR, + PINELOG_TRACE_STR, + }; + + fputs(level_strings[level], output_stream); + fputs(": ", output_stream); + } while (0); + #endif + + #if PINELOG_SHOW_BACKTRACE + fprintf(output_stream, "%s:%d ", file, line); + #endif + + va_start(ap, fmt); + vfprintf(output_stream, fmt, ap); + va_end(ap); + // Append a trailing newline to flush the log message + fputs("\n", output_stream); +} diff --git a/lib/pinelog/pinelog.h b/lib/pinelog/pinelog.h new file mode 100644 index 0000000..0020ad9 --- /dev/null +++ b/lib/pinelog/pinelog.h @@ -0,0 +1,173 @@ +/* + * Pinelog lightweight logging library + * + * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: MIT + */ + +/** + * @file logging.h + * @brief Logging utility library + * + * This file contains the prototypes for the pinelog logging library + * used by any programs that need to log messages. + * + * @author Nirenjan Krishnan (nirenjan@nirenjan.org) + */ +#ifndef LOGGING_H +#define LOGGING_H + +#include "config.h" +#include +#ifndef PINELOG_TEST +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Logging levels + * + * The log levels indicate the lowest severity level that will actually be + * logged to the logging framework. + */ +enum { + /** No messages will be logged */ + PINELOG_LVL_NONE = -1, + + /** Only fatal messages will be logged */ + PINELOG_LVL_FATAL, + + /** Error messages. This is the default log level */ + PINELOG_LVL_ERROR, + + /** Warning messages */ + PINELOG_LVL_WARNING, + + /** Informational messages */ + PINELOG_LVL_INFO, + + /** Debug messages */ + PINELOG_LVL_DEBUG, + + /** Trace messages */ + PINELOG_LVL_TRACE, +}; + +/** + * @brief Set the default log level and output stream + */ +void pinelog_set_defaults(void); + +#ifdef PINELOG_TEST +/** + * @brief Get the pointer to the output stream. Only used in test harness. + * + * @returns FILE pointer to output stream + */ +FILE * pinelog_get_output_stream(void); +#endif + +/** + * @brief Set the output stream. Must be a FILE pointer. + * + * @param[in] stream Pointer to the output stream + * + * @returns 0 on success, EINVAL if the pointer is not valid. + */ +int pinelog_set_output_stream(FILE *stream); + +/** + * @brief Set the output file. + * + * @param[in] file Filename to write to + * + * @returns 0 on success, EINVAL if the filename pointer is not valid, other + * error if the file could not be opened for writing. + */ +int pinelog_set_output_file(const char *file); + +/** + * @brief Set the logging level + * + * @param[in] level Level to filter + * + * @returns 0 on success, EINVAL if the level is not valid + */ +int pinelog_set_level(int level); + +/** + * @brief Get the logging level + * + * @returns the configured logging level + */ +int pinelog_get_level(void); + +/** + * @brief Log a message to the logger + * + * This is the actual function that logs the message. The application should + * never need to call this directly, but instead, should always use the + * \code PINELOG_* macros. + * + * @param[in] level Level to log the message at + * @param[in] fmt Format string + * + * @returns None + */ +#if HAVE_FUNC_ATTRIBUTE_FORMAT +__attribute__((format(printf, 4, 5))) +#endif + +void pinelog_log_message(int level, const char *file, int line, const char *fmt, ...); + +// Test harness will redefine pinelog_exit +#ifndef PINELOG_TEST +#define pinelog_exit exit +#endif + +#define PINELOG_FATAL(fmt, ...) do { \ + if (PINELOG_LVL_FATAL <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_FATAL, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ + pinelog_exit(1); \ +} while (0) + +#define PINELOG_ERROR(fmt, ...) do { \ + if (PINELOG_LVL_ERROR <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_ERROR, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ +} while (0) + +#define PINELOG_WARN(fmt, ...) do { \ + if (PINELOG_LVL_WARNING <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_WARNING, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define PINELOG_INFO(fmt, ...) do { \ + if (PINELOG_LVL_INFO <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_INFO, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define PINELOG_DEBUG(fmt, ...) do { \ + if (PINELOG_LVL_DEBUG <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_DEBUG, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#define PINELOG_TRACE(fmt, ...) do { \ + if (PINELOG_LVL_TRACE <= pinelog_get_level()) { \ + pinelog_log_message(PINELOG_LVL_TRACE, __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + } \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif // !defined LOGGING_H diff --git a/lib/pinelog/test_pinelog.c b/lib/pinelog/test_pinelog.c new file mode 100644 index 0000000..dd568a8 --- /dev/null +++ b/lib/pinelog/test_pinelog.c @@ -0,0 +1,194 @@ +/* + * Pinelog lightweight logging library - test harness + * + * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: MIT + */ + +#include "pinelog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/********************************************************************** + * Global variables + *********************************************************************/ +// Test ID (of current test case) +static unsigned int test_id; + +// Observed output stream +static FILE *observed_stream_w; +static FILE *observed_stream_r; + +// Temporary pipe for observed data +static char observed_fifo[NAME_MAX]; + +// Buffer for expected output +static char expected_output[1024]; +static size_t expected_len; + +static void test_case(const char *desc, bool test) +{ + test_id++; + if (test) { + printf("ok %u %s\n", test_id, desc); + } else { + printf("not ok %u %s\n", test_id, desc); + } +} + +static void pinelog_exit(int status) +{ + fprintf(observed_stream_w, "EXIT(%d)\n", status); + expected_len += snprintf(&expected_output[expected_len], + sizeof(expected_output) - expected_len, + "EXIT(%d)\n", status); +} + +static void dump_data(const char *type, size_t len, char *data) +{ + char *line; + printf("# %s (%lu bytes):\n", type, len); + line = strtok(data, "\n"); + while (line != NULL) { + printf("#\t%s\n", line); + line = strtok(NULL, "\n"); + } + printf("\n"); +} + +static void test_setup(int level, int filter, const char *file, int line, const char *fmt, ...) +{ + va_list ap; + + expected_len = 0; + memset(expected_output, 0, sizeof(expected_output)); + + if (level <= filter) { + if (PINELOG_SHOW_DATE) { + time_t t; + struct tm *tmp; + + t = time(NULL); + tmp = localtime(&t); + expected_len += strftime(&expected_output[expected_len], + sizeof(expected_output) - expected_len, + "%F %T ", tmp); + } + + if (PINELOG_SHOW_LEVEL) { + const char * level_string[] = { + PINELOG_FATAL_STR, + PINELOG_ERROR_STR, + PINELOG_WARNING_STR, + PINELOG_INFO_STR, + PINELOG_DEBUG_STR, + PINELOG_TRACE_STR, + }; + expected_len += snprintf(&expected_output[expected_len], + sizeof(expected_output) - expected_len, + "%s: ", level_string[level]); + } + + if (PINELOG_SHOW_BACKTRACE) { + expected_len += snprintf(&expected_output[expected_len], + sizeof(expected_output) - expected_len, + "%s:%d ", file, line); + } + + va_start(ap, fmt); + expected_len += vsnprintf(&expected_output[expected_len], + sizeof(expected_output) - expected_len, + fmt, ap); + va_end(ap); + expected_output[expected_len] = '\n'; + expected_len++; + } +} + +static void test_teardown(const char *desc) +{ + // Compare the output + static char observed[1024]; + size_t observed_len; + int result; + + observed_len = fread(observed, 1, sizeof(observed), observed_stream_r); + + result = ((expected_len == observed_len) && + (memcmp(expected_output, observed, expected_len) == 0)); + test_case(desc, result); + if (!result) { + dump_data("expected", expected_len, expected_output); + dump_data("observed", observed_len, observed); + } +} + +static void verify_defaults(void) +{ + test_case("Get default output stream", + pinelog_get_output_stream() == PINELOG_DEFAULT_STREAM); + test_case("Get default logging level", + pinelog_get_level() == PINELOG_DEFAULT_LEVEL); +} + +#define PINELOG_WARNING PINELOG_WARN + +#define TEST_LOG(lvl, filter, fmt, ...) do { \ + test_setup(PINELOG_LVL_ ## lvl, PINELOG_LVL_ ## filter, \ + __FILE__, __LINE__, fmt, ##__VA_ARGS__); \ + PINELOG_ ## lvl (fmt, ##__VA_ARGS__); \ + test_teardown("Log " #lvl " filter " #filter); \ +} while(0) + +#define TEST(filter, fmt, ...) do { \ + pinelog_set_level(PINELOG_LVL_ ## filter); \ + TEST_LOG(TRACE, filter, fmt, ##__VA_ARGS__); \ + TEST_LOG(DEBUG, filter, fmt, ##__VA_ARGS__); \ + TEST_LOG(INFO, filter, fmt, ##__VA_ARGS__); \ + TEST_LOG(WARNING, filter, fmt, ##__VA_ARGS__); \ + TEST_LOG(ERROR, filter, fmt, ##__VA_ARGS__); \ + TEST_LOG(FATAL, filter, fmt, ##__VA_ARGS__); \ +} while (0) + +int main(int argc, char **argv) +{ + int fifo_fd_r, fifo_fd_w; + snprintf(observed_fifo, sizeof(observed_fifo), "%s.fifo", argv[0]); + mkfifo(observed_fifo, 0777); + + fifo_fd_r = open(observed_fifo, O_RDONLY | O_NONBLOCK); + fifo_fd_w = open(observed_fifo, O_WRONLY | O_NONBLOCK); + observed_stream_r = fdopen(fifo_fd_r, "r"); + observed_stream_w = fdopen(fifo_fd_w, "w"); + + verify_defaults(); + + pinelog_set_output_stream(observed_stream_w); + TEST(TRACE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(DEBUG, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(INFO, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(WARNING, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(ERROR, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(FATAL, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + TEST(NONE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1); + + printf("1..%u\n", test_id); + + fclose(observed_stream_w); + fclose(observed_stream_r); + close(fifo_fd_w); + close(fifo_fd_r); + unlink(observed_fifo); + + return 0; +}