commit c209d8b19163cd56d98b14717618010c2d4ec246
parent a6e617e1299ba43f5ca0f6c3f7c261df262b2100
Author: nibo <nibo@relim.de>
Date: Tue, 18 Feb 2025 20:40:42 +0100
Start implementing metadata substitution
Diffstat:
5 files changed, 141 insertions(+), 5 deletions(-)
diff --git a/DEVELOPMENT_NOTES b/DEVELOPMENT_NOTES
@@ -1,3 +1,8 @@
+## general
+
+The variable prefix 'g_' means it's a global variable.
+It has nothing to do with the glib library.
+
## stderr messages
Text of the form '* failed' is a message for the developer.
diff --git a/src/chordpro.c b/src/chordpro.c
@@ -34,7 +34,9 @@ static const char *state_enums[] = {
"STATE_MARKUP_TAG_END",
"STATE_MARKUP_ATTR_NAME",
"STATE_MARKUP_ATTR_VALUE",
- "STATE_COMMENT"
+ "STATE_COMMENT",
+ "STATE_MAYBE_METADATA_SUBSTITUTION",
+ "STATE_METADATA_SUBSTITUTION"
};
struct StyleProperty default_style_properties[] = {
@@ -1683,6 +1685,58 @@ cho_metadata_split(const char *directive_value)
}
}
+static struct ChoMetadata **
+cho_metadata_load_default(void)
+{
+ struct ChoMetadata **meta = NULL;
+ char *filename;
+ int i = 0;
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("chordpro");
+ meta[i]->value = strdup("ChordPro");
+ meta[i]->style = cho_style_new_default();
+ i++;
+ if (g_chordpro_filepath) {
+ filename = filepath_basename(g_chordpro_filepath);
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("chordpro.songsource");
+ meta[i]->value = filename;
+ i++;
+ }
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("chordpro.version");
+ meta[i]->value = strdup("6");
+ i++;
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("instrument");
+ meta[i]->value = strdup(config_instrument_to_config_string(g_config->output->diagram->instrument));
+ i++;
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("instrument.type");
+ meta[i]->value = strdup(config_instrument_to_config_string(g_config->output->diagram->instrument));
+ i++;
+ meta = erealloc(meta, (i+1) * sizeof(struct ChoMetadata *));
+ meta[i] = emalloc(sizeof(struct ChoMetadata));
+ meta[i]->name = strdup("instrument.description");
+ meta[i]->value = strdup(config_instrument_description(g_config->output->diagram->instrument));
+ i++;
+ return meta;
+}
+
+static char *
+cho_metadata_substitution_parse(
+ const char *str,
+ struct ChoMetadata **metadata,
+ enum State state_before_substitution
+)
+{
+}
+
static bool
transposition_parse(const char *str, int *transpose)
{
@@ -3352,7 +3406,7 @@ static struct ChoSong *
cho_song_new(void)
{
struct ChoSong *song = emalloc(sizeof(struct ChoSong));
- song->metadata = NULL;
+ song->metadata = cho_metadata_load_default();
song->sections = NULL;
song->diagrams = NULL;
memset(song->present_text_types, 0, TT_LENGTH);
@@ -3939,16 +3993,19 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
char tag_start[6];
char tag_end[6];
char custom_directive[64];
+ char metadata_substitution[4096];
char *label, *metadata_value, *stripped_directive_value;
enum State state = STATE_LYRICS;
enum State state_before_comment = STATE_LYRICS;
enum State state_before_tag = STATE_LYRICS;
enum State state_before_backslash = STATE_LYRICS;
+ enum State state_before_metadata_substitution = STATE_LYRICS;
int dn = 0;
int dv = 0;
int ch = 0;
int c = 0;
- int m = 0;
+ // Not zero by default because there are default metadata entries
+ int m = 1;
int ly = 0;
int t = 0;
int so = 0;
@@ -3964,6 +4021,8 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
int transpose;
int th = 0;
int dia = 0;
+ int ms = 0;
+ int nested_level = 0;
size_t read;
g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *));
g_transpose_history[th] = 0;
@@ -4034,6 +4093,11 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
state = STATE_MARKUP_TAG;
break;
}
+ if (buf == '%') {
+ state_before_metadata_substitution = STATE_LYRICS;
+ state = STATE_MAYBE_METADATA_SUBSTITUTION;
+ break;
+ }
if (buf == '\n') {
if (prev_buf == '\\') {
state_before_backslash = STATE_LYRICS;
@@ -5344,6 +5408,55 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
}
break;
}
+ case STATE_MAYBE_METADATA_SUBSTITUTION: {
+ if (buf == '{') {
+ state = STATE_METADATA_SUBSTITUTION;
+ break;
+ }
+ switch (state_before_metadata_substitution) {
+ case STATE_LYRICS:
+ (*lines)[li]->items[ly]->u.text->text = erealloc((*lines)[li]->items[ly]->u.text->text, (te+1) * sizeof(char));
+ (*lines)[li]->items[ly]->u.text->text[te] = '%';
+ te++;
+ break;
+ default:
+ }
+ state = state_before_metadata_substitution;
+ if (fseek(fp, -1, SEEK_CUR)) {
+ LOG_DEBUG("fseek failed.");
+ perror("fseek");
+ return NULL;
+ }
+ break;
+ }
+ case STATE_METADATA_SUBSTITUTION: {
+ if (buf == '}') {
+ if (nested_level == 0) {
+ metadata_substitution[ms] = 0;
+ ms = 0;
+ printf("substitution: '%s'\n", metadata_substitution);
+ /* char *substituted = cho_metadata_substitution_parse(
+ metadata_substitution,
+ songs[so]->metadata,
+ state_before_metadata_substitution
+ ); */
+ // Append 'substituted' to whatever text
+ state = state_before_metadata_substitution;
+ break;
+ }
+ nested_level--;
+ }
+ if (prev_buf == '%' && buf == '{') {
+ nested_level++;
+ }
+ if (ms > 4094) {
+ cho_log(LOG_ERR, "Metadata substitution can't be greater than 4095 bytes.");
+ return NULL;
+ }
+ metadata_substitution[ms] = buf;
+ ms++;
+ break;
+ }
}
prev_buf = buf;
} else {
diff --git a/src/chordpro.h b/src/chordpro.h
@@ -76,7 +76,9 @@ enum State {
STATE_MARKUP_TAG_END,
STATE_MARKUP_ATTR_NAME,
STATE_MARKUP_ATTR_VALUE,
- STATE_COMMENT
+ STATE_COMMENT,
+ STATE_MAYBE_METADATA_SUBSTITUTION,
+ STATE_METADATA_SUBSTITUTION
};
enum StylePropertyType : int8_t {
diff --git a/src/config.c b/src/config.c
@@ -30,6 +30,13 @@ static const char *instruments[] = {
"ukulele"
};
+static const char *instrument_descriptions[] = {
+ "Guitar, 6 strings, standard tuning",
+ "Piano",
+ "Mandolin, 4 strings, standard tuning",
+ "Ukulele, 4 strings, standard tuning"
+};
+
static const char *text_types[] = {
"chord", "annotation", "chorus",
"footer", "grid", "tab", "toc", "toc_title", "text",
@@ -218,12 +225,18 @@ config_instrument_parse(const char *str)
return -1;
}
-static const char *
+const char *
config_instrument_to_config_string(enum Instrument ins)
{
return instruments[ins];
}
+const char *
+config_instrument_description(enum Instrument ins)
+{
+ return instrument_descriptions[ins];
+}
+
static struct Note *
config_note_new(void)
{
diff --git a/src/config.h b/src/config.h
@@ -13,4 +13,7 @@ struct Config *config_load(const char *filepath);
void config_free(struct Config *config);
void config_print_default(void);
+const char *config_instrument_to_config_string(enum Instrument ins);
+const char *config_instrument_description(enum Instrument ins);
+
#endif /* _CONFIG_H_ */