[
  {
    "path": ".appveyor.yml",
    "content": "version: 0.3.1-{build}\n\nenvironment:\n  matrix:\n  - GENERATOR: \"Visual Studio 12\"\n    CONFIG: Release\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n  - GENERATOR: \"Visual Studio 12\"\n    CONFIG: Debug\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n\n  - GENERATOR: \"Visual Studio 12 Win64\"\n    CONFIG: Release\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n  - GENERATOR: \"Visual Studio 12 Win64\"\n    CONFIG: Debug\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n\n  - GENERATOR: \"Visual Studio 14\"\n    CONFIG: Release\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n  - GENERATOR: \"Visual Studio 14\"\n    CONFIG: Debug\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n\n  - GENERATOR: \"Visual Studio 14 Win64\"\n    CONFIG: Release\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n  - GENERATOR: \"Visual Studio 14 Win64\"\n    CONFIG: Debug\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n\n  - GENERATOR: \"MinGW Makefiles\"\n    CONFIG: Debug\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n  - GENERATOR: \"MinGW Makefiles\"\n    CONFIG: Release\n    OPTIONS: -DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON\n\nbuild_script:\n  - if \"MinGW Makefiles\"==\"%GENERATOR%\" set PATH=%PATH:C:\\Program Files\\Git\\usr\\bin;=%\n  - if \"MinGW Makefiles\"==\"%GENERATOR%\" set PATH=C:\\MinGW\\bin;%PATH%\n  - ps: mkdir build.msvc\n  - ps: cd build.msvc\n  - cmake \"-G%GENERATOR%\" %OPTIONS% ..\n  - cmake --build . --config \"%CONFIG%\"\n\ntest_script:\n  - ctest --output-on-failure -C \"%CONFIG%\"\n"
  },
  {
    "path": ".gitignore",
    "content": "/build.*\n/CMakeLists.txt.user\n/tags\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: c++\n\ncompiler:\n- clang\n- gcc\n\nos:\n- osx\n\nenv:\n  - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug\"\n  - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release\"\n\nmatrix:\n  include:\n  - os: linux\n    dist: trusty\n    sudo: required\n    compiler: clang\n    env:\n    - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug\"\n  - os: linux\n    dist: trusty\n    sudo: required\n    compiler: clang\n    env:\n    - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release\"\n  - os: linux\n    dist: trusty\n    sudo: required\n    compiler: gcc\n    env:\n    - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Debug\"\n  - os: linux\n    dist: trusty\n    sudo: required\n    compiler: gcc\n    env:\n    - OPTIONS=\"-DZF_LOG_EXAMPLES:bool=ON -DZF_LOG_TESTS:bool=ON -DCMAKE_BUILD_TYPE:string=Release\"\n\ninstall: true\n\nscript:\n  - find . -name \"CMakeLists.txt\" -exec sed -i .bak -e \"s/VERSION 3.2/VERSION 2.8/g\" {} \\;\n  - mkdir build.make && cd build.make && cmake ${OPTIONS} .. && cmake --build . && ctest --output-on-failure\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.2)\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)\nif(NOT DEFINED CMAKE_BUILD_TYPE)\n\tset(CMAKE_BUILD_TYPE Release CACHE STRING \"Build type\")\nendif()\n\nproject(zf_log)\n\nset(INSTALL_INCLUDE_DIR include CACHE PATH\n\t\"Installation directory for header files\")\nset(INSTALL_LIB_DIR lib CACHE PATH\n\t\"Installation directory for libraries\")\nset(INSTALL_CMAKE_DIR lib/cmake/zf_log CACHE PATH\n\t\"Installation directory for CMake files\")\nset(ZF_LOG_LIBRARY_PREFIX CACHE STRING\n\t\"Prefix for all linker symbols exported by the library\")\noption(ZF_LOG_CONFIGURE_INSTALL \"Generate install target\" ON)\noption(ZF_LOG_EXAMPLES \"Build examples\" OFF)\noption(ZF_LOG_TESTS \"Build tests\" OFF)\noption(ZF_LOG_PERF_TESTS \"Build performance tests (requires Python)\" OFF)\noption(ZF_LOG_USE_ANDROID_LOG \"Use Android log by defaul when available\" OFF)\noption(ZF_LOG_USE_NSLOG \"Use NSLog (Apple System Log) by default when available\" OFF)\noption(ZF_LOG_USE_DEBUGSTRING \"Use OutputDebugString (Windows) by default when available\" OFF)\noption(ZF_LOG_USE_CONFIG_HEADER \"Include zf_log_config.h header file in zf_log compilation untis\" OFF)\noption(ZF_LOG_OPTIMIZE_SIZE \"Optimize for size (prefer size over speed)\" OFF)\n\nadd_subdirectory(zf_log)\n\nif(ZF_LOG_EXAMPLES)\n\tadd_subdirectory(examples)\nendif()\nif(ZF_LOG_TESTS)\n\tenable_testing()\n\tadd_subdirectory(tests)\nendif()\nif(ZF_LOG_PERF_TESTS)\n\tenable_testing()\n\tadd_subdirectory(tests/perf)\nendif()\n\nif(ZF_LOG_CONFIGURE_INSTALL)\n\texport(EXPORT zf_log)\n\tinstall(EXPORT zf_log\n\t\tDESTINATION ${INSTALL_CMAKE_DIR})\n\tconfigure_file(zf_log-config.cmake.in zf_log-config.cmake @ONLY)\n\tinstall(FILES ${CMAKE_CURRENT_BINARY_DIR}/zf_log-config.cmake\n\t\tDESTINATION ${INSTALL_CMAKE_DIR})\nendif()\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017 wonder-mice\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "[![Build Status](https://travis-ci.org/wonder-mice/zf_log.svg?branch=master)](https://travis-ci.org/wonder-mice/zf_log)\n[![Build Status](https://ci.appveyor.com/api/projects/status/u9rmuaw147q578w0/branch/master?svg=true)](https://ci.appveyor.com/project/wonder-mice/zf-log/branch/master)\n[![Gitter Chat](https://badges.gitter.im/wonder-mice/zf_log.svg)](https://gitter.im/wonder-mice/zf_log?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\nzf_log\n========\n\n### Core logging library for C, Objective-C and C++\n\nFollowing the [Unix way](https://en.wikipedia.org/wiki/Unix_philosophy), this\nlibrary provides the logging core which can be used directly or extended. In\nessence, it's a thin wrapper around snprintf() function. By implementing less\nthan 20% of functionality found in more sophisticated and feature reach\nlibraries, it covers more than 80% of common use cases. Found to be\nparticularly useful in cross-platform applications and on mobile/embedded\nplatforms. Focus is made on simplicity, ease of use and performance (to be\nmore precise - low overhead).\n\nFeatures:\n\n* Debug logging is reduced to no-op in release builds:\n\n  ```c\n  /* no runtime overhead whatsoever if verbose log is disabled */\n  ZF_LOGV(\"entering foobar(), args: %i, %s\", arg0, arg1);\n  ```\n\n* No \"unused\" warning for variables used in log statements only:\n\n  ```c\n  /* no warning about err being unused even if verbose log is disabled */\n  int err = close(fd);\n  ZF_LOGV(\"close status %i\", err);\n  ```\n\n* Arguments are not evaluated when the message is not logged:\n\n  ```c\n  /* to_utf8() will not be called if debug log is turned off or disabled */\n  ZF_LOGD(\"Login: %s\", to_utf8(loginUtf16));\n  ```\n\n* Log a memory region as HEX and ASCII:\n\n  ```c\n  /* will print HEX and ASCII view of received network packet */\n  ZF_LOGD_MEM(pkg_ptr, pkg_sz, \"Received network packet (%u bytes):\", pkg_sz);\n  ```\n\n* Compiler warnings when format string and arguments don't match:\n\n  ```c\n  /* warning: format specifies type 'char *' but the argument has type 'int' */\n  ZF_LOGI(\"This is int %s\", 42);\n  ```\n\n* Conditional logging of sensitive information (also known as Personally\n  Identifiable Information or PII):\n\n  ```c\n  /* will be logged only when logging of sensitive information is enabled */\n  ZF_LOG_SECRET(ZF_LOGI(\"Credit card number: %s\", credit_card));\n  ```\n\n* Custom output functions\n* Custom log message formats\n* Compile time configuration of logging level\n* Run time configuration of logging level\n* Optional built-in support for Android log and Apple system log (iOS, OS X)\n* Reasonably cross-platform (OS X, iOS, Linux, Android, other Unix flavors,\n  POSIX platforms and Windows)\n* No external dependencies\n* Compact call site (smaller executables)\n* Thread safe\n* Library size is under 10Kb (when compiled for x86_64)\n* Can be used privatly in libraries\n\nExamples\n--------\n\nLibrary provides a set of `ZF_LOGX` macros where `X` is an abbreviated log\nlevel (e.g. `I` for `INFO`). This code will log an `INFO` message:\n\n```c\nZF_LOGI(\"Number of arguments: %i\", argc);\n```\n\nAnd will produce the following log line if `NDEBUG` is defined (aka release\nbuild):\n\n```\n+- month           +- process id\n|  +- day          |      +- thread id      +- message\n|  |               |      |                 |\n04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1\n      |                        | |     |\n      +- time                  | |     +- tag (optional)\n                               | +- tag prefix (optional)\n                               +- level\n```\n\nAnd if `NDEBUG` is NOT defined (aka debug build):\n\n```\n04-29 22:43:20.244 40059  1299 I hello.MAIN main@hello.c:9 Number of arguments: 1\n                                            |    |       |\n                                            |    |       +- line number\n                                            |    +- source file name\n                                            +- function name\n```\n\nIt's also possible to dump a memory region. For example:\n\n```c\nconst char data[] = \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\";\nZF_LOGI_MEM(data, sizeof(data), \"Lorem ipsum at %p\", data);\n```\n\nWill produce the following output:\n\n```\n05-06 00:54:33.825 35864  1299 I hello.MAIN Lorem ipsum at 0x10fbc0f20:\n05-06 00:54:33.825 35864  1299 I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo\n05-06 00:54:33.825 35864  1299 I hello.MAIN 722073697420616d65742c20636f6e73  r sit amet, cons\n05-06 00:54:33.825 35864  1299 I hello.MAIN 65637465747572206164697069736369  ectetur adipisci\n05-06 00:54:33.825 35864  1299 I hello.MAIN 6e6720656c69742e00                ng elit.?\n```\n\nMore examples available in [examples](examples) folder. For more details see\ncomments in [zf_log/zf_log.h](zf_log/zf_log.h) file.\n\nUsage\n--------\n\n### Embedding\n\nThe simplest way of using this library is to embed its sources into existing\nproject. For that, copy the following files to your source tree:\n\n* [zf_log.h](zf_log/zf_log.h)\n* [zf_log.c](zf_log/zf_log.c)\n\nSee comments in those files for configuration macros. One particularly useful\noption when embedding into a library project is `ZF_LOG_LIBRARY_PREFIX`. It\ncould be used to decorate zf_log exported symbols to avoid linker conflicts\n(when that library project is used in other project that is also uses zf_log).\n\n### Embedding with CMake\n\nAnother options is avaibale for projects that are using CMake. Copy\n[zf_log](zf_log) folder to you source tree and add it with `add_subdirectory()`\ncall in one of your CMakeLists.txt files. Also see\n[zf_log/CMakeLists.txt](zf_log/CMakeLists.txt) for available `ZF_LOG_`\nconfiguration options. For example:\n\n```\nset(ZF_LOG_USE_ANDROID_LOG ON)\nadd_subdirectory(zf_log)\n```\n\nThis will add `zf_log` library target. For each target that uses zf_log in\ncorresponding CMakeLists.txt file add:\n\n```cmake\ntarget_link_libraries(my_target zf_log)\n```\n\n### Installation\n\nAnother option is to build and install the library:\n\n```bash\ngit clone https://github.com/wonder-mice/zf_log.git zf_log.git\nmkdir zf_log.build && cd zf_log.build\ncmake ../zf_log.git -DCMAKE_INSTALL_PREFIX=/usr/local\nmake\nsudo make install\n```\n\nThis will also install\n`${CMAKE_INSTALL_PREFIX}/lib/cmake/zf_log/zf_log.cmake`\nand\n`${CMAKE_INSTALL_PREFIX}/lib/cmake/zf_log/zf_log-config.cmake`.\nThe first one is for direct `include` from CMakeLists.txt files.\nThe second can be located by CMake with:\n\n```cmake\nfind_package(zf_log)\n```\n\nBoth will add `zf_log` imported library target.\nFor each target that uses zf_log in corresponding CMakeLists.txt file add:\n\n```cmake\ntarget_link_libraries(my_target zf_log)\n```\n\nTo build as a shared library set CMake variable `BUILD_SHARED_LIBS`:\n\n```bash\ncmake ../zf_log.git -DBUILD_SHARED_LIBS:BOOL=ON\n```\n\nPerformance\n--------\n\nLog statements that are below *current log level* (compile time check) have\n**no overhead** - they are compiled out and their log arguments will **not** be\nevaluated. Consider:\n\n```c\n#include <signal.h>\n#include <unistd.h>\n#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n\nint main(int argc, char *argv[])\n{\n\tZF_LOGV(\"Argument of this VERBOSE message will not be evaluated: %i\",\n\t\t\tkill(getpid(), SIGKILL));\n\tZF_LOGI(\"So you will see that INFO message\");\n\treturn 0;\n}\n```\n\nLog statements that are below *output log level* (run time check)\nhave a **small overhead** of compare operation and conditional jump. Arguments\nwill **not** be evaluated and no function call will be performed. Consider:\n\n```c\n#include <stdlib.h>\n#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_level(ZF_LOG_WARN);\n\tint count = 0;\n\tfor (int i = 2; 0 < i--;)\n\t{\n\t\tZF_LOGI(\"Argument of this INFO message will be evaluated only once: %i\",\n\t\t\t\t++count);\n\t\tzf_log_set_output_level(ZF_LOG_INFO);\n\t}\n\tif (1 != count)\n\t{\n\t\tabort();\n\t}\n\tZF_LOGI(\"And you will see that INFO message\");\n\treturn 0;\n}\n```\n\nLog statements that are on or above current log level and output log level will\ngo into log output (and arguments will be evaluated). In that case it's hard to\ntalk about performance because string formatting routines will be called and IO\nwill be performed.\n\nTo conclude, it is OK to have log statements for debug and development purposes,\neven in performance critical parts. But make sure to set correct current log\nlevel (to compile them out) or output log level (to suppress them) in release\nbuilds.\n\nThat said, in some rare cases it could be useful to provide a custom output\nfunction that will use memory buffer for the log output.\n\nOutput\n--------\n\nBy default log messages are written to the `stderr`, but it is also possible to\nset custom output function. Library has an optional built-in support for the\nfollowing output facilities (see [zf_log/zf_log.c] for details):\n\n* Android Log (via android/log.h)\n* Apple System Log (iOS, OS X via asl.h)\n\nSee [examples/custom_output.c] for an example of custom output function.\n\n[zf_log/zf_log.c]: zf_log/zf_log.c\n[examples/custom_output.c]: examples/custom_output.c\n\nComparison\n--------\n\nThis table is work in progress. See [tests/perf](tests/perf) folder for how\nthis table was generated (fully automated).\n\n|                                        |  Easylogging++  |     g3log     |     glog    |     spdlog    |      zf_log     |\n| -------------------------------------- | ---------------:| -------------:| -----------:| -------------:| ---------------:|\n|  Call site size: string                |          304 B  |        360 B  |      160 B  |        352 B  |         **48 B**|\n|  Call site size: 3 integers            |          856 B  |        384 B  |      320 B  |        312 B  |         **72 B**|\n|  Executable size: 1 module             |      208.84 KB  |    183.73 KB  |  137.37 KB  |    133.69 KB  |     **18.33 KB**|\n|  Module compile time                   |      3.182 sec  |    0.511 sec  |  0.374 sec  |    2.163 sec  |    **0.024 sec**|\n|  Executable link time                  |      0.025 sec  |    0.022 sec  |  0.026 sec  |  **0.020 sec**|    **0.017 sec**|\n|  Speed: 1 thread, string               |        378,722  |    1,257,168  |    385,098  |    1,909,253  |    **5,296,201**|\n|  Speed: 1 thread, 3 integers           |        311,690  |    1,023,108  |    321,507  |    1,470,271  |    **3,173,097**|\n|  Speed: 1 thread, string, off          |      4,199,431  |   55,297,247  |    411,960  |   78,675,820  |  **482,713,041**|\n|  Speed: 1 thread, slow function, off   |            743  |   54,877,221  |        732  |          750  |  **423,658,146**|\n|  Speed: 4 threads, string              |        132,836  |    2,353,169  |    196,950  |      196,930  |    **9,690,216**|\n|  Speed: 4 threads, 3 integers          |        116,696  |    1,896,178  |    235,141  |      172,880  |    **5,545,075**|\n|  Speed: 4 threads, string, off         |        244,448  |  106,600,866  |    186,233  |  164,582,184  |**1,229,398,467**|\n|  Speed: 4 threads, slow function, off  |            733  |  111,685,033  |      2,887  |        2,976  |**1,106,166,551**|\n|  Speed: 8 threads, string              |        131,691  |    2,447,058  |    172,824  |      183,277  |    **9,731,434**|\n|  Speed: 8 threads, 3 integers          |        115,991  |    1,936,270  |    176,594  |      177,950  |    **5,596,045**|\n|  Speed: 8 threads, string, off         |        240,538  |  104,424,749  |    182,465  |  164,632,729  |**1,228,058,986**|\n|  Speed: 8 threads, slow function, off  |            774  |  116,354,224  |      5,815  |        5,976  |**1,127,173,552**|\n\nDetails:\n\n* Call site size - amount of code generated for each LOG() statement when\n  logging a string, format string with 4 integers or format string with 4\n  integers where the function is used to get an integer.\n* Compile time - time to compile a source file that includes public API\n  header from the logging library.\n* Speed - log lines per second. Thread(s) call LOG() N times in a\n  tight loop for T seconds. N/T is log lines per second.\n* When it says \"off\", it means that log level was turned off. Expecting\n  very low overhead in this mode.\n\nWhy zf?\n--------\n\nIt stands for Ze Foundation. \"Ze\" is like \"The\" but with french or german accent.\nMostly because zf_anything looks better than tf_anything.\n"
  },
  {
    "path": "TODO.md",
    "content": "Things to do\n------------\n\n* Add callback arg to output callback\n* Update README, it sucks now\n* Print start address for each line of memory output?\n* Introduce private format_callback which probably will replace put_msg\n  This will provide more modular structure and will point out where to\n  insert custom code when different format function must be used.\n  As an exercise, add optional support for CFStringCreateWithFormat().\n* Use Cmake GNUInstallDirs for install locations.\n\nThings probably not to do\n-------------------------\n\n* Number of parameters in _zf_log_write_xxx() functions could be reduced\n  by having a separate function for each log level. One way to implement\n  that is to have a static array of logging functions. Log level will be\n  an index in that array. This technique reduces the size of code\n  generated per log statement (e.g. 5 bytes less on x64). But it also\n  increases the size of the library itself, because all those new\n  28 functions (7 levels x 2 mem/msg x 2 debug/ndebug) must be defined.\n  And it also makes implementation more complex. Currently considered\n  not worth the effort.\n\n* Output some memory even when buffer is too small. Will significantly\n  increase complexity of output_mem() function, while providing not\n  much benefits. Memory output line is pretty much limited in length,\n  so problem could be solved easily by choosing right ZF_LOG_BUF_SZ.\n\n* Debug functions (_zf_log_write.*_d) could also receive the length of\n  string passed in as a \"file\" parameter. That will allow to search for\n  a slash from the end of the string. While it will be up to 30 times\n  faster, overall performance gain will be too small to notice, because\n  the biggest offenders right now are localtime() and file io. Also\n  this will require to push additional argument which will increase the\n  size of call site which could be very noticable - size of the binary\n  will go up.\n"
  },
  {
    "path": "examples/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.2)\n\nset(CMAKE_C_STANDARD 99)\nset(CMAKE_C_STANDARD_REQUIRED ON)\nset(CMAKE_C_EXTENSIONS OFF)\nif(MSVC)\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /W4 /WX\")\nelse()\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors\")\nendif()\n\nif(ZF_LOG_LIBRARY_PREFIX)\n\tadd_definitions(\"-DZF_LOG_LIBRARY_PREFIX=${ZF_LOG_LIBRARY_PREFIX}\")\nendif()\n\nadd_executable(hello_c hello.c)\ntarget_link_libraries(hello_c zf_log)\n\nadd_executable(custom_output custom_output.c)\ntarget_link_libraries(custom_output zf_log)\n\nadd_executable(file_output file_output.c)\ntarget_link_libraries(file_output zf_log)\n\nadd_executable(args_eval args_eval.c)\ntarget_link_libraries(args_eval zf_log)\n"
  },
  {
    "path": "examples/args_eval.c",
    "content": "#include <signal.h>\n#include <stdlib.h>\n#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n\nstatic int call_exit()\n{\n\texit(1);\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\n\t/* Current log level is set to ZF_LOG_INFO by defining ZF_LOG_LEVEL\n\t * before zf_log.h include. All log messages below INFO level will be\n\t * compiled out.\n\t */\n\tZF_LOGV(\"Argument of this VERBOSE message will not be evaluated: %i\",\n\t\t\tcall_exit());\n\tZF_LOGI(\"So you will see that INFO message\");\n\n\t/* Output log level is set to WARN and then to INFO. Argument of INFO log\n\t * statement will be evaluated only once (after setting output log level to\n\t * INFO).\n\t */\n\tzf_log_set_output_level(ZF_LOG_WARN);\n\tint count = 0;\n\tfor (int i = 2; 0 < i--;)\n\t{\n\t\tZF_LOGI(\"Argument of this INFO message will be evaluated only once: %i\",\n\t\t\t\t++count);\n\t\tzf_log_set_output_level(ZF_LOG_INFO);\n\t}\n\tif (1 != count)\n\t{\n\t\tabort();\n\t}\n\tZF_LOGI(\"And you will see that INFO message\");\n\treturn 0;\n}\n"
  },
  {
    "path": "examples/custom_output.c",
    "content": "#include <assert.h>\n#if defined(_WIN32) || defined(_WIN64)\n\t#include <windows.h>\n\t#define OUTPUT_DEBUG_STRING\n#else\n\t#include <syslog.h>\n\t#define OUTPUT_SYSLOG\n#endif\n#include <zf_log.h>\n\n#ifdef OUTPUT_SYSLOG\nstatic int syslog_level(const int lvl)\n{\n\tswitch (lvl)\n\t{\n\tcase ZF_LOG_VERBOSE:\n\t\treturn LOG_DEBUG;\n\tcase ZF_LOG_DEBUG:\n\t\treturn LOG_DEBUG;\n\tcase ZF_LOG_INFO:\n\t\treturn LOG_INFO;\n\tcase ZF_LOG_WARN:\n\t\treturn LOG_WARNING;\n\tcase ZF_LOG_ERROR:\n\t\treturn LOG_ERR;\n\tcase ZF_LOG_FATAL:\n\t\treturn LOG_EMERG;\n\tdefault:\n\t\tassert(!\"can't be\");\n\t\treturn LOG_EMERG;\n\t}\n}\n#endif\n\nstatic void custom_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\t/* p points to the log message end. By default, message is not terminated\n\t * with 0, but it has some space allocated for EOL area, so there is always\n\t * some place for terminating zero in the end (see ZF_LOG_EOL_SZ define in\n\t * zf_log.c).\n\t */\n\t*msg->p = 0;\n#if defined(OUTPUT_DEBUG_STRING)\n\tOutputDebugStringA(msg->buf);\n#elif defined(OUTPUT_SYSLOG)\n\tsyslog(syslog_level(msg->lvl), \"%s\", msg->tag_b);\n#else\n\t#error Unsupported platform\n#endif\n}\n\nint main(int argc, char *argv[])\n{\n#if defined(OUTPUT_SYSLOG)\n\topenlog(\"custom_output\", LOG_CONS|LOG_PERROR|LOG_PID, LOG_USER);\n#endif\n\n\tconst unsigned put_mask =\n#if defined(OUTPUT_SYSLOG)\n\t\t\tZF_LOG_PUT_STD & !ZF_LOG_PUT_CTX;\n#else\n\t\t\tZF_LOG_PUT_STD;\n#endif\n\t\t\t;\n\tzf_log_set_output_v(put_mask, 0, custom_output_callback);\n\n\tZF_LOGI(\"Number of arguments goes into custom output: %i\", argc);\n\tZF_LOGI_MEM(argv, argc * sizeof(*argv), \"and argv pointers as well:\");\n\n#if defined(OUTPUT_SYSLOG)\n\tcloselog();\n#endif\n\treturn 0;\n}\n"
  },
  {
    "path": "examples/file_output.c",
    "content": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_SECURE_NO_WARNINGS\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n#include \"zf_log.h\"\n\nFILE *g_log_file;\n\nstatic void file_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\t*msg->p = '\\n';\n\tfwrite(msg->buf, msg->p - msg->buf + 1, 1, g_log_file);\n\tfflush(g_log_file);\n}\n\nstatic void file_output_close(void)\n{\n\tfclose(g_log_file);\n}\n\nstatic void file_output_open(const char *const log_path)\n{\n\tg_log_file = fopen(log_path, \"a\");\n\tif (!g_log_file)\n\t{\n\t\tZF_LOGW(\"Failed to open log file %s\", log_path);\n\t\treturn;\n\t}\n\tatexit(file_output_close);\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, file_output_callback);\n}\n\nint main(int argc, char *argv[])\n{\n\tfile_output_open(\"example.log\");\n\n\tZF_LOGI(\"Writing number of arguments to log file: %i\", argc);\n\tZF_LOGI_MEM(argv, argc * sizeof(*argv), \"argv pointers:\");\n\n\treturn 0;\n}\n"
  },
  {
    "path": "examples/hello.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#define ZF_LOG_TAG \"MAIN\"\n#include <zf_log.h>\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_tag_prefix(\"hello\");\n\n\tZF_LOGI(\"You will see the number of arguments: %i\", argc);\n\tZF_LOGD(\"You will NOT see the first argument: %s\", *argv);\n\n\tzf_log_set_output_level(ZF_LOG_WARN);\n\tZF_LOGW(\"You will see this WARNING message\");\n\tZF_LOGI(\"You will NOT see this INFO message\");\n\n\tconst char data[] =\n\t\t\t\"Lorem ipsum dolor sit amet, consectetur adipiscing elit. \"\n\t\t\t\"Aliquam pharetra orci id velit porttitor tempus.\";\n\tZF_LOGW_MEM(data, sizeof(data), \"Lorem ipsum at %p:\", (const void *) data);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.2)\n\ninclude(CMakeParseArguments)\n\nset(CMAKE_C_STANDARD 99)\nset(CMAKE_C_STANDARD_REQUIRED ON)\nset(CMAKE_C_EXTENSIONS OFF)\nif(MSVC)\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /W4 /WX\")\nelse()\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors\")\nendif()\n\n# zf_test\nset(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})\nadd_library(zf_test INTERFACE)\ntarget_include_directories(zf_test INTERFACE $<BUILD_INTERFACE:${HEADERS_DIR}>)\nset(HEADERS zf_test.h)\nadd_custom_target(zf_test_headers SOURCES ${HEADERS})\n\nfunction(add_test_target target)\n\tcmake_parse_arguments(arg\n\t\t\"COMPILE_ONLY\"\n\t\t\"\"\n\t\t\"SOURCES;CSTD;CXXSTD;DEFINES\"\n\t\t${ARGN})\n\tif(arg_COMPILE_ONLY)\n\t\tadd_library(${target} STATIC ${arg_SOURCES})\n\telse()\n\t\tadd_executable(${target} ${arg_SOURCES})\n\t\ttarget_link_libraries(${target} zf_test)\n\t\tadd_test(NAME ${target} COMMAND ${target})\n\tendif()\n\tif(arg_CSTD)\n\t\tset_property(TARGET ${target} PROPERTY C_STANDARD \"${arg_CSTD}\")\n\tendif()\n\tif(arg_CXXSTD)\n\t\tset_property(TARGET ${target} PROPERTY CXX_STANDARD \"${arg_CXXSTD}\")\n\tendif()\n\tset_property(TARGET ${target} PROPERTY COMPILE_DEFINITIONS \"${arg_DEFINES}\")\n\ttarget_include_directories(${target} PRIVATE \"${PROJECT_SOURCE_DIR}/zf_log\")\nendfunction()\n\nfunction(add_test_target_group target)\n\tadd_test_target(${target}_c99 ${ARGN} CSTD 99)\n\tadd_test_target(${target}_c11 ${ARGN} CSTD 11)\nendfunction()\n\nadd_test_target_group(test_log_level_switches_verbose SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_VERBOSE)\nadd_test_target_group(test_log_level_switches_debug SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_DEBUG)\nadd_test_target_group(test_log_level_switches_info SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_INFO)\nadd_test_target_group(test_log_level_switches_warn SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_WARN)\nadd_test_target_group(test_log_level_switches_error SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_ERROR)\nadd_test_target_group(test_log_level_switches_fatal SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_FATAL)\nadd_test_target_group(test_log_level_switches_none SOURCES test_log_level_switches.c DEFINES ZF_LOG_LEVEL=ZF_LOG_NONE)\nadd_test_target_group(test_log_level_override SOURCES test_log_level_override.c)\n\nadd_test_target_group(test_log_message_content SOURCES test_log_message_content.c)\nadd_test_target_group(test_log_message_content_Os SOURCES test_log_message_content.c DEFINES ZF_LOG_OPTIMIZE_SIZE=1)\n\nadd_test_target_group(test_log_message_content_empty_format SOURCES test_log_message_content.c DEFINES\n\t\"ZF_LOG_MESSAGE_CTX_FORMAT=()\"\n\t\"ZF_LOG_MESSAGE_TAG_FORMAT=()\"\n\t\"ZF_LOG_MESSAGE_SRC_FORMAT=()\")\nadd_test_target_group(test_log_message_content_empty_format_Os SOURCES test_log_message_content.c DEFINES\n\t\"ZF_LOG_OPTIMIZE_SIZE=1\"\n\t\"ZF_LOG_MESSAGE_CTX_FORMAT=()\"\n\t\"ZF_LOG_MESSAGE_TAG_FORMAT=()\"\n\t\"ZF_LOG_MESSAGE_SRC_FORMAT=()\")\n\n# Here we use several F_INIT() fields in a row to workaround CMake problem with \";\", which acts\n# as a list separator in CMake. If not for CMake, context format specification could look like:\n#   #define ZF_LOG_MESSAGE_CTX_FORMAT \\\n#       (YEAR, S(\"-ctx:\"), F_INIT(( struct { int v; } f_box_a; f_box_a.v = 45; )), F_UINT(4, f_box_a.v))\nadd_test_target_group(test_log_message_content_custom_fields SOURCES test_log_message_content.c DEFINES\n\t\"ZF_LOG_MESSAGE_CTX_FORMAT=(YEAR, S(\\\"-ctx:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_a )), F_INIT(( f_box_a.v = 45 )), F_UINT(4, f_box_a.v))\"\n\t\"ZF_LOG_MESSAGE_TAG_FORMAT=(S(\\\"-tag:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_b )), F_INIT(( f_box_b.v = 36 )), F_UINT(4, f_box_b.v))\"\n\t\"ZF_LOG_MESSAGE_SRC_FORMAT=(S(\\\"-src:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_c )), F_INIT(( f_box_c.v = 27 )), F_UINT(4, f_box_c.v))\")\nadd_test_target_group(test_log_message_content_custom_fields_Os SOURCES test_log_message_content.c DEFINES\n\t\"ZF_LOG_OPTIMIZE_SIZE=1\"\n\t\"ZF_LOG_MESSAGE_CTX_FORMAT=(YEAR, S(\\\"ctx:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_a )), F_INIT(( f_box_a.v = 45 )), F_UINT(4, f_box_a.v))\"\n\t\"ZF_LOG_MESSAGE_TAG_FORMAT=(S(\\\"tag:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_b )), F_INIT(( f_box_b.v = 36 )), F_UINT(4, f_box_b.v))\"\n\t\"ZF_LOG_MESSAGE_SRC_FORMAT=(S(\\\"src:\\\"), F_INIT(( struct { int v )), F_INIT(( } f_box_c )), F_INIT(( f_box_c.v = 27 )), F_UINT(4, f_box_c.v))\")\n\nadd_test_target_group(test_source_location_none SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_NONE TEST_SRCLOC=ZF_LOG_SRCLOC_NONE)\nadd_test_target_group(test_source_location_short SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_SHORT TEST_SRCLOC=ZF_LOG_SRCLOC_SHORT)\nadd_test_target_group(test_source_location_long SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_LONG TEST_SRCLOC=ZF_LOG_SRCLOC_LONG)\nadd_test_target_group(test_source_location_none_Os SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_NONE TEST_SRCLOC=ZF_LOG_SRCLOC_NONE ZF_LOG_OPTIMIZE_SIZE=1)\nadd_test_target_group(test_source_location_short_Os SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_SHORT TEST_SRCLOC=ZF_LOG_SRCLOC_SHORT ZF_LOG_OPTIMIZE_SIZE=1)\nadd_test_target_group(test_source_location_long_Os SOURCES test_source_location.c\n\t\tDEFINES ZF_LOG_SRCLOC=ZF_LOG_SRCLOC_LONG TEST_SRCLOC=ZF_LOG_SRCLOC_LONG ZF_LOG_OPTIMIZE_SIZE=1)\n\nadd_test_target_group(test_conditional SOURCES test_conditional.c)\nadd_test_target_group(test_censoring_off SOURCES test_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_UNCENSORED TEST_LOG_SECRETS=1)\nadd_test_target_group(test_censoring_on SOURCES test_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_CENSORED TEST_LOG_SECRETS=0)\n\nadd_test_target_group(test_private_parts SOURCES test_private_parts.c)\nadd_test_target_group(test_decoration SOURCES test_decoration.module.c test_decoration.main.c)\nadd_test_target_group(test_aux_spec SOURCES test_aux_spec.c)\nadd_test_target_group(test_builtin_output_facilities SOURCES test_builtin_output_facilities.c COMPILE_ONLY)\nadd_test_target_group(test_externally_defined_state SOURCES test_externally_defined_state.c)\nadd_test_target(test_externally_defined_state_cpp SOURCES test_externally_defined_state_cpp.cpp CXXSTD 11)\nadd_test_target(test_compilation_cpp SOURCES test_compilation_cpp.cpp CXXSTD 11)\n\n# generated code size tests\nadd_executable(filesize_check filesize_check.c)\nset(CODE_SIZE_SOURCE_DIR \"${CMAKE_CURRENT_BINARY_DIR}/code_size_tests\")\n\nfunction(save_preprocessor_output target)\n\tif(MSVC)\n\t\t# MSVC lacks this feature, /P suppresses compilation.\n\t\t#target_compile_options(${target} PRIVATE \"/P\")\n\telse()\n\t\ttarget_compile_options(${target} PRIVATE \"-save-temps\")\n\tendif()\nendfunction()\n\nfunction(add_copy_command src dst)\n\tadd_custom_command(OUTPUT \"${dst}\"\n\t\tCOMMAND \"${CMAKE_COMMAND}\" -E copy_if_different \"${src}\" \"${dst}\"\n\t\tDEPENDS \"${src}\")\n\tset_source_files_properties(\"${dst}\" PROPERTIES GENERATED TRUE)\nendfunction()\n\n# copy reference and current versions of zf_log.h\nadd_copy_command(\"${CMAKE_CURRENT_SOURCE_DIR}/zf_log.h.master\" \"${CODE_SIZE_SOURCE_DIR}/prev/zf_log.h\")\nadd_copy_command(\"${PROJECT_SOURCE_DIR}/zf_log/zf_log.h\" \"${CODE_SIZE_SOURCE_DIR}/curr/zf_log.h\")\n\nfunction(add_code_size_test target)\n\tcmake_parse_arguments(arg\n\t\t\"\"\n\t\t\"\"\n\t\t\"SOURCES;DEFINES\"\n\t\t${ARGN})\n\tset(prev_sources \"${CODE_SIZE_SOURCE_DIR}/prev/zf_log.h\")\n\tset(curr_sources \"${CODE_SIZE_SOURCE_DIR}/curr/zf_log.h\")\n\tforeach(src ${arg_SOURCES})\n\t\t# \"-save-temps\" will put all \".s\" files directly in the \"tests\" build\n\t\t# directory which is not specific for the target. Since it's useful to\n\t\t# examine those files, test sources will be copied with different\n\t\t# names for *-prev and *-curr targets. That way generated \"*.s\" files\n\t\t# will have different names too and will not overwrite each other.\n\t\tget_filename_component(src_name \"${src}\" NAME_WE)\n\t\tget_filename_component(src_ext \"${src}\" EXT)\n\t\tget_filename_component(src_path \"${src}\" ABSOLUTE)\n\t\tset(src_copy_prev \"${CODE_SIZE_SOURCE_DIR}/${target}-${src_name}-prev${src_ext}\")\n\t\tset(src_copy_curr \"${CODE_SIZE_SOURCE_DIR}/${target}-${src_name}-curr${src_ext}\")\n\t\tadd_copy_command(\"${src_path}\" \"${src_copy_prev}\")\n\t\tadd_copy_command(\"${src_path}\" \"${src_copy_curr}\")\n\t\tlist(APPEND prev_sources \"${src_copy_prev}\")\n\t\tlist(APPEND curr_sources \"${src_copy_curr}\")\n\tendforeach()\n\n\t# prev library\n\tadd_library(${target}-prev STATIC ${prev_sources})\n\ttarget_include_directories(${target}-prev PRIVATE \"${CODE_SIZE_SOURCE_DIR}/prev\")\n\ttarget_compile_definitions(${target}-prev PRIVATE ${arg_DEFINES})\n\tsave_preprocessor_output(${target}-prev)\n\t# curr library\n\tadd_library(${target}-curr STATIC ${curr_sources})\n\ttarget_include_directories(${target}-curr PRIVATE \"${CODE_SIZE_SOURCE_DIR}/curr\")\n\ttarget_compile_definitions(${target}-curr PRIVATE ${arg_DEFINES})\n\tsave_preprocessor_output(${target}-curr)\n\t# test case\n\tadd_dependencies(filesize_check ${target}-prev ${target}-curr)\n\tadd_test(NAME ${target}_check\n\t\tCOMMAND filesize_check \"$<TARGET_FILE:${target}-prev>\" \"$<TARGET_FILE:${target}-curr>\")\nendfunction()\n\nadd_code_size_test(test_call_site_size_msg_only SOURCES test_call_site_size_msg_only.c)\nadd_code_size_test(test_call_site_size_fmt_args SOURCES test_call_site_size_fmt_args.c)\nadd_code_size_test(test_call_site_size_conditional_true  SOURCES test_call_site_size_conditional.c DEFINES TEST_CONDITION=1)\nadd_code_size_test(test_call_site_size_conditional_false SOURCES test_call_site_size_conditional.c DEFINES TEST_CONDITION=0)\nadd_code_size_test(test_call_site_size_censoring_on  SOURCES test_call_site_size_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_CENSORED)\nadd_code_size_test(test_call_site_size_censoring_off SOURCES test_call_site_size_censoring.c DEFINES ZF_LOG_CENSORING=ZF_LOG_UNCENSORED)\n"
  },
  {
    "path": "tests/filesize_check.c",
    "content": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_SECURE_NO_WARNINGS\n#endif\n#include <stdio.h>\n#include <stdlib.h>\n\nstatic long filesize(const char *const path)\n{\n\tFILE *const f = fopen(path, \"rb\");\n\tif (0 == f)\n\t{\n\t\tfprintf(stderr, \"Bad file: %s\\n\", path);\n\t\texit(1);\n\t}\n\tfseek(f, 0, SEEK_END);\n\tconst long sz = (unsigned)ftell(f);\n\tfclose(f);\n\treturn sz;\n}\n\nint main(int argc, const char *argv[])\n{\n\tif (2 >= argc)\n\t{\n\t\tfprintf(stderr, \"Usage: prog f1_path f2_path\\n\");\n\t\treturn 1;\n\t}\n\tconst long f1_sz = filesize(argv[1]);\n\tconst long f2_sz = filesize(argv[2]);\n\tif (f1_sz < f2_sz)\n\t{\n\t\tfprintf(stderr, \"New size is larger: %li <  %li\\n\", f1_sz, f2_sz);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.2)\n\ninclude(ExternalProject)\ninclude(CMakeParseArguments)\nset(THREADS_PREFER_PTHREAD_FLAG ON)\nfind_package(Threads REQUIRED)\nfind_package(PythonInterp 2.7 REQUIRED)\n\nset(CMAKE_C_STANDARD 11)\nset(CMAKE_C_STANDARD_REQUIRED ON)\nset(CMAKE_C_EXTENSIONS OFF)\nset(CMAKE_CXX_STANDARD 11)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\nif(MSVC)\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /W4 /WX\")\nelse()\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors\")\nendif()\n\noption(ZF_LOG_PERF_TEST_SAVE_TEMPS \"Save preprocessor and disassembler output\" OFF)\noption(ZF_LOG_PERF_TEST_ZF_LOG_OS \"Add zf_log built with ZF_LOG_OPTIMIZE_SIZE to performance tests\" OFF)\noption(ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD \"Enable verbose build output for 3rd party libraries (noisy)\" OFF)\n\n# Launch rules are target properties (RULE_LAUNCH_COMPILE, RULE_LAUNCH_LINK)\n# that are used to time compilation and linking. Tests that require this\n# properties will be disabled if current generator doesn't support launch\n# rules. See CMake documentation for up to date list of generators that support\n# launch rules.\nif(CMAKE_GENERATOR MATCHES \"Makefiles\" OR\n   CMAKE_GENERATOR MATCHES \"Ninja\")\n\tset(LAUNCH_RULES ON)\nelse()\n\tmessage(WARNING \"Timing compilation and linking is not supported by \\\"${CMAKE_GENERATOR}\\\" generator!\")\n\tset(LAUNCH_RULES OFF)\nendif()\n# Since a lot of 3rd party dependencies envolved, it's only so much we can do here.\n# Non-Unix support is possible, but not in the scope right now.\nif(NOT UNIX)\n\tmessage(WARNING \"Performance tests only maintained for Unix platforms!\")\nendif()\n# For convenience, ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD is inverse of what is\n# actually needed. SILENT_3P_BUILD variable will be used instead.\nset(SILENT_3P_BUILD ON)\nif(ZF_LOG_PERF_TEST_VERBOSE_3P_BUILD)\n\tset(SILENT_3P_BUILD OFF)\nendif()\n\nfunction(add_target target)\n\tcmake_parse_arguments(arg\n\t\t\"STATICLIB;EXECUTABLE;NO_THREADS\"\n\t\t\"TIME_COMPILE;TIME_LINK\"\n\t\t\"SOURCES;DEFINES;INCLUDES;COMPILE_OPTIONS;LIBRARIES\"\n\t\t${ARGN})\n\tif(ZF_LOG_PERF_TEST_SAVE_TEMPS)\n\t\t# Clang writes *.s and *.ii files into its current working directory.\n\t\t# Since the same source files are used in multiple targets, need to\n\t\t# copy them, so they will have different names for different targets.\n\t\tset(SOURCES \"\")\n\t\tforeach(source ${arg_SOURCES})\n\t\t\tif(IS_ABSOLUTE source)\n\t\t\t\tset(src \"${source}\")\n\t\t\telse()\n\t\t\t\tset(src \"${CMAKE_CURRENT_SOURCE_DIR}/${source}\")\n\t\t\tendif()\n\t\t\tget_filename_component(src_name \"${source}\" NAME)\n\t\t\tset(dst \"${CMAKE_CURRENT_BINARY_DIR}/sources/${target}-${src_name}\")\n\t\t\tadd_custom_command(OUTPUT \"${dst}\"\n\t\t\t\tCOMMAND \"${CMAKE_COMMAND}\" -E copy_if_different \"${src}\" \"${dst}\"\n\t\t\t\tDEPENDS \"${src}\")\n\t\t\tlist(APPEND SOURCES \"${dst}\")\n\t\tendforeach()\n\telse()\n\t\tset(SOURCES ${arg_SOURCES})\n\tendif()\n\tif(arg_STATICLIB)\n\t\tadd_library(${target} STATIC ${SOURCES})\n\telseif(arg_EXECUTABLE)\n\t\tadd_executable(${target} ${SOURCES})\n\t\tif(NOT NO_THREADS)\n\t\t\ttarget_link_libraries(${target} Threads::Threads)\n\t\tendif()\n\telse()\n\t\tmessage(FATAL_ERROR \"Test target type is not specified.\")\n\tendif()\n\tif(ZF_LOG_PERF_SAVE_TEMPS)\n\t\ttarget_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})\n\t\ttarget_compile_options(${target} PRIVATE \"-save-temps\")\n\tendif()\n\tif(arg_DEFINES)\n\t\tset_property(TARGET ${target} PROPERTY COMPILE_DEFINITIONS \"${arg_DEFINES}\")\n\tendif()\n\tif(arg_INCLUDES)\n\t\ttarget_include_directories(${target} PRIVATE ${arg_INCLUDES})\n\tendif()\n\tif(arg_COMPILE_OPTIONS)\n\t\ttarget_compile_options(${target} PRIVATE ${arg_COMPILE_OPTIONS})\n\tendif()\n\tif(arg_LIBRARIES)\n\t\ttarget_link_libraries(${target} ${arg_LIBRARIES})\n\tendif()\n\tif(arg_TIME_COMPILE)\n\t\tset_property(TARGET ${target} PROPERTY RULE_LAUNCH_COMPILE\n\t\t\t\"\\\"${PYTHON_EXECUTABLE}\\\" \\\"${CMAKE_CURRENT_SOURCE_DIR}/time_it.py\\\" \\\"${arg_TIME_COMPILE}\\\"\")\n\t\tset_property(TARGET ${target} PROPERTY TIME_COMPILE \"${arg_TIME_COMPILE}\")\n\tendif()\n\tif(arg_TIME_LINK)\n\t\tset_property(TARGET ${target} PROPERTY RULE_LAUNCH_LINK\n\t\t\t\"\\\"${PYTHON_EXECUTABLE}\\\" \\\"${CMAKE_CURRENT_SOURCE_DIR}/time_it.py\\\" \\\"${arg_TIME_LINK}\\\"\")\n\t\tset_property(TARGET ${target} PROPERTY TIME_LINK \"${arg_TIME_LINK}\")\n\tendif()\nendfunction()\n\n# zf_log\nset(ZF_LOG_DIR \"${PROJECT_SOURCE_DIR}/zf_log\")\nadd_library(zf_log_n STATIC \"${ZF_LOG_DIR}/zf_log.h\" \"${ZF_LOG_DIR}/zf_log.c\")\ntarget_include_directories(zf_log_n PUBLIC \"${ZF_LOG_DIR}\")\nadd_library(zf_log_Os STATIC \"${ZF_LOG_DIR}/zf_log.h\" \"${ZF_LOG_DIR}/zf_log.c\")\ntarget_include_directories(zf_log_Os PUBLIC \"${ZF_LOG_DIR}\")\nset_property(TARGET zf_log_Os PROPERTY COMPILE_DEFINITIONS \"ZF_LOG_OPTIMIZE_SIZE\")\n\n# spdlog\nset(SPDLOG_DIR \"${CMAKE_CURRENT_BINARY_DIR}/spdlog\")\nExternalProject_Add(spdlog_ep\n\tPREFIX \"${SPDLOG_DIR}\"\n\tUPDATE_COMMAND \"\"\n\tGIT_REPOSITORY \"https://github.com/gabime/spdlog.git\"\n\tGIT_TAG \"e91e1b80f9c4332bcef8388ff48ee705128e5519\"\n\tCMAKE_GENERATOR \"${CMAKE_GENERATOR}\"\n\tCMAKE_ARGS\n\t\t\"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}\"\n\t\t\"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>\"\n\t\t\"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}\"\n\t\t\"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}\"\n\t\t\"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}\"\n\t\t\"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}\"\n\tLOG_DOWNLOAD ${SILENT_3P_BUILD}\n\tLOG_UPDATE ${SILENT_3P_BUILD}\n\tLOG_CONFIGURE ${SILENT_3P_BUILD}\n\tLOG_BUILD ${SILENT_3P_BUILD}\n\tLOG_TEST ${SILENT_3P_BUILD}\n\tLOG_INSTALL ${SILENT_3P_BUILD}\n)\nadd_library(spdlog INTERFACE)\nadd_dependencies(spdlog spdlog_ep)\nset_target_properties(spdlog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"${SPDLOG_DIR}/include\")\n\n# easyloggingpp\nset(EASYLOG_DIR \"${CMAKE_CURRENT_BINARY_DIR}/easyloggingpp\")\nExternalProject_Add(easylog_ep\n\tPREFIX \"${EASYLOG_DIR}\"\n\tUPDATE_COMMAND \"\"\n\tGIT_REPOSITORY \"https://github.com/easylogging/easyloggingpp.git\"\n\tGIT_TAG \"f926802dfbde716d82b64b8ef3c25b7f0fcfec65\"\n\tCONFIGURE_COMMAND \"\"\n\tBUILD_COMMAND \"\"\n\tINSTALL_COMMAND \"${CMAKE_COMMAND}\" -E copy_directory\n\t\t\"<SOURCE_DIR>/src\" \"<INSTALL_DIR>/include\"\n\tLOG_DOWNLOAD ${SILENT_3P_BUILD}\n\tLOG_UPDATE ${SILENT_3P_BUILD}\n\tLOG_CONFIGURE ${SILENT_3P_BUILD}\n\tLOG_BUILD ${SILENT_3P_BUILD}\n\tLOG_TEST ${SILENT_3P_BUILD}\n\tLOG_INSTALL ${SILENT_3P_BUILD}\n)\nadd_library(easylog INTERFACE)\nadd_dependencies(easylog easylog_ep)\nset_target_properties(easylog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"${EASYLOG_DIR}/include\")\n\n# g3log\nset(G3LOG_DIR \"${CMAKE_CURRENT_BINARY_DIR}/g3log\")\nset(G3LOG_LIBRARY \"${CMAKE_STATIC_LIBRARY_PREFIX}g3logger${CMAKE_STATIC_LIBRARY_SUFFIX}\")\nExternalProject_Add(g3log_ep\n\tPREFIX \"${G3LOG_DIR}\"\n\tUPDATE_COMMAND \"\"\n\tGIT_REPOSITORY \"https://github.com/KjellKod/g3log.git\"\n\tGIT_TAG \"1c6ede6db4fbb12006b61a913de737df56b9dd32\"\n\tCMAKE_GENERATOR \"${CMAKE_GENERATOR}\"\n\tCMAKE_ARGS\n\t\t\"-Wno-dev\"\n\t\t\"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}\"\n\t\t\"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>\"\n\t\t\"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}\"\n\t\t\"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}\"\n\t\t\"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}\"\n\t\t\"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}\"\n\t\t\"-DUSE_DYNAMIC_LOGGING_LEVELS:bool=ON\"\n\tINSTALL_COMMAND \"${CMAKE_COMMAND}\" -E copy_directory\n\t\t\"<SOURCE_DIR>/src/g3log\" \"<INSTALL_DIR>/include/g3log\"\n\t\tCOMMAND \"${CMAKE_COMMAND}\" -E copy_if_different\n\t\t\"<BINARY_DIR>/${G3LOG_LIBRARY}\" \"<INSTALL_DIR>/lib/${G3LOG_LIBRARY}\"\n\tLOG_DOWNLOAD ${SILENT_3P_BUILD}\n\tLOG_UPDATE ${SILENT_3P_BUILD}\n\tLOG_CONFIGURE ${SILENT_3P_BUILD}\n\tLOG_BUILD ${SILENT_3P_BUILD}\n\tLOG_TEST ${SILENT_3P_BUILD}\n\tLOG_INSTALL ${SILENT_3P_BUILD}\n)\nadd_library(g3log INTERFACE)\nadd_dependencies(g3log g3log_ep)\nset_target_properties(g3log PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"${G3LOG_DIR}/include\")\nset_target_properties(g3log PROPERTIES INTERFACE_LINK_LIBRARIES \"${G3LOG_DIR}/lib/${G3LOG_LIBRARY}\")\n\n# glog\nset(GLOG_DIR \"${CMAKE_CURRENT_BINARY_DIR}/glog\")\nset(GLOG_LIBRARY \"${CMAKE_STATIC_LIBRARY_PREFIX}glog${CMAKE_STATIC_LIBRARY_SUFFIX}\")\nExternalProject_Add(glog_ep\n\tPREFIX \"${GLOG_DIR}\"\n\tUPDATE_COMMAND \"\"\n\tGIT_REPOSITORY \"https://github.com/google/glog.git\"\n\tGIT_TAG \"4d391fe692ae6b9e0105f473945c415a3ce5a401\"\n\tCMAKE_GENERATOR \"${CMAKE_GENERATOR}\"\n\tCMAKE_ARGS\n\t\t\"-Wno-dev\"\n\t\t\"-DCMAKE_TOOLCHAIN_FILE:filepath=${CMAKE_TOOLCHAIN_FILE}\"\n\t\t\"-DCMAKE_INSTALL_PREFIX:path=<INSTALL_DIR>\"\n\t\t\"-DCMAKE_BUILD_TYPE:string=${CMAKE_BUILD_TYPE}\"\n\t\t\"-DCMAKE_OSX_ARCHITECTURES:string=${CMAKE_OSX_ARCHITECTURES}\"\n\t\t\"-DCMAKE_OSX_DEPLOYMENT_TARGET:string=${CMAKE_OSX_DEPLOYMENT_TARGET}\"\n\t\t\"-DCMAKE_OSX_SYSROOT:path=${CMAKE_OSX_SYSROOT}\"\n\tLOG_DOWNLOAD ${SILENT_3P_BUILD}\n\tLOG_UPDATE ${SILENT_3P_BUILD}\n\tLOG_CONFIGURE ${SILENT_3P_BUILD}\n\tLOG_BUILD ${SILENT_3P_BUILD}\n\tLOG_TEST ${SILENT_3P_BUILD}\n\tLOG_INSTALL ${SILENT_3P_BUILD}\n)\nadd_library(glog INTERFACE)\nadd_dependencies(glog glog_ep)\nset_target_properties(glog PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"${GLOG_DIR}/include\")\nset_target_properties(glog PROPERTIES INTERFACE_LINK_LIBRARIES \"${GLOG_DIR}/lib/${GLOG_LIBRARY}\")\n\nfunction(get_test_library lib var)\n\tif((lib STREQUAL \"zf_log_n\") OR (lib STREQUAL \"zf_log_Os\"))\n\t\tset(lib \"zf_log\")\n\tendif()\n\tset(${var} \"${lib}\" PARENT_SCOPE)\nendfunction()\n\nfunction(get_test_compile_options lib var)\n\tset(compile_options)\n\tif(lib STREQUAL \"g3log\")\n\t\t# g3log public headers generate \"braced-scalar-init\" warnings\n\t\tset(compile_options \"-Wno-braced-scalar-init\")\n\tendif()\n\tset(${var} \"${compile_options}\" PARENT_SCOPE)\nendfunction()\n\nfunction(add_executable_size_test lib)\n\tget_test_library(\"${lib}\" test_library)\n\tget_test_compile_options(\"${lib}\" compile_options)\n\tadd_target(test_call_site_size.str.${lib}.1 STATICLIB LIBRARIES \"${lib}\"\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tTIME_COMPILE \"${CMAKE_CURRENT_BINARY_DIR}/compile_time.${lib}.json\"\n\t\tSOURCES test_executable_size.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\"\n\t\t\t\"TEST_SEVERAL_STATEMENTS\")\n\tadd_target(test_call_site_size.str.${lib}.2 STATICLIB LIBRARIES \"${lib}\"\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_executable_size.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\"\n\t\t\t\"TEST_SEVERAL_STATEMENTS\" \"TEST_EXTRA_STATEMENT\")\n\tadd_target(test_call_site_size.fmti.${lib}.1 STATICLIB LIBRARIES \"${lib}\"\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_executable_size.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\"\n\t\t\t\"TEST_FORMAT_INTS\" \"TEST_SEVERAL_STATEMENTS\")\n\tadd_target(test_call_site_size.fmti.${lib}.2 STATICLIB LIBRARIES \"${lib}\"\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_executable_size.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\"\n\t\t\t\"TEST_FORMAT_INTS\" \"TEST_SEVERAL_STATEMENTS\" \"TEST_EXTRA_STATEMENT\")\n\tadd_target(test_executable_size.m1.${lib} EXECUTABLE LIBRARIES \"${lib}\" NO_THREADS\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tTIME_LINK \"${CMAKE_CURRENT_BINARY_DIR}/link_time.${lib}.json\"\n\t\tSOURCES test_executable_size.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\")\n\tlist(APPEND PARAMETERS \"-p\" \"call_site_size:str:${lib}:1:$<TARGET_FILE:test_call_site_size.str.${lib}.1>\")\n\tlist(APPEND PARAMETERS \"-p\" \"call_site_size:str:${lib}:2:$<TARGET_FILE:test_call_site_size.str.${lib}.2>\")\n\tlist(APPEND PARAMETERS \"-p\" \"call_site_size:fmti:${lib}:1:$<TARGET_FILE:test_call_site_size.fmti.${lib}.1>\")\n\tlist(APPEND PARAMETERS \"-p\" \"call_site_size:fmti:${lib}:2:$<TARGET_FILE:test_call_site_size.fmti.${lib}.2>\")\n\tlist(APPEND PARAMETERS \"-p\" \"executable_size:m1:${lib}:$<TARGET_FILE:test_executable_size.m1.${lib}>\")\n\tif(LAUNCH_RULES)\n\t\tlist(APPEND PARAMETERS \"-p\" \"compile_time:${lib}:$<TARGET_PROPERTY:test_call_site_size.str.${lib}.1,TIME_COMPILE>\")\n\t\tlist(APPEND PARAMETERS \"-p\" \"link_time:${lib}:$<TARGET_PROPERTY:test_executable_size.m1.${lib},TIME_LINK>\")\n\tendif()\n\tset(PARAMETERS \"${PARAMETERS}\" PARENT_SCOPE)\nendfunction()\n\nif(ZF_LOG_PERF_TEST_ZF_LOG_OS)\n\tadd_executable_size_test(zf_log_Os)\nendif()\nadd_executable_size_test(zf_log_n)\nadd_executable_size_test(spdlog)\nadd_executable_size_test(easylog)\nadd_executable_size_test(g3log)\nadd_executable_size_test(glog)\n\nfunction(add_speed_test lib)\n\tget_test_library(\"${lib}\" test_library)\n\tget_test_compile_options(\"${lib}\" compile_options)\n\tadd_target(test_speed.str.${lib} EXECUTABLE\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_speed.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\" \"TEST_NULL_SINK\"\n\t\tLIBRARIES \"${lib}\")\n\tadd_target(test_speed.fmti.${lib} EXECUTABLE\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_speed.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\" \"TEST_NULL_SINK\" \"TEST_FORMAT_INTS\"\n\t\tLIBRARIES \"${lib}\")\n\tadd_target(test_speed.str-off.${lib} EXECUTABLE\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_speed.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\" \"TEST_NULL_SINK\" \"TEST_LOG_OFF\"\n\t\tLIBRARIES \"${lib}\")\n\tadd_target(test_speed.slowf-off.${lib} EXECUTABLE\n\t\tCOMPILE_OPTIONS ${compile_options}\n\t\tSOURCES test_speed.cpp\n\t\tDEFINES \"TEST_LIBRARY=${test_library}\" \"TEST_NULL_SINK\" \"TEST_FORMAT_SLOW_FUNC\" \"TEST_LOG_OFF\"\n\t\tLIBRARIES \"${lib}\")\n\tlist(APPEND PARAMETERS \"-p\" \"speed:str:${lib}:$<TARGET_FILE:test_speed.str.${lib}>\")\n\tlist(APPEND PARAMETERS \"-p\" \"speed:fmti:${lib}:$<TARGET_FILE:test_speed.fmti.${lib}>\")\n\tlist(APPEND PARAMETERS \"-p\" \"speed:str-off:${lib}:$<TARGET_FILE:test_speed.str-off.${lib}>\")\n\tlist(APPEND PARAMETERS \"-p\" \"speed:slowf-off:${lib}:$<TARGET_FILE:test_speed.slowf-off.${lib}>\")\n\tset(PARAMETERS \"${PARAMETERS}\" PARENT_SCOPE)\nendfunction()\n\nif(ZF_LOG_PERF_TEST_ZF_LOG_OS)\n\tadd_speed_test(zf_log_Os)\nendif()\nadd_speed_test(zf_log_n)\nadd_speed_test(spdlog)\nadd_speed_test(easylog)\nadd_speed_test(g3log)\nadd_speed_test(glog)\n\n# results\nadd_test(NAME perf_tests COMMAND \"${PYTHON_EXECUTABLE}\"\n\t\"${CMAKE_CURRENT_SOURCE_DIR}/run_tests.py\"\n\t-t \"${CMAKE_CURRENT_BINARY_DIR}/results.txt\"\n\t-m \"${CMAKE_CURRENT_BINARY_DIR}/results.md\"\n\t-b \"${CMAKE_BUILD_TYPE}\"\n\t-v\n\t${PARAMETERS})\n"
  },
  {
    "path": "tests/perf/run_tests.py",
    "content": "#!/usr/bin/python\n\nimport sys\nimport os\nimport argparse\nimport subprocess\nimport multiprocessing\nimport json\nimport pprint\n\ndef take_first(value):\n\tif type(value) is tuple or type(value) is list:\n\t\treturn value[0]\n\treturn value\n\ndef take_order(value, order):\n\tfor i in range(len(order)):\n\t\tif value == order[i]:\n\t\t\treturn i\n\treturn len(order)\n\ndef take_map(value, keys, vals):\n\tif len(keys) != len(vals):\n\t\traise RuntimeError(\"Length of keys and vals must match\")\n\tfor i in range(len(keys)):\n\t\tif value == keys[i]:\n\t\t\treturn vals[i]\n\treturn value\n\ndef take_best(values, key, compare, reverse=False):\n\tif 0 == len(values):\n\t\treturn []\n\tvalues = sorted(values, key=key, reverse=reverse)\n\tfor i in range(1, len(values)):\n\t\tif not compare(values[0], values[i]):\n\t\t\treturn values[0:i]\n\treturn values\n\ndef take_plural(count, base, suffix):\n\tif 1 == abs(count):\n\t\treturn base\n\treturn base + suffix\n\ndef take_threads_variants():\n\t# single thread\n\tvariants = [1]\n\tcpus = multiprocessing.cpu_count()\n\tif 1 > cpus:\n\t\tcpus = 1\n\t# load all CPUs\n\tif 1 < cpus:\n\t\tvariants.append(cpus)\n\t# overcommit\n\tvariants.append(2 * cpus)\n\treturn variants\n\ndef _cmp_percentage(p, key, a, b):\n\tif key(a) == key(b):\n\t\treturn True\n\tif p >= abs((key(a) - key(b)) / float(key(a))):\n\t\treturn True\n\treturn False\n\ndef cmp_percentage(p, key):\n\treturn lambda a, b: _cmp_percentage(p, key, a, b)\n\ndef translate_test(test):\n\tname = take_first(test)\n\tif \"call_site_size.str\" == name:\n\t\treturn 1000, \"Call site size: string\"\n\tif \"call_site_size.fmti\" == name:\n\t\treturn 2000, \"Call site size: 3 integers\"\n\tif \"executable_size.m1\" == name:\n\t\treturn 3000, \"Executable size: 1 module\"\n\tif \"compile_time\" == name:\n\t\treturn 4000, \"Module compile time\"\n\tif \"link_time\" == name:\n\t\treturn 5000, \"Executable link time\"\n\tif \"speed\" == name:\n\t\tthreads = test[1]\n\t\tmode = test[2]\n\t\tmode_keys = [\"str\",    \"fmti\",       \"str-off\",        \"slowf-off\"]\n\t\tmode_vals = [\"string\", \"3 integers\", \"string, off\", \"slow function, off\"]\n\t\ttr_mode = take_map(mode, mode_keys, mode_vals)\n\t\torder = 10 * threads + take_order(mode, mode_keys)\n\t\treturn 6000 + order, \"Speed: %i %s, %s\" % (threads, take_plural(threads, \"thread\", \"s\"), tr_mode)\n\tif type(test) is tuple or type(test) is list:\n\t\treturn 31416, \", \".join(test)\n\treturn 27183, test\n\ndef translate_subj(subj):\n\tif \"zf_log_n\" == subj:\n\t\treturn 31416, \"zf_log\"\n\tif \"easylog\" == subj:\n\t\treturn 31416, \"Easylogging++\"\n\treturn 31416, subj\n\ndef translation_sort_key(v):\n\treturn \"[%04i] %s\" % (v[0], v[1])\n\ndef translation_value(v):\n\treturn v[1]\n\nclass data_cell:\n\tdef __init__(self):\n\t\tself.best = False\n\tdef set_best(self, best=True):\n\t\tself.best = best\n\tdef ifbest(self, a, b):\n\t\tif hasattr(self, \"best\") and self.best:\n\t\t\treturn a\n\t\treturn b\n\nclass data_str(data_cell):\n\tdef __init__(self, value):\n\t\tif type(value) is not str:\n\t\t\traise RuntimeError(\"Not a string\")\n\t\tself.value = value\n\tdef __str__(self):\n\t\treturn self.value\n\tdef __repr__(self):\n\t\treturn repr(self.value)\n\nclass data_bytes(data_cell):\n\tdef __init__(self, value):\n\t\tif type(value) is not int:\n\t\t\traise RuntimeError(\"Not an int\")\n\t\tself.value = value\n\tdef __str__(self):\n\t\tif self.value < 1024:\n\t\t\treturn \"%i B\" % (self.value)\n\t\tif self.value < 1024 * 1024:\n\t\t\treturn \"%.2f KB\" % (self.value / 1024.0)\n\t\treturn \"%.2f MB\" % (self.value / 1024.0 / 1024.0)\n\tdef __repr__(self):\n\t\treturn repr(self.value)\n\nclass data_seconds(data_cell):\n\tdef __init__(self, value):\n\t\tif type(value) is not int and type(value) is not float:\n\t\t\traise RuntimeError(\"Not an int or float\")\n\t\tself.value = value\n\tdef __str__(self):\n\t\treturn \"%.3f sec\" % (self.value)\n\tdef __repr__(self):\n\t\treturn repr(self.value)\n\nclass data_freq(data_cell):\n\tdef __init__(self, count, seconds):\n\t\tif type(count) is not int and type(count) is not float:\n\t\t\traise RuntimeError(\"Not an int or float\")\n\t\tif type(seconds) is not int and type(seconds) is not float:\n\t\t\traise RuntimeError(\"Not an int or float\")\n\t\tself.count = count\n\t\tself.seconds = seconds\n\tdef __str__(self):\n\t\treturn \"{:,}\".format(self.count / self.seconds)\n\tdef __repr__(self):\n\t\treturn repr((self.count, self.seconds))\n\tdef freq(self):\n\t\treturn self.count / self.seconds\n\ndef get_table_data(result):\n\t# collect all tests\n\ttests = result.keys()\n\ttests = sorted(tests, key=lambda x: translation_sort_key(translate_test(x)))\n\t# collect all subjects\n\tsubjs = set()\n\tfor test in tests:\n\t\tsubjs.update(result[test].keys())\n\tsubjs = sorted(subjs, key=lambda x: translation_sort_key(translate_subj(x)))\n\t# create table\n\trows = len(tests) + 1\n\tcols = len(subjs) + 1\n\ttable = [[None for _ in range(cols)] for _ in range(rows)]\n\t# put names and captions\n\tfor i in range(1, rows):\n\t\ttable[i][0] = data_str(translation_value(translate_test(tests[i - 1])))\n\tfor j in range(1, cols):\n\t\ttable[0][j] = data_str(translation_value(translate_subj(subjs[j - 1])))\n\t# put data\n\tfor i in range(1, rows):\n\t\tfor j in range(1, cols):\n\t\t\ttest = tests[i - 1]\n\t\t\tsubj = subjs[j - 1]\n\t\t\tif subj in result[test]:\n\t\t\t\ttable[i][j] = result[test][subj]\n\t# gen cells content\n\tfor i in range(0, rows):\n\t\tfor j in range(0, cols):\n\t\t\tvalue = table[i][j]\n\t\t\tif value is None:\n\t\t\t\tvalue = data_str(\"\")\n\t\t\telif not isinstance(value, data_cell):\n\t\t\t\traise RuntimeError(\"Value \\\"%s\\\" is of unsupported type \\\"%s\\\"\" % (value, type(value)))\n\t\t\ttable[i][j] = value\n\t# find cols width\n\twidths = [0 for _ in range(cols)]\n\tfor j in range(0, cols):\n\t\tfor i in range(0, rows):\n\t\t\ts = str(table[i][j])\n\t\t\tif widths[j] < len(s):\n\t\t\t\twidths[j] = len(s)\n\treturn table, rows, cols, widths\n\ndef gen_table_ascii(result):\n\ttable, rows, cols, widths = get_table_data(result)\n\t# apply cell format\n\tmargin_norm  = (\" \", \" \")\n\tmargin_best  = (\"*\", \" \")\n\tmargins = max(map(len, margin_norm)) + max(map(len, margin_norm))\n\tfor i in range(1, rows):\n\t\ttable[i][0] = str(table[i][0]).ljust(widths[0]).join(margin_norm)\n\tfor j in range(0, cols):\n\t\ttable[0][j] = str(table[0][j]).center(widths[j]).join(margin_norm)\n\tfor i in range(1, rows):\n\t\tfor j in range(1, cols):\n\t\t\tdata = table[i][j]\n\t\t\tmargin = data.ifbest(margin_best, margin_norm)\n\t\t\ttable[i][j] = str(data).rjust(widths[j]).join(margin)\n\t# draw chart\n\tline = \"+\" + \"-\" * (sum(widths) + (margins + 1) * len(widths) - 1) + \"+\\n\"\n\tchart = line\n\tfor row in table:\n\t\tchart += \"|\"\n\t\tfor cell in row:\n\t\t\tchart += \"%s|\" % (cell)\n\t\tchart += \"\\n\" + line\n\treturn chart\n\ndef gen_table_markdown(result):\n\ttable, rows, cols, widths = get_table_data(result)\n\t# apply cell format\n\tmargin_norm  = (\"  \", \"  \")\n\tmargin_best  = (\"**\", \"**\")\n\tmargins = max(map(len, margin_norm)) + max(map(len, margin_norm))\n\tfor i in range(1, rows):\n\t\ttable[i][0] = str(table[i][0]).ljust(widths[0]).join(margin_norm)\n\tfor j in range(0, cols):\n\t\ttable[0][j] = str(table[0][j]).center(widths[j]).join(margin_norm)\n\tfor i in range(1, rows):\n\t\tfor j in range(1, cols):\n\t\t\tdata = table[i][j]\n\t\t\tmargin = data.ifbest(margin_best, margin_norm)\n\t\t\ttable[i][j] = str(data).join(margin).rjust(widths[j] + margins)\n\t# draw chart\n\tchart = \"\"\n\tif 0 == rows:\n\t\treturn chart\n\tchart += \"|\"\n\tfor cell in table[0]:\n\t\tchart += \"%s|\" % (cell)\n\tchart += \"\\n\"\n\tchart += \"| \" + \"-\" * (margins + widths[0] - 2) + \" |\"\n\tfor i in range(1, cols):\n\t\tchart += \" \" + \"-\" * (margins + widths[i] - 2) + \":|\"\n\tchart += \"\\n\"\n\tfor i in range(1, rows):\n\t\tchart += \"|\"\n\t\tfor j in range(0, cols):\n\t\t\tchart += \"%s|\" % (table[i][j])\n\t\tchart += \"\\n\"\n\treturn chart\n\ndef run_call_site_size(params, result):\n\tif type(result) is not dict:\n\t\traise RuntimeError(\"Not a dictionary\")\n\tid = \"call_site_size\"\n\tparams = params[id]\n\tfor mode in params:\n\t\tname = \"%s.%s\" % (id, mode)\n\t\tvalues = dict()\n\t\tfor subj in params[mode]:\n\t\t\tdata = params[mode][subj]\n\t\t\tsz1 = os.path.getsize(data[\"1\"])\n\t\t\tsz2 = os.path.getsize(data[\"2\"])\n\t\t\tdata = data_bytes(sz2 - sz1)\n\t\t\tvalues[subj] = data\n\t\tresult[name] = values\n\t\tfor best in take_best(values.values(),\n\t\t\t\t\t\t\t  key=lambda x: x.value,\n\t\t\t\t\t\t\t  compare=cmp_percentage(0.0, key=lambda x: x.value)):\n\t\t\tbest.set_best()\n\ndef run_executable_size(params, result):\n\tif type(result) is not dict:\n\t\traise RuntimeError(\"Not a dictionary\")\n\tid = \"executable_size\"\n\tparams = params[id]\n\tfor mode in params:\n\t\tname = \"%s.%s\" % (id, mode)\n\t\tvalues = dict()\n\t\tfor subj in params[mode]:\n\t\t\tsz = os.path.getsize(params[mode][subj])\n\t\t\tvalues[subj] = data_bytes(sz)\n\t\tresult[name] = values\n\t\tfor best in take_best(values.values(),\n\t\t\t\t\t\t\t  key=lambda x: x.value,\n\t\t\t\t\t\t\t  compare=cmp_percentage(0.0, key=lambda x: x.value)):\n\t\t\tbest.set_best()\n\ndef run_build_time(params, result, id, optional=False):\n\tif type(result) is not dict:\n\t\traise RuntimeError(\"Not a dictionary\")\n\tif optional and id not in params:\n\t\treturn\n\tparams = params[id]\n\tvalues = dict()\n\tfor subj in params:\n\t\twith open(params[subj], \"r\") as f:\n\t\t\tdt = json.load(f)[\"dt\"]\n\t\t\tvalues[subj] = data_seconds(dt)\n\tresult[id] = values\n\tfor best in take_best(values.values(),\n\t\t\t\t\t\t  key=lambda x: x.value,\n\t\t\t\t\t\t  compare=cmp_percentage(0.2, key=lambda x: x.value)):\n\t\tbest.set_best()\n\ndef run_speed(params, result, threads_variants, seconds=1):\n\tif type(result) is not dict:\n\t\traise RuntimeError(\"Not a dictionary\")\n\tid = \"speed\"\n\tparams = params[id]\n\tfor threads in threads_variants:\n\t\tfor mode in params:\n\t\t\tname = (id, threads, mode)\n\t\t\tvalues = dict()\n\t\t\tfor subj in params[mode]:\n\t\t\t\tpath = params[mode][subj]\n\t\t\t\tp = subprocess.Popen([path, str(threads), str(seconds)], stdout=subprocess.PIPE)\n\t\t\t\tstdout, stderr = p.communicate()\n\t\t\t\tvalues[subj] = data_freq(int(stdout), seconds)\n\t\t\tresult[name] = values\n\t\t\tfor best in take_best(values.values(),\n\t\t\t\t\t\t\t\t  key=lambda x: x.freq(), reverse=True,\n\t\t\t\t\t\t\t\t  compare=cmp_percentage(0.1, key=lambda x: x.freq())):\n\t\t\t\tbest.set_best()\n\ndef run_tests(params):\n\tresult = dict()\n\trun_call_site_size(params, result)\n\trun_executable_size(params, result)\n\trun_build_time(params, result, \"compile_time\", optional=True)\n\trun_build_time(params, result, \"link_time\", optional=True)\n\trun_speed(params, result, take_threads_variants())\n\treturn result\n\ndef main(argv):\n\tparser = argparse.ArgumentParser()\n\tparser.add_argument(\"-t\", \"--text\", metavar=\"PATH\", default=None,\n\t\t\thelp=\"Text output file path\")\n\tparser.add_argument(\"-m\", \"--markdown\", metavar=\"PATH\", default=None,\n\t\t\thelp=\"Markdown output file path\")\n\tparser.add_argument(\"-p\", \"--parameter\", metavar=\"VALUE\", action=\"append\", default=[],\n\t\t\thelp=\"Input parameter\")\n\tparser.add_argument(\"-b\", \"--build\", metavar=\"TYPE\",\n\t\t\thelp=\"Input parameter\")\n\tparser.add_argument(\"-v\", \"--verbose\", action=\"store_true\",\n\t\t\thelp=\"Verbose output\")\n\targs = parser.parse_args(argv[1:])\n\t# process parameters\n\tparams = dict()\n\tfor p in args.parameter:\n\t\td = params\n\t\tvs = p.split(\":\")\n\t\tkey = None\n\t\tfor i in range(len(vs)):\n\t\t\tif i == len(vs) - 1:\n\t\t\t\td[key] = vs[i]\n\t\t\t\tbreak\n\t\t\tif key is not None:\n\t\t\t\td = d[key]\n\t\t\tkey = vs[i]\n\t\t\tif key not in d:\n\t\t\t\td[key] = dict()\n\tif args.verbose:\n\t\tsys.stderr.write(pprint.pformat(params, indent=4))\n\t\tsys.stderr.write(\"\\n\")\n\t# run, run, run!\n\tresult = run_tests(params)\n\tif args.verbose:\n\t\tsys.stderr.write(pprint.pformat(result, indent=4))\n\t\tsys.stderr.write(\"\\n\")\n\tif args.text is not None:\n\t\twith open(args.text, \"w\") as f:\n\t\t\ttable = gen_table_ascii(result)\n\t\t\tf.write(table)\n\tif args.markdown is not None:\n\t\twith open(args.markdown, \"w\") as f:\n\t\t\ttable = gen_table_markdown(result)\n\t\t\tf.write(table)\n\treturn 0\n\nif __name__ == \"__main__\":\n\tsys.exit(main(sys.argv))\n"
  },
  {
    "path": "tests/perf/test_executable_size.cpp",
    "content": "#include \"test_switch.h\"\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tXLOG_INIT();\n\tXLOG_STATEMENT();\n#ifdef TEST_SEVERAL_STATEMENTS\n\tXLOG_STATEMENT();\n\tXLOG_STATEMENT();\n\tXLOG_STATEMENT();\n\tXLOG_STATEMENT();\n\tXLOG_STATEMENT();\n\tXLOG_STATEMENT();\n#endif\n#ifdef TEST_EXTRA_STATEMENT\n\tXLOG_STATEMENT();\n#endif\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/test_speed.cpp",
    "content": "#include <cstdint>\n#include <cinttypes>\n#include <atomic>\n#include <functional>\n#include <memory>\n#include <vector>\n#include <string>\n#include <thread>\n#include <condition_variable>\n#include \"test_switch.h\"\n\nnamespace\n{\n\tclass thread_latch\n\t{\n\tpublic:\n\t\tthread_latch(): _go(false), _halt(false) {}\n\t\tvoid wait() const;\n\t\tvoid release();\n\t\tbool halted() const;\n\t\tvoid halt();\n\tprivate:\n\t\tmutable std::mutex _m;\n\t\tmutable std::condition_variable _cv;\n\t\tbool _go;\n\t\tstd::atomic<bool> _halt;\n\t};\n\n\tvoid thread_latch::wait() const\n\t{\n\t\tstd::unique_lock<std::mutex> lock(_m);\n\t\twhile (!_go)\n\t\t{\n\t\t\t_cv.wait(lock);\n\t\t}\n\t}\n\n\tvoid thread_latch::release()\n\t{\n\t\tconst std::lock_guard<std::mutex> lock(_m);\n\t\t_go = true;\n\t\t_cv.notify_all();\n\t}\n\n\tbool thread_latch::halted() const\n\t{\n\t\treturn _halt;\n\t}\n\n\tvoid thread_latch::halt()\n\t{\n\t\t_halt = true;\n\t}\n\n\tclass thread_group\n\t{\n\tpublic:\n\t\tthread_group(const thread_latch &latch, const unsigned n);\n\t\tvoid start(const std::function<void(void)> f);\n\t\tuint64_t join();\n\tprivate:\n\t\tvoid run();\n\t\tconst thread_latch &_latch;\n\t\tconst unsigned _n;\n\t\tstd::atomic<uint64_t> _count;\n\t\tstd::function<void(void)> _f;\n\t\tstd::vector<std::thread> _ths;\n\t};\n\n\tthread_group::thread_group(const thread_latch &latch, const unsigned n):\n\t\t_latch(latch), _n(n), _count(0)\n\t{\n\t}\n\n\tvoid thread_group::start(const std::function<void(void)> f)\n\t{\n\t\t_f = std::move(f);\n\t\tfor (auto i = _n; 0 < i--;)\n\t\t{\n\t\t\t_ths.push_back(std::thread(&thread_group::run, this));\n\t\t}\n\t}\n\n\tuint64_t thread_group::join()\n\t{\n\t\tfor (auto &th : _ths)\n\t\t{\n\t\t\tth.join();\n\t\t}\n\t\t_ths.clear();\n\t\treturn _count;\n\t}\n\n\tvoid thread_group::run()\n\t{\n\t\tuint64_t count = 0;\n\t\twhile (!_latch.halted())\n\t\t{\n\t\t\t_f();\n\t\t\t++count;\n\t\t}\n\t\t_count += count;\n\t}\n\n\tclass bench\n\t{\n\tpublic:\n\t\tbench() {}\n\t\tvoid setup(const std::function<void(void)> f);\n\t\tunsigned run(const unsigned n, const unsigned seconds);\n\tprivate:\n\t\tstd::function<void(void)> _f;\n\t};\n\n\tvoid bench::setup(const std::function<void(void)> f)\n\t{\n\t\t_f = std::move(f);\n\t}\n\n\tunsigned bench::run(const unsigned n, const unsigned seconds)\n\t{\n\t\tthread_latch latch;\n\t\tthread_group tg(latch, n);\n\t\ttg.start(_f);\n\t\tlatch.release();\n\t\tstd::this_thread::sleep_for(std::chrono::seconds(seconds));\n\t\tlatch.halt();\n\t\treturn tg.join();\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tXLOG_INIT();\n\tunsigned n = 1;\n\tif (1 < argc)\n\t{\n\t\tn = std::stoi(argv[1]);\n\t\tif (n <= 0 || 99 < n)\n\t\t{\n\t\t\tfprintf(stderr, \"Bad thread count (%u).\\n\", n);\n\t\t\treturn -1;\n\t\t}\n\t}\n\tunsigned seconds = 1;\n\tif (2 < argc)\n\t{\n\t\tseconds = std::stoi(argv[2]);\n\t\tif (seconds <= 0 || 60*60 < seconds)\n\t\t{\n\t\t\tfprintf(stderr, \"Bad duration (%u).\\n\", seconds);\n\t\t\treturn -1;\n\t\t}\n\t}\n\tbench b;\n\tb.setup([](){\n\t\tXLOG_STATEMENT();\n\t});\n\tconst uint64_t k = b.run(n, seconds);\n\tfprintf(stdout, \"%\" PRIu64 \"\\n\", static_cast<uint64_t>(k));\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/perf/test_switch.h",
    "content": "#pragma once\n\n#define TEST_LIBRARY_ID_zf_log 1\n#define TEST_LIBRARY_ID_spdlog 2\n#define TEST_LIBRARY_ID_easylog 3\n#define TEST_LIBRARY_ID_g3log 4\n#define TEST_LIBRARY_ID_glog 5\n\n#define _CONCAT(a, b) a##b\n#define CONCAT(a, b) _CONCAT(a, b)\n\n#if TEST_LIBRARY_ID_zf_log == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)\n\t#define TEST_LIBRARY_ZF_LOG\n#elif TEST_LIBRARY_ID_spdlog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)\n\t#define TEST_LIBRARY_SPDLOG\n#elif TEST_LIBRARY_ID_easylog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)\n\t#define TEST_LIBRARY_EASYLOG\n#elif TEST_LIBRARY_ID_g3log == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)\n\t#define TEST_LIBRARY_G3LOG\n#elif TEST_LIBRARY_ID_glog == CONCAT(TEST_LIBRARY_ID_, TEST_LIBRARY)\n\t#define TEST_LIBRARY_GLOG\n#else\n\t#error Unknown test library name\n#endif\n\n#define XLOG_STRING_LITERAL \"A random string\"\n#define XLOG_INT_LITERAL 42\n/* It's important that values are not const. Otherwise compilers will be able\n * to optimize out things that we care about.\n */\nextern const char *XLOG_STRING_VALUE;\nextern int XLOG_INT_VALUE;\n#ifndef TEST_SWITCH_MODULE\n\tconst char *XLOG_STRING_VALUE = XLOG_STRING_LITERAL;\n\tint XLOG_INT_VALUE = XLOG_INT_LITERAL;\n#endif\n#ifdef TEST_FORMAT_SLOW_FUNC\n\t#include <chrono>\n\t#include <thread>\n\tstatic int XLOG_SLOW_FUNC()\n\t{\n\t\tstd::this_thread::sleep_for(std::chrono::milliseconds(1));\n\t\treturn (int)std::hash<std::thread::id>()(std::this_thread::get_id());\n\t}\n#endif\n\n#define XLOG_MESSAGE_STR_LITERAL_PRINTF XLOG_STRING_LITERAL\n#define XLOG_MESSAGE_STR_LITERAL_CPPFMT XLOG_STRING_LITERAL\n#define XLOG_MESSAGE_STR_LITERAL_STREAM XLOG_STRING_LITERAL\n\n#define XLOG_MESSAGE_3INT_VALUES_PRINTF \\\n\t\t\"vA: %i, vB: %i, vC: %i\", \\\n\t\tXLOG_INT_VALUE, XLOG_INT_VALUE, XLOG_INT_VALUE\n#define XLOG_MESSAGE_3INT_VALUES_CPPFMT \\\n\t\t\"vA: {}, vB: {}, vC: {}\", \\\n\t\tXLOG_INT_VALUE, XLOG_INT_VALUE, XLOG_INT_VALUE\n#define XLOG_MESSAGE_3INT_VALUES_STREAM \\\n\t\t\"vA: \" << XLOG_INT_VALUE << \", vB: \" << XLOG_INT_VALUE << \\\n\t\t\", vC: \" << XLOG_INT_VALUE\n\n#define XLOG_MESSAGE_SLOW_FUNC_PRINTF \"%i\", XLOG_SLOW_FUNC()\n#define XLOG_MESSAGE_SLOW_FUNC_CPPFMT \"{}\", XLOG_SLOW_FUNC()\n#define XLOG_MESSAGE_SLOW_FUNC_STREAM XLOG_SLOW_FUNC()\n\n#ifdef TEST_LIBRARY_ZF_LOG\n\t#include <zf_log.h>\n\t#ifdef TEST_NULL_SINK\n\t\t#define _XLOG_INIT_SINK() \\\n\t\t\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, \\\n\t\t\t\t\t\t\t\t[](const zf_log_message *, void *){})\n\t#else\n\t\t#define _XLOG_INIT_SINK()\n\t#endif\n\t#ifdef TEST_LOG_OFF\n\t\t#define _XLOG_INIT_LEVEL() \\\n\t\t\tzf_log_set_output_level(ZF_LOG_ERROR)\n\t#else\n\t\t#define _XLOG_INIT_LEVEL()\n\t#endif\n\tstatic void XLOG_INIT()\n\t{\n\t\t_XLOG_INIT_SINK();\n\t\t_XLOG_INIT_LEVEL();\n\t}\n\n\t#if defined(TEST_FORMAT_INTS)\n\t\t#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_3INT_VALUES_PRINTF)\n\t#elif defined(TEST_FORMAT_SLOW_FUNC)\n\t\t#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_SLOW_FUNC_PRINTF)\n\t#else\n\t\t#define XLOG_STATEMENT() ZF_LOGI(XLOG_MESSAGE_STR_LITERAL_PRINTF)\n\t#endif\n#endif\n\n#ifdef TEST_LIBRARY_SPDLOG\n\t#include <spdlog/spdlog.h>\n\textern const std::shared_ptr<spdlog::logger> g_logger;\n\t#ifdef TEST_NULL_SINK\n\t\tclass null_sink: public spdlog::sinks::sink\n\t\t{\n\t\tpublic:\n\t\t\tvoid log(const spdlog::details::log_msg &) override {}\n\t\t\tvoid flush() override {}\n\t\t};\n\t\t#ifndef TEST_SWITCH_MODULE\n\t\t\tconst std::shared_ptr<spdlog::logger> g_logger = spdlog::create<null_sink>(\"null\");\n\t\t#endif\n\t#else\n\t\t#ifndef TEST_SWITCH_MODULE\n\t\t\tconst std::shared_ptr<spdlog::logger> g_logger = spdlog::stderr_logger_st(\"stderr\");\n\t\t#endif\n\t#endif\n\t#ifdef TEST_LOG_OFF\n\t\t#define _XLOG_INIT_LEVEL() spdlog::set_level(spdlog::level::err)\n\t#else\n\t\t#define _XLOG_INIT_LEVEL()\n\t#endif\n\tstatic void XLOG_INIT()\n\t{\n\t\t_XLOG_INIT_LEVEL();\n\t}\n\n\t#if defined(TEST_FORMAT_INTS)\n\t\t#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_3INT_VALUES_CPPFMT)\n\t#elif defined(TEST_FORMAT_SLOW_FUNC)\n\t\t#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_SLOW_FUNC_CPPFMT)\n\t#else\n\t\t#define XLOG_STATEMENT() g_logger->info(XLOG_MESSAGE_STR_LITERAL_CPPFMT)\n\t#endif\n#endif\n\n#ifdef TEST_LIBRARY_EASYLOG\n\t#ifdef TEST_NULL_SINK\n\t\tclass null_stream {\n\t\tpublic:\n\t\t\ttemplate<typename T>\n\t\t\tnull_stream &operator<<(T) { return *this; }\n\t\t\tnull_stream &operator<<(std::ostream& (*)(std::ostream&)) { return *this; }\n\t\t};\n\t\textern null_stream g_null;\n\t\t#ifndef TEST_SWITCH_MODULE\n\t\t\tnull_stream g_null;\n\t\t#endif\n\t\t#define ELPP_CUSTOM_COUT g_null\n\t\t#define _XLOG_INIT_SINK() \\\n\t\t\tel::Loggers::reconfigureAllLoggers(el::ConfigurationType::ToFile, \"false\")\n\t#else\n\t\t#define _XLOG_INIT_SINK()\n\t#endif\n\t#ifdef TEST_LOG_OFF\n\t\t#define _XLOG_INIT_LEVEL() \\\n\t\t\tel::Loggers::reconfigureAllLoggers(el::ConfigurationType::Enabled, \"false\")\n\t#else\n\t\t#define _XLOG_INIT_LEVEL()\n\t#endif\n\t#define ELPP_THREAD_SAFE\n\t#include <easylogging++.h>\n\t#ifndef TEST_SWITCH_MODULE\n\t\tINITIALIZE_EASYLOGGINGPP\n\t#endif\n\tstatic void XLOG_INIT()\n\t{\n\t\t_XLOG_INIT_SINK();\n\t\t_XLOG_INIT_LEVEL();\n\t}\n\n\n\t#if defined(TEST_FORMAT_INTS)\n\t\t#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_3INT_VALUES_STREAM\n\t#elif defined(TEST_FORMAT_SLOW_FUNC)\n\t\t#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_SLOW_FUNC_STREAM\n\t#else\n\t\t#define XLOG_STATEMENT() LOG(INFO) << XLOG_MESSAGE_STR_LITERAL_STREAM\n\t#endif\n#endif\n\n#ifdef TEST_LIBRARY_G3LOG\n\t#include <g3log/g3log.hpp>\n\t#include <g3log/logworker.hpp>\n\t#ifdef TEST_NULL_SINK\n\t\tclass null_sink\n\t\t{\n\t\tpublic:\n\t\t\tvoid log(const std::string) {}\n\t\t};\n\t\t#define _XLOG_INIT_SINK() \\\n\t\t\tauto worker = g3::LogWorker::createLogWorker(); \\\n\t\t\tg3::initializeLogging(worker.get()); \\\n\t\t\tworker->addSink(std::unique_ptr<null_sink>(new null_sink), &null_sink::log);\n\t#else\n\t\t#define _XLOG_INIT_SINK() \\\n\t\t\tauto worker = g3::LogWorker::createLogWorker(); \\\n\t\t\tg3::initializeLogging(worker.get()); \\\n\t\t\tworker->addDefaultLogger(\"g3log\", \"g3log.log\");\n\t#endif\n\t#ifdef TEST_LOG_OFF\n\t\t#ifndef G3_DYNAMIC_LOGGING\n\t\t\t#error g3log must be built with G3_DYNAMIC_LOGGING defined\n\t\t#endif\n\t\t#define _XLOG_INIT_LEVEL() \\\n\t\t\tg3::only_change_at_initialization::setLogLevel(INFO, false)\n\t#else\n\t\t#define _XLOG_INIT_LEVEL()\n\t#endif\n\tstatic void XLOG_INIT()\n\t{\n\t\t_XLOG_INIT_SINK();\n\t\t_XLOG_INIT_LEVEL();\n\t}\n\n\t#if defined(TEST_FORMAT_INTS)\n\t\t#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_3INT_VALUES_PRINTF)\n\t#elif defined(TEST_FORMAT_SLOW_FUNC)\n\t\t#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_SLOW_FUNC_PRINTF)\n\t#else\n\t\t#define XLOG_STATEMENT() LOGF(INFO, XLOG_MESSAGE_STR_LITERAL_PRINTF)\n\t#endif\n#endif\n\n#ifdef TEST_LIBRARY_GLOG\n\t#include <glog/logging.h>\n\t#ifdef TEST_NULL_SINK\n\t\tclass null_sink: public google::LogSink\n\t\t{\n\t\tpublic:\n\t\t\tvoid send(google::LogSeverity, const char *, const char *, int,\n\t\t\t\t\t  const struct ::tm *, const char *, size_t) override {}\n\t\t\tvoid WaitTillSent() override {}\n\t\t};\n\t\textern null_sink g_sink;\n\t\t#ifndef TEST_SWITCH_MODULE\n\t\t\tnull_sink g_sink;\n\t\t#endif\n\t\t#define _XLOG_LOG(lvl) LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&g_sink, lvl)\n\t#else\n\t\t#define _XLOG_LOG(lvl) LOG(lvl)\n\t#endif\n\t#ifdef TEST_LOG_OFF\n\t\t#define _XLOG_INIT_LEVEL() FLAGS_minloglevel = google::ERROR\n\t#else\n\t\t#define _XLOG_INIT_LEVEL()\n\t#endif\n\tstatic void XLOG_INIT()\n\t{\n\t\tgoogle::InitGoogleLogging(\"glog\");\n\t\t_XLOG_INIT_LEVEL();\n\t}\n\n\t#if defined(TEST_FORMAT_INTS)\n\t\t#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_3INT_VALUES_STREAM\n\t#elif defined(TEST_FORMAT_SLOW_FUNC)\n\t\t#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_SLOW_FUNC_STREAM\n\t#else\n\t\t#define XLOG_STATEMENT() _XLOG_LOG(INFO) << XLOG_MESSAGE_STR_LITERAL_STREAM\n\t#endif\n#endif\n"
  },
  {
    "path": "tests/perf/time_it.py",
    "content": "#!/usr/bin/python\n\nimport sys\nimport time\nimport subprocess\nimport json\n\ndef usage(f, st):\n\tf.write(\"Usage:\\n\")\n\tf.write(\"    time_it.py file utility [argument ...]\\n\\n\")\n\tf.write(\"Writes running time of utility into file.\\n\")\n\treturn st\n\ndef main(argv):\n\tif 3 > len(argv):\n\t\treturn usage(sys.stderr, -1)\n\tt = time.time()\n\tret = subprocess.call(argv[2:])\n\tt = time.time() - t\n\tif 0 == ret:\n\t\twith open(argv[1], \"w\") as f:\n\t\t\tjson.dump({\"dt\":t}, f)\n\treturn ret\n\nif __name__ == \"__main__\":\n\tsys.exit(main(sys.argv))\n"
  },
  {
    "path": "tests/test_aux_spec.c",
    "content": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic const zf_log_spec g_spec =\n{\n\tZF_LOG_GLOBAL_FORMAT,\n\tZF_LOG_GLOBAL_OUTPUT\n};\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)msg; (void)arg;\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\tZF_LOGI_AUX(&g_spec, \"aux log, argc=%i\", argc);\n\tZF_LOGI_MEM_AUX(&g_spec, argv, argc * sizeof(*argv), \"aux log, argv pointers:\");\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_builtin_output_facilities.c",
    "content": "#if defined(_WIN32) || defined(_WIN64)\n\t#define ZF_LOG_USE_DEBUGSTRING\n#endif\n#if defined(__APPLE__) && defined(__MACH__)\n\t#define ZF_LOG_USE_NSLOG\n#endif\n#if defined(__ANDROID__)\n\t#define ZF_LOG_USE_ANDROID_LOG\n#endif\n#include <zf_log.c>\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\t/* Testing compilation only for now. */\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_call_site_size_censoring.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\n#define LOG_SOME_ONCE \\\n\tZF_LOG_SECRET(ZF_LOGI(\"Lorem ipsum dolor sit amet\")); \\\n\ttime(0); \\\n\nstatic void log_some()\n{\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tlog_some();\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_call_site_size_conditional.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\n#if TEST_CONDITION\n\t#define CONDITION 1 < 2\n#else\n\t#define CONDITION 1 > 2\n#endif\n\n#define LOG_SOME_ONCE \\\n\tZF_LOG_IF(CONDITION, ZF_LOGI(\"Lorem ipsum dolor sit amet\")); \\\n\ttime(0); \\\n\nstatic void log_some()\n{\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n\tLOG_SOME_ONCE\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tlog_some();\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_call_site_size_fmt_args.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\nint g_int1;\nint g_int2;\nchar *g_str1;\nchar *g_str2;\nvoid *g_p1;\nvoid *g_p2;\n\nstatic void log_some()\n{\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n\tZF_LOGI(\"%i-%i/%s-%s/%p-%p\", g_int1, g_int2, g_str1, g_str2, g_p1, g_p2);\n\ttime(0);\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tlog_some();\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_call_site_size_msg_only.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.h>\n#include <time.h>\n\nstatic void log_some()\n{\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n\tZF_LOGI(\"Lorem ipsum dolor sit amet\");\n\ttime(0);\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tlog_some();\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_censoring.c",
    "content": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic unsigned g_logged = 0;\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)msg; (void)arg;\n\t++g_logged;\n}\n\nstatic unsigned was_logged()\n{\n\tconst unsigned logged = g_logged;\n\tg_logged = 0;\n\treturn logged;\n}\n\nstatic void some_function_0()\n{\n\t++g_logged;\n}\n\nstatic void some_function_1(const unsigned d)\n{\n\tassert(0 < d);\n\tg_logged += d;\n}\n\n#if TEST_LOG_SECRETS\n\t#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), (n))\n#else\n\t#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), 0)\n#endif\n\nstatic void test_censoring()\n{\n\tconst char name[] = \"Orion\";\n\tconst char address[] = \"Space\";\n\tconst char cipher[] = \"Secret\";\n\tconst zf_log_spec spec = {ZF_LOG_GLOBAL_FORMAT, ZF_LOG_GLOBAL_OUTPUT};\n\n\t#if ZF_LOG_SECRETS\n\t\tZF_LOGI(\"Customer name: %s\", name);\n\t\tZF_LOGI(\"Customer address: %s\", address);\n\t#endif\n\tEXPECTED_LINES(2);\n\n\tZF_LOG_SECRET(ZF_LOGI(\"Customer name: %s\", name));\n\tEXPECTED_LINES(1);\n\tZF_LOG_SECRET(ZF_LOGI_MEM(cipher, sizeof(cipher), \"Customer cipher:\"));\n\tEXPECTED_LINES(2);\n\tZF_LOG_SECRET(ZF_LOGI_AUX(&spec, \"Customer address: %s\", address));\n\tEXPECTED_LINES(1);\n\tZF_LOG_SECRET(ZF_LOGI_MEM_AUX(&spec, cipher, sizeof(cipher), \"Customer cipher:\"));\n\tEXPECTED_LINES(2);\n\n\tZF_LOG_SECRET(some_function_0());\n\tEXPECTED_LINES(1);\n\tZF_LOG_SECRET(some_function_1(42));\n\tEXPECTED_LINES(42);\n\n\tZF_LOGI(\"Must always log this\");\n\tTEST_VERIFY_EQUAL(was_logged(), 1);\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\n\tTEST_RUNNER_CREATE(argc, argv);\n\tTEST_EXECUTE(test_censoring());\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_compilation_cpp.cpp",
    "content": "#include <zf_log.c>\n\nnamespace\n{\n\tvoid mock_output_callback(const zf_log_message *, void *)\n\t{\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\tZF_LOGI(\"log from cpp, argc=%i\", argc);\n\tZF_LOGI_MEM(argv, argc * sizeof(*argv), \"log from cpp, argv pointers:\");\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_conditional.c",
    "content": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic unsigned g_logged = 0;\n/* Keep it extern (non-static), so compiler has less chances to optimize access\n * to this variable.\n */\nunsigned g_forty_two = 42;\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)msg; (void)arg;\n\t++g_logged;\n}\n\nstatic unsigned was_logged()\n{\n\tconst unsigned logged = g_logged;\n\tg_logged = 0;\n\treturn logged;\n}\n\nstatic unsigned forty_two()\n{\n\treturn g_forty_two;\n}\n\n#define EXPECTED_LINES(n) TEST_VERIFY_EQUAL(was_logged(), (n))\n\nstatic void test_conditional()\n{\n\tZF_LOG_IF(1 < 2, ZF_LOGI(\"True\"));\n\tEXPECTED_LINES(1);\n\tZF_LOG_IF(2 < 1, ZF_LOGI(\"False\"));\n\tEXPECTED_LINES(0);\n\n\tZF_LOG_IF(g_forty_two == 42, ZF_LOGI(\"True\"));\n\tEXPECTED_LINES(1);\n\tZF_LOG_IF(g_forty_two != 42, ZF_LOGI(\"False\"));\n\tEXPECTED_LINES(0);\n\n\tZF_LOG_IF(g_forty_two == 42, ZF_LOGI(\"True\"));\n\tEXPECTED_LINES(1);\n\tZF_LOG_IF(g_forty_two != 42, ZF_LOGI(\"False\"));\n\tEXPECTED_LINES(0);\n\n\tZF_LOG_IF(forty_two() == 42, ZF_LOGI(\"True\"));\n\tEXPECTED_LINES(1);\n\tZF_LOG_IF(forty_two() != 42, ZF_LOGI(\"False\"));\n\tEXPECTED_LINES(0);\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\n\tTEST_RUNNER_CREATE(argc, argv);\n\tTEST_EXECUTE(test_conditional());\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_decoration.main.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#include <zf_log.c>\n#include <stdlib.h>\n#include <stdio.h>\n\nstatic int main_called;\n\nstatic void main_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\tif (strncmp(\"main\", msg->msg_b, (size_t)(msg->p - msg->msg_b)))\n\t{\n\t\tfprintf(stderr, \"incorrect message in main\\n\");\n\t\texit(1);\n\t}\n\t++main_called;\n}\n\nvoid test_module();\n\nvoid test_main()\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, main_output_callback);\n\tZF_LOGI(\"main\");\n\tif (!main_called)\n\t{\n\t\tfprintf(stderr, \"main callback was not called\\n\");\n\t\texit(1);\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, main_output_callback);\n\n\ttest_module();\n\ttest_main();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_decoration.module.c",
    "content": "#define ZF_LOG_LEVEL ZF_LOG_INFO\n#define ZF_LOG_LIBRARY_PREFIX module\n#include <zf_log.c>\n#include <stdlib.h>\n#include <stdio.h>\n\nstatic int module_called;\n\nstatic void module_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\tif (strncmp(\"module\", msg->msg_b, (size_t)(msg->p - msg->msg_b)))\n\t{\n\t\tfprintf(stderr, \"incorrect message in module\\n\");\n\t\texit(1);\n\t}\n\t++module_called;\n}\n\nvoid test_module()\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, module_output_callback);\n\tZF_LOGI(\"module\");\n\tif (!module_called)\n\t{\n\t\tfprintf(stderr, \"module callback was not called\\n\");\n\t\texit(1);\n\t}\n}\n"
  },
  {
    "path": "tests/test_externally_defined_state.c",
    "content": "#define ZF_LOG_EXTERN_TAG_PREFIX\n#define ZF_LOG_EXTERN_GLOBAL_FORMAT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n#include <zf_log.c>\n#include \"zf_test.h\"\n\nenum { MEM_WIDTH = 8 };\nstatic void mock_output_callback(const zf_log_message *msg, void *arg);\n\nZF_LOG_DEFINE_TAG_PREFIX = \"MOCK_PREFIX\";\nZF_LOG_DEFINE_GLOBAL_FORMAT =\n{\n\t0xc0defade\n};\nZF_LOG_DEFINE_GLOBAL_OUTPUT =\n{\n\t0xcafebabe,\n\t(void *)(ptrdiff_t)0xfafacaca,\n\tmock_output_callback\n};\nZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0xdeadbeef;\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)msg; (void)arg;\n}\n\nstatic void test_static_initialization()\n{\n\tTEST_VERIFY_TRUE(0 == strcmp(_zf_log_tag_prefix, \"MOCK_PREFIX\"));\n\tTEST_VERIFY_EQUAL(_zf_log_global_format.mem_width, 0xc0defade);\n\tTEST_VERIFY_EQUAL(_zf_log_global_output.mask, 0xcafebabe);\n\tTEST_VERIFY_EQUAL(_zf_log_global_output.arg, (void *)(ptrdiff_t)0xfafacaca);\n\tTEST_VERIFY_EQUAL(_zf_log_global_output.callback, mock_output_callback);\n\tTEST_VERIFY_EQUAL(_zf_log_global_output_lvl, (int)0xdeadbeef);\n\tTEST_VERIFY_EQUAL(ZF_LOG_GLOBAL_FORMAT, &_zf_log_global_format);\n\tTEST_VERIFY_EQUAL(ZF_LOG_GLOBAL_OUTPUT, &_zf_log_global_output);\n}\n\nint main(int argc, char *argv[])\n{\n\tTEST_RUNNER_CREATE(argc, argv);\n\n\tTEST_EXECUTE(test_static_initialization());\n\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_externally_defined_state_cpp.cpp",
    "content": "#define ZF_LOG_EXTERN_TAG_PREFIX\n#define ZF_LOG_EXTERN_GLOBAL_FORMAT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n#include <zf_log.c>\n\nZF_LOG_DEFINE_TAG_PREFIX = \"MAIN\";\nZF_LOG_DEFINE_GLOBAL_FORMAT = {32};\nZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};\nZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_INFO;\n\nnamespace\n{\n\tvoid mock_output_callback(const zf_log_message *, void *)\n\t{\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\tZF_LOGI(\"log from cpp, argc=%i\", argc);\n\tZF_LOGI_MEM(argv, argc * sizeof(*argv), \"log from cpp, argv pointers:\");\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_log_level_override.c",
    "content": "#define ZF_LOG_LEVEL 0\n#define ZF_LOG_OUTPUT_LEVEL g_output_level\n#include <zf_log.c>\n#include <zf_test.h>\n\nstatic const int c_levels[] =\n{\n\tZF_LOG_VERBOSE,\n\tZF_LOG_DEBUG,\n\tZF_LOG_INFO,\n\tZF_LOG_WARN,\n\tZF_LOG_ERROR,\n\tZF_LOG_FATAL,\n\tZF_LOG_NONE,\n};\n\nstatic int g_output_level = 0;\n\nstatic void test_level_checks()\n{\n\tfor (unsigned i = 0; _countof(c_levels) > i; ++i)\n\t{\n\t\t/* must not effect anything */\n\t\tzf_log_set_output_level(c_levels[i]);\n\t\tfor (unsigned j = 0; _countof(c_levels) > j; ++j)\n\t\t{\n\t\t\tg_output_level = c_levels[j];\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_VERBOSE, g_output_level <= ZF_LOG_VERBOSE);\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_DEBUG, g_output_level <= ZF_LOG_DEBUG);\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_INFO, g_output_level <= ZF_LOG_INFO);\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_WARN, g_output_level <= ZF_LOG_WARN);\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_ERROR, g_output_level <= ZF_LOG_ERROR);\n\t\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_FATAL, g_output_level <= ZF_LOG_FATAL);\n\t\t}\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tTEST_RUNNER_CREATE(argc, argv);\n\n\tTEST_EXECUTE(test_level_checks());\n\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_log_level_switches.c",
    "content": "#ifndef ZF_LOG_LEVEL\n\t#error ZF_LOG_LEVEL must be defined for this test\n#endif\n#include <zf_log.c>\n#include <zf_test.h>\n#include <string.h>\n#include <stdbool.h>\n\nstatic int g_output_lvl_used;\nstatic unsigned g_output_called;\nstatic unsigned g_arg_called;\nstatic char g_msg[1024];\nstatic unsigned g_msg_len;\n\nstatic const int c_levels[] =\n{\n\tZF_LOG_VERBOSE,\n\tZF_LOG_DEBUG,\n\tZF_LOG_INFO,\n\tZF_LOG_WARN,\n\tZF_LOG_ERROR,\n\tZF_LOG_FATAL,\n\tZF_LOG_NONE,\n};\n\nstatic void reset()\n{\n\tg_output_called = 0;\n\tg_arg_called = 0;\n\tzf_log_set_output_level(0);\n}\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\tg_output_lvl_used = msg->lvl;\n\tg_msg_len = (unsigned)(msg->p - msg->buf);\n\tmemcpy(g_msg, msg->buf, g_msg_len);\n\t++g_output_called;\n}\n\nstatic int get_arg()\n{\n\t++g_arg_called;\n\treturn 0;\n}\n\nstatic void test_current_level()\n{\n\treset();\n\tZF_LOGV(\"verbose log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_VERBOSE == g_output_lvl_used);\n\treset();\n\tZF_LOGD(\"debug log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_DEBUG == g_output_lvl_used);\n\treset();\n\tZF_LOGI(\"info log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_INFO);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_INFO == g_output_lvl_used);\n\treset();\n\tZF_LOGW(\"warning log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_WARN);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_WARN == g_output_lvl_used);\n\treset();\n\tZF_LOGE(\"error log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_ERROR);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_ERROR == g_output_lvl_used);\n\treset();\n\tZF_LOGF(\"fatal log\");\n\tTEST_VERIFY_EQUAL(1 == g_output_called, ZF_LOG_LEVEL <= ZF_LOG_FATAL);\n\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_FATAL == g_output_lvl_used);\n}\n\nstatic void test_output_level()\n{\n\tfor (unsigned i = 0; _countof(c_levels) > i; ++i)\n\t{\n\t\tconst int lvl = c_levels[i];\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGV(\"verbose log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_VERBOSE == g_output_lvl_used);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGD(\"debug log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_DEBUG == g_output_lvl_used);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGI(\"info log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_INFO == g_output_lvl_used);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGW(\"warn log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_WARN == g_output_lvl_used);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGE(\"error log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_ERROR == g_output_lvl_used);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGF(\"fatal log\");\n\t\tTEST_VERIFY_EQUAL(1 == g_output_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);\n\t\tTEST_VERIFY_TRUE(0 == g_output_called || ZF_LOG_FATAL == g_output_lvl_used);\n\t}\n}\n\nstatic void test_args_evaluation()\n{\n\treset();\n\tZF_LOGV(\"verbose log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);\n\treset();\n\tZF_LOGD(\"debug log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);\n\treset();\n\tZF_LOGI(\"info log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_INFO);\n\treset();\n\tZF_LOGW(\"warning log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_WARN);\n\treset();\n\tZF_LOGE(\"error log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_ERROR);\n\treset();\n\tZF_LOGF(\"fatal log: %i\", get_arg());\n\tTEST_VERIFY_EQUAL(1 == g_arg_called, ZF_LOG_LEVEL <= ZF_LOG_FATAL);\n\n\tfor (unsigned i = 0; _countof(c_levels) > i; ++i)\n\t{\n\t\tconst int lvl = c_levels[i];\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGV(\"verbose log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGD(\"debug log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGI(\"info log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGW(\"warn log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGE(\"error log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tZF_LOGF(\"fatal log: %i\", get_arg());\n\t\tTEST_VERIFY_EQUAL(1 == g_arg_called,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);\n\t}\n}\n\nstatic void test_level_checks()\n{\n\treset();\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_VERBOSE, ZF_LOG_LEVEL <= ZF_LOG_VERBOSE);\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_DEBUG, ZF_LOG_LEVEL <= ZF_LOG_DEBUG);\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_INFO, ZF_LOG_LEVEL <= ZF_LOG_INFO);\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_WARN, ZF_LOG_LEVEL <= ZF_LOG_WARN);\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_ERROR, ZF_LOG_LEVEL <= ZF_LOG_ERROR);\n\tTEST_VERIFY_EQUAL(!!ZF_LOG_ENABLED_FATAL, ZF_LOG_LEVEL <= ZF_LOG_FATAL);\n\n\tfor (unsigned i = 0; _countof(c_levels) > i; ++i)\n\t{\n\t\tconst int lvl = c_levels[i];\n\t\treset();\n\t\tzf_log_set_output_level(lvl);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_VERBOSE,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_VERBOSE && lvl <= ZF_LOG_VERBOSE);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_DEBUG,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_DEBUG && lvl <= ZF_LOG_DEBUG);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_INFO,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_INFO && lvl <= ZF_LOG_INFO);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_WARN,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_WARN && lvl <= ZF_LOG_WARN);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_ERROR,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_ERROR && lvl <= ZF_LOG_ERROR);\n\t\tTEST_VERIFY_EQUAL(!!ZF_LOG_ON_FATAL,\n\t\t\t\t\t\t  ZF_LOG_LEVEL <= ZF_LOG_FATAL && lvl <= ZF_LOG_FATAL);\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\tTEST_RUNNER_CREATE(argc, argv);\n\n\tTEST_EXECUTE(test_current_level());\n\tTEST_EXECUTE(test_output_level());\n\tTEST_EXECUTE(test_args_evaluation());\n\tTEST_EXECUTE(test_level_checks());\n\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_log_message_content.c",
    "content": "#if defined(_WIN32) || defined(_WIN64)\n\t#define _CRT_NONSTDC_NO_WARNINGS\n#endif\n#define ZF_LOG_ANDROID_LOG 0\n#define ZF_LOG_BUF_SZ 128\n#define ZF_LOG_MEM_WIDTH 16\n#define ZF_LOG_INSTRUMENTED 1\n#define ZF_LOG_LEVEL ZF_LOG_INFO\n#define ZF_LOG_TAG \"TAG\"\n#include <zf_log.c>\n#include <stddef.h>\n#include <stdio.h>\n#include <string.h>\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(snprintf)\n    #define snprintf(buf, len, ...) _snprintf_s(buf, len, _TRUNCATE, __VA_ARGS__)\n#endif\n\n#define MESSAGE_EXPECTED_PRINTF_FMT__             \"\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__YEAR         \"2016\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__MONTH        \"12\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__DAY          \"23\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__HOUR         \"12\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__MINUTE       \"34\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__SECOND       \"56\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__MILLISECOND  \"789\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__PID          \" 9876\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__TID          \" 5432\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__LEVEL        \"I\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__TAG(ps, ts)  \"prefix\" ps \"TAG\" ts\n#define MESSAGE_EXPECTED_PRINTF_FMT__FUNCTION     \"function\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__FILENAME     \"file\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__FILELINE     \"42\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__S(s)         s\n#define MESSAGE_EXPECTED_PRINTF_FMT__F_INIT(expr) \"\"\n#define MESSAGE_EXPECTED_PRINTF_FMT__F_UINT(w, v) \"%\" #w \"u\"\n#define MESSAGE_EXPECTED_PRINTF_FMT(field) \\\n\t_PP_CONCAT_3(MESSAGE_EXPECTED_PRINTF_FMT_, _, field)\n\n#define MESSAGE_EXPECTED_PRINTF_VAL__\n#define MESSAGE_EXPECTED_PRINTF_VAL__YEAR\n#define MESSAGE_EXPECTED_PRINTF_VAL__MONTH\n#define MESSAGE_EXPECTED_PRINTF_VAL__DAY\n#define MESSAGE_EXPECTED_PRINTF_VAL__HOUR\n#define MESSAGE_EXPECTED_PRINTF_VAL__MINUTE\n#define MESSAGE_EXPECTED_PRINTF_VAL__SECOND\n#define MESSAGE_EXPECTED_PRINTF_VAL__MILLISECOND\n#define MESSAGE_EXPECTED_PRINTF_VAL__PID\n#define MESSAGE_EXPECTED_PRINTF_VAL__TID\n#define MESSAGE_EXPECTED_PRINTF_VAL__LEVEL\n#define MESSAGE_EXPECTED_PRINTF_VAL__TAG(ps, ts)\n#define MESSAGE_EXPECTED_PRINTF_VAL__FUNCTION\n#define MESSAGE_EXPECTED_PRINTF_VAL__FILENAME\n#define MESSAGE_EXPECTED_PRINTF_VAL__FILELINE\n#define MESSAGE_EXPECTED_PRINTF_VAL__S(s)\n#define MESSAGE_EXPECTED_PRINTF_VAL__F_INIT(expr)\n#define MESSAGE_EXPECTED_PRINTF_VAL__F_UINT(w, v) ,v\n#define MESSAGE_EXPECTED_PRINTF_VAL(field) \\\n\t_PP_CONCAT_3(MESSAGE_EXPECTED_PRINTF_VAL_, _, field)\n\n#define MESSAGE_EXPECTED_PRINTF_FMTS \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_CTX_FORMAT) \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_TAG_FORMAT) \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_FMT, ZF_LOG_MESSAGE_SRC_FORMAT)\n\n#define MESSAGE_EXPECTED_PRINTF_VALS \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_CTX_FORMAT) \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_TAG_FORMAT) \\\n\t_PP_MAP(MESSAGE_EXPECTED_PRINTF_VAL, ZF_LOG_MESSAGE_SRC_FORMAT)\n\nstatic const char c_test_fmt[] =\n\t\"Lorem ipsum dolor sit amet.\";\nstatic const char c_test_mem[] =\n\t\"Here's to the crazy ones.\";\n\nstatic const char *c_msg_expected_lines[1];\nstatic const char *c_mem_expected_lines[3];\n\n#define MAX_LINES 4\nstatic char g_lines[MAX_LINES][ZF_LOG_BUF_SZ];\nstatic size_t g_len[MAX_LINES];\nstatic size_t g_null_pos[MAX_LINES];\nstatic size_t g_line;\n\nstatic size_t memchk(const void *const b, const int c, const size_t sz)\n{\n\tconst unsigned char v = (unsigned char)c;\n\tconst unsigned char *const s = (const unsigned char *)b;\n\tconst unsigned char *const e = s + sz;\n\tconst unsigned char *p = s;\n\tfor (;p != e && v == *p; ++p) {}\n\treturn (size_t)(p - s);\n}\n\nstatic size_t common_prefix(const char *const s1, const size_t s1_len,\n\t\t\t\t\t\t\tconst char *const s2, const size_t s2_len)\n{\n\tconst char *const e1 = s1 + s1_len;\n\tconst char *const e2 = s2 + s2_len;\n\tconst char *c1 = s1, *c2 = s2;\n\tfor (;e1 != c1 && e2 != c2 && *c1 == *c2; ++c1, ++c2) {}\n\treturn (size_t)(c1 - s1);\n}\n\nstatic void reset()\n{\n\tg_buf_sz = ZF_LOG_BUF_SZ;\n\tfor (size_t i = 0; MAX_LINES > i; ++i)\n\t{\n\t\tmemset(g_lines[i], -1, ZF_LOG_BUF_SZ);\n\t\tg_len[i] = 0;\n\t\tg_null_pos[i] = 0;\n\t}\n\tg_line = 0;\n}\n\nstatic void mock_time_callback(struct tm *const tm, unsigned *const msec)\n{\n\tmemset(tm, 0, sizeof(*tm));\n\ttm->tm_sec = 56;\n\ttm->tm_min = 34;\n\ttm->tm_hour = 12;\n\ttm->tm_mday = 23;\n\ttm->tm_mon = 11;\n\ttm->tm_year = 2016 - 1900;\n\t*msec = 789;\n}\n\nstatic void mock_pid_callback(int *const pid, int *const tid)\n{\n\t*pid = 9876;\n\t*tid = 5432;\n}\n\nstatic void mock_buffer_callback(zf_log_message *msg, char *buf)\n{\n\tmemset(buf, -1, ZF_LOG_BUF_SZ);\n\tbuffer_callback(msg, buf);\n}\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\tconst size_t i = g_line++;\n\tif (MAX_LINES <= i)\n\t{\n\t\tfprintf(stderr, \"too many lines produced\\n\");\n\t\texit(1);\n\t}\n\tchar *const line = g_lines[i];\n\tmemcpy(line, msg->buf, ZF_LOG_BUF_SZ);\n\tconst size_t len = (size_t)(msg->p - msg->buf);\n\tsize_t null_pos;\n\tfor\t(null_pos = 0; len > null_pos && 0 != line[null_pos]; ++null_pos) {}\n\tg_len[i] = len;\n\tg_null_pos[i] = null_pos;\n}\n\nstatic void verify_log_output(const size_t buf_sz,\n\t\t\t\t\t\t\t  const char *const expected[],\n\t\t\t\t\t\t\t  const size_t expected_n)\n{\n\tconst size_t modifiable = buf_sz + 1;\n\tconst size_t unmodifiable = ZF_LOG_BUF_SZ - modifiable;\n\tif (g_line > expected_n)\n\t{\n\t\tfprintf(stderr, \"Lines produced: actual=%u, expected=<%u\\n\",\n\t\t\t\t(unsigned)g_line, (unsigned)expected_n);\n\t\texit(1);\n\t}\n\tsize_t complete_lines = 0;\n\tfor (size_t i = 0; g_line > i; ++i)\n\t{\n\t\tconst char *const line = g_lines[i];\n\t\tconst size_t line_len = strlen(expected[i]);\n\t\tconst size_t untouched = memchk(line + modifiable, -1, unmodifiable);\n\t\tconst size_t match = common_prefix(expected[i], line_len,\n\t\t\t\t\t\t\t\t\t\t   line, g_len[i]);\n\t\tif (untouched != unmodifiable)\n\t\t{\n\t\t\tfprintf(stderr, \"Untouched bytes: actual=%u, expected=%u\\n\",\n\t\t\t\t\t(unsigned)untouched, (unsigned)unmodifiable);\n\t\t\texit(1);\n\t\t}\n\t\tif (g_null_pos[i] != g_len[i])\n\t\t{\n\t\t\tfprintf(stderr, \"Null position: actual=%u, expected=%u\\n\",\n\t\t\t\t\t(unsigned)g_null_pos[i], (unsigned)g_len[i]);\n\t\t\texit(1);\n\t\t}\n\t\tif (match < g_len[i])\n\t\t{\n\t\t\tfprintf(stderr, \"Line partial match: actual=%u, expected=>%u\\n\",\n\t\t\t\t\t(unsigned)match, (unsigned)g_len[i]);\n\t\t\texit(1);\n\t\t}\n\t\tif (line_len <= buf_sz)\n\t\t{\n\t\t\t++complete_lines;\n\t\t\tif (line_len <= buf_sz && match != g_len[i])\n\t\t\t{\n\t\t\t\tfprintf(stderr, \"Line complete match: actual=%u, expected=%u\\n\",\n\t\t\t\t\t\t(unsigned)match, (unsigned)g_len[i]);\n\t\t\t\texit(1);\n\t\t\t}\n\t\t}\n\t}\n\tif (expected_n == complete_lines && g_line != expected_n)\n\t{\n\t\tfprintf(stderr, \"Complete lines produced: actual=%u, expected=<%u\\n\",\n\t\t\t\t(unsigned)g_line, (unsigned)expected_n);\n\t\texit(1);\n\t}\n}\n\nstatic void test_msg_output()\n{\n\tfor (unsigned buf_sz = 0; ZF_LOG_BUF_SZ - ZF_LOG_EOL_SZ >= buf_sz; ++buf_sz)\n\t{\n\t\treset();\n\t\tg_buf_sz = buf_sz;\n\t\t_zf_log_write_d(\"function\", \"file\", 42, ZF_LOG_INFO, ZF_LOG_TAG,\n\t\t\t\t\t\tc_test_fmt);\n\t\tverify_log_output(buf_sz,\n\t\t\t\t\t\t  c_msg_expected_lines, _countof(c_msg_expected_lines));\n\t}\n}\n\nstatic void test_mem_output()\n{\n\tfor (unsigned buf_sz = 0; ZF_LOG_BUF_SZ - ZF_LOG_EOL_SZ >= buf_sz; ++buf_sz)\n\t{\n\t\treset();\n\t\tg_buf_sz = buf_sz;\n\t\t_zf_log_write_mem_d(\"function\", \"file\", 42, ZF_LOG_INFO, ZF_LOG_TAG,\n\t\t\t\t\t\t\tc_test_mem, sizeof(c_test_mem),\n\t\t\t\t\t\t\tc_test_fmt);\n\t\tverify_log_output(buf_sz,\n\t\t\t\t\t\t  c_mem_expected_lines, _countof(c_mem_expected_lines));\n\t}\n}\n\nstatic void init_expected_lines()\n{\n\tchar expected_header[256];\n\tchar line[512];\n\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_CTX_FORMAT)\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_TAG_FORMAT)\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_SRC_FORMAT)\n#if _ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_TAG_FORMAT) || \\\n\t_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_SRC_FORMAT)\n\tsnprintf(expected_header, sizeof(expected_header),\n\t\t\tMESSAGE_EXPECTED_PRINTF_FMTS\n\t\t\tMESSAGE_EXPECTED_PRINTF_VALS);\n#else\n\t*expected_header ='\\0';\n#endif\n\n\tsnprintf(line, sizeof(line), \"%s%s\", expected_header,\n\t\t\t \"Lorem ipsum dolor sit amet.\");\n\tc_msg_expected_lines[0] = strdup(line);\n\n\tsnprintf(line, sizeof(line), \"%s%s\", expected_header,\n\t\t\t \"Lorem ipsum dolor sit amet.\");\n\tc_mem_expected_lines[0] = strdup(line);\n\tsnprintf(line, sizeof(line), \"%s%s\", expected_header,\n\t\t\t \"48657265277320746f20746865206372  Here's to the cr\");\n\tc_mem_expected_lines[1] = strdup(line);\n\tsnprintf(line, sizeof(line), \"%s%s\", expected_header,\n\t\t\t \"617a79206f6e65732e00              azy ones.?\");\n\tc_mem_expected_lines[2] = strdup(line);\n}\n\nint main(int argc, char *argv[])\n{\n\t(void)argc; (void)argv;\n\tg_time_cb = mock_time_callback;\n\tg_pid_cb = mock_pid_callback;\n\tg_buffer_cb = mock_buffer_callback;\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\tzf_log_set_tag_prefix(\"prefix\");\n\n\tinit_expected_lines();\n\n\ttest_msg_output();\n\ttest_mem_output();\n\n\treturn 0;\n}\n"
  },
  {
    "path": "tests/test_private_parts.c",
    "content": "#include <zf_log.c>\n#include <zf_test.h>\n\nstatic char *strcopy_r(const char *s, char *e)\n{\n\te -= strlen(s) + 1;\n\tfor (char *p = e; 0 != (*p++ = *s++);) {}\n\treturn e;\n}\n\ntypedef struct put_padding_r_testcase\n{\n\tconst char *const s;\n\tconst unsigned w;\n\tconst char *const p;\n}\nput_padding_r_testcase;\n\nstatic const put_padding_r_testcase g_put_padding_r_testcases[] =\n{\n\t{\"\", 0, \"\"},\n\t{\"1\", 0, \"1\"},\n\t{\"123\", 0, \"123\"},\n\t{\"\", 3, \"---\"},\n\t{\"1\", 3, \"--1\"},\n\t{\"123\", 3, \"123\"},\n\t{\"1234\", 3, \"1234\"},\n};\n\nstatic void test_put_padding_r()\n{\n\tchar buf[16];\n\tchar *const e = buf + _countof(buf) - 1;\n\tchar *p;\n\tfor (unsigned i = 0; _countof(g_put_padding_r_testcases) > i; ++i)\n\t{\n\t\tconst put_padding_r_testcase *const tc = g_put_padding_r_testcases + i;\n\t\tp = strcopy_r(tc->s, e + 1);\n\t\tp = put_padding_r(tc->w, '-', p, e);\n\t\tTEST_VERIFY_TRUE_MSG(0 == strcmp(p, tc->p), \"i=%u\", i);\n\t}\n}\n\nint main(int argc, char *argv[])\n{\n\tTEST_RUNNER_CREATE(argc, argv);\n\n\tTEST_EXECUTE(test_put_padding_r());\n\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/test_source_location.c",
    "content": "#include <zf_log.c>\n#include <zf_test.h>\n#include <stdio.h>\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(snprintf)\n\t#define snprintf(buf, len, ...) _snprintf_s(buf, len, _TRUNCATE, __VA_ARGS__)\n#endif\n\nconst char *const c_filename = \"test_source_location.c\";\nstatic char g_srcloc_buf[ZF_LOG_BUF_SZ];\nstatic const char *g_srcloc;\n\nstatic char *trim(char *s)\n{\n\tchar *sb;\n\twhile (0 != *(sb = s) && ' ' == *s) ++s;\n\tchar *se;\n\twhile (0 != *(se = s) && ' ' != *s) ++s;\n\t*se = 0;\n\treturn sb;\n}\n\nstatic void mock_output_callback(const zf_log_message *msg, void *arg)\n{\n\t(void)arg;\n\tconst size_t len = msg->msg_b - msg->tag_e;\n\tmemcpy(g_srcloc_buf, msg->tag_e, len);\n\tg_srcloc_buf[len] = 0;\n\tg_srcloc = trim(g_srcloc_buf);\n}\n\nstatic void test_function()\n{\n\tconst unsigned line = __LINE__ + 1;\n\tZF_LOGI(\"test message\");\n\n\tchar expected[64];\n#if ZF_LOG_SRCLOC_NONE==TEST_SRCLOC\n\t(void)line;\n\t*expected = 0;\n#endif\n#if ZF_LOG_SRCLOC_SHORT==TEST_SRCLOC\n\tsnprintf(expected, sizeof(expected), \"@%s:%u\",\n\t\t\t c_filename, line);\n#endif\n#if ZF_LOG_SRCLOC_LONG==TEST_SRCLOC\n\tsnprintf(expected, sizeof(expected), \"%s@%s:%u\",\n\t\t\t _ZF_LOG_FUNCTION, c_filename, line);\n#endif\n\tTEST_VERIFY_EQUAL(strcmp(expected, g_srcloc), 0);\n}\n\nint main(int argc, char *argv[])\n{\n\tzf_log_set_output_v(ZF_LOG_PUT_STD, 0, mock_output_callback);\n\n\tTEST_RUNNER_CREATE(argc, argv);\n\tTEST_EXECUTE(test_function());\n\treturn TEST_RUNNER_EXIT_CODE();\n}\n"
  },
  {
    "path": "tests/zf_log.h.master",
    "content": "#pragma once\n\n#ifndef _ZF_LOG_H_\n#define _ZF_LOG_H_\n\n/* To detect incompatible changes you can define ZF_LOG_VERSION_REQUIRED to be\n * the current value of ZF_LOG_VERSION before including this file (or via\n * compiler command line):\n *\n *   #define ZF_LOG_VERSION_REQUIRED 4\n *   #include <zf_log.h>\n *\n * Compilation will fail when included file has different version.\n */\n#define ZF_LOG_VERSION 4\n#if defined(ZF_LOG_VERSION_REQUIRED)\n\t#if ZF_LOG_VERSION_REQUIRED != ZF_LOG_VERSION\n\t\t#error different zf_log version required\n\t#endif\n#endif\n\n/* Log level guideline:\n * - ZF_LOG_FATAL - happened something impossible and absolutely unexpected.\n *   Process can't continue and must be terminated.\n *   Example: division by zero, unexpected modifications from other thread.\n * - ZF_LOG_ERROR - happened something possible, but highly unexpected. The\n *   process is able to recover and continue execution.\n *   Example: out of memory (could also be FATAL if not handled properly).\n * - ZF_LOG_WARN - happened something that *usually* should not happen and\n *   significantly changes application behavior for some period of time.\n *   Example: configuration file not found, auth error.\n * - ZF_LOG_INFO - happened significant life cycle event or major state\n *   transition.\n *   Example: app started, user logged in.\n * - ZF_LOG_DEBUG - minimal set of events that could help to reconstruct the\n *   execution path. Usually disabled in release builds.\n * - ZF_LOG_VERBOSE - all other events. Usually disabled in release builds.\n *\n * *Ideally*, log file of debugged, well tested, production ready application\n * should be empty or very small. Choosing a right log level is as important as\n * providing short and self descriptive log message.\n */\n#define ZF_LOG_VERBOSE 1\n#define ZF_LOG_DEBUG   2\n#define ZF_LOG_INFO    3\n#define ZF_LOG_WARN    4\n#define ZF_LOG_ERROR   5\n#define ZF_LOG_FATAL   6\n#define ZF_LOG_NONE    0xFF\n\n/* \"Current\" log level is a compile time check and has no runtime overhead. Log\n * level that is below current log level it said to be \"disabled\". Otherwise,\n * it's \"enabled\". Log messages that are disabled has no runtime overhead - they\n * are converted to no-op by preprocessor and then eliminated by compiler.\n * Current log level is configured per compilation module (.c/.cpp/.m file) by\n * defining ZF_LOG_DEF_LEVEL or ZF_LOG_LEVEL. ZF_LOG_LEVEL has higer priority\n * and when defined overrides value provided by ZF_LOG_DEF_LEVEL.\n *\n * Common practice is to define default current log level with ZF_LOG_DEF_LEVEL\n * in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_LEVEL=ZF_LOG_INFO\n *\n * And when necessary to override it with ZF_LOG_LEVEL in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_LEVEL ZF_LOG_VERBOSE\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_LEVEL and ZF_LOG_LEVEL are undefined, then ZF_LOG_INFO\n * will be used for release builds (NDEBUG is defined) and ZF_LOG_DEBUG\n * otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_LEVEL)\n\t#define _ZF_LOG_LEVEL ZF_LOG_LEVEL\n#elif defined(ZF_LOG_DEF_LEVEL)\n\t#define _ZF_LOG_LEVEL ZF_LOG_DEF_LEVEL\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_LEVEL ZF_LOG_INFO\n\t#else\n\t\t#define _ZF_LOG_LEVEL ZF_LOG_DEBUG\n\t#endif\n#endif\n\n/* \"Output\" log level is a runtime check. When log level is below output log\n * level it said to be \"turned off\" (or just \"off\" for short). Otherwise it's\n * \"turned on\" (or just \"on\"). Log levels that were \"disabled\" (see\n * ZF_LOG_LEVEL and ZF_LOG_DEF_LEVEL) can't be \"turned on\", but \"enabled\" log\n * levels could be \"turned off\". Only messages with log level which is\n * \"turned on\" will reach output facility. All other messages will be ignored\n * (and their arguments will not be evaluated). Output log level is a global\n * property and configured per process using zf_log_set_output_level() function\n * which can be called at any time.\n *\n * Though in some cases it could be useful to configure output log level per\n * compilation module or per library. There are two ways to achieve that:\n * - Define ZF_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output\n *   log level.\n * - Copy zf_log.h and zf_log.c files into your library and build it with\n *   ZF_LOG_LIBRARY_PREFIX defined to library specific prefix. See\n *   ZF_LOG_LIBRARY_PREFIX for more details.\n *\n * When defined, ZF_LOG_OUTPUT_LEVEL must evaluate to integral value that\n * corresponds to desired output log level. Use it only when compilation module\n * is required to have output log level which is different from global output\n * log level set by zf_log_set_output_level() function. For other cases,\n * consider defining ZF_LOG_LEVEL or using zf_log_set_output_level() function.\n *\n * Example:\n *\n *   #define ZF_LOG_OUTPUT_LEVEL g_module_log_level\n *   #include <zf_log.h>\n *   static int g_module_log_level = ZF_LOG_INFO;\n *   static void foo() {\n *       ZF_LOGI(\"Will check g_module_log_level for output log level\");\n *   }\n *   void debug_log(bool on) {\n *       g_module_log_level = on? ZF_LOG_DEBUG: ZF_LOG_INFO;\n *   }\n *\n * Note on performance. This expression will be evaluated each time message is\n * logged (except when message log level is \"disabled\" - see ZF_LOG_LEVEL for\n * details). Keep this expression as simple as possible, otherwise it will not\n * only add runtime overhead, but also will increase size of call site (which\n * will result in larger executable). The prefered way is to use integer\n * variable (as in example above). If structure must be used, log_level field\n * must be the first field in this structure:\n *\n *   #define ZF_LOG_OUTPUT_LEVEL (g_config.log_level)\n *   #include <zf_log.h>\n *   struct config {\n *       int log_level;\n *       unsigned other_field;\n *       [...]\n *   };\n *   static config g_config = {ZF_LOG_INFO, 0, ...};\n *\n * This allows compiler to generate more compact load instruction (no need to\n * specify offset since it's zero). Calling a function to get output log level\n * is generaly a bad idea, since it will increase call site size and runtime\n * overhead even further.\n */\n#if defined(ZF_LOG_OUTPUT_LEVEL)\n\t#define _ZF_LOG_OUTPUT_LEVEL ZF_LOG_OUTPUT_LEVEL\n#else\n\t#define _ZF_LOG_OUTPUT_LEVEL _zf_log_global_output_lvl\n#endif\n\n/* \"Tag\" is a compound string that could be associated with a log message. It\n * consists of tag prefix and tag (both are optional).\n *\n * Tag prefix is a global property and configured per process using\n * zf_log_set_tag_prefix() function. Tag prefix identifies context in which\n * component or module is running (e.g. process name). For example, the same\n * library could be used in both client and server processes that work on the\n * same machine. Tag prefix could be used to easily distinguish between them.\n * For more details about tag prefix see zf_log_set_tag_prefix() function. Tag\n * prefix\n *\n * Tag identifies component or module. It is configured per compilation module\n * (.c/.cpp/.m file) by defining ZF_LOG_TAG or ZF_LOG_DEF_TAG. ZF_LOG_TAG has\n * higer priority and when defined overrides value provided by ZF_LOG_DEF_TAG.\n * When defined, value must evaluate to (const char *), so for strings double\n * quotes must be used.\n *\n * Default tag could be defined with ZF_LOG_DEF_TAG in build script (e.g.\n * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_TAG=\\\"MISC\\\"\n *\n * And when necessary could be overriden with ZF_LOG_TAG in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_TAG \"MAIN\"\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_TAG and ZF_LOG_TAG are undefined no tag will be added to\n * the log message (tag prefix still could be added though).\n *\n * Output example:\n *\n *   04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1\n *                                    |     |\n *                                    |     +- tag (e.g. module)\n *                                    +- tag prefix (e.g. process name)\n */\n#if defined(ZF_LOG_TAG)\n\t#define _ZF_LOG_TAG ZF_LOG_TAG\n#elif defined(ZF_LOG_DEF_TAG)\n\t#define _ZF_LOG_TAG ZF_LOG_DEF_TAG\n#else\n\t#define _ZF_LOG_TAG 0\n#endif\n\n/* Source location is part of a log line that describes location (function or\n * method name, file name and line number, e.g. \"runloop@main.cpp:68\") of a\n * log statement that produced it.\n * Source location formats are:\n * - ZF_LOG_SRCLOC_NONE - don't add source location to log line.\n * - ZF_LOG_SRCLOC_SHORT - add source location in short form (file and line\n *   number, e.g. \"@main.cpp:68\").\n * - ZF_LOG_SRCLOC_LONG - add source location in long form (function or method\n *   name, file and line number, e.g. \"runloop@main.cpp:68\").\n */\n#define ZF_LOG_SRCLOC_NONE  0\n#define ZF_LOG_SRCLOC_SHORT 1\n#define ZF_LOG_SRCLOC_LONG  2\n\n/* Source location format is configured per compilation module (.c/.cpp/.m\n * file) by defining ZF_LOG_DEF_SRCLOC or ZF_LOG_SRCLOC. ZF_LOG_SRCLOC has\n * higer priority and when defined overrides value provided by\n * ZF_LOG_DEF_SRCLOC.\n *\n * Common practice is to define default format with ZF_LOG_DEF_SRCLOC in\n * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_SRCLOC=ZF_LOG_SRCLOC_LONG\n *\n * And when necessary to override it with ZF_LOG_SRCLOC in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_SRCLOC and ZF_LOG_SRCLOC are undefined, then\n * ZF_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and\n * ZF_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_SRCLOC)\n\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC\n#elif defined(ZF_LOG_DEF_SRCLOC)\n\t#define _ZF_LOG_SRCLOC ZF_LOG_DEF_SRCLOC\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE\n\t#else\n\t\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_LONG\n\t#endif\n#endif\n#if ZF_LOG_SRCLOC_LONG == _ZF_LOG_SRCLOC\n\t#define _ZF_LOG_SRCLOC_FUNCTION _ZF_LOG_FUNCTION\n#else\n\t#define _ZF_LOG_SRCLOC_FUNCTION 0\n#endif\n\n/* Censoring provides conditional logging of secret information, also known as\n * Personally Identifiable Information (PII) or Sensitive Personal Information\n * (SPI). Censoring can be either enabled (ZF_LOG_CENSORED) or disabled\n * (ZF_LOG_UNCENSORED). When censoring is enabled, log statements marked as\n * \"secrets\" will be ignored and will have zero overhead (arguments also will\n * not be evaluated).\n */\n#define ZF_LOG_CENSORED   1\n#define ZF_LOG_UNCENSORED 0\n\n/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining\n * ZF_LOG_DEF_CENSORING or ZF_LOG_CENSORING. ZF_LOG_CENSORING has higer priority\n * and when defined overrides value provided by ZF_LOG_DEF_CENSORING.\n *\n * Common practice is to define default censoring with ZF_LOG_DEF_CENSORING in\n * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_CENSORING=ZF_LOG_CENSORED\n *\n * And when necessary to override it with ZF_LOG_CENSORING in .c/.cpp/.m files\n * before including zf_log.h (consider doing it only for debug purposes and be\n * very careful not to push such temporary changes to source control):\n *\n *   #define ZF_LOG_CENSORING ZF_LOG_UNCENSORED\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_CENSORING and ZF_LOG_CENSORING are undefined, then\n * ZF_LOG_CENSORED will be used for release builds (NDEBUG is defined) and\n * ZF_LOG_UNCENSORED otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_CENSORING)\n\t#define _ZF_LOG_CENSORING ZF_LOG_CENSORING\n#elif defined(ZF_LOG_DEF_CENSORING)\n\t#define _ZF_LOG_CENSORING ZF_LOG_DEF_CENSORING\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_CENSORING ZF_LOG_CENSORED\n\t#else\n\t\t#define _ZF_LOG_CENSORING ZF_LOG_UNCENSORED\n\t#endif\n#endif\n\n/* Check censoring at compile time. Evaluates to true when censoring is disabled\n * (i.e. when secrets will be logged). For example:\n *\n *   #if ZF_LOG_SECRETS\n *       char ssn[16];\n *       getSocialSecurityNumber(ssn);\n *       ZF_LOGI(\"Customer ssn: %s\", ssn);\n *   #endif\n *\n * See ZF_LOG_SECRET() macro for a more convenient way of guarding single log\n * statement.\n */\n#define ZF_LOG_SECRETS (ZF_LOG_UNCENSORED == _ZF_LOG_CENSORING)\n\n/* Static (compile-time) initialization support allows to configure logging\n * before entering main() function. This mostly useful in C++ where functions\n * and methods could be called during initialization of global objects. Those\n * functions and methods could record log messages too and for that reason\n * static initialization of logging configuration is customizable.\n *\n * Macros below allow to specify values to use for initial configuration:\n * - ZF_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)\n * - ZF_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see\n *   ZF_LOG_MEM_WIDTH in zf_log.c)\n * - ZF_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or\n *   platform specific, see ZF_LOG_USE_XXX macros in zf_log.c)\n * - ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 -\n *   all levals are \"turned on\")\n *\n * For example, in log_config.c:\n *\n *   #include <zf_log.h>\n *   ZF_LOG_DEFINE_TAG_PREFIX = \"MyApp\";\n *   ZF_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_PUT_STD, custom_output_callback, 0};\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_INFO;\n *\n * However, to use any of those macros zf_log library must be compiled with\n * following macros defined:\n * - to use ZF_LOG_DEFINE_TAG_PREFIX define ZF_LOG_EXTERN_TAG_PREFIX\n * - to use ZF_LOG_DEFINE_GLOBAL_FORMAT define ZF_LOG_EXTERN_GLOBAL_FORMAT\n * - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n * - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define\n *   ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n *\n * When zf_log library compiled with one of ZF_LOG_EXTERN_XXX macros defined,\n * corresponding ZF_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.\n * Otherwise build will fail with link error (undefined symbol).\n */\n#define ZF_LOG_DEFINE_TAG_PREFIX const char *_zf_log_tag_prefix\n#define ZF_LOG_DEFINE_GLOBAL_FORMAT zf_log_format _zf_log_global_format\n#define ZF_LOG_DEFINE_GLOBAL_OUTPUT zf_log_output _zf_log_global_output\n#define ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL int _zf_log_global_output_lvl\n\n/* Pointer to global format options. Direct modification is not allowed. Use\n * zf_log_set_mem_width() instead. Could be used to initialize zf_log_spec\n * structure:\n *\n *   const zf_log_output g_output = {ZF_LOG_PUT_STD, output_callback, 0};\n *   const zf_log_spec g_spec = {ZF_LOG_GLOBAL_FORMAT, &g_output};\n *   ZF_LOGI_AUX(&g_spec, \"Hello\");\n */\n#define ZF_LOG_GLOBAL_FORMAT ((const zf_log_format *)&_zf_log_global_format)\n\n/* Pointer to global output variable. Direct modification is not allowed. Use\n * zf_log_set_output_v() or zf_log_set_output_p() instead. Could be used to\n * initialize zf_log_spec structure:\n *\n *   const zf_log_format g_format = {40};\n *   const zf_log_spec g_spec = {g_format, ZF_LOG_GLOBAL_OUTPUT};\n *   ZF_LOGI_AUX(&g_spec, \"Hello\");\n */\n#define ZF_LOG_GLOBAL_OUTPUT ((const zf_log_output *)&_zf_log_global_output)\n\n/* When defined, all library symbols produced by linker will be prefixed with\n * provided value. That allows to use zf_log library privately in another\n * libraries without exposing zf_log symbols in their original form (to avoid\n * possible conflicts with other libraries / components that also could use\n * zf_log for logging). Value must be without quotes, for example:\n *\n *   CC_ARGS := -DZF_LOG_LIBRARY_PREFIX=my_lib_\n *\n * Note, that in this mode ZF_LOG_LIBRARY_PREFIX must be defined when building\n * zf_log library AND it also must be defined to the same value when building\n * a library that uses it. For example, consider fictional KittyHttp library\n * that wants to use zf_log for logging. First approach that could be taken is\n * to add zf_log.h and zf_log.c to the KittyHttp's source code tree directly.\n * In that case it will be enough just to define ZF_LOG_LIBRARY_PREFIX in\n * KittyHttp's build script:\n *\n *   // KittyHttp/CMakeLists.txt\n *   target_compile_definitions(KittyHttp PRIVATE\n *                              \"ZF_LOG_LIBRARY_PREFIX=KittyHttp_\")\n *\n * If KittyHttp doesn't want to include zf_log source code in its source tree\n * and wants to build zf_log as a separate library than zf_log library must be\n * built with ZF_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library\n * itself also needs to define ZF_LOG_LIBRARY_PREFIX to KittyHttp_. It can do\n * so either in its build script, as in example above, or by providing a\n * wrapper header that KittyHttp library will need to use instead of zf_log.h:\n *\n *   // KittyHttpLogging.h\n *   #define ZF_LOG_LIBRARY_PREFIX KittyHttp_\n *   #include <zf_log.h>\n *\n * Regardless of the method chosen, the end result is that zf_log symbols will\n * be prefixed with \"KittyHttp_\", so if a user of KittyHttp (say DogeBrowser)\n * also uses zf_log for logging, they will not interferer with each other. Both\n * will have their own log level, output facility, format options etc.\n */\n#ifdef ZF_LOG_LIBRARY_PREFIX\n\t#define _ZF_LOG_DECOR__(prefix, name) prefix ## name\n\t#define _ZF_LOG_DECOR_(prefix, name) _ZF_LOG_DECOR__(prefix, name)\n\t#define _ZF_LOG_DECOR(name) _ZF_LOG_DECOR_(ZF_LOG_LIBRARY_PREFIX, name)\n\n\t#define zf_log_set_tag_prefix _ZF_LOG_DECOR(zf_log_set_tag_prefix)\n\t#define zf_log_set_mem_width _ZF_LOG_DECOR(zf_log_set_mem_width)\n\t#define zf_log_set_output_level _ZF_LOG_DECOR(zf_log_set_output_level)\n\t#define zf_log_set_output_v _ZF_LOG_DECOR(zf_log_set_output_v)\n\t#define zf_log_set_output_p _ZF_LOG_DECOR(zf_log_set_output_p)\n\t#define zf_log_out_stderr_callback _ZF_LOG_DECOR(zf_log_out_stderr_callback)\n\t#define _zf_log_tag_prefix _ZF_LOG_DECOR(_zf_log_tag_prefix)\n\t#define _zf_log_global_format _ZF_LOG_DECOR(_zf_log_global_format)\n\t#define _zf_log_global_output _ZF_LOG_DECOR(_zf_log_global_output)\n\t#define _zf_log_global_output_lvl _ZF_LOG_DECOR(_zf_log_global_output_lvl)\n\t#define _zf_log_write_d _ZF_LOG_DECOR(_zf_log_write_d)\n\t#define _zf_log_write_aux_d _ZF_LOG_DECOR(_zf_log_write_aux_d)\n\t#define _zf_log_write _ZF_LOG_DECOR(_zf_log_write)\n\t#define _zf_log_write_aux _ZF_LOG_DECOR(_zf_log_write_aux)\n\t#define _zf_log_write_mem_d _ZF_LOG_DECOR(_zf_log_write_mem_d)\n\t#define _zf_log_write_mem_aux_d _ZF_LOG_DECOR(_zf_log_write_mem_aux_d)\n\t#define _zf_log_write_mem _ZF_LOG_DECOR(_zf_log_write_mem)\n\t#define _zf_log_write_mem_aux _ZF_LOG_DECOR(_zf_log_write_mem_aux)\n\t#define _zf_log_stderr_spec _ZF_LOG_DECOR(_zf_log_stderr_spec)\n#endif\n\n#if defined(__printflike)\n\t#define _ZF_LOG_PRINTFLIKE(a, b) __printflike(a, b)\n#else\n\t#define _ZF_LOG_PRINTFLIKE(a, b)\n#endif\n\n#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)\n\t#define _ZF_LOG_FUNCTION __FUNCTION__\n#else\n\t#define _ZF_LOG_FUNCTION __func__\n#endif\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)\n\t#define _ZF_LOG_INLINE __inline\n\t#define _ZF_LOG_IF(cond) \\\n\t\t__pragma(warning(push)) \\\n\t\t__pragma(warning(disable:4127)) \\\n\t\tif(cond) \\\n\t\t__pragma(warning(pop))\n\t#define _ZF_LOG_WHILE(cond) \\\n\t\t__pragma(warning(push)) \\\n\t\t__pragma(warning(disable:4127)) \\\n\t\twhile(cond) \\\n\t\t__pragma(warning(pop))\n#else\n\t#define _ZF_LOG_INLINE inline\n\t#define _ZF_LOG_IF(cond) if(cond)\n\t#define _ZF_LOG_WHILE(cond) while(cond)\n#endif\n#define _ZF_LOG_NEVER _ZF_LOG_IF(0)\n#define _ZF_LOG_ONCE _ZF_LOG_WHILE(0)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Set tag prefix. Prefix will be separated from the tag with dot ('.').\n * Use 0 or empty string to disable (default). Common use is to set it to\n * the process (or build target) name (e.g. to separate client and server\n * processes). Function will NOT copy provided prefix string, but will store the\n * pointer. Hence specified prefix string must remain valid. See\n * ZF_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function.\n * See ZF_LOG_TAG for more information about tag and tag prefix.\n */\nvoid zf_log_set_tag_prefix(const char *const prefix);\n\n/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:\n *\n *   I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo\n *                |<-          w bytes         ->|  |<-  w chars ->|\n *\n * See ZF_LOGF_MEM and ZF_LOGF_MEM_AUX for more details.\n */\nvoid zf_log_set_mem_width(const unsigned w);\n\n/* Set \"output\" log level. See ZF_LOG_LEVEL and ZF_LOG_OUTPUT_LEVEL for more\n * info about log levels.\n */\nvoid zf_log_set_output_level(const int lvl);\n\n/* Put mask is a set of flags that define what fields will be added to each\n * log message. Default value is ZF_LOG_PUT_STD and other flags could be used to\n * alter its behavior. See zf_log_set_output_v() for more details.\n *\n * Note about ZF_LOG_PUT_SRC: it will be added only in debug builds (NDEBUG is\n * not defined).\n */\nenum\n{\n\tZF_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */\n\tZF_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */\n\tZF_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */\n\tZF_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */\n\tZF_LOG_PUT_STD = 0xffff, /* everything (default) */\n};\n\ntypedef struct zf_log_message\n{\n\tint lvl; /* Log level of the message */\n\tconst char *tag; /* Associated tag (without tag prefix) */\n\tchar *buf; /* Buffer start */\n\tchar *e; /* Buffer end (last position where EOL with 0 could be written) */\n\tchar *p; /* Buffer content end (append position) */\n\tchar *tag_b; /* Prefixed tag start */\n\tchar *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */\n\tchar *msg_b; /* Message start (expanded format string) */\n}\nzf_log_message;\n\n/* Type of output callback function. It will be called for each log line allowed\n * by both \"current\" and \"output\" log levels (\"enabled\" and \"turned on\").\n * Callback function is allowed to modify content of the buffers pointed by the\n * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg\n * is UTF-8 encoded (no BOM mark).\n */\ntypedef void (*zf_log_output_cb)(const zf_log_message *msg, void *arg);\n\n/* Format options. For more details see zf_log_set_mem_width().\n */\ntypedef struct zf_log_format\n{\n\tunsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */\n}\nzf_log_format;\n\n/* Output facility.\n */\ntypedef struct zf_log_output\n{\n\tunsigned mask; /* What to put into log line buffer (see ZF_LOG_PUT_XXX) */\n\tvoid *arg; /* User provided output callback argument */\n\tzf_log_output_cb callback; /* Output callback function */\n}\nzf_log_output;\n\n/* Set output callback function.\n *\n * Mask allows to control what information will be added to the log line buffer\n * before callback function is invoked. Default mask value is ZF_LOG_PUT_STD.\n */\nvoid zf_log_set_output_v(const unsigned mask, void *const arg,\n\t\t\t\t\t\t const zf_log_output_cb callback);\nstatic _ZF_LOG_INLINE void zf_log_set_output_p(const zf_log_output *const output)\n{\n\tzf_log_set_output_v(output->mask, output->arg, output->callback);\n}\n\n/* Used with _AUX macros and allows to override global format and output\n * facility. Use ZF_LOG_GLOBAL_FORMAT and ZF_LOG_GLOBAL_OUTPUT for values from\n * global configuration. Example:\n *\n *   static const zf_log_output module_output = {\n *       ZF_LOG_PUT_STD, 0, custom_output_callback\n *   };\n *   static const zf_log_spec module_spec = {\n *       ZF_LOG_GLOBAL_FORMAT, &module_output\n *   };\n *   ZF_LOGI_AUX(&module_spec, \"Position: %ix%i\", x, y);\n *\n * See ZF_LOGF_AUX and ZF_LOGF_MEM_AUX for details.\n */\ntypedef struct zf_log_spec\n{\n\tconst zf_log_format *format;\n\tconst zf_log_output *output;\n}\nzf_log_spec;\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Execute log statement if condition is true. Example:\n *\n *   ZF_LOG_IF(1 < 2, ZF_LOGI(\"Log this\"));\n *   ZF_LOG_IF(1 > 2, ZF_LOGI(\"Don't log this\"));\n *\n * Keep in mind though, that if condition can't be evaluated at compile time,\n * then it will be evaluated at run time. This will increase exectuable size\n * and can have noticeable performance overhead. Try to limit conditions to\n * expressions that can be evaluated at compile time.\n */\n#define ZF_LOG_IF(cond, f) do { _ZF_LOG_IF((cond)) { f; } } _ZF_LOG_ONCE\n\n/* Mark log statement as \"secret\". Log statements that are marked as secrets\n * will NOT be executed when censoring is enabled (see ZF_LOG_CENSORED).\n * Example:\n *\n *   ZF_LOG_SECRET(ZF_LOGI(\"Credit card: %s\", credit_card));\n *   ZF_LOG_SECRET(ZF_LOGD_MEM(cipher, cipher_sz, \"Cipher bytes:\"));\n */\n#define ZF_LOG_SECRET(f) ZF_LOG_IF(ZF_LOG_SECRETS, f)\n\n/* Check \"current\" log level at compile time (ignoring \"output\" log level).\n * Evaluates to true when specified log level is enabled. For example:\n *\n *   #if ZF_LOG_ENABLED_DEBUG\n *       const char *const g_enum_strings[] = {\n *           \"enum_value_0\", \"enum_value_1\", \"enum_value_2\"\n *       };\n *   #endif\n *   // ...\n *   #if ZF_LOG_ENABLED_DEBUG\n *       ZF_LOGD(\"enum value: %s\", g_enum_strings[v]);\n *   #endif\n *\n * See ZF_LOG_LEVEL for details.\n */\n#define ZF_LOG_ENABLED(lvl)     ((lvl) >= _ZF_LOG_LEVEL)\n#define ZF_LOG_ENABLED_VERBOSE  ZF_LOG_ENABLED(ZF_LOG_VERBOSE)\n#define ZF_LOG_ENABLED_DEBUG    ZF_LOG_ENABLED(ZF_LOG_DEBUG)\n#define ZF_LOG_ENABLED_INFO     ZF_LOG_ENABLED(ZF_LOG_INFO)\n#define ZF_LOG_ENABLED_WARN     ZF_LOG_ENABLED(ZF_LOG_WARN)\n#define ZF_LOG_ENABLED_ERROR    ZF_LOG_ENABLED(ZF_LOG_ERROR)\n#define ZF_LOG_ENABLED_FATAL    ZF_LOG_ENABLED(ZF_LOG_FATAL)\n\n/* Check \"output\" log level at run time (taking into account \"current\" log\n * level as well). Evaluates to true when specified log level is turned on AND\n * enabled. For example:\n *\n *   if (ZF_LOG_ON_DEBUG)\n *   {\n *       char hash[65];\n *       sha256(data_ptr, data_sz, hash);\n *       ZF_LOGD(\"data: len=%u, sha256=%s\", data_sz, hash);\n *   }\n *\n * See ZF_LOG_OUTPUT_LEVEL for details.\n */\n#define ZF_LOG_ON(lvl) \\\n\t\t(ZF_LOG_ENABLED((lvl)) && (lvl) >= _ZF_LOG_OUTPUT_LEVEL)\n#define ZF_LOG_ON_VERBOSE   ZF_LOG_ON(ZF_LOG_VERBOSE)\n#define ZF_LOG_ON_DEBUG     ZF_LOG_ON(ZF_LOG_DEBUG)\n#define ZF_LOG_ON_INFO      ZF_LOG_ON(ZF_LOG_INFO)\n#define ZF_LOG_ON_WARN      ZF_LOG_ON(ZF_LOG_WARN)\n#define ZF_LOG_ON_ERROR     ZF_LOG_ON(ZF_LOG_ERROR)\n#define ZF_LOG_ON_FATAL     ZF_LOG_ON(ZF_LOG_FATAL)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern const char *_zf_log_tag_prefix;\nextern zf_log_format _zf_log_global_format;\nextern zf_log_output _zf_log_global_output;\nextern int _zf_log_global_output_lvl;\nextern const zf_log_spec _zf_log_stderr_spec;\n\nvoid _zf_log_write_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);\nvoid _zf_log_write_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(7, 8);\nvoid _zf_log_write(\n\t\tconst int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(3, 4);\nvoid _zf_log_write_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(4, 5);\nvoid _zf_log_write_mem_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(8, 9);\nvoid _zf_log_write_mem_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(9, 10);\nvoid _zf_log_write_mem(\n\t\tconst int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(5, 6);\nvoid _zf_log_write_mem_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Message logging macros:\n * - ZF_LOGV(\"format string\", args, ...)\n * - ZF_LOGD(\"format string\", args, ...)\n * - ZF_LOGI(\"format string\", args, ...)\n * - ZF_LOGW(\"format string\", args, ...)\n * - ZF_LOGE(\"format string\", args, ...)\n * - ZF_LOGF(\"format string\", args, ...)\n *\n * Memory logging macros:\n * - ZF_LOGV_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGD_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGI_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGW_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGE_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGF_MEM(data_ptr, data_sz, \"format string\", args, ...)\n *\n * Auxiliary logging macros:\n * - ZF_LOGV_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGD_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGI_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGW_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGE_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGF_AUX(&log_instance, \"format string\", args, ...)\n *\n * Auxiliary memory logging macros:\n * - ZF_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n *\n * Preformatted string logging macros:\n * - ZF_LOGV_STR(\"preformatted string\");\n * - ZF_LOGD_STR(\"preformatted string\");\n * - ZF_LOGI_STR(\"preformatted string\");\n * - ZF_LOGW_STR(\"preformatted string\");\n * - ZF_LOGE_STR(\"preformatted string\");\n * - ZF_LOGF_STR(\"preformatted string\");\n *\n * Explicit log level and tag macros:\n * - ZF_LOG_WRITE(level, tag, \"format string\", args, ...)\n * - ZF_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOG_WRITE_AUX(&log_instance, level, tag, \"format string\", args, ...)\n * - ZF_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,\n *                        \"format string\", args, ...)\n *\n * Format string follows printf() conventions. Both data_ptr and data_sz could\n * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments\n * match format specifiers in format string.\n *\n * Library assuming UTF-8 encoding for all strings (char *), including format\n * string itself.\n */\n#if ZF_LOG_SRCLOC_NONE == _ZF_LOG_SRCLOC\n\t#define ZF_LOG_WRITE(lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write(lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_aux(log, lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n#else\n\t#define ZF_LOG_WRITE(lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlog, lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlog, lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n#endif\n\nstatic _ZF_LOG_INLINE void _zf_log_unused(const int dummy, ...) {(void)dummy;}\n\n#define _ZF_LOG_UNUSED(...) \\\n\t\tdo { _ZF_LOG_NEVER _zf_log_unused(0, __VA_ARGS__); } _ZF_LOG_ONCE\n\n#if ZF_LOG_ENABLED_VERBOSE\n\t#define ZF_LOGV(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGV_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGV_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGV_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGV(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_DEBUG\n\t#define ZF_LOGD(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGD_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGD_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGD_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGD(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_INFO\n\t#define ZF_LOGI(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGI_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGI_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGI_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGI(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_WARN\n\t#define ZF_LOGW(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGW_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGW_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGW_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGW(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_ERROR\n\t#define ZF_LOGE(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGE_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGE_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGE_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGE(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_FATAL\n\t#define ZF_LOGF(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGF_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGF_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGF_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGF(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#define ZF_LOGV_STR(s) ZF_LOGV(\"%s\", (s))\n#define ZF_LOGD_STR(s) ZF_LOGD(\"%s\", (s))\n#define ZF_LOGI_STR(s) ZF_LOGI(\"%s\", (s))\n#define ZF_LOGW_STR(s) ZF_LOGW(\"%s\", (s))\n#define ZF_LOGE_STR(s) ZF_LOGE(\"%s\", (s))\n#define ZF_LOGF_STR(s) ZF_LOGF(\"%s\", (s))\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Output to standard error stream. Library uses it by default, though in few\n * cases it could be necessary to specify it explicitly. For example, when\n * zf_log library is compiled with ZF_LOG_EXTERN_GLOBAL_OUTPUT, application must\n * define and initialize global output variable:\n *\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};\n *\n * Another example is when using custom output, stderr could be used as a\n * fallback when custom output facility failed to initialize:\n *\n *   zf_log_set_output_v(ZF_LOG_OUT_STDERR);\n */\nenum { ZF_LOG_OUT_STDERR_MASK = ZF_LOG_PUT_STD };\nvoid zf_log_out_stderr_callback(const zf_log_message *const msg, void *arg);\n#define ZF_LOG_OUT_STDERR ZF_LOG_OUT_STDERR_MASK, 0, zf_log_out_stderr_callback\n\n/* Predefined spec for stderr. Uses global format options (ZF_LOG_GLOBAL_FORMAT)\n * and ZF_LOG_OUT_STDERR. Could be used to force output to stderr for a\n * particular message. Example:\n *\n *   f = fopen(\"foo.log\", \"w\");\n *   if (!f)\n *       ZF_LOGE_AUX(ZF_LOG_STDERR, \"Failed to open log file\");\n */\n#define ZF_LOG_STDERR (&_zf_log_stderr_spec)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "tests/zf_test.h",
    "content": "#pragma once\n\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n\n#if !defined(_ZF_TEST_STRINGIFY) && !defined(_ZF_TEST__STRINGIFY)\n#define _ZF_TEST__STRINGIFY(x) #x\n#define _ZF_TEST_STRINGIFY(x) _ZF_TEST__STRINGIFY(x)\n#endif\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)\n\t#define _ZF_TEST_INLINE __inline\n#else\n\t#define _ZF_TEST_INLINE inline\n#endif\n\n/* Workaround for MSVC warning 4127 about constant expression in if condition.\n */\nstatic _ZF_TEST_INLINE bool _zf_test_bool(const bool v)\n{\n\treturn v;\n}\n\n#define TEST_RUNNER_CREATE(argc, argv) \\\n\t(void)argc; (void)argv;\n\n#define TEST_SUIT_ARGUMENTS\n\n#define TEST_VERIFY_TRUE(a) \\\n\tif (!_zf_test_bool(a)) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"not true\"); \\\n\t\tfprintf(stderr, \"    false: %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_VERIFY_TRUE_MSG(a, ...) \\\n\tif (!_zf_test_bool(a)) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"not true\"); \\\n\t\tfprintf(stderr, \"    false: %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\tfprintf(stderr, \"    about: \"); \\\n\t\tfprintf(stderr, __VA_ARGS__); \\\n\t\tfprintf(stderr, \"\\n\"); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_VERIFY_FALSE(a) \\\n\tif (_zf_test_bool(a)) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"not false\"); \\\n\t\tfprintf(stderr, \"    true: %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_VERIFY_EQUAL(a, b) \\\n\tif (!_zf_test_bool((a) == (b))) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"not equal\"); \\\n\t\tfprintf(stderr, \"    left:   %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\tfprintf(stderr, \"    reight: %s\\n\", _ZF_TEST_STRINGIFY(b)); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_VERIFY_NOT_EQUAL(a, b) \\\n\tif (!_zf_test_bool((a) != (b))) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"equal\"); \\\n\t\tfprintf(stderr, \"    left:   %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\tfprintf(stderr, \"    reight: %s\\n\", _ZF_TEST_STRINGIFY(b)); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_VERIFY_GREATER_OR_EQUAL(a, b) \\\n\tif (!_zf_test_bool((a) >= (b))) { \\\n\t\tfprintf(stderr, \"%s:%u: %s:\\n\", __FILE__, __LINE__, \"less\"); \\\n\t\tfprintf(stderr, \"    left:   %s\\n\", _ZF_TEST_STRINGIFY(a)); \\\n\t\tfprintf(stderr, \"    reight: %s\\n\", _ZF_TEST_STRINGIFY(b)); \\\n\t\texit(1); \\\n\t}\n\n#define TEST_EXECUTE(f) \\\n\tf\n\n#define TEST_EXECUTE_SUITE(s) \\\n\ts()\n\n#define TEST_RUNNER_EXIT_CODE() \\\n\t0\n"
  },
  {
    "path": "zf_log/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.2)\n\n# zf_log target (required)\nset(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})\nset(HEADERS zf_log.h)\nset(SOURCES zf_log.c)\n\nset(CMAKE_C_STANDARD 99)\nset(CMAKE_C_STANDARD_REQUIRED ON)\nset(CMAKE_C_EXTENSIONS OFF)\nif(MSVC)\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} /W4 /WX\")\nelse()\n\tset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wall -Wextra -Werror -pedantic-errors\")\nendif()\n\nadd_library(zf_log ${HEADERS} ${SOURCES})\ntarget_include_directories(zf_log PUBLIC $<BUILD_INTERFACE:${HEADERS_DIR}>)\nif(ZF_LOG_LIBRARY_PREFIX)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_LIBRARY_PREFIX=${ZF_LOG_LIBRARY_PREFIX}\")\nendif()\nif(ZF_LOG_USE_ANDROID_LOG)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_USE_ANDROID_LOG\")\n\ttarget_link_libraries(zf_log log)\nendif()\nif(ZF_LOG_USE_NSLOG)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_USE_NSLOG\")\n\ttarget_link_libraries(zf_log \"-framework CoreFoundation\")\nendif()\nif(ZF_LOG_USE_DEBUGSTRING)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_USE_DEBUGSTRING\")\nendif()\nif(ZF_LOG_USE_CONFIG_HEADER)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_USE_CONFIG_HEADER\")\nendif()\nif(ZF_LOG_OPTIMIZE_SIZE)\n\ttarget_compile_definitions(zf_log PRIVATE \"ZF_LOG_OPTIMIZE_SIZE\")\nendif()\n\n# install (optional)\nif(ZF_LOG_CONFIGURE_INSTALL)\n\tif(NOT DEFINED INSTALL_INCLUDE_DIR)\n\t\tset(INSTALL_INCLUDE_DIR include)\n\tendif()\n\tif(NOT DEFINED INSTALL_LIB_DIR)\n\t\tset(INSTALL_LIB_DIR lib)\n\tendif()\n\tinstall(TARGETS zf_log EXPORT zf_log\n\t\tINCLUDES DESTINATION ${INSTALL_INCLUDE_DIR}\n\t\tARCHIVE DESTINATION ${INSTALL_LIB_DIR})\n\tinstall(DIRECTORY ${HEADERS_DIR}/\n\t\tDESTINATION ${INSTALL_INCLUDE_DIR}\n\t\tFILES_MATCHING PATTERN \"zf_*.h*\")\nendif()\n"
  },
  {
    "path": "zf_log/zf_log.c",
    "content": "#ifdef ZF_LOG_USE_CONFIG_HEADER\n\t#include \"zf_log_config.h\"\n#endif\n\n/* When defined, Android log (android/log.h) will be used by default instead of\n * stderr (ignored on non-Android platforms). Date, time, pid and tid (context)\n * will be provided by Android log. Android log features will be used to output\n * log level and tag.\n */\n#ifdef ZF_LOG_USE_ANDROID_LOG\n\t#undef ZF_LOG_USE_ANDROID_LOG\n\t#if defined(__ANDROID__)\n\t\t#define ZF_LOG_USE_ANDROID_LOG 1\n\t#else\n\t\t#define ZF_LOG_USE_ANDROID_LOG 0\n\t#endif\n#else\n\t#define ZF_LOG_USE_ANDROID_LOG 0\n#endif\n/* When defined, NSLog (uses Apple System Log) will be used instead of stderr\n * (ignored on non-Apple platforms). Date, time, pid and tid (context) will be\n * provided by NSLog. Curiously, doesn't use NSLog() directly, but piggybacks on\n * non-public CFLog() function. Both use Apple System Log internally, but it's\n * easier to call CFLog() from C than NSLog(). Current implementation doesn't\n * support \"%@\" format specifier.\n */\n#ifdef ZF_LOG_USE_NSLOG\n\t#undef ZF_LOG_USE_NSLOG\n\t#if defined(__APPLE__) && defined(__MACH__)\n\t\t#define ZF_LOG_USE_NSLOG 1\n\t#else\n\t\t#define ZF_LOG_USE_NSLOG 0\n\t#endif\n#else\n\t#define ZF_LOG_USE_NSLOG 0\n#endif\n/* When defined, OutputDebugString() will be used instead of stderr (ignored on\n * non-Windows platforms). Uses OutputDebugStringA() variant and feeds it with\n * UTF-8 data.\n */\n#ifdef ZF_LOG_USE_DEBUGSTRING\n\t#undef ZF_LOG_USE_DEBUGSTRING\n\t#if defined(_WIN32) || defined(_WIN64)\n\t\t#define ZF_LOG_USE_DEBUGSTRING 1\n\t#else\n\t\t#define ZF_LOG_USE_DEBUGSTRING 0\n\t#endif\n#else\n\t#define ZF_LOG_USE_DEBUGSTRING 0\n#endif\n/* When defined, zf_log library will not contain definition of tag prefix\n * variable. In that case it must be defined elsewhere using\n * ZF_LOG_DEFINE_TAG_PREFIX macro, for example:\n *\n *   ZF_LOG_DEFINE_TAG_PREFIX = \"ProcessName\";\n *\n * This allows to specify custom value for static initialization and avoid\n * overhead of setting this value in runtime.\n */\n#ifdef ZF_LOG_EXTERN_TAG_PREFIX\n\t#undef ZF_LOG_EXTERN_TAG_PREFIX\n\t#define ZF_LOG_EXTERN_TAG_PREFIX 1\n#else\n\t#define ZF_LOG_EXTERN_TAG_PREFIX 0\n#endif\n/* When defined, zf_log library will not contain definition of global format\n * variable. In that case it must be defined elsewhere using\n * ZF_LOG_DEFINE_GLOBAL_FORMAT macro, for example:\n *\n *   ZF_LOG_DEFINE_GLOBAL_FORMAT = {MEM_WIDTH};\n *\n * This allows to specify custom value for static initialization and avoid\n * overhead of setting this value in runtime.\n */\n#ifdef ZF_LOG_EXTERN_GLOBAL_FORMAT\n\t#undef ZF_LOG_EXTERN_GLOBAL_FORMAT\n\t#define ZF_LOG_EXTERN_GLOBAL_FORMAT 1\n#else\n\t#define ZF_LOG_EXTERN_GLOBAL_FORMAT 0\n#endif\n/* When defined, zf_log library will not contain definition of global output\n * variable. In that case it must be defined elsewhere using\n * ZF_LOG_DEFINE_GLOBAL_OUTPUT macro, for example:\n *\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_PUT_STD, custom_output_callback};\n *\n * This allows to specify custom value for static initialization and avoid\n * overhead of setting this value in runtime.\n */\n#ifdef ZF_LOG_EXTERN_GLOBAL_OUTPUT\n\t#undef ZF_LOG_EXTERN_GLOBAL_OUTPUT\n\t#define ZF_LOG_EXTERN_GLOBAL_OUTPUT 1\n#else\n\t#define ZF_LOG_EXTERN_GLOBAL_OUTPUT 0\n#endif\n/* When defined, zf_log library will not contain definition of global output\n * level variable. In that case it must be defined elsewhere using\n * ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL macro, for example:\n *\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_WARN;\n *\n * This allows to specify custom value for static initialization and avoid\n * overhead of setting this value in runtime.\n */\n#ifdef ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n\t#undef ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n\t#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 1\n#else\n\t#define ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL 0\n#endif\n/* When defined, implementation will prefer smaller code size over speed.\n * Very rough estimate is that code will be up to 2x smaller and up to 2x\n * slower. Disabled by default.\n */\n#ifdef ZF_LOG_OPTIMIZE_SIZE\n\t#undef ZF_LOG_OPTIMIZE_SIZE\n\t#define ZF_LOG_OPTIMIZE_SIZE 1\n#else\n\t#define ZF_LOG_OPTIMIZE_SIZE 0\n#endif\n/* Size of the log line buffer. The buffer is allocated on stack. It limits\n * maximum length of a log line.\n */\n#ifndef ZF_LOG_BUF_SZ\n\t#define ZF_LOG_BUF_SZ 512\n#endif\n/* Default number of bytes in one line of memory output. For large values\n * ZF_LOG_BUF_SZ also must be increased.\n */\n#ifndef ZF_LOG_MEM_WIDTH\n\t#define ZF_LOG_MEM_WIDTH 32\n#endif\n/* String to put in the end of each log line (can be empty). Its value used by\n * stderr output callback. Its size used as a default value for ZF_LOG_EOL_SZ.\n */\n#ifndef ZF_LOG_EOL\n\t#define ZF_LOG_EOL \"\\n\"\n#endif\n/* Default delimiter that separates parts of log message. Can NOT contain '%'\n * or '\\0'.\n *\n * Log message format specifications can override (or ignore) this value. For\n * more details see ZF_LOG_MESSAGE_CTX_FORMAT, ZF_LOG_MESSAGE_SRC_FORMAT and\n * ZF_LOG_MESSAGE_TAG_FORMAT.\n */\n#ifndef ZF_LOG_DEF_DELIMITER\n\t#define ZF_LOG_DEF_DELIMITER \" \"\n#endif\n/* Specifies log message context format. Log message context includes date,\n * time, process id, thread id and message's log level. Custom information can\n * be added as well. Supported fields: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND,\n * MILLISECOND, PID, TID, LEVEL, S(str), F_INIT(statements),\n * F_UINT(width, value).\n *\n * Must be defined as a tuple, for example:\n *\n *   #define ZF_LOG_MESSAGE_CTX_FORMAT (YEAR, S(\".\"), MONTH, S(\".\"), DAY, S(\" > \"))\n *\n * In that case, resulting log message will be:\n *\n *   2016.12.22 > TAG function@filename.c:line Message text\n *\n * Note, that tag, source location and message text are not impacted by\n * this setting. See ZF_LOG_MESSAGE_TAG_FORMAT and ZF_LOG_MESSAGE_SRC_FORMAT.\n *\n * If message context must be visually separated from the rest of the message,\n * it must be reflected in context format (notice trailing S(\" > \") in the\n * example above).\n *\n * S(str) adds constant string str. String can NOT contain '%' or '\\0'.\n *\n * F_INIT(statements) adds initialization statement(s) that will be evaluated\n * once for each log message. All statements are evaluated in specified order.\n * Several F_INIT() fields can be used in every log message format\n * specification. Fields, like F_UINT(width, value), are allowed to use results\n * of initialization statements. If statement introduces variables (or other\n * names, like structures) they must be prefixed with \"f_\". Statements  must be\n * enclosed into additional \"()\". Example:\n *\n *   #define ZF_LOG_MESSAGE_CTX_FORMAT \\\n *       (F_INIT(( struct rusage f_ru; getrusage(RUSAGE_SELF, &f_ru); )), \\\n *        YEAR, S(\".\"), MONTH, S(\".\"), DAY, S(\" \"), \\\n *        F_UINT(5, f_ru.ru_nsignals), \\\n *        S(\" \"))\n *\n * F_UINT(width, value) adds unsigned integer value extended with up to width\n * spaces (for alignment purposes). Value can be any expression that evaluates\n * to unsigned integer. If expression contains non-standard functions, they\n * must be declared with F_INIT(). Example:\n *\n *   #define ZF_LOG_MESSAGE_CTX_FORMAT \\\n *        (YEAR, S(\".\"), MONTH, S(\".\"), DAY, S(\" \"), \\\n *        F_INIT(( unsigned tickcount(); )), \\\n *        F_UINT(5, tickcount()), \\\n *        S(\" \"))\n *\n * Other log message format specifications follow same rules, but have a\n * different set of supported fields.\n */\n#ifndef ZF_LOG_MESSAGE_CTX_FORMAT\n\t#define ZF_LOG_MESSAGE_CTX_FORMAT \\\n\t\t(MONTH, S(\"-\"), DAY, S(ZF_LOG_DEF_DELIMITER), \\\n\t\t HOUR, S(\":\"), MINUTE, S(\":\"), SECOND, S(\".\"), MILLISECOND, S(ZF_LOG_DEF_DELIMITER), \\\n\t\t PID, S(ZF_LOG_DEF_DELIMITER), TID, S(ZF_LOG_DEF_DELIMITER), \\\n\t\t LEVEL, S(ZF_LOG_DEF_DELIMITER))\n#endif\n/* Specifies log message tag format. It includes tag prefix and tag. Custom\n * information can be added as well. Supported fields:\n * TAG(prefix_delimiter, tag_delimiter), S(str), F_INIT(statements),\n * F_UINT(width, value).\n *\n * TAG(prefix_delimiter, tag_delimiter) adds following string to log message:\n *\n *   PREFIX<prefix_delimiter>TAG<tag_delimiter>\n *\n * Prefix delimiter will be used only when prefix is not empty. Tag delimiter\n * will be used only when prefixed tag is not empty. Example:\n *\n *   #define ZF_LOG_TAG_FORMAT (S(\"[\"), TAG(\".\", \"\"), S(\"] \"))\n *\n * See ZF_LOG_MESSAGE_CTX_FORMAT for details.\n */\n#ifndef ZF_LOG_MESSAGE_TAG_FORMAT\n\t#define ZF_LOG_MESSAGE_TAG_FORMAT \\\n\t\t(TAG(\".\", ZF_LOG_DEF_DELIMITER))\n#endif\n/* Specifies log message source location format. It includes function name,\n * file name and file line. Custom information can be added as well. Supported\n * fields: FUNCTION, FILENAME, FILELINE, S(str), F_INIT(statements),\n * F_UINT(width, value).\n *\n * See ZF_LOG_MESSAGE_CTX_FORMAT for details.\n */\n#ifndef ZF_LOG_MESSAGE_SRC_FORMAT\n\t#define ZF_LOG_MESSAGE_SRC_FORMAT \\\n\t\t(FUNCTION, S(\"@\"), FILENAME, S(\":\"), FILELINE, S(ZF_LOG_DEF_DELIMITER))\n#endif\n/* Fields that can be used in log message format specifications (see above).\n * Mentioning them here explicitly, so we know that nobody else defined them\n * before us. See ZF_LOG_MESSAGE_CTX_FORMAT for details.\n */\n#define YEAR YEAR\n#define MONTH MONTH\n#define DAY DAY\n#define MINUTE MINUTE\n#define SECOND SECOND\n#define MILLISECOND MILLISECOND\n#define PID PID\n#define TID TID\n#define LEVEL LEVEL\n#define TAG(prefix_delim, tag_delim) TAG(prefix_delim, tag_delim)\n#define FUNCTION FUNCTION\n#define FILENAME FILENAME\n#define FILELINE FILELINE\n#define S(str) S(str)\n#define F_INIT(statements) F_INIT(statements)\n#define F_UINT(width, value) F_UINT(width, value)\n/* To use custom `vsnprintf()` function, define `ZF_LOG_CUSTOM_VSNPRINTF` to have its name. Example:\n *   #define ZF_LOG_CUSTOM_VSNPRINTF my_vsnprintf\n */\n#ifdef ZF_LOG_CUSTOM_VSNPRINTF\n\t#define _ZF_LOG_VSNPRINTF ZF_LOG_CUSTOM_VSNPRINTF\n#endif\n/* To use custom `snprintf()` function, define `ZF_LOG_CUSTOM_SNPRINTF` to have its name. Example:\n *   #define ZF_LOG_CUSTOM_SNPRINTF my_snprintf\n * Note, that it only will be used when `ZF_LOG_OPTIMIZE_SIZE` is enabled.\n */\n#ifdef ZF_LOG_CUSTOM_SNPRINTF\n\t#define _ZF_LOG_SNPRINTF ZF_LOG_CUSTOM_SNPRINTF\n#endif\n/* Number of bytes to reserve for EOL in the log line buffer (must be >0).\n * Must be larger than or equal to length of ZF_LOG_EOL with terminating null.\n */\n#ifndef ZF_LOG_EOL_SZ\n\t#define ZF_LOG_EOL_SZ sizeof(ZF_LOG_EOL)\n#endif\n/* Compile instrumented version of the library to facilitate unit testing.\n */\n#ifndef ZF_LOG_INSTRUMENTED\n\t#define ZF_LOG_INSTRUMENTED 0\n#endif\n\n#if defined(__linux__)\n\t#if !defined(__ANDROID__) && !defined(_GNU_SOURCE)\n\t\t#define _GNU_SOURCE\n\t#endif\n#endif\n#if defined(__MINGW32__)\n\t#ifdef __STRICT_ANSI__\n\t\t#undef __STRICT_ANSI__\n\t#endif\n#endif\n#include <assert.h>\n#include <ctype.h>\n#include <string.h>\n#include <time.h>\n#include <stdarg.h>\n#include <stddef.h>\n#include <stdlib.h>\n#include <stdio.h>\n#include \"zf_log.h\"\n\n#if defined(_WIN32) || defined(_WIN64)\n\t#include <windows.h>\n#else\n\t#include <unistd.h>\n\t#include <sys/time.h>\n\t#if defined(__linux__)\n\t\t#include <linux/limits.h>\n\t#elif defined(_AIX) || defined(__CYGWIN__)\n\t\t#include <limits.h>\n\t#else\n\t\t#include <sys/syslimits.h>\n\t#endif\n#endif\n\n#if defined(__linux__)\n\t#include <sys/prctl.h>\n\t#include <sys/types.h>\n\t#if !defined(__ANDROID__)\n\t\t#include <sys/syscall.h>\n\t#endif\n#endif\n#if defined(__MACH__) || defined(_AIX)\n\t#include <pthread.h>\n#endif\n\n#define INLINE _ZF_LOG_INLINE\n#define VAR_UNUSED(var) (void)var\n#define RETVAL_UNUSED(expr) do { while(expr) break; } while(0)\n#define STATIC_ASSERT(name, cond) \\\n\ttypedef char assert_##name[(cond)? 1: -1]\n#define ASSERT_UNREACHABLE(why) assert(!sizeof(why))\n#ifndef _countof\n\t#define _countof(xs) (sizeof(xs) / sizeof((xs)[0]))\n#endif\n\n#if ZF_LOG_INSTRUMENTED\n\t#define INSTRUMENTED_CONST\n#else\n\t#define INSTRUMENTED_CONST const\n#endif\n\n#define _PP_PASTE_2(a, b) a ## b\n#define _PP_CONCAT_2(a, b) _PP_PASTE_2(a, b)\n\n#define _PP_PASTE_3(a, b, c) a ## b ## c\n#define _PP_CONCAT_3(a, b, c) _PP_PASTE_3(a, b, c)\n\n/* Microsoft C preprocessor is a piece of shit. This moron treats __VA_ARGS__\n * as a single token and requires additional expansion to realize that it's\n * actually a list. If not for it, there would be no need in this extra\n * expansion.\n */\n#define _PP_ID(x) x\n#define _PP_NARGS_N(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,...) _24\n#define _PP_NARGS(...) _PP_ID(_PP_NARGS_N(__VA_ARGS__,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))\n\n/* There is a more efficient way to implement this, but it requires\n * working C preprocessor. Unfortunately, Microsoft Visual Studio doesn't\n * have one.\n */\n#define _PP_HEAD__(x, ...) x\n#define _PP_HEAD_(...) _PP_ID(_PP_HEAD__(__VA_ARGS__, ~))\n#define _PP_HEAD(xs) _PP_HEAD_ xs\n#define _PP_TAIL_(x, ...) (__VA_ARGS__)\n#define _PP_TAIL(xs) _PP_TAIL_ xs\n#define _PP_UNTUPLE_(...) __VA_ARGS__\n#define _PP_UNTUPLE(xs) _PP_UNTUPLE_ xs\n\n/* Apply function macro to each element in tuple. Output is not\n * enforced to be a tuple.\n */\n#define _PP_MAP_1(f, xs) f(_PP_HEAD(xs))\n#define _PP_MAP_2(f, xs) f(_PP_HEAD(xs)) _PP_MAP_1(f, _PP_TAIL(xs))\n#define _PP_MAP_3(f, xs) f(_PP_HEAD(xs)) _PP_MAP_2(f, _PP_TAIL(xs))\n#define _PP_MAP_4(f, xs) f(_PP_HEAD(xs)) _PP_MAP_3(f, _PP_TAIL(xs))\n#define _PP_MAP_5(f, xs) f(_PP_HEAD(xs)) _PP_MAP_4(f, _PP_TAIL(xs))\n#define _PP_MAP_6(f, xs) f(_PP_HEAD(xs)) _PP_MAP_5(f, _PP_TAIL(xs))\n#define _PP_MAP_7(f, xs) f(_PP_HEAD(xs)) _PP_MAP_6(f, _PP_TAIL(xs))\n#define _PP_MAP_8(f, xs) f(_PP_HEAD(xs)) _PP_MAP_7(f, _PP_TAIL(xs))\n#define _PP_MAP_9(f, xs) f(_PP_HEAD(xs)) _PP_MAP_8(f, _PP_TAIL(xs))\n#define _PP_MAP_10(f, xs) f(_PP_HEAD(xs)) _PP_MAP_9(f, _PP_TAIL(xs))\n#define _PP_MAP_11(f, xs) f(_PP_HEAD(xs)) _PP_MAP_10(f, _PP_TAIL(xs))\n#define _PP_MAP_12(f, xs) f(_PP_HEAD(xs)) _PP_MAP_11(f, _PP_TAIL(xs))\n#define _PP_MAP_13(f, xs) f(_PP_HEAD(xs)) _PP_MAP_12(f, _PP_TAIL(xs))\n#define _PP_MAP_14(f, xs) f(_PP_HEAD(xs)) _PP_MAP_13(f, _PP_TAIL(xs))\n#define _PP_MAP_15(f, xs) f(_PP_HEAD(xs)) _PP_MAP_14(f, _PP_TAIL(xs))\n#define _PP_MAP_16(f, xs) f(_PP_HEAD(xs)) _PP_MAP_15(f, _PP_TAIL(xs))\n#define _PP_MAP_17(f, xs) f(_PP_HEAD(xs)) _PP_MAP_16(f, _PP_TAIL(xs))\n#define _PP_MAP_18(f, xs) f(_PP_HEAD(xs)) _PP_MAP_17(f, _PP_TAIL(xs))\n#define _PP_MAP_19(f, xs) f(_PP_HEAD(xs)) _PP_MAP_18(f, _PP_TAIL(xs))\n#define _PP_MAP_20(f, xs) f(_PP_HEAD(xs)) _PP_MAP_19(f, _PP_TAIL(xs))\n#define _PP_MAP_21(f, xs) f(_PP_HEAD(xs)) _PP_MAP_20(f, _PP_TAIL(xs))\n#define _PP_MAP_22(f, xs) f(_PP_HEAD(xs)) _PP_MAP_21(f, _PP_TAIL(xs))\n#define _PP_MAP_23(f, xs) f(_PP_HEAD(xs)) _PP_MAP_22(f, _PP_TAIL(xs))\n#define _PP_MAP_24(f, xs) f(_PP_HEAD(xs)) _PP_MAP_23(f, _PP_TAIL(xs))\n#define _PP_MAP(f, xs) _PP_CONCAT_2(_PP_MAP_, _PP_NARGS xs) (f, xs)\n\n/* Apply function macro to each element in tuple in reverse order.\n * Output is not enforced to be a tuple.\n */\n#define _PP_RMAP_1(f, xs) f(_PP_HEAD(xs))\n#define _PP_RMAP_2(f, xs) _PP_RMAP_1(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_3(f, xs) _PP_RMAP_2(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_4(f, xs) _PP_RMAP_3(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_5(f, xs) _PP_RMAP_4(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_6(f, xs) _PP_RMAP_5(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_7(f, xs) _PP_RMAP_6(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_8(f, xs) _PP_RMAP_7(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_9(f, xs) _PP_RMAP_8(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_10(f, xs) _PP_RMAP_9(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_11(f, xs) _PP_RMAP_10(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_12(f, xs) _PP_RMAP_11(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_13(f, xs) _PP_RMAP_12(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_14(f, xs) _PP_RMAP_13(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_15(f, xs) _PP_RMAP_14(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_16(f, xs) _PP_RMAP_15(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_17(f, xs) _PP_RMAP_16(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_18(f, xs) _PP_RMAP_17(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_19(f, xs) _PP_RMAP_18(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_20(f, xs) _PP_RMAP_19(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_21(f, xs) _PP_RMAP_20(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_22(f, xs) _PP_RMAP_21(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_23(f, xs) _PP_RMAP_22(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP_24(f, xs) _PP_RMAP_23(f, _PP_TAIL(xs)) f(_PP_HEAD(xs))\n#define _PP_RMAP(f, xs) _PP_CONCAT_2(_PP_RMAP_, _PP_NARGS xs) (f, xs)\n\n/* Used to implement _ZF_LOG_MESSAGE_FORMAT_CONTAINS() macro. All possible\n * fields must be mentioned here. Not counting F_INIT() here because it's\n * somewhat special and is handled spearatly (at least for now).\n */\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__             (0<<0)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__YEAR         (1<<1)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__MONTH        (1<<2)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__DAY          (1<<3)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__HOUR         (1<<4)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__MINUTE       (1<<5)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__SECOND       (1<<6)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__MILLISECOND  (1<<7)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__PID          (1<<8)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__TID          (1<<9)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__LEVEL        (1<<10)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__TAG(ps, ts)  (1<<11)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__FUNCTION     (1<<12)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__FILENAME     (1<<13)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__FILELINE     (1<<14)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__S(s)         (1<<15)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__F_INIT(expr) (0<<16)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK__F_UINT(w, v) (1<<17)\n#define _ZF_LOG_MESSAGE_FORMAT_MASK(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_MASK_, _, field)\n\n/* Logical \"or\" of masks of fields used in specified format specification.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_FIELDS(format) \\\n\t(0 _PP_MAP(| _ZF_LOG_MESSAGE_FORMAT_MASK, format))\n\n/* Expands to expressions that evaluates to true if field is used in\n * specified format specification. Example:\n *\n *   #if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(F_UINT, ZF_LOG_MESSAGE_CTX_FORMAT)\n *       ...\n *   #endif\n */\n#define _ZF_LOG_MESSAGE_FORMAT_CONTAINS(field, format) \\\n\t(_ZF_LOG_MESSAGE_FORMAT_MASK(field) & _ZF_LOG_MESSAGE_FORMAT_FIELDS(format))\n\n/* Same, but checks all supported format specifications.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_FIELD_USED(field) \\\n\t(_ZF_LOG_MESSAGE_FORMAT_CONTAINS(field, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(field, ZF_LOG_MESSAGE_TAG_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(field, ZF_LOG_MESSAGE_SRC_FORMAT))\n\n#define _ZF_LOG_MESSAGE_FORMAT_DATETIME_USED \\\n\t(_ZF_LOG_MESSAGE_FORMAT_CONTAINS(YEAR, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(MONTH, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(DAY, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(HOUR, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(MINUTE, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(SECOND, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t _ZF_LOG_MESSAGE_FORMAT_CONTAINS(MILLISECOND, ZF_LOG_MESSAGE_CTX_FORMAT))\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)\n\t#pragma warning(disable:4204) /* nonstandard extension used: non-constant aggregate initializer */\n\t#define memccpy _memccpy\n#endif\n\n#ifndef _ZF_LOG_VSNPRINTF\n\t#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)\n\t\tstatic int fake_vsnprintf(char *s, size_t sz, const char *fmt, va_list ap)\n\t\t{\n\t\t\tconst int n = vsnprintf_s(s, sz, _TRUNCATE, fmt, ap);\n\t\t\treturn 0 < n? n: (int)sz + 1; /* no need in _vscprintf() for now */\n\t\t}\n\t\t#define _ZF_LOG_VSNPRINTF fake_vsnprintf\n\t#else\n\t\t#define _ZF_LOG_VSNPRINTF vsnprintf\n\t#endif\n#endif\n\n#if ZF_LOG_OPTIMIZE_SIZE\n\t#ifndef _ZF_LOG_SNPRINTF\n\t\t#if (defined(_MSC_VER) && !defined(__INTEL_COMPILER)) || defined(__MINGW64__)\n\t\t\tstatic int fake_snprintf(char *s, size_t sz, const char *fmt, ...)\n\t\t\t{\n\t\t\t\tva_list va;\n\t\t\t\tva_start(va, fmt);\n\t\t\t\tconst int n = _ZF_LOG_VSNPRINTF(s, sz, fmt, va);\n\t\t\t\tva_end(va);\n\t\t\t\treturn n;\n\t\t\t}\n\t\t\t#define _ZF_LOG_SNPRINTF fake_snprintf\n\t\t#else\n\t\t\t#define _ZF_LOG_SNPRINTF snprintf\n\t\t#endif\n\t#endif\n#endif\n\ntypedef void (*time_cb)(struct tm *const tm, unsigned *const usec);\ntypedef void (*pid_cb)(int *const pid, int *const tid);\ntypedef void (*buffer_cb)(zf_log_message *msg, char *buf);\n\ntypedef struct src_location\n{\n\tconst char *const func;\n\tconst char *const file;\n\tconst unsigned line;\n}\nsrc_location;\n\ntypedef struct mem_block\n{\n\tconst void *const d;\n\tconst unsigned d_sz;\n}\nmem_block;\n\nstatic void time_callback(struct tm *const tm, unsigned *const usec);\nstatic void pid_callback(int *const pid, int *const tid);\nstatic void buffer_callback(zf_log_message *msg, char *buf);\n\nSTATIC_ASSERT(eol_fits_eol_sz, sizeof(ZF_LOG_EOL) <= ZF_LOG_EOL_SZ);\nSTATIC_ASSERT(eol_sz_greater_than_zero, 0 < ZF_LOG_EOL_SZ);\nSTATIC_ASSERT(eol_sz_less_than_buf_sz, ZF_LOG_EOL_SZ < ZF_LOG_BUF_SZ);\n#if !defined(_WIN32) && !defined(_WIN64)\n\tSTATIC_ASSERT(buf_sz_less_than_pipe_buf, ZF_LOG_BUF_SZ <= PIPE_BUF);\n#endif\nstatic const char c_hex[] = \"0123456789abcdef\";\n\nstatic INSTRUMENTED_CONST unsigned g_buf_sz = ZF_LOG_BUF_SZ - ZF_LOG_EOL_SZ;\nstatic INSTRUMENTED_CONST time_cb g_time_cb = time_callback;\nstatic INSTRUMENTED_CONST pid_cb g_pid_cb = pid_callback;\nstatic INSTRUMENTED_CONST buffer_cb g_buffer_cb = buffer_callback;\n\n#if ZF_LOG_USE_ANDROID_LOG\n\t#include <android/log.h>\n\n\tstatic INLINE int android_lvl(const int lvl)\n\t{\n\t\tswitch (lvl)\n\t\t{\n\t\tcase ZF_LOG_VERBOSE:\n\t\t\treturn ANDROID_LOG_VERBOSE;\n\t\tcase ZF_LOG_DEBUG:\n\t\t\treturn ANDROID_LOG_DEBUG;\n\t\tcase ZF_LOG_INFO:\n\t\t\treturn ANDROID_LOG_INFO;\n\t\tcase ZF_LOG_WARN:\n\t\t\treturn ANDROID_LOG_WARN;\n\t\tcase ZF_LOG_ERROR:\n\t\t\treturn ANDROID_LOG_ERROR;\n\t\tcase ZF_LOG_FATAL:\n\t\t\treturn ANDROID_LOG_FATAL;\n\t\tdefault:\n\t\t\tASSERT_UNREACHABLE(\"Bad log level\");\n\t\t\treturn ANDROID_LOG_UNKNOWN;\n\t\t}\n\t}\n\n\tstatic void out_android_callback(const zf_log_message *const msg, void *arg)\n\t{\n\t\tVAR_UNUSED(arg);\n\t\t*msg->p = 0;\n\t\tconst char *tag = msg->p;\n\t\tif (msg->tag_e != msg->tag_b)\n\t\t{\n\t\t\ttag = msg->tag_b;\n\t\t\t*msg->tag_e = 0;\n\t\t}\n\t\t__android_log_print(android_lvl(msg->lvl), tag, \"%s\", msg->msg_b);\n\t}\n\n\tenum { OUT_ANDROID_MASK = ZF_LOG_PUT_STD & ~ZF_LOG_PUT_CTX };\n\t#define OUT_ANDROID OUT_ANDROID_MASK, 0, out_android_callback\n#endif\n\n#if ZF_LOG_USE_NSLOG\n\t#include <CoreFoundation/CoreFoundation.h>\n\tCF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);\n\n\tstatic INLINE int apple_lvl(const int lvl)\n\t{\n\t\tswitch (lvl)\n\t\t{\n\t\tcase ZF_LOG_VERBOSE:\n\t\t\treturn 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;\n\t\tcase ZF_LOG_DEBUG:\n\t\t\treturn 7; /* ASL_LEVEL_DEBUG / kCFLogLevelDebug */;\n\t\tcase ZF_LOG_INFO:\n\t\t\treturn 6; /* ASL_LEVEL_INFO / kCFLogLevelInfo */;\n\t\tcase ZF_LOG_WARN:\n\t\t\treturn 4; /* ASL_LEVEL_WARNING / kCFLogLevelWarning */;\n\t\tcase ZF_LOG_ERROR:\n\t\t\treturn 3; /* ASL_LEVEL_ERR / kCFLogLevelError */;\n\t\tcase ZF_LOG_FATAL:\n\t\t\treturn 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;\n\t\tdefault:\n\t\t\tASSERT_UNREACHABLE(\"Bad log level\");\n\t\t\treturn 0; /* ASL_LEVEL_EMERG / kCFLogLevelEmergency */;\n\t\t}\n\t}\n\n\tstatic void out_nslog_callback(const zf_log_message *const msg, void *arg)\n\t{\n\t\tVAR_UNUSED(arg);\n\t\t*msg->p = 0;\n\t\tCFLog(apple_lvl(msg->lvl), CFSTR(\"%s\"), msg->tag_b);\n\t}\n\n\tenum { OUT_NSLOG_MASK = ZF_LOG_PUT_STD & ~ZF_LOG_PUT_CTX };\n\t#define OUT_NSLOG OUT_NSLOG_MASK, 0, out_nslog_callback\n#endif\n\n#if ZF_LOG_USE_DEBUGSTRING\n\t#include <windows.h>\n\n\tstatic void out_debugstring_callback(const zf_log_message *const msg, void *arg)\n\t{\n\t\tVAR_UNUSED(arg);\n\t\tmsg->p[0] = '\\n';\n\t\tmsg->p[1] = '\\0';\n\t\tOutputDebugStringA(msg->buf);\n\t}\n\n\tenum { OUT_DEBUGSTRING_MASK = ZF_LOG_PUT_STD };\n\t#define OUT_DEBUGSTRING OUT_DEBUGSTRING_MASK, 0, out_debugstring_callback\n#endif\n\nvoid zf_log_out_stderr_callback(const zf_log_message *const msg, void *arg)\n{\n\tVAR_UNUSED(arg);\n\tconst size_t eol_len = sizeof(ZF_LOG_EOL) - 1;\n\tmemcpy(msg->p, ZF_LOG_EOL, eol_len);\n#if defined(_WIN32) || defined(_WIN64)\n\t/* WriteFile() is atomic for local files opened with FILE_APPEND_DATA and\n\t   without FILE_WRITE_DATA */\n\tDWORD written;\n\tWriteFile(GetStdHandle(STD_ERROR_HANDLE), msg->buf,\n\t\t\t  (DWORD)(msg->p - msg->buf + eol_len), &written, 0);\n#else\n\t/* write() is atomic for buffers less than or equal to PIPE_BUF. */\n\tRETVAL_UNUSED(write(STDERR_FILENO, msg->buf,\n\t\t\t\t\t\t(size_t)(msg->p - msg->buf) + eol_len));\n#endif\n}\n\nstatic const zf_log_output out_stderr = {ZF_LOG_OUT_STDERR};\n\n#if !ZF_LOG_EXTERN_TAG_PREFIX\n\tZF_LOG_DEFINE_TAG_PREFIX = 0;\n#endif\n\n#if !ZF_LOG_EXTERN_GLOBAL_FORMAT\n\tZF_LOG_DEFINE_GLOBAL_FORMAT = {ZF_LOG_MEM_WIDTH};\n#endif\n\n#if !ZF_LOG_EXTERN_GLOBAL_OUTPUT\n\t#if ZF_LOG_USE_ANDROID_LOG\n\t\tZF_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_ANDROID};\n\t#elif ZF_LOG_USE_NSLOG\n\t\tZF_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_NSLOG};\n\t#elif ZF_LOG_USE_DEBUGSTRING\n\t\tZF_LOG_DEFINE_GLOBAL_OUTPUT = {OUT_DEBUGSTRING};\n\t#else\n\t\tZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};\n\t#endif\n#endif\n\n#if !ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n\tZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = 0;\n#endif\n\nconst zf_log_spec _zf_log_stderr_spec =\n{\n\tZF_LOG_GLOBAL_FORMAT,\n\t&out_stderr,\n};\n\nstatic const zf_log_spec global_spec =\n{\n\tZF_LOG_GLOBAL_FORMAT,\n\tZF_LOG_GLOBAL_OUTPUT,\n};\n\n#if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(LEVEL, ZF_LOG_MESSAGE_CTX_FORMAT)\nstatic char lvl_char(const int lvl)\n{\n\tswitch (lvl)\n\t{\n\tcase ZF_LOG_VERBOSE:\n\t\treturn 'V';\n\tcase ZF_LOG_DEBUG:\n\t\treturn 'D';\n\tcase ZF_LOG_INFO:\n\t\treturn 'I';\n\tcase ZF_LOG_WARN:\n\t\treturn 'W';\n\tcase ZF_LOG_ERROR:\n\t\treturn 'E';\n\tcase ZF_LOG_FATAL:\n\t\treturn 'F';\n\tdefault:\n\t\tASSERT_UNREACHABLE(\"Bad log level\");\n\t\treturn '?';\n\t}\n}\n#endif\n\n#define GCCVER_LESS(MAJOR, MINOR, PATCH) \\\n\t(__GNUC__ < MAJOR || \\\n\t\t(__GNUC__ == MAJOR && (__GNUC_MINOR__ < MINOR || \\\n\t\t\t(__GNUC_MINOR__ == MINOR && __GNUC_PATCHLEVEL__ < PATCH))))\n\n#if !defined(__clang__) && defined(__GNUC__) && GCCVER_LESS(4,7,0)\n\t#define __atomic_load_n(vp, model) __sync_fetch_and_add(vp, 0)\n\t#define __atomic_fetch_add(vp, n, model) __sync_fetch_and_add(vp, n)\n\t#define __atomic_sub_fetch(vp, n, model) __sync_sub_and_fetch(vp, n)\n\t#define __atomic_or_fetch(vp, n, model) __sync_or_and_fetch(vp, n)\n\t#define __atomic_and_fetch(vp, n, model) __sync_and_and_fetch(vp, n)\n\t/* Note: will not store old value of *vp in *ep (non-standard behaviour) */\n\t#define __atomic_compare_exchange_n(vp, ep, d, weak, smodel, fmodel) \\\n\t\t__sync_bool_compare_and_swap(vp, *(ep), d)\n#endif\n\n#if !ZF_LOG_OPTIMIZE_SIZE && !defined(_WIN32) && !defined(_WIN64)\n#define TCACHE\n#define TCACHE_STALE (0x40000000)\n#define TCACHE_FLUID (0x40000000 | 0x80000000)\nstatic unsigned g_tcache_mode = TCACHE_STALE;\nstatic struct timeval g_tcache_tv = {0, 0};\n\nstatic struct tm g_tcache_tm;\n\nstatic INLINE int tcache_get(const struct timeval *const tv, struct tm *const tm)\n{\n\tunsigned mode;\n\tmode = __atomic_load_n(&g_tcache_mode, __ATOMIC_RELAXED);\n\tif (0 == (mode & TCACHE_FLUID))\n\t{\n\t\tmode = __atomic_fetch_add(&g_tcache_mode, 1, __ATOMIC_ACQUIRE);\n\t\tif (0 == (mode & TCACHE_FLUID))\n\t\t{\n\t\t\tif (g_tcache_tv.tv_sec == tv->tv_sec)\n\t\t\t{\n\t\t\t\t*tm = g_tcache_tm;\n\t\t\t\t__atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);\n\t\t\t\treturn !0;\n\t\t\t}\n\t\t\t__atomic_or_fetch(&g_tcache_mode, TCACHE_STALE, __ATOMIC_RELAXED);\n\t\t}\n\t\t__atomic_sub_fetch(&g_tcache_mode, 1, __ATOMIC_RELEASE);\n\t}\n\treturn 0;\n}\n\nstatic INLINE void tcache_set(const struct timeval *const tv, struct tm *const tm)\n{\n\tunsigned stale = TCACHE_STALE;\n\tif (__atomic_compare_exchange_n(&g_tcache_mode, &stale, TCACHE_FLUID,\n\t\t\t\t\t\t\t\t\t0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))\n\t{\n\t\tg_tcache_tv = *tv;\n\t\tg_tcache_tm = *tm;\n\t\t__atomic_and_fetch(&g_tcache_mode, ~TCACHE_FLUID, __ATOMIC_RELEASE);\n\t}\n}\n#endif\n\nstatic void time_callback(struct tm *const tm, unsigned *const msec)\n{\n#if !_ZF_LOG_MESSAGE_FORMAT_DATETIME_USED\n\tVAR_UNUSED(tm);\n\tVAR_UNUSED(msec);\n#else\n\t#if defined(_WIN32) || defined(_WIN64)\n\tSYSTEMTIME st;\n\tGetLocalTime(&st);\n\ttm->tm_year = st.wYear;\n\ttm->tm_mon = st.wMonth - 1;\n\ttm->tm_mday = st.wDay;\n\ttm->tm_wday = st.wDayOfWeek;\n\ttm->tm_hour = st.wHour;\n\ttm->tm_min = st.wMinute;\n\ttm->tm_sec = st.wSecond;\n\t*msec = st.wMilliseconds;\n\t#else\n\tstruct timeval tv;\n\tgettimeofday(&tv, 0);\n\t\t#ifndef TCACHE\n\t\tlocaltime_r(&tv.tv_sec, tm);\n\t\t#else\n\t\tif (!tcache_get(&tv, tm))\n\t\t{\n\t\t\tlocaltime_r(&tv.tv_sec, tm);\n\t\t\ttcache_set(&tv, tm);\n\t\t}\n\t\t#endif\n\t*msec = (unsigned)tv.tv_usec / 1000;\n\t#endif\n#endif\n}\n\nstatic void pid_callback(int *const pid, int *const tid)\n{\n#if !_ZF_LOG_MESSAGE_FORMAT_CONTAINS(PID, ZF_LOG_MESSAGE_CTX_FORMAT)\n\tVAR_UNUSED(pid);\n#else\n\t#if defined(_WIN32) || defined(_WIN64)\n\t*pid = GetCurrentProcessId();\n\t#else\n\t*pid = getpid();\n\t#endif\n#endif\n\n#if !_ZF_LOG_MESSAGE_FORMAT_CONTAINS(TID, ZF_LOG_MESSAGE_CTX_FORMAT)\n\tVAR_UNUSED(tid);\n#else\n\t#if defined(_WIN32) || defined(_WIN64)\n\t*tid = GetCurrentThreadId();\n\t#elif defined(__ANDROID__)\n\t*tid = gettid();\n\t#elif defined(__linux__)\n\t*tid = syscall(SYS_gettid);\n\t#elif defined(__MACH__)\n\t*tid = (int)pthread_mach_thread_np(pthread_self());\n\t#elif defined(_AIX)\n\tpthread_t t = pthread_self();\n\tstruct __pthrdsinfo tinfo;\n\tpthread_getthrds_np(&t, PTHRDSINFO_QUERY_TID, &tinfo, sizeof(tinfo), NULL, 0);\n\t*tid = (int)tinfo.__pi_tid;\n\t#else\n\t\t#define Platform not supported\n\t#endif\n#endif\n}\n\nstatic void buffer_callback(zf_log_message *msg, char *buf)\n{\n\tmsg->e = (msg->p = msg->buf = buf) + g_buf_sz;\n}\n\n#if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, ZF_LOG_MESSAGE_SRC_FORMAT)\nstatic const char *funcname(const char *func)\n{\n\treturn func? func: \"\";\n}\n#endif\n\n#if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, ZF_LOG_MESSAGE_SRC_FORMAT)\nstatic const char *filename(const char *file)\n{\n\tconst char *f = file;\n\tfor (const char *p = file; 0 != *p; ++p)\n\t{\n\t\tif ('/' == *p || '\\\\' == *p)\n\t\t{\n\t\t\tf = p + 1;\n\t\t}\n\t}\n\treturn f;\n}\n#endif\n\nstatic INLINE size_t nprintf_size(zf_log_message *const msg)\n{\n\t// *nprintf() always puts 0 in the end when input buffer is not empty. This\n\t// 0 is not desired because its presence sets (ctx->p) to (ctx->e - 1) which\n\t// leaves space for one more character. Some put_xxx() functions don't use\n\t// *nprintf() and could use that last character. In that case log line will\n\t// have multiple (two) half-written parts which is confusing. To workaround\n\t// that we allow *nprintf() to write its 0 in the eol area (which is always\n\t// not empty).\n\treturn (size_t)(msg->e - msg->p + 1);\n}\n\nstatic INLINE void put_nprintf(zf_log_message *const msg, const int n)\n{\n\tif (0 < n)\n\t{\n\t\tmsg->p = n < msg->e - msg->p? msg->p + n: msg->e;\n\t}\n}\n\nstatic INLINE char *put_padding_r(const unsigned w, const char wc,\n\t\t\t\t\t\t\t\t  char *p, char *e)\n{\n\tfor (char *const b = e - w; b < p; *--p = wc) {}\n\treturn p;\n}\n\nstatic char *put_integer_r(unsigned v, const int sign,\n\t\t\t\t\t\t   const unsigned w, const char wc, char *const e)\n{\n\tstatic const char _signs[] = {'-', '0', '+'};\n\tstatic const char *const signs = _signs + 1;\n\tchar *p = e;\n\tdo { *--p = '0' + v % 10; } while (0 != (v /= 10));\n\tif (0 == sign) return put_padding_r(w, wc, p, e);\n\tif ('0' != wc)\n\t{\n\t\t*--p = signs[sign];\n\t\treturn put_padding_r(w, wc, p, e);\n\t}\n\tp = put_padding_r(w, wc, p, e + 1);\n\t*--p = signs[sign];\n\treturn p;\n}\n\nstatic INLINE char *put_uint_r(const unsigned v, const unsigned w, const char wc,\n\t\t\t\t\t\t\t   char *const e)\n{\n\treturn put_integer_r(v, 0, w, wc, e);\n}\n\nstatic INLINE char *put_int_r(const int v, const unsigned w, const char wc,\n\t\t\t\t\t\t\t  char *const e)\n{\n\treturn 0 <= v? put_integer_r((unsigned)v, 0, w, wc, e)\n\t\t\t\t : put_integer_r((unsigned)-v, -1, w, wc, e);\n}\n\nstatic INLINE char *put_stringn(const char *const s_p, const char *const s_e,\n\t\t\t\t\t\t\t\tchar *const p, char *const e)\n{\n\tconst ptrdiff_t m = e - p;\n\tptrdiff_t n = s_e - s_p;\n\tif (n > m)\n\t{\n\t\tn = m;\n\t}\n\tmemcpy(p, s_p, n);\n\treturn p + n;\n}\n\nstatic INLINE char *put_string(const char *s, char *p, char *const e)\n{\n\tconst ptrdiff_t n = e - p;\n\tchar *const c = (char *)memccpy(p, s, '\\0', n);\n\treturn 0 != c? c - 1: e;\n}\n\nstatic INLINE char *put_uint(unsigned v, const unsigned w, const char wc,\n\t\t\t\t\t\t\t char *const p, char *const e)\n{\n\tchar buf[16];\n\tchar *const se = buf + _countof(buf);\n\tchar *sp = put_uint_r(v, w, wc, se);\n\treturn put_stringn(sp, se, p, e);\n}\n\n#define PUT_CSTR_R(p, STR) \\\n\tdo { \\\n\t\tfor (unsigned i = sizeof(STR) - 1; 0 < i--;) { \\\n\t\t\t*--(p) = (STR)[i]; \\\n\t\t} \\\n\t} _ZF_LOG_ONCE\n\n#define PUT_CSTR_CHECKED(p, e, STR) \\\n\tdo { \\\n\t\tfor (unsigned i = 0; (e) > (p) && (sizeof(STR) - 1) > i; ++i) { \\\n\t\t\t*(p)++ = (STR)[i]; \\\n\t\t} \\\n\t} _ZF_LOG_ONCE\n\n/* F_INIT field support.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__YEAR\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__MONTH\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__DAY\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__HOUR\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__MINUTE\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__SECOND\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__MILLISECOND\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__PID\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__TID\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__LEVEL\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__TAG(ps, ts)\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__FUNCTION\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__FILENAME\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__FILELINE\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__S(s)\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__F_INIT(expr) _PP_UNTUPLE(expr);\n#define _ZF_LOG_MESSAGE_FORMAT_INIT__F_UINT(w, v)\n#define _ZF_LOG_MESSAGE_FORMAT_INIT(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_INIT_, _, field)\n\n/* Implements generation of printf-like format string for log message\n * format specification.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__             \"\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__YEAR         \"%04u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__MONTH        \"%02u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__DAY          \"%02u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__HOUR         \"%02u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__MINUTE       \"%02u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__SECOND       \"%02u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__MILLISECOND  \"%03u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__PID          \"%5i\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__TID          \"%5i\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__LEVEL        \"%c\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__TAG          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__FUNCTION     \"%s\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILENAME     \"%s\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__FILELINE     \"%u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__S(s)         s\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_INIT(expr) \"\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT__F_UINT(w, v) \"%\" #w \"u\"\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT_, _, field)\n\n/* Implements generation of printf-like format parameters for log message\n * format specification.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__YEAR         ,(unsigned)(tm.tm_year + 1900)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__MONTH        ,(unsigned)(tm.tm_mon + 1)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__DAY          ,(unsigned)tm.tm_mday\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__HOUR         ,(unsigned)tm.tm_hour\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__MINUTE       ,(unsigned)tm.tm_min\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__SECOND       ,(unsigned)tm.tm_sec\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__MILLISECOND  ,(unsigned)msec\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__PID          ,pid\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__TID          ,tid\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__LEVEL        ,(char)lvl_char(msg->lvl)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__TAG          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__FUNCTION     ,funcname(src->func)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILENAME     ,filename(src->file)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__FILELINE     ,src->line\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__S(s)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_INIT(expr)\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL__F_UINT(w, v) ,v\n#define _ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL_, _, field)\n\n/* Implements generation of put_xxx_t statements for log message specification.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__YEAR         p = put_uint_r(tm.tm_year + 1900, 4, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__MONTH        p = put_uint_r((unsigned)tm.tm_mon + 1, 2, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__DAY          p = put_uint_r((unsigned)tm.tm_mday, 2, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__HOUR         p = put_uint_r((unsigned)tm.tm_hour, 2, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__MINUTE       p = put_uint_r((unsigned)tm.tm_min, 2, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__SECOND       p = put_uint_r((unsigned)tm.tm_sec, 2, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__MILLISECOND  p = put_uint_r(msec, 3, '0', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__PID          p = put_int_r(pid, 5, ' ', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__TID          p = put_int_r(tid, 5, ' ', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__LEVEL        *--p = lvl_char(msg->lvl);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__TAG          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__FUNCTION     UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__FILENAME     UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__FILELINE     UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__S(s)         PUT_CSTR_R(p, s);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__F_INIT(expr)\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R__F_UINT(w, v) p = put_uint_r(v, w, ' ', p);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT_R(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_PUT_R_, _, field)\n\nstatic void put_ctx(zf_log_message *const msg)\n{\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_CTX_FORMAT)\n#if !_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_CTX_FORMAT)\n\tVAR_UNUSED(msg);\n#else\n\t#if _ZF_LOG_MESSAGE_FORMAT_DATETIME_USED\n\tstruct tm tm;\n\tunsigned msec;\n\tg_time_cb(&tm, &msec);\n\t#endif\n\t#if _ZF_LOG_MESSAGE_FORMAT_CONTAINS(PID, ZF_LOG_MESSAGE_CTX_FORMAT) || \\\n\t\t_ZF_LOG_MESSAGE_FORMAT_CONTAINS(TID, ZF_LOG_MESSAGE_CTX_FORMAT)\n\tint pid, tid;\n\tg_pid_cb(&pid, &tid);\n\t#endif\n\n\t#if ZF_LOG_OPTIMIZE_SIZE\n\tint n;\n\tn = _ZF_LOG_SNPRINTF(msg->p, nprintf_size(msg),\n\t\t\t\t\t\t _PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT, ZF_LOG_MESSAGE_CTX_FORMAT)\n\t\t\t\t\t\t _PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL, ZF_LOG_MESSAGE_CTX_FORMAT));\n\tput_nprintf(msg, n);\n\t#else\n\tchar buf[64];\n\tchar *const e = buf + sizeof(buf);\n\tchar *p = e;\n\t_PP_RMAP(_ZF_LOG_MESSAGE_FORMAT_PUT_R, ZF_LOG_MESSAGE_CTX_FORMAT)\n\tmsg->p = put_stringn(p, e, msg->p, msg->e);\n\t#endif\n#endif\n}\n\n#define PUT_TAG(msg, tag, prefix_delim, tag_delim) \\\n\tdo { \\\n\t\tconst char *ch; \\\n\t\tmsg->tag_b = msg->p; \\\n\t\tif (0 != (ch = _zf_log_tag_prefix)) { \\\n\t\t\tfor (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \\\n\t\t} \\\n\t\tif (0 != (ch = tag) && 0 != tag[0]) { \\\n\t\t\tif (msg->tag_b != msg->p) { \\\n\t\t\t\tPUT_CSTR_CHECKED(msg->p, msg->e, prefix_delim); \\\n\t\t\t} \\\n\t\t\tfor (;msg->e != msg->p && 0 != (*msg->p = *ch); ++msg->p, ++ch) {} \\\n\t\t} \\\n\t\tmsg->tag_e = msg->p; \\\n\t\tif (msg->tag_b != msg->p) { \\\n\t\t\tPUT_CSTR_CHECKED(msg->p, msg->e, tag_delim); \\\n\t\t} \\\n\t} _ZF_LOG_ONCE\n\n/* Implements simple put statements for log message specification.\n */\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__YEAR         UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__MONTH        UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__DAY          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__HOUR         UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__MINUTE       UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__SECOND       UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__MILLISECOND  UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__PID          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__TID          UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__LEVEL        UNDEFINED\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__TAG(pd, td)  PUT_TAG(msg, tag, pd, td);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__FUNCTION     msg->p = put_string(funcname(src->func), msg->p, msg->e);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__FILENAME     msg->p = put_string(filename(src->file), msg->p, msg->e);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__FILELINE     msg->p = put_uint(src->line, 0, '\\0', msg->p, msg->e);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__S(s)         PUT_CSTR_CHECKED(msg->p, msg->e, s);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__F_INIT(expr)\n#define _ZF_LOG_MESSAGE_FORMAT_PUT__F_UINT(w, v) msg->p = put_uint(v, w, ' ', msg->p, msg->e);\n#define _ZF_LOG_MESSAGE_FORMAT_PUT(field) \\\n\t_PP_CONCAT_3(_ZF_LOG_MESSAGE_FORMAT_PUT_, _, field)\n\nstatic void put_tag(zf_log_message *const msg, const char *const tag)\n{\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_TAG_FORMAT)\n#if !_ZF_LOG_MESSAGE_FORMAT_CONTAINS(TAG, ZF_LOG_MESSAGE_TAG_FORMAT)\n\tVAR_UNUSED(tag);\n#endif\n#if !_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_TAG_FORMAT)\n\tVAR_UNUSED(msg);\n#else\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PUT, ZF_LOG_MESSAGE_TAG_FORMAT)\n#endif\n}\n\nstatic void put_src(zf_log_message *const msg, const src_location *const src)\n{\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_INIT, ZF_LOG_MESSAGE_SRC_FORMAT)\n#if !_ZF_LOG_MESSAGE_FORMAT_CONTAINS(FUNCTION, ZF_LOG_MESSAGE_SRC_FORMAT) && \\\n\t!_ZF_LOG_MESSAGE_FORMAT_CONTAINS(FILENAME, ZF_LOG_MESSAGE_SRC_FORMAT) && \\\n\t!_ZF_LOG_MESSAGE_FORMAT_CONTAINS(FILELINE, ZF_LOG_MESSAGE_SRC_FORMAT)\n\tVAR_UNUSED(src);\n#endif\n#if !_ZF_LOG_MESSAGE_FORMAT_FIELDS(ZF_LOG_MESSAGE_SRC_FORMAT)\n\tVAR_UNUSED(msg);\n#else\n\t#if ZF_LOG_OPTIMIZE_SIZE\n\tint n;\n\tn = _ZF_LOG_SNPRINTF(msg->p, nprintf_size(msg),\n\t\t\t\t\t\t _PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PRINTF_FMT, ZF_LOG_MESSAGE_SRC_FORMAT)\n\t\t\t\t\t\t _PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PRINTF_VAL, ZF_LOG_MESSAGE_SRC_FORMAT));\n\tput_nprintf(msg, n);\n\t#else\n\t_PP_MAP(_ZF_LOG_MESSAGE_FORMAT_PUT, ZF_LOG_MESSAGE_SRC_FORMAT)\n\t#endif\n#endif\n}\n\nstatic void put_msg(zf_log_message *const msg,\n\t\t\t\t\tconst char *const fmt, va_list va)\n{\n\tint n;\n\tmsg->msg_b = msg->p;\n\tn = _ZF_LOG_VSNPRINTF(msg->p, nprintf_size(msg), fmt, va);\n\tput_nprintf(msg, n);\n}\n\nstatic void output_mem(const zf_log_spec *log, zf_log_message *const msg,\n\t\t\t\t\t   const mem_block *const mem)\n{\n\tif (0 == mem->d || 0 == mem->d_sz)\n\t{\n\t\treturn;\n\t}\n\tconst unsigned char *mem_p = (const unsigned char *)mem->d;\n\tconst unsigned char *const mem_e = mem_p + mem->d_sz;\n\tconst unsigned char *mem_cut;\n\tconst ptrdiff_t mem_width = (ptrdiff_t)log->format->mem_width;\n\tchar *const hex_b = msg->msg_b;\n\tchar *const ascii_b = hex_b + 2 * mem_width + 2;\n\tchar *const ascii_e = ascii_b + mem_width;\n\tif (msg->e < ascii_e)\n\t{\n\t\treturn;\n\t}\n\twhile (mem_p != mem_e)\n\t{\n\t\tchar *hex = hex_b;\n\t\tchar *ascii = ascii_b;\n\t\tfor (mem_cut = mem_width < mem_e - mem_p? mem_p + mem_width: mem_e;\n\t\t\t mem_cut != mem_p; ++mem_p)\n\t\t{\n\t\t\tconst unsigned char ch = *mem_p;\n\t\t\t*hex++ = c_hex[(0xf0 & ch) >> 4];\n\t\t\t*hex++ = c_hex[(0x0f & ch)];\n\t\t\t*ascii++ = isprint(ch)? (char)ch: '?';\n\t\t}\n\t\twhile (hex != ascii_b)\n\t\t{\n\t\t\t*hex++ = ' ';\n\t\t}\n\t\tmsg->p = ascii;\n\t\tlog->output->callback(msg, log->output->arg);\n\t}\n}\n\nvoid zf_log_set_tag_prefix(const char *const prefix)\n{\n\t_zf_log_tag_prefix = prefix;\n}\n\nvoid zf_log_set_mem_width(const unsigned w)\n{\n\t_zf_log_global_format.mem_width = w;\n}\n\nvoid zf_log_set_output_level(const int lvl)\n{\n\t_zf_log_global_output_lvl = lvl;\n}\n\nvoid zf_log_set_output_v(const unsigned mask, void *const arg,\n\t\t\t\t\t\t const zf_log_output_cb callback)\n{\n\t_zf_log_global_output.mask = mask;\n\t_zf_log_global_output.arg = arg;\n\t_zf_log_global_output.callback = callback;\n}\n\nstatic void _zf_log_write_imp(\n\t\tconst zf_log_spec *log,\n\t\tconst src_location *const src, const mem_block *const mem,\n\t\tconst int lvl, const char *const tag, const char *const fmt, va_list va)\n{\n\tzf_log_message msg;\n\tchar buf[ZF_LOG_BUF_SZ];\n\tconst unsigned mask = log->output->mask;\n\tmsg.lvl = lvl;\n\tmsg.tag = tag;\n\tg_buffer_cb(&msg, buf);\n\tif (ZF_LOG_PUT_CTX & mask)\n\t{\n\t\tput_ctx(&msg);\n\t}\n\tif (ZF_LOG_PUT_TAG & mask)\n\t{\n\t\tput_tag(&msg, tag);\n\t}\n\tif (0 != src && ZF_LOG_PUT_SRC & mask)\n\t{\n\t\tput_src(&msg, src);\n\t}\n\tif (ZF_LOG_PUT_MSG & mask)\n\t{\n\t\tput_msg(&msg, fmt, va);\n\t}\n\tlog->output->callback(&msg, log->output->arg);\n\tif (0 != mem && ZF_LOG_PUT_MSG & mask)\n\t{\n\t\toutput_mem(log, &msg, mem);\n\t}\n}\n\nvoid _zf_log_write_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst char *const fmt, ...)\n{\n\tconst src_location src = {func, file, line};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(&global_spec, &src, 0, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...)\n{\n\tconst src_location src = {func, file, line};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(log, &src, 0, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write(const int lvl, const char *const tag,\n\t\t\t\t   const char *const fmt, ...)\n{\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(&global_spec, 0, 0, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...)\n{\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(log, 0, 0, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_mem_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...)\n{\n\tconst src_location src = {func, file, line};\n\tconst mem_block mem = {d, d_sz};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(&global_spec, &src, &mem, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_mem_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...)\n{\n\tconst src_location src = {func, file, line};\n\tconst mem_block mem = {d, d_sz};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(log, &src, &mem, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_mem(const int lvl, const char *const tag,\n\t\t\t\t\t   const void *const d, const unsigned d_sz,\n\t\t\t\t\t   const char *const fmt, ...)\n{\n\tconst mem_block mem = {d, d_sz};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(&global_spec, 0, &mem, lvl, tag, fmt, va);\n\tva_end(va);\n}\n\nvoid _zf_log_write_mem_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...)\n{\n\tconst mem_block mem = {d, d_sz};\n\tva_list va;\n\tva_start(va, fmt);\n\t_zf_log_write_imp(log, 0, &mem, lvl, tag, fmt, va);\n\tva_end(va);\n}\n"
  },
  {
    "path": "zf_log/zf_log.h",
    "content": "#pragma once\n\n#ifndef _ZF_LOG_H_\n#define _ZF_LOG_H_\n\n/* To detect incompatible changes you can define ZF_LOG_VERSION_REQUIRED to be\n * the current value of ZF_LOG_VERSION before including this file (or via\n * compiler command line):\n *\n *   #define ZF_LOG_VERSION_REQUIRED 4\n *   #include <zf_log.h>\n *\n * Compilation will fail when included file has different version.\n */\n#define ZF_LOG_VERSION 4\n#if defined(ZF_LOG_VERSION_REQUIRED)\n\t#if ZF_LOG_VERSION_REQUIRED != ZF_LOG_VERSION\n\t\t#error different zf_log version required\n\t#endif\n#endif\n\n/* Log level guideline:\n * - ZF_LOG_FATAL - happened something impossible and absolutely unexpected.\n *   Process can't continue and must be terminated.\n *   Example: division by zero, unexpected modifications from other thread.\n * - ZF_LOG_ERROR - happened something possible, but highly unexpected. The\n *   process is able to recover and continue execution.\n *   Example: out of memory (could also be FATAL if not handled properly).\n * - ZF_LOG_WARN - happened something that *usually* should not happen and\n *   significantly changes application behavior for some period of time.\n *   Example: configuration file not found, auth error.\n * - ZF_LOG_INFO - happened significant life cycle event or major state\n *   transition.\n *   Example: app started, user logged in.\n * - ZF_LOG_DEBUG - minimal set of events that could help to reconstruct the\n *   execution path. Usually disabled in release builds.\n * - ZF_LOG_VERBOSE - all other events. Usually disabled in release builds.\n *\n * *Ideally*, log file of debugged, well tested, production ready application\n * should be empty or very small. Choosing a right log level is as important as\n * providing short and self descriptive log message.\n */\n#define ZF_LOG_VERBOSE 1\n#define ZF_LOG_DEBUG   2\n#define ZF_LOG_INFO    3\n#define ZF_LOG_WARN    4\n#define ZF_LOG_ERROR   5\n#define ZF_LOG_FATAL   6\n#define ZF_LOG_NONE    0xFF\n\n/* \"Current\" log level is a compile time check and has no runtime overhead. Log\n * level that is below current log level it said to be \"disabled\". Otherwise,\n * it's \"enabled\". Log messages that are disabled has no runtime overhead - they\n * are converted to no-op by preprocessor and then eliminated by compiler.\n * Current log level is configured per compilation module (.c/.cpp/.m file) by\n * defining ZF_LOG_DEF_LEVEL or ZF_LOG_LEVEL. ZF_LOG_LEVEL has higer priority\n * and when defined overrides value provided by ZF_LOG_DEF_LEVEL.\n *\n * Common practice is to define default current log level with ZF_LOG_DEF_LEVEL\n * in build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_LEVEL=ZF_LOG_INFO\n *\n * And when necessary to override it with ZF_LOG_LEVEL in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_LEVEL ZF_LOG_VERBOSE\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_LEVEL and ZF_LOG_LEVEL are undefined, then ZF_LOG_INFO\n * will be used for release builds (NDEBUG is defined) and ZF_LOG_DEBUG\n * otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_LEVEL)\n\t#define _ZF_LOG_LEVEL ZF_LOG_LEVEL\n#elif defined(ZF_LOG_DEF_LEVEL)\n\t#define _ZF_LOG_LEVEL ZF_LOG_DEF_LEVEL\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_LEVEL ZF_LOG_INFO\n\t#else\n\t\t#define _ZF_LOG_LEVEL ZF_LOG_DEBUG\n\t#endif\n#endif\n\n/* \"Output\" log level is a runtime check. When log level is below output log\n * level it said to be \"turned off\" (or just \"off\" for short). Otherwise it's\n * \"turned on\" (or just \"on\"). Log levels that were \"disabled\" (see\n * ZF_LOG_LEVEL and ZF_LOG_DEF_LEVEL) can't be \"turned on\", but \"enabled\" log\n * levels could be \"turned off\". Only messages with log level which is\n * \"turned on\" will reach output facility. All other messages will be ignored\n * (and their arguments will not be evaluated). Output log level is a global\n * property and configured per process using zf_log_set_output_level() function\n * which can be called at any time.\n *\n * Though in some cases it could be useful to configure output log level per\n * compilation module or per library. There are two ways to achieve that:\n * - Define ZF_LOG_OUTPUT_LEVEL to expresion that evaluates to desired output\n *   log level.\n * - Copy zf_log.h and zf_log.c files into your library and build it with\n *   ZF_LOG_LIBRARY_PREFIX defined to library specific prefix. See\n *   ZF_LOG_LIBRARY_PREFIX for more details.\n *\n * When defined, ZF_LOG_OUTPUT_LEVEL must evaluate to integral value that\n * corresponds to desired output log level. Use it only when compilation module\n * is required to have output log level which is different from global output\n * log level set by zf_log_set_output_level() function. For other cases,\n * consider defining ZF_LOG_LEVEL or using zf_log_set_output_level() function.\n *\n * Example:\n *\n *   #define ZF_LOG_OUTPUT_LEVEL g_module_log_level\n *   #include <zf_log.h>\n *   static int g_module_log_level = ZF_LOG_INFO;\n *   static void foo() {\n *       ZF_LOGI(\"Will check g_module_log_level for output log level\");\n *   }\n *   void debug_log(bool on) {\n *       g_module_log_level = on? ZF_LOG_DEBUG: ZF_LOG_INFO;\n *   }\n *\n * Note on performance. This expression will be evaluated each time message is\n * logged (except when message log level is \"disabled\" - see ZF_LOG_LEVEL for\n * details). Keep this expression as simple as possible, otherwise it will not\n * only add runtime overhead, but also will increase size of call site (which\n * will result in larger executable). The prefered way is to use integer\n * variable (as in example above). If structure must be used, log_level field\n * must be the first field in this structure:\n *\n *   #define ZF_LOG_OUTPUT_LEVEL (g_config.log_level)\n *   #include <zf_log.h>\n *   struct config {\n *       int log_level;\n *       unsigned other_field;\n *       [...]\n *   };\n *   static config g_config = {ZF_LOG_INFO, 0, ...};\n *\n * This allows compiler to generate more compact load instruction (no need to\n * specify offset since it's zero). Calling a function to get output log level\n * is generaly a bad idea, since it will increase call site size and runtime\n * overhead even further.\n */\n#if defined(ZF_LOG_OUTPUT_LEVEL)\n\t#define _ZF_LOG_OUTPUT_LEVEL ZF_LOG_OUTPUT_LEVEL\n#else\n\t#define _ZF_LOG_OUTPUT_LEVEL _zf_log_global_output_lvl\n#endif\n\n/* \"Tag\" is a compound string that could be associated with a log message. It\n * consists of tag prefix and tag (both are optional).\n *\n * Tag prefix is a global property and configured per process using\n * zf_log_set_tag_prefix() function. Tag prefix identifies context in which\n * component or module is running (e.g. process name). For example, the same\n * library could be used in both client and server processes that work on the\n * same machine. Tag prefix could be used to easily distinguish between them.\n * For more details about tag prefix see zf_log_set_tag_prefix() function. Tag\n * prefix\n *\n * Tag identifies component or module. It is configured per compilation module\n * (.c/.cpp/.m file) by defining ZF_LOG_TAG or ZF_LOG_DEF_TAG. ZF_LOG_TAG has\n * higer priority and when defined overrides value provided by ZF_LOG_DEF_TAG.\n * When defined, value must evaluate to (const char *), so for strings double\n * quotes must be used.\n *\n * Default tag could be defined with ZF_LOG_DEF_TAG in build script (e.g.\n * Makefile, CMakeLists.txt, gyp, etc.) for the entire project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_TAG=\\\"MISC\\\"\n *\n * And when necessary could be overriden with ZF_LOG_TAG in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_TAG \"MAIN\"\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_TAG and ZF_LOG_TAG are undefined no tag will be added to\n * the log message (tag prefix still could be added though).\n *\n * Output example:\n *\n *   04-29 22:43:20.244 40059  1299 I hello.MAIN Number of arguments: 1\n *                                    |     |\n *                                    |     +- tag (e.g. module)\n *                                    +- tag prefix (e.g. process name)\n */\n#if defined(ZF_LOG_TAG)\n\t#define _ZF_LOG_TAG ZF_LOG_TAG\n#elif defined(ZF_LOG_DEF_TAG)\n\t#define _ZF_LOG_TAG ZF_LOG_DEF_TAG\n#else\n\t#define _ZF_LOG_TAG 0\n#endif\n\n/* Source location is part of a log line that describes location (function or\n * method name, file name and line number, e.g. \"runloop@main.cpp:68\") of a\n * log statement that produced it.\n * Source location formats are:\n * - ZF_LOG_SRCLOC_NONE - don't add source location to log line.\n * - ZF_LOG_SRCLOC_SHORT - add source location in short form (file and line\n *   number, e.g. \"@main.cpp:68\").\n * - ZF_LOG_SRCLOC_LONG - add source location in long form (function or method\n *   name, file and line number, e.g. \"runloop@main.cpp:68\").\n */\n#define ZF_LOG_SRCLOC_NONE  0\n#define ZF_LOG_SRCLOC_SHORT 1\n#define ZF_LOG_SRCLOC_LONG  2\n\n/* Source location format is configured per compilation module (.c/.cpp/.m\n * file) by defining ZF_LOG_DEF_SRCLOC or ZF_LOG_SRCLOC. ZF_LOG_SRCLOC has\n * higer priority and when defined overrides value provided by\n * ZF_LOG_DEF_SRCLOC.\n *\n * Common practice is to define default format with ZF_LOG_DEF_SRCLOC in\n * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_SRCLOC=ZF_LOG_SRCLOC_LONG\n *\n * And when necessary to override it with ZF_LOG_SRCLOC in .c/.cpp/.m files\n * before including zf_log.h:\n *\n *   #define ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_SRCLOC and ZF_LOG_SRCLOC are undefined, then\n * ZF_LOG_SRCLOC_NONE will be used for release builds (NDEBUG is defined) and\n * ZF_LOG_SRCLOC_LONG otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_SRCLOC)\n\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC\n#elif defined(ZF_LOG_DEF_SRCLOC)\n\t#define _ZF_LOG_SRCLOC ZF_LOG_DEF_SRCLOC\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_NONE\n\t#else\n\t\t#define _ZF_LOG_SRCLOC ZF_LOG_SRCLOC_LONG\n\t#endif\n#endif\n#if ZF_LOG_SRCLOC_LONG == _ZF_LOG_SRCLOC\n\t#define _ZF_LOG_SRCLOC_FUNCTION _ZF_LOG_FUNCTION\n#else\n\t#define _ZF_LOG_SRCLOC_FUNCTION 0\n#endif\n\n/* Censoring provides conditional logging of secret information, also known as\n * Personally Identifiable Information (PII) or Sensitive Personal Information\n * (SPI). Censoring can be either enabled (ZF_LOG_CENSORED) or disabled\n * (ZF_LOG_UNCENSORED). When censoring is enabled, log statements marked as\n * \"secrets\" will be ignored and will have zero overhead (arguments also will\n * not be evaluated).\n */\n#define ZF_LOG_CENSORED   1\n#define ZF_LOG_UNCENSORED 0\n\n/* Censoring is configured per compilation module (.c/.cpp/.m file) by defining\n * ZF_LOG_DEF_CENSORING or ZF_LOG_CENSORING. ZF_LOG_CENSORING has higer priority\n * and when defined overrides value provided by ZF_LOG_DEF_CENSORING.\n *\n * Common practice is to define default censoring with ZF_LOG_DEF_CENSORING in\n * build script (e.g. Makefile, CMakeLists.txt, gyp, etc.) for the entire\n * project or target:\n *\n *   CC_ARGS := -DZF_LOG_DEF_CENSORING=ZF_LOG_CENSORED\n *\n * And when necessary to override it with ZF_LOG_CENSORING in .c/.cpp/.m files\n * before including zf_log.h (consider doing it only for debug purposes and be\n * very careful not to push such temporary changes to source control):\n *\n *   #define ZF_LOG_CENSORING ZF_LOG_UNCENSORED\n *   #include <zf_log.h>\n *\n * If both ZF_LOG_DEF_CENSORING and ZF_LOG_CENSORING are undefined, then\n * ZF_LOG_CENSORED will be used for release builds (NDEBUG is defined) and\n * ZF_LOG_UNCENSORED otherwise (NDEBUG is not defined).\n */\n#if defined(ZF_LOG_CENSORING)\n\t#define _ZF_LOG_CENSORING ZF_LOG_CENSORING\n#elif defined(ZF_LOG_DEF_CENSORING)\n\t#define _ZF_LOG_CENSORING ZF_LOG_DEF_CENSORING\n#else\n\t#ifdef NDEBUG\n\t\t#define _ZF_LOG_CENSORING ZF_LOG_CENSORED\n\t#else\n\t\t#define _ZF_LOG_CENSORING ZF_LOG_UNCENSORED\n\t#endif\n#endif\n\n/* Check censoring at compile time. Evaluates to true when censoring is disabled\n * (i.e. when secrets will be logged). For example:\n *\n *   #if ZF_LOG_SECRETS\n *       char ssn[16];\n *       getSocialSecurityNumber(ssn);\n *       ZF_LOGI(\"Customer ssn: %s\", ssn);\n *   #endif\n *\n * See ZF_LOG_SECRET() macro for a more convenient way of guarding single log\n * statement.\n */\n#define ZF_LOG_SECRETS (ZF_LOG_UNCENSORED == _ZF_LOG_CENSORING)\n\n/* Static (compile-time) initialization support allows to configure logging\n * before entering main() function. This mostly useful in C++ where functions\n * and methods could be called during initialization of global objects. Those\n * functions and methods could record log messages too and for that reason\n * static initialization of logging configuration is customizable.\n *\n * Macros below allow to specify values to use for initial configuration:\n * - ZF_LOG_EXTERN_TAG_PREFIX - tag prefix (default: none)\n * - ZF_LOG_EXTERN_GLOBAL_FORMAT - global format options (default: see\n *   ZF_LOG_MEM_WIDTH in zf_log.c)\n * - ZF_LOG_EXTERN_GLOBAL_OUTPUT - global output facility (default: stderr or\n *   platform specific, see ZF_LOG_USE_XXX macros in zf_log.c)\n * - ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL - global output log level (default: 0 -\n *   all levals are \"turned on\")\n *\n * For example, in log_config.c:\n *\n *   #include <zf_log.h>\n *   ZF_LOG_DEFINE_TAG_PREFIX = \"MyApp\";\n *   ZF_LOG_DEFINE_GLOBAL_FORMAT = {CUSTOM_MEM_WIDTH};\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_PUT_STD, custom_output_callback, 0};\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL = ZF_LOG_INFO;\n *\n * However, to use any of those macros zf_log library must be compiled with\n * following macros defined:\n * - to use ZF_LOG_DEFINE_TAG_PREFIX define ZF_LOG_EXTERN_TAG_PREFIX\n * - to use ZF_LOG_DEFINE_GLOBAL_FORMAT define ZF_LOG_EXTERN_GLOBAL_FORMAT\n * - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT define ZF_LOG_EXTERN_GLOBAL_OUTPUT\n * - to use ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL define\n *   ZF_LOG_EXTERN_GLOBAL_OUTPUT_LEVEL\n *\n * When zf_log library compiled with one of ZF_LOG_EXTERN_XXX macros defined,\n * corresponding ZF_LOG_DEFINE_XXX macro MUST be used exactly once somewhere.\n * Otherwise build will fail with link error (undefined symbol).\n */\n#define ZF_LOG_DEFINE_TAG_PREFIX const char *_zf_log_tag_prefix\n#define ZF_LOG_DEFINE_GLOBAL_FORMAT zf_log_format _zf_log_global_format\n#define ZF_LOG_DEFINE_GLOBAL_OUTPUT zf_log_output _zf_log_global_output\n#define ZF_LOG_DEFINE_GLOBAL_OUTPUT_LEVEL int _zf_log_global_output_lvl\n\n/* Pointer to global format options. Direct modification is not allowed. Use\n * zf_log_set_mem_width() instead. Could be used to initialize zf_log_spec\n * structure:\n *\n *   const zf_log_output g_output = {ZF_LOG_PUT_STD, output_callback, 0};\n *   const zf_log_spec g_spec = {ZF_LOG_GLOBAL_FORMAT, &g_output};\n *   ZF_LOGI_AUX(&g_spec, \"Hello\");\n */\n#define ZF_LOG_GLOBAL_FORMAT ((const zf_log_format *)&_zf_log_global_format)\n\n/* Pointer to global output variable. Direct modification is not allowed. Use\n * zf_log_set_output_v() or zf_log_set_output_p() instead. Could be used to\n * initialize zf_log_spec structure:\n *\n *   const zf_log_format g_format = {40};\n *   const zf_log_spec g_spec = {g_format, ZF_LOG_GLOBAL_OUTPUT};\n *   ZF_LOGI_AUX(&g_spec, \"Hello\");\n */\n#define ZF_LOG_GLOBAL_OUTPUT ((const zf_log_output *)&_zf_log_global_output)\n\n/* When defined, all library symbols produced by linker will be prefixed with\n * provided value. That allows to use zf_log library privately in another\n * libraries without exposing zf_log symbols in their original form (to avoid\n * possible conflicts with other libraries / components that also could use\n * zf_log for logging). Value must be without quotes, for example:\n *\n *   CC_ARGS := -DZF_LOG_LIBRARY_PREFIX=my_lib_\n *\n * Note, that in this mode ZF_LOG_LIBRARY_PREFIX must be defined when building\n * zf_log library AND it also must be defined to the same value when building\n * a library that uses it. For example, consider fictional KittyHttp library\n * that wants to use zf_log for logging. First approach that could be taken is\n * to add zf_log.h and zf_log.c to the KittyHttp's source code tree directly.\n * In that case it will be enough just to define ZF_LOG_LIBRARY_PREFIX in\n * KittyHttp's build script:\n *\n *   // KittyHttp/CMakeLists.txt\n *   target_compile_definitions(KittyHttp PRIVATE\n *                              \"ZF_LOG_LIBRARY_PREFIX=KittyHttp_\")\n *\n * If KittyHttp doesn't want to include zf_log source code in its source tree\n * and wants to build zf_log as a separate library than zf_log library must be\n * built with ZF_LOG_LIBRARY_PREFIX defined to KittyHttp_ AND KittyHttp library\n * itself also needs to define ZF_LOG_LIBRARY_PREFIX to KittyHttp_. It can do\n * so either in its build script, as in example above, or by providing a\n * wrapper header that KittyHttp library will need to use instead of zf_log.h:\n *\n *   // KittyHttpLogging.h\n *   #define ZF_LOG_LIBRARY_PREFIX KittyHttp_\n *   #include <zf_log.h>\n *\n * Regardless of the method chosen, the end result is that zf_log symbols will\n * be prefixed with \"KittyHttp_\", so if a user of KittyHttp (say DogeBrowser)\n * also uses zf_log for logging, they will not interferer with each other. Both\n * will have their own log level, output facility, format options etc.\n */\n#ifdef ZF_LOG_LIBRARY_PREFIX\n\t#define _ZF_LOG_DECOR__(prefix, name) prefix ## name\n\t#define _ZF_LOG_DECOR_(prefix, name) _ZF_LOG_DECOR__(prefix, name)\n\t#define _ZF_LOG_DECOR(name) _ZF_LOG_DECOR_(ZF_LOG_LIBRARY_PREFIX, name)\n\n\t#define zf_log_set_tag_prefix _ZF_LOG_DECOR(zf_log_set_tag_prefix)\n\t#define zf_log_set_mem_width _ZF_LOG_DECOR(zf_log_set_mem_width)\n\t#define zf_log_set_output_level _ZF_LOG_DECOR(zf_log_set_output_level)\n\t#define zf_log_set_output_v _ZF_LOG_DECOR(zf_log_set_output_v)\n\t#define zf_log_set_output_p _ZF_LOG_DECOR(zf_log_set_output_p)\n\t#define zf_log_out_stderr_callback _ZF_LOG_DECOR(zf_log_out_stderr_callback)\n\t#define _zf_log_tag_prefix _ZF_LOG_DECOR(_zf_log_tag_prefix)\n\t#define _zf_log_global_format _ZF_LOG_DECOR(_zf_log_global_format)\n\t#define _zf_log_global_output _ZF_LOG_DECOR(_zf_log_global_output)\n\t#define _zf_log_global_output_lvl _ZF_LOG_DECOR(_zf_log_global_output_lvl)\n\t#define _zf_log_write_d _ZF_LOG_DECOR(_zf_log_write_d)\n\t#define _zf_log_write_aux_d _ZF_LOG_DECOR(_zf_log_write_aux_d)\n\t#define _zf_log_write _ZF_LOG_DECOR(_zf_log_write)\n\t#define _zf_log_write_aux _ZF_LOG_DECOR(_zf_log_write_aux)\n\t#define _zf_log_write_mem_d _ZF_LOG_DECOR(_zf_log_write_mem_d)\n\t#define _zf_log_write_mem_aux_d _ZF_LOG_DECOR(_zf_log_write_mem_aux_d)\n\t#define _zf_log_write_mem _ZF_LOG_DECOR(_zf_log_write_mem)\n\t#define _zf_log_write_mem_aux _ZF_LOG_DECOR(_zf_log_write_mem_aux)\n\t#define _zf_log_stderr_spec _ZF_LOG_DECOR(_zf_log_stderr_spec)\n#endif\n\n#if defined(__printflike)\n\t#define _ZF_LOG_PRINTFLIKE(str_index, first_to_check) \\\n\t\t__printflike(str_index, first_to_check)\n#elif defined(__GNUC__)\n\t#define _ZF_LOG_PRINTFLIKE(str_index, first_to_check) \\\n\t\t__attribute__((format(__printf__, str_index, first_to_check)))\n#else\n\t#define _ZF_LOG_PRINTFLIKE(str_index, first_to_check)\n#endif\n\n#if (defined(_WIN32) || defined(_WIN64)) && !defined(__GNUC__)\n\t#define _ZF_LOG_FUNCTION __FUNCTION__\n#else\n\t#define _ZF_LOG_FUNCTION __func__\n#endif\n\n#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)\n\t#define _ZF_LOG_INLINE __inline\n\t#define _ZF_LOG_IF(cond) \\\n\t\t__pragma(warning(push)) \\\n\t\t__pragma(warning(disable:4127)) \\\n\t\tif(cond) \\\n\t\t__pragma(warning(pop))\n\t#define _ZF_LOG_WHILE(cond) \\\n\t\t__pragma(warning(push)) \\\n\t\t__pragma(warning(disable:4127)) \\\n\t\twhile(cond) \\\n\t\t__pragma(warning(pop))\n#else\n\t#define _ZF_LOG_INLINE inline\n\t#define _ZF_LOG_IF(cond) if(cond)\n\t#define _ZF_LOG_WHILE(cond) while(cond)\n#endif\n#define _ZF_LOG_NEVER _ZF_LOG_IF(0)\n#define _ZF_LOG_ONCE _ZF_LOG_WHILE(0)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Set tag prefix. Prefix will be separated from the tag with dot ('.').\n * Use 0 or empty string to disable (default). Common use is to set it to\n * the process (or build target) name (e.g. to separate client and server\n * processes). Function will NOT copy provided prefix string, but will store the\n * pointer. Hence specified prefix string must remain valid. See\n * ZF_LOG_DEFINE_TAG_PREFIX for a way to set it before entering main() function.\n * See ZF_LOG_TAG for more information about tag and tag prefix.\n */\nvoid zf_log_set_tag_prefix(const char *const prefix);\n\n/* Set number of bytes per log line in memory (ASCII-HEX) output. Example:\n *\n *   I hello.MAIN 4c6f72656d20697073756d20646f6c6f  Lorem ipsum dolo\n *                |<-          w bytes         ->|  |<-  w chars ->|\n *\n * See ZF_LOGF_MEM and ZF_LOGF_MEM_AUX for more details.\n */\nvoid zf_log_set_mem_width(const unsigned w);\n\n/* Set \"output\" log level. See ZF_LOG_LEVEL and ZF_LOG_OUTPUT_LEVEL for more\n * info about log levels.\n */\nvoid zf_log_set_output_level(const int lvl);\n\n/* Put mask is a set of flags that define what fields will be added to each\n * log message. Default value is ZF_LOG_PUT_STD and other flags could be used to\n * alter its behavior. See zf_log_set_output_v() for more details.\n *\n * Note about ZF_LOG_PUT_SRC: it will be added only in debug builds (NDEBUG is\n * not defined).\n */\nenum\n{\n\tZF_LOG_PUT_CTX = 1 << 0, /* context (time, pid, tid, log level) */\n\tZF_LOG_PUT_TAG = 1 << 1, /* tag (including tag prefix) */\n\tZF_LOG_PUT_SRC = 1 << 2, /* source location (file, line, function) */\n\tZF_LOG_PUT_MSG = 1 << 3, /* message text (formatted string) */\n\tZF_LOG_PUT_STD = 0xffff, /* everything (default) */\n};\n\ntypedef struct zf_log_message\n{\n\tint lvl; /* Log level of the message */\n\tconst char *tag; /* Associated tag (without tag prefix) */\n\tchar *buf; /* Buffer start */\n\tchar *e; /* Buffer end (last position where EOL with 0 could be written) */\n\tchar *p; /* Buffer content end (append position) */\n\tchar *tag_b; /* Prefixed tag start */\n\tchar *tag_e; /* Prefixed tag end (if != tag_b, points to msg separator) */\n\tchar *msg_b; /* Message start (expanded format string) */\n}\nzf_log_message;\n\n/* Type of output callback function. It will be called for each log line allowed\n * by both \"current\" and \"output\" log levels (\"enabled\" and \"turned on\").\n * Callback function is allowed to modify content of the buffers pointed by the\n * msg, but it's not allowed to modify any of msg fields. Buffer pointed by msg\n * is UTF-8 encoded (no BOM mark).\n */\ntypedef void (*zf_log_output_cb)(const zf_log_message *msg, void *arg);\n\n/* Format options. For more details see zf_log_set_mem_width().\n */\ntypedef struct zf_log_format\n{\n\tunsigned mem_width; /* Bytes per line in memory (ASCII-HEX) dump */\n}\nzf_log_format;\n\n/* Output facility.\n */\ntypedef struct zf_log_output\n{\n\tunsigned mask; /* What to put into log line buffer (see ZF_LOG_PUT_XXX) */\n\tvoid *arg; /* User provided output callback argument */\n\tzf_log_output_cb callback; /* Output callback function */\n}\nzf_log_output;\n\n/* Set output callback function.\n *\n * Mask allows to control what information will be added to the log line buffer\n * before callback function is invoked. Default mask value is ZF_LOG_PUT_STD.\n */\nvoid zf_log_set_output_v(const unsigned mask, void *const arg,\n\t\t\t\t\t\t const zf_log_output_cb callback);\nstatic _ZF_LOG_INLINE void zf_log_set_output_p(const zf_log_output *const output)\n{\n\tzf_log_set_output_v(output->mask, output->arg, output->callback);\n}\n\n/* Used with _AUX macros and allows to override global format and output\n * facility. Use ZF_LOG_GLOBAL_FORMAT and ZF_LOG_GLOBAL_OUTPUT for values from\n * global configuration. Example:\n *\n *   static const zf_log_output module_output = {\n *       ZF_LOG_PUT_STD, 0, custom_output_callback\n *   };\n *   static const zf_log_spec module_spec = {\n *       ZF_LOG_GLOBAL_FORMAT, &module_output\n *   };\n *   ZF_LOGI_AUX(&module_spec, \"Position: %ix%i\", x, y);\n *\n * See ZF_LOGF_AUX and ZF_LOGF_MEM_AUX for details.\n */\ntypedef struct zf_log_spec\n{\n\tconst zf_log_format *format;\n\tconst zf_log_output *output;\n}\nzf_log_spec;\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Execute log statement if condition is true. Example:\n *\n *   ZF_LOG_IF(1 < 2, ZF_LOGI(\"Log this\"));\n *   ZF_LOG_IF(1 > 2, ZF_LOGI(\"Don't log this\"));\n *\n * Keep in mind though, that if condition can't be evaluated at compile time,\n * then it will be evaluated at run time. This will increase exectuable size\n * and can have noticeable performance overhead. Try to limit conditions to\n * expressions that can be evaluated at compile time.\n */\n#define ZF_LOG_IF(cond, f) do { _ZF_LOG_IF((cond)) { f; } } _ZF_LOG_ONCE\n\n/* Mark log statement as \"secret\". Log statements that are marked as secrets\n * will NOT be executed when censoring is enabled (see ZF_LOG_CENSORED).\n * Example:\n *\n *   ZF_LOG_SECRET(ZF_LOGI(\"Credit card: %s\", credit_card));\n *   ZF_LOG_SECRET(ZF_LOGD_MEM(cipher, cipher_sz, \"Cipher bytes:\"));\n */\n#define ZF_LOG_SECRET(f) ZF_LOG_IF(ZF_LOG_SECRETS, f)\n\n/* Check \"current\" log level at compile time (ignoring \"output\" log level).\n * Evaluates to true when specified log level is enabled. For example:\n *\n *   #if ZF_LOG_ENABLED_DEBUG\n *       const char *const g_enum_strings[] = {\n *           \"enum_value_0\", \"enum_value_1\", \"enum_value_2\"\n *       };\n *   #endif\n *   // ...\n *   #if ZF_LOG_ENABLED_DEBUG\n *       ZF_LOGD(\"enum value: %s\", g_enum_strings[v]);\n *   #endif\n *\n * See ZF_LOG_LEVEL for details.\n */\n#define ZF_LOG_ENABLED(lvl)     ((lvl) >= _ZF_LOG_LEVEL)\n#define ZF_LOG_ENABLED_VERBOSE  ZF_LOG_ENABLED(ZF_LOG_VERBOSE)\n#define ZF_LOG_ENABLED_DEBUG    ZF_LOG_ENABLED(ZF_LOG_DEBUG)\n#define ZF_LOG_ENABLED_INFO     ZF_LOG_ENABLED(ZF_LOG_INFO)\n#define ZF_LOG_ENABLED_WARN     ZF_LOG_ENABLED(ZF_LOG_WARN)\n#define ZF_LOG_ENABLED_ERROR    ZF_LOG_ENABLED(ZF_LOG_ERROR)\n#define ZF_LOG_ENABLED_FATAL    ZF_LOG_ENABLED(ZF_LOG_FATAL)\n\n/* Check \"output\" log level at run time (taking into account \"current\" log\n * level as well). Evaluates to true when specified log level is turned on AND\n * enabled. For example:\n *\n *   if (ZF_LOG_ON_DEBUG)\n *   {\n *       char hash[65];\n *       sha256(data_ptr, data_sz, hash);\n *       ZF_LOGD(\"data: len=%u, sha256=%s\", data_sz, hash);\n *   }\n *\n * See ZF_LOG_OUTPUT_LEVEL for details.\n */\n#define ZF_LOG_ON(lvl) \\\n\t\t(ZF_LOG_ENABLED((lvl)) && (lvl) >= _ZF_LOG_OUTPUT_LEVEL)\n#define ZF_LOG_ON_VERBOSE   ZF_LOG_ON(ZF_LOG_VERBOSE)\n#define ZF_LOG_ON_DEBUG     ZF_LOG_ON(ZF_LOG_DEBUG)\n#define ZF_LOG_ON_INFO      ZF_LOG_ON(ZF_LOG_INFO)\n#define ZF_LOG_ON_WARN      ZF_LOG_ON(ZF_LOG_WARN)\n#define ZF_LOG_ON_ERROR     ZF_LOG_ON(ZF_LOG_ERROR)\n#define ZF_LOG_ON_FATAL     ZF_LOG_ON(ZF_LOG_FATAL)\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern const char *_zf_log_tag_prefix;\nextern zf_log_format _zf_log_global_format;\nextern zf_log_output _zf_log_global_output;\nextern int _zf_log_global_output_lvl;\nextern const zf_log_spec _zf_log_stderr_spec;\n\nvoid _zf_log_write_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);\nvoid _zf_log_write_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(7, 8);\nvoid _zf_log_write(\n\t\tconst int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(3, 4);\nvoid _zf_log_write_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(4, 5);\nvoid _zf_log_write_mem_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(8, 9);\nvoid _zf_log_write_mem_aux_d(\n\t\tconst char *const func, const char *const file, const unsigned line,\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(9, 10);\nvoid _zf_log_write_mem(\n\t\tconst int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(5, 6);\nvoid _zf_log_write_mem_aux(\n\t\tconst zf_log_spec *const log, const int lvl, const char *const tag,\n\t\tconst void *const d, const unsigned d_sz,\n\t\tconst char *const fmt, ...) _ZF_LOG_PRINTFLIKE(6, 7);\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Message logging macros:\n * - ZF_LOGV(\"format string\", args, ...)\n * - ZF_LOGD(\"format string\", args, ...)\n * - ZF_LOGI(\"format string\", args, ...)\n * - ZF_LOGW(\"format string\", args, ...)\n * - ZF_LOGE(\"format string\", args, ...)\n * - ZF_LOGF(\"format string\", args, ...)\n *\n * Memory logging macros:\n * - ZF_LOGV_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGD_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGI_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGW_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGE_MEM(data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGF_MEM(data_ptr, data_sz, \"format string\", args, ...)\n *\n * Auxiliary logging macros:\n * - ZF_LOGV_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGD_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGI_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGW_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGE_AUX(&log_instance, \"format string\", args, ...)\n * - ZF_LOGF_AUX(&log_instance, \"format string\", args, ...)\n *\n * Auxiliary memory logging macros:\n * - ZF_LOGV_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGD_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGI_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGW_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGE_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOGF_MEM_AUX(&log_instance, data_ptr, data_sz, \"format string\", args, ...)\n *\n * Preformatted string logging macros:\n * - ZF_LOGV_STR(\"preformatted string\");\n * - ZF_LOGD_STR(\"preformatted string\");\n * - ZF_LOGI_STR(\"preformatted string\");\n * - ZF_LOGW_STR(\"preformatted string\");\n * - ZF_LOGE_STR(\"preformatted string\");\n * - ZF_LOGF_STR(\"preformatted string\");\n *\n * Explicit log level and tag macros:\n * - ZF_LOG_WRITE(level, tag, \"format string\", args, ...)\n * - ZF_LOG_WRITE_MEM(level, tag, data_ptr, data_sz, \"format string\", args, ...)\n * - ZF_LOG_WRITE_AUX(&log_instance, level, tag, \"format string\", args, ...)\n * - ZF_LOG_WRITE_MEM_AUX(&log_instance, level, tag, data_ptr, data_sz,\n *                        \"format string\", args, ...)\n *\n * Format string follows printf() conventions. Both data_ptr and data_sz could\n * be 0. Tag can be 0 as well. Most compilers will verify that type of arguments\n * match format specifiers in format string.\n *\n * Library assuming UTF-8 encoding for all strings (char *), including format\n * string itself.\n */\n#if ZF_LOG_SRCLOC_NONE == _ZF_LOG_SRCLOC\n\t#define ZF_LOG_WRITE(lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write(lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem(lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_aux(log, lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_aux(log, lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n#else\n\t#define ZF_LOG_WRITE(lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM(lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_AUX(log, lvl, tag, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlog, lvl, tag, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n\t#define ZF_LOG_WRITE_MEM_AUX(log, lvl, tag, d, d_sz, ...) \\\n\t\t\tdo { \\\n\t\t\t\tif (ZF_LOG_ON(lvl)) \\\n\t\t\t\t\t_zf_log_write_mem_aux_d(_ZF_LOG_SRCLOC_FUNCTION, __FILE__, __LINE__, \\\n\t\t\t\t\t\t\tlog, lvl, tag, d, d_sz, __VA_ARGS__); \\\n\t\t\t} _ZF_LOG_ONCE\n#endif\n\nstatic _ZF_LOG_INLINE void _zf_log_unused(const int dummy, ...) {(void)dummy;}\n\n#define _ZF_LOG_UNUSED(...) \\\n\t\tdo { _ZF_LOG_NEVER _zf_log_unused(0, __VA_ARGS__); } _ZF_LOG_ONCE\n\n#if ZF_LOG_ENABLED_VERBOSE\n\t#define ZF_LOGV(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGV_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGV_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGV_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(log, ZF_LOG_VERBOSE, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGV(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGV_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_DEBUG\n\t#define ZF_LOGD(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGD_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGD_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGD_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_DEBUG, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGD(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGD_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_INFO\n\t#define ZF_LOGI(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGI_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGI_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGI_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_INFO, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGI(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGI_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_WARN\n\t#define ZF_LOGW(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGW_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGW_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGW_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_WARN, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGW(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGW_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_ERROR\n\t#define ZF_LOGE(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGE_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGE_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGE_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_ERROR, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGE(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGE_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#if ZF_LOG_ENABLED_FATAL\n\t#define ZF_LOGF(...) \\\n\t\t\tZF_LOG_WRITE(ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGF_AUX(log, ...) \\\n\t\t\tZF_LOG_WRITE_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, __VA_ARGS__)\n\t#define ZF_LOGF_MEM(d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM(ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n\t#define ZF_LOGF_MEM_AUX(log, d, d_sz, ...) \\\n\t\t\tZF_LOG_WRITE_MEM_AUX(log, ZF_LOG_FATAL, _ZF_LOG_TAG, d, d_sz, __VA_ARGS__)\n#else\n\t#define ZF_LOGF(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_MEM(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n\t#define ZF_LOGF_MEM_AUX(...) _ZF_LOG_UNUSED(__VA_ARGS__)\n#endif\n\n#define ZF_LOGV_STR(s) ZF_LOGV(\"%s\", (s))\n#define ZF_LOGD_STR(s) ZF_LOGD(\"%s\", (s))\n#define ZF_LOGI_STR(s) ZF_LOGI(\"%s\", (s))\n#define ZF_LOGW_STR(s) ZF_LOGW(\"%s\", (s))\n#define ZF_LOGE_STR(s) ZF_LOGE(\"%s\", (s))\n#define ZF_LOGF_STR(s) ZF_LOGF(\"%s\", (s))\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/* Output to standard error stream. Library uses it by default, though in few\n * cases it could be necessary to specify it explicitly. For example, when\n * zf_log library is compiled with ZF_LOG_EXTERN_GLOBAL_OUTPUT, application must\n * define and initialize global output variable:\n *\n *   ZF_LOG_DEFINE_GLOBAL_OUTPUT = {ZF_LOG_OUT_STDERR};\n *\n * Another example is when using custom output, stderr could be used as a\n * fallback when custom output facility failed to initialize:\n *\n *   zf_log_set_output_v(ZF_LOG_OUT_STDERR);\n */\nenum { ZF_LOG_OUT_STDERR_MASK = ZF_LOG_PUT_STD };\nvoid zf_log_out_stderr_callback(const zf_log_message *const msg, void *arg);\n#define ZF_LOG_OUT_STDERR ZF_LOG_OUT_STDERR_MASK, 0, zf_log_out_stderr_callback\n\n/* Predefined spec for stderr. Uses global format options (ZF_LOG_GLOBAL_FORMAT)\n * and ZF_LOG_OUT_STDERR. Could be used to force output to stderr for a\n * particular message. Example:\n *\n *   f = fopen(\"foo.log\", \"w\");\n *   if (!f)\n *       ZF_LOGE_AUX(ZF_LOG_STDERR, \"Failed to open log file\");\n */\n#define ZF_LOG_STDERR (&_zf_log_stderr_spec)\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n"
  },
  {
    "path": "zf_log-config.cmake.in",
    "content": "include(\"${CMAKE_CURRENT_LIST_DIR}/zf_log.cmake\")\n"
  }
]