lorid

convert chordpro to pdf
git clone git://git.relim.de/lorid.git
Log | Files | Refs | README | LICENSE

commit 5262593690217c8b6e06fe3537184ff48dc78ffd
parent 35ea8f898f3d437ecb47b5dde1e44a2e09c84f30
Author: nibo <nibo@relim.de>
Date:   Wed,  9 Oct 2024 18:15:18 +0200

Improve logging

Diffstat:
MMakefile | 6++++--
Mchordpro.c | 247++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mchordpro.h | 14+-------------
Mconfig.c | 10+++++-----
Mlorid.c | 16+++++++++-------
Mout_pdf.c | 132++++++++++++++++++++++++++++++++++++++++----------------------------------------
Mtodo | 6+++++-
Mutil.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.h | 14++++++++++++--
9 files changed, 326 insertions(+), 187 deletions(-)

diff --git a/Makefile b/Makefile @@ -4,10 +4,12 @@ CFLAGS = -pedantic -Wall -Wextra -DVERSION=\"${VERSION}\" LDFLAGS = -lpdfio -ltoml -lfontconfig SRC = util.c fontconfig.c config.c chordpro.c out_pdf.c lorid.c +COLOR = 0 + all: - $(CC) ${CFLAGS} -O2 ${SRC} -o lorid ${LDFLAGS} + $(CC) ${CFLAGS} -DCOLOR=${COLOR} -O2 ${SRC} -o lorid ${LDFLAGS} debug: - $(CC) ${CFLAGS} -DDEBUG=1 -g ${SRC} -o lorid ${LDFLAGS} + $(CC) ${CFLAGS} -DCOLOR=${COLOR} -DDEBUG -g ${SRC} -o lorid ${LDFLAGS} clean: rm *.o rm lorid diff --git a/chordpro.c b/chordpro.c @@ -2,11 +2,11 @@ #include <stdlib.h> #include <stdbool.h> #include <stdint.h> +#include <stdarg.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <limits.h> -#include <math.h> #include "chordpro.h" #include "config.h" #include "util.h" @@ -177,6 +177,7 @@ static const char *chord_extensions_minor[] = { static enum SongFragmentType g_current_ftype = SF_TEXT; static enum SongFragmentType g_prev_ftype = SF_TEXT; static struct Config *g_config = NULL; +static const char *g_chordpro_filepath = NULL; static int *g_transpose_history = NULL; static int *g_transpose = NULL; static size_t g_line_number = 1; @@ -269,6 +270,66 @@ static void cho_debug_chord_print(struct ChoChord *chord) #endif /* DEBUG */ +static void cho_log(enum LogLevel level, const char *msg, ...) +{ + va_list va; + va_start(va, msg); +#if COLOR == 1 + const char *log_level; + const char *color; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + color = "37"; + break; + case LOG_WARN: + log_level = "WARN"; + color = "33"; + break; + case LOG_ERR: + log_level = " ERR"; + color = "31"; + break; + } + if (g_chordpro_filepath) { + /* fprintf(stderr, "\033[1m%s:%ld:\033[0m \033[1m\033[%sm%s\033[0m: %s\n", + g_chordpro_filepath, g_line_number, color, log_level, msg); */ + fprintf(stderr, "\033[1m%s:%ld:\033[0m \033[1m\033[%sm%s\033[0m: ", + g_chordpro_filepath, g_line_number, color, log_level); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "line \033[1m%ld:\033[0m \033[1m\033[%sm%s\033[0m: ", + g_line_number, color, log_level); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); + } +#else + const char *log_level; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + break; + case LOG_WARN: + log_level = "WARN"; + break; + case LOG_ERR: + log_level = " ERR"; + break; + } + if (g_chordpro_filepath) { + fprintf(stderr, "%s:%ld: %s: ", g_chordpro_filepath, g_line_number, + log_level); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); + } else { + fprintf(stderr, "line %ld: %s: ", g_line_number, log_level); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); + } +#endif +} + static inline bool is_whitespace(char c) { if ( @@ -323,7 +384,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[2]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -337,7 +398,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[4]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -351,7 +412,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[6]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -367,7 +428,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[1]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -381,7 +442,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[2]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -395,7 +456,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) tmp[1] = str[3]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - fprintf(stderr, "ERR: Invalid primary color in rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -403,7 +464,7 @@ struct RGBColor *cho_rgbcolor_parse(const char *str) } } } else { - fprintf(stderr, "ERR: Invalid rgb color, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid rgb color."); free(color); return NULL; } @@ -420,7 +481,7 @@ struct RGBColor *cho_color_parse(const char *str) color = rgb_color; } else { free(color); - DEBUG_MSG("cho_rgbcolor_parse failed."); + LOG_DEBUG("cho_rgbcolor_parse failed."); return NULL; } } else if (!strcmp(str, "red")) { @@ -460,7 +521,7 @@ struct RGBColor *cho_color_parse(const char *str) color->green = 0; color->blue = 0; } else { - fprintf(stderr, "ERR: Invalid color value '%s', line '%ld'.\n", str, g_line_number); + cho_log(LOG_ERR, "Invalid color value '%s'.", str); free(color); return NULL; } @@ -699,7 +760,7 @@ static bool cho_style_property_apply_default(enum SongFragmentType current_ftype } break; default: - fprintf(stderr, "WARN: Invalid style property type '%d', line '%ld'.\n", ptype, g_line_number); + cho_log(LOG_WARN, "Invalid style property type '%d'.", ptype); return false; } } @@ -959,7 +1020,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "monospace")) { style->font->family = FF_MONOSPACE; } else { - fprintf(stderr, "ERR: Invalid value in attribute 'font_family/face', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid value in attribute 'font_family/face'."); return NULL; } } else if (!strcmp(attrs[a]->name, "size")) { @@ -972,11 +1033,11 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct if (percentage != 0 && percentage <= 100) { style->font->size *= percentage / 100.0; } else { - fprintf(stderr, "ERR: Invalid percentage in attribute 'size', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid percentage in attribute 'size'."); return NULL; } } else { - fprintf(stderr, "ERR: Invalid percentage in attribute 'size', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid percentage in attribute 'size'."); return NULL; } } else if (isdigit(attrs[a]->value[0]) != 0) { @@ -984,7 +1045,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct if (size != 0.0) { style->font->size = size; } else { - fprintf(stderr, "ERR: Invalid number in attribute 'size', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid number in attribute 'size'."); return NULL; } } else if (!strcmp(attrs[a]->value, "xx-small")) { @@ -1011,7 +1072,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "smaller")) { style->font->size *= 0.8; } else { - fprintf(stderr, "ERR: Invalid value '%s' for the attribute 'size', line '%ld'.\n", attrs[a]->value, g_line_number); + cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'size'.", attrs[a]->value); return NULL; } } else if (!strcmp(attrs[a]->name, "style")) { @@ -1022,7 +1083,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "italic")) { style->font->style = FS_ITALIC; } else { - fprintf(stderr, "ERR: Invalid value in attribute 'style', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid value in attribute 'style'."); return NULL; } } else if (!strcmp(attrs[a]->name, "weight")) { @@ -1031,13 +1092,13 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "bold")) { style->font->weight = FW_BOLD; } else { - fprintf(stderr, "ERR: Invalid value in attribute 'weight', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid value in attribute 'weight'."); return NULL; } } else if (!strcmp(attrs[a]->name, "foreground")) { rgb_color = cho_color_parse(attrs[a]->value); if (!rgb_color) { - DEBUG_MSG("cho_color_parse failed."); + LOG_DEBUG("cho_color_parse failed."); return NULL; } else { free(style->foreground_color); @@ -1046,7 +1107,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->name, "background")) { rgb_color = cho_color_parse(attrs[a]->value); if (!rgb_color) { - DEBUG_MSG("cho_color_parse failed."); + LOG_DEBUG("cho_color_parse failed."); return NULL; } else { free(style->background_color); @@ -1060,13 +1121,13 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "none")) { style->underline_style = LS_NONE; } else { - fprintf(stderr, "ERR: Invalid value in attribute 'underline', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid value in attribute 'underline'."); return NULL; } } else if (!strcmp(attrs[a]->name, "underline_colour")) { rgb_color = cho_color_parse(attrs[a]->value); if (!rgb_color) { - DEBUG_MSG("cho_color_parse failed."); + LOG_DEBUG("cho_color_parse failed."); return NULL; } else { free(style->underline_color); @@ -1080,13 +1141,13 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "none")) { style->overline_style = LS_NONE; } else { - fprintf(stderr, "ERR: Invalid value in attribute 'overline', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid value in attribute 'overline'."); return NULL; } } else if (!strcmp(attrs[a]->name, "overline_colour")) { rgb_color = cho_color_parse(attrs[a]->value); if (!rgb_color) { - DEBUG_MSG("cho_color_parse failed."); + LOG_DEBUG("cho_color_parse failed."); return NULL; } else { free(style->overline_color); @@ -1103,7 +1164,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct if (percentage != 0 && percentage <= 100) { style->rise = (style->font->size / 2) * percentage / 100.0; } else { - fprintf(stderr, "ERR: Invalid percentage in attribute 'rise', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'."); return NULL; } } @@ -1112,11 +1173,11 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct if (rise != 0.0) { style->rise = rise; } else { - fprintf(stderr, "ERR: Invalid number in attribute 'rise', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid number in attribute 'rise'."); return NULL; } } else { - fprintf(stderr, "ERR: Invalid value '%s' for the attribute 'rise', line '%ld'.\n", attrs[a]->value, g_line_number); + cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); return NULL; } } else { @@ -1129,7 +1190,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct double more = style->font->size / 2.0 * percentage / 100.0; style->rise += more; } else { - fprintf(stderr, "ERR: Invalid percentage in attribute 'rise', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'."); return NULL; } } @@ -1138,11 +1199,11 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct if (rise != 0.0) { style->rise = rise; } else { - fprintf(stderr, "ERR: Invalid number in attribute 'rise', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Invalid number in attribute 'rise'."); return NULL; } } else { - fprintf(stderr, "ERR: Invalid value '%s' for the attribute 'rise', line '%ld'.\n", attrs[a]->value, g_line_number); + cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); return NULL; } } @@ -1152,13 +1213,13 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->value, "false")) { style->strikethrough = false; } else { - fprintf(stderr, "ERR: Invalid value '%s' in attribute 'strikethrough', line '%ld'.\n", attrs[a]->value, g_line_number); + cho_log(LOG_ERR, "Invalid value '%s' in attribute 'strikethrough'.", attrs[a]->value); return NULL; } } else if (!strcmp(attrs[a]->name, "strikethrough_colour")) { rgb_color = cho_color_parse(attrs[a]->value); if (!rgb_color) { - DEBUG_MSG("cho_color_parse failed."); + LOG_DEBUG("cho_color_parse failed."); return NULL; } else { free(style->strikethrough_color); @@ -1167,7 +1228,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(attrs[a]->name, "href")) { style->href = strdup(attrs[a]->value); } else { - fprintf(stderr, "ERR: Invalid attribute '%s', line '%ld'.\n", attrs[a]->name, g_line_number); + cho_log(LOG_ERR, "Invalid attribute '%s'.", attrs[a]->name); return NULL; } a++; @@ -1193,7 +1254,7 @@ struct Style *cho_style_parse(const char *tag_name, struct Attr **attrs, struct } else if (!strcmp(tag_name, "u")) { style->underline_style = LS_SINGLE; } else { - fprintf(stderr, "ERR: Invalid tag name '%s', line '%ld'.\n", tag_name, g_line_number); + cho_log(LOG_ERR, "Invalid tag name '%s'.", tag_name); cho_style_free(style); return NULL; } @@ -1249,7 +1310,7 @@ static bool cho_style_change_default(struct StyleProperty sprop) } return true; default: - fprintf(stderr, "ERR: Invalid style property type '%d', line '%ld'.\n", sprop.type, g_line_number); + cho_log(LOG_ERR, "Invalid style property type '%d'.", sprop.type); return false; } } @@ -1274,7 +1335,7 @@ static bool cho_style_reset_default(void) default_style_properties[i].u.foreground_color = NULL; return true; default: - fprintf(stderr, "ERR: Invalid style property type '%d', line '%ld'.\n", default_style_properties[i].type, g_line_number); + cho_log(LOG_ERR, "Invalid style property type '%d'.", default_style_properties[i].type); return false; } } @@ -1335,7 +1396,7 @@ static bool cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, } i--; } - fprintf(stderr, "ERR: Didn't find a start tag for the end tag '%s', line '%ld'.\n", tag_name, g_line_number); + cho_log(LOG_ERR, "Didn't find a start tag for the end tag '%s'.", tag_name); return false; } @@ -1411,7 +1472,7 @@ static struct ChoMetadata *cho_metadata_split(const char *directive_value) free(meta->name); free(meta->value); free(meta); - fprintf(stderr, "ERR: Failed to parse directive 'meta', line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Failed to parse directive 'meta'."); return NULL; } } @@ -1507,7 +1568,7 @@ static char *transposition_calc_chord_root(int index, enum NoteType type) case NT_FLAT: return strdup(g_config->output->notes[new_index]->flat); } - fprintf(stderr, "ERR: Invalid NoteType '%d', line '%ld'.\n", note_type, g_line_number); + cho_log(LOG_ERR, "Invalid NoteType '%d'.", note_type); return NULL; } @@ -1565,7 +1626,7 @@ static int cho_chord_root_parse(const char *str, struct ChoChord *chord) if (sharp && str_starts_with(str, sharp)) { transposed_root = transposition_calc_chord_root(i, NT_SHARP); if (!transposed_root) { - DEBUG_MSG("transposition_calc_chord_root failed."); + LOG_DEBUG("transposition_calc_chord_root failed."); return 0; } chord->root = transposed_root; @@ -1575,7 +1636,7 @@ static int cho_chord_root_parse(const char *str, struct ChoChord *chord) if (flat && str_starts_with(str, flat)) { transposed_root = transposition_calc_chord_root(i, NT_FLAT); if (!transposed_root) { - DEBUG_MSG("transposition_calc_chord_root failed."); + LOG_DEBUG("transposition_calc_chord_root failed."); return 0; } chord->root = transposed_root; @@ -1585,7 +1646,7 @@ static int cho_chord_root_parse(const char *str, struct ChoChord *chord) if (str_starts_with(str, note)) { transposed_root = transposition_calc_chord_root(i, NT_NOTE); if (!transposed_root) { - DEBUG_MSG("transposition_calc_chord_root failed."); + LOG_DEBUG("transposition_calc_chord_root failed."); return 0; } chord->root = transposed_root; @@ -1997,7 +2058,7 @@ static struct ChoImage *cho_image_directive_parse(const char *str) case OS_VALUE: if (avs == AVS_NO) { if (is_whitespace(c)) { - fprintf(stderr, "ERR: Whitespace character after equals sign in image directive is invalid, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Whitespace character after equals sign in image directive is invalid."); return NULL; } if (c == '\'') { @@ -2012,7 +2073,7 @@ static struct ChoImage *cho_image_directive_parse(const char *str) break; } if (c == '\n') { - fprintf(stderr, "ERR: Newline character inside an option value in image directive is invalid, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Newline character inside an option value in image directive is invalid."); return NULL; } if ( @@ -2339,9 +2400,10 @@ END: return directive; } -struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) +struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) { g_config = config; + g_chordpro_filepath = chordpro_filepath; bool is_chord_already_initialized = false; char buf = 0; char prev_buf = '\n'; @@ -2396,6 +2458,9 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) while (feof(fp) == 0) { read = fread(&buf, 1, 1, fp); if (read == 1) { + if (buf == '\n') { + g_line_number++; + } // printf("state: %s, prev_state: %s, prev_buf: %c, buf: %c\n", cho_state_to_string(state), cho_state_to_string(prev_state), prev_buf, buf); if (buf == '\r') { continue; @@ -2530,12 +2595,12 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } break; default: - fprintf(stderr, "ERR: Invalid position value '%d', line '%ld'.\n", directive->position, g_line_number); + cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position); return NULL; } break; case DT_METADATA: - fprintf(stderr, "INFO: Metadata directive '%s' has no value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_INFO, "Metadata directive '%s' has no value.", directive_name); songs[so]->metadata = realloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); songs[so]->metadata[m] = cho_metadata_new(); songs[so]->metadata[m]->name = strdup(directive_name); @@ -2543,10 +2608,10 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) memset(directive_name, 0, strlen(directive_name)); break; case DT_FORMATTING: - fprintf(stderr, "WARN: Formatting directive '%s' has no value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_WARN, "Formatting directive '%s' has no value.", directive_name); break; case DT_IMAGE: - fprintf(stderr, "ERR: Directive 'image' has no value, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Directive 'image' has no value."); return NULL; case DT_PREAMBLE: // INFO: The only preamble directive is 'new_song' @@ -2560,7 +2625,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections = realloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); songs[so]->sections[se] = NULL; if (!cho_style_reset_default()) { - DEBUG_MSG("cho_style_reset_default failed."); + LOG_DEBUG("cho_style_reset_default failed."); return NULL; } so++; @@ -2591,11 +2656,11 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) sprop.u.foreground_color = NULL; break; default: - fprintf(stderr, "ERR: Invalid style property type '%d', line '%ld'.\n", directive->sprop, g_line_number); + cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop); return NULL; } if (!cho_style_change_default(sprop)) { - DEBUG_MSG("cho_style_change_default failed."); + LOG_DEBUG("cho_style_change_default failed."); return NULL; } break; @@ -2611,10 +2676,10 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) break; case DT_CUSTOM: // TODO: Implement {start_of_*} and {end_of_*} custom directives - fprintf(stderr, "INFO: Ignoring custom directive '%s', line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name); break; default: - fprintf(stderr, "ERR: Invalid directive '%s', line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_ERR, "Invalid directive '%s'.", directive_name); return NULL; } cho_directive_free(directive); @@ -2685,7 +2750,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } break; default: - fprintf(stderr, "ERR: Invalid position value '%d', line '%ld'.\n", directive->position, g_line_number); + cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position); return NULL; } break; @@ -2697,7 +2762,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->metadata[m] = metadata; m++; } else { - DEBUG_MSG("cho_metadata_split failed."); + LOG_DEBUG("cho_metadata_split failed."); return NULL; } } else { @@ -2738,13 +2803,13 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) case DT_IMAGE: image = cho_image_directive_parse(directive_value); if (!image) { - DEBUG_MSG("cho_image_directive_parse failed."); + LOG_DEBUG("cho_image_directive_parse failed."); return NULL; } cho_image_free(image); break; case DT_PREAMBLE: - fprintf(stderr, "ERR: Preamble directive '%s' can't have a value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name); return NULL; case DT_FONT: sprop.ftype = directive->ftype; @@ -2758,7 +2823,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) case SPT_SIZE: sprop.u.font_size = strtod(dir_value, NULL); if (sprop.u.font_size == 0.0) { - fprintf(stderr, "ERR: Font directive '%s' has an invalid value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); return NULL; } sprop.type = SPT_SIZE; @@ -2766,17 +2831,17 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) case SPT_COLOR: sprop.u.foreground_color = cho_color_parse(dir_value); if (sprop.u.foreground_color == NULL) { - fprintf(stderr, "ERR: Font directive '%s' has an invalid value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); return NULL; } sprop.type = SPT_COLOR; break; default: - fprintf(stderr, "ERR: Invalid style property type '%d', line '%ld'.\n", directive->sprop, g_line_number); + cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop); return NULL; } if (!cho_style_change_default(sprop)) { - DEBUG_MSG("cho_style_change_default failed."); + LOG_DEBUG("cho_style_change_default failed."); return NULL; } if (sprop.type == SPT_FONT) { @@ -2789,8 +2854,8 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) case DT_CHORD: /* INFO: The only chord directive is currently 'transpose' */ if (!transposition_parse(directive_value, &transpose)) { - DEBUG_MSG("transposition_parse failed."); - fprintf(stderr, "ERR: Directive 'transpose' has an invalid value, line '%ld'.\n", g_line_number); + LOG_DEBUG("transposition_parse failed."); + cho_log(LOG_ERR, "Directive 'transpose' has an invalid value."); return NULL; } g_transpose_history = realloc(g_transpose_history, (th+1) * sizeof(int *)); @@ -2799,13 +2864,13 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) th++; break; case DT_OUTPUT: - fprintf(stderr, "ERR: Directive '%s' can't have a value, line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_ERR, "Directive '%s' can't have a value.", directive_name); return NULL; case DT_CUSTOM: - fprintf(stderr, "INFO: Ignoring custom directive '%s', line '%ld'.\n", directive_name, g_line_number); + cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name); break; default: - fprintf(stderr, "ERR: Invalid directive '%d', line '%ld'.\n", directive->dtype, g_line_number); + cho_log(LOG_ERR, "Invalid directive type '%d'.", directive->dtype); return NULL; } memset(directive_value, 0, strlen(directive_value)); @@ -2829,7 +2894,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tmp_chord = cho_chord_parse(chord); cho_chord_complete(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord, tmp_chord); if (!songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->is_canonical) { - fprintf(stderr, "INFO: Didn't recognize the chord '%s', line '%ld'.\n", songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name, g_line_number); + cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name); } cho_chord_free(tmp_chord); is_chord_already_initialized = false; @@ -2842,7 +2907,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections[se]->lines[li]->text_above[c]->position = chord_pos; songs[so]->sections[se]->lines[li]->text_above[c]->u.chord = cho_chord_parse(chord); if (!songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->is_canonical) { - fprintf(stderr, "INFO: Didn't recognize the chord '%s', line '%ld'.\n", songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name, g_line_number); + cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->name); } // cho_debug_chord_print(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord); } @@ -2917,7 +2982,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tags[ta]->name = strdup(tag_begin); tag_style = cho_style_parse(tag_begin, NULL, cho_tag_style_inherit(tags, ta-1)); if (!tag_style) { - DEBUG_MSG("cho_style_parse failed."); + LOG_DEBUG("cho_style_parse failed."); return NULL; } tags[ta]->style = tag_style; @@ -2935,7 +3000,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_duplicate(tag_style); break; default: - fprintf(stderr, "ERR: Invalid prev_state '%s', line '%ld'.\n", state_enums[prev_state], g_line_number); + cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); return NULL; } memset(tag_begin, 0, strlen(tag_begin)); @@ -2952,8 +3017,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) break; } if (t == 5) { - tag_begin[t] = 0; - fprintf(stderr, "ERR: Begin tag name '%s' is too long, line '%ld'.\n", tag_begin, g_line_number); + cho_log(LOG_ERR, "Begin tag name is too long."); return NULL; } tag_begin[t] = buf; @@ -2975,7 +3039,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tag_end[t] = 0; t = 0; if (!cho_tag_close_last_unclosed(tag_end, tags, ta)) { - DEBUG_MSG("cho_tag_close_last_unclosed failed."); + LOG_DEBUG("cho_tag_close_last_unclosed failed."); return NULL; } memset(tag_end, 0, strlen(tag_end)); @@ -2983,8 +3047,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) break; } if (t == 5) { - tag_end[t] = 0; - fprintf(stderr, "ERR: End tag name '%s' is too long, line '%ld'.\n", tag_end, g_line_number); + cho_log(LOG_ERR, "End tag name is too long."); return NULL; } tag_end[t] = buf; @@ -3005,7 +3068,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } else { tags[ta]->attrs[at]->name = realloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); tags[ta]->attrs[at]->name[atn] = 0; - fprintf(stderr, "ERR: Attribute with name '%s' of tag '%s' has no value, line '%ld'.\n", tags[ta]->attrs[at]->name, tag_begin, g_line_number); + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_begin); return NULL; } } @@ -3017,7 +3080,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } tags[ta]->attrs[at]->name = realloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); tags[ta]->attrs[at]->name[atn] = 0; - fprintf(stderr, "ERR: Attribute with name '%s' of tag '%s' has no value, line '%ld'.\n", tags[ta]->attrs[at]->name, tag_begin, g_line_number); + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_begin); return NULL; } if (buf == '>') { @@ -3026,7 +3089,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tags[ta]->attrs[at] = NULL; tag_style = cho_style_parse(tag_begin, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); if (!tag_style) { - DEBUG_MSG("cho_style_parse failed."); + LOG_DEBUG("cho_style_parse failed."); return NULL; } tags[ta]->style = tag_style; @@ -3044,7 +3107,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_duplicate(tag_style); break; default: - fprintf(stderr, "ERR: Invalid prev_state '%s', line '%ld'.\n", state_enums[prev_state], g_line_number); + cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); return NULL; } at = 0; @@ -3055,7 +3118,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tags[ta]->attrs[at]->name = realloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); tags[ta]->attrs[at]->name[atn] = 0; atn = 0; - fprintf(stderr, "ERR: Attribute with name '%s' of tag '%s' has no value, line '%ld'.\n", tags[ta]->attrs[at]->name, tag_begin, g_line_number); + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_begin); return NULL; } } @@ -3066,11 +3129,11 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) case STATE_MARKUP_ATTR_VALUE: if (avs == AVS_NO) { if (is_whitespace(buf)) { - fprintf(stderr, "ERR: Whitespace character after equals sign is invalid, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Whitespace character after equals sign is invalid."); return NULL; } if (buf == '>') { - fprintf(stderr, "ERR: Attribute with name '%s' of tag '%s' has no value, line '%ld'.\n", tags[ta]->attrs[at]->name, tag_begin, g_line_number); + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_begin); return NULL; } if (buf == '\'') { @@ -3086,7 +3149,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) break; } if (buf == '\n') { - fprintf(stderr, "ERR: Newline character inside an attribute value is invalid, line '%ld'.\n", g_line_number); + cho_log(LOG_ERR, "Newline character inside an attribute value is invalid."); return NULL; } if (avs == AVS_UNQUOTED && buf == '>') { @@ -3098,7 +3161,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) tags[ta]->attrs[at] = NULL; tag_style = cho_style_parse(tag_begin, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); if (!tag_style) { - DEBUG_MSG("cho_style_parse failed."); + LOG_DEBUG("cho_style_parse failed."); return NULL; } tags[ta]->style = tag_style; @@ -3116,7 +3179,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_duplicate(tag_style); break; default: - fprintf(stderr, "ERR: Invalid prev_state '%s', line '%ld'.\n", state_enums[prev_state], g_line_number); + cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); return NULL; } at = 0; @@ -3153,12 +3216,12 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } prev_buf = buf; } else if (ferror(fp) != 0) { - DEBUG_MSG("fread failed."); + LOG_DEBUG("fread failed."); return NULL; } - if (buf == '\n') { + /* if (buf == '\n') { g_line_number++; - } + } */ } int e = 0; while (e <= ta) { @@ -3185,7 +3248,7 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) songs[so]->sections[se]->lines[li] = NULL; } if (!cho_style_reset_default()) { - DEBUG_MSG("cho_style_reset_default failed."); + LOG_DEBUG("cho_style_reset_default failed."); return NULL; } songs[so]->metadata = realloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); @@ -3209,7 +3272,9 @@ struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config) } } if (!exist_title) { - fprintf(stderr, "ERR: Song no. %d has no title.\n", so+1); + g_line_number = 0; + /* INFO: This cho_log() is not line specific. It's a workaround. */ + cho_log(LOG_ERR, "Song has no title."); return NULL; } exist_title = false; diff --git a/chordpro.h b/chordpro.h @@ -21,14 +21,6 @@ enum EnvironmentDirective { }; -/* enum MetadataDirective { - TITLE, SORTTITLE, SUBTITLE, - ARTIST, COMPOSER, LYRICIST, - COPYRIGHT, ALBUM, YEAR, KEY, - TIME, TEMPO, DURATION, CAPO, - META, ARRANGER -}; */ - enum FormattingDirective { COMMENT, C, HIGHLIGHT, COMMENT_ITALIC, CI, COMMENT_BOX, CB @@ -38,10 +30,6 @@ enum ImageDirectve { IMAGE }; -/* enum PreabmleDirective { - NEW_SONG, NS -}; */ - enum FontDirective { CHORDFONT, CF, CHORDSIZE, CS, CHORDCOLOR, CHORUSFONT, CHORUSSIZE, CHORUSCOLOR, @@ -331,7 +319,7 @@ struct ChoSong { struct ChoSection **sections; }; -struct ChoSong **cho_songs_parse(FILE *fp, struct Config *config); +struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config); int cho_song_count(struct ChoSong **songs); void cho_songs_free(struct ChoSong **song); diff --git a/config.c b/config.c @@ -425,7 +425,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch toml_table_t *font_section = toml_table_table(table, "font"); if (font_section) { if (!config_load_font(style->font, font_section, key_name)) { - DEBUG_MSG("config_load_font failed."); + LOG_DEBUG("config_load_font failed."); return false; } } @@ -570,7 +570,7 @@ struct Config *config_load(const char *filepath) char errbuf[200]; toml_table_t *table = toml_parse_file(fp, (char *)&errbuf, sizeof(errbuf)); if (!table) { - DEBUG_MSG("toml_parse_file failed."); + LOG_DEBUG("toml_parse_file failed."); fprintf(stderr, "ERR: Config file is not a valid toml file.\n"); fprintf(stderr, "%s\n", (char *)&errbuf); return NULL; @@ -595,7 +595,7 @@ struct Config *config_load(const char *filepath) config_notes_free(config->output->notes); config->output->notes = custom_notes; } else { - DEBUG_MSG("config_notes_load failed."); + LOG_DEBUG("config_notes_load failed."); fprintf(stderr, "ERR: Couldn't load custom notes '%s' from [notes] section.\n", value.u.s); return NULL; } @@ -619,7 +619,7 @@ struct Config *config_load(const char *filepath) item = config_printable_item_get(config->output->printable_items, key_name); if (item) { if (!config_load_style(item->style, key, key_name)) { - DEBUG_MSG("config_load_style failed."); + LOG_DEBUG("config_load_style failed."); return NULL; } } @@ -650,7 +650,7 @@ struct Config *config_load(const char *filepath) config_notes_free(config->parser->notes); config->parser->notes = custom_notes; } else { - DEBUG_MSG("config_notes_load failed."); + LOG_DEBUG("config_notes_load failed."); fprintf(stderr, "ERR: Couldn't load custom notes '%s' from [notes] section.\n", value.u.s); return NULL; } diff --git a/lorid.c b/lorid.c @@ -20,6 +20,7 @@ int main(int argc, char *argv[]) { 0, 0, 0, 0 } }; int o, option_index; + const char *chordpro_filepath = NULL; char *config_filepath = NULL; char *output = NULL; FILE *fp; @@ -46,7 +47,7 @@ int main(int argc, char *argv[]) } struct Config *config = config_load(config_filepath); if (!config) { - DEBUG_MSG("config_load failed."); + LOG_DEBUG("config_load failed."); return 1; } free(config_filepath); @@ -55,24 +56,25 @@ int main(int argc, char *argv[]) } else if (argc == optind+1) { fp = fopen(argv[argc-1], "r"); if (!fp) { - DEBUG_MSG("fopen failed."); + LOG_DEBUG("fopen failed."); return 1; } + chordpro_filepath = argv[argc-1]; } else { - fprintf(stderr, "ERR: Provide only one file.\n"); + util_log(LOG_ERR, "Provide only one file."); return 1; } - struct ChoSong **songs = cho_songs_parse(fp, config); + struct ChoSong **songs = cho_songs_parse(fp, chordpro_filepath, config); if (!songs) { - DEBUG_MSG("cho_parse failed."); + LOG_DEBUG("cho_songs_parse failed."); return 1; } char *pdf_filename = out_pdf_new(argc == optind+1 ? argv[argc-1] : NULL, output ? output : NULL, songs, config); if (!pdf_filename) { - DEBUG_MSG("out_pdf_new failed."); + LOG_DEBUG("out_pdf_new failed."); return 1; } - fprintf(stderr, "INFO: Writing pdf to file: '%s'\n", pdf_filename); + util_log(LOG_INFO, "Writing pdf to file: '%s'.", pdf_filename); free(pdf_filename); free(output); cho_songs_free(songs); diff --git a/out_pdf.c b/out_pdf.c @@ -181,7 +181,7 @@ static char *out_pdf_filename_create(struct ChoSong **songs, const char *cho_fil } else { pdf_filename = out_pdf_filename_generate_from_songs(songs); if (!pdf_filename) { - DEBUG_MSG("out_pdf_filename_generate_from_songs failed."); + LOG_DEBUG("out_pdf_filename_generate_from_songs failed."); return NULL; } } @@ -318,12 +318,12 @@ static bool out_pdf_font_set(pdfio_stream_t *stream, struct Font *font) return true; } if (!pdfioContentSetTextFont(stream, name, font->size)) { - DEBUG_MSG("pdfioContentSetTextFont failed."); + LOG_DEBUG("pdfioContentSetTextFont failed."); return false; } pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return false; } strcpy(g_current_font_name, name); @@ -371,7 +371,7 @@ static double text_width(struct TextLineItem *item) char *name = out_pdf_fnt_name_create(item->style->font); pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return -1.0; } free(name); @@ -384,7 +384,7 @@ static enum Bool text_fits(const char *str, struct Style *style) char *name = out_pdf_fnt_name_create(style->font); pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return B_ERROR; } free(name); @@ -423,7 +423,7 @@ static char *text_find_fitting(const char *str, struct Style *style) tmp[i] = 0; fits = text_fits((const char *)&tmp, style); if (fits == B_ERROR) { - DEBUG_MSG("text_fits failed."); + LOG_DEBUG("text_fits failed."); return NULL; } start = i - 1; @@ -445,7 +445,7 @@ static struct TextLine **text_split_by_whitespace(const char *str, struct Style while (1) { fits = text_fits(text, style); if (fits == B_ERROR) { - DEBUG_MSG("text_fits failed."); + LOG_DEBUG("text_fits failed."); return NULL; } if (fits) { @@ -461,7 +461,7 @@ static struct TextLine **text_split_by_whitespace(const char *str, struct Style } fitting = text_find_fitting(text, style); if (!fitting) { - DEBUG_MSG("text_find_fitting failed."); + LOG_DEBUG("text_find_fitting failed."); return NULL; } line = text_line_create(fitting, style); @@ -487,7 +487,7 @@ static enum Bool text_line_fits(struct TextLine *line) } width = text_width(line->items[i-1]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return B_ERROR; } if (line->items[i-1]->x + width > LINE_WIDTH) { @@ -520,19 +520,19 @@ static bool out_pdf_draw_line(pdfio_stream_t *stream, struct TextLineItem *item, break; } if (!pdfioContentPathMoveTo(stream, item->x, y)) { - DEBUG_MSG("pdfioContentPathMoveTo failed."); + LOG_DEBUG("pdfioContentPathMoveTo failed."); return false; } if (!pdfioContentPathLineTo(stream, item->x + width, y)) { - DEBUG_MSG("pdfioContentPathLineTo failed."); + LOG_DEBUG("pdfioContentPathLineTo failed."); return false; } if (!pdfioContentSetStrokeColorRGB(stream, red, green, blue)) { - DEBUG_MSG("pdfioContentSetStrokeColorRGB failed."); + LOG_DEBUG("pdfioContentSetStrokeColorRGB failed."); return false; } if (!pdfioContentStroke(stream)) { - DEBUG_MSG("pdfioContentStroke failed."); + LOG_DEBUG("pdfioContentStroke failed."); return false; } return true; @@ -544,38 +544,38 @@ static bool out_pdf_text_show(pdfio_stream_t *stream, struct TextLineItem *item, // TODO: Maybe store the width in TextLineItem width = text_width(item); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return false; } if (!out_pdf_font_set(stream, item->style->font)) { - DEBUG_MSG("out_pdf_font_set failed."); + LOG_DEBUG("out_pdf_font_set failed."); return false; } red = item->style->foreground_color->red / 255.0; green = item->style->foreground_color->green / 255.0; blue = item->style->foreground_color->blue / 255.0; if (!pdfioContentSetFillColorRGB(stream, red, green, blue)) { - DEBUG_MSG("pdfioContentSetFillColorRGB failed."); + LOG_DEBUG("pdfioContentSetFillColorRGB failed."); return false; } if (!pdfioContentTextBegin(stream)) { - DEBUG_MSG("pdfioContentTextBegin failed."); + LOG_DEBUG("pdfioContentTextBegin failed."); return false; } if (!pdfioContentTextMoveTo(stream, item->x, y)) { - DEBUG_MSG("pdfioContentTextMoveTo failed."); + LOG_DEBUG("pdfioContentTextMoveTo failed."); return false; } if (!pdfioContentSetTextRise(stream, item->style->rise)) { - DEBUG_MSG("pdfioContentSetTextRise failed."); + LOG_DEBUG("pdfioContentSetTextRise failed."); return false; } if (!pdfioContentTextShow(stream, true, item->text)) { - DEBUG_MSG("pdfioContentTextShow failed."); + LOG_DEBUG("pdfioContentTextShow failed."); return false; } if (!pdfioContentTextEnd(stream)) { - DEBUG_MSG("pdfioContentTextEnd failed."); + LOG_DEBUG("pdfioContentTextEnd failed."); return false; } if (item->style->underline_style == LS_SINGLE) { @@ -598,15 +598,15 @@ static bool out_pdf_text_show(pdfio_stream_t *stream, struct TextLineItem *item, green = item->style->boxed_color->green / 255.0; blue = item->style->boxed_color->blue / 255.0; if (!pdfioContentSetStrokeColorRGB(stream, red, green, blue)) { - DEBUG_MSG("pdfioContentSetFillColorRGB failed."); + LOG_DEBUG("pdfioContentSetFillColorRGB failed."); return false; } if (!pdfioContentPathRect(stream, item->x - 2.0, y - 2.0, width + 4.0, item->style->font->size * 0.8 + 4.0)) { - DEBUG_MSG("pdfioContentPathRect failed."); + LOG_DEBUG("pdfioContentPathRect failed."); return false; } if (!pdfioContentStroke(stream)) { - DEBUG_MSG("pdfioContentStroke failed."); + LOG_DEBUG("pdfioContentStroke failed."); return false; } } @@ -644,7 +644,7 @@ static double line_width_until_chord(struct ChoLine *line, struct ChoLineItemAbo name = out_pdf_fnt_name_create(line->lyrics[ly]->style->font); font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return EMPTY; } if (ly == last_ly) { @@ -678,7 +678,7 @@ static enum Bool out_pdf_text_above_is_enough_space(struct ChoLine *line, struct name = out_pdf_fnt_name_create(prev_text_above->u.chord->style->font); font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return B_ERROR; } free(name); @@ -687,7 +687,7 @@ static enum Bool out_pdf_text_above_is_enough_space(struct ChoLine *line, struct name = out_pdf_fnt_name_create(prev_text_above->u.annot->style->font); font_obj = out_pdf_fnt_obj_get_by_name(name); if (!font_obj) { - DEBUG_MSG("out_pdf_fnt_obj_get_by_name failed."); + LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); return B_ERROR; } free(name); @@ -740,7 +740,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) if (!strcmp(songs[so]->metadata[m]->name, "title")) { fits = text_fits(songs[so]->metadata[m]->value, songs[so]->metadata[m]->style); if (fits == B_ERROR) { - DEBUG_MSG("text_fits failed."); + LOG_DEBUG("text_fits failed."); return NULL; } if (fits) { @@ -752,7 +752,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[0]->style = cho_style_duplicate(songs[so]->metadata[m]->style); width = text_width(text[t]->lines[tl]->items[0]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text[t]->lines[tl]->items[0]->x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2; @@ -771,7 +771,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) for (int i = 0; text_lines[i]; i++) { width = text_width(text_lines[i]->items[0]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text_lines[i]->items[0]->x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2; @@ -787,13 +787,13 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) if (!strcmp(songs[so]->metadata[m]->name, "subtitle")) { fits = text_fits(songs[so]->metadata[m]->value, songs[so]->metadata[m]->style); if (fits == B_ERROR) { - DEBUG_MSG("text_fits failed."); + LOG_DEBUG("text_fits failed."); return NULL; } if (fits) { printable_item = config_printable_item_get(config->output->printable_items, "subtitle"); if (!printable_item) { - DEBUG_MSG("config_printable_item_get failed."); + LOG_DEBUG("config_printable_item_get failed."); return NULL; } text[t]->lines = realloc(text[t]->lines, (tl+1) * sizeof(struct TextLine *)); @@ -804,7 +804,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[0]->style = cho_style_duplicate(printable_item->style); width = text_width(text[t]->lines[tl]->items[0]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text[t]->lines[tl]->items[0]->x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2; @@ -823,7 +823,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) for (int i = 0; text_lines[i]; i++) { width = text_width(text_lines[i]->items[0]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text_lines[i]->items[0]->x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2; @@ -845,7 +845,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) if (songs[so]->sections[se]->label) { fits = text_fits(songs[so]->sections[se]->label->name, songs[so]->sections[se]->label->style); if (fits == B_ERROR) { - DEBUG_MSG("text_fits failed."); + LOG_DEBUG("text_fits failed."); return NULL; } if (fits) { @@ -871,7 +871,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) for (int i = 0; text_lines[i]; i++) { width = text_width(text_lines[i]->items[0]); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } // text_lines[i]->items[0]->x = MARGIN_HORIZONTAL + (LINE_WIDTH - width) / 2; @@ -904,7 +904,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[tli] = malloc(sizeof(struct TextLineItem)); double width_until = line_width_until_chord(lines[li], text_above[ch], NULL); if (width_until == EMPTY) { - DEBUG_MSG("line_width_until_chord failed."); + LOG_DEBUG("line_width_until_chord failed."); return NULL; } if (tli == 0) { @@ -925,7 +925,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) tmp.text = text_above[b]->u.annot->text; width = text_width(&tmp); if (width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text[t]->lines[tl]->items[tli]->x += width; @@ -948,7 +948,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) } enough_space = out_pdf_text_above_is_enough_space(songs[so]->sections[se]->lines[li], text_above[ch], text_above[ch+1], &space); if (enough_space == B_ERROR) { - DEBUG_MSG("out_pdf_text_above_is_enough_space failed."); + LOG_DEBUG("out_pdf_text_above_is_enough_space failed."); return NULL; } if (!enough_space) { @@ -968,7 +968,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[tli] = NULL; fits = text_line_fits(text[t]->lines[tl]); if (fits == B_ERROR) { - DEBUG_MSG("text_line_fits failed."); + LOG_DEBUG("text_line_fits failed."); return NULL; } if (!fits) { @@ -1009,7 +1009,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) } else { last_text_line_item_width = text_width(text[t]->lines[tl]->items[tli-1]); if (last_text_line_item_width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text[t]->lines[tl]->items[tli]->x = text[t]->lines[tl]->items[tli-1]->x + last_text_line_item_width; @@ -1030,7 +1030,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[tli]->style = cho_style_duplicate(lines[li]->lyrics[ly]->style); last_text_line_item_width = text_width(text[t]->lines[tl]->items[tli-1]); if (last_text_line_item_width == EMPTY) { - DEBUG_MSG("text_width failed."); + LOG_DEBUG("text_width failed."); return NULL; } text[t]->lines[tl]->items[tli]->x = text[t]->lines[tl]->items[tli-1]->x + last_text_line_item_width + sp->amount; @@ -1048,7 +1048,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items[tli] = NULL; fits = text_line_fits(text[t]->lines[tl]); if (fits == B_ERROR) { - DEBUG_MSG("text_line_fits failed."); + LOG_DEBUG("text_line_fits failed."); return NULL; } if (!fits) { @@ -1119,24 +1119,24 @@ static pdfio_dict_t *annot_create(pdfio_file_t *pdf, const char *uri, pdfio_rect { pdfio_dict_t *annot = pdfioDictCreate(pdf); if (!pdfioDictSetName(annot, "Subtype", "Link")) { - DEBUG_MSG("pdfioDictSetName failed."); + LOG_DEBUG("pdfioDictSetName failed."); return NULL; } if (!pdfioDictSetRect(annot, "Rect", rect)) { - DEBUG_MSG("pdfioDictSetRect failed."); + LOG_DEBUG("pdfioDictSetRect failed."); return NULL; } pdfio_dict_t *action = pdfioDictCreate(pdf); if (!pdfioDictSetName(action, "S", "URI")) { - DEBUG_MSG("pdfioDictSetName failed."); + LOG_DEBUG("pdfioDictSetName failed."); return NULL; } if (!pdfioDictSetString(action, "URI", uri)) { - DEBUG_MSG("pdfioDictSetString failed."); + LOG_DEBUG("pdfioDictSetString failed."); return NULL; } if (!pdfioDictSetDict(annot, "A", action)) { - DEBUG_MSG("pdfioDictSetDict failed."); + LOG_DEBUG("pdfioDictSetDict failed."); return NULL; } return annot; @@ -1152,7 +1152,7 @@ static bool annots_create(pdfio_file_t *pdf, pdfio_array_t *annots, struct Text int t, tl, tli; pdfio_array_t *page_annots = pdfioArrayCreate(pdf); if (!page_annots) { - DEBUG_MSG("pdfioArrayCreate failed."); + LOG_DEBUG("pdfioArrayCreate failed."); return false; } for (t = 0; text[t]; t++) { @@ -1168,11 +1168,11 @@ static bool annots_create(pdfio_file_t *pdf, pdfio_array_t *annots, struct Text rect.y2 = y + item->style->font->size * 0.8; annot = annot_create(pdf, item->style->href, &rect); if (!annot) { - DEBUG_MSG("annot_create failed."); + LOG_DEBUG("annot_create failed."); return false; } if (!pdfioArrayAppendDict(page_annots, annot)) { - DEBUG_MSG("pdfioArrayAppendDict failed."); + LOG_DEBUG("pdfioArrayAppendDict failed."); return false; } } @@ -1180,12 +1180,12 @@ static bool annots_create(pdfio_file_t *pdf, pdfio_array_t *annots, struct Text } if (text[t]->lines[tl]->btype == BT_PAGE) { if (!pdfioArrayAppendArray(annots, page_annots)) { - DEBUG_MSG("pdfioArrayAppendArray failed."); + LOG_DEBUG("pdfioArrayAppendArray failed."); return false; } page_annots = pdfioArrayCreate(pdf); if (!page_annots) { - DEBUG_MSG("pdfioArrayCreate failed."); + LOG_DEBUG("pdfioArrayCreate failed."); return false; } y = MEDIABOX_HEIGHT - MARGIN_TOP; @@ -1195,7 +1195,7 @@ static bool annots_create(pdfio_file_t *pdf, pdfio_array_t *annots, struct Text } } if (!pdfioArrayAppendArray(annots, page_annots)) { - DEBUG_MSG("pdfioArrayAppendArray failed."); + LOG_DEBUG("pdfioArrayAppendArray failed."); return false; } return true; @@ -1225,27 +1225,27 @@ static pdfio_stream_t *out_pdf_page_create(pdfio_file_t *pdf, pdfio_array_t *ann pdfio_array_t *color_array = pdfioArrayCreateColorFromStandard(pdf, 3, PDFIO_CS_ADOBE); page_dict = pdfioDictCreate(pdf); if (!pdfioPageDictAddColorSpace(page_dict, "rgbcolorspace", color_array)) { - DEBUG_MSG("pdfioPageDictAddColorSpace failed."); + LOG_DEBUG("pdfioPageDictAddColorSpace failed."); return false; } for (f = 0; g_fonts[f]; f++) { if (!pdfioPageDictAddFont(page_dict, g_fonts[f]->name, g_fonts[f]->font)) { - DEBUG_MSG("pdfioPageDictAddFont failed."); + LOG_DEBUG("pdfioPageDictAddFont failed."); return false; } } page_annots = pdfioArrayGetArray(annots, page_no); if (!pdfioDictSetArray(page_dict, "Annots", page_annots)) { - DEBUG_MSG("pdfioDictSetArray failed."); + LOG_DEBUG("pdfioDictSetArray failed."); return false; } page_stream = pdfioFileCreatePage(pdf, page_dict); if (!pdfioContentSetFillColorSpace(page_stream, "rgbcolorspace")) { - DEBUG_MSG("pdfioContentSetFillColorSpace failed."); + LOG_DEBUG("pdfioContentSetFillColorSpace failed."); return false; } if (!pdfioContentSetStrokeColorSpace(page_stream, "rgbcolorspace")) { - DEBUG_MSG("pdfioContentSetStrokeColorSpace failed."); + LOG_DEBUG("pdfioContentSetStrokeColorSpace failed."); return false; } return page_stream; @@ -1256,14 +1256,14 @@ char *out_pdf_new(const char *cho_filepath, const char *output_folder_or_file, s memset(&g_current_font_name, 0, sizeof(g_current_font_name)); char *pdf_filename = out_pdf_filename_create(songs, cho_filepath, output_folder_or_file); if (!pdf_filename) { - DEBUG_MSG("out_pdf_filename_create failed."); + LOG_DEBUG("out_pdf_filename_create failed."); return NULL; } pdfio_rect_t media_box_a4 = { 0.0, 0.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; pdfio_rect_t crop_box = { 36.0, 36.0, MEDIABOX_WIDTH, MEDIABOX_HEIGHT }; pdfio_file_t *pdf = pdfioFileCreate(pdf_filename, "2.0", &media_box_a4, &crop_box, NULL, NULL); if (!out_pdf_set_title(pdf, songs)) { - DEBUG_MSG("out_pdf_set_title failed."); + LOG_DEBUG("out_pdf_set_title failed."); return NULL; } struct Font **needed_fonts = out_pdf_font_get_all(songs, config); @@ -1297,12 +1297,12 @@ char *out_pdf_new(const char *cho_filepath, const char *output_folder_or_file, s cho_fonts_free(needed_fonts); struct Text **text = text_create(songs, config); if (!text) { - DEBUG_MSG("text_create failed."); + LOG_DEBUG("text_create failed."); return NULL; } pdfio_array_t *annots = pdfioArrayCreate(pdf); if (!annots_create(pdf, annots, text)) { - DEBUG_MSG("annotations_create failed."); + LOG_DEBUG("annotations_create failed."); return NULL; } pdfio_stream_t *page_stream; @@ -1319,7 +1319,7 @@ char *out_pdf_new(const char *cho_filepath, const char *output_folder_or_file, s } if (text[t]->lines[tl]->btype == BT_PAGE) { if (!pdfioStreamClose(page_stream)) { - DEBUG_MSG("pdfioStreamClose failed."); + LOG_DEBUG("pdfioStreamClose failed."); return NULL; } p++; @@ -1331,11 +1331,11 @@ char *out_pdf_new(const char *cho_filepath, const char *output_folder_or_file, s } } if (!pdfioStreamClose(page_stream)) { - DEBUG_MSG("pdfioStreamClose failed."); + LOG_DEBUG("pdfioStreamClose failed."); return NULL; } if (!pdfioFileClose(pdf)) { - DEBUG_MSG("pdfioFileClose failed."); + LOG_DEBUG("pdfioFileClose failed."); return NULL; } text_free(text); diff --git a/todo b/todo @@ -22,4 +22,8 @@ render in two or more columns find better name for PrintableItem, TextAbove consider freeing memory in case of errors -add line number to error, warning and info fprintf's. +decide and then change consistent global variables prefix 'g_' or not +change logging: + #define LOG_DEBUG + #define LOG_INFO + <filepath> <line_number> <log_level> <msg> diff --git a/util.c b/util.c @@ -1,10 +1,58 @@ +#include <stdio.h> #include <stdlib.h> #include <stdbool.h> +#include <stdarg.h> #include <ctype.h> #include <string.h> #include <sys/stat.h> +#include <errno.h> #include "util.h" +void util_log(enum LogLevel level, const char *msg, ...) +{ +#if COLOR == 1 + const char *log_level = ""; + const char *color = ""; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + color = "37"; + break; + case LOG_WARN: + log_level = "WARN"; + color = "33"; + break; + case LOG_ERR: + log_level = " ERR"; + color = "31"; + break; + } + fprintf(stderr, "\033[1m\033[%sm%s\033[0m: ", color, log_level); + va_list va; + va_start(va, msg); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); +#else + const char *log_level = ""; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + break; + case LOG_WARN: + log_level = "WARN"; + break; + case LOG_ERR: + log_level = " ERR"; + break; + } + fprintf(stderr, "%s: ", log_level); + va_list va; + va_start(va, msg); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); +#endif +} + bool str_starts_with(const char *str, const char *part) { unsigned int i; @@ -93,6 +141,26 @@ char *str_remove_leading_whitespace(const char *str) return strdup(&str[i]); } +short str_parse_as_percent(const char *str) +{ + if (strlen(str) > 4) { + return -1; + } + long l; + char *endptr; + l = strtol(str, &endptr, 10); + if (str == endptr) { + return -1; + } + if (errno == ERANGE) { + return -1; + } + if (l < 1 || l > 100) { + return -1; + } + return (short)l; +} + enum FileType file_type(const char *path) { struct stat s; diff --git a/util.h b/util.h @@ -1,9 +1,15 @@ #ifdef DEBUG -#define DEBUG_MSG(msg) fprintf(stderr, msg"\n") +#define LOG_DEBUG(msg) fprintf(stderr, msg"\n") #else -#define DEBUG_MSG(msg) +#define LOG_DEBUG(msg) #endif +enum LogLevel { + LOG_INFO, + LOG_WARN, + LOG_ERR +}; + enum FileType { F_ERROR, F_FOLDER, @@ -11,10 +17,13 @@ enum FileType { F_OTHER }; +void util_log(enum LogLevel level, const char *msg, ...); + bool str_starts_with(const char *str, const char *part); char *str_normalize(const char *str); char *str_trim(const char *str); char *str_remove_leading_whitespace(const char *str); +short str_parse_as_percent(const char *str); enum FileType file_type(const char *path); char *file_extension_replace_or_add(const char *old, const char *extension); @@ -22,3 +31,4 @@ char *file_extension_replace_or_add(const char *old, const char *extension); char *filepath_add_ending_slash_if_missing(const char *path); char *filepath_basename(const char *path); char *filepath_dirname(const char *path); +