commit 98628363cde64aef5ce5c14b4a3f92cdf0a5ccc5
parent b9bdabaf1aeb7a59dcabfc617b8db5b42e1cdb79
Author: nibo <nibo@relim.de>
Date: Sat, 8 Feb 2025 17:35:23 +0100
Add copy option in 'define' directive
Diffstat:
6 files changed, 199 insertions(+), 89 deletions(-)
diff --git a/chord_diagram.c b/chord_diagram.c
@@ -320,22 +320,6 @@ string_diagram_free(struct StringDiagram *d)
free(d);
}
-/* static struct StringDiagram *
-string_diagram_copy(struct StringDiagram *diagram)
-{
- struct StringDiagram *copy = emalloc(sizeof(struct StringDiagram));
- copy->name = strdup(diagram->name);
- copy->base_fret = diagram->base_fret;
- int i;
- for (i = 0; i<12; i++) {
- copy->frets[i] = diagram->frets[i];
- }
- for (i = 0; i<12; i++) {
- copy->fingers[i] = diagram->fingers[i];
- }
- return copy;
-} */
-
static struct StringDiagram *
string_diagram_copy_all_but_name(struct StringDiagram *diagram)
{
@@ -522,6 +506,14 @@ keyboard_diagram_new(void)
return d;
}
+static struct KeyboardDiagram *
+keyboard_diagram_copy_all_but_name(struct KeyboardDiagram *diagram)
+{
+ struct KeyboardDiagram *copy = keyboard_diagram_new();
+ memcpy(copy->keys, diagram->keys, 24);
+ return copy;
+}
+
static void
keyboard_diagram_free(struct KeyboardDiagram *d)
{
@@ -529,18 +521,6 @@ keyboard_diagram_free(struct KeyboardDiagram *d)
free(d);
}
-/* static struct KeyboardDiagram *
-keyboard_diagram_copy(struct KeyboardDiagram *diagram)
-{
- struct KeyboardDiagram *copy = emalloc(sizeof(struct KeyboardDiagram));
- copy->name = strdup(diagram->name);
- int i;
- for (i = 0; i<24; i++) {
- copy->keys[i] = diagram->keys[i];
- }
- return copy;
-} */
-
struct ChordDiagram *
chord_diagram_new()
{
@@ -562,19 +542,74 @@ chord_diagram_free(struct ChordDiagram *d)
free(d);
}
-/* static struct ChordDiagram *
-chord_diagram_copy(struct ChordDiagram *diagram)
+static struct ChordDiagram *
+chord_diagram_copy_all_but_name(struct ChordDiagram *diagram)
{
struct ChordDiagram *copy = emalloc(sizeof(struct ChordDiagram));
+ copy->show = diagram->show;
+ copy->color = cho_color_copy(diagram->color);
+ copy->is_string_instrument = diagram->is_string_instrument;
if (diagram->is_string_instrument) {
- copy->is_string_instrument = true;
- copy->u.sd = string_diagram_copy(diagram->u.sd);
+ copy->u.sd = string_diagram_copy_all_but_name(diagram->u.sd);
} else {
- copy->is_string_instrument = false;
- copy->u.kd = keyboard_diagram_copy(diagram->u.kd);
+ copy->u.kd = keyboard_diagram_copy_all_but_name(diagram->u.kd);
}
return copy;
-} */
+}
+
+enum ChordDiagramContent
+chord_diagram_duplicate(
+ struct ChordDiagram *diagram,
+ struct ChordDiagram **custom_diagrams,
+ int custom_diagrams_len,
+ const char *name,
+ const char *chord_to_copy,
+ enum Instrument instrument
+)
+{
+ int d;
+ for (d = custom_diagrams_len-1; d >= 0; d--) {
+ if (custom_diagrams[d]->is_string_instrument) {
+ if (!strcmp(custom_diagrams[d]->u.sd->name, chord_to_copy)) {
+ diagram->is_string_instrument = true;
+ diagram->u.sd = string_diagram_copy_all_but_name(custom_diagrams[d]->u.sd);
+ diagram->u.sd->name = strdup(name);
+ return CDC_STRING;
+ }
+ } else {
+ if (!strcmp(custom_diagrams[d]->u.kd->name, chord_to_copy)) {
+ diagram->is_string_instrument = false;
+ diagram->u.kd = keyboard_diagram_copy_all_but_name(custom_diagrams[d]->u.kd);
+ diagram->u.kd->name = strdup(name);
+ return CDC_KEYBOARD;
+ }
+ }
+ }
+ switch (instrument) {
+ case INS_GUITAR: {
+ size_t i;
+ for (i = 0; i<LENGTH(guitar_diagrams); i++) {
+ if (!strcmp(guitar_diagrams[i].name, chord_to_copy)) {
+ diagram->is_string_instrument = true;
+ diagram->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]);
+ diagram->u.sd->name = strdup(name);
+ return CDC_STRING;
+ }
+ }
+ break;
+ }
+ case INS_KEYBOARD: {
+ break;
+ }
+ case INS_MANDOLIN: {
+ break;
+ }
+ case INS_UKULELE: {
+ break;
+ }
+ }
+ return -1;
+}
void
chord_diagrams_free(struct ChordDiagram **diagrams)
@@ -650,11 +685,9 @@ chord_diagrams_create(
!strcmp((*c)->name, (*cd)->u.sd->name)
) {
diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *));
- // diagrams[d] = chord_diagram_copy(*cd);
- diagrams[d] = emalloc(sizeof(struct ChordDiagram));
- diagrams[d]->is_string_instrument = true;
- diagrams[d]->u.sd = string_diagram_copy_all_but_name((*cd)->u.sd);
+ diagrams[d] = chord_diagram_copy_all_but_name(*cd);
diagrams[d]->u.sd->name = cho_chord_name_generate(*c);
+ printf("custom: name '%s'\n", diagrams[d]->u.sd->name);
d++;
goto NEXT_CHORD;
}
@@ -662,10 +695,11 @@ chord_diagrams_create(
for (i = 0; i<LENGTH(guitar_diagrams); i++) {
if (!strcmp((*c)->name, guitar_diagrams[i].name)) {
diagrams = erealloc(diagrams, (d+1) * sizeof(struct ChordDiagram *));
- diagrams[d] = emalloc(sizeof(struct ChordDiagram));
+ diagrams[d] = chord_diagram_new();
diagrams[d]->is_string_instrument = true;
diagrams[d]->u.sd = string_diagram_copy_all_but_name(&guitar_diagrams[i]);
diagrams[d]->u.sd->name = cho_chord_name_generate(*c);
+ printf("predefined: name '%s'\n", diagrams[d]->u.sd->name);
d++;
}
}
diff --git a/chord_diagram.h b/chord_diagram.h
@@ -15,6 +15,7 @@ enum Direction {
struct ChordDiagram *chord_diagram_new();
void chord_diagram_free(struct ChordDiagram *d);
bool chord_diagram_draw(pdfio_stream_t *stream, struct ChordDiagram *diagram, double x, double y, double width);
+enum ChordDiagramContent chord_diagram_duplicate(struct ChordDiagram *diagram, struct ChordDiagram **custom_diagrams, int custom_diagrams_len, const char *name, const char *chord_to_copy, enum Instrument instrument);
struct StringDiagram *string_diagram_new(void);
struct KeyboardDiagram *keyboard_diagram_new(void);
diff --git a/chordpro.c b/chordpro.c
@@ -19,6 +19,7 @@ static const char *font_styles[] = { "normal", "oblique", "italic" };
static const char *font_weights[] = { "normal", "bold" };
static const char *line_styles[] = { "single", "double", "none" };
static const char *chord_qualifiers[] = { "m", "", "+", "°" };
+static const char *instruments[] = { "guitar", "keyboard", "mandolin", "ukulele" };
static const char *state_enums[] = {
"STATE_LYRICS",
@@ -2765,7 +2766,11 @@ finger_to_int(char c)
}
static struct ChordDiagram *
-cho_chord_diagram_parse(const char *str)
+cho_chord_diagram_parse(
+ const char *str,
+ struct ChordDiagram **custom_diagrams,
+ int custom_diagrams_len
+)
{
struct ChordDiagram *diagram = chord_diagram_new();
enum ChordDiagramState state = CDS_NAME;
@@ -2777,11 +2782,8 @@ cho_chord_diagram_parse(const char *str)
char key[3];
char base_fret[3];
char diagram_value[7+1];
- int n = 0;
- int o = 0;
- int k = 0;
- int b = 0;
- int d = 0;
+ char chord_to_copy[20];
+ int i = 0;
int f = 0;
int fret_count = 0;
int finger_count = 0;
@@ -2793,27 +2795,28 @@ cho_chord_diagram_parse(const char *str)
switch (state) {
case CDS_NAME: {
if (is_whitespace(*c)) {
- if (n == 0) {
+ if (i == 0) {
break;
}
- name[n] = 0;
+ name[i] = 0;
+ i = 0;
state = CDS_OPTION_NAME;
break;
}
- if (n > 18) {
+ if (i > 18) {
cho_log(LOG_ERR, "Chord name in chord diagram is too long.");
return NULL;
}
- name[n] = *c;
- n++;
+ name[i] = *c;
+ i++;
break;
}
case CDS_OPTION_NAME: {
if (is_whitespace(*c)) {
- if (o == 0) {
+ if (i == 0) {
break;
}
- option[o] = 0;
+ option[i] = 0;
future_content = -1;
if (!strcmp(option, "base-fret")) {
state = CDS_BASE_FRET;
@@ -2833,12 +2836,15 @@ cho_chord_diagram_parse(const char *str)
} else
if (!strcmp(option, "diagram")) {
state = CDS_DIAGRAM;
+ } else
+ if (!strcmp(option, "copy")) {
+ state = CDS_COPY;
} else {
cho_log(LOG_ERR, "Invalid option '%s' in define directive.", option);
return NULL;
}
- memset(option, 0, o);
- o = 0;
+ memset(option, 0, i);
+ i = 0;
if (current_content == -1 && future_content != -1) {
current_content = future_content;
switch (future_content) {
@@ -2858,20 +2864,21 @@ cho_chord_diagram_parse(const char *str)
}
break;
}
- if (o > 8) {
+ if (i > 8) {
cho_log(LOG_ERR, "Option in chord diagram is too long.");
return NULL;
}
- option[o] = *c;
- o++;
+ option[i] = *c;
+ i++;
break;
}
case CDS_BASE_FRET: {
if (is_whitespace(*c)) {
- if (b == 0) {
+ if (i == 0) {
break;
}
- base_fret[b] = 0;
+ base_fret[i] = 0;
+ i = 0;
l = str_to_number(base_fret);
if (l == -1) {
LOG_DEBUG("str_to_number failed.");
@@ -2882,17 +2889,19 @@ cho_chord_diagram_parse(const char *str)
cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c);
return NULL;
}
+ printf("base-fret %d\n", (int8_t)l);
diagram->u.sd->base_fret = (int8_t)l;
state = CDS_OPTION_NAME;
break;
}
- if (b > 1) {
+ if (i > 1) {
cho_log(LOG_ERR, "base-fret value is too long.");
printf("c: %c\n", *c);
return NULL;
}
- base_fret[b] = *c;
- b++;
+ printf("parsing base-fret '%c'\n", *c);
+ base_fret[i] = *c;
+ i++;
break;
}
case CDS_FRETS: {
@@ -2965,11 +2974,11 @@ cho_chord_diagram_parse(const char *str)
}
case CDS_KEYS: {
if (is_whitespace(*c)) {
- if (k == 0) {
+ if (i == 0) {
break;
}
- key[k] = 0;
- k = 0;
+ key[i] = 0;
+ i = 0;
l = str_to_number(key);
if (l == -1) {
LOG_DEBUG("str_to_number failed.");
@@ -2989,22 +2998,22 @@ cho_chord_diagram_parse(const char *str)
c--;
break;
}
- if (k > 1) {
- cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", k);
+ if (i > 1) {
+ cho_log(LOG_ERR, "Too high key value in chord diagram. '%d'", i);
printf("key '%s'\n", key);
return NULL;
}
- key[k] = *c;
- k++;
+ key[i] = *c;
+ i++;
break;
}
case CDS_DIAGRAM: {
if (is_whitespace(*c)) {
- if (d == 0) {
+ if (i == 0) {
break;
}
- diagram_value[d] = 0;
- d = 0;
+ diagram_value[i] = 0;
+ i = 0;
if (!strcmp(diagram_value, "off")) {
diagram->show = false;
} else
@@ -3021,15 +3030,58 @@ cho_chord_diagram_parse(const char *str)
state = CDS_OPTION_NAME;
break;
}
- diagram_value[d] = *c;
- d++;
+ diagram_value[i] = *c;
+ i++;
+ break;
+ }
+ case CDS_COPY: {
+ if (is_whitespace(*c)) {
+ if (i == 0) {
+ break;
+ }
+ chord_to_copy[i] = 0;
+ if (current_content != -1) {
+ cho_log(LOG_ERR, "The define options 'base-fret', 'frets', 'fingers' and 'keys' are not allowed before the 'copy' option.");
+ return NULL;
+ }
+ enum Instrument ins = g_config->output->diagram->instrument;
+ current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins);
+ if (current_content == -1) {
+ cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s'"
+ "because no previous definition was found and also"
+ "no predefined chord diagram for the instrument '%s'"
+ "was found.", chord_to_copy, instruments[ins]);
+ return NULL;
+ }
+ i = 0;
+ state = CDS_OPTION_NAME;
+ break;
+ }
+ chord_to_copy[i] = *c;
+ i++;
break;
}
}
}
switch (state) {
+ case CDS_BASE_FRET: {
+ base_fret[i] = 0;
+ i = 0;
+ l = str_to_number(base_fret);
+ if (l == -1) {
+ LOG_DEBUG("str_to_number failed.");
+ cho_log(LOG_ERR, "Invalid base-fret value '%s' in chord diagram.", base_fret);
+ return NULL;
+ }
+ if (l == 0) {
+ cho_log(LOG_ERR, "Invalid base-fret value '%c' in chord diagram.", *c);
+ return NULL;
+ }
+ diagram->u.sd->base_fret = (int8_t)l;
+ break;
+ }
case CDS_KEYS: {
- key[k] = 0;
+ key[i] = 0;
if (strlen(key) > 0) {
l = str_to_number(key);
if (l == -1) {
@@ -3046,7 +3098,7 @@ cho_chord_diagram_parse(const char *str)
break;
}
case CDS_DIAGRAM: {
- diagram_value[d] = 0;
+ diagram_value[i] = 0;
if (!strcmp(diagram_value, "off")) {
diagram->show = false;
} else
@@ -3062,8 +3114,27 @@ cho_chord_diagram_parse(const char *str)
}
}
break;
- default:
}
+ case CDS_COPY: {
+ chord_to_copy[i] = 0;
+ if (current_content != -1) {
+ cho_log(LOG_ERR, "The define options 'base-fret', 'frets',"
+ "'fingers' and 'keys' are not allowed before the 'copy'"
+ "option.");
+ return NULL;
+ }
+ enum Instrument ins = g_config->output->diagram->instrument;
+ current_content = chord_diagram_duplicate(diagram, custom_diagrams, custom_diagrams_len, name, chord_to_copy, ins);
+ if (current_content == -1) {
+ cho_log(LOG_ERR, "Can't copy the diagram for the chord '%s' because"
+ "no previous definition was found and also no predefined"
+ "chord diagram for the instrument '%s' was found.",
+ chord_to_copy, instruments[ins]);
+ return NULL;
+ }
+ break;
+ }
+ default:
}
if (
current_content == CDC_STRING &&
@@ -4648,7 +4719,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
th++;
break;
case DEFINE:
- diagram = cho_chord_diagram_parse(directive_value);
+ diagram = cho_chord_diagram_parse(directive_value, songs[so]->diagrams, dia);
if (!diagram) {
LOG_DEBUG("cho_chord_diagram_parse failed.");
return NULL;
diff --git a/chordpro.h b/chordpro.h
@@ -19,11 +19,6 @@ enum AttrValueSyntax : int8_t {
AVS_UNQUOTED
};
-enum ChordDiagramContent : int8_t {
- CDC_STRING,
- CDC_KEYBOARD
-};
-
enum ChordDiagramState {
CDS_NAME,
CDS_OPTION_NAME,
@@ -31,7 +26,8 @@ enum ChordDiagramState {
CDS_FRETS,
CDS_FINGERS,
CDS_KEYS,
- CDS_DIAGRAM
+ CDS_DIAGRAM,
+ CDS_COPY
};
enum ChordDirective {
diff --git a/out_pdf.c b/out_pdf.c
@@ -2709,11 +2709,14 @@ pdf_content_render(struct PDFContent *content, pdfio_file_t *file)
struct ChordDiagram **d;
/* TODO: Handle line break when too long */
for (d = pages[p]->diagrams; *d; d++) {
- if (!chord_diagram_draw(stream, *d, x, y, size)) {
- LOG_DEBUG("chord_diagram_draw failed.");
- return false;
+ debug_chord_diagram_print(*d);
+ if ((*d)->show) {
+ if (!chord_diagram_draw(stream, *d, x, y, size)) {
+ LOG_DEBUG("chord_diagram_draw failed.");
+ return false;
+ }
+ x += size + padding;
}
- x += size + padding;
}
}
if (!pdfioStreamClose(stream)) {
diff --git a/types.h b/types.h
@@ -42,6 +42,11 @@ enum BreakType : int8_t {
BT_COLUMN
};
+enum ChordDiagramContent : int8_t {
+ CDC_STRING,
+ CDC_KEYBOARD
+};
+
enum ChordQualifier {
CQ_MIN,
CQ_MAJ,