commit cbc4d406d23ad19a7804069c2a79667112f962d7
parent fbfb37c5440ea4d836d3742f89a32919d8e43349
Author: nibo <nibo@relim.de>
Date: Fri, 21 Feb 2025 14:27:22 +0100
Improve metadata substitution parsing
Diffstat:
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,