commit fbfb37c5440ea4d836d3742f89a32919d8e43349
parent 78d4be4302a623b81db0ccb4f09831964dc2a690
Author: nibo <nibo@relim.de>
Date: Thu, 20 Feb 2025 20:20:59 +0100
Continue implementing metadata substitution
Diffstat:
2 files changed, 139 insertions(+), 8 deletions(-)
diff --git a/src/chordpro.c b/src/chordpro.c
@@ -1772,14 +1772,133 @@ cho_metadata_load_default(struct ChoContext *ctx)
return meta;
}
-/* static char *
+static char *
cho_metadata_substitution_parse(
+ struct ChoContext *ctx,
const char *str,
struct ChoMetadata **metadata,
enum State state_before_substitution
)
{
-} */
+ enum MetadataSubstitutionState state = MSS_NAME;
+ enum AttrValueSyntax avs = -1;
+ char name[128];
+ name[0] = 0;
+ char value[4096];
+ value[0] = 0;
+ char prev_c = 0;
+ char c = 0;
+ int n = 0;
+ for (; *str; str++) {
+ c = *str;
+ switch (state) {
+ case MSS_NAME: {
+ if (c == '=') {
+ name[n] = 0;
+ n = 0;
+ state = MSS_VALUE;
+ break;
+ }
+ if (prev_c != '\\' && c == '|') {
+ name[n] = 0;
+ n = 0;
+ state = MSS_TRUE_TEXT;
+ break;
+ }
+ name[n] = c;
+ n++;
+ break;
+ }
+ case MSS_VALUE: {
+ if (avs == -1) {
+ if (is_whitespace(c)) {
+ cho_log(ctx, LOG_ERR, "Whitespace character after equals sign is invalid.");
+ return NULL;
+ }
+ if (c == '|') {
+ cho_log(ctx, LOG_ERR, "If you specify an equals sign then you have to provide a value.");
+ return NULL;
+ }
+ if (c == '\'') {
+ avs = AVS_APOSTROPHE;
+ } else if (c == '"') {
+ avs = AVS_QUOTATION_MARK;
+ } else {
+ avs = AVS_UNQUOTED;
+ value[n] = c;
+ n++;
+ }
+ break;
+ }
+ if (prev_c != '\\' && c == '|') {
+ if (avs == AVS_APOSTROPHE) {
+ cho_log(ctx, LOG_ERR, "Can't find a matching '\''.");
+ return NULL;
+ }
+ if (avs == AVS_QUOTATION_MARK) {
+ cho_log(ctx, LOG_ERR, "Can't find a matching '\"'.");
+ return NULL;
+ }
+ if (avs == AVS_UNQUOTED) {
+ value[n] = 0;
+ n = 0;
+ state = MSS_TRUE_TEXT;
+ break;
+ }
+ if (avs == -1) {
+ state = MSS_TRUE_TEXT;
+ break;
+ }
+ break;
+ }
+ if (
+ (avs == AVS_APOSTROPHE && c == '\'') ||
+ (avs == AVS_QUOTATION_MARK && c == '"') ||
+ (avs == AVS_UNQUOTED && c == ' ')
+ ) {
+ value[n] = 0;
+ n = 0;
+ state = MSS_WAIT_FOR_PIPE;
+ break;
+ }
+ value[n] = c;
+ n++;
+ break;
+ }
+ case MSS_TRUE_TEXT: {
+ if (prev_c != '\\' && c == '|') {
+ state = MSS_FALSE_TEXT;
+ break;
+ }
+ break;
+ }
+ case MSS_FALSE_TEXT: {
+ break;
+ }
+ case MSS_WAIT_FOR_PIPE: {
+ if (is_whitespace(c)) {
+ break;
+ }
+ if (c == '|') {
+ state = MSS_TRUE_TEXT;
+ break;
+ }
+ break;
+ }
+ }
+ prev_c = c;
+ }
+ if (state == MSS_NAME) {
+ name[n] = 0;
+ } else if (state == MSS_VALUE && avs == AVS_UNQUOTED) {
+ value[n] = 0;
+ }
+ if (name[0] != 0)
+ printf("name '%s'\n", name);
+ if (value[0] != 0)
+ printf("value '%s'\n", value);
+ return "";
+}
static bool
transposition_parse(const char *str, int *transpose)
@@ -5509,16 +5628,20 @@ cho_songs_parse(const char *str, const char *chordpro_filepath, struct Config *c
break;
}
case STATE_METADATA_SUBSTITUTION: {
- if (c == '}') {
+ if (prev_c != '\\' && c == '}') {
if (ctx.nested_level == 0) {
metadata_substitution[ctx.ms] = 0;
ctx.ms = 0;
- printf("substitution: '%s'\n", metadata_substitution);
- /* char *substituted = cho_metadata_substitution_parse(
+ char *substituted = cho_metadata_substitution_parse(
+ &ctx,
metadata_substitution,
- songs[so]->metadata,
- state_before_metadata_substitution
- ); */
+ ctx.songs[ctx.so]->metadata,
+ ctx.state_before_metadata_substitution
+ );
+ if (!substituted) {
+ LOG_DEBUG("cho_metadata_substitution_parse failed.");
+ return NULL;
+ }
// Append 'substituted' to whatever text
ctx.state = ctx.state_before_metadata_substitution;
break;
diff --git a/src/chordpro.h b/src/chordpro.h
@@ -30,6 +30,14 @@ enum ChordDiagramState {
CDS_COPY
};
+enum MetadataSubstitutionState {
+ MSS_NAME,
+ MSS_VALUE,
+ MSS_TRUE_TEXT,
+ MSS_FALSE_TEXT,
+ MSS_WAIT_FOR_PIPE
+};
+
enum ChordDirective {
TRANSPOSE, DEFINE /* , CHORD */
};