mirror of
https://github.com/ascii-boxes/boxes.git
synced 2025-03-02 16:21:26 +01:00
Add new module 'logging' to handle debug logging
This should be nicer than using the preprocessor.
This commit is contained in:
parent
716348befc
commit
d8e0e7421c
@ -23,11 +23,11 @@ GEN_HDR = parser.h boxes.h lex.yy.h
|
||||
GEN_SRC = parser.c lex.yy.c
|
||||
GEN_FILES = $(GEN_SRC) $(GEN_HDR)
|
||||
ORIG_HDRCL = boxes.in.h config.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) bxstring.h cmdline.h detect.h discovery.h generate.h input.h list.h parsecode.h parsing.h \
|
||||
query.h regulex.h remove.h shape.h tools.h unicode.h
|
||||
ORIG_HDR = $(ORIG_HDRCL) bxstring.h cmdline.h detect.h discovery.h generate.h input.h list.h logging.h parsecode.h \
|
||||
parsing.h query.h regulex.h remove.h shape.h tools.h unicode.h
|
||||
ORIG_GEN = lexer.l parser.y
|
||||
ORIG_NORM = boxes.c bxstring.c cmdline.c detect.c discovery.c generate.c input.c list.c parsecode.c parsing.c query.c \
|
||||
regulex.c remove.c shape.c tools.c unicode.c
|
||||
ORIG_NORM = boxes.c bxstring.c cmdline.c detect.c discovery.c generate.c input.c list.c logging.c parsecode.c \
|
||||
parsing.c query.c regulex.c remove.c shape.c tools.c unicode.c
|
||||
ORIG_SRC = $(ORIG_GEN) $(ORIG_NORM)
|
||||
ORIG_FILES = $(ORIG_SRC) $(ORIG_HDR)
|
||||
|
||||
@ -116,6 +116,7 @@ generate.o: generate.c generate.h boxes.h shape.h tools.h unicode.h config.h |
|
||||
input.o: input.c boxes.h input.h regulex.h tools.h unicode.h config.h | check_dir
|
||||
lex.yy.o: lex.yy.c parser.h boxes.h parsing.h tools.h shape.h unicode.h config.h | check_dir
|
||||
list.o: list.c list.h boxes.h bxstring.h parsing.h query.h shape.h tools.h unicode.h config.h | check_dir
|
||||
logging.o: logging.c logging.h tools.h config.h | check_dir
|
||||
parsecode.o: parsecode.c parsecode.h discovery.h lex.yy.h parsing.h parser.h query.h regulex.h shape.h tools.h unicode.h config.h | check_dir
|
||||
parser.o: parser.c boxes.h bxstring.h lex.yy.h parsecode.h parser.h parsing.h shape.h tools.h unicode.h config.h | check_dir
|
||||
parsing.o: parsing.c parsing.h bxstring.h parser.h lex.yy.h boxes.h tools.h config.h | check_dir
|
||||
|
@ -143,6 +143,7 @@ typedef struct { /* Command line options: */
|
||||
char *eol; /** `-e`: line break to use. Never NULL, default to "\n". */
|
||||
int eol_overridden; /** `-e`: 0: value in `eol` is the default; 1: value in `eol` specified via `-e` */
|
||||
char *f; /** `-f`: config file path */
|
||||
int *debug; /** `-g`: activate debug logging for given debug log areas */
|
||||
int help; /** `-h`: flags if help argument was specified */
|
||||
char indentmode; /** `-i`: 'b', 't', 'n', or '\0' */
|
||||
int killblank; /** `-k`: kill blank lines, -1 if not set */
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "boxes.h"
|
||||
#include "discovery.h"
|
||||
#include "logging.h"
|
||||
#include "query.h"
|
||||
#include "tools.h"
|
||||
#include "cmdline.h"
|
||||
@ -91,6 +92,7 @@ void usage_long(FILE *st)
|
||||
strcmp(EOL_DEFAULT, "\r\n") == 0 ? "CRLF" : "LF");
|
||||
fprintf(st, " -f, --config <file> Configuration file [default: %s]\n",
|
||||
config_file != NULL ? bxs_to_output(config_file) : "none");
|
||||
/* fprintf(st, " -g, --debug <areas> Activate debug logging for specified log areas [default area: MAIN]"); // undocumented */
|
||||
fprintf(st, " -h, --help Print usage information\n");
|
||||
fprintf(st, " -i, --indent <mode> Indentation mode [default: box]\n");
|
||||
fprintf(st, " -k <bool> Leading/trailing blank line retention on removal\n");
|
||||
@ -121,6 +123,7 @@ static opt_t *create_new_opt()
|
||||
result->eol = "\n"; /* we must default to "\n" instead of EOL_DEFAULT as long as stdout is in text mode */
|
||||
result->tabexp = 'e';
|
||||
result->killblank = -1;
|
||||
result->debug = (int *) calloc(NUM_LOG_AREAS, sizeof(int));
|
||||
for (int i = 0; i < NUM_SIDES; ++i) {
|
||||
result->padding[i] = -1;
|
||||
}
|
||||
@ -458,6 +461,51 @@ static int size_of_box(opt_t *result, char *optarg)
|
||||
|
||||
|
||||
|
||||
static int debug_areas(opt_t *result, char *optarg)
|
||||
{
|
||||
char *dup = NULL;
|
||||
if (optarg != NULL) {
|
||||
dup = strdup(optarg); /* required because strtok() modifies its input */
|
||||
}
|
||||
else {
|
||||
dup = strdup(log_area_names[MAIN]);
|
||||
}
|
||||
|
||||
for (char *a = strtok(dup, ","); a != NULL; a = strtok(NULL, ","))
|
||||
{
|
||||
char *trimmed = trimdup(a, a + strlen(a) - 1);
|
||||
if (strlen(trimmed) == 0) {
|
||||
BFREE(trimmed);
|
||||
continue;
|
||||
}
|
||||
int valid = 0;
|
||||
for (size_t i = ALL; i < NUM_LOG_AREAS + 2; i++) {
|
||||
if (strcasecmp(trimmed, log_area_names[i]) == 0) {
|
||||
valid = 1;
|
||||
if (i == ALL) {
|
||||
for (size_t i = 0; i < NUM_LOG_AREAS; i++) {
|
||||
result->debug[i] = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result->debug[i - 2] = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
bx_fprintf(stderr, "%s: invalid debug area -- %s\n", PROJECT, trimmed);
|
||||
BFREE(trimmed);
|
||||
return 1;
|
||||
}
|
||||
BFREE(trimmed);
|
||||
}
|
||||
BFREE(dup);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tab handling. Format is `n[eku]`.
|
||||
* @param result the options struct we are building
|
||||
@ -644,6 +692,7 @@ opt_t *process_commandline(int argc, char *argv[])
|
||||
{ "create", required_argument, NULL, 'c' },
|
||||
{ "color", no_argument, NULL, OPT_COLOR },
|
||||
{ "no-color", no_argument, NULL, OPT_NO_COLOR },
|
||||
{ "debug", optional_argument, NULL, 'g' },
|
||||
{ "design", required_argument, NULL, 'd' },
|
||||
{ "eol", required_argument, NULL, 'e' },
|
||||
{ "config", required_argument, NULL, 'f' },
|
||||
@ -662,7 +711,7 @@ opt_t *process_commandline(int argc, char *argv[])
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
const char *short_options = "a:c:d:e:f:hi:k:lmn:p:q:rs:t:v";
|
||||
const char *short_options = "a:c:d:e:f:g::hi:k:lmn:p:q:rs:t:v";
|
||||
|
||||
int oc; /* option character */
|
||||
do {
|
||||
@ -709,6 +758,14 @@ opt_t *process_commandline(int argc, char *argv[])
|
||||
case 'f':
|
||||
result->f = strdup(optarg); /* input file */
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (debug_areas(result, optarg) != 0) {
|
||||
BFREE(result);
|
||||
return NULL;
|
||||
}
|
||||
activate_debug_logging(result->debug);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
result->help = 1;
|
||||
|
154
src/logging.c
Normal file
154
src/logging.c
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2023 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* 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/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Simple makeshift log facility for handling debug output.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "regulex.h"
|
||||
#include "tools.h"
|
||||
#include "logging.h"
|
||||
|
||||
|
||||
char *log_area_names[] = { "RESERVED", "ALL", "MAIN", "REGEXP", "PARSER", "LEXER", "DISCOVERY" };
|
||||
|
||||
static int debug_logging_active = 0;
|
||||
|
||||
static int *areas_active = NULL;
|
||||
|
||||
|
||||
|
||||
static char *shorten_module(const char *module)
|
||||
{
|
||||
if (module == NULL) {
|
||||
return strdup("NULL");
|
||||
}
|
||||
|
||||
const char *s = strrchr(module, '/');
|
||||
if (s == NULL) {
|
||||
s = strrchr(module, '\\');
|
||||
}
|
||||
if (s != NULL) {
|
||||
s++;
|
||||
}
|
||||
else {
|
||||
s = module;
|
||||
}
|
||||
|
||||
char *e = strrchr(module, '.');
|
||||
if (e != NULL && e > s && *s != '\0') {
|
||||
char *result = strdup(s);
|
||||
result[e-s] = '\0';
|
||||
return result;
|
||||
}
|
||||
return strdup(s);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void activate_debug_logging(int *log_areas)
|
||||
{
|
||||
debug_logging_active = 0;
|
||||
|
||||
if (areas_active != NULL) {
|
||||
BFREE(areas_active);
|
||||
}
|
||||
areas_active = (int *) calloc(NUM_LOG_AREAS, sizeof(int));
|
||||
if (log_areas != NULL) {
|
||||
memcpy(areas_active, log_areas, NUM_LOG_AREAS * sizeof(int));
|
||||
debug_logging_active = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int is_area_active(log_area_t log_area)
|
||||
{
|
||||
if (debug_logging_active && areas_active != NULL && log_area != RESERVED && log_area < NUM_LOG_AREAS + 2) {
|
||||
if (log_area == ALL) {
|
||||
for (size_t i = 0; i < NUM_LOG_AREAS; i++) {
|
||||
if (!areas_active[i]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return areas_active[log_area - 2];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int is_debug_logging(log_area_t log_area)
|
||||
{
|
||||
return (debug_logging_active && is_area_active(log_area)) ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int is_debug_activated()
|
||||
{
|
||||
if (debug_logging_active) {
|
||||
for (size_t i = 0; i < NUM_LOG_AREAS; i++) {
|
||||
if (areas_active[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void log_debug(const char *module, log_area_t log_area, const char *format, ...)
|
||||
{
|
||||
if (is_debug_logging(log_area)) {
|
||||
char *msg = (char *) malloc(1024);
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vsprintf(msg, format, va);
|
||||
va_end(va);
|
||||
|
||||
char *short_module = shorten_module(module);
|
||||
bx_fprintf(stderr, "[%-9s] %s", short_module, msg);
|
||||
BFREE(short_module);
|
||||
BFREE(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void log_debug_cont(log_area_t log_area, const char *format, ...)
|
||||
{
|
||||
if (is_debug_logging(log_area)) {
|
||||
char *msg = (char *) malloc(1024);
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
vsprintf(msg, format, va);
|
||||
va_end(va);
|
||||
|
||||
bx_fprintf(stderr, "%s", msg);
|
||||
BFREE(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* vim: set cindent sw=4: */
|
101
src/logging.h
Normal file
101
src/logging.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* boxes - Command line filter to draw/remove ASCII boxes around text
|
||||
* Copyright (c) 1999-2023 Thomas Jensen and the boxes contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License, version 3, as published by the Free Software Foundation.
|
||||
* 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/>.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*/
|
||||
|
||||
/*
|
||||
* Simple makeshift log facility for handling debug output.
|
||||
*
|
||||
* Debug output is printed on stderr. Each message is annotated with its module and "area".
|
||||
* The "area" defines certain sections of code as a possible filter criterion.
|
||||
*/
|
||||
|
||||
#ifndef LOGGING_H
|
||||
#define LOGGING_H
|
||||
|
||||
|
||||
/** Enum of the log areas supported. `ALL` means all of them, `RESERVED` cannot be used. */
|
||||
typedef enum _log_area_t {
|
||||
/** the 0 value is reserved and must not be used */
|
||||
RESERVED,
|
||||
|
||||
/** all areas */
|
||||
ALL,
|
||||
|
||||
/** the main areas of the code (activate this if unsure) */
|
||||
MAIN,
|
||||
|
||||
/** regular expression handling */
|
||||
REGEXP,
|
||||
|
||||
/** parser code */
|
||||
PARSER,
|
||||
|
||||
/** lexer code */
|
||||
LEXER,
|
||||
|
||||
/** config file discovery */
|
||||
DISCOVERY
|
||||
} log_area_t;
|
||||
|
||||
/** names of the values of `log_area_t` as strings for parsing */
|
||||
extern char *log_area_names[];
|
||||
|
||||
/** number of log areas in `log_area_t`, excluding `ALL` and `RESERVED` */
|
||||
#define NUM_LOG_AREAS 5
|
||||
|
||||
|
||||
/**
|
||||
* Activate debug logging.
|
||||
* @param log_areas an array of log areas to activate, zero-terminated, should not be empty. The value will by copied
|
||||
* and can be freed after returning from the function. Passing NULL will turn off debug logging.
|
||||
*/
|
||||
void activate_debug_logging(int *log_areas);
|
||||
|
||||
|
||||
/**
|
||||
* Determine if debug logging was activated for any debug area.
|
||||
* @return 1 if active, 0 if not
|
||||
*/
|
||||
int is_debug_activated();
|
||||
|
||||
|
||||
/**
|
||||
* Determine if debug logging is active and the given area is active, too.
|
||||
* @param log_area the log area to check
|
||||
* @return 1 if active, 0 if not
|
||||
*/
|
||||
int is_debug_logging(log_area_t log_area);
|
||||
|
||||
|
||||
/**
|
||||
* Print a debug log message if the log area is active. Debug log messages will be printed on `stderr`.
|
||||
* @param module the module name as per `__FILE__`
|
||||
* @param log_area_t log_area
|
||||
* @param format format string for the message, followed by the placeholder arguments
|
||||
*/
|
||||
void log_debug(const char *module, log_area_t log_area, const char *format, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Print a debug log message if the log area is active. Debug log messages will be printed on `stderr`.
|
||||
* The difference to `log_debug()` is that no module is printed.
|
||||
* @param log_area_t log_area
|
||||
* @param format format string for the message, followed by the placeholder arguments
|
||||
*/
|
||||
void log_debug_cont(log_area_t log_area, const char *format, ...);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* vim: set cindent sw=4: */
|
Loading…
Reference in New Issue
Block a user