initial project setup

This commit is contained in:
Rick Barenthin 2022-01-20 23:49:46 +01:00
parent dafd1ae93e
commit a650630f81
17 changed files with 1113 additions and 0 deletions

66
.clang-format Normal file
View 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
View 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
View 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 ()

View File

@ -1,2 +1,3 @@
# waitui
[![Build Status](https://drone.riba-interactive.de/api/badges/rick/waitui/status.svg?ref=refs/heads/main)](https://drone.riba-interactive.de/rick/waitui)

50
app/CMakeLists.txt Normal file
View 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
)

View 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
View 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
View 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
View 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)

View 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()

View 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()

View 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")

View 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

View 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
View 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
View 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
View File

@ -0,0 +1,3 @@
include(../cmake/FetchCMocka.cmake)
#add_subdirectory()