lorid

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

commit d2ed7d2819772fd65b44195bfb5dfe822772610c
parent fae7c6227c961afe8c694c14d7a5511b58eb60bd
Author: nibo <nibo@relim.de>
Date:   Sun, 23 Feb 2025 10:49:58 +0100

Imporove metadata substitution parsing

Diffstat:
Msrc/chordpro.c | 175++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 146 insertions(+), 29 deletions(-)

diff --git a/src/chordpro.c b/src/chordpro.c @@ -1773,12 +1773,59 @@ cho_metadata_load_default(struct ChoContext *ctx) } static char * -cho_metadata_substitution_replace(struct ChoMetadata **metadata, const char *name) +cho_metadata_substitution_replace( + struct ChoContext *ctx, + const char *name, + const char *value, + int index +) { - struct ChoMetadata **m; - for (m = metadata; *m; m++) { - if (!strcmp((*m)->name, name)) { - return strdup((*m)->value); + struct ChoMetadata *m; + int n = 0; + int i; + if (index < 0) { + if (value[0] != 0) { + for (i = ctx->m-1; i >= 0; i--) { + m = ctx->songs[ctx->so]->metadata[i]; + if (!strcmp(m->name, name)) { + n--; + if (!strcmp(m->value, value) && n == index) { + return strdup(m->value); + } + } + } + } else { + for (i = ctx->m-1; i >= 0; i--) { + m = ctx->songs[ctx->so]->metadata[i]; + if (!strcmp(m->name, name)) { + n--; + if (n == index) { + return strdup(m->value); + } + } + } + } + } else if (index > 0) { + if (value[0] != 0) { + for (i = 0; i<ctx->m; i++) { + m = ctx->songs[ctx->so]->metadata[i]; + if (!strcmp(m->name, name)) { + n++; + if (!strcmp(m->value, value) && n == index) { + return strdup(m->value); + } + } + } + } else { + for (i = 0; i<ctx->m; i++) { + m = ctx->songs[ctx->so]->metadata[i]; + if (!strcmp(m->name, name)) { + n++; + if (n == index) { + return strdup(m->value); + } + } + } } } return NULL; @@ -1794,10 +1841,24 @@ static char * cho_metadata_substitution_parse( struct ChoContext *ctx, const char *str, - struct ChoMetadata **metadata, + const char *parent_name, enum State state_before_substitution ) { + int o = 0; + char *out = NULL; + int len = strlen(str); + int i; + for (i = 0; i<len; i++) { + if (str[i] == '%' && str[i+1] == '{') { + i += 2; + break; + } + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = str[i]; + o++; + } + enum MetadataSubstitutionState state = MSS_NAME; enum AttrValueSyntax avs = -1; char name[128]; @@ -1813,8 +1874,20 @@ cho_metadata_substitution_parse( char prev_c = 0; char c = 0; int n = 0; - for (; *str; str++) { - c = *str; + int nested_level = 0; + for (; i<len; i++) { + c = str[i]; + + if (prev_c == '%' && c == '{') { + nested_level++; + } else if (prev_c != '\\' && c == '}') { + if (nested_level == 0) { + i++; + break; + } + nested_level--; + } + switch (state) { case MSS_NAME: { if (c == '=') { @@ -1853,7 +1926,6 @@ cho_metadata_substitution_parse( 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; @@ -1919,7 +1991,7 @@ cho_metadata_substitution_parse( break; } case MSS_TRUE_TEXT: { - if (prev_c != '\\' && c == '|') { + if (prev_c != '\\' && c == '|' && nested_level == 0) { true_text[n] = 0; n = 0; state = MSS_FALSE_TEXT; @@ -1973,36 +2045,74 @@ cho_metadata_substitution_parse( case MSS_FALSE_TEXT: false_text[n] = 0; break; + default: + } + char *replaced, *substituted, *ch; + int index = 1; + if (name_index[0] != 0) { + index = atoi(name_index); + if (index == 0) { + LOG_DEBUG("atoi failed."); + return NULL; + } } - char *replaced; if (name[0] != 0) { - replaced = cho_metadata_substitution_replace(metadata, name); + replaced = cho_metadata_substitution_replace(ctx, name, value, index); if (replaced) { if (true_text[0] != 0) { - // return cho_metadata_substitution_parse(); + substituted = cho_metadata_substitution_parse(ctx, true_text, name, STATE_METADATA_SUBSTITUTION); + for (ch = substituted; *ch; ch++) { + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = *ch; + o++; + } + free(substituted); } else { - return replaced; + for (ch = replaced; *ch; ch++) { + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = *ch; + o++; + } } + free(replaced); } else { if (false_text[0] != 0) { - // return cho_metadata_substitution_parse(); + substituted = cho_metadata_substitution_parse(ctx, false_text, name, STATE_METADATA_SUBSTITUTION); + for (ch = substituted; *ch; ch++) { + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = *ch; + o++; + } + free(substituted); } else { - return strdup(""); + cho_log(ctx, LOG_WARN, "There is no metadata item named '%s'.", name); } } + } else { + if (state_before_substitution != STATE_METADATA_SUBSTITUTION) { + cho_log(ctx, LOG_ERR, "An empty metadata substitution can only be used inside of another metadata substitution."); + return NULL; + } + replaced = cho_metadata_substitution_replace(ctx, parent_name, "", 1); + if (replaced) { + for (ch = replaced; *ch; ch++) { + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = *ch; + o++; + } + } else { + cho_log(ctx, LOG_WARN, "There is no metadata item named '%s'.", parent_name); + } + free(replaced); + } + for (; i<len; i++) { + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = str[i]; + o++; } - /* 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' ", 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 ""; */ + out = erealloc(out, (o+1) * sizeof(char)); + out[o] = 0; + return out; } static bool @@ -5725,6 +5835,10 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c } case STATE_MAYBE_METADATA_SUBSTITUTION: { if (c == '{') { + metadata_substitution[ctx.ms] = '%'; + ctx.ms++; + metadata_substitution[ctx.ms] = '{'; + ctx.ms++; ctx.state = STATE_METADATA_SUBSTITUTION; break; } @@ -5743,12 +5857,14 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c case STATE_METADATA_SUBSTITUTION: { if (prev_c != '\\' && c == '}') { if (ctx.nested_level == 0) { + metadata_substitution[ctx.ms] = '}'; + ctx.ms++; metadata_substitution[ctx.ms] = 0; ctx.ms = 0; char *substituted = cho_metadata_substitution_parse( &ctx, metadata_substitution, - ctx.songs[ctx.so]->metadata, + NULL, ctx.state_before_metadata_substitution ); if (!substituted) { @@ -5765,6 +5881,7 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c ctx.te++; } break; + default: } free(substituted); ctx.state = ctx.state_before_metadata_substitution;