lorid

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

commit c209d8b19163cd56d98b14717618010c2d4ec246
parent a6e617e1299ba43f5ca0f6c3f7c261df262b2100
Author: nibo <nibo@relim.de>
Date:   Tue, 18 Feb 2025 20:40:42 +0100

Start implementing metadata substitution

Diffstat:
MDEVELOPMENT_NOTES | 5+++++
Msrc/chordpro.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/chordpro.h | 4+++-
Msrc/config.c | 15++++++++++++++-
Msrc/config.h | 3+++
5 files changed, 141 insertions(+), 5 deletions(-)

diff --git a/DEVELOPMENT_NOTES b/DEVELOPMENT_NOTES @@ -1,3 +1,8 @@ +## general + +The variable prefix 'g_' means it's a global variable. +It has nothing to do with the glib library. + ## stderr messages Text of the form '* failed' is a message for the developer. diff --git a/src/chordpro.c b/src/chordpro.c @@ -34,7 +34,9 @@ static const char *state_enums[] = { "STATE_MARKUP_TAG_END", "STATE_MARKUP_ATTR_NAME", "STATE_MARKUP_ATTR_VALUE", - "STATE_COMMENT" + "STATE_COMMENT", + "STATE_MAYBE_METADATA_SUBSTITUTION", + "STATE_METADATA_SUBSTITUTION" }; struct StyleProperty default_style_properties[] = { @@ -1683,6 +1685,58 @@ cho_metadata_split(const char *directive_value) } } +static struct ChoMetadata ** +cho_metadata_load_default(void) +{ + struct ChoMetadata **meta = NULL; + char *filename; + 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(); + i++; + if (g_chordpro_filepath) { + filename = filepath_basename(g_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; + 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"); + i++; + meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *)); + meta[i] = emalloc(sizeof(struct ChoMetadata)); + meta[i]->name = strdup("instrument"); + meta[i]->value = strdup(config_instrument_to_config_string(g_config->output->diagram->instrument)); + 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(config_instrument_to_config_string(g_config->output->diagram->instrument)); + 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(config_instrument_description(g_config->output->diagram->instrument)); + i++; + return meta; +} + +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) { @@ -3352,7 +3406,7 @@ static struct ChoSong * cho_song_new(void) { struct ChoSong *song = emalloc(sizeof(struct ChoSong)); - song->metadata = NULL; + song->metadata = cho_metadata_load_default(); song->sections = NULL; song->diagrams = NULL; memset(song->present_text_types, 0, TT_LENGTH); @@ -3939,16 +3993,19 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) char tag_start[6]; char tag_end[6]; char custom_directive[64]; + char metadata_substitution[4096]; char *label, *metadata_value, *stripped_directive_value; enum State state = STATE_LYRICS; enum State state_before_comment = STATE_LYRICS; enum State state_before_tag = STATE_LYRICS; enum State state_before_backslash = STATE_LYRICS; + enum State state_before_metadata_substitution = STATE_LYRICS; int dn = 0; int dv = 0; int ch = 0; int c = 0; - int m = 0; + // Not zero by default because there are default metadata entries + int m = 1; int ly = 0; int t = 0; int so = 0; @@ -3964,6 +4021,8 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) int transpose; int th = 0; int dia = 0; + int ms = 0; + int nested_level = 0; size_t read; g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *)); g_transpose_history[th] = 0; @@ -4034,6 +4093,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) state = STATE_MARKUP_TAG; break; } + if (buf == '%') { + state_before_metadata_substitution = STATE_LYRICS; + state = STATE_MAYBE_METADATA_SUBSTITUTION; + break; + } if (buf == '\n') { if (prev_buf == '\\') { state_before_backslash = STATE_LYRICS; @@ -5344,6 +5408,55 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } break; } + case STATE_MAYBE_METADATA_SUBSTITUTION: { + if (buf == '{') { + state = STATE_METADATA_SUBSTITUTION; + break; + } + switch (state_before_metadata_substitution) { + case STATE_LYRICS: + (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char)); + (*lines)[li]->items[ly]->u.text->text[te] = '%'; + te++; + break; + default: + } + state = state_before_metadata_substitution; + if (fseek(fp, -1, SEEK_CUR)) { + LOG_DEBUG("fseek failed."); + perror("fseek"); + return NULL; + } + break; + } + case STATE_METADATA_SUBSTITUTION: { + if (buf == '}') { + if (nested_level == 0) { + metadata_substitution[ms] = 0; + ms = 0; + printf("substitution: '%s'\n", metadata_substitution); + /* char *substituted = cho_metadata_substitution_parse( + metadata_substitution, + songs[so]->metadata, + state_before_metadata_substitution + ); */ + // Append 'substituted' to whatever text + state = state_before_metadata_substitution; + break; + } + nested_level--; + } + if (prev_buf == '%' && buf == '{') { + nested_level++; + } + if (ms > 4094) { + cho_log(LOG_ERR, "Metadata substitution can't be greater than 4095 bytes."); + return NULL; + } + metadata_substitution[ms] = buf; + ms++; + break; + } } prev_buf = buf; } else { diff --git a/src/chordpro.h b/src/chordpro.h @@ -76,7 +76,9 @@ enum State { STATE_MARKUP_TAG_END, STATE_MARKUP_ATTR_NAME, STATE_MARKUP_ATTR_VALUE, - STATE_COMMENT + STATE_COMMENT, + STATE_MAYBE_METADATA_SUBSTITUTION, + STATE_METADATA_SUBSTITUTION }; enum StylePropertyType : int8_t { diff --git a/src/config.c b/src/config.c @@ -30,6 +30,13 @@ static const char *instruments[] = { "ukulele" }; +static const char *instrument_descriptions[] = { + "Guitar, 6 strings, standard tuning", + "Piano", + "Mandolin, 4 strings, standard tuning", + "Ukulele, 4 strings, standard tuning" +}; + static const char *text_types[] = { "chord", "annotation", "chorus", "footer", "grid", "tab", "toc", "toc_title", "text", @@ -218,12 +225,18 @@ config_instrument_parse(const char *str) return -1; } -static const char * +const char * config_instrument_to_config_string(enum Instrument ins) { return instruments[ins]; } +const char * +config_instrument_description(enum Instrument ins) +{ + return instrument_descriptions[ins]; +} + static struct Note * config_note_new(void) { diff --git a/src/config.h b/src/config.h @@ -13,4 +13,7 @@ struct Config *config_load(const char *filepath); void config_free(struct Config *config); void config_print_default(void); +const char *config_instrument_to_config_string(enum Instrument ins); +const char *config_instrument_description(enum Instrument ins); + #endif /* _CONFIG_H_ */