mirror of
https://github.com/rupertwh/bmplib.git
synced 2026-02-04 05:35:48 +00:00
* add dll import/export declarations * add casts to avoid compiler warnings * fix long vs long long error, unearthed by compiling under Windows Compiling with Visual Studio still needs some manual work that is otherwise done by meson: * create config.h * compile and run gen-huffman.c and gen-reversebits.c to create the header files huffman-codes.h and reversebits.h gitignore visual studio
300 lines
6.6 KiB
C
300 lines
6.6 KiB
C
/* bmplib - logging.c
|
|
*
|
|
* Copyright (c) 2024, Rupert Weber.
|
|
*
|
|
* This file is part of bmplib.
|
|
* bmplib is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library.
|
|
* If not, see <https://www.gnu.org/licenses/>
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
#include <errno.h>
|
|
|
|
#include "config.h"
|
|
#include "logging.h"
|
|
|
|
|
|
struct Log {
|
|
int size;
|
|
char *buffer;
|
|
};
|
|
|
|
|
|
/* logerr(log, fmt, ...) and logsyserr(log, fmt, ...) are
|
|
* printf-style logging functions.
|
|
*
|
|
* Use logsyserr() where perror() would be used, logerr()
|
|
* otherwise.
|
|
*
|
|
* 'separator' and 'inter' can have any length
|
|
* 'air' is just there so we don't need to realloc every
|
|
* single time.
|
|
*/
|
|
|
|
static const char separator[]="\n"; /* separator between log entries */
|
|
static const char inter[]=": "; /* between own message and sys err text */
|
|
static const int air = 80; /* how much more than required we allocate */
|
|
|
|
static int s_allocate(LOG log, size_t add_chars);
|
|
static void s_log(LOG log, const char *file, int line, const char *function,
|
|
const char *etxt, const char *fmt, va_list args);
|
|
static void panic(LOG log);
|
|
#ifdef DEBUG
|
|
static int s_add_file_etc(LOG log, const char *file, int line, const char *function);
|
|
#endif
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* logcreate / logfree / etc.
|
|
*********************************************************/
|
|
|
|
LOG logcreate(void)
|
|
{
|
|
LOG log;
|
|
|
|
if (!(log = malloc(sizeof *log)))
|
|
return NULL;
|
|
memset(log, 0, sizeof *log);
|
|
return log;
|
|
}
|
|
|
|
void logfree(LOG log)
|
|
{
|
|
if (log) {
|
|
if (log->size != -1 && log->buffer)
|
|
free(log->buffer);
|
|
free(log);
|
|
}
|
|
}
|
|
|
|
void logreset(LOG log)
|
|
{
|
|
if (log && log->buffer)
|
|
*log->buffer = 0;
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* logmsg()
|
|
*********************************************************/
|
|
|
|
const char* logmsg(LOG log)
|
|
{
|
|
if (log && log->buffer)
|
|
return log->buffer;
|
|
else
|
|
return "";
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* logerr()
|
|
*********************************************************/
|
|
|
|
#ifdef DEBUG
|
|
void logerr_(LOG log, const char *file, int line, const char *function, const char *fmt, ...)
|
|
#else
|
|
void logerr(LOG log, const char *fmt, ...)
|
|
#endif
|
|
{
|
|
va_list args;
|
|
|
|
va_start(args, fmt);
|
|
|
|
#ifdef DEBUG
|
|
s_log(log, file, line, function, NULL, fmt, args);
|
|
#else
|
|
s_log(log, NULL, 0, NULL, NULL, fmt, args);
|
|
#endif
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* logsyserr()
|
|
*********************************************************/
|
|
|
|
#ifdef DEBUG
|
|
void logsyserr_(LOG log, const char *file, int line, const char *function, const char *fmt, ...)
|
|
#else
|
|
void logsyserr(LOG log, const char *fmt, ...)
|
|
#endif
|
|
{
|
|
va_list args;
|
|
const char *etxt;
|
|
|
|
va_start(args, fmt);
|
|
etxt = strerror(errno);
|
|
|
|
#ifdef DEBUG
|
|
s_log(log, file, line, function, etxt, fmt, args);
|
|
#else
|
|
s_log(log, NULL, 0, NULL, etxt, fmt, args);
|
|
#endif
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* s_log()
|
|
*********************************************************/
|
|
|
|
static void s_log(LOG log, const char *file, int line, const char *function,
|
|
const char *etxt, const char *fmt, va_list args)
|
|
{
|
|
va_list argsdup;
|
|
int len = 0,addl_len, required_len;
|
|
|
|
if (log->size == -1)
|
|
return; /* log is set to a string literal (panic) */
|
|
|
|
#ifdef DEBUG
|
|
if (!s_add_file_etc(log, file, line, function))
|
|
return;
|
|
#endif
|
|
|
|
if (log->buffer)
|
|
len = strlen(log->buffer);
|
|
|
|
va_copy(argsdup, args);
|
|
addl_len = vsnprintf(NULL, 0, fmt, argsdup);
|
|
va_end(argsdup);
|
|
|
|
required_len = len + strlen(separator) +
|
|
addl_len + (etxt ? strlen(inter) + strlen (etxt) : 0) + 1;
|
|
if (required_len > log->size) {
|
|
if (!s_allocate(log, required_len - log->size)) {
|
|
panic(log);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifndef DEBUG /* <-- if NOT defined */
|
|
if (*log->buffer) {
|
|
strcat(log->buffer, separator);
|
|
len += strlen(separator);
|
|
}
|
|
#endif
|
|
|
|
if (log->size - len <= vsnprintf(log->buffer + len, log->size - len,
|
|
fmt, args)) {
|
|
panic(log);
|
|
return;
|
|
}
|
|
|
|
if (etxt) {
|
|
strcat(log->buffer, inter);
|
|
strcat(log->buffer, etxt);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* s_allocate()
|
|
*********************************************************/
|
|
|
|
static int s_allocate(LOG log, size_t add_chars)
|
|
{
|
|
char *tmp;
|
|
size_t newsize;
|
|
|
|
if (log->size == -1)
|
|
return 0; /* log is set to a string literal (panic) */
|
|
|
|
add_chars += air;
|
|
|
|
newsize = (size_t) log->size + add_chars;
|
|
if (newsize > INT_MAX) {
|
|
panic(log);
|
|
return 0;
|
|
}
|
|
|
|
tmp = realloc(log->buffer, newsize);
|
|
if (tmp) {
|
|
log->buffer = tmp;
|
|
if (log->size == 0)
|
|
log->buffer[0] = 0;
|
|
log->size = newsize;
|
|
} else {
|
|
panic(log);
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* panic()
|
|
*********************************************************/
|
|
|
|
static void panic(LOG log)
|
|
{
|
|
log->size = -1;
|
|
log->buffer = "PANIC! bmplib encountered an error while trying to set "
|
|
"an error message";
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************
|
|
* s_add_file_etc()
|
|
*********************************************************/
|
|
|
|
#ifdef DEBUG
|
|
static int s_add_file_etc(LOG log, const char *file, int line, const char *function)
|
|
{
|
|
int len = 0, addl_len, required_len;
|
|
|
|
if (log->buffer)
|
|
len = strlen(log->buffer);
|
|
|
|
addl_len = snprintf(NULL, 0, "[%s, line %d, %s()] ", file, line, function);
|
|
|
|
required_len = len + strlen(separator) + addl_len + 1;
|
|
if (required_len > log->size) {
|
|
if (!s_allocate(log, required_len - log->size)) {
|
|
panic(log);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (*log->buffer) {
|
|
strcat(log->buffer, separator);
|
|
addl_len += strlen(separator);
|
|
len += strlen(separator);
|
|
}
|
|
|
|
if (log->size - len <= snprintf(log->buffer + len, log->size - len,
|
|
"[%s, line %d, %s()] ", file, line, function)) {
|
|
panic(log);
|
|
return 0;
|
|
}
|
|
return addl_len;
|
|
}
|
|
#endif
|