lorid

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

commit 839d04eea6d10aa8b8396fde89bd48215a0898a4
parent ed845e75a1e73877454fb70958bb06a437f23825
Author: nibo <nibo@relim.de>
Date:   Thu, 20 Feb 2025 11:54:09 +0100

Move global variables into 'struct ChoContext'

Diffstat:
Msrc/chordpro.c | 753++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/chordpro.h | 7+++++++
2 files changed, 387 insertions(+), 373 deletions(-)

diff --git a/src/chordpro.c b/src/chordpro.c @@ -145,15 +145,6 @@ static const char *chord_extensions_minor[] = { }; static bool g_show_info_logs = false; -static enum TextType g_current_ttype = TT_TEXT; -static enum TextType g_prev_ttype = TT_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; -struct ChoImage **g_image_assets = NULL; -static int g_ia = 0; #ifdef DEBUG @@ -266,7 +257,7 @@ cho_log_enable_info_logs(void) #if COLOR == 1 static void -cho_log(enum LogLevel level, const char *msg, ...) +cho_log(struct ChoContext *ctx, enum LogLevel level, const char *msg, ...) { if (level == LOG_INFO && !g_show_info_logs) { return; @@ -294,25 +285,25 @@ cho_log(enum LogLevel level, const char *msg, ...) break; } if (isatty(2)) { - if (g_chordpro_filepath) { + if (ctx->chordpro_filepath) { fprintf(stderr, COLOR_BOLD_WHITE"%s:%ld:"COLOR_RESET" %s%s"COLOR_RESET": ", - g_chordpro_filepath, g_line_number, color, log_level); + ctx->chordpro_filepath, ctx->line_number, color, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } else { fprintf(stderr, "line "COLOR_BOLD_WHITE"%ld:"COLOR_RESET" %s%s"COLOR_RESET": ", - g_line_number, color, log_level); + ctx->line_number, color, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } } else { - if (g_chordpro_filepath) { - fprintf(stderr, "%s:%ld: %s: ", g_chordpro_filepath, g_line_number, + if (ctx->chordpro_filepath) { + fprintf(stderr, "%s:%ld: %s: ", ctx->chordpro_filepath, ctx->line_number, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } else { - fprintf(stderr, "line %ld: %s: ", g_line_number, log_level); + fprintf(stderr, "line %ld: %s: ", ctx->line_number, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } @@ -320,7 +311,7 @@ cho_log(enum LogLevel level, const char *msg, ...) } #else static void -cho_log(enum LogLevel level, const char *msg, ...) +cho_log(struct ChoContext *ctx, enum LogLevel level, const char *msg, ...) { if (level == LOG_INFO && !g_show_info_logs) { return; @@ -342,13 +333,13 @@ cho_log(enum LogLevel level, const char *msg, ...) log_level = "TODO"; break; } - if (g_chordpro_filepath) { - fprintf(stderr, "%s:%ld: %s: ", g_chordpro_filepath, g_line_number, + if (ctx->chordpro_filepath) { + fprintf(stderr, "%s:%ld: %s: ", ctx->chordpro_filepath, ctx->line_number, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } else { - fprintf(stderr, "line %ld: %s: ", g_line_number, log_level); + fprintf(stderr, "line %ld: %s: ", ctx->line_number, log_level); vfprintf(stderr, msg, va); fprintf(stderr, "\n"); } @@ -409,7 +400,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[2]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -423,7 +414,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[4]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -437,7 +428,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[6]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -453,7 +444,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[1]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -467,7 +458,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[2]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -481,7 +472,7 @@ cho_rgbcolor_parse(const char *str) tmp[1] = str[3]; primary_color = strtol((char *)&tmp, NULL, 16); if (primary_color == 0) { - cho_log(LOG_ERR, "Invalid primary color in rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid primary color in rgb color."); free(color); return NULL; } else { @@ -489,7 +480,7 @@ cho_rgbcolor_parse(const char *str) } } } else { - cho_log(LOG_ERR, "Invalid rgb color."); + // cho_log(ctx, LOG_ERR, "Invalid rgb color."); free(color); return NULL; } @@ -547,7 +538,8 @@ cho_color_parse(const char *str) color->green = 0; color->blue = 0; } else { - cho_log(LOG_ERR, "Invalid color value '%s'.", str); + // TODO: If this is called by config.c what should 'ctx' have as value + // cho_log(ctx, LOG_ERR, "Invalid color value '%s'.", str); free(color); return NULL; } @@ -776,7 +768,12 @@ cho_debug_style_print(struct ChoStyle *style) #endif /* DEBUG */ static bool -cho_style_property_apply_default(enum TextType current_ttype, enum StylePropertyType ptype, struct ChoStyle *style) +cho_style_property_apply_default( + struct ChoContext *ctx, + enum TextType current_ttype, + enum StylePropertyType ptype, + struct ChoStyle *style +) { unsigned int i; for (i = 0; i<LENGTH(default_style_properties); i++) { @@ -812,7 +809,7 @@ cho_style_property_apply_default(enum TextType current_ttype, enum StyleProperty } break; default: - cho_log(LOG_WARN, "Invalid style property type '%d'.", ptype); + cho_log(ctx, LOG_WARN, "Invalid style property type '%d'.", ptype); return false; } } @@ -821,22 +818,22 @@ cho_style_property_apply_default(enum TextType current_ttype, enum StyleProperty } static void -cho_style_apply_default(enum TextType current_ttype, struct ChoStyle *style) +cho_style_apply_default(struct ChoContext *ctx, enum TextType current_ttype, struct ChoStyle *style) { if (current_ttype == TT_CHORUS) { - if (!cho_style_property_apply_default(TT_CHORUS, SPT_FONT, style)) { - cho_style_property_apply_default(TT_TEXT, SPT_FONT, style); + if (!cho_style_property_apply_default(ctx, TT_CHORUS, SPT_FONT, style)) { + cho_style_property_apply_default(ctx, TT_TEXT, SPT_FONT, style); } - if (!cho_style_property_apply_default(TT_CHORUS, SPT_SIZE, style)) { - cho_style_property_apply_default(TT_TEXT, SPT_SIZE, style); + if (!cho_style_property_apply_default(ctx, TT_CHORUS, SPT_SIZE, style)) { + cho_style_property_apply_default(ctx, TT_TEXT, SPT_SIZE, style); } - if (!cho_style_property_apply_default(TT_CHORUS, SPT_COLOR, style)) { - cho_style_property_apply_default(TT_TEXT, SPT_COLOR, style); + if (!cho_style_property_apply_default(ctx, TT_CHORUS, SPT_COLOR, style)) { + cho_style_property_apply_default(ctx, TT_TEXT, SPT_COLOR, style); } } else { - cho_style_property_apply_default(current_ttype, SPT_FONT, style); - cho_style_property_apply_default(current_ttype, SPT_SIZE, style); - cho_style_property_apply_default(current_ttype, SPT_COLOR, style); + cho_style_property_apply_default(ctx, current_ttype, SPT_FONT, style); + cho_style_property_apply_default(ctx, current_ttype, SPT_SIZE, style); + cho_style_property_apply_default(ctx, current_ttype, SPT_COLOR, style); } } @@ -949,20 +946,20 @@ cho_style_complement( } static struct ChoStyle * -cho_style_new_from_config(enum TextType ttype) +cho_style_new_from_config(struct ChoContext *ctx, enum TextType ttype) { - return cho_style_copy(g_config->output->styles[ttype]); + return cho_style_copy(ctx->config->output->styles[ttype]); } static struct ChoStyle * -cho_style_new_default(void) +cho_style_new_default(struct ChoContext *ctx) { - struct ChoStyle *style = cho_style_new_from_config(g_current_ttype); + struct ChoStyle *style = cho_style_new_from_config(ctx, ctx->current_ttype); if (!style) { LOG_DEBUG("cho_style_new_from_config failed."); return NULL; } - cho_style_apply_default(g_current_ttype, style); + cho_style_apply_default(ctx, ctx->current_ttype, style); return style; } @@ -1107,6 +1104,7 @@ cho_style_font_desc_parse(const char *str, struct ChoStylePresence *presence) static struct ChoStyle * cho_style_parse( + struct ChoContext *ctx, const char *tag_name, struct Attr **attrs, struct ChoStyle *inherited_style, @@ -1120,7 +1118,7 @@ cho_style_parse( if (inherited_style) { style = cho_style_copy(inherited_style); } else { - style = cho_style_new_default(); + style = cho_style_new_default(ctx); } if (!strcmp(tag_name, "span")) { int a; @@ -1151,7 +1149,7 @@ cho_style_parse( style->font->family = FF_MONOSPACE; presence->font.family = true; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'font_family/face'."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'font_family/face'."); return NULL; } } else if (!strcmp(attrs[a]->name, "size")) { @@ -1165,11 +1163,11 @@ cho_style_parse( style->font->size *= percentage / 100.0; presence->font.size = true; } else { - cho_log(LOG_ERR, "Invalid percentage in attribute 'size'."); + cho_log(ctx, LOG_ERR, "Invalid percentage in attribute 'size'."); return NULL; } } else { - cho_log(LOG_ERR, "Invalid percentage in attribute 'size'."); + cho_log(ctx, LOG_ERR, "Invalid percentage in attribute 'size'."); return NULL; } } else if (isdigit(attrs[a]->value[0]) != 0) { @@ -1178,7 +1176,7 @@ cho_style_parse( style->font->size = size; presence->font.size = true; } else { - cho_log(LOG_ERR, "Invalid number in attribute 'size'."); + cho_log(ctx, LOG_ERR, "Invalid number in attribute 'size'."); return NULL; } } else if (!strcmp(attrs[a]->value, "xx-small")) { @@ -1213,7 +1211,7 @@ cho_style_parse( style->font->size *= 0.8; presence->font.size = true; } else { - cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'size'.", attrs[a]->value); + cho_log(ctx, LOG_ERR, "Invalid value '%s' for the attribute 'size'.", attrs[a]->value); return NULL; } } else if (!strcmp(attrs[a]->name, "style")) { @@ -1227,7 +1225,7 @@ cho_style_parse( style->font->style = FS_ITALIC; presence->font.style = true; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'style'."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'style'."); return NULL; } } else if (!strcmp(attrs[a]->name, "weight")) { @@ -1238,7 +1236,7 @@ cho_style_parse( style->font->weight = FW_BOLD; presence->font.weight = true; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'weight'."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'weight'."); return NULL; } } else if (!strcmp(attrs[a]->name, "foreground")) { @@ -1272,7 +1270,7 @@ cho_style_parse( style->underline_style = LS_NONE; presence->underline_style = true; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'underline'."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'underline'."); return NULL; } } else if (!strcmp(attrs[a]->name, "underline_colour")) { @@ -1296,7 +1294,7 @@ cho_style_parse( style->overline_style = LS_NONE; presence->overline_style = true; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'overline'."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'overline'."); return NULL; } } else if (!strcmp(attrs[a]->name, "overline_colour")) { @@ -1321,7 +1319,7 @@ cho_style_parse( style->rise = (style->font->size / 2) * percentage / 100.0; presence->rise = true; } else { - cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'."); + cho_log(ctx, LOG_ERR, "Invalid percentage in attribute 'rise'."); return NULL; } } @@ -1331,11 +1329,11 @@ cho_style_parse( style->rise = rise; presence->rise = true; } else { - cho_log(LOG_ERR, "Invalid number in attribute 'rise'."); + cho_log(ctx, LOG_ERR, "Invalid number in attribute 'rise'."); return NULL; } } else { - cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); + cho_log(ctx, LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); return NULL; } } else { @@ -1349,7 +1347,7 @@ cho_style_parse( style->rise += more; presence->rise = true; } else { - cho_log(LOG_ERR, "Invalid percentage in attribute 'rise'."); + cho_log(ctx, LOG_ERR, "Invalid percentage in attribute 'rise'."); return NULL; } } @@ -1359,11 +1357,11 @@ cho_style_parse( style->rise = rise; presence->rise = true; } else { - cho_log(LOG_ERR, "Invalid number in attribute 'rise'."); + cho_log(ctx, LOG_ERR, "Invalid number in attribute 'rise'."); return NULL; } } else { - cho_log(LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); + cho_log(ctx, LOG_ERR, "Invalid value '%s' for the attribute 'rise'.", attrs[a]->value); return NULL; } } @@ -1375,7 +1373,7 @@ cho_style_parse( style->strikethrough = false; presence->strikethrough = true; } else { - cho_log(LOG_ERR, "Invalid value '%s' in attribute 'strikethrough'.", attrs[a]->value); + cho_log(ctx, LOG_ERR, "Invalid value '%s' in attribute 'strikethrough'.", attrs[a]->value); return NULL; } } else if (!strcmp(attrs[a]->name, "strikethrough_colour")) { @@ -1392,7 +1390,7 @@ cho_style_parse( style->href = strdup(attrs[a]->value); presence->href = true; } else { - cho_log(LOG_ERR, "Invalid attribute '%s'.", attrs[a]->name); + cho_log(ctx, LOG_ERR, "Invalid attribute '%s'.", attrs[a]->name); return NULL; } } @@ -1428,7 +1426,7 @@ cho_style_parse( style->underline_style = LS_SINGLE; presence->underline_style = true; } else { - cho_log(LOG_ERR, "Invalid tag name '%s'.", tag_name); + cho_log(ctx, LOG_ERR, "Invalid tag name '%s'.", tag_name); cho_style_free(style); return NULL; } @@ -1454,7 +1452,7 @@ cho_style_print_as_toml(struct ChoStyle *style, const char *section) } static bool -cho_style_change_default(struct StyleProperty sprop) +cho_style_change_default(struct ChoContext *ctx, struct StyleProperty sprop) { if (sprop.type == -1) return false; @@ -1485,7 +1483,7 @@ cho_style_change_default(struct StyleProperty sprop) } return true; default: - cho_log(LOG_ERR, "Invalid style property type '%d'.", sprop.type); + cho_log(ctx, LOG_ERR, "Invalid style property type '%d'.", sprop.type); return false; } } @@ -1494,7 +1492,7 @@ cho_style_change_default(struct StyleProperty sprop) } static bool -cho_style_reset_default(void) +cho_style_reset_default(struct ChoContext *ctx) { unsigned int i; for (i = 0; i<LENGTH(default_style_properties); i++) { @@ -1511,7 +1509,7 @@ cho_style_reset_default(void) default_style_properties[i].u.foreground_color = NULL; return true; default: - cho_log(LOG_ERR, "Invalid style property type '%d'.", default_style_properties[i].type); + cho_log(ctx, LOG_ERR, "Invalid style property type '%d'.", default_style_properties[i].type); return false; } } @@ -1578,7 +1576,7 @@ cho_tag_free(struct Tag *tag) } static bool -cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int last_index) +cho_tag_close_last_unclosed(struct ChoContext *ctx, const char *tag_name, struct Tag **tags, int last_index) { int i; for (i = last_index; i >= 0; i--) { @@ -1587,7 +1585,7 @@ cho_tag_close_last_unclosed(const char *tag_name, struct Tag **tags, int last_in return true; } } - cho_log(LOG_ERR, "Didn't find a start tag for the end tag '%s'.", tag_name); + cho_log(ctx, LOG_ERR, "Didn't find a start tag for the end tag '%s'.", tag_name); return false; } @@ -1609,12 +1607,12 @@ cho_tag_style_inherit(struct Tag **tags, int prev_index) } static struct ChoMetadata * -cho_metadata_new(void) +cho_metadata_new(struct ChoContext *ctx) { struct ChoMetadata *meta = emalloc(sizeof(struct ChoMetadata)); meta->name = NULL; meta->value = NULL; - meta->style = cho_style_new_default(); + meta->style = cho_style_new_default(ctx); return meta; } @@ -1643,9 +1641,9 @@ cho_metadata_get(struct ChoMetadata **metadata, const char *name) } static struct ChoMetadata * -cho_metadata_split(const char *directive_value) +cho_metadata_split(struct ChoContext *ctx, const char *directive_value) { - struct ChoMetadata *meta = cho_metadata_new(); + struct ChoMetadata *meta = cho_metadata_new(ctx); bool is_name = true; char *value = str_remove_leading_whitespace(directive_value); int n = 0; @@ -1677,13 +1675,13 @@ cho_metadata_split(const char *directive_value) free(meta->name); free(meta->value); free(meta); - cho_log(LOG_ERR, "Failed to parse directive 'meta'."); + cho_log(ctx, LOG_ERR, "Failed to parse directive 'meta'."); return NULL; } } static struct ChoMetadata ** -cho_metadata_load_default(void) +cho_metadata_load_default(struct ChoContext *ctx) { struct ChoMetadata **meta = NULL; char *filename; @@ -1692,46 +1690,46 @@ cho_metadata_load_default(void) LOG_DEBUG("getenv(USER) failed."); return NULL; } - struct InstrumentInfo ins_info = config_instrument_get(g_config->output->diagram->instrument); + struct InstrumentInfo ins_info = config_instrument_get(ctx->config->output->diagram->instrument); int i = 0; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("chordpro"); meta[i]->value = strdup("ChordPro"); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; - if (g_chordpro_filepath) { - filename = filepath_basename(g_chordpro_filepath); + if (ctx->chordpro_filepath) { + filename = filepath_basename(ctx->chordpro_filepath); meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("chordpro.songsource"); meta[i]->value = filename; - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; } meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("chordpro.version"); meta[i]->value = strdup("6"); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("instrument"); meta[i]->value = strdup(ins_info.name); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("instrument.type"); meta[i]->value = strdup(ins_info.name); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("instrument.description"); meta[i]->value = strdup(ins_info.description); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; const time_t t = time(NULL); struct tm *tt = localtime(&t); @@ -1744,43 +1742,43 @@ cho_metadata_load_default(void) meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("today"); meta[i]->value = strdup(time_str); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("tuning"); meta[i]->value = strdup(ins_info.tuning); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("user"); meta[i]->value = strdup(logged_in_user); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("user.name"); meta[i]->value = strdup(logged_in_user); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); meta[i] = emalloc(sizeof(struct ChoMetadata)); meta[i]->name = strdup("user.fullname"); meta[i]->value = strdup(logged_in_user); - meta[i]->style = cho_style_new_default(); + meta[i]->style = cho_style_new_default(ctx); i++; return meta; } -static char * +/* static char * cho_metadata_substitution_parse( const char *str, struct ChoMetadata **metadata, enum State state_before_substitution ) { -} +} */ static bool transposition_parse(const char *str, int *transpose) @@ -1808,11 +1806,11 @@ transposition_calc_chord_root(struct ChoContext *ctx, int index, enum NoteType t if (transpose == 0) { switch (type) { case NT_NOTE: - return strdup(g_config->output->notes[index]->note); + return strdup(ctx->config->output->notes[index]->note); case NT_SHARP: - return strdup(g_config->output->notes[index]->sharp); + return strdup(ctx->config->output->notes[index]->sharp); case NT_FLAT: - return strdup(g_config->output->notes[index]->flat); + return strdup(ctx->config->output->notes[index]->flat); } } int new_index = index; @@ -1869,21 +1867,21 @@ transposition_calc_chord_root(struct ChoContext *ctx, int index, enum NoteType t } switch (note_type) { case NT_NOTE: - return strdup(g_config->output->notes[new_index]->note); + return strdup(ctx->config->output->notes[new_index]->note); case NT_SHARP: - return strdup(g_config->output->notes[new_index]->sharp); + return strdup(ctx->config->output->notes[new_index]->sharp); case NT_FLAT: - return strdup(g_config->output->notes[new_index]->flat); + return strdup(ctx->config->output->notes[new_index]->flat); } - cho_log(LOG_ERR, "Invalid NoteType '%d'.", note_type); + cho_log(ctx, LOG_ERR, "Invalid NoteType '%d'.", note_type); return NULL; } static struct ChoChord * -cho_chord_new(void) +cho_chord_new(struct ChoContext *ctx) { struct ChoChord *chord = emalloc(sizeof(struct ChoChord)); - chord->style = cho_style_new_default(); + chord->style = cho_style_new_default(ctx); chord->name = NULL; chord->is_canonical = false; chord->root = NULL; @@ -2016,7 +2014,7 @@ cho_chord_root_parse(struct ChoContext *ctx, const char *str, struct ChoChord *c char *transposed_root; int i; for (i = 0; i<7; i++) { - sharp = g_config->parser->notes[i]->sharp; + sharp = ctx->config->parser->notes[i]->sharp; if (sharp && str_starts_with(str, sharp)) { transposed_root = transposition_calc_chord_root(ctx, i, NT_SHARP); if (!transposed_root) { @@ -2026,7 +2024,7 @@ cho_chord_root_parse(struct ChoContext *ctx, const char *str, struct ChoChord *c chord->root = transposed_root; return strlen(sharp); } - flat = g_config->parser->notes[i]->flat; + flat = ctx->config->parser->notes[i]->flat; if (flat && str_starts_with(str, flat)) { transposed_root = transposition_calc_chord_root(ctx, i, NT_FLAT); if (!transposed_root) { @@ -2036,7 +2034,7 @@ cho_chord_root_parse(struct ChoContext *ctx, const char *str, struct ChoChord *c chord->root = transposed_root; return strlen(flat); } - note = g_config->parser->notes[i]->note; + note = ctx->config->parser->notes[i]->note; if (str_starts_with(str, note)) { transposed_root = transposition_calc_chord_root(ctx, i, NT_NOTE); if (!transposed_root) { @@ -2103,7 +2101,7 @@ cho_chord_qualifier_and_extension_parse(const char *str, struct ChoChord *chord) } static int -cho_chord_bass_parse(const char *str, struct ChoChord *chord) +cho_chord_bass_parse(struct ChoContext *ctx, const char *str, struct ChoChord *chord) { if (str[0] == '/') { const char *note = NULL; @@ -2114,20 +2112,20 @@ cho_chord_bass_parse(const char *str, struct ChoChord *chord) const char *out_flat = NULL; int i; for (i = 0; i<7; i++) { - sharp = g_config->parser->notes[i]->sharp; - out_sharp = g_config->output->notes[i]->sharp; + sharp = ctx->config->parser->notes[i]->sharp; + out_sharp = ctx->config->output->notes[i]->sharp; if (sharp && !strcmp((char *)&str[1], sharp)) { chord->bass = strdup(out_sharp); return strlen(sharp) + 1; } - flat = g_config->parser->notes[i]->flat; - out_flat = g_config->output->notes[i]->flat; + flat = ctx->config->parser->notes[i]->flat; + out_flat = ctx->config->output->notes[i]->flat; if (flat && !strcmp((char *)&str[1], flat)) { chord->bass = strdup(out_flat); return strlen(flat) + 1; } - note = g_config->parser->notes[i]->note; - out_note = g_config->parser->notes[i]->note; + note = ctx->config->parser->notes[i]->note; + out_note = ctx->config->parser->notes[i]->note; if (!strcmp((char *)&str[1], note)) { chord->bass = strdup(out_note); return strlen(note) + 1; @@ -2140,7 +2138,7 @@ cho_chord_bass_parse(const char *str, struct ChoChord *chord) static struct ChoChord * cho_chord_parse(struct ChoContext *ctx, const char *str) { - struct ChoChord *chord = cho_chord_new(); + struct ChoChord *chord = cho_chord_new(ctx); size_t str_len = strlen(str); size_t bytes_parsed = 0; int ret; @@ -2161,7 +2159,7 @@ cho_chord_parse(struct ChoContext *ctx, const char *str) chord->is_canonical = true; return chord; } - ret = cho_chord_bass_parse((const char *)&str[bytes_parsed], chord); + ret = cho_chord_bass_parse(ctx, (const char *)&str[bytes_parsed], chord); bytes_parsed += ret; if (bytes_parsed == str_len) { chord->is_canonical = true; @@ -2294,12 +2292,12 @@ cho_image_copy(struct ChoImage *image) } static struct ChoImage * -cho_image_find_asset(const char *id) +cho_image_find_asset(struct ChoContext *ctx, const char *id) { int i; - for (i = 0; i<g_ia; i++) { - if (!strcmp(g_image_assets[i]->id, id)) { - return g_image_assets[i]; + for (i = 0; i<ctx->ia; i++) { + if (!strcmp(ctx->image_assets[i]->id, id)) { + return ctx->image_assets[i]; } } return NULL; @@ -2390,7 +2388,7 @@ cho_debug_image_print(struct ChoImage *image) #endif /* DEBUG */ static bool -cho_image_option_parse(struct ChoImage *image, const char *name, const char *value) +cho_image_option_parse(struct ChoContext *ctx, struct ChoImage *image, const char *name, const char *value) { char *endptr; struct Size *size; @@ -2407,11 +2405,11 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(name, "width")) { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'width' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'width' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'width' in image directive. Allowed types are: points, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'width' in image directive. Allowed types are: points, percentage."); return false; } image->width = size; @@ -2419,11 +2417,11 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(name, "height")) { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'height' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'height' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'height' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'height' in image directive. Allowed types are: point, percentage."); return false; } image->height = size; @@ -2434,32 +2432,32 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val *comma = 0; size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'scale' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); return false; } image->width_scale = size; size = size_create(++comma); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'scale' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); return false; } image->height_scale = size; } else { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'scale' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); return false; } image->width_scale = size; @@ -2476,7 +2474,7 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(value, "center")) { image->align = A_CENTER; } else { - cho_log(LOG_ERR, "Invalid value in option 'align' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'align' in image directive."); return false; } } else @@ -2490,11 +2488,11 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(name, "spread")) { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'spread' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'spread' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'spread' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'spread' in image directive. Allowed types are: point, percentage."); return false; } image->spread_space = size; @@ -2505,11 +2503,11 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(name, "x")) { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'x' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'x' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'x' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'x' in image directive. Allowed types are: point, percentage."); return false; } image->x = size; @@ -2517,11 +2515,11 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(name, "y")) { size = size_create(value); if (!size) { - cho_log(LOG_ERR, "Invalid value in option 'y' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'y' in image directive."); return false; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in option 'y' in image directive. Allowed types are: point, percentage."); + cho_log(ctx, LOG_ERR, "Invalid type of value in option 'y' in image directive. Allowed types are: point, percentage."); return false; } image->y = size; @@ -2542,7 +2540,7 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val if (!strcmp(value, "float")) { image->anchor = AN_FLOAT; } else { - cho_log(LOG_ERR, "Invalid value in option 'anchor' in image directive."); + cho_log(ctx, LOG_ERR, "Invalid value in option 'anchor' in image directive."); return false; } } @@ -2550,7 +2548,7 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val } static struct ChoImage * -cho_image_directive_parse(const char *str) +cho_image_directive_parse(struct ChoContext *ctx, const char *str) { struct ChoImage *image = cho_image_new(); struct ChoImage *asset; @@ -2574,7 +2572,7 @@ cho_image_directive_parse(const char *str) break; } else { name[n] = 0; - cho_log(LOG_ERR, "Option with name '%s' in image directive has no value.", name); + cho_log(ctx, LOG_ERR, "Option with name '%s' in image directive has no value.", name); return NULL; } } @@ -2584,7 +2582,7 @@ cho_image_directive_parse(const char *str) break; } if (n > 5) { - cho_log(LOG_ERR, "Option name in image directive is too long."); + cho_log(ctx, LOG_ERR, "Option name in image directive is too long."); return NULL; } name[n] = c; @@ -2593,7 +2591,7 @@ cho_image_directive_parse(const char *str) case OS_VALUE: if (avs == -1) { if (is_whitespace(c)) { - cho_log(LOG_ERR, "Whitespace character after equals sign in image directive is invalid."); + cho_log(ctx, LOG_ERR, "Whitespace character after equals sign in image directive is invalid."); return NULL; } if (c == '\'') { @@ -2608,7 +2606,7 @@ cho_image_directive_parse(const char *str) break; } if (c == '\n') { - cho_log(LOG_ERR, "Newline character inside an option value in image directive is invalid."); + cho_log(ctx, LOG_ERR, "Newline character inside an option value in image directive is invalid."); return NULL; } if ( @@ -2617,8 +2615,8 @@ cho_image_directive_parse(const char *str) (avs == AVS_UNQUOTED && (c == ' ' || c == '\t')) ) { value[v] = 0; - if (!cho_image_option_parse(image, name, value)) { - LOG_DEBUG("cho_image_option_check failed."); + if (!cho_image_option_parse(ctx, image, name, value)) { + LOG_DEBUG("cho_image_option_parse failed."); return NULL; } option_count++; @@ -2637,8 +2635,8 @@ cho_image_directive_parse(const char *str) } if (avs == AVS_UNQUOTED) { value[v] = 0; - if (!cho_image_option_parse(image, name, value)) { - LOG_DEBUG("cho_image_option_check failed."); + if (!cho_image_option_parse(ctx, image, name, value)) { + LOG_DEBUG("cho_image_option_parse failed."); return NULL; } option_count++; @@ -2646,14 +2644,14 @@ cho_image_directive_parse(const char *str) if (image->id) { if (image->src) { if (option_count > 2) { - cho_log(LOG_ERR, "Defining an image asset disallows any options other than 'id' and 'src'."); + cho_log(ctx, LOG_ERR, "Defining an image asset disallows any options other than 'id' and 'src'."); return NULL; } image->is_asset = true; } else { - asset = cho_image_find_asset(image->id); + asset = cho_image_find_asset(ctx, image->id); if (!asset) { - cho_log(LOG_ERR, "There is no image asset with the id '%s'.", image->id); + cho_log(ctx, LOG_ERR, "There is no image asset with the id '%s'.", image->id); return NULL; } image->src = strdup(asset->src); @@ -2663,7 +2661,7 @@ cho_image_directive_parse(const char *str) } static struct ChoImage * -cho_image_tag_parse(struct Attr **attrs) +cho_image_tag_parse(struct ChoContext *ctx, struct Attr **attrs) { struct ChoImage *image = cho_image_new(); struct ChoImage *asset; @@ -2683,11 +2681,11 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->name, "width")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'width' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'width' in 'img' tag."); return NULL; } if (size->type == ST_PERCENT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'width' in 'img' tag. Allowed types are: point, em, ex."); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'width' in 'img' tag. Allowed types are: point, em, ex."); return NULL; } image->width = size; @@ -2695,11 +2693,11 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->name, "height")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'height' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'height' in 'img' tag."); return NULL; } if (size->type == ST_PERCENT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'height' in 'img' tag. Allowed types are: point, em, ex."); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'height' in 'img' tag. Allowed types are: point, em, ex."); return NULL; } image->height = size; @@ -2707,11 +2705,11 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->name, "dx")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'dx' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'dx' in 'img' tag."); return NULL; } if (size->type == ST_PERCENT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'dx' in 'img' tag. Allowed types are: point, em, ex."); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'dx' in 'img' tag. Allowed types are: point, em, ex."); return NULL; } image->dx = size; @@ -2719,11 +2717,11 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->name, "dy")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'dy' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'dy' in 'img' tag."); return NULL; } if (size->type == ST_PERCENT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'dy' in 'img' tag. Allowed types are: point, em, ex."); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'dy' in 'img' tag. Allowed types are: point, em, ex."); return NULL; } image->dy = size; @@ -2734,32 +2732,32 @@ cho_image_tag_parse(struct Attr **attrs) *comma = 0; size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); return NULL; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); return NULL; } image->width_scale = size; size = size_create(++comma); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); return NULL; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); return NULL; } image->height_scale = size; } else { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); return NULL; } if (size->type == ST_EM || size->type == ST_EX) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); return NULL; } image->width_scale = size; @@ -2776,7 +2774,7 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->value, "center")) { image->align = A_CENTER; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'align' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'align' in 'img' tag."); return NULL; } } else @@ -2787,18 +2785,18 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->value, "0")) { image->bbox = false; } else { - cho_log(LOG_ERR, "Invalid value in attribute 'bbox' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'bbox' in 'img' tag."); return NULL; } } else if (!strcmp(attrs[a]->name, "w")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'w' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'w' in 'img' tag."); return NULL; } if (size->type != ST_POINT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'w' in 'img' tag. Allowed type is: point"); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'w' in 'img' tag. Allowed type is: point"); return NULL; } image->w = size; @@ -2806,34 +2804,34 @@ cho_image_tag_parse(struct Attr **attrs) if (!strcmp(attrs[a]->name, "h")) { size = size_create(attrs[a]->value); if (!size) { - cho_log(LOG_ERR, "Invalid value in attribute 'h' in 'img' tag."); + cho_log(ctx, LOG_ERR, "Invalid value in attribute 'h' in 'img' tag."); return NULL; } if (size->type != ST_POINT) { - cho_log(LOG_ERR, "Invalid type of value in attribute 'h' in 'img' tag. Allowed type is: point"); + cho_log(ctx, LOG_ERR, "Invalid type of value in attribute 'h' in 'img' tag. Allowed type is: point"); return NULL; } image->h = size; } else { - cho_log(LOG_ERR, "Invalid attribute '%s' in 'img' tag.", attrs[a]->name); + cho_log(ctx, LOG_ERR, "Invalid attribute '%s' in 'img' tag.", attrs[a]->name); return NULL; } } if (image->id) { if (image->src) { - cho_log(LOG_ERR, "'img' tag can't have both attributes 'id' and 'src' at the same time."); + cho_log(ctx, LOG_ERR, "'img' tag can't have both attributes 'id' and 'src' at the same time."); return NULL; } else { - asset = cho_image_find_asset(image->id); + asset = cho_image_find_asset(ctx, image->id); if (!asset) { - cho_log(LOG_ERR, "There is no image asset with the id '%s'.", image->id); + cho_log(ctx, LOG_ERR, "There is no image asset with the id '%s'.", image->id); return NULL; } image->src = strdup(asset->src); } } else { if (!image->src) { - cho_log(LOG_ERR, "'img' tag has to have at least either the attribute 'id' or 'src'."); + cho_log(ctx, LOG_ERR, "'img' tag has to have at least either the attribute 'id' or 'src'."); return NULL; } } @@ -2866,6 +2864,7 @@ finger_to_int(char c) static struct ChordDiagram * cho_chord_diagram_parse( + struct ChoContext *ctx, const char *str, struct ChordDiagram **custom_diagrams, int custom_diagrams_len @@ -2903,7 +2902,7 @@ cho_chord_diagram_parse( break; } if (i > 18) { - cho_log(LOG_ERR, "Chord name in chord diagram is too long."); + cho_log(ctx, LOG_ERR, "Chord name in chord diagram is too long."); return NULL; } name[i] = *c; @@ -2939,7 +2938,7 @@ cho_chord_diagram_parse( if (!strcmp(option, "copy")) { state = CDS_COPY; } else { - cho_log(LOG_ERR, "Invalid option '%s' in define directive.", option); + cho_log(ctx, LOG_ERR, "Invalid option '%s' in define directive.", option); return NULL; } memset(option, 0, i); @@ -2958,13 +2957,13 @@ cho_chord_diagram_parse( diagram->u.kd->name = strdup(name); break; default: - cho_log(LOG_ERR, "'future_content' cannot be empty at this point.\n"); + cho_log(ctx, LOG_ERR, "'future_content' cannot be empty at this point.\n"); } } break; } if (i > 8) { - cho_log(LOG_ERR, "Option in chord diagram is too long."); + cho_log(ctx, LOG_ERR, "Option in chord diagram is too long."); return NULL; } option[i] = *c; @@ -2981,11 +2980,11 @@ cho_chord_diagram_parse( l = str_to_number(base_fret); if (l == -1) { LOG_DEBUG("str_to_number failed."); - cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret); + cho_log(ctx, LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret); return NULL; } if (l == 0) { - cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); + cho_log(ctx, LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); return NULL; } diagram->u.sd->base_fret = (int8_t)l; @@ -2993,7 +2992,7 @@ cho_chord_diagram_parse( break; } if (i > 1) { - cho_log(LOG_ERR, "base-fret value is too long."); + cho_log(ctx, LOG_ERR, "base-fret value is too long."); printf("c: %c\n", *c); return NULL; } @@ -3015,7 +3014,7 @@ cho_chord_diagram_parse( number = -1; is_maybe_minus_one = false; } else { - cho_log(LOG_ERR, "Invalid frets value '-%c' in chord diagram.", *c); + cho_log(ctx, LOG_ERR, "Invalid frets value '-%c' in chord diagram.", *c); return NULL; } } @@ -3032,12 +3031,12 @@ cho_chord_diagram_parse( number = char_to_positive_int(*c); if (number == -1) { LOG_DEBUG("char_to_positive_int failed."); - cho_log(LOG_ERR, "Invalid frets value '%c' in chord diagram.", *c); + cho_log(ctx, LOG_ERR, "Invalid frets value '%c' in chord diagram.", *c); return NULL; } } if (f > 11) { - cho_log(LOG_ERR, "Too many fret values in chord diagram."); + cho_log(ctx, LOG_ERR, "Too many fret values in chord diagram."); return NULL; } diagram->u.sd->frets[f] = number; @@ -3057,11 +3056,11 @@ cho_chord_diagram_parse( } number = finger_to_int(*c); if (number == -2) { - cho_log(LOG_ERR, "Invalid fingers value '%c' in chord diagram.", *c); + cho_log(ctx, LOG_ERR, "Invalid fingers value '%c' in chord diagram.", *c); return NULL; } if (f > 11) { - cho_log(LOG_ERR, "Too many finger values in chord diagram."); + cho_log(ctx, LOG_ERR, "Too many finger values in chord diagram."); return NULL; } diagram->u.sd->fingers[f] = number; @@ -3079,11 +3078,11 @@ cho_chord_diagram_parse( l = str_to_number(key); if (l == -1) { LOG_DEBUG("str_to_number failed."); - cho_log(LOG_ERR, "Invalid number in keys in chord diagram."); + cho_log(ctx, LOG_ERR, "Invalid number in keys in chord diagram."); return NULL; } if (f > 23) { - cho_log(LOG_ERR, "Too many key values in chord diagram."); + cho_log(ctx, LOG_ERR, "Too many key values in chord diagram."); return NULL; } diagram->u.kd->keys[f] = (int8_t)l; @@ -3096,7 +3095,7 @@ cho_chord_diagram_parse( break; } if (i > 1) { - cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", i); + cho_log(ctx, LOG_ERR, "Too high key value in chord diagram. '%d'", i); printf("key '%s'\n", key); return NULL; } @@ -3138,13 +3137,13 @@ cho_chord_diagram_parse( } chord_to_copy[i] = 0; if (current_content != -1) { - cho_log(LOG_ERR, "The define options 'base-fret', 'frets', 'fingers' and 'keys' are not allowed before the 'copy' option."); + cho_log(ctx, LOG_ERR, "The define options 'base-fret', 'frets', 'fingers' and 'keys' are not allowed before the 'copy' option."); return NULL; } - enum Instrument ins = g_config->output->diagram->instrument; + enum Instrument ins = ctx->config->output->diagram->instrument; current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins); if (current_content == -1) { - cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s'" + cho_log(ctx, LOG_ERR, "Can't copy the diagram for the chord '%s'" "because no previous definition was found and also" "no predefined chord diagram for the instrument '%s'" "was found.", chord_to_copy, instruments[ins]); @@ -3167,11 +3166,11 @@ cho_chord_diagram_parse( l = str_to_number(base_fret); if (l == -1) { LOG_DEBUG("str_to_number failed."); - cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret); + cho_log(ctx, LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret); return NULL; } if (l == 0) { - cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); + cho_log(ctx, LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c); return NULL; } diagram->u.sd->base_fret = (int8_t)l; @@ -3183,11 +3182,11 @@ cho_chord_diagram_parse( l = str_to_number(key); if (l == -1) { LOG_DEBUG("str_to_number failed."); - cho_log(LOG_ERR, "Invalid number in keys in chord diagram."); + cho_log(ctx, LOG_ERR, "Invalid number in keys in chord diagram."); return NULL; } if (f > 23) { - cho_log(LOG_ERR, "Too many key values in chord diagram."); + cho_log(ctx, LOG_ERR, "Too many key values in chord diagram."); return NULL; } diagram->u.kd->keys[f] = (int8_t)l; @@ -3215,15 +3214,15 @@ cho_chord_diagram_parse( case CDS_COPY: { chord_to_copy[i] = 0; if (current_content != -1) { - cho_log(LOG_ERR, "The define options 'base-fret', 'frets'," + cho_log(ctx, LOG_ERR, "The define options 'base-fret', 'frets'," "'fingers' and 'keys' are not allowed before the 'copy'" "option."); return NULL; } - enum Instrument ins = g_config->output->diagram->instrument; + enum Instrument ins = ctx->config->output->diagram->instrument; current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins); if (current_content == -1) { - cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s' because" + cho_log(ctx, LOG_ERR, "Can't copy the diagram for the chord '%s' because" "no previous definition was found and also no predefined" "chord diagram for the instrument '%s' was found.", chord_to_copy, instruments[ins]); @@ -3239,17 +3238,17 @@ cho_chord_diagram_parse( finger_count > 0 && fret_count != finger_count ) { - cho_log(LOG_ERR, "The number of frets (%d) and fingers (%d) in the chord diagram must be equal.", fret_count, finger_count); + cho_log(ctx, LOG_ERR, "The number of frets (%d) and fingers (%d) in the chord diagram must be equal.", fret_count, finger_count); return NULL; } return diagram; } static struct ChoText * -cho_text_new(void) +cho_text_new(struct ChoContext *ctx) { struct ChoText *text = emalloc(sizeof(struct ChoText)); - text->style = cho_style_new_default(); + text->style = cho_style_new_default(ctx); text->text = NULL; return text; } @@ -3303,11 +3302,11 @@ cho_text_above_copy(struct ChoLineItemAbove *text_above) } static struct ChoLineItem * -cho_line_item_new(void) +cho_line_item_new(struct ChoContext *ctx) { struct ChoLineItem *item = emalloc(sizeof(struct ChoLineItem)); item->is_text = true; - item->u.text = cho_text_new(); + item->u.text = cho_text_new(ctx); return item; } @@ -3448,10 +3447,10 @@ cho_section_copy(struct ChoSection *section) } static struct ChoSong * -cho_song_new(void) +cho_song_new(struct ChoContext *ctx) { struct ChoSong *song = emalloc(sizeof(struct ChoSong)); - song->metadata = cho_metadata_load_default(); + song->metadata = cho_metadata_load_default(ctx); if (!song->metadata) { LOG_DEBUG("cho_metadata_load_default failed."); return NULL; @@ -3549,7 +3548,7 @@ cho_find_previous_chorus(struct ChoSection **sections, int se) } static struct ChoDirective * -cho_directive_new(void) +cho_directive_new(struct ChoContext *ctx) { struct ChoDirective *directive = emalloc(sizeof(struct ChoDirective)); directive->dtype = -1; @@ -3560,7 +3559,7 @@ cho_directive_new(void) directive->btype = -1; directive->meta = -1; directive->ctype = -1; - directive->style = cho_style_new_default(); + directive->style = cho_style_new_default(ctx); return directive; } @@ -3575,9 +3574,9 @@ cho_directive_free(struct ChoDirective *directive) } static struct ChoDirective * -cho_directive_parse(const char *name) +cho_directive_parse(struct ChoContext *ctx, const char *name) { - struct ChoDirective *directive = cho_directive_new(); + struct ChoDirective *directive = cho_directive_new(ctx); if ( !strcmp(name, "start_of_chorus") || !strcmp(name, "soc") @@ -3681,10 +3680,10 @@ cho_directive_parse(const char *name) directive->dtype = DT_METADATA; directive->meta = TITLE; cho_style_free(directive->style); - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_TITLE; - directive->style = cho_style_new_default(); - g_current_ttype = g_prev_ttype; + ctx->prev_ttype = ctx->current_ttype; + ctx->current_ttype = TT_TITLE; + directive->style = cho_style_new_default(ctx); + ctx->current_ttype = ctx->prev_ttype; return directive; } else if ( @@ -3694,10 +3693,10 @@ cho_directive_parse(const char *name) directive->dtype = DT_METADATA; directive->meta = SUBTITLE; cho_style_free(directive->style); - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_SUBTITLE; - directive->style = cho_style_new_default(); - g_current_ttype = g_prev_ttype; + ctx->prev_ttype = ctx->current_ttype; + ctx->current_ttype = TT_SUBTITLE; + directive->style = cho_style_new_default(ctx); + ctx->current_ttype = ctx->prev_ttype; return directive; } if ( @@ -3725,11 +3724,11 @@ cho_directive_parse(const char *name) !strcmp(name, "highlight") ) { directive->dtype = DT_FORMATTING; - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_COMMENT; + ctx->prev_ttype = ctx->current_ttype; + ctx->current_ttype = TT_COMMENT; cho_style_free(directive->style); - directive->style = cho_style_new_default(); - g_current_ttype = g_prev_ttype; + directive->style = cho_style_new_default(ctx); + ctx->current_ttype = ctx->prev_ttype; directive->ttype = TT_COMMENT; return directive; } else if ( @@ -3737,11 +3736,11 @@ cho_directive_parse(const char *name) !strcmp(name, "ci") ) { directive->dtype = DT_FORMATTING; - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_COMMENT_ITALIC; + ctx->prev_ttype = ctx->current_ttype; + ctx->current_ttype = TT_COMMENT_ITALIC; cho_style_free(directive->style); - directive->style = cho_style_new_default(); - g_current_ttype = g_prev_ttype; + directive->style = cho_style_new_default(ctx); + ctx->current_ttype = ctx->prev_ttype; directive->ttype = TT_COMMENT_ITALIC; return directive; } else if ( @@ -3749,11 +3748,11 @@ cho_directive_parse(const char *name) !strcmp(name, "cb") ) { directive->dtype = DT_FORMATTING; - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_COMMENT_BOX; + ctx->prev_ttype = ctx->current_ttype; + ctx->current_ttype = TT_COMMENT_BOX; cho_style_free(directive->style); - directive->style = cho_style_new_default(); - g_current_ttype = g_prev_ttype; + directive->style = cho_style_new_default(ctx); + ctx->current_ttype = ctx->prev_ttype; directive->ttype = TT_COMMENT_BOX; return directive; } @@ -3937,7 +3936,7 @@ cho_directive_parse(const char *name) } static char * -cho_directive_label_parse(const char *directive_name, const char *str) +cho_directive_label_parse(struct ChoContext *ctx, const char *directive_name, const char *str) { char *label_name = NULL; char c; @@ -3959,14 +3958,14 @@ cho_directive_label_parse(const char *directive_name, const char *str) break; } else { name[n] = 0; - cho_log(LOG_ERR, "Option with name '%s' in environment directive '%s' has no value.", name, directive_name); + cho_log(ctx, LOG_ERR, "Option with name '%s' in environment directive '%s' has no value.", name, directive_name); return NULL; } } if (c == '=') { name[n] = 0; if (strcmp(name, "label") != 0) { - cho_log(LOG_ERR, "Invalid option name '%s' in environment directive '%s'.", name, directive_name); + cho_log(ctx, LOG_ERR, "Invalid option name '%s' in environment directive '%s'.", name, directive_name); } memset(name, 0, n); n = 0; @@ -3974,7 +3973,7 @@ cho_directive_label_parse(const char *directive_name, const char *str) break; } if (n > 4) { - cho_log(LOG_ERR, "Option name in environment directive '%s' is too long.", directive_name); + cho_log(ctx, LOG_ERR, "Option name in environment directive '%s' is too long.", directive_name); return NULL; } name[n] = c; @@ -3983,7 +3982,7 @@ cho_directive_label_parse(const char *directive_name, const char *str) case OS_VALUE: if (avs == -1) { if (is_whitespace(c)) { - cho_log(LOG_ERR, "Whitespace character after equals sign in environment directive '%s' is invalid.", directive_name); + cho_log(ctx, LOG_ERR, "Whitespace character after equals sign in environment directive '%s' is invalid.", directive_name); return NULL; } if (c == '\'') { @@ -3998,7 +3997,7 @@ cho_directive_label_parse(const char *directive_name, const char *str) break; } if (c == '\n') { - cho_log(LOG_ERR, "Newline character inside an option value in environment directive '%s' is invalid.", directive_name); + cho_log(ctx, LOG_ERR, "Newline character inside an option value in environment directive '%s' is invalid.", directive_name); return NULL; } if ( @@ -4027,16 +4026,23 @@ cho_directive_label_parse(const char *directive_name, const char *str) } static bool -cho_context_init(struct ChoContext *ctx) +cho_context_init( + struct ChoContext *ctx, + struct Config *config, + const char *chordpro_filepath +) { ctx->is_chord_already_initialized = false; ctx->is_maybe_end_of_tab_directive = false; ctx->directive_has_tag = false; + ctx->chordpro_filepath = chordpro_filepath; ctx->state = STATE_LYRICS; ctx->state_before_comment = STATE_LYRICS; ctx->state_before_tag = STATE_LYRICS; ctx->state_before_backslash = STATE_LYRICS; ctx->state_before_metadata_substitution = STATE_LYRICS; + ctx->current_ttype = TT_TEXT; + ctx->prev_ttype = TT_TEXT; ctx->ann = 0; ctx->at = 0; ctx->atn = 0; @@ -4045,6 +4051,7 @@ cho_context_init(struct ChoContext *ctx) ctx->dia = 0; ctx->dn = 0; ctx->dv = 0; + ctx->ia = 0; ctx->li = 0; ctx->lia = 0; ctx->lii = 0; @@ -4057,15 +4064,18 @@ cho_context_init(struct ChoContext *ctx) ctx->te = 0; ctx->th = 0; ctx->nested_level = 0; + ctx->line_number = 1; ctx->tags = NULL; + ctx->image_assets = NULL; ctx->transpose_history = emalloc((ctx->th+1) * sizeof(int *)); ctx->transpose_history[ctx->th] = 0; ctx->transpose = &ctx->transpose_history[ctx->th]; ctx->th++; + ctx->config = config; ctx->songs = emalloc(sizeof(struct ChoSong *)); - ctx->songs[ctx->so] = cho_song_new(); + ctx->songs[ctx->so] = cho_song_new(ctx); if (!ctx->songs[ctx->so]) { LOG_DEBUG("cho_song_new failed."); return false; @@ -4104,23 +4114,20 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) int transpose; size_t read; - g_config = config; - g_chordpro_filepath = chordpro_filepath; - - if (!cho_context_init(&ctx)) { + if (!cho_context_init(&ctx, config, chordpro_filepath)) { LOG_DEBUG("cho_context_init failed."); return NULL; } lines = &ctx.songs[ctx.so]->sections[ctx.se]->lines; (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); ctx.songs[ctx.so]->present_text_types[TT_TOC] = config->output->toc->show; while (feof(fp) == 0) { read = fread(&c, 1, 1, fp); if (read == 1) { if (c == '\n') { - g_line_number++; + ctx.line_number++; } // printf("state: %s, buf: %c\n", state_enums[state], buf); if (c == '\r') { @@ -4155,7 +4162,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } ctx.te = 0; (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); ctx.state_before_tag = STATE_LYRICS; ctx.state = STATE_MARKUP_TAG; break; @@ -4173,7 +4180,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.ta]->name, "img")) { - cho_log(LOG_ERR, "Tag has to be closed on same line."); + cho_log(&ctx, LOG_ERR, "Tag has to be closed on same line."); return NULL; } if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { @@ -4191,7 +4198,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); break; } } @@ -4212,7 +4219,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); break; } (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); @@ -4235,14 +4242,14 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (c == '}') { directive_name[ctx.dn] = 0; ctx.dn = 0; - directive = cho_directive_parse(directive_name); + directive = cho_directive_parse(&ctx, directive_name); /* printf( "directive: '%s'\ndtype: %s, stype: %s, position: %s\n", directive_name, cho_debug_dtype(directive->dtype), cho_debug_the_stype(directive->stype), cho_debug_the_pos(directive->position) ); */ switch (directive->dtype) { case DT_ENVIRONMENT: { - g_current_ttype = directive->ttype; + ctx.current_ttype = directive->ttype; switch (directive->position) { case POS_START: { if (directive->stype == ST_CUSTOM) { @@ -4263,7 +4270,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; break; } @@ -4287,7 +4294,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } break; } @@ -4321,7 +4328,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } else { if (chorus->label) { label = strdup(chorus->label->text); @@ -4340,16 +4347,16 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.lii++; } (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - g_current_ttype = TT_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + ctx.current_ttype = TT_LABEL; + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; ctx.te += strlen(label); } } else { if (config->output->chorus->quote) { - cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously."); + cho_log(&ctx, LOG_WARN, "Can't quote chorus because it's not defined previously."); } label = strdup(config->output->chorus->label); if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { @@ -4364,29 +4371,29 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.lii++; } (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - g_current_ttype = TT_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + ctx.current_ttype = TT_LABEL; + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; ctx.te += strlen(label); } break; } default: - cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position); + cho_log(&ctx, LOG_ERR, "Invalid position value '%d'.", directive->position); return NULL; } break; } case DT_METADATA: - cho_log(LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); + cho_log(&ctx, LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); break; case DT_FORMATTING: - cho_log(LOG_WARN, "Formatting directive '%s' has no value.", directive_name); + cho_log(&ctx, LOG_WARN, "Formatting directive '%s' has no value.", directive_name); break; case DT_IMAGE: - cho_log(LOG_ERR, "Directive 'image' has no value."); + cho_log(&ctx, LOG_ERR, "Directive 'image' has no value."); return NULL; case DT_PREAMBLE: { // INFO: The only preamble directive is 'new_song' @@ -4401,13 +4408,13 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.songs[ctx.so]->sections[ctx.se] = NULL; ctx.songs[ctx.so]->diagrams = erealloc(ctx.songs[ctx.so]->diagrams, (ctx.dia+1) * sizeof(struct ChordDiagram *)); ctx.songs[ctx.so]->diagrams[ctx.dia] = NULL; - if (!cho_style_reset_default()) { + if (!cho_style_reset_default(&ctx)) { LOG_DEBUG("cho_style_reset_default failed."); return NULL; } ctx.so++; ctx.songs = erealloc(ctx.songs, (ctx.so+1) * sizeof(struct ChoSong *)); - ctx.songs[ctx.so] = cho_song_new(); + ctx.songs[ctx.so] = cho_song_new(&ctx); if (!ctx.songs[ctx.so]) { LOG_DEBUG("cho_song_new failed."); return NULL; @@ -4423,7 +4430,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); break; } case DT_FONT: { @@ -4440,10 +4447,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) sprop.u.foreground_color = NULL; break; default: - cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop); + cho_log(&ctx, LOG_ERR, "Invalid style property type '%d'.", directive->sprop); return NULL; } - if (!cho_style_change_default(sprop)) { + if (!cho_style_change_default(&ctx, sprop)) { LOG_DEBUG("cho_style_change_default failed."); return NULL; } @@ -4456,7 +4463,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.th--; break; case DEFINE: - cho_log(LOG_WARN, "Ignoring chord directive '%s' because it has no value.", directive_name); + cho_log(&ctx, LOG_WARN, "Ignoring chord directive '%s' because it has no value.", directive_name); break; } break; @@ -4470,10 +4477,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) // INFO: Such a directive should not be logged. break; case DT_CUSTOM: - cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name); + cho_log(&ctx, LOG_INFO, "Ignoring custom directive '%s'.", directive_name); break; default: - cho_log(LOG_ERR, "Invalid directive '%s'.", directive_name); + cho_log(&ctx, LOG_ERR, "Invalid directive '%s'.", directive_name); return NULL; } if (directive->stype == ST_TAB) { @@ -4486,7 +4493,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } if (c == '{') { - cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); + cho_log(&ctx, LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); return NULL; } if (c == '\n') { @@ -4496,7 +4503,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.dn--; break; } - cho_log(LOG_ERR, "Can't have a newline in a directive name."); + cho_log(&ctx, LOG_ERR, "Can't have a newline in a directive name."); return NULL; } if (c == ':' || c == ' ') { @@ -4514,7 +4521,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) directive_value[ctx.dv] = 0; ctx.dv = 0; stripped_directive_value = str_remove_leading_whitespace(directive_value); - directive = cho_directive_parse(directive_name); + directive = cho_directive_parse(&ctx, directive_name); /* printf( "directive: '%s'\ndtype: %s, stype: %s, position: %s\n", directive_name, dtype(directive->dtype), the_stype(directive->stype), pos(directive->position) @@ -4524,7 +4531,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (strlen(stripped_directive_value) > 0) { ctx.songs[ctx.so]->present_text_types[TT_LABEL] = true; } - g_current_ttype = directive->ttype; + ctx.current_ttype = directive->ttype; switch (directive->position) { case POS_START: { if (directive->stype == ST_CUSTOM) { @@ -4542,17 +4549,17 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.songs[ctx.so]->sections[ctx.se]->type = directive->stype; ctx.songs[ctx.so]->sections[ctx.se]->label = emalloc(sizeof(struct ChoText)); if (strstr(directive_value, "=")) { - label = cho_directive_label_parse(directive_name, directive_value); + label = cho_directive_label_parse(&ctx, directive_name, directive_value); if (!label) { LOG_DEBUG("cho_directive_label_parse failed."); - cho_log(LOG_ERR, "Failed to parse the section label. You have to ways of specifying a label:\n\t\t\t1. {start_of_*: label=\"Label name\"}\n\t\t\t2. {start_of*: Label name}"); + cho_log(&ctx, LOG_ERR, "Failed to parse the section label. You have to ways of specifying a label:\n\t\t\t1. {start_of_*: label=\"Label name\"}\n\t\t\t2. {start_of*: Label name}"); return NULL; } ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } else { ctx.songs[ctx.so]->sections[ctx.se]->label->text = strdup(stripped_directive_value); } - ctx.songs[ctx.so]->sections[ctx.se]->label->style = cho_style_new_from_config(TT_LABEL); + ctx.songs[ctx.so]->sections[ctx.se]->label->style = cho_style_new_from_config(&ctx, TT_LABEL); if (ctx.directive_has_tag) { cho_style_complement(ctx.songs[ctx.so]->sections[ctx.se]->label->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); ctx.directive_has_tag = false; @@ -4562,7 +4569,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; break; } @@ -4581,7 +4588,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } break; } @@ -4614,8 +4621,8 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) free(ctx.songs[ctx.so]->sections[ctx.se]->label->text); ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } else { - g_current_ttype = TT_LABEL; - ctx.songs[ctx.so]->sections[ctx.se]->label = cho_text_new(); + ctx.current_ttype = TT_LABEL; + ctx.songs[ctx.so]->sections[ctx.se]->label = cho_text_new(&ctx); ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } if (ctx.directive_has_tag) { @@ -4629,7 +4636,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } else { if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); @@ -4643,10 +4650,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.lii++; } (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - g_current_ttype = TT_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + ctx.current_ttype = TT_LABEL; + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; if (ctx.directive_has_tag) { cho_style_complement((*lines)[ctx.li]->items[ctx.lii]->u.text->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); @@ -4656,7 +4663,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } } else { if (config->output->chorus->quote) { - cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously."); + cho_log(&ctx, LOG_WARN, "Can't quote chorus because it's not defined previously."); } if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); @@ -4670,10 +4677,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.lii++; } (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - g_current_ttype = TT_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + ctx.current_ttype = TT_LABEL; + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; if (ctx.directive_has_tag) { cho_style_complement((*lines)[ctx.li]->items[ctx.lii]->u.text->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); @@ -4683,7 +4690,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } default: - cho_log(LOG_ERR, "Invalid position value '%d'.", directive->position); + cho_log(&ctx, LOG_ERR, "Invalid position value '%d'.", directive->position); return NULL; } break; @@ -4691,14 +4698,14 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) case DT_METADATA: { metadata_value = strdup(stripped_directive_value); if (strlen(metadata_value) == 0) { - cho_log(LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); + cho_log(&ctx, LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); free(metadata_value); break; } switch (directive->meta) { case TITLE: ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); - ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(&ctx); ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup("title"); ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; cho_style_free(ctx.songs[ctx.so]->metadata[ctx.m]->style); @@ -4707,7 +4714,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; case SUBTITLE: ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); - ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(&ctx); ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup("subtitle"); ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; cho_style_free(ctx.songs[ctx.so]->metadata[ctx.m]->style); @@ -4716,7 +4723,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; default: if (!strcmp(directive_name, "meta")) { - metadata = cho_metadata_split(directive_value); + metadata = cho_metadata_split(&ctx, directive_value); if (!metadata) { LOG_DEBUG("cho_metadata_split failed."); return NULL; @@ -4726,7 +4733,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) free(metadata_value); } else { ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); - ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(&ctx); ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup(directive_name); ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; } @@ -4751,7 +4758,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.lii++; } (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_copy(directive->style); (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(stripped_directive_value); @@ -4765,7 +4772,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } case DT_IMAGE: { if (strstr(directive_value, "=")) { - image = cho_image_directive_parse(directive_value); + image = cho_image_directive_parse(&ctx, directive_value); if (!image) { LOG_DEBUG("cho_image_directive_parse failed."); return NULL; @@ -4775,9 +4782,9 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) image->src = strdup(stripped_directive_value); } if (image->is_asset) { - g_image_assets = erealloc(g_image_assets, (g_ia+1) * sizeof(struct ChoImage *)); - g_image_assets[g_ia] = image; - g_ia++; + ctx.image_assets = erealloc(ctx.image_assets, (ctx.ia+1) * sizeof(struct ChoImage *)); + ctx.image_assets[ctx.ia] = image; + ctx.ia++; } else { if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); @@ -4786,7 +4793,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } ctx.lii++; (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); (*lines)[ctx.li]->items[ctx.lii]->is_text = false; (*lines)[ctx.li]->items[ctx.lii]->u.image = image; @@ -4794,7 +4801,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } case DT_PREAMBLE: - cho_log(LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name); + cho_log(&ctx, LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name); return NULL; case DT_FONT: { sprop.ttype = directive->ttype; @@ -4808,7 +4815,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) case SPT_SIZE: sprop.u.font_size = strtod(dir_value, NULL); if (sprop.u.font_size == 0.0) { - cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); + cho_log(&ctx, LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); return NULL; } sprop.type = SPT_SIZE; @@ -4816,16 +4823,16 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) case SPT_COLOR: sprop.u.foreground_color = cho_color_parse(dir_value); if (sprop.u.foreground_color == NULL) { - cho_log(LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); + cho_log(&ctx, LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); return NULL; } sprop.type = SPT_COLOR; break; default: - cho_log(LOG_ERR, "Invalid style property type '%d'.", directive->sprop); + cho_log(&ctx, LOG_ERR, "Invalid style property type '%d'.", directive->sprop); return NULL; } - if (!cho_style_change_default(sprop)) { + if (!cho_style_change_default(&ctx, sprop)) { LOG_DEBUG("cho_style_change_default failed."); return NULL; } @@ -4842,7 +4849,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) case TRANSPOSE: if (!transposition_parse(directive_value, &transpose)) { LOG_DEBUG("transposition_parse failed."); - cho_log(LOG_ERR, "Directive 'transpose' has an invalid value."); + cho_log(&ctx, LOG_ERR, "Directive 'transpose' has an invalid value."); return NULL; } ctx.transpose_history = erealloc(ctx.transpose_history, (ctx.th+1) * sizeof(int *)); @@ -4851,7 +4858,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.th++; break; case DEFINE: - diagram = cho_chord_diagram_parse(directive_value, ctx.songs[ctx.so]->diagrams, ctx.dia); + diagram = cho_chord_diagram_parse(&ctx, directive_value, ctx.songs[ctx.so]->diagrams, ctx.dia); if (!diagram) { LOG_DEBUG("cho_chord_diagram_parse failed."); return NULL; @@ -4864,16 +4871,16 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } case DT_OUTPUT: - cho_log(LOG_ERR, "Directive '%s' can't have a value.", directive_name); + cho_log(&ctx, LOG_ERR, "Directive '%s' can't have a value.", directive_name); return NULL; case DT_EXTENSION: // INFO: Such a directive should not be logged. break; case DT_CUSTOM: - cho_log(LOG_INFO, "Ignoring custom directive '%s'.", directive_name); + cho_log(&ctx, LOG_INFO, "Ignoring custom directive '%s'.", directive_name); break; default: - cho_log(LOG_ERR, "Invalid directive type '%d'.", directive->dtype); + cho_log(&ctx, LOG_ERR, "Invalid directive type '%d'.", directive->dtype); return NULL; } memset(directive_value, 0, strlen(directive_value)); @@ -4889,7 +4896,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } if (c == '{') { - cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); + cho_log(&ctx, LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); return NULL; } if (c == '\n') { @@ -4899,11 +4906,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.dv--; break; } - cho_log(LOG_ERR, "Newline character inside a directive value is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside a directive value is invalid."); return NULL; } if (ctx.dv > 4094) { - cho_log(LOG_ERR, "Directive value can't be greater than 4095 bytes."); + cho_log(&ctx, LOG_ERR, "Directive value can't be greater than 4095 bytes."); return NULL; } directive_value[ctx.dv] = c; @@ -4914,15 +4921,15 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (c == ']') { chord[ctx.ch] = 0; ctx.ch = 0; - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_CHORD; + ctx.prev_ttype = ctx.current_ttype; + ctx.current_ttype = TT_CHORD; if (ctx.is_chord_already_initialized) { ctx.text_above_pos = cho_line_compute_text_above_position(ctx.songs[ctx.so]->sections[ctx.se]->lines[ctx.li], ctx.lii, ctx.te); (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; tmp_chord = cho_chord_parse(&ctx, chord); cho_chord_complete((*lines)[ctx.li]->text_above[ctx.lia]->u.chord, tmp_chord); if (!(*lines)[ctx.li]->text_above[ctx.lia]->u.chord->is_canonical) { - cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); + cho_log(&ctx, LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); } cho_chord_free(tmp_chord); ctx.is_chord_already_initialized = false; @@ -4934,25 +4941,25 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; (*lines)[ctx.li]->text_above[ctx.lia]->u.chord = cho_chord_parse(&ctx, chord); if (!(*lines)[ctx.li]->text_above[ctx.lia]->u.chord->is_canonical) { - cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); + cho_log(&ctx, LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); } } ctx.songs[ctx.so]->present_text_types[TT_CHORD] = true; memset(chord, 0, strlen(chord)); ctx.lia++; - g_current_ttype = g_prev_ttype; + ctx.current_ttype = ctx.prev_ttype; ctx.state = STATE_LYRICS; break; } if (prev_c == '[' && c == '*') { - g_prev_ttype = g_current_ttype; - g_current_ttype = TT_ANNOT; + ctx.prev_ttype = ctx.current_ttype; + ctx.current_ttype = TT_ANNOT; (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = false; ctx.text_above_pos = cho_line_compute_text_above_position((*lines)[ctx.li], ctx.lii, ctx.te); (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; - (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(&ctx); ctx.state = STATE_ANNOTATION; break; } @@ -4963,11 +4970,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.ch--; break; } - cho_log(LOG_ERR, "Newline character inside a chord is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside a chord is invalid."); return NULL; } if (c == '[') { - cho_log(LOG_ERR, "Can't start a new chord/annotation if the previous one is not yet closed."); + cho_log(&ctx, LOG_ERR, "Can't start a new chord/annotation if the previous one is not yet closed."); return NULL; } if (c == '<') { @@ -4975,7 +4982,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = true; - (*lines)[ctx.li]->text_above[ctx.lia]->u.chord = cho_chord_new(); + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord = cho_chord_new(&ctx); ctx.is_chord_already_initialized = true; } ctx.state_before_tag = STATE_CHORD; @@ -4993,7 +5000,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.songs[ctx.so]->present_text_types[TT_ANNOT] = true; ctx.ann = 0; ctx.lia++; - g_current_ttype = g_prev_ttype; + ctx.current_ttype = ctx.prev_ttype; ctx.state = STATE_LYRICS; break; } @@ -5009,7 +5016,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.ann--; break; } - cho_log(LOG_ERR, "Newline character inside an annotation is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside an annotation is invalid."); return NULL; } (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text = erealloc((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text, (ctx.ann+1) * sizeof(char)); @@ -5043,8 +5050,8 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = emalloc(sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); - g_current_ttype = TT_TEXT; + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); + ctx.current_ttype = TT_TEXT; ctx.state = STATE_LYRICS; break; } else { @@ -5096,7 +5103,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.ta]->name, "img")) { - cho_log(LOG_ERR, "Tag has to be closed on same line."); + cho_log(&ctx, LOG_ERR, "Tag has to be closed on same line."); return NULL; } if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { @@ -5114,7 +5121,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); break; } } @@ -5135,7 +5142,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); (*lines)[ctx.li] = cho_line_new(); (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); break; } (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); @@ -5163,11 +5170,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) tag_start[ctx.t] = 0; ctx.t = 0; if (!strcmp(tag_start, "img")) { - cho_log(LOG_ERR, "'img' tag has to have at least the 'src' attribute."); + cho_log(&ctx, LOG_ERR, "'img' tag has to have at least the 'src' attribute."); return NULL; } ctx.tags[ctx.ta]->name = strdup(tag_start); - tag_style = cho_style_parse(tag_start, NULL, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); + tag_style = cho_style_parse(&ctx, tag_start, NULL, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; @@ -5192,7 +5199,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = false; (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; - (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(&ctx); } cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style); (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style = cho_style_copy(tag_style); @@ -5201,7 +5208,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); + cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } memset(tag_start, 0, strlen(tag_start)); @@ -5224,11 +5231,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.t--; break; } - cho_log(LOG_ERR, "Newline character inside a tag name is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside a tag name is invalid."); return NULL; } if (ctx.t == 5) { - cho_log(LOG_ERR, "Start tag name is too long."); + cho_log(&ctx, LOG_ERR, "Start tag name is too long."); return NULL; } tag_start[ctx.t] = c; @@ -5239,7 +5246,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (c == '>') { tag_end[ctx.t] = 0; ctx.t = 0; - if (!cho_tag_close_last_unclosed(tag_end, ctx.tags, ctx.ta)) { + if (!cho_tag_close_last_unclosed(&ctx, tag_end, ctx.tags, ctx.ta)) { LOG_DEBUG("cho_tag_close_last_unclosed failed."); return NULL; } @@ -5254,11 +5261,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.t--; break; } - cho_log(LOG_ERR, "Newline character inside a tag name is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside a tag name is invalid."); return NULL; } if (ctx.t == 5) { - cho_log(LOG_ERR, "End tag name is too long."); + cho_log(&ctx, LOG_ERR, "End tag name is too long."); return NULL; } tag_end[ctx.t] = c; @@ -5280,7 +5287,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } else { ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); + cho_log(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } } @@ -5292,7 +5299,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); + cho_log(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } if (c == '>') { @@ -5303,7 +5310,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (!strcmp(ctx.tags[ctx.ta]->name, "img")) { cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); (*lines)[ctx.li]->items[ctx.lii]->is_text = false; - image = cho_image_tag_parse(ctx.tags[ctx.ta]->attrs); + image = cho_image_tag_parse(&ctx, ctx.tags[ctx.ta]->attrs); if (!image) { LOG_DEBUG("cho_image_tag_parse failed."); return NULL; @@ -5311,9 +5318,9 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li]->items[ctx.lii]->u.image = image; ctx.lii++; (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } else { - tag_style = cho_style_parse(tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); + tag_style = cho_style_parse(&ctx, tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; @@ -5336,7 +5343,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); + cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } } @@ -5348,7 +5355,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; ctx.atn = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); + cho_log(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } } @@ -5359,7 +5366,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.atn--; break; } - cho_log(LOG_ERR, "Newline character inside an tag attribute name is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside an tag attribute name is invalid."); return NULL; } ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); @@ -5375,16 +5382,16 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.atv--; break; } - cho_log(LOG_ERR, "Newline character inside an attribute value is invalid."); + cho_log(&ctx, LOG_ERR, "Newline character inside an attribute value is invalid."); return NULL; } if (avs == -1) { if (is_whitespace(c)) { - cho_log(LOG_ERR, "Whitespace character after equals sign is invalid."); + cho_log(&ctx, LOG_ERR, "Whitespace character after equals sign is invalid."); return NULL; } if (c == '>') { - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); + cho_log(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } if (c == '\'') { @@ -5409,7 +5416,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (!strcmp(ctx.tags[ctx.ta]->name, "img")) { cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); (*lines)[ctx.li]->items[ctx.lii]->is_text = false; - image = cho_image_tag_parse(ctx.tags[ctx.ta]->attrs); + image = cho_image_tag_parse(&ctx, ctx.tags[ctx.ta]->attrs); if (!image) { LOG_DEBUG("cho_image_tag_parse failed."); return NULL; @@ -5417,9 +5424,9 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li]->items[ctx.lii]->u.image = image; ctx.lii++; (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); } else { - tag_style = cho_style_parse(tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); + tag_style = cho_style_parse(&ctx, tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; @@ -5442,7 +5449,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); + cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } } @@ -5521,7 +5528,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.nested_level++; } if (ctx.ms > 4094) { - cho_log(LOG_ERR, "Metadata substitution can't be greater than 4095 bytes."); + cho_log(&ctx, LOG_ERR, "Metadata substitution can't be greater than 4095 bytes."); return NULL; } metadata_substitution[ctx.ms] = c; @@ -5560,7 +5567,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) (*lines)[ctx.li] = NULL; } } - if (!cho_style_reset_default()) { + if (!cho_style_reset_default(&ctx)) { LOG_DEBUG("cho_style_reset_default failed."); return NULL; } @@ -5574,20 +5581,20 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) ctx.so++; ctx.songs = erealloc(ctx.songs, (ctx.so+1) * sizeof(struct ChoSong *)); ctx.songs[ctx.so] = NULL; - g_current_ttype = TT_TEXT; - g_prev_ttype = TT_TEXT; - g_config = NULL; - g_chordpro_filepath = NULL; + ctx.current_ttype = TT_TEXT; + ctx.prev_ttype = TT_TEXT; + ctx.config = NULL; + ctx.chordpro_filepath = NULL; free(ctx.transpose_history); ctx.transpose_history = NULL; ctx.transpose = NULL; - g_line_number = 1; - for (e = 0; e<g_ia; e++) { - cho_image_free(g_image_assets[e]); + ctx.line_number = 1; + for (e = 0; e<ctx.ia; e++) { + cho_image_free(ctx.image_assets[e]); } - free(g_image_assets); - g_image_assets = NULL; - g_ia = 0; + free(ctx.image_assets); + ctx.image_assets = NULL; + ctx.ia = 0; bool exist_title = false; for (ctx.so = 0; ctx.songs[ctx.so]; ctx.so++) { for (ctx.m = 0; ctx.songs[ctx.so]->metadata[ctx.m]; ctx.m++) { @@ -5600,9 +5607,9 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } } if (!exist_title) { - g_line_number = 0; - /* INFO: This cho_log() is not line specific. It's a workaround. */ - cho_log(LOG_ERR, "Song has no title."); + ctx.line_number = 0; + /* INFO: This cho_log(ctx, ) is not line specific. It's a workaround. */ + cho_log(&ctx, LOG_ERR, "Song has no title."); return NULL; } exist_title = false; diff --git a/src/chordpro.h b/src/chordpro.h @@ -133,11 +133,14 @@ struct ChoContext { bool is_chord_already_initialized; bool is_maybe_end_of_tab_directive; bool directive_has_tag; + const char *chordpro_filepath; enum State state; enum State state_before_comment; enum State state_before_tag; enum State state_before_backslash; enum State state_before_metadata_substitution; + enum TextType current_ttype; + enum TextType prev_ttype; index_t ann; // annotation index_t at; // struct Attr index_t atn; // struct Attr.name @@ -146,6 +149,7 @@ struct ChoContext { index_t dia; // struct ChordDiagram index_t dn; // char directive_name index_t dv; // char directive_value + index_t ia; // struct ChoImage index_t li; // struct ChoLine index_t lia; // struct ChoLineItemAbove index_t lii; // struct ChoLineItem @@ -159,10 +163,13 @@ struct ChoContext { index_t th; // transpose_history int text_above_pos; int nested_level; + size_t line_number; int *transpose_history; int *transpose; struct ChoSong **songs; struct Tag **tags; + struct Config *config; + struct ChoImage **image_assets; }; void cho_log_enable_info_logs(void);