lorid

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

commit cbc4d406d23ad19a7804069c2a79667112f962d7
parent fbfb37c5440ea4d836d3742f89a32919d8e43349
Author: nibo <nibo@relim.de>
Date:   Fri, 21 Feb 2025 14:27:22 +0100

Improve metadata substitution parsing

Diffstat:
Msrc/chordpro.c | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/chordpro.h | 1+
2 files changed, 126 insertions(+), 9 deletions(-)

diff --git a/src/chordpro.c b/src/chordpro.c @@ -1773,6 +1773,24 @@ cho_metadata_load_default(struct ChoContext *ctx) } static char * +cho_metadata_substitution_replace(struct ChoMetadata **metadata, const char *name) +{ + struct ChoMetadata **m; + for (m = metadata; *m; m++) { + if (!strcmp((*m)->name, name)) { + return strdup((*m)->value); + } + } + return NULL; +} + +/* + FIXME: metadata item names containing a dot like 'chordpro.version' simply doesn't work. + Their naming is against the naming rule described at 'https://www.chordpro.org/beta/directives-meta/'. + Handle the following metadata item names specially: 'chordpro.version', 'instrument.type', + 'instrument.description', 'user.name' and 'user.fullname'. +*/ +static char * cho_metadata_substitution_parse( struct ChoContext *ctx, const char *str, @@ -1783,9 +1801,15 @@ cho_metadata_substitution_parse( enum MetadataSubstitutionState state = MSS_NAME; enum AttrValueSyntax avs = -1; char name[128]; - name[0] = 0; + char name_index[8]; char value[4096]; + char true_text[4096]; + char false_text[4096]; + name[0] = 0; + name_index[0] = 0; value[0] = 0; + true_text[0] = 0; + false_text[0] = 0; char prev_c = 0; char c = 0; int n = 0; @@ -1799,6 +1823,12 @@ cho_metadata_substitution_parse( state = MSS_VALUE; break; } + if (c == '.') { + name[n] = 0; + n = 0; + state = MSS_NAME_INDEX; + break; + } if (prev_c != '\\' && c == '|') { name[n] = 0; n = 0; @@ -1809,6 +1839,29 @@ cho_metadata_substitution_parse( n++; break; } + case MSS_NAME_INDEX: { + if (c == '=') { + name_index[n] = 0; + n = 0; + state = MSS_VALUE; + break; + } + if (prev_c != '\\' && c == '|') { + name_index[n] = 0; + n = 0; + state = MSS_TRUE_TEXT; + break; + } + if (c != '-' && !isdigit(c)) { + printf("THID: %c", c); + // TODO: Find a better term for 'metadata substitution name index'! + cho_log(ctx, LOG_ERR, "Specify a positive or negative number in metadata substitution name index."); + return NULL; + } + name_index[n] = c; + n++; + break; + } case MSS_VALUE: { if (avs == -1) { if (is_whitespace(c)) { @@ -1832,7 +1885,7 @@ cho_metadata_substitution_parse( } if (prev_c != '\\' && c == '|') { if (avs == AVS_APOSTROPHE) { - cho_log(ctx, LOG_ERR, "Can't find a matching '\''."); + cho_log(ctx, LOG_ERR, "Can't find a matching \"\'\"."); return NULL; } if (avs == AVS_QUOTATION_MARK) { @@ -1867,12 +1920,18 @@ cho_metadata_substitution_parse( } case MSS_TRUE_TEXT: { if (prev_c != '\\' && c == '|') { + true_text[n] = 0; + n = 0; state = MSS_FALSE_TEXT; break; } + true_text[n] = c; + n++; break; } case MSS_FALSE_TEXT: { + false_text[n] = c; + n++; break; } case MSS_WAIT_FOR_PIPE: { @@ -1888,16 +1947,62 @@ cho_metadata_substitution_parse( } prev_c = c; } - if (state == MSS_NAME) { + switch (state) { + case MSS_NAME: name[n] = 0; - } else if (state == MSS_VALUE && avs == AVS_UNQUOTED) { - value[n] = 0; + break; + case MSS_NAME_INDEX: + name_index[n] = 0; + break; + case MSS_VALUE: + switch (avs) { + case AVS_APOSTROPHE: + cho_log(ctx, LOG_ERR, "Can't find a matching \"\'\"."); + return NULL; + case AVS_QUOTATION_MARK: + cho_log(ctx, LOG_ERR, "Can't find a matching '\"'."); + return NULL; + case AVS_UNQUOTED: + value[n] = 0; + break; + } + break; + case MSS_TRUE_TEXT: + true_text[n] = 0; + break; + case MSS_FALSE_TEXT: + false_text[n] = 0; + break; } - if (name[0] != 0) - printf("name '%s'\n", name); + char *replaced; + if (name[0] != 0) { + replaced = cho_metadata_substitution_replace(metadata, name); + if (replaced) { + if (true_text[0] != 0) { + // return cho_metadata_substitution_parse(); + } else { + return replaced; + } + } else { + if (false_text[0] != 0) { + // return cho_metadata_substitution_parse(); + } else { + return strdup(""); + } + } + } + /* if (name[0] != 0) + printf("name '%s' ", name); + if (name_index[0] != 0) + printf("name_index '%s' ", name_index); if (value[0] != 0) - printf("value '%s'\n", value); - return ""; + printf("value '%s' ", value); + if (true_text[0] != 0) + printf("true_text '%s' ", true_text); + if (false_text[0] != 0) + printf("false_text '%s' ", false_text); + printf("\n"); + return ""; */ } static bool @@ -5643,6 +5748,17 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c return NULL; } // Append 'substituted' to whatever text + switch (ctx.state_before_metadata_substitution) { + case STATE_LYRICS: + char *ch; + for (ch = substituted; *ch; ch++) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = *ch; + ctx.te++; + } + break; + } + free(substituted); ctx.state = ctx.state_before_metadata_substitution; break; } diff --git a/src/chordpro.h b/src/chordpro.h @@ -32,6 +32,7 @@ enum ChordDiagramState { enum MetadataSubstitutionState { MSS_NAME, + MSS_NAME_INDEX, MSS_VALUE, MSS_TRUE_TEXT, MSS_FALSE_TEXT,