lorid

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

commit 29335272dd54eacceb81471dad2554a300ef5423
parent 60244ad2cdae9c85c97cf68ed758a18b6857987b
Author: nibo <nibo@relim.de>
Date:   Wed, 21 Aug 2024 10:44:12 +0200

Restructure config file format

Diffstat:
Mchordpro.c | 62++++++++++++++++++++++++++++++++++++++++++--------------------
Mconfig.c | 285+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mconfig.h | 20++++++++++++++++++--
Mout_pdf.c | 6+++---
Mtodo | 2++
5 files changed, 221 insertions(+), 154 deletions(-)

diff --git a/chordpro.c b/chordpro.c @@ -690,25 +690,25 @@ struct Style *cho_style_new_from_config(enum SongFragmentType ftype) struct PrintableItem *printable_item; switch (ftype) { case SF_CHORD: - printable_item = config_printable_item_get(g_config->printable_items, "chord"); + printable_item = config_printable_item_get(g_config->output->printable_items, "chord"); return cho_style_duplicate(printable_item->style); case SF_ANNOT: - printable_item = config_printable_item_get(g_config->printable_items, "annotation"); + printable_item = config_printable_item_get(g_config->output->printable_items, "annotation"); return cho_style_duplicate(printable_item->style); case SF_GRID: - printable_item = config_printable_item_get(g_config->printable_items, "grid"); + printable_item = config_printable_item_get(g_config->output->printable_items, "grid"); return cho_style_duplicate(printable_item->style); case SF_TAB: - printable_item = config_printable_item_get(g_config->printable_items, "tab"); + printable_item = config_printable_item_get(g_config->output->printable_items, "tab"); return cho_style_duplicate(printable_item->style); case SF_LABEL: - printable_item = config_printable_item_get(g_config->printable_items, "label"); + printable_item = config_printable_item_get(g_config->output->printable_items, "label"); return cho_style_duplicate(printable_item->style); case SF_TITLE: - printable_item = config_printable_item_get(g_config->printable_items, "title"); + printable_item = config_printable_item_get(g_config->output->printable_items, "title"); return cho_style_duplicate(printable_item->style); default: - printable_item = config_printable_item_get(g_config->printable_items, "text"); + printable_item = config_printable_item_get(g_config->output->printable_items, "text"); return cho_style_duplicate(printable_item->style); } } @@ -1369,25 +1369,27 @@ static int cho_chord_root_parse(const char *str, struct ChoChord *chord) const char *note = NULL; const char *sharp = NULL; const char *flat = NULL; + const char *out_note = NULL; + const char *out_sharp = NULL; + const char *out_flat = NULL; int i; for (i = 0; i<7; i++) { - sharp = g_config->chords->notes[i]->sharp; + sharp = g_config->parser->notes[i]->sharp; + out_sharp = g_config->output->notes[i]->sharp; if (sharp && str_starts_with(str, sharp)) { - chord->root = strdup(sharp); + chord->root = strdup(out_sharp); return strlen(sharp); } - } - for (i = 0; i<7; i++) { - flat = g_config->chords->notes[i]->flat; + flat = g_config->parser->notes[i]->flat; + out_flat = g_config->output->notes[i]->flat; if (flat && str_starts_with(str, flat)) { - chord->root = strdup(flat); + chord->root = strdup(out_flat); return strlen(flat); } - } - for (i = 0; i<7; i++) { - note = g_config->chords->notes[i]->note; + note = g_config->parser->notes[i]->note; + out_note = g_config->output->notes[i]->note; if (str_starts_with(str, note)) { - chord->root = strdup(note); + chord->root = strdup(out_note); return strlen(note); } } @@ -1443,11 +1445,31 @@ static int cho_chord_qualifier_and_extension_parse(const char *str, struct ChoCh static int cho_chord_bass_parse(const char *str, struct ChoChord *chord) { if (str[0] == '/') { + const char *note = NULL; + const char *sharp = NULL; + const char *flat = NULL; + const char *out_note = NULL; + const char *out_sharp = NULL; + const char *out_flat = NULL; int i; for (i = 0; i<7; i++) { - if (strcmp((char *)&str[1], g_config->chords->notes[i]->note) == 0) { - chord->bass = strdup((char *)&str[1]); - return strlen((char *)&str[1]) + 1; + sharp = g_config->parser->notes[i]->sharp; + out_sharp = g_config->output->notes[i]->sharp; + if (sharp && strcmp((char *)&str[1], sharp) == 0) { + chord->bass = strdup(out_sharp); + return strlen(sharp) + 1; + } + flat = g_config->parser->notes[i]->flat; + out_flat = g_config->output->notes[i]->flat; + if (flat && strcmp((char *)&str[1], flat) == 0) { + chord->bass = strdup(out_flat); + return strlen(flat) + 1; + } + note = g_config->parser->notes[i]->note; + out_note = g_config->parser->notes[i]->note; + if (strcmp((char *)&str[1], note) == 0) { + chord->bass = strdup(out_note); + return strlen(note) + 1; } } } diff --git a/config.c b/config.c @@ -230,74 +230,69 @@ static const char *config_naming_system_to_config_string(enum NamingSystem syste static struct Config *config_load_default(void) { struct Config *config = malloc(sizeof(struct Config)); - config->printable_items = malloc(12 * sizeof(struct PrintableItem *)); - config->printable_items[0] = config_printable_item_new("title"); - config->printable_items[0]->style->font->name = strdup("Inter"); - config->printable_items[0]->style->font->weight = FW_BOLD; - config->printable_items[0]->style->font->size = 18.0; - config->printable_items[1] = config_printable_item_new("subtitle"); - config->printable_items[1]->style->font->name = strdup("Inter"); - config->printable_items[1]->style->font->size = 12.0; - config->printable_items[2] = config_printable_item_new("text"); - config->printable_items[2]->style->font->name = strdup("Inter"); - config->printable_items[3] = config_printable_item_new("chord"); - config->printable_items[3]->style->font->name = strdup("Inter"); - config->printable_items[3]->style->font->weight = FW_BOLD; - config->printable_items[4] = config_printable_item_new("comment"); - config->printable_items[4]->style->font->name = strdup("Inter"); - config->printable_items[5] = config_printable_item_new("comment_italic"); - config->printable_items[5]->style->font->name = strdup("Inter"); - config->printable_items[5]->style->font->style = FS_ITALIC; - config->printable_items[6] = config_printable_item_new("comment_box"); - config->printable_items[6]->style->font->name = strdup("Inter"); - config->printable_items[7] = config_printable_item_new("tab"); - config->printable_items[7]->style->font->name = strdup("Inter"); - config->printable_items[8] = config_printable_item_new("grid"); - config->printable_items[8]->style->font->name = strdup("Inter"); - config->printable_items[8]->style->font->weight = FW_BOLD; - config->printable_items[9] = config_printable_item_new("label"); - config->printable_items[9]->style->font->name = strdup("Inter"); - config->printable_items[9]->style->font->style = FS_ITALIC; - config->printable_items[10] = config_printable_item_new("annotation"); - config->printable_items[10]->style->font->name = strdup("Inter"); - config->printable_items[10]->style->font->style = FS_ITALIC; - config->printable_items[11] = NULL; - config->chords = malloc(sizeof(struct ConfigChords)); - config->chords->system = NS_COMMON; - config->chords->mode = PM_STRICT; - config->chords->notes = NULL; + config->output = malloc(sizeof(struct ConfigOutput)); + config->output->system = NS_COMMON; + config->output->printable_items = malloc(12 * sizeof(struct PrintableItem *)); + config->output->printable_items[0] = config_printable_item_new("title"); + config->output->printable_items[0]->style->font->name = strdup("Inter"); + config->output->printable_items[0]->style->font->weight = FW_BOLD; + config->output->printable_items[0]->style->font->size = 18.0; + config->output->printable_items[1] = config_printable_item_new("subtitle"); + config->output->printable_items[1]->style->font->name = strdup("Inter"); + config->output->printable_items[1]->style->font->size = 12.0; + config->output->printable_items[2] = config_printable_item_new("text"); + config->output->printable_items[2]->style->font->name = strdup("Inter"); + config->output->printable_items[3] = config_printable_item_new("chord"); + config->output->printable_items[3]->style->font->name = strdup("Inter"); + config->output->printable_items[3]->style->font->weight = FW_BOLD; + config->output->printable_items[4] = config_printable_item_new("comment"); + config->output->printable_items[4]->style->font->name = strdup("Inter"); + config->output->printable_items[5] = config_printable_item_new("comment_italic"); + config->output->printable_items[5]->style->font->name = strdup("Inter"); + config->output->printable_items[5]->style->font->style = FS_ITALIC; + config->output->printable_items[6] = config_printable_item_new("comment_box"); + config->output->printable_items[6]->style->font->name = strdup("Inter"); + config->output->printable_items[7] = config_printable_item_new("tab"); + config->output->printable_items[7]->style->font->name = strdup("Inter"); + config->output->printable_items[8] = config_printable_item_new("grid"); + config->output->printable_items[8]->style->font->name = strdup("Inter"); + config->output->printable_items[8]->style->font->weight = FW_BOLD; + config->output->printable_items[9] = config_printable_item_new("label"); + config->output->printable_items[9]->style->font->name = strdup("Inter"); + config->output->printable_items[9]->style->font->style = FS_ITALIC; + config->output->printable_items[10] = config_printable_item_new("annotation"); + config->output->printable_items[10]->style->font->name = strdup("Inter"); + config->output->printable_items[10]->style->font->style = FS_ITALIC; + config->output->printable_items[11] = NULL; + config->output->notes = config_notes_new_default(NS_COMMON); + config->parser = malloc(sizeof(struct ConfigParser)); + config->parser->chords = malloc(sizeof(struct ConfigChords)); + config->parser->chords->system = NS_COMMON; + config->parser->chords->mode = PM_STRICT; + config->parser->notes = config_notes_new_default(NS_COMMON); return config; } static void config_printable_item_print_as_toml(struct PrintableItem *item) { - printf("[styles.%s]\n\n", item->name); + printf("[output.styles.%s]\n\n", item->name); cho_style_print_as_toml(item->style, item->name); } void config_print_default(void) { struct Config *config = config_load_default(); - config->chords->notes = config_notes_new_default(config->chords->system); int i = 0; - printf("[styles]\n"); - while (config->printable_items[i] != NULL) { - config_printable_item_print_as_toml(config->printable_items[i]); + printf("[output]\n\n"); + printf("[output.styles]\n\n"); + while (config->output->printable_items[i] != NULL) { + config_printable_item_print_as_toml(config->output->printable_items[i]); i++; } - printf("[chords]\n\n"); - printf("mode = \"%s\"\n", config_parse_mode_to_config_string(config->chords->mode)); - printf("system = \"%s\"\n\n", config_naming_system_to_config_string(config->chords->system)); - printf("[chords.notes]\n\n"); - printf("common = [\n"); - printf("\t{ note = \"C\", sharp = \"C#\" },\n"); - printf("\t{ note = \"D\", sharp = \"D#\", flat = \"Db\" },\n"); - printf("\t{ note = \"E\", flat = \"Eb\" },\n"); - printf("\t{ note = \"F\", sharp = \"F#\" },\n"); - printf("\t{ note = \"G\", sharp = \"G#\", flat = \"Gb\" },\n"); - printf("\t{ note = \"A\", sharp = \"A#\", flat = \"Ab\" },\n"); - printf("\t{ note = \"B\", flat = \"Bb\" }\n"); - printf("]\n"); + printf("[parser]\n\n"); + printf("[parser.chords]\n\n"); + printf("mode = \"%s\"\n", config_parse_mode_to_config_string(config->parser->chords->mode)); + printf("system = \"%s\"\n\n", config_naming_system_to_config_string(config->parser->chords->system)); config_free(config); } @@ -318,7 +313,7 @@ static bool config_load_font(struct Font *font, toml_table_t *table, const char if (family != FF_EMPTY) { font->family = family; } else { - fprintf(stderr, "ERR: Config section [styles.%s.font] family value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s.font] family value is invalid.\n", key_name); return false; } free(value.u.s); @@ -329,7 +324,7 @@ static bool config_load_font(struct Font *font, toml_table_t *table, const char if (style != FS_EMPTY) { font->style = style; } else { - fprintf(stderr, "ERR: Config section [styles.%s.font] style value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s.font] style value is invalid.\n", key_name); return false; } free(value.u.s); @@ -340,7 +335,7 @@ static bool config_load_font(struct Font *font, toml_table_t *table, const char if (weight != FW_EMPTY) { font->weight = weight; } else { - fprintf(stderr, "ERR: Config section [styles.%s.font] weight value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s.font] weight value is invalid.\n", key_name); return false; } free(value.u.s); @@ -371,7 +366,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->foreground_color); style->foreground_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] foreground color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] foreground color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -383,7 +378,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->background_color); style->background_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] background color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] background color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -394,7 +389,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch if (line_style != LS_EMPTY) { style->underline_style = line_style; } else { - fprintf(stderr, "ERR: Config section [styles.%s] underline style value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] underline style value is invalid.\n", key_name); return false; } free(value.u.s); @@ -406,7 +401,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->underline_color); style->underline_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] underline color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] underline color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -417,7 +412,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch if (line_style != LS_EMPTY) { style->overline_style = line_style; } else { - fprintf(stderr, "ERR: Config section [styles.%s] overline style value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] overline style value is invalid.\n", key_name); return false; } free(value.u.s); @@ -429,7 +424,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->overline_color); style->overline_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] overline color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] overline color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -445,7 +440,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->strikethrough_color); style->strikethrough_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] strikethrough color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] strikethrough color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -461,7 +456,7 @@ static bool config_load_style(struct Style *style, toml_table_t *table, const ch free(style->boxed_color); style->boxed_color = color; } else { - fprintf(stderr, "ERR: Config section [styles.%s] boxed color value is invalid.\n", key_name); + fprintf(stderr, "ERR: Config section [output.styles.%s] boxed color value is invalid.\n", key_name); return false; } free(value.u.s); @@ -491,7 +486,6 @@ static bool config_is_style(const char *str) struct Config *config_load(const char *filepath) { struct Config *config = config_load_default(); - config->chords->notes = config_notes_new_default(NS_COMMON); char *home = getenv("HOME"); char path[26+strlen(home)+1]; if (!filepath) { @@ -510,72 +504,102 @@ struct Config *config_load(const char *filepath) fprintf(stderr, "ERR: Config file is not a valid toml file.\n"); return NULL; } - toml_table_t *styles = toml_table_table(table, "styles"); - if (styles) { - int unused; - const char *key_name; - toml_table_t *key; - struct PrintableItem *item; - for (int i=0; i<toml_table_len(styles); i++) { - key_name = toml_table_key(styles, i, &unused); - if (config_is_style(key_name)) { - key = toml_table_table(styles, key_name); - if (key) { - item = config_printable_item_get(config->printable_items, key_name); - if (item) { - if (!config_load_style(item->style, key, key_name)) { - fprintf(stderr, "config_load_style failed.\n"); - return NULL; + toml_table_t *output = toml_table_table(table, "output"); + if (output) { + toml_table_t *notes; + toml_value_t value; + enum NamingSystem system; + struct Note **custom_notes; + value = toml_table_string(output, "system"); + if (value.ok) { + system = config_naming_system_parse(value.u.s); + if (system == NS_CUSTOM) { + notes = toml_table_table(table, "notes"); + if (!notes) { + fprintf(stderr, "ERR: Custom notes '%s' has no corresponding definition in [notes].\n", value.u.s); + return NULL; + } + custom_notes = config_notes_load(notes, value.u.s); + if (custom_notes) { + config_notes_free(config->output->notes); + config->output->notes = custom_notes; + } else { + fprintf(stderr, "config_notes_load failed.\n"); + fprintf(stderr, "ERR: Couldn't load custom notes '%s' from [notes] section.\n", value.u.s); + return NULL; + } + } else { + config_notes_free(config->output->notes); + config->output->notes = config_notes_new_default(system); + } + free(value.u.s); + } + toml_table_t *styles = toml_table_table(output, "styles"); + if (styles) { + int unused; + const char *key_name; + toml_table_t *key; + struct PrintableItem *item; + for (int i=0; i<toml_table_len(styles); i++) { + key_name = toml_table_key(styles, i, &unused); + if (config_is_style(key_name)) { + key = toml_table_table(styles, key_name); + if (key) { + item = config_printable_item_get(config->output->printable_items, key_name); + if (item) { + if (!config_load_style(item->style, key, key_name)) { + fprintf(stderr, "config_load_style failed.\n"); + return NULL; + } } } } } } } - toml_table_t *chords = toml_table_table(table, "chords"); - struct Note **notes_custom = NULL; - if (chords) { - toml_value_t value; - value = toml_table_string(chords, "system"); - if (value.ok) { - if (strcasecmp(value.u.s, "common") == 0 || strcasecmp(value.u.s, "dutch") == 0) { - config->chords->system = NS_COMMON; - } else if (strcasecmp(value.u.s, "german") == 0) { - config->chords->system = NS_GERMAN; - } else if (strcasecmp(value.u.s, "scandinavian") == 0) { - config->chords->system = NS_SCANDINAVIAN; - } else if (strcasecmp(value.u.s, "latin") == 0) { - config->chords->system = NS_LATIN; - } else { - toml_table_t *notes = toml_table_table(chords, "notes"); - if (notes) { - notes_custom = config_notes_load(notes, value.u.s); - if (notes_custom) { - config_notes_free(config->chords->notes); - config->chords->notes = notes_custom; + toml_table_t *parser = toml_table_table(table, "parser"); + if (parser) { + toml_table_t *chords = toml_table_table(parser, "chords"); + if (chords) { + toml_table_t *notes; + toml_value_t value; + enum NamingSystem system; + struct Note **custom_notes; + value = toml_table_string(chords, "system"); + if (value.ok) { + system = config_naming_system_parse(value.u.s); + if (system == NS_CUSTOM) { + notes = toml_table_table(table, "notes"); + if (!notes) { + fprintf(stderr, "ERR: Custom notes '%s' has no corresponding definition in [notes].\n", value.u.s); + return NULL; + } + custom_notes = config_notes_load(notes, value.u.s); + if (custom_notes) { + config_notes_free(config->parser->notes); + config->parser->notes = custom_notes; } else { fprintf(stderr, "config_notes_load failed.\n"); - fprintf(stderr, "WARN: Continuing with default naming system 'common'.\n"); + fprintf(stderr, "ERR: Couldn't load custom notes '%s' from [notes] section.\n", value.u.s); + return NULL; } + } else { + config_notes_free(config->parser->notes); + config->parser->notes = config_notes_new_default(system); } + free(value.u.s); } - free(value.u.s); - } - value = toml_table_string(chords, "mode"); - if (value.ok) { - if (strcasecmp(value.u.s, "strict") == 0) { - config->chords->mode = PM_STRICT; - } else if (strcasecmp(value.u.s, "relaxed") == 0) { - config->chords->mode = PM_RELAXED; + value = toml_table_string(chords, "mode"); + if (value.ok) { + if (strcasecmp(value.u.s, "strict") == 0) { + config->parser->chords->mode = PM_STRICT; + } else if (strcasecmp(value.u.s, "relaxed") == 0) { + config->parser->chords->mode = PM_RELAXED; + } + free(value.u.s); } - free(value.u.s); } } - /* if (notes_custom) { - config->chords->notes = notes_custom; - } else { - config->chords->notes = config_notes_new_default(config->chords->system); - } */ toml_free(table); fclose(fp); return config; @@ -583,18 +607,21 @@ struct Config *config_load(const char *filepath) void config_free(struct Config *config) { - int i = 0; - while (config->printable_items[i] != NULL) { - config_printable_item_free(config->printable_items[i]); - i++; + int i; + for (i = 0; config->output->printable_items[i]; i++) { + config_printable_item_free(config->output->printable_items[i]); } - free(config->printable_items); - i = 0; - while (config->chords->notes[i] != NULL) { - config_note_free(config->chords->notes[i]); - i++; + free(config->output->printable_items); + for (i = 0; config->output->notes[i]; i++) { + config_note_free(config->output->notes[i]); + } + free(config->output->notes); + free(config->output); + free(config->parser->chords); + for (i = 0; config->parser->notes[i]; i++) { + config_note_free(config->parser->notes[i]); } - free(config->chords->notes); - free(config->chords); + free(config->parser->notes); + free(config->parser); free(config); } diff --git a/config.h b/config.h @@ -27,12 +27,28 @@ struct Note { struct ConfigChords { enum NamingSystem system; enum ParseMode mode; - struct Note **notes; + // struct Note **notes; }; -struct Config { +/* struct Config { struct PrintableItem **printable_items; struct ConfigChords *chords; +}; */ + +struct ConfigParser { + struct ConfigChords *chords; + struct Note **notes; +}; + +struct ConfigOutput { + enum NamingSystem system; + struct PrintableItem **printable_items; + struct Note **notes; +}; + +struct Config { + struct ConfigOutput *output; + struct ConfigParser *parser; }; struct Config *config_load(const char *filepath); diff --git a/out_pdf.c b/out_pdf.c @@ -101,8 +101,8 @@ static struct Font **out_pdf_font_get_all(struct ChoSong **songs, struct Config struct Font *font; bool added = false; int i = 0; - while (config->printable_items[i] != NULL) { - font = cho_font_duplicate(config->printable_items[i]->style->font); + while (config->output->printable_items[i] != NULL) { + font = cho_font_duplicate(config->output->printable_items[i]->style->font); added = out_pdf_font_add_if_not_in(font, &fonts); if (!added) cho_font_free(font); @@ -649,7 +649,7 @@ static struct Text **text_create(struct ChoSong **songs, struct Config *config) } for (m = 0; songs[so]->metadata[m]; m++) { if (strcmp(songs[so]->metadata[m]->name, "subtitle") == 0) { - printable_item = config_printable_item_get(config->printable_items, "subtitle"); + printable_item = config_printable_item_get(config->output->printable_items, "subtitle"); if (!printable_item) { fprintf(stderr, "config_printable_item_get failed.\n"); return NULL; diff --git a/todo b/todo @@ -18,3 +18,5 @@ parse environment directive value when: label="Verse 1" # pdf output break lines when too long render in two or more columns + +find better name fore PrintableItem, TextAbove