commit 11ebd41a6c1db534165bf5eb2b22c87ea2c93f9e
parent 4953aaa9d1ffafa0b1abf79ee82da6c417144542
Author: nibo <nibo@relim.de>
Date: Tue, 15 Oct 2024 09:16:59 +0200
Support this syntax: {start_of_*: label="..."}
Diffstat:
| M | chordpro.c | | | 102 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
| M | todo | | | 3 | ++- |
2 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -2599,6 +2599,96 @@ END:
return directive;
}
+static char *
+cho_directive_label_parse(const char *directive_name, const char *str)
+{
+ char *label_name = NULL;
+ char c;
+ enum OptionState state = OS_NAME;
+ enum AttrValueSyntax avs = AVS_NO;
+ char name[5+1];
+ char value[URL_MAX_LEN+1];
+ int n = 0;
+ int v = 0;
+ memset(name, 0, sizeof(name));
+ memset(value, 0, sizeof(value));
+ int i;
+ for (i = 0; str[i] != 0; i++) {
+ c = str[i];
+ switch (state) {
+ case OS_NAME:
+ if (is_whitespace(c)) {
+ if (n == 0) {
+ break;
+ } else {
+ name[n] = 0;
+ cho_log(LOG_ERR, "Option with name '%s' in environment directive '%s' has no value.", name, directive_name);
+ return NULL;
+ }
+ }
+ if (c == '=') {
+ name[n] = 0;
+ if (strcmp(name, "label") != 0) {
+ cho_log(LOG_ERR, "Invalid option name '%s' in environment directive '%s'.", name, directive_name);
+ }
+ memset(name, 0, n);
+ n = 0;
+ state = OS_VALUE;
+ break;
+ }
+ if (n > 4) {
+ cho_log(LOG_ERR, "Option name in environment directive '%s' is too long.", directive_name);
+ return NULL;
+ }
+ name[n] = c;
+ n++;
+ break;
+ case OS_VALUE:
+ if (avs == AVS_NO) {
+ if (is_whitespace(c)) {
+ cho_log(LOG_ERR, "Whitespace character after equals sign in environment directive '%s' is invalid.", directive_name);
+ return NULL;
+ }
+ if (c == '\'') {
+ avs = AVS_APOSTROPHE;
+ } else if (c == '"') {
+ avs = AVS_QUOTATION_MARK;
+ } else {
+ avs = AVS_UNQUOTED;
+ value[v] = c;
+ v++;
+ }
+ break;
+ }
+ if (c == '\n') {
+ cho_log(LOG_ERR, "Newline character inside an option value in environment directive '%s' is invalid.", directive_name);
+ return NULL;
+ }
+ if (
+ (avs == AVS_APOSTROPHE && c == '\'') ||
+ (avs == AVS_QUOTATION_MARK && c == '"') ||
+ (avs == AVS_UNQUOTED && (c == ' ' || c == '\t'))
+ ) {
+ value[v] = 0;
+ label_name = strdup(value);
+ memset(value, 0, v);
+ v = 0;
+ avs = AVS_NO;
+ state = OS_NAME;
+ break;
+ }
+ value[v] = c;
+ v++;
+ break;
+ }
+ }
+ if (avs == AVS_UNQUOTED) {
+ value[v] = 0;
+ label_name = strdup(value);
+ }
+ return label_name;
+}
+
struct ChoSong **
cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
{
@@ -3009,7 +3099,17 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
songs[so]->sections[se] = cho_section_new();
songs[so]->sections[se]->type = directive->stype;
songs[so]->sections[se]->label = malloc(sizeof(struct ChoLabel));
- songs[so]->sections[se]->label->name = str_remove_leading_whitespace(directive_value);
+ if (strstr(directive_value, "=")) {
+ label = cho_directive_label_parse(directive_name, directive_value);
+ if (!label) {
+ LOG_DEBUG("cho_directive_label_parse failed.");
+ cho_log(LOG_ERR, "Failed to parse the section label. You have to ways of specifying a label:\n\t\t\t1. {start_of_*: label=\"Label name\"}\n\t\t\t2. {start_of*: Label name}");
+ return NULL;
+ }
+ songs[so]->sections[se]->label->name = label;
+ } else {
+ songs[so]->sections[se]->label->name = str_remove_leading_whitespace(directive_value);
+ }
songs[so]->sections[se]->label->style = cho_style_new_from_config(SF_LABEL);
li = 0;
songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
diff --git a/todo b/todo
@@ -1,16 +1,17 @@
+# parser
'image' directive
https://chordpro.org/chordpro/directives-image/
metadata directives
%{blabla} in lyrics, chords and annotations
conditional metadata directives
don't forget key, key_actual, key_from
+grid
chords
define chords
chord diagrams
strict and relaxed parsing makes no difference!?
make parser bulletproof
try to detect invalid input as much as possible
-parse environment directive value when: label="Verse 1"
# pdf output
break lines when too long