Files
bmplib/logging.c
Rupert 052c5ade33 make it compile with MS Visual Studio
* 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
2024-11-16 02:40:19 +01:00

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