commit cc59a9879c0371a85dd89b1a79e04482cf3db342
parent 36abc048f17df2f33f223ff4f21607c64c80e172
Author: nibo <nibo@relim.de>
Date: Tue, 28 Jan 2025 14:34:13 +0100
Implement tab section
In a tab section markup tags and directives aren't
available.
Diffstat:
4 files changed, 143 insertions(+), 6 deletions(-)
diff --git a/chordpro.c b/chordpro.c
@@ -25,6 +25,7 @@ static const char *state_enums[] = {
"STATE_DIRECTIVE_VALUE",
"STATE_CHORD",
"STATE_ANNOTATION",
+ "STATE_TAB",
"STATE_MARKUP_TAG_START",
"STATE_MARKUP_TAG_END",
"STATE_MARKUP_TAG",
@@ -3790,6 +3791,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
g_config = config;
g_chordpro_filepath = chordpro_filepath;
bool is_chord_already_initialized = false;
+ bool is_maybe_end_of_tab_directive = false;
bool directive_has_tag = false;
char buf = 0;
char prev_buf = '\n';
@@ -3862,6 +3864,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
switch (state) {
case STATE_LYRICS:
if (prev_buf == '\n' && buf == '#') {
+ prev_state = STATE_LYRICS;
state = STATE_COMMENT;
break;
}
@@ -4179,9 +4182,13 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
cho_log(LOG_ERR, "Invalid directive '%s'.", directive_name);
return NULL;
}
+ if (directive->stype == ST_TAB) {
+ state = STATE_TAB;
+ } else {
+ state = STATE_LYRICS;
+ }
cho_directive_free(directive);
directive = NULL;
- state = STATE_LYRICS;
break;
}
if (buf == '{') {
@@ -4681,6 +4688,129 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
(*lines)[li]->text_above[c]->u.annot->text[ann] = buf;
ann++;
break;
+ case STATE_TAB:
+ // INFO: similar to STATE_LYRICS but without markup and directives
+ if (prev_buf == '\n' && buf == '#') {
+ prev_state = STATE_TAB;
+ state = STATE_COMMENT;
+ break;
+ }
+ if (is_maybe_end_of_tab_directive) {
+ if (buf == '}') {
+ directive_name[dn] = 0;
+ dn = 0;
+ is_maybe_end_of_tab_directive = false;
+ if (!strcmp(directive_name, "end_of_tab") || !strcmp(directive_name, "eot")) {
+ cho_line_item_free((*lines)[li]->items[ly]);
+ free((*lines)[li]->items);
+ ly = 0;
+ free((*lines)[li]);
+ (*lines)[li] = NULL;
+ se++;
+ songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *));
+ songs[so]->sections[se] = cho_section_new();
+ li = 0;
+ lines = &songs[so]->sections[se]->lines;
+ *lines = emalloc(sizeof(struct ChoLine *));
+ (*lines)[li] = cho_line_new();
+ (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *));
+ (*lines)[li]->items[ly] = cho_line_item_new();
+ g_current_ttype = TT_TEXT;
+ state = STATE_LYRICS;
+ break;
+ } else {
+ (*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++;
+ char *k;
+ for (k = (char *)&directive_name; *k; k++, te++) {
+ (*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] = *k;
+ }
+ (*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;
+ }
+ if (buf == ' ' || buf == ':') {
+ directive_name[dn] = 0;
+ dn = 0;
+ is_maybe_end_of_tab_directive = false;
+ (*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++;
+ char *k;
+ for (k = (char *)&directive_name; *k; k++, te++) {
+ (*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] = *k;
+ }
+ (*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] = buf;
+ te++;
+ break;
+ }
+ directive_name[dn] = buf;
+ dn++;
+ break;
+ }
+ if (prev_buf == '\n' && buf == '{') {
+ is_maybe_end_of_tab_directive = true;
+ break;
+ }
+ if (buf == '\n') {
+ if (prev_buf == '\\') {
+ // INFO: This will later overwrite the backslash
+ te--;
+ break;
+ }
+ if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) {
+ cho_log(LOG_ERR, "Tag has to be closed on same line.");
+ return NULL;
+ }
+ if ((*lines)[li]->items[ly]->is_text) {
+ (*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] = 0;
+ if (strlen((*lines)[li]->items[ly]->u.text->text) == 0) {
+ cho_line_item_free((*lines)[li]->items[ly]);
+ if (ly == 0) {
+ if (
+ !(*lines)[li]->text_above &&
+ (*lines)[li]->btype == BT_LINE
+ ) {
+ free((*lines)[li]->items);
+ free((*lines)[li]);
+ *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
+ (*lines)[li] = cho_line_new();
+ (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
+ (*lines)[li]->items[ly] = cho_line_item_new();
+ break;
+ }
+ }
+ } else {
+ ly++;
+ }
+ } else {
+ ly++;
+ }
+ (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
+ (*lines)[li]->items[ly] = NULL;
+ ly = 0;
+ te = 0;
+ (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *));
+ (*lines)[li]->text_above[c] = NULL;
+ c = 0;
+ li++;
+ *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *));
+ (*lines)[li] = cho_line_new();
+ (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *));
+ (*lines)[li]->items[ly] = cho_line_item_new();
+ break;
+ }
+ (*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] = buf;
+ te++;
+ break;
case STATE_MARKUP_TAG_START:
MARKUP_TAG_START:
if (buf == '>') {
@@ -4981,7 +5111,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config)
break;
case STATE_COMMENT:
if (buf == '\n') {
- state = STATE_LYRICS;
+ state = prev_state;
break;
}
break;
diff --git a/chordpro.h b/chordpro.h
@@ -178,6 +178,7 @@ enum State {
STATE_DIRECTIVE_VALUE,
STATE_CHORD,
STATE_ANNOTATION,
+ STATE_TAB,
STATE_MARKUP_TAG_START,
STATE_MARKUP_TAG_END,
STATE_MARKUP_TAG,
diff --git a/config.c b/config.c
@@ -446,7 +446,8 @@ config_load_default(void)
config->output->styles[TT_GRID]->font->name = strdup(DEFAULT_FONT_FAMILY);
config->output->styles[TT_GRID]->font->weight = FW_BOLD;
config->output->styles[TT_TAB] = cho_style_new();
- config->output->styles[TT_TAB]->font->name = strdup(DEFAULT_FONT_FAMILY);
+ config->output->styles[TT_TAB]->font->name = strdup("Courier");
+ // config->output->styles[TT_TAB]->font->family = FF_MONOSPACE;
config->output->styles[TT_TOC] = cho_style_new();
config->output->styles[TT_TOC]->font->name = strdup(DEFAULT_FONT_FAMILY);
config->output->styles[TT_TOC]->font->size = 12.0;
diff --git a/out_pdf.c b/out_pdf.c
@@ -256,15 +256,19 @@ fontpath_count_fonts(FcChar8 *path)
static char *
fontpath_find(struct Font *font, enum FontType font_type)
{
+ FcObjectSet *obj;
+ FcPattern *pattern;
char *filepath = NULL;
- FcObjectSet *obj = FcObjectSetBuild(FC_FAMILY, FC_SLANT, FC_WEIGHT, FC_FONTFORMAT, FC_FONT_WRAPPER, FC_FILE, NULL);
- FcPattern *pattern = FcPatternCreate();
+ obj = FcObjectSetBuild(FC_FAMILY, FC_SLANT, FC_WIDTH, FC_WEIGHT, FC_FONTFORMAT, FC_FONT_WRAPPER, FC_FILE, NULL);
+ pattern = FcPatternCreate();
FcValue family = { .type = FcTypeString, .u.s = (FcChar8 *)font->name };
FcPatternAdd(pattern, FC_FAMILY, family, FcFalse);
FcValue font_wrapper = { .type = FcTypeString, .u.s = (FcChar8 *)"SFNT" };
FcPatternAdd(pattern, FC_FONT_WRAPPER, font_wrapper, FcFalse);
FcValue variable = { .type = FcTypeBool, .u.b = FcFalse };
FcPatternAdd(pattern, FC_VARIABLE, variable, FcFalse);
+ FcValue width = { .type = FcTypeInteger, .u.i = FC_WIDTH_NORMAL };
+ FcPatternAdd(pattern, FC_WIDTH, width, FcFalse);
/* TODO: Also handle FF_NORMAL, FF_SANS and FF_SERIF, but how? */
if (font->family == FF_MONOSPACE) {
FcValue spacing = { .type = FcTypeInteger, .u.i = FC_MONO };
@@ -310,7 +314,8 @@ fontpath_find(struct Font *font, enum FontType font_type)
FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse);
FcFontSet *set = FcFontList(NULL, pattern, obj);
FcChar8 *file;
- for (int i=0; i<set->nfont; i++) {
+ int i;
+ for (i = 0; i<set->nfont; i++) {
if (FcPatternGetString(set->fonts[i], FC_FILE, 0, &file) == FcResultMatch) {
if (
!file_extension_equals((const char *)file, "ttc") &&