commit 32c9c5f9317b037451c7690140ce8829243203d4
parent 52067be37cffb0b14ca8553f0eafad81ebad1676
Author: nibo <nibo@relim.de>
Date: Sat, 1 Jun 2024 22:07:45 +0200
Make progress
Diffstat:
| M | chordpro.c | | | 419 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------- |
| M | chordpro.h | | | 93 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
| M | lorid.c | | | 2 | ++ |
3 files changed, 462 insertions(+), 52 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -1,19 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include "chordpro.h"
-static char *string_remove_leading_whitespace(const char *str)
-{
- int i = 0;
- while (str[i] == ' ' || str[i] == '\t') {
- i++;
- }
- return strdup(&str[i]);
-}
-
-
static const char *environment_directives[] = {
"start_of_chorus", "soc", "end_of_chorus", "eoc", "chorus",
"start_of_verse", "sov", "end_of_verse", "eov",
@@ -50,11 +41,23 @@ static const char *the_state(enum State state)
return "STATE_DIRECTIVE_VALUE";
case STATE_CHORD:
return "STATE_CHORD";
+ case STATE_MARKUP_TAG_BEGIN:
+ return "STATE_MARKUP_TAG_BEGIN";
+ case STATE_MARKUP_TAG_END:
+ return "STATE_MARKUP_TAG_END";
+ case STATE_MARKUP_TAG_INSIDE:
+ return "STATE_MARKUP_TAG_INSIDE";
+ case STATE_MARKUP_TAG:
+ return "STATE_MARKUP_TAG";
+ case STATE_MARKUP_ATTR_NAME:
+ return "STATE_MARKUP_ATTR_NAME";
+ case STATE_MARKUP_ATTR_VALUE:
+ return "STATE_MARKUP_ATTR_VALUE";
}
return "";
}
-static const char *dtype(enum DirectiveType dtype)
+const char *the_dtype(enum DirectiveType dtype)
{
switch (dtype) {
case DT_ENVIRONMENT:
@@ -92,7 +95,7 @@ const char *the_stype(enum SectionType stype)
return "";
}
-static const char *pos(enum Position pos)
+const char *the_pos(enum Position pos)
{
switch (pos) {
case POS_NOTHING:
@@ -105,7 +108,29 @@ static const char *pos(enum Position pos)
return "";
}
-const char *the_style(enum LineStyle style)
+static char *string_remove_leading_whitespace(const char *str)
+{
+ int i = 0;
+ while (str[i] == ' ' || str[i] == '\t') {
+ i++;
+ }
+ return strdup(&str[i]);
+}
+
+static inline bool is_whitespace(char c)
+{
+ if (
+ c == '\t' ||
+ c == '\n' ||
+ c == '\f' ||
+ c == '\r' ||
+ c == ' '
+ )
+ return true;
+ return false;
+}
+
+/* const char *the_style(enum LineStyle style)
{
switch (style) {
case LS_NORMAL:
@@ -118,6 +143,131 @@ const char *the_style(enum LineStyle style)
return "LS_BOX";
}
return "";
+} */
+
+struct RGBColor *cho_rgbcolor_new(uint8_t red, uint8_t green, uint8_t blue)
+{
+ struct RGBColor *color = malloc(sizeof(struct RGBColor));
+ color->red = red;
+ color->green = green;
+ color->blue = blue;
+ return color;
+}
+
+struct RGBColor *cho_rgbcolor_duplicate(struct RGBColor *color)
+{
+ struct RGBColor *copy = malloc(sizeof(struct RGBColor));
+ copy->red = color->red;
+ copy->green = color->green;
+ copy->blue = color->blue;
+ return copy;
+}
+
+struct Style *cho_style_new(void)
+{
+ struct Style *style = malloc(sizeof(struct Style));
+ style->font = NULL;
+ style->font_family = FF_NORMAL;
+ style->font_size = DEFAULT_FONT_SIZE;
+ style->font_style = FS_NORMAL;
+ style->font_weight = FW_NORMAL;
+ style->foreground_color = cho_rgbcolor_new(20, 20, 20);
+ style->background_color = cho_rgbcolor_new(255, 255, 255);
+ style->underline_style = LS_NONE;
+ style->underline_color = cho_rgbcolor_new(20, 20, 20);
+ style->overline_style = LS_NONE;
+ style->overline_color = cho_rgbcolor_new(20, 20, 20);
+ style->strikethrough = false;
+ style->strikethrough_color = cho_rgbcolor_new(20, 20, 20);
+ style->boxed = false;
+ style->boxed_color = cho_rgbcolor_new(20, 20, 20);
+ style->rise = 0.0;
+ style->href = NULL;
+ return style;
+}
+
+void cho_style_free(struct Style *style)
+{
+ free(style->font);
+ free(style->foreground_color);
+ free(style->background_color);
+ free(style->underline_color);
+ free(style->overline_color);
+ free(style->strikethrough_color);
+ free(style->boxed_color);
+ free(style->href);
+ free(style);
+}
+
+struct Style *cho_style_duplicate(struct Style *style)
+{
+ struct Style *copy = malloc(sizeof(struct Style));
+ copy->font = style->font;
+ copy->font_family = style->font_family;
+ copy->font_size = style->font_size;
+ copy->font_style = style->font_style;
+ copy->font_weight = style->font_weight;
+ copy->foreground_color = cho_rgbcolor_duplicate(style->foreground_color);
+ copy->background_color = cho_rgbcolor_duplicate(style->background_color);
+ copy->underline_style = style->underline_style;
+ copy->underline_color = cho_rgbcolor_duplicate(style->underline_color);
+ copy->overline_style = style->overline_style;
+ copy->overline_color = cho_rgbcolor_duplicate(style->overline_color);
+ copy->strikethrough = style->strikethrough;
+ copy->strikethrough_color = cho_rgbcolor_duplicate(style->strikethrough_color);
+ copy->boxed = style->boxed;
+ copy->boxed_color = cho_rgbcolor_duplicate(style->boxed_color);
+ copy->rise = style->rise;
+ copy->href = style->href;
+ return copy;
+}
+
+struct Style *cho_style_get(const char *tag_name, void *attrs)// struct Attr **attrs)
+{
+ struct Style *style = cho_style_new();
+ if (strcmp(tag_name, "span") == 0) {
+ // check the attrs
+ } else if (strcmp(tag_name, "b") == 0) {
+ style->font_weight = FW_BOLD;
+ } else if (strcmp(tag_name, "big") == 0) {
+ style->font_size *= 0.8;
+ } else if (strcmp(tag_name, "i") == 0) {
+ style->font_style = FS_ITALIC;
+ } else if (strcmp(tag_name, "s") == 0) {
+ style->strikethrough = true;
+ } else if (strcmp(tag_name, "sub") == 0) {
+ style->font_size *= 0.8;
+ style->rise = (style->font_size / 2) * 0.3;
+ } else if (strcmp(tag_name, "sup") == 0) {
+ style->font_size *= 0.8;
+ float thirty_percent = (style->font_size / 2) * 0.3;
+ style->rise = thirty_percent - thirty_percent * 2;
+ } else if (strcmp(tag_name, "small") == 0) {
+ style->font_size *= 0.8;
+ } else if (strcmp(tag_name, "tt") == 0) {
+ style->font_family = FF_MONOSPACE;
+ } else if (strcmp(tag_name, "u") == 0) {
+ style->underline_style = LS_SINGLE;
+ } else {
+ cho_style_free(style);
+ return NULL;
+ }
+ return style;
+}
+
+struct Tag *cho_tag_new(void)
+{
+ struct Tag *tag = malloc(sizeof(struct Tag));
+ tag->name = NULL;
+ tag->style = NULL;
+ tag->is_closed = false;
+ return tag;
+}
+
+void cho_directive_free(struct ChoDirective *directive)
+{
+ cho_style_free(directive->style);
+ free(directive);
}
struct ChoMetadata *cho_metadata_new(void)
@@ -179,12 +329,19 @@ struct ChoChord *cho_chord_new(void)
struct ChoLine *cho_line_new(void)
{
struct ChoLine *line = malloc(sizeof(struct ChoLine));
- line->style = LS_NORMAL;
line->chords = NULL;
line->lyrics = NULL;
return line;
}
+struct ChoLineItem *cho_line_item_new(void)
+{
+ struct ChoLineItem *item = malloc(sizeof(struct ChoLineItem));
+ item->style = cho_style_new();
+ item->text = NULL;
+ return item;
+}
+
struct ChoSection *cho_section_new(void)
{
struct ChoSection *section = malloc(sizeof(struct ChoSection));
@@ -207,6 +364,7 @@ void cho_song_free(struct ChoSong *song)
int i = 0;
int k = 0;
int c = 0;
+ int ly = 0;
while (song->metadata[i] != NULL) {
free(song->metadata[i]->name);
free(song->metadata[i]->value);
@@ -218,14 +376,21 @@ void cho_song_free(struct ChoSong *song)
while (song->sections[i] != NULL) {
free(song->sections[i]->name);
while (song->sections[i]->lines[k] != NULL) {
- free(song->sections[i]->lines[k]->lyrics);
+ while (song->sections[i]->lines[k]->lyrics[ly] != NULL) {
+ cho_style_free(song->sections[i]->lines[k]->lyrics[ly]->style);
+ free(song->sections[i]->lines[k]->lyrics[ly]->text);
+ free(song->sections[i]->lines[k]->lyrics[ly]);
+ ly++;
+ }
while (song->sections[i]->lines[k]->chords[c] != NULL) {
free(song->sections[i]->lines[k]->chords[c]->chord);
free(song->sections[i]->lines[k]->chords[c]);
c++;
}
+ free(song->sections[i]->lines[k]->lyrics);
free(song->sections[i]->lines[k]->chords);
free(song->sections[i]->lines[k]);
+ ly = 0;
c = 0;
k++;
}
@@ -251,7 +416,7 @@ void cho_songs_free(struct ChoSong **songs)
struct ChoDirective *directive_parse(const char *name)
{
struct ChoDirective *directive = malloc(sizeof(struct ChoDirective));
- directive->style = LS_NORMAL;
+ directive->style = cho_style_new();
int i = 0;
if (
strcmp(name, environment_directives[0]) == 0 ||
@@ -349,7 +514,8 @@ struct ChoDirective *directive_parse(const char *name)
strcmp(formatting_directives[1], name) == 0 ||
strcmp(formatting_directives[2], name) == 0
) {
- directive->style = LS_GREY_BACKGROUND;
+ // directive->style = LS_GREY_BACKGROUND;
+ directive->style->background_color = cho_rgbcolor_new(228, 228, 228);
directive->dtype = DT_FORMATTING;
directive->stype = ST_NOTHING;
directive->position = POS_NOTHING;
@@ -358,7 +524,8 @@ struct ChoDirective *directive_parse(const char *name)
strcmp(formatting_directives[3], name) == 0 ||
strcmp(formatting_directives[4], name) == 0
) {
- directive->style = LS_ITALIC;
+ // directive->style = LS_ITALIC;
+ directive->style->font_style = FS_ITALIC;
directive->dtype = DT_FORMATTING;
directive->stype = ST_NOTHING;
directive->position = POS_NOTHING;
@@ -367,7 +534,7 @@ struct ChoDirective *directive_parse(const char *name)
strcmp(formatting_directives[5], name) == 0 ||
strcmp(formatting_directives[4], name) == 0
) {
- directive->style = LS_BOX;
+ directive->style->boxed = true;
directive->dtype = DT_FORMATTING;
directive->stype = ST_NOTHING;
directive->position = POS_NOTHING;
@@ -391,33 +558,49 @@ END:
struct ChoSong **cho_parse(FILE *fp)
{
- struct ChoSong **songs = malloc(sizeof(struct ChoSong *));
- int so = 0;
- songs[so] = cho_song_new();
- int se = 0;
- songs[so]->sections = malloc((se+1) * sizeof(struct ChoSection *));
- songs[so]->sections[se] = cho_section_new();
- int li = 0;
- songs[so]->sections[se]->lines = realloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *));
- songs[so]->sections[se]->lines[li] = cho_line_new();
+ char buf;
+ char directive_name[16];
+ char directive_value[512];
+ char chord[15];
+ char tag_begin[6];
+ char tag_end[6];
+ char attr_name[21];
+ char attr_value[URL_MAX_LEN+1];
+ enum State state = STATE_LYRICS;
+ enum State return_to_state;
int dn = 0;
int dv = 0;
int ch = 0;
int c = 0;
int m = 0;
int ly = 0;
- char buf;
+ int t = 0;
+ int an = 0;
+ int av = 0;
+ int so = 0;
+ int se = 0;
+ int li = 0;
+ int ta = 0;
+ int te = 0;
size_t read;
- char directive_name[16];
- char directive_value[512];
- char chord[15];
- enum State state = STATE_LYRICS;
struct ChoDirective *directive = NULL;
struct ChoMetadata *metadata = NULL;
+ struct ChoSong **songs = malloc(sizeof(struct ChoSong *));
+ songs[so] = cho_song_new();
+ songs[so]->sections = malloc((se+1) * sizeof(struct ChoSection *));
+ songs[so]->sections[se] = cho_section_new();
+ songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
+ songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = malloc(sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
+ struct Tag **tags = malloc(sizeof(struct Tag *));
+ tags[ta] = NULL;
+ ta++;
while (feof(fp) == 0) {
read = fread(&buf, 1, 1, fp);
if (read == 1) {
- // printf("state: %s, buf: %c\n", the_state(state), buf);
+ printf("state: %s, buf: %c\n", the_state(state), buf);
switch (state) {
case STATE_LYRICS:
if (buf == '{') {
@@ -428,9 +611,20 @@ struct ChoSong **cho_parse(FILE *fp)
state = STATE_CHORD;
break;
}
+ if (buf == '<') {
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text = realloc(songs[so]->sections[se]->lines[li]->lyrics[ly]->text, (te+1) * sizeof(char));
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text[te] = 0;
+ ly++;
+ return_to_state = STATE_LYRICS;
+ state = STATE_MARKUP_TAG_BEGIN;
+ break;
+ }
if (buf == '\n') {
- songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(char));
- songs[so]->sections[se]->lines[li]->lyrics[ly] = 0;
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text = realloc(songs[so]->sections[se]->lines[li]->lyrics[ly]->text, (te+1) * sizeof(char));
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text[te] = 0;
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = NULL;
ly = 0;
songs[so]->sections[se]->lines[li]->chords = realloc(songs[so]->sections[se]->lines[li]->chords, (c+1) * sizeof(struct ChoChord *));
songs[so]->sections[se]->lines[li]->chords[c] = NULL;
@@ -438,11 +632,14 @@ struct ChoSong **cho_parse(FILE *fp)
li++;
songs[so]->sections[se]->lines = realloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
break;
}
- songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(char));
- songs[so]->sections[se]->lines[li]->lyrics[ly] = buf;
- ly++;
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text = realloc(songs[so]->sections[se]->lines[li]->lyrics[ly]->text, (te+1) * sizeof(char));
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text[te] = buf;
+ te++;
break;
case STATE_DIRECTIVE_NAME:
if (buf == '}') {
@@ -457,6 +654,10 @@ struct ChoSong **cho_parse(FILE *fp)
case DT_ENVIRONMENT:
switch (directive->position) {
case POS_BEGIN:
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = NULL;
+ ly = 0;
free(songs[so]->sections[se]->lines[li]);
songs[so]->sections[se]->lines[li] = NULL;
se++;
@@ -466,9 +667,16 @@ struct ChoSong **cho_parse(FILE *fp)
li = 0;
songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = malloc(sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
break;
case POS_END:
if (directive->stype == songs[so]->sections[se]->type) {
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = NULL;
+ ly = 0;
free(songs[so]->sections[se]->lines[li]);
songs[so]->sections[se]->lines[li] = NULL;
se++;
@@ -477,6 +685,9 @@ struct ChoSong **cho_parse(FILE *fp)
li = 0;
songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = malloc(sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
}
break;
}
@@ -493,11 +704,29 @@ struct ChoSong **cho_parse(FILE *fp)
fprintf(stderr, "INFO: Formatting directive '%s' has no value.\n", directive_name);
break;
case DT_PREAMBLE:
+ // Only preamble directive is 'new_song'
+ free(songs[so]->sections[se]->lines[li]);
+ songs[so]->sections[se]->lines[li] = NULL;
+ songs[so]->metadata = realloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
+ songs[so]->metadata[m] = NULL;
+ se++;
+ songs[so]->sections = realloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
+ songs[so]->sections[se] = NULL;
+ so++;
+ songs = realloc(songs, (so+1) * sizeof(struct ChoSong *));
+ songs[so] = cho_song_new();
+ se = 0;
+ li = 0;
+ m = 0;
+ songs[so]->sections = malloc((se+1) * sizeof(struct ChoSection *));
+ songs[so]->sections[se] = cho_section_new();
+ songs[so]->sections[se]->lines = realloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *));
+ songs[so]->sections[se]->lines[li] = cho_line_new();
break;
case DT_CUSTOM:
break;
}
- free(directive);
+ cho_directive_free(directive);
directive = NULL;
state = STATE_LYRICS;
break;
@@ -524,6 +753,10 @@ struct ChoSong **cho_parse(FILE *fp)
case DT_ENVIRONMENT:
switch (directive->position) {
case POS_BEGIN:
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = NULL;
+ ly = 0;
free(songs[so]->sections[se]->lines[li]);
songs[so]->sections[se]->lines[li] = NULL;
se++;
@@ -534,9 +767,16 @@ struct ChoSong **cho_parse(FILE *fp)
li = 0;
songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = malloc(sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
break;
case POS_END:
if (directive->stype == songs[so]->sections[se]->type) {
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = NULL;
+ ly = 0;
free(songs[so]->sections[se]->lines[li]);
songs[so]->sections[se]->lines[li] = NULL;
se++;
@@ -545,6 +785,9 @@ struct ChoSong **cho_parse(FILE *fp)
li = 0;
songs[so]->sections[se]->lines = malloc(sizeof(struct ChoLine *));
songs[so]->sections[se]->lines[li] = cho_line_new();
+ songs[so]->sections[se]->lines[li]->lyrics = malloc(sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_new();
}
break;
}
@@ -566,17 +809,24 @@ struct ChoSong **cho_parse(FILE *fp)
}
break;
case DT_FORMATTING:
- songs[so]->sections[se]->lines[li]->style = directive->style;
- songs[so]->sections[se]->lines[li]->lyrics = string_remove_leading_whitespace(directive_value);
- ly = strlen(songs[so]->sections[se]->lines[li]->lyrics);
+ // songs[so]->sections[se]->lines[li]->style = directive->style;
+ // songs[so]->sections[se]->lines[li]->lyrics = string_remove_leading_whitespace(directive_value);
+ // ly = strlen(songs[so]->sections[se]->lines[li]->lyrics);
+ ly++;
+ songs[so]->sections[se]->lines[li]->lyrics = realloc(songs[so]->sections[se]->lines[li]->lyrics, (ly+1) * sizeof(struct ChoLineItem *));
+ songs[so]->sections[se]->lines[li]->lyrics[ly] = cho_line_item_new();
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->style = cho_style_duplicate(directive->style);
+ songs[so]->sections[se]->lines[li]->lyrics[ly]->text = string_remove_leading_whitespace(directive_value);
+ te = 0;
break;
case DT_PREAMBLE:
+ fprintf(stderr, "INFO: Preamble directive '%s' can't have a value.\n", directive_name);
break;
case DT_CUSTOM:
break;
}
memset(directive_value, 0, strlen(directive_value));
- free(directive);
+ cho_directive_free(directive);
directive = NULL;
state = STATE_LYRICS;
break;
@@ -600,12 +850,93 @@ struct ChoSong **cho_parse(FILE *fp)
chord[ch] = buf;
ch++;
break;
+ case STATE_MARKUP_TAG_BEGIN:
+ MARKUP_TAG_BEGIN:
+ if (buf == '>') {
+ tag_begin[t] = 0;
+ t = 0;
+ tags = realloc(tags, (ta+1) * sizeof(struct Tag *));
+ tags[ta-1] = cho_tag_new();
+ tags[ta-1]->name = strdup(tag_begin);
+ tags[ta-1]->style = cho_style_get(tag_begin, NULL);
+ tags[ta] = NULL;
+ ta++;
+ state = STATE_MARKUP_TAG_INSIDE;
+ break;
+ }
+ if (is_whitespace(buf)) {
+ tag_begin[t] = 0;
+ printf("tag_begin: %s\n", tag_begin);
+ t = 0;
+ state = STATE_MARKUP_ATTR_NAME;
+ break;
+ }
+ if (t == 5) {
+ fprintf(stderr, "ERROR: Begin tag name is too long.\n");
+ return NULL;
+ }
+ tag_begin[t] = buf;
+ t++;
+ break;
+ case STATE_MARKUP_TAG_INSIDE:
+ if (buf == '<') {
+ state = STATE_MARKUP_TAG;
+ break;
+ }
+ // append to the cho line item
+ break;
+ case STATE_MARKUP_TAG:
+ if (buf == '/') {
+ state = STATE_MARKUP_TAG_END;
+ break;
+ }
+ // If we not use 'goto' we loose the first character of the begin tag name
+ goto MARKUP_TAG_BEGIN;
+ case STATE_MARKUP_TAG_END:
+ if (buf == '>') {
+ tag_end[t] = 0;
+ t = 0;
+ printf("tag_end: %s\n", tag_end);
+ state = return_to_state;
+ break;
+ }
+ if (t == 5) {
+ fprintf(stderr, "ERROR: End tag name is too long.\n");
+ return NULL;
+ }
+ tag_end[t] = buf;
+ t++;
+ break;
+ case STATE_MARKUP_ATTR_NAME:
+ if (buf == '=') {
+ attr_name[an] = 0;
+ an = 0;
+ state = STATE_MARKUP_ATTR_VALUE;
+ break;
+ }
+ if (buf == '>' || is_whitespace(buf)) {
+ fprintf(stderr, "ERROR: Attribute name '%s' of tag '%s' has no value.\n", attr_name, tag_begin);
+ return NULL;
+ }
+ attr_name[an] = buf;
+ an++;
+ break;
+ case STATE_MARKUP_ATTR_VALUE:
+ if (buf == '>') {
+ break;
+ }
+ break;
}
} else if (ferror(fp) != 0) {
fprintf(stderr, "fread failed.\n");
return NULL;
}
}
+ int e = 0;
+ while (tags[e] != NULL) {
+ printf("name: %s\n", tags[e]->name);
+ e++;
+ }
free(songs[so]->sections[se]->lines[li]);
songs[so]->sections[se]->lines[li] = NULL;
songs[so]->metadata = realloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *));
diff --git a/chordpro.h b/chordpro.h
@@ -1,8 +1,77 @@
+/* ChordPro markup language <https://chordpro.org/chordpro/chordpro_markup> */
+
+#define RISE_MAX
+#define DEFAULT_FONT_SIZE 14.0
+// Based on https://stackoverflow.com/a/417184
+#define URL_MAX_LEN 2000
+
+enum FontFamily {
+ FF_NORMAL,
+ FF_SANS,
+ FF_SERIF,
+ FF_MONOSPACE
+};
+
+enum FontStyle {
+ FS_NORMAL,
+ FS_OBLIQUE,
+ FS_ITALIC
+};
+
+enum FontWeight {
+ FW_NORMAL,
+ FW_BOLD
+};
+
+enum LineStyle {
+ LS_SINGLE,
+ LS_DOUBLE,
+ LS_NONE
+};
+
+struct RGBColor {
+ uint8_t red;
+ uint8_t green;
+ uint8_t blue;
+};
+
+struct Style {
+ char *font; // If NULL use default font.
+ enum FontFamily font_family;
+ float font_size;
+ enum FontStyle font_style;
+ enum FontWeight font_weight;
+ struct RGBColor *foreground_color;
+ struct RGBColor *background_color;
+ enum LineStyle underline_style;
+ struct RGBColor *underline_color;
+ enum LineStyle overline_style;
+ struct RGBColor *overline_color;
+ bool strikethrough;
+ struct RGBColor *strikethrough_color;
+ bool boxed;
+ struct RGBColor *boxed_color;
+ float rise;
+ char *href;
+};
+
+struct Tag {
+ char *name;
+ struct Style *style;
+ bool is_closed;
+};
+
enum State {
STATE_LYRICS,
STATE_DIRECTIVE_NAME,
STATE_DIRECTIVE_VALUE,
- STATE_CHORD
+ STATE_CHORD,
+ STATE_MARKUP_TAG_BEGIN,
+ STATE_MARKUP_TAG_END,
+ STATE_MARKUP_TAG_INSIDE,
+ STATE_MARKUP_TAG,
+ STATE_MARKUP_ATTR_NAME,
+ STATE_MARKUP_ATTR_VALUE
};
enum DirectiveType {
@@ -25,22 +94,22 @@ enum SectionType {
enum Position {
POS_NOTHING,
- POS_BEGIN,
+ POS_BEGIN, // rename to POS_START
POS_END
};
-enum LineStyle {
+/* enum LineStyle {
LS_NORMAL,
LS_GREY_BACKGROUND,
LS_ITALIC,
LS_BOX
-};
+}; */
struct ChoDirective {
enum DirectiveType dtype;
enum SectionType stype;
enum Position position;
- enum LineStyle style;
+ struct Style *style;
};
struct ChoMetadata {
@@ -49,14 +118,21 @@ struct ChoMetadata {
};
struct ChoChord {
+ // struct Style *style;
int index_in_lyrics;
char *chord;
};
+struct ChoLineItem {
+ struct Style *style;
+ char *text;
+};
+
struct ChoLine {
- enum LineStyle style;
+ // enum LineStyle style;
struct ChoChord **chords;
- char *lyrics;
+ // char *lyrics;
+ struct ChoLineItem **lyrics;
};
struct ChoSection {
@@ -72,5 +148,6 @@ struct ChoSong {
struct ChoSong **cho_parse(FILE *fp);
void cho_songs_free(struct ChoSong **song);
+const char *the_dtype(enum DirectiveType dtype);
const char *the_stype(enum SectionType stype);
-const char *the_style(enum LineStyle style);
+const char *the_pos(enum Position pos);
diff --git a/lorid.c b/lorid.c
@@ -1,5 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include <getopt.h>
#include "chordpro.h"