lorid

convert chordpro to pdf
git clone git://git.relim.de/lorid.git
Log | Files | Refs | README | LICENSE

commit 32c9c5f9317b037451c7690140ce8829243203d4
parent 52067be37cffb0b14ca8553f0eafad81ebad1676
Author: nibo <nibo@relim.de>
Date:   Sat,  1 Jun 2024 22:07:45 +0200

Make progress

Diffstat:
Mchordpro.c | 419++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mchordpro.h | 93++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mlorid.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"