shayla

a simple yet fast static site builder
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/shayla

commit bfd9b03284a64a0963da9ec9c4819a27010c73b9
Author: Louis Solofrizzo <lsolofrizzo@online.net>
Date:   Mon, 27 Aug 2018 15:10:10 +0200

Log: Add various log functions and macros

This commit do introduce various helpers on logging inside shayla. I've
also imported my 'utils.h' file, which I do not use much at the moment,
but will come handy in the future. As for the log helpers:

Simple log macros:
- INFO
- WARNING
- ERROR
- FATAL
- DEBUG

I've also added a more 'complex' API for progressions. The code is well
documented, but I'll describe the basics here:

One can start a progression with PROGRESS_BEGIN(). This macro takes a
printf-like format, aswell as all of the macros in this API. Once the
progress has begun, and the huge task is underway, one can update the
displayed message with PROGRESS_UPDATE(). If one encounter an error in
the progression, the status and message can be updated with
PROGRESS_ERROR(). Otherwise, one can terminate the progression with
PROGRESS_DONE(). Here's a simple example:

> PROGRESS_BEGIN("Massive allocation...");
>
> for (size_t i = 0; i < 100000; i++)
> {
>     char *ptr = malloc(2048);
>     if (ptr == NULL)
>     {
>         PROGRESS_ERROR("Cannot allocate memory");
>         return ;
>     }
>
>     PROGRESS_UPDATE("Chunk %zu allocated", i);
>     usleep(200);
> }
>
> PROGRESS_DONE();

Signed-off-by: Louis Solofrizzo <lsolofrizzo@online.net>

Diffstat:
A.gitignore | 1+
ACMakeLists.txt | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alog.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alog.h | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.c | 39+++++++++++++++++++++++++++++++++++++++
Autils.h | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 383 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/CMakeLists.txt b/CMakeLists.txt @@ -0,0 +1,55 @@ +cmake_minimum_required(VERSION 3.4) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message (FATAL_ERROR "Don't use 'cmake .' Create a build folder first") +endif (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + +set(SDOW_NAME "shayla") +set(SDOWN_MAJOR "1") +set(SDOWN_MINOR "0") + +add_compile_options("-Wall;-Wextra;-Werror;-Wno-unused-parameter;-Wno-unused-result;-O3;-g") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexceptions") # Enable table-based thread cancellation +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector") # Compile / Run time stack protection +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pipe") # Avoid temporary files, speeding up builds +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2") # Run-time buffer overflow detection +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=format-security") # Reject potentially unsafe format string arguents +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow") # Don't shadow variables +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunreachable-code") # Warn if the compiler detects that code will never be executed +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-enum") # Force a switch on an enum to have all the cases possible + +set(CMAKE_C_STANDARD 99) +set(CMAKE_C_STANDARD_REQUIRED ON) + +#SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -g") + +add_definitions(-DSDOWN_NAME="${SDOW_NAME}") +add_definitions(-DSDOWN_MAJOR="${SDOWN_MAJOR}") +add_definitions(-DSDOWN_MINOR="${SDOWN_MINOR}") + +include_directories(".") +include_directories("./sundown/src") +include_directories("./sundown/html") + +link_libraries(pthread) + +add_executable(${SDOW_NAME} main.c + #args.c + #file.c + #parser.c + #parse_header.c + log.c +# site.c + #./sundown/src/autolink.c + #./sundown/src/buffer.c + #./sundown/src/markdown.c + #./sundown/html/html.c + #./sundown/html/html_smartypants.c + #./sundown/html/houdini_href_e.c + #./sundown/html/houdini_html_e.c + #./sundown/src/stack.c +) diff --git a/log.c b/log.c @@ -0,0 +1,103 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <log.h> +#include <pthread.h> + +static bool g_debug = false; +static pthread_t thread_progress = { 0 }; +static pthread_mutex_t msg_lock = { 0 }; +static char *spinners[] = { "⠋", "⠙","⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" }; +static int spinner_count = 0; +static char msg[2048] = EMPTY_STR(); +static bool run = false; + +void set_debug(bool val) +{ + g_debug = val; +} + +bool get_debug(void) +{ + return g_debug; +} + +static void *progress_function(void *unused) +{ + UNUSED_ARG(unused); + + for (size_t i = 0; run; i++) + { + pthread_mutex_lock(&msg_lock); + fprintf(stdout, "\r" COLOR_INFO "%s" COLOR_RESET " %s", + spinners[spinner_count], msg); + pthread_mutex_unlock(&msg_lock); + + if (i % 80 == 0 && i != 0) + spinner_count++; + + if (spinner_count == COUNT_OF(spinners)) + spinner_count = 0; + + fflush(stdout); + usleep(800); + } + + return NULL; +} + +static void update_msg(const char *str, va_list *ap) +{ + pthread_mutex_lock(&msg_lock); + vsnprintf(msg, sizeof(msg), str, *ap); + pthread_mutex_unlock(&msg_lock); +} + +void progress_begin(const char *str, ...) +{ + va_list ap; + + pthread_mutex_init(&msg_lock, NULL); + + va_start(ap, str); + update_msg(str, &ap); + va_end(ap); + + run = true; + pthread_create(&thread_progress, NULL, progress_function, NULL); +} + +void progress_update(const char *str, ...) +{ + va_list ap; + + va_start(ap, str); + update_msg(str, &ap); + va_end(ap); +} + +void progress_end(bool result) +{ + run = false; + pthread_join(thread_progress, NULL); + + if (result) + fprintf(stdout, "\r" SYMBOL_INFO " %s\n", msg); + else + fprintf(stderr, "\r" SYMBOL_ERROR " %s\n", msg); + + pthread_mutex_destroy(&msg_lock); + spinner_count = 0; +} diff --git a/log.h b/log.h @@ -0,0 +1,105 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef LOG_H +# define LOG_H + +# include <stdio.h> +# include <stdbool.h> +# include <utils.h> +# include <stdarg.h> + +# define COLOR_OK "\e[1;32m" +# define COLOR_DEBUG "\e[1;39m" +# define COLOR_INFO "\e[1;34m" +# define COLOR_WARNING "\e[1;33m" +# define COLOR_ERROR "\e[1;31m" +# define COLOR_FATAL COLOR_ERROR +# define COLOR_RESET "\e[0m" + +# define SYMBOL_OK COLOR_OK "✓" COLOR_RESET +# define SYMBOL_DEBUG COLOR_DEBUG "…" COLOR_RESET +# define SYMBOL_INFO COLOR_INFO "»" COLOR_RESET +# define SYMBOL_WARNING COLOR_WARNING "!" COLOR_RESET +# define SYMBOL_ERROR COLOR_ERROR "✘" COLOR_RESET +# define SYMBOL_FATAL COLOR_FATAL "✘ FATAL" COLOR_RESET + +# define INFO(str, ...) fprintf(stdout, SYMBOL_INFO " " str, ##__VA_ARGS__) +# define WARNING(str, ...) fprintf(stdout, SYMBOL_WARNING " " str, ##__VA_ARGS__) +# define ERROR(str, ...) fprintf(stderr, SYMBOL_ERROR " " str, ##__VA_ARGS__) +# define FATAL(str, ...) fprintf(stderr, SYMBOL_FATAL " " str, ##__VA_ARGS__) +# define DEBUG(str, ...) \ + do { \ + if (GET_DEBUG()) \ + fprintf(stdout, \ + SYMBOL_DEBUG " " __FILE__ ":" STR(__LINE__) ": " str, \ + ##__VA_ARGS__); \ + } while (0) + +/*! + * \brief Set the debug mode + * + * \param[in] val Debug mode value + */ +# define SET_DEBUG set_debug +void set_debug(bool val); + +/*! + * \brief Get the debug mode + */ +# define GET_DEBUG get_debug +bool get_debug(void); + +/*! + * \brief Begin a spinner progress thread + * + * \param[in] str Printf format-like string + * + * \note A new thread will be created + */ +# define PROGRESS_BEGIN(str, ...) progress_begin(str, ##__VA_ARGS__) +void progress_begin(const char *str, ...); + +/*! + * \brief Update the progress message + * + * \param[in] str Printf format-like string + * + * \note This function will take a lock on the message string + */ +# define PROGRESS_UPDATE(str, ...) progress_update(str, ##__VA_ARGS__) +void progress_update(const char *str, ...); + +/*! + * \brief Terminate a spinner progress thread + * + * \param[in] result Status of the termination (true = all, false = error) + * \note If an error happened, one must call progress_update before calling this + * function in order to update the final message that will be printed. See + * the PROGRESS_ERROR macro. + * + * \sa PROGRESS_ERROR + * \sa PROGRESS_DONE + * \sa PROGRESS_UPDATE + */ +# define PROGRESS_DONE() progress_end(true) +# define PROGRESS_ERROR(str, ...) \ + do { \ + progress_update(str, ##__VA_ARGS__); \ + progress_end(false); \ + } while (0) +void progress_end(bool result); + +#endif /* LOG_H */ diff --git a/main.c b/main.c @@ -0,0 +1,39 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <log.h> + +int main(void) +{ + DEBUG("Alu !\n"); + INFO("info\n"); + WARNING("Warning\n"); + ERROR("Error!\n"); + SET_DEBUG(true); + DEBUG("Oui!\n"); + + PROGRESS_BEGIN("Yes."); + + for (size_t i = 0; i < 100000; i++) + { + PROGRESS_UPDATE("Count: %zu", i); + usleep(200); + } + + PROGRESS_DONE(); + + FATAL("ava ?\n"); + return 0; +} diff --git a/utils.h b/utils.h @@ -0,0 +1,80 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#ifndef UTILS_H +# define UTILS_H + +# include <fcntl.h> +# include <unistd.h> +# include <stdbool.h> + +/* Compile-time assertion */ +# define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1] +# define COUNT_OF(ptr) sizeof(ptr) / sizeof(ptr[0]) + +# define QUOTE_ME(x) #x +# define STR(x) QUOTE_ME(x) + +# define EMPTY_STR() { '\0' } +# define STR_OR_EMPTY(str) (str != NULL ? str : "") +# define STR_NULL_OR_EMPTY(str) (str == NULL || (str != NULL && *str == '\0')) +# define FREE(ptr) free(ptr); ptr = NULL; +# define UNUSED_ARG(arg) (void)arg + +/* Magic things */ +# undef offsetof +# ifdef __compiler_offsetof +# define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER) +# else +# define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) +# endif /* __compiler_offsetof */ + +# define container_of(ptr, type, member) ({\ + const typeof( ((type *)0)->member ) *__mptr = (ptr);\ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +# define ___UNIQ(name, n) name##n +# define __UNIQ(name, n) ___UNIQ(name, n) +# define _UNIQ(name, n) __UNIQ(name, n) +# define UNIQ(name) _UNIQ(name, __LINE__) + +# define __STATIC_ARRAY_FOREACH(index, keep, item, array) \ + for (size_t keep = 1, index = 0; keep && index < COUNT_OF(array); keep = !keep, index++) \ + for (item = &array[index]; keep; keep = !keep) + +# define STATIC_ARRAY_FOREACH_I(index, item, array) __STATIC_ARRAY_FOREACH(index, UNIQ(__foreach_keep), item, array) +# define STATIC_ARRAY_FOREACH(item, array) __STATIC_ARRAY_FOREACH(UNIQ(__foreach_index), UNIQ(__foreach_keep), item, array) + +# define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +# define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) + +# define __HOT_FUNCTION __attribute__((hot)) +# define __COLD_FUNCTION __attribute__((cold)) +# ifndef __DEPRECATED +# define __DEPRECATED __attribute__((deprecated)) +# endif /* __DEPRECATED */ +# define __CONST_FUNCTION __attribute__((const)) +# define __NORETURN_FUNCTION __attribute__((noreturn)) +# define __INLINE_FUNCTION __attribute__((always_inline)) +# define __NON_NULL_ARGS(...) __attribute__((nonnull(__VA_ARGS__))) +# define __NON_NULL_ALL __attribute__((nonnull)) +# define __PURE_FUNCTION __attribute__((pure)) +# define __PRINTF_FUNCTION(...) __attribute__((format (printf, __VA_ARGS__))) +# define likely(x) __builtin_expect((x), 1) +# define unlikely(x) __builtin_expect((x), 0) + +# define UNREACHABLE_CODE assert(!"Unreachable code " __FILE__ ": " STR(__FUNCTION__)) + +#endif /* UTILS_H */