commit 165d8b925f31ec8d3a4eb9feafa330545bfc6ca9
parent 56243a4c30ca1172edba725bd1e0e7f4064afdaa
Author: nibo <nibo@relim.de>
Date: Sat, 22 Mar 2025 11:10:53 +0100
Imrove metadata substitutions
Support metadata names that have a dot inside
like e.g. 'chordpro.version'
Diffstat:
2 files changed, 40 insertions(+), 24 deletions(-)
diff --git a/src/chordpro.c b/src/chordpro.c
@@ -1896,13 +1896,6 @@ cho_metadata_substitution_replace(
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'.
-*/
-// TODO: %{lang=""|yes|no} prints langs' value and the string 'yes', that's wrong.
static char *
cho_metadata_substitution_parse(
struct ChoContext *ctx,
@@ -1911,12 +1904,14 @@ cho_metadata_substitution_parse(
enum State state_before_substitution
)
{
+ bool substitution_exist = false;
int o = 0;
char *out = NULL;
int len = strlen(str);
int i;
for (i = 0; i<len; i++) {
if (str[i] == '%' && str[i+1] == '{') {
+ substitution_exist = true;
i += 2;
break;
}
@@ -1964,8 +1959,7 @@ cho_metadata_substitution_parse(
}
if (c == '.') {
name[n] = 0;
- n = 0;
- state = MSS_NAME_INDEX;
+ state = MSS_NAME_OR_INDEX;
break;
}
if (prev_c != '\\' && c == '|') {
@@ -1978,7 +1972,26 @@ cho_metadata_substitution_parse(
n++;
break;
}
- case MSS_NAME_INDEX: {
+ case MSS_NAME_OR_INDEX: {
+ if (c == '-' || isdigit(c)) {
+ n = 0;
+ name_index[n] = c;
+ n++;
+ state = MSS_INDEX;
+ break;
+ } else
+ if (islower(c)) {
+ name[n] = '.';
+ n++;
+ name[n] = c;
+ n++;
+ state = MSS_NAME;
+ break;
+ }
+ cho_log(ctx, LOG_ERR, "Invalid character after the dot.");
+ return NULL;
+ }
+ case MSS_INDEX: {
if (c == '=') {
name_index[n] = 0;
n = 0;
@@ -1991,7 +2004,7 @@ cho_metadata_substitution_parse(
state = MSS_TRUE_TEXT;
break;
}
- if (c != '-' && !isdigit(c)) {
+ if (!isdigit(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;
@@ -2089,7 +2102,7 @@ cho_metadata_substitution_parse(
case MSS_NAME:
name[n] = 0;
break;
- case MSS_NAME_INDEX:
+ case MSS_INDEX:
name_index[n] = 0;
break;
case MSS_VALUE:
@@ -2125,7 +2138,7 @@ cho_metadata_substitution_parse(
}
if (name[0] != 0) {
replaced = cho_metadata_substitution_replace(ctx, name, value, index);
- if (replaced) {
+ if (replaced[0] != 0) {
if (true_text[0] != 0) {
substituted = cho_metadata_substitution_parse(ctx, true_text, name, STATE_METADATA_SUBSTITUTION);
for (ch = substituted; *ch; ch++) {
@@ -2141,7 +2154,6 @@ cho_metadata_substitution_parse(
o++;
}
}
- free(replaced);
} else {
if (false_text[0] != 0) {
substituted = cho_metadata_substitution_parse(ctx, false_text, name, STATE_METADATA_SUBSTITUTION);
@@ -2159,22 +2171,25 @@ cho_metadata_substitution_parse(
}
}
}
+ free(replaced);
} 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, "", 0);
- if (replaced) {
- for (ch = replaced; *ch; ch++) {
- out = erealloc(out, (o+1) * sizeof(char));
- out[o] = *ch;
- o++;
+ if (substitution_exist) {
+ replaced = cho_metadata_substitution_replace(ctx, parent_name, "", 0);
+ if (replaced[0] != 0) {
+ 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);
}
- } else {
- cho_log(ctx, LOG_WARN, "There is no metadata item named '%s'.", parent_name);
+ free(replaced);
}
- free(replaced);
}
for (; i<len; i++) {
out = erealloc(out, (o+1) * sizeof(char));
diff --git a/src/chordpro.h b/src/chordpro.h
@@ -34,7 +34,8 @@ enum ChordDiagramState {
enum MetadataSubstitutionState {
MSS_NAME,
- MSS_NAME_INDEX,
+ MSS_NAME_OR_INDEX,
+ MSS_INDEX,
MSS_VALUE,
MSS_TRUE_TEXT,
MSS_FALSE_TEXT,