initial project setup
This commit is contained in:
parent
dafd1ae93e
commit
a650630f81
66
.clang-format
Normal file
66
.clang-format
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Generated from CLion C/C++ Code Style settings
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: AcrossComments
|
||||||
|
AlignOperands: true
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
ColumnLimit: 80
|
||||||
|
CompactNamespaces: false
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 0
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
29
.drone.yml
Normal file
29
.drone.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: main
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Tag commit
|
||||||
|
image: alpine
|
||||||
|
commands:
|
||||||
|
- echo This would create a tag
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: develop
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Tag commit
|
||||||
|
image: kitware/cmake
|
||||||
|
commands:
|
||||||
|
- cmake -DCMAKE_BUILD_TYPE=Debug .
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- main
|
||||||
|
...
|
||||||
27
CMakeLists.txt
Normal file
27
CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/project-meta-info.in")
|
||||||
|
|
||||||
|
project(waitui-project
|
||||||
|
VERSION ${project_version}
|
||||||
|
DESCRIPTION ${project_description}
|
||||||
|
HOMEPAGE_URL ${project_homepage}
|
||||||
|
LANGUAGES C
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 17)
|
||||||
|
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
|
||||||
|
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||||
|
include(CTest)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
add_subdirectory(app)
|
||||||
|
add_subdirectory(library/log)
|
||||||
|
|
||||||
|
if ((CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME OR MODERN_CMAKE_BUILD_TESTING)
|
||||||
|
AND BUILD_TESTING)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif ()
|
||||||
@ -1,2 +1,3 @@
|
|||||||
# waitui
|
# waitui
|
||||||
|
|
||||||
|
[](https://drone.riba-interactive.de/rick/waitui)
|
||||||
50
app/CMakeLists.txt
Normal file
50
app/CMakeLists.txt
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||||
|
|
||||||
|
include("project-meta-info.in")
|
||||||
|
|
||||||
|
project(waitui
|
||||||
|
VERSION ${project_version}
|
||||||
|
DESCRIPTION ${project_description}
|
||||||
|
HOMEPAGE_URL ${project_homepage}
|
||||||
|
LANGUAGES C
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(waitui)
|
||||||
|
|
||||||
|
target_sources(waitui
|
||||||
|
PRIVATE
|
||||||
|
"src/main.c"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/include/waitui/version.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(waitui PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/include")
|
||||||
|
|
||||||
|
target_link_libraries(waitui PRIVATE log)
|
||||||
|
|
||||||
|
find_package(Git)
|
||||||
|
if (GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD OUTPUT_VARIABLE SHORT_SHA OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
|
||||||
|
set(REVISION ${SHORT_SHA} CACHE STRING "git short sha" FORCE)
|
||||||
|
|
||||||
|
# only use the plugin to tie the configure state to the sha to force rebuilds
|
||||||
|
# of files that depend on version.h
|
||||||
|
include(GetGitRevisionDescription)
|
||||||
|
get_git_head_revision(REFSPEC COMMITHASH)
|
||||||
|
else ()
|
||||||
|
message(WARNING "Git not found, cannot set version info")
|
||||||
|
set(REVISION "unknown")
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (NOT project_prerelease STREQUAL "")
|
||||||
|
set(WAITUI_VERSION_IS_PRERELEASE ON)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
math(EXPR PROJECT_VERSION_LONG "${PROJECT_VERSION_MAJOR} * 10000 + ${PROJECT_VERSION_MINOR} * 100 + ${PROJECT_VERSION_PATCH}")
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
"include/waitui/version.h.in"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/include/waitui/version.h"
|
||||||
|
@ONLY
|
||||||
|
)
|
||||||
36
app/include/waitui/version.h.in
Normal file
36
app/include/waitui/version.h.in
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* @file version.h
|
||||||
|
* @author rick
|
||||||
|
* @date 30.07.20
|
||||||
|
* @brief File for the Version implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WAITUI_VERSION_H
|
||||||
|
#define WAITUI_VERSION_H
|
||||||
|
|
||||||
|
#define WAITUI_VERSION_NAME "@PROJECT_NAME@"
|
||||||
|
|
||||||
|
#define WAITUI_VERSION_MAJOR "@PROJECT_VERSION_MAJOR@"
|
||||||
|
#define WAITUI_VERSION_MINOR "@PROJECT_VERSION_MINOR@"
|
||||||
|
#define WAITUI_VERSION_PATCH "@PROJECT_VERSION_PATCH@"
|
||||||
|
|
||||||
|
#define WAITUI_VERSION_PRERELEASE "@PROJECT_PRERELEASE@"
|
||||||
|
|
||||||
|
#define WAITUI_VERSION_REVISION "@REVISION@"
|
||||||
|
|
||||||
|
#cmakedefine WAITUI_VERSION_IS_PRERELEASE
|
||||||
|
|
||||||
|
#ifdef WAITUI_VERSION_IS_PRERELEASE
|
||||||
|
#define WAITUI_VERSION_STRING \
|
||||||
|
WAITUI_VERSION_MAJOR "." WAITUI_VERSION_MINOR "." WAITUI_VERSION_PATCH \
|
||||||
|
"-" WAITUI_VERSION_PRERELEASE \
|
||||||
|
"+" WAITUI_VERSION_REVISION
|
||||||
|
#else
|
||||||
|
#define WAITUI_VERSION_STRING \
|
||||||
|
WAITUI_VERSION_MAJOR "." WAITUI_VERSION_MINOR "." WAITUI_VERSION_PATCH \
|
||||||
|
"+" WAITUI_VERSION_REVISION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WAITUI_VERSION_LONG @PROJECT_VERSION_LONG@L
|
||||||
|
|
||||||
|
#endif //WAITUI_VERSION_H
|
||||||
4
app/project-meta-info.in
Normal file
4
app/project-meta-info.in
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(project_version 0.0.1)
|
||||||
|
set(project_description "waitui executable")
|
||||||
|
set(project_homepage "http://example.com")
|
||||||
|
set(project_prerelease "")
|
||||||
163
app/src/main.c
Normal file
163
app/src/main.c
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
#include "waitui/version.h"
|
||||||
|
|
||||||
|
#include <waitui/log.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local defines
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define WAITUI_SUCCESS 0
|
||||||
|
#define WAITUI_FAILURE 1
|
||||||
|
#define WAITUI_MEMORY_ERROR 2
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static const char * waitui_shortOptions = "vhqd::";
|
||||||
|
static const struct option waitui_longOptions[] = {
|
||||||
|
{"version", no_argument, 0, 'v'},
|
||||||
|
{"help", no_argument, 0, 'h'},
|
||||||
|
{"quiet", no_argument, 0, 'q'},
|
||||||
|
{"debug", optional_argument, 0,'d'},
|
||||||
|
0
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#define waitui_printLogo(s) \
|
||||||
|
do { \
|
||||||
|
fprintf((s), "\n"); \
|
||||||
|
fprintf((s), "\n"); \
|
||||||
|
fprintf((s), " ___ __ \n"); \
|
||||||
|
fprintf((s), " (_ ( . ) )__ -.- '. \\ : / .' \n"); \
|
||||||
|
fprintf((s), " '(___(_____) -.- '. \\ : / .' \n"); \
|
||||||
|
fprintf((s), " '. \\ : / .' \n"); \
|
||||||
|
fprintf((s), " __ -----____ _ _____----- \n"); \
|
||||||
|
fprintf((s), "_________________/. _\\________________________________(_)______________________\n"); \
|
||||||
|
fprintf((s), " .--.|/_/__ \n"); \
|
||||||
|
fprintf((s), " ''.--o/___ \\ ~ ~ ,-----------------------, \n"); \
|
||||||
|
fprintf((s), " ~ /.'o|_o '.| ~ | | \n"); \
|
||||||
|
fprintf((s), " |/ |_| ~ | Waitui | \n"); \
|
||||||
|
fprintf((s), " ~ ' |_| ~ | by Rick | \n"); \
|
||||||
|
fprintf((s), " __|_|-;.___.;--.,___ | | \n"); \
|
||||||
|
fprintf((s), " ~ _,,-\"\" |_| \"\"-,,_ `------------------------' \n"); \
|
||||||
|
fprintf((s), " .-'´'´ |_| ``-. ~ \n"); \
|
||||||
|
fprintf((s), " \", |_| ,\" ~ \n"); \
|
||||||
|
fprintf((s), " \"-_ _-\" ~ \n"); \
|
||||||
|
fprintf((s), " ~ ``----..,_ , __,,..---'´ ~ ~ \n"); \
|
||||||
|
fprintf((s), " ```'''''' ~ ~ \n"); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print version.
|
||||||
|
* @param[in] stream Where the version should be printed
|
||||||
|
* @param logo Whether to print the logo
|
||||||
|
*/
|
||||||
|
void waitui_printVersion(FILE *stream, int logo) {
|
||||||
|
fprintf(stream, "%s version %s", WAITUI_VERSION_NAME,
|
||||||
|
WAITUI_VERSION_STRING);
|
||||||
|
|
||||||
|
if (logo) { waitui_printLogo(stream); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Print help.
|
||||||
|
* @param[in] stream Where the help should be printed
|
||||||
|
*/
|
||||||
|
void waitui_printHelp(FILE *stream) {
|
||||||
|
waitui_printVersion(stream, 0);
|
||||||
|
|
||||||
|
fprintf(stream, "\n\n");
|
||||||
|
fprintf(stream, "Usage: %s[-hvq] [-d level]\n", WAITUI_VERSION_NAME);
|
||||||
|
fprintf(stream, "\t--help, -h \t\tDisplays this help\n");
|
||||||
|
fprintf(stream, "\t--version, -v \t\tDisplays the version\n");
|
||||||
|
fprintf(stream, "\t--quiet, -q \t\tDisplays the version\n");
|
||||||
|
fprintf(stream, "\t--debug=level, -d level\t\tDisplays the version\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Main function
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int result = WAITUI_SUCCESS;
|
||||||
|
|
||||||
|
bool quite = false;
|
||||||
|
long loglevel = WAITUI_LOG_DEBUG;
|
||||||
|
|
||||||
|
waitui_log_setQuiet(quite);
|
||||||
|
waitui_log_setLevel(loglevel);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int index = -1;
|
||||||
|
struct option *opt = NULL;
|
||||||
|
|
||||||
|
int optRes = getopt_long(argc, argv, waitui_shortOptions,
|
||||||
|
waitui_longOptions, &index);
|
||||||
|
if (optRes == -1) break; /* end of list */
|
||||||
|
switch (optRes) {
|
||||||
|
case 'v':
|
||||||
|
waitui_printVersion(stdout, 1);
|
||||||
|
return WAITUI_SUCCESS;
|
||||||
|
case 'h':
|
||||||
|
waitui_printHelp(stdout);
|
||||||
|
return WAITUI_SUCCESS;
|
||||||
|
case 'q':
|
||||||
|
quite = true;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
if (optarg) {
|
||||||
|
char *endPtr = NULL;
|
||||||
|
errno = 0;
|
||||||
|
loglevel = strtol(optarg, &endPtr, 10);
|
||||||
|
if (errno != 0 || endPtr == optarg ||
|
||||||
|
loglevel < WAITUI_LOG_TRACE ||
|
||||||
|
loglevel >= WAITUI_LOG_MAX) {
|
||||||
|
waitui_log_warn(
|
||||||
|
"no valid log level given or out of range "
|
||||||
|
"(%d - %d): %s",
|
||||||
|
WAITUI_LOG_TRACE, WAITUI_LOG_MAX - 1, optarg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* all parameter that do not appear in the option string */
|
||||||
|
opt = (struct option *) &(waitui_longOptions[index]);
|
||||||
|
printf("'%s' was specified.", opt->name);
|
||||||
|
if (opt->has_arg == required_argument)
|
||||||
|
printf("Arg: <%s>", optarg);
|
||||||
|
printf("\n");
|
||||||
|
break;
|
||||||
|
default: /* unknown */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* print all others parameters */
|
||||||
|
while (optind < argc) { printf("other parameter: <%s>\n", argv[optind++]); }
|
||||||
|
|
||||||
|
waitui_log_setQuiet(quite);
|
||||||
|
waitui_log_setLevel(loglevel);
|
||||||
|
|
||||||
|
waitui_log_debug("waitui start execution");
|
||||||
|
|
||||||
|
waitui_log_debug("waitui execution done");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
35
cmake/FetchCMocka.cmake
Normal file
35
cmake/FetchCMocka.cmake
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Copyright 2020 OLIVIER LE DOEUFF
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
# and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
# including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
# subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
# substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||||
|
# THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
cmocka
|
||||||
|
GIT_REPOSITORY https://git.cryptomilk.org/projects/cmocka.git
|
||||||
|
GIT_TAG cmocka-1.1.5
|
||||||
|
GIT_SHALLOW 1
|
||||||
|
)
|
||||||
|
|
||||||
|
set(WITH_STATIC_LIB ON CACHE BOOL "CMocka: Build with a static library" FORCE)
|
||||||
|
set(WITH_CMOCKERY_SUPPORT OFF CACHE BOOL "CMocka: Install a cmockery header" FORCE)
|
||||||
|
set(WITH_EXAMPLES OFF CACHE BOOL "CMocka: Build examples" FORCE)
|
||||||
|
set(UNIT_TESTING OFF CACHE BOOL "CMocka: Build with unit testing" FORCE)
|
||||||
|
set(PICKY_DEVELOPER OFF CACHE BOOL "CMocka: Build with picky developer flags" FORCE)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(cmocka)
|
||||||
274
cmake/GetGitRevisionDescription.cmake
Normal file
274
cmake/GetGitRevisionDescription.cmake
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
# - Returns a version string from Git
|
||||||
|
#
|
||||||
|
# These functions force a re-configure on each git commit so that you can
|
||||||
|
# trust the values of the variables in your build system.
|
||||||
|
#
|
||||||
|
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
|
||||||
|
#
|
||||||
|
# Returns the refspec and sha hash of the current head revision
|
||||||
|
#
|
||||||
|
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the source tree, and adjusting
|
||||||
|
# the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe on the working tree (--dirty option),
|
||||||
|
# and adjusting the output so that it tests false if an error occurs.
|
||||||
|
#
|
||||||
|
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||||
|
#
|
||||||
|
# Returns the results of git describe --exact-match on the source tree,
|
||||||
|
# and adjusting the output so that it tests false if there was no exact
|
||||||
|
# matching tag.
|
||||||
|
#
|
||||||
|
# git_local_changes(<var>)
|
||||||
|
#
|
||||||
|
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
|
||||||
|
# Uses the return code of "git diff-index --quiet HEAD --".
|
||||||
|
# Does not regard untracked files.
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
#
|
||||||
|
# Copyright 2009-2013, Iowa State University.
|
||||||
|
# Copyright 2013-2020, Ryan Pavlik
|
||||||
|
# Copyright 2013-2020, Contributors
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
if(__get_git_revision_description)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(__get_git_revision_description YES)
|
||||||
|
|
||||||
|
# We must run the following at "include" time, not at function call time,
|
||||||
|
# to find the path to this module rather than the path to a calling list file
|
||||||
|
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||||
|
|
||||||
|
# Function _git_find_closest_git_dir finds the next closest .git directory
|
||||||
|
# that is part of any directory in the path defined by _start_dir.
|
||||||
|
# The result is returned in the parent scope variable whose name is passed
|
||||||
|
# as variable _git_dir_var. If no .git directory can be found, the
|
||||||
|
# function returns an empty string via _git_dir_var.
|
||||||
|
#
|
||||||
|
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
|
||||||
|
# neither foo nor bar contain a file/directory .git. This wil return
|
||||||
|
# C:/bla/.git
|
||||||
|
#
|
||||||
|
function(_git_find_closest_git_dir _start_dir _git_dir_var)
|
||||||
|
set(cur_dir "${_start_dir}")
|
||||||
|
set(git_dir "${_start_dir}/.git")
|
||||||
|
while(NOT EXISTS "${git_dir}")
|
||||||
|
# .git dir not found, search parent directories
|
||||||
|
set(git_previous_parent "${cur_dir}")
|
||||||
|
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
|
||||||
|
if(cur_dir STREQUAL git_previous_parent)
|
||||||
|
# We have reached the root directory, we are not in git
|
||||||
|
set(${_git_dir_var}
|
||||||
|
""
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(git_dir "${cur_dir}/.git")
|
||||||
|
endwhile()
|
||||||
|
set(${_git_dir_var}
|
||||||
|
"${git_dir}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(get_git_head_revision _refspecvar _hashvar)
|
||||||
|
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
|
||||||
|
|
||||||
|
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
|
||||||
|
else()
|
||||||
|
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
|
||||||
|
endif()
|
||||||
|
if(NOT "${GIT_DIR}" STREQUAL "")
|
||||||
|
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
|
||||||
|
"${GIT_DIR}")
|
||||||
|
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
|
||||||
|
# We've gone above the CMake root dir.
|
||||||
|
set(GIT_DIR "")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
if("${GIT_DIR}" STREQUAL "")
|
||||||
|
set(${_refspecvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"GITDIR-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Check if the current source dir is a git submodule or a worktree.
|
||||||
|
# In both cases .git is a file instead of a directory.
|
||||||
|
#
|
||||||
|
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||||
|
# The following git command will return a non empty string that
|
||||||
|
# points to the super project working tree if the current
|
||||||
|
# source dir is inside a git submodule.
|
||||||
|
# Otherwise the command will return an empty string.
|
||||||
|
#
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" rev-parse
|
||||||
|
--show-superproject-working-tree
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT "${out}" STREQUAL "")
|
||||||
|
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
|
||||||
|
file(READ ${GIT_DIR} submodule)
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
|
||||||
|
${submodule})
|
||||||
|
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
|
||||||
|
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||||
|
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
|
||||||
|
ABSOLUTE)
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
else()
|
||||||
|
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
|
||||||
|
file(READ ${GIT_DIR} worktree_ref)
|
||||||
|
# The .git directory contains a path to the worktree information directory
|
||||||
|
# inside the parent git repo of the worktree.
|
||||||
|
#
|
||||||
|
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
|
||||||
|
${worktree_ref})
|
||||||
|
string(STRIP ${git_worktree_dir} git_worktree_dir)
|
||||||
|
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
|
||||||
|
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
|
||||||
|
endif()
|
||||||
|
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||||
|
if(NOT EXISTS "${GIT_DATA}")
|
||||||
|
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||||
|
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
|
||||||
|
|
||||||
|
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
|
||||||
|
"${GIT_DATA}/grabRef.cmake" @ONLY)
|
||||||
|
include("${GIT_DATA}/grabRef.cmake")
|
||||||
|
|
||||||
|
set(${_refspecvar}
|
||||||
|
"${HEAD_REF}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
set(${_hashvar}
|
||||||
|
"${HEAD_HASH}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_describe_working_tree _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(NOT res EQUAL 0)
|
||||||
|
set(out "${out}-${res}-NOTFOUND")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_get_exact_tag _var)
|
||||||
|
git_describe(out --exact-match ${ARGN})
|
||||||
|
set(${_var}
|
||||||
|
"${out}"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(git_local_changes _var)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
find_package(Git QUIET)
|
||||||
|
endif()
|
||||||
|
get_git_head_revision(refspec hash)
|
||||||
|
if(NOT GIT_FOUND)
|
||||||
|
set(${_var}
|
||||||
|
"GIT-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
if(NOT hash)
|
||||||
|
set(${_var}
|
||||||
|
"HEAD-HASH-NOTFOUND"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
|
||||||
|
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
RESULT_VARIABLE res
|
||||||
|
OUTPUT_VARIABLE out
|
||||||
|
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
if(res EQUAL 0)
|
||||||
|
set(${_var}
|
||||||
|
"CLEAN"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
else()
|
||||||
|
set(${_var}
|
||||||
|
"DIRTY"
|
||||||
|
PARENT_SCOPE)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
43
cmake/GetGitRevisionDescription.cmake.in
Normal file
43
cmake/GetGitRevisionDescription.cmake.in
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
# Internal file for GetGitRevisionDescription.cmake
|
||||||
|
#
|
||||||
|
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||||
|
#
|
||||||
|
# Original Author:
|
||||||
|
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||||
|
# http://academic.cleardefinition.com
|
||||||
|
# Iowa State University HCI Graduate Program/VRAC
|
||||||
|
#
|
||||||
|
# Copyright 2009-2012, Iowa State University
|
||||||
|
# Copyright 2011-2015, Contributors
|
||||||
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
|
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
|
# http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
# SPDX-License-Identifier: BSL-1.0
|
||||||
|
|
||||||
|
set(HEAD_HASH)
|
||||||
|
|
||||||
|
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||||
|
|
||||||
|
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||||
|
if(HEAD_CONTENTS MATCHES "ref")
|
||||||
|
# named branch
|
||||||
|
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||||
|
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||||
|
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
else()
|
||||||
|
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
|
||||||
|
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
|
||||||
|
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
|
||||||
|
set(HEAD_HASH "${CMAKE_MATCH_1}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
# detached HEAD
|
||||||
|
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT HEAD_HASH)
|
||||||
|
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||||
|
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||||
|
endif()
|
||||||
22
library/log/CMakeLists.txt
Normal file
22
library/log/CMakeLists.txt
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
|
||||||
|
|
||||||
|
include("project-meta-info.in")
|
||||||
|
|
||||||
|
project(waitui-log
|
||||||
|
VERSION ${project_version}
|
||||||
|
DESCRIPTION ${project_description}
|
||||||
|
HOMEPAGE_URL ${project_homepage}
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
add_library(log OBJECT)
|
||||||
|
|
||||||
|
target_sources(log
|
||||||
|
PRIVATE
|
||||||
|
"src/log.c"
|
||||||
|
PUBLIC
|
||||||
|
"include/waitui/log.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(log PUBLIC "include")
|
||||||
|
|
||||||
|
target_compile_definitions(log PUBLIC "LOG_USE_COLOR")
|
||||||
130
library/log/include/waitui/log.h
Normal file
130
library/log/include/waitui/log.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
* @file log.h
|
||||||
|
* @author rick
|
||||||
|
* @date 28.08.20
|
||||||
|
* @brief File for the Log implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WAITUI_LOG_H
|
||||||
|
#define WAITUI_LOG_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Public types
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The type for log events.
|
||||||
|
*/
|
||||||
|
typedef struct waitui_log_event {
|
||||||
|
va_list ap;
|
||||||
|
const char *format;
|
||||||
|
const char *file;
|
||||||
|
int line;
|
||||||
|
struct tm *time;
|
||||||
|
int level;
|
||||||
|
void *userData;
|
||||||
|
} waitui_log_event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The logging callback function type.
|
||||||
|
*/
|
||||||
|
typedef void (*waitui_log_logging_fn)(waitui_log_event *event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The locking callback function type.
|
||||||
|
*/
|
||||||
|
typedef void (*waitui_log_lock_fn)(bool lock, void *userData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The different log levels.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
WAITUI_LOG_TRACE,
|
||||||
|
WAITUI_LOG_DEBUG,
|
||||||
|
WAITUI_LOG_INFO,
|
||||||
|
WAITUI_LOG_WARN,
|
||||||
|
WAITUI_LOG_ERROR,
|
||||||
|
WAITUI_LOG_FATAL,
|
||||||
|
WAITUI_LOG_MAX,
|
||||||
|
} waitui_log_level;
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Public defines
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define waitui_log_trace(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define waitui_log_debug(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define waitui_log_info(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define waitui_log_warn(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_WARN, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define waitui_log_error(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#define waitui_log_fatal(...) \
|
||||||
|
waitui_log_writeLog(WAITUI_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set locking function for log.
|
||||||
|
* @param lockFn The function to be called for lock and unlock when writing logs
|
||||||
|
* @param[in] userData Extra user data to pass to the locking function
|
||||||
|
*/
|
||||||
|
extern void waitui_log_set_lock(waitui_log_lock_fn lockFn, void *userData);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Set minimum log level to log on stderr.
|
||||||
|
* @param level The minimum log level from which on log appear on stderr
|
||||||
|
*/
|
||||||
|
extern void waitui_log_setLevel(waitui_log_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disable or enable logging to stderr.
|
||||||
|
* @param enable True to disable logging to stderr, false to enable
|
||||||
|
*/
|
||||||
|
extern void waitui_log_setQuiet(bool enable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add the logFn as a log callback to write logs starting at the level.
|
||||||
|
* @param logFn The function to add as a log callback
|
||||||
|
* @param[in] userData Extra user data to pass to the logFn
|
||||||
|
* @param level The level from which on this log callback is executed
|
||||||
|
* @retval 1 Successful added the callback
|
||||||
|
* @retval 0 No more space to add the callback
|
||||||
|
*/
|
||||||
|
extern int waitui_log_addCallback(waitui_log_logging_fn logFn, void *userData,
|
||||||
|
waitui_log_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a log callback to write logs starting at the level into the file.
|
||||||
|
* @param[in] file The file into which to write the log
|
||||||
|
* @param level The level from which on this log callback is executed
|
||||||
|
* @retval 1 Successful added the file callback
|
||||||
|
* @retval 0 No more space to add the callback
|
||||||
|
*/
|
||||||
|
extern int waitui_log_addFile(FILE *file, waitui_log_level level);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write the log message to log with the given parameters.
|
||||||
|
* @param level The log level for this message
|
||||||
|
* @param[in] file The filename where this log is written
|
||||||
|
* @param line The line number where this log is written
|
||||||
|
* @param[in] format The message to write to the log
|
||||||
|
* @param ... Extra values to be used inside the message
|
||||||
|
*/
|
||||||
|
extern void waitui_log_writeLog(waitui_log_level level, const char *file,
|
||||||
|
int line, const char *format, ...);
|
||||||
|
|
||||||
|
#endif//WAITUI_LOG_H
|
||||||
3
library/log/project-meta-info.in
Normal file
3
library/log/project-meta-info.in
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
set(project_version 0.0.1)
|
||||||
|
set(project_description "waitui waitui_log library")
|
||||||
|
set(project_homepage "http://example.com")
|
||||||
224
library/log/src/log.c
Normal file
224
library/log/src/log.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/**
|
||||||
|
* @file log.c
|
||||||
|
* @author rick
|
||||||
|
* @date 28.08.20
|
||||||
|
* @brief File for the Log implementation
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "waitui/log.h"
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local defines
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The maximum number of possible callbacks to register.
|
||||||
|
*/
|
||||||
|
#define MAX_CALLBACKS 32
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local types
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Internal type to store the log callback function with all its info.
|
||||||
|
*/
|
||||||
|
typedef struct waitui_log_callback {
|
||||||
|
waitui_log_logging_fn logFn;
|
||||||
|
waitui_log_level level;
|
||||||
|
void *userData;
|
||||||
|
} waitui_log_callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Internal type to store the log with all its info.
|
||||||
|
*/
|
||||||
|
typedef struct waitui_log {
|
||||||
|
waitui_log_lock_fn lockFn;
|
||||||
|
waitui_log_level level;
|
||||||
|
bool quiet;
|
||||||
|
waitui_log_callback callbacks[MAX_CALLBACKS];
|
||||||
|
void *userData;
|
||||||
|
} log;
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local variables
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The internal state of the log lib.
|
||||||
|
*/
|
||||||
|
static struct waitui_log L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief String representations of the log levels.
|
||||||
|
*/
|
||||||
|
static const char *waitui_log_level_strings[] = {
|
||||||
|
"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
/**
|
||||||
|
* @brief Color representations of the log levels.
|
||||||
|
*/
|
||||||
|
static const char *waitui_log_level_colors[] = {
|
||||||
|
"\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m",
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Local functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the string representations of the log level.
|
||||||
|
* @param level The level to return as a string.
|
||||||
|
* @return The string representations of the log level or empty when out of bounds.
|
||||||
|
*/
|
||||||
|
static inline const char *waitui_log_levelAsString(waitui_log_level level) {
|
||||||
|
if (level < WAITUI_LOG_TRACE || level >= WAITUI_LOG_MAX) { return ""; }
|
||||||
|
return waitui_log_level_strings[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return the color representations of the log level.
|
||||||
|
* @param level The level to return as a color.
|
||||||
|
* @return The color representations of the log level or empty when out of bounds.
|
||||||
|
*/
|
||||||
|
static inline const char *waitui_log_levelAsColor(waitui_log_level level) {
|
||||||
|
if (level < WAITUI_LOG_TRACE || level >= WAITUI_LOG_MAX) { return ""; }
|
||||||
|
return waitui_log_level_colors[level];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the locking callback function to get the lock.
|
||||||
|
*/
|
||||||
|
static inline void waitui_log_lock(void) {
|
||||||
|
if (L.lockFn) { L.lockFn(true, L.userData); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calls the locking callback function to release the lock.
|
||||||
|
*/
|
||||||
|
static inline void waitui_log_unlock(void) {
|
||||||
|
if (L.lockFn) { L.lockFn(false, L.userData); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback that write the log event to the console.
|
||||||
|
* @param[in] event log event to write to the console
|
||||||
|
*/
|
||||||
|
static void waitui_log_console_callback(waitui_log_event *event) {
|
||||||
|
char buffer[16];
|
||||||
|
buffer[strftime(buffer, sizeof(buffer), "%H:%M:%S", event->time)] = '\0';
|
||||||
|
|
||||||
|
#ifdef LOG_USE_COLOR
|
||||||
|
fprintf(event->userData, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buffer,
|
||||||
|
waitui_log_levelAsColor(event->level),
|
||||||
|
waitui_log_levelAsString(event->level), event->file, event->line);
|
||||||
|
#else
|
||||||
|
fprintf(event->userData, "%s %-5s %s:%d: ", buffer,
|
||||||
|
waitui_log_levelAsString(event->level), event->file, event->line);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vfprintf(event->userData, event->format, event->ap);
|
||||||
|
fprintf(event->userData, "\n");
|
||||||
|
fflush(event->userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Callback that write the log event to a file.
|
||||||
|
* @param[in] event log event to write to a file
|
||||||
|
*/
|
||||||
|
static void waitui_log_file_callback(waitui_log_event *event) {
|
||||||
|
char buffer[64];
|
||||||
|
buffer[strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", event->time)] =
|
||||||
|
'\0';
|
||||||
|
|
||||||
|
fprintf(event->userData, "%s %-5s %s:%d: ", buffer,
|
||||||
|
waitui_log_levelAsString(event->level), event->file, event->line);
|
||||||
|
|
||||||
|
vfprintf(event->userData, event->format, event->ap);
|
||||||
|
fprintf(event->userData, "\n");
|
||||||
|
fflush(event->userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initializes the log event with time and userdata.
|
||||||
|
* @param[in,out] event log event to write to initialize
|
||||||
|
* @param[in] user_data user data to set for the log event
|
||||||
|
*/
|
||||||
|
static inline void waitui_log_init_event(waitui_log_event *event,
|
||||||
|
void *userData) {
|
||||||
|
if (!event->time) {
|
||||||
|
time_t t = time(NULL);
|
||||||
|
event->time = localtime(&t);
|
||||||
|
}
|
||||||
|
|
||||||
|
event->userData = userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Public functions
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void waitui_log_set_lock(waitui_log_lock_fn lockFn, void *userData) {
|
||||||
|
L.lockFn = lockFn;
|
||||||
|
L.userData = userData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitui_log_setLevel(waitui_log_level level) { L.level = level; }
|
||||||
|
|
||||||
|
void waitui_log_setQuiet(bool enable) { L.quiet = enable; }
|
||||||
|
|
||||||
|
int waitui_log_addCallback(waitui_log_logging_fn logFn, void *userData,
|
||||||
|
waitui_log_level level) {
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS; ++i) {
|
||||||
|
if (!L.callbacks[i].logFn) {
|
||||||
|
L.callbacks[i] = (waitui_log_callback){.logFn = logFn,
|
||||||
|
.userData = userData,
|
||||||
|
.level = level};
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int waitui_log_addFile(FILE *file, waitui_log_level level) {
|
||||||
|
return waitui_log_addCallback(waitui_log_file_callback, file, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
void waitui_log_writeLog(waitui_log_level level, const char *file, int line,
|
||||||
|
const char *format, ...) {
|
||||||
|
waitui_log_event event = {
|
||||||
|
.format = format,
|
||||||
|
.file = file,
|
||||||
|
.line = line,
|
||||||
|
.level = level,
|
||||||
|
};
|
||||||
|
|
||||||
|
waitui_log_lock();
|
||||||
|
|
||||||
|
if (!L.quiet && level >= L.level) {
|
||||||
|
waitui_log_init_event(&event, stderr);
|
||||||
|
va_start(event.ap, format);
|
||||||
|
waitui_log_console_callback(&event);
|
||||||
|
va_end(event.ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].logFn; ++i) {
|
||||||
|
waitui_log_callback *cb = &L.callbacks[i];
|
||||||
|
if (level >= cb->level) {
|
||||||
|
waitui_log_init_event(&event, cb->userData);
|
||||||
|
va_start(event.ap, format);
|
||||||
|
cb->logFn(&event);
|
||||||
|
va_end(event.ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
waitui_log_unlock();
|
||||||
|
}
|
||||||
3
project-meta-info.in
Normal file
3
project-meta-info.in
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
set(project_version 0.0.1)
|
||||||
|
set(project_description "waitui language system")
|
||||||
|
set(project_homepage "http://example.com")
|
||||||
3
tests/CMakeLists.txt
Normal file
3
tests/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
include(../cmake/FetchCMocka.cmake)
|
||||||
|
|
||||||
|
#add_subdirectory()
|
||||||
Loading…
Reference in New Issue
Block a user