lorid

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

commit ed845e75a1e73877454fb70958bb06a437f23825
parent 9ec1d5d00ac60396aedb12f15213b61406c716ab
Author: nibo <nibo@relim.de>
Date:   Wed, 19 Feb 2025 20:02:26 +0100

Start refactoring 'cho_songs_parse'

First refactor by creating 'struct ChoContext'
and after that I can continue with the metadata
substitution.

Diffstat:
Msrc/chordpro.c | 1652++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/chordpro.h | 36++++++++++++++++++++++++++++++++++++
Msrc/types.h | 3+++
3 files changed, 872 insertions(+), 819 deletions(-)

diff --git a/src/chordpro.c b/src/chordpro.c @@ -149,8 +149,8 @@ static enum TextType g_current_ttype = TT_TEXT; static enum TextType g_prev_ttype = TT_TEXT; static struct Config *g_config = NULL; static const char *g_chordpro_filepath = NULL; -static int *g_transpose_history = NULL; -static int *g_transpose = NULL; +// static int *g_transpose_history = NULL; +// static int *g_transpose = NULL; static size_t g_line_number = 1; struct ChoImage **g_image_assets = NULL; static int g_ia = 0; @@ -1802,9 +1802,9 @@ transposition_parse(const char *str, int *transpose) } static char * -transposition_calc_chord_root(int index, enum NoteType type) +transposition_calc_chord_root(struct ChoContext *ctx, int index, enum NoteType type) { - int transpose = *g_transpose; + int transpose = *ctx->transpose; if (transpose == 0) { switch (type) { case NT_NOTE: @@ -2008,7 +2008,7 @@ cho_chords_free(struct ChoChord **chords) /* returns how many bytes make up the root; returns 0 if no root was found */ static int -cho_chord_root_parse(const char *str, struct ChoChord *chord) +cho_chord_root_parse(struct ChoContext *ctx, const char *str, struct ChoChord *chord) { const char *note = NULL; const char *sharp = NULL; @@ -2018,7 +2018,7 @@ cho_chord_root_parse(const char *str, struct ChoChord *chord) for (i = 0; i<7; i++) { sharp = g_config->parser->notes[i]->sharp; if (sharp && str_starts_with(str, sharp)) { - transposed_root = transposition_calc_chord_root(i, NT_SHARP); + transposed_root = transposition_calc_chord_root(ctx, i, NT_SHARP); if (!transposed_root) { LOG_DEBUG("transposition_calc_chord_root failed."); return 0; @@ -2028,7 +2028,7 @@ cho_chord_root_parse(const char *str, struct ChoChord *chord) } flat = g_config->parser->notes[i]->flat; if (flat && str_starts_with(str, flat)) { - transposed_root = transposition_calc_chord_root(i, NT_FLAT); + transposed_root = transposition_calc_chord_root(ctx, i, NT_FLAT); if (!transposed_root) { LOG_DEBUG("transposition_calc_chord_root failed."); return 0; @@ -2038,7 +2038,7 @@ cho_chord_root_parse(const char *str, struct ChoChord *chord) } note = g_config->parser->notes[i]->note; if (str_starts_with(str, note)) { - transposed_root = transposition_calc_chord_root(i, NT_NOTE); + transposed_root = transposition_calc_chord_root(ctx, i, NT_NOTE); if (!transposed_root) { LOG_DEBUG("transposition_calc_chord_root failed."); return 0; @@ -2138,14 +2138,14 @@ cho_chord_bass_parse(const char *str, struct ChoChord *chord) } static struct ChoChord * -cho_chord_parse(const char *str) +cho_chord_parse(struct ChoContext *ctx, const char *str) { struct ChoChord *chord = cho_chord_new(); size_t str_len = strlen(str); size_t bytes_parsed = 0; int ret; chord->name = strdup(str); - ret = cho_chord_root_parse(str, chord); + ret = cho_chord_root_parse(ctx, str, chord); if (ret == 0) { return chord; } @@ -4026,16 +4026,72 @@ cho_directive_label_parse(const char *directive_name, const char *str) return label_name; } +static bool +cho_context_init(struct ChoContext *ctx) +{ + ctx->is_chord_already_initialized = false; + ctx->is_maybe_end_of_tab_directive = false; + ctx->directive_has_tag = false; + ctx->state = STATE_LYRICS; + ctx->state_before_comment = STATE_LYRICS; + ctx->state_before_tag = STATE_LYRICS; + ctx->state_before_backslash = STATE_LYRICS; + ctx->state_before_metadata_substitution = STATE_LYRICS; + ctx->ann = 0; + ctx->at = 0; + ctx->atn = 0; + ctx->atv = 0; + ctx->ch = 0; + ctx->dia = 0; + ctx->dn = 0; + ctx->dv = 0; + ctx->li = 0; + ctx->lia = 0; + ctx->lii = 0; + ctx->m = 11; + ctx->ms = 0; + ctx->se = 0; + ctx->so = 0; + ctx->t = 0; + ctx->ta = -1; + ctx->te = 0; + ctx->th = 0; + ctx->nested_level = 0; + ctx->tags = NULL; + + ctx->transpose_history = emalloc((ctx->th+1) * sizeof(int *)); + ctx->transpose_history[ctx->th] = 0; + ctx->transpose = &ctx->transpose_history[ctx->th]; + ctx->th++; + + ctx->songs = emalloc(sizeof(struct ChoSong *)); + ctx->songs[ctx->so] = cho_song_new(); + if (!ctx->songs[ctx->so]) { + LOG_DEBUG("cho_song_new failed."); + return false; + } + ctx->songs[ctx->so]->sections = emalloc((ctx->se+1) * sizeof(struct ChoSection *)); + ctx->songs[ctx->so]->sections[ctx->se] = cho_section_new(); + ctx->songs[ctx->so]->sections[ctx->se]->lines = emalloc(sizeof(struct ChoLine *)); + ctx->songs[ctx->so]->sections[ctx->se]->lines[ctx->li] = cho_line_new(); + return true; +} + struct ChoSong ** 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'; + enum AttrValueSyntax avs = -1; + struct ChoStyle *tag_style; + struct StyleProperty sprop; + struct ChoChord *tmp_chord; + struct ChoSection *chorus; + struct ChoImage *image; + struct ChordDiagram *diagram; + struct ChoDirective *directive; + struct ChoMetadata *metadata; + struct ChoLine ***lines; + struct ChoContext ctx; + char *label, *metadata_value, *stripped_directive_value; char directive_name[128]; char directive_value[4096]; char chord[15]; @@ -4043,184 +4099,142 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) char tag_end[6]; char custom_directive[64]; char metadata_substitution[4096]; - char *label, *metadata_value, *stripped_directive_value; - enum State state = STATE_LYRICS; - enum State state_before_comment = STATE_LYRICS; - enum State state_before_tag = STATE_LYRICS; - enum State state_before_backslash = STATE_LYRICS; - enum State state_before_metadata_substitution = STATE_LYRICS; - int dn = 0; - int dv = 0; - int ch = 0; - int c = 0; - // Not zero by default because there are default metadata entries - int m = 11; - int ly = 0; - int t = 0; - int so = 0; - int se = 0; - int li = 0; - int ta = -1; - int te = 0; - int at = 0; - int atn = 0; - int atv = 0; - int ann = 0; - int text_above_pos; + char c = 0; + char prev_c = '\n'; int transpose; - int th = 0; - int dia = 0; - int ms = 0; - int nested_level = 0; size_t read; - g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *)); - g_transpose_history[th] = 0; - g_transpose = &g_transpose_history[th]; - th++; - enum AttrValueSyntax avs = -1; - struct ChoDirective *directive = NULL; - struct ChoMetadata *metadata = NULL; - struct ChoLine ***lines; - struct ChoSong **songs = emalloc(sizeof(struct ChoSong *)); - songs[so] = cho_song_new(); - if (!songs[so]) { - LOG_DEBUG("cho_song_new failed."); + + g_config = config; + g_chordpro_filepath = chordpro_filepath; + + if (!cho_context_init(&ctx)) { + LOG_DEBUG("cho_context_init failed."); return NULL; } - songs[so]->sections = emalloc((se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_new(); - songs[so]->sections[se]->lines = emalloc(sizeof(struct ChoLine *)); - songs[so]->sections[se]->lines[li] = cho_line_new(); - lines = &songs[so]->sections[se]->lines; - (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - songs[so]->present_text_types[TT_TOC] = config->output->toc->show; - struct Tag **tags = NULL; - struct ChoStyle *tag_style; - struct StyleProperty sprop; - struct ChoChord *tmp_chord; - struct ChoSection *chorus; - struct ChoImage *image; - struct ChordDiagram *diagram; + + lines = &ctx.songs[ctx.so]->sections[ctx.se]->lines; + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + ctx.songs[ctx.so]->present_text_types[TT_TOC] = config->output->toc->show; while (feof(fp) == 0) { - read = fread(&buf, 1, 1, fp); + read = fread(&c, 1, 1, fp); if (read == 1) { - if (buf == '\n') { + if (c == '\n') { g_line_number++; } // printf("state: %s, buf: %c\n", state_enums[state], buf); - if (buf == '\r') { + if (c == '\r') { continue; } - switch (state) { + switch (ctx.state) { case STATE_LYRICS: { - if (prev_buf == '\n' && buf == '#') { - state_before_comment = STATE_LYRICS; - state = STATE_COMMENT; + if (prev_c == '\n' && c == '#') { + ctx.state_before_comment = STATE_LYRICS; + ctx.state = STATE_COMMENT; break; } - if (prev_buf == '\n' && buf == '{') { - state = STATE_DIRECTIVE_NAME; + if (prev_c == '\n' && c == '{') { + ctx.state = STATE_DIRECTIVE_NAME; break; } - if (buf == '[') { - state = STATE_CHORD; + if (c == '[') { + ctx.state = STATE_CHORD; break; } - if (buf == '<') { - 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 (c == '<') { + if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - te = 0; - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - state_before_tag = STATE_LYRICS; - state = STATE_MARKUP_TAG; + ctx.te = 0; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + ctx.state_before_tag = STATE_LYRICS; + ctx.state = STATE_MARKUP_TAG; break; } - if (buf == '%') { - state_before_metadata_substitution = STATE_LYRICS; - state = STATE_MAYBE_METADATA_SUBSTITUTION; + if (c == '%') { + ctx.state_before_metadata_substitution = STATE_LYRICS; + ctx.state = STATE_MAYBE_METADATA_SUBSTITUTION; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_LYRICS; - state = STATE_BACKSLASH; - te--; // INFO: This will later overwrite the backslash + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_LYRICS; + ctx.state = STATE_BACKSLASH; + ctx.te--; // INFO: This will later overwrite the backslash break; } - if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) { + if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.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)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + if (ctx.lii == 0) { if ( - !(*lines)[li]->text_above && - (*lines)[li]->btype == BT_LINE + !(*lines)[ctx.li]->text_above && + (*lines)[ctx.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(); + free((*lines)[ctx.li]->items); + free((*lines)[ctx.li]); + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); break; } } } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*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(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = NULL; + ctx.lii = 0; + ctx.te = 0; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = NULL; + ctx.lia = 0; + ctx.li++; + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = 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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = c; + ctx.te++; break; } case STATE_BACKSLASH: { - if (!is_whitespace(buf)) { + if (!is_whitespace(c)) { if (fseek(fp, -1, SEEK_CUR)) { LOG_DEBUG("fseek failed."); return NULL; } - state = state_before_backslash; + ctx.state = ctx.state_before_backslash; break; } break; } case STATE_DIRECTIVE_NAME: { - if (buf == '}') { - directive_name[dn] = 0; - dn = 0; + if (c == '}') { + directive_name[ctx.dn] = 0; + ctx.dn = 0; directive = cho_directive_parse(directive_name); /* printf( "directive: '%s'\ndtype: %s, stype: %s, position: %s\n", @@ -4235,127 +4249,127 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) memset(custom_directive, 0, sizeof(custom_directive)); strcpy(custom_directive, &directive_name[9]); } - 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(); - songs[so]->sections[se]->type = directive->stype; - li = 0; - lines = &songs[so]->sections[se]->lines; + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + ctx.lii = 0; + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + ctx.songs[ctx.so]->sections[ctx.se]->type = directive->stype; + ctx.li = 0; + lines = &ctx.songs[ctx.so]->sections[ctx.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(); - songs[so]->present_text_types[directive->ttype] = true; + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; break; } case POS_END: { - if (directive->stype == songs[so]->sections[se]->type) { + if (directive->stype == ctx.songs[ctx.so]->sections[ctx.se]->type) { if (directive->stype == ST_CUSTOM) { if (strcmp(custom_directive, &directive_name[7]) != 0) { break; } } - 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; + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + ctx.lii = 0; + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + ctx.li = 0; + lines = &ctx.songs[ctx.so]->sections[ctx.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(); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } break; } case POS_NO: { /* INFO: {chorus} */ - chorus = cho_find_previous_chorus(songs[so]->sections, se); + chorus = cho_find_previous_chorus(ctx.songs[ctx.so]->sections, ctx.se); if (chorus) { if (config->output->chorus->quote) { - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; } - 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; - cho_line_free((*lines)[li]); - (*lines)[li] = NULL; - li = 0; - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_copy(chorus); - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_new(); - lines = &songs[so]->sections[se]->lines; + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = NULL; + ctx.lii = 0; + ctx.te = 0; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = NULL; + ctx.lia = 0; + cho_line_free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.li = 0; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_copy(chorus); + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + lines = &ctx.songs[ctx.so]->sections[ctx.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(); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } else { if (chorus->label) { label = strdup(chorus->label->text); } else { label = strdup(config->output->chorus->label); } - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_style_free((*lines)[li]->items[ly]->u.text->style); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); g_current_ttype = TT_LABEL; - (*lines)[li]->items[ly]->u.text->style = cho_style_new_default(); - (*lines)[li]->items[ly]->u.text->text = label; - te += strlen(label); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; + ctx.te += strlen(label); } } else { if (config->output->chorus->quote) { cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously."); } label = strdup(config->output->chorus->label); - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_style_free((*lines)[li]->items[ly]->u.text->style); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); g_current_ttype = TT_LABEL; - (*lines)[li]->items[ly]->u.text->style = cho_style_new_default(); - (*lines)[li]->items[ly]->u.text->text = label; - te += strlen(label); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; + ctx.te += strlen(label); } break; } @@ -4376,40 +4390,40 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) return NULL; case DT_PREAMBLE: { // INFO: The only preamble directive is 'new_song' - cho_line_item_free((*lines)[li]->items[ly]); - free((*lines)[li]->items); - free((*lines)[li]); - (*lines)[li] = NULL; - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = NULL; - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = NULL; - songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *)); - songs[so]->diagrams[dia] = NULL; + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = NULL; + ctx.songs[ctx.so]->diagrams = erealloc(ctx.songs[ctx.so]->diagrams, (ctx.dia+1) * sizeof(struct ChordDiagram *)); + ctx.songs[ctx.so]->diagrams[ctx.dia] = NULL; if (!cho_style_reset_default()) { LOG_DEBUG("cho_style_reset_default failed."); return NULL; } - so++; - songs = erealloc(songs, (so+1) * sizeof(struct ChoSong *)); - songs[so] = cho_song_new(); - if (!songs[so]) { + ctx.so++; + ctx.songs = erealloc(ctx.songs, (ctx.so+1) * sizeof(struct ChoSong *)); + ctx.songs[ctx.so] = cho_song_new(); + if (!ctx.songs[ctx.so]) { LOG_DEBUG("cho_song_new failed."); return NULL; } - se = 0; - li = 0; - ly = 0; - m = 11; - dia = 0; - songs[so]->sections = emalloc((se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_new(); - lines = &songs[so]->sections[se]->lines; - *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *)); - (*lines)[li] = cho_line_new(); - (*lines)[li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); + ctx.se = 0; + ctx.li = 0; + ctx.lii = 0; + ctx.m = 11; + ctx.dia = 0; + ctx.songs[ctx.so]->sections = emalloc((ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + lines = &ctx.songs[ctx.so]->sections[ctx.se]->lines; + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); break; } case DT_FONT: { @@ -4438,8 +4452,8 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) case DT_CHORD: { switch (directive->ctype) { case TRANSPOSE: - g_transpose--; - th--; + ctx.transpose--; + ctx.th--; break; case DEFINE: cho_log(LOG_WARN, "Ignoring chord directive '%s' because it has no value.", directive_name); @@ -4449,7 +4463,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } case DT_OUTPUT: if (directive->btype != -1) { - (*lines)[li]->btype = directive->btype; + (*lines)[ctx.li]->btype = directive->btype; } break; case DT_EXTENSION: @@ -4463,42 +4477,42 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) return NULL; } if (directive->stype == ST_TAB) { - state = STATE_TAB; + ctx.state = STATE_TAB; } else { - state = STATE_LYRICS; + ctx.state = STATE_LYRICS; } cho_directive_free(directive); directive = NULL; break; } - if (buf == '{') { + if (c == '{') { cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); return NULL; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_DIRECTIVE_NAME; - state = STATE_BACKSLASH; - dn--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_DIRECTIVE_NAME; + ctx.state = STATE_BACKSLASH; + ctx.dn--; break; } cho_log(LOG_ERR, "Can't have a newline in a directive name."); return NULL; } - if (buf == ':' || buf == ' ') { - directive_name[dn] = 0; - dn = 0; - state = STATE_DIRECTIVE_VALUE; + if (c == ':' || c == ' ') { + directive_name[ctx.dn] = 0; + ctx.dn = 0; + ctx.state = STATE_DIRECTIVE_VALUE; break; } - directive_name[dn] = buf; - dn++; + directive_name[ctx.dn] = c; + ctx.dn++; break; } case STATE_DIRECTIVE_VALUE: { - if (buf == '}') { - directive_value[dv] = 0; - dv = 0; + if (c == '}') { + directive_value[ctx.dv] = 0; + ctx.dv = 0; stripped_directive_value = str_remove_leading_whitespace(directive_value); directive = cho_directive_parse(directive_name); /* printf( @@ -4508,7 +4522,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) switch (directive->dtype) { case DT_ENVIRONMENT: { if (strlen(stripped_directive_value) > 0) { - songs[so]->present_text_types[TT_LABEL] = true; + ctx.songs[ctx.so]->present_text_types[TT_LABEL] = true; } g_current_ttype = directive->ttype; switch (directive->position) { @@ -4517,16 +4531,16 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) memset(custom_directive, 0, sizeof(custom_directive)); strcpy(custom_directive, &directive_name[9]); } - 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(); - songs[so]->sections[se]->type = directive->stype; - songs[so]->sections[se]->label = emalloc(sizeof(struct ChoText)); + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + ctx.lii = 0; + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + ctx.songs[ctx.so]->sections[ctx.se]->type = directive->stype; + ctx.songs[ctx.so]->sections[ctx.se]->label = emalloc(sizeof(struct ChoText)); if (strstr(directive_value, "=")) { label = cho_directive_label_parse(directive_name, directive_value); if (!label) { @@ -4534,137 +4548,137 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) 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->text = label; + ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } else { - songs[so]->sections[se]->label->text = strdup(stripped_directive_value); + ctx.songs[ctx.so]->sections[ctx.se]->label->text = strdup(stripped_directive_value); } - songs[so]->sections[se]->label->style = cho_style_new_from_config(TT_LABEL); - if (directive_has_tag) { - cho_style_complement(songs[so]->sections[se]->label->style, tags[ta]->style, &tags[ta]->style_presence); - directive_has_tag = false; + ctx.songs[ctx.so]->sections[ctx.se]->label->style = cho_style_new_from_config(TT_LABEL); + if (ctx.directive_has_tag) { + cho_style_complement(ctx.songs[ctx.so]->sections[ctx.se]->label->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); + ctx.directive_has_tag = false; } - li = 0; - lines = &songs[so]->sections[se]->lines; + ctx.li = 0; + lines = &ctx.songs[ctx.so]->sections[ctx.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(); - songs[so]->present_text_types[directive->ttype] = true; + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; break; } case POS_END: { - if (directive->stype == songs[so]->sections[se]->type) { - 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; + if (directive->stype == ctx.songs[ctx.so]->sections[ctx.se]->type) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + ctx.lii = 0; + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + ctx.li = 0; + lines = &ctx.songs[ctx.so]->sections[ctx.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(); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } break; } case POS_NO: { /* INFO: {chorus: ...} */ label = strdup(stripped_directive_value); - chorus = cho_find_previous_chorus(songs[so]->sections, se); + chorus = cho_find_previous_chorus(ctx.songs[ctx.so]->sections, ctx.se); if (chorus) { if (config->output->chorus->quote) { - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; } - 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; - cho_line_free((*lines)[li]); + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = NULL; + ctx.lii = 0; + ctx.te = 0; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = NULL; + ctx.lia = 0; + cho_line_free((*lines)[ctx.li]); // songs[so]->sections[se]->lines = erealloc(songs[so]->sections[se]->lines, (li+1) * sizeof(struct ChoLine *)); - (*lines)[li] = NULL; - li = 0; - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_copy(chorus); - if (songs[so]->sections[se]->label) { - free(songs[so]->sections[se]->label->text); - songs[so]->sections[se]->label->text = label; + (*lines)[ctx.li] = NULL; + ctx.li = 0; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_copy(chorus); + if (ctx.songs[ctx.so]->sections[ctx.se]->label) { + free(ctx.songs[ctx.so]->sections[ctx.se]->label->text); + ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } else { g_current_ttype = TT_LABEL; - songs[so]->sections[se]->label = cho_text_new(); - songs[so]->sections[se]->label->text = label; + ctx.songs[ctx.so]->sections[ctx.se]->label = cho_text_new(); + ctx.songs[ctx.so]->sections[ctx.se]->label->text = label; } - if (directive_has_tag) { - cho_style_complement(songs[so]->sections[se]->label->style, tags[ta]->style, &tags[ta]->style_presence); - directive_has_tag = false; + if (ctx.directive_has_tag) { + cho_style_complement(ctx.songs[ctx.so]->sections[ctx.se]->label->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); + ctx.directive_has_tag = false; } - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = cho_section_new(); - lines = &songs[so]->sections[se]->lines; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + lines = &ctx.songs[ctx.so]->sections[ctx.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(); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } else { - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_style_free((*lines)[li]->items[ly]->u.text->style); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); g_current_ttype = TT_LABEL; - (*lines)[li]->items[ly]->u.text->style = cho_style_new_default(); - (*lines)[li]->items[ly]->u.text->text = label; - if (directive_has_tag) { - cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence); - directive_has_tag = false; + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; + if (ctx.directive_has_tag) { + cho_style_complement((*lines)[ctx.li]->items[ctx.lii]->u.text->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); + ctx.directive_has_tag = false; } - te += strlen(label); + ctx.te += strlen(label); } } else { if (config->output->chorus->quote) { cho_log(LOG_WARN, "Can't quote chorus because it's not defined previously."); } - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_style_free((*lines)[li]->items[ly]->u.text->style); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); g_current_ttype = TT_LABEL; - (*lines)[li]->items[ly]->u.text->style = cho_style_new_default(); - (*lines)[li]->items[ly]->u.text->text = label; - if (directive_has_tag) { - cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; + if (ctx.directive_has_tag) { + cho_style_complement((*lines)[ctx.li]->items[ctx.lii]->u.text->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); } - te += strlen(label); + ctx.te += strlen(label); } break; } @@ -4683,22 +4697,22 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } switch (directive->meta) { case TITLE: - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = cho_metadata_new(); - songs[so]->metadata[m]->name = strdup("title"); - songs[so]->metadata[m]->value = metadata_value; - cho_style_free(songs[so]->metadata[m]->style); - songs[so]->metadata[m]->style = cho_style_copy(directive->style); - songs[so]->present_text_types[TT_TITLE] = true; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup("title"); + ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; + cho_style_free(ctx.songs[ctx.so]->metadata[ctx.m]->style); + ctx.songs[ctx.so]->metadata[ctx.m]->style = cho_style_copy(directive->style); + ctx.songs[ctx.so]->present_text_types[TT_TITLE] = true; break; case SUBTITLE: - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = cho_metadata_new(); - songs[so]->metadata[m]->name = strdup("subtitle"); - songs[so]->metadata[m]->value = metadata_value; - cho_style_free(songs[so]->metadata[m]->style); - songs[so]->metadata[m]->style = cho_style_copy(directive->style); - songs[so]->present_text_types[TT_SUBTITLE] = true; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup("subtitle"); + ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; + cho_style_free(ctx.songs[ctx.so]->metadata[ctx.m]->style); + ctx.songs[ctx.so]->metadata[ctx.m]->style = cho_style_copy(directive->style); + ctx.songs[ctx.so]->present_text_types[TT_SUBTITLE] = true; break; default: if (!strcmp(directive_name, "meta")) { @@ -4707,46 +4721,46 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) LOG_DEBUG("cho_metadata_split failed."); return NULL; } - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = metadata; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = metadata; free(metadata_value); } else { - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = cho_metadata_new(); - songs[so]->metadata[m]->name = strdup(directive_name); - songs[so]->metadata[m]->value = metadata_value; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = cho_metadata_new(); + ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup(directive_name); + ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; } } - if (directive_has_tag) { - cho_style_complement(songs[so]->metadata[m]->style, tags[ta]->style, &tags[ta]->style_presence); - directive_has_tag = false; + if (ctx.directive_has_tag) { + cho_style_complement(ctx.songs[ctx.so]->metadata[ctx.m]->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); + ctx.directive_has_tag = false; } - m++; + ctx.m++; break; } case DT_FORMATTING: { - 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 ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_style_free((*lines)[li]->items[ly]->u.text->style); - (*lines)[li]->items[ly]->u.text->style = cho_style_copy(directive->style); - (*lines)[li]->items[ly]->u.text->text = strdup(stripped_directive_value); - if (directive_has_tag) { - cho_style_complement((*lines)[li]->items[ly]->u.text->style, tags[ta]->style, &tags[ta]->style_presence); - directive_has_tag = false; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_copy(directive->style); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(stripped_directive_value); + if (ctx.directive_has_tag) { + cho_style_complement((*lines)[ctx.li]->items[ctx.lii]->u.text->style, ctx.tags[ctx.ta]->style, &ctx.tags[ctx.ta]->style_presence); + ctx.directive_has_tag = false; } - te += strlen(stripped_directive_value); - songs[so]->present_text_types[directive->ttype] = true; + ctx.te += strlen(stripped_directive_value); + ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; break; } case DT_IMAGE: { @@ -4765,17 +4779,17 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) g_image_assets[g_ia] = image; g_ia++; } else { - 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; - te = 0; + if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + ctx.te = 0; } - ly++; - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); - cho_text_free((*lines)[li]->items[ly]->u.text); - (*lines)[li]->items[ly]->is_text = false; - (*lines)[li]->items[ly]->u.image = image; + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); + cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); + (*lines)[ctx.li]->items[ctx.lii]->is_text = false; + (*lines)[ctx.li]->items[ctx.lii]->u.image = image; } break; } @@ -4831,20 +4845,20 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) cho_log(LOG_ERR, "Directive 'transpose' has an invalid value."); return NULL; } - g_transpose_history = erealloc(g_transpose_history, (th+1) * sizeof(int *)); - g_transpose_history[th] = g_transpose_history[th-1] + transpose; - g_transpose = &g_transpose_history[th]; - th++; + ctx.transpose_history = erealloc(ctx.transpose_history, (ctx.th+1) * sizeof(int *)); + ctx.transpose_history[ctx.th] = ctx.transpose_history[ctx.th-1] + transpose; + ctx.transpose = &ctx.transpose_history[ctx.th]; + ctx.th++; break; case DEFINE: - diagram = cho_chord_diagram_parse(directive_value, songs[so]->diagrams, dia); + diagram = cho_chord_diagram_parse(directive_value, ctx.songs[ctx.so]->diagrams, ctx.dia); if (!diagram) { LOG_DEBUG("cho_chord_diagram_parse failed."); return NULL; } - songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *)); - songs[so]->diagrams[dia] = diagram; - dia++; + ctx.songs[ctx.so]->diagrams = erealloc(ctx.songs[ctx.so]->diagrams, (ctx.dia+1) * sizeof(struct ChordDiagram *)); + ctx.songs[ctx.so]->diagrams[ctx.dia] = diagram; + ctx.dia++; break; } break; @@ -4866,278 +4880,278 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) free(stripped_directive_value); cho_directive_free(directive); directive = NULL; - state = STATE_LYRICS; + ctx.state = STATE_LYRICS; break; } - if (buf == '<') { - state_before_tag = STATE_DIRECTIVE_VALUE; - state = STATE_MARKUP_TAG; + if (c == '<') { + ctx.state_before_tag = STATE_DIRECTIVE_VALUE; + ctx.state = STATE_MARKUP_TAG; break; } - if (buf == '{') { + if (c == '{') { cho_log(LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); return NULL; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_DIRECTIVE_VALUE; - state = STATE_BACKSLASH; - dv--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_DIRECTIVE_VALUE; + ctx.state = STATE_BACKSLASH; + ctx.dv--; break; } cho_log(LOG_ERR, "Newline character inside a directive value is invalid."); return NULL; } - if (dv > 4094) { + if (ctx.dv > 4094) { cho_log(LOG_ERR, "Directive value can't be greater than 4095 bytes."); return NULL; } - directive_value[dv] = buf; - dv++; + directive_value[ctx.dv] = c; + ctx.dv++; break; } case STATE_CHORD: { - if (buf == ']') { - chord[ch] = 0; - ch = 0; + if (c == ']') { + chord[ctx.ch] = 0; + ctx.ch = 0; g_prev_ttype = g_current_ttype; g_current_ttype = TT_CHORD; - if (is_chord_already_initialized) { - text_above_pos = cho_line_compute_text_above_position(songs[so]->sections[se]->lines[li], ly, te); - (*lines)[li]->text_above[c]->position = text_above_pos; - tmp_chord = cho_chord_parse(chord); - cho_chord_complete((*lines)[li]->text_above[c]->u.chord, tmp_chord); - if (!(*lines)[li]->text_above[c]->u.chord->is_canonical) { - cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[li]->text_above[c]->u.chord->name); + if (ctx.is_chord_already_initialized) { + ctx.text_above_pos = cho_line_compute_text_above_position(ctx.songs[ctx.so]->sections[ctx.se]->lines[ctx.li], ctx.lii, ctx.te); + (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; + tmp_chord = cho_chord_parse(&ctx, chord); + cho_chord_complete((*lines)[ctx.li]->text_above[ctx.lia]->u.chord, tmp_chord); + if (!(*lines)[ctx.li]->text_above[ctx.lia]->u.chord->is_canonical) { + cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); } cho_chord_free(tmp_chord); - is_chord_already_initialized = false; + ctx.is_chord_already_initialized = false; } else { - (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *)); - (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove)); - (*lines)[li]->text_above[c]->is_chord = true; - text_above_pos = cho_line_compute_text_above_position((*lines)[li], ly, te); - (*lines)[li]->text_above[c]->position = text_above_pos; - (*lines)[li]->text_above[c]->u.chord = cho_chord_parse(chord); - if (!(*lines)[li]->text_above[c]->u.chord->is_canonical) { - cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[li]->text_above[c]->u.chord->name); + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); + (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = true; + ctx.text_above_pos = cho_line_compute_text_above_position((*lines)[ctx.li], ctx.lii, ctx.te); + (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord = cho_chord_parse(&ctx, chord); + if (!(*lines)[ctx.li]->text_above[ctx.lia]->u.chord->is_canonical) { + cho_log(LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); } } - songs[so]->present_text_types[TT_CHORD] = true; + ctx.songs[ctx.so]->present_text_types[TT_CHORD] = true; memset(chord, 0, strlen(chord)); - c++; + ctx.lia++; g_current_ttype = g_prev_ttype; - state = STATE_LYRICS; + ctx.state = STATE_LYRICS; break; } - if (prev_buf == '[' && buf == '*') { + if (prev_c == '[' && c == '*') { g_prev_ttype = g_current_ttype; g_current_ttype = TT_ANNOT; - (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *)); - (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove)); - (*lines)[li]->text_above[c]->is_chord = false; - text_above_pos = cho_line_compute_text_above_position((*lines)[li], ly, te); - (*lines)[li]->text_above[c]->position = text_above_pos; - (*lines)[li]->text_above[c]->u.annot = cho_text_new(); - state = STATE_ANNOTATION; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); + (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = false; + ctx.text_above_pos = cho_line_compute_text_above_position((*lines)[ctx.li], ctx.lii, ctx.te); + (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(); + ctx.state = STATE_ANNOTATION; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_CHORD; - state = STATE_BACKSLASH; - ch--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_CHORD; + ctx.state = STATE_BACKSLASH; + ctx.ch--; break; } cho_log(LOG_ERR, "Newline character inside a chord is invalid."); return NULL; } - if (buf == '[') { + if (c == '[') { cho_log(LOG_ERR, "Can't start a new chord/annotation if the previous one is not yet closed."); return NULL; } - if (buf == '<') { - if (prev_buf == '[') { - (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *)); - (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove)); - (*lines)[li]->text_above[c]->is_chord = true; - (*lines)[li]->text_above[c]->u.chord = cho_chord_new(); - is_chord_already_initialized = true; + if (c == '<') { + if (prev_c == '[') { + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); + (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = true; + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord = cho_chord_new(); + ctx.is_chord_already_initialized = true; } - state_before_tag = STATE_CHORD; - state = STATE_MARKUP_TAG; + ctx.state_before_tag = STATE_CHORD; + ctx.state = STATE_MARKUP_TAG; break; } - chord[ch] = buf; - ch++; + chord[ctx.ch] = c; + ctx.ch++; break; } case STATE_ANNOTATION: { - if (buf == ']') { - (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char)); - (*lines)[li]->text_above[c]->u.annot->text[ann] = 0; - songs[so]->present_text_types[TT_ANNOT] = true; - ann = 0; - c++; + if (c == ']') { + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text = erealloc((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text, (ctx.ann+1) * sizeof(char)); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text[ctx.ann] = 0; + ctx.songs[ctx.so]->present_text_types[TT_ANNOT] = true; + ctx.ann = 0; + ctx.lia++; g_current_ttype = g_prev_ttype; - state = STATE_LYRICS; + ctx.state = STATE_LYRICS; break; } - if (buf == '<') { - state_before_tag = STATE_ANNOTATION; - state = STATE_MARKUP_TAG; + if (c == '<') { + ctx.state_before_tag = STATE_ANNOTATION; + ctx.state = STATE_MARKUP_TAG; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_ANNOTATION; - state = STATE_BACKSLASH; - ann--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_ANNOTATION; + ctx.state = STATE_BACKSLASH; + ctx.ann--; break; } cho_log(LOG_ERR, "Newline character inside an annotation is invalid."); return NULL; } - (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char)); - (*lines)[li]->text_above[c]->u.annot->text[ann] = buf; - ann++; + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text = erealloc((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text, (ctx.ann+1) * sizeof(char)); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text[ctx.ann] = c; + ctx.ann++; break; } case STATE_TAB: { // INFO: similar to STATE_LYRICS but without markup and directives - if (prev_buf == '\n' && buf == '#') { - state_before_comment = STATE_TAB; - state = STATE_COMMENT; + if (prev_c == '\n' && c == '#') { + ctx.state_before_comment = STATE_TAB; + ctx.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 (ctx.is_maybe_end_of_tab_directive) { + if (c == '}') { + directive_name[ctx.dn] = 0; + ctx.dn = 0; + ctx.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; + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + ctx.lii = 0; + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = cho_section_new(); + ctx.li = 0; + lines = &ctx.songs[ctx.so]->sections[ctx.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(); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); g_current_ttype = TT_TEXT; - state = STATE_LYRICS; + ctx.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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = '{'; + ctx.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; + for (k = (char *)&directive_name; *k; k++, ctx.te++) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = '}'; + ctx.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++; + if (c == ' ' || c == ':') { + directive_name[ctx.dn] = 0; + ctx.dn = 0; + ctx.is_maybe_end_of_tab_directive = false; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = '{'; + ctx.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; + for (k = (char *)&directive_name; *k; k++, ctx.te++) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = c; + ctx.te++; break; } - directive_name[dn] = buf; - dn++; + directive_name[ctx.dn] = c; + ctx.dn++; break; } - if (prev_buf == '\n' && buf == '{') { - is_maybe_end_of_tab_directive = true; + if (prev_c == '\n' && c == '{') { + ctx.is_maybe_end_of_tab_directive = true; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_TAB; - state = STATE_BACKSLASH; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_TAB; + ctx.state = STATE_BACKSLASH; // INFO: This will later overwrite the backslash - te--; + ctx.te--; break; } - if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) { + if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.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)[ctx.li]->items[ctx.lii]->is_text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + if (strlen((*lines)[ctx.li]->items[ctx.lii]->u.text->text) == 0) { + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + if (ctx.lii == 0) { if ( - !(*lines)[li]->text_above && - (*lines)[li]->btype == BT_LINE + !(*lines)[ctx.li]->text_above && + (*lines)[ctx.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(); + free((*lines)[ctx.li]->items); + free((*lines)[ctx.li]); + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); break; } } } else { - ly++; + ctx.lii++; } } else { - ly++; + ctx.lii++; } - (*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(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = NULL; + ctx.lii = 0; + ctx.te = 0; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = NULL; + ctx.lia = 0; + ctx.li++; + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = cho_line_new(); + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = 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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = c; + ctx.te++; break; } case STATE_MARKUP_TAG: { - if (buf == '/') { - state = STATE_MARKUP_TAG_END; + if (c == '/') { + ctx.state = STATE_MARKUP_TAG_END; break; } - ta++; - tags = erealloc(tags, (ta+1) * sizeof(struct Tag *)); - tags[ta] = cho_tag_new(); - state = STATE_MARKUP_TAG_START; + ctx.ta++; + ctx.tags = erealloc(ctx.tags, (ctx.ta+1) * sizeof(struct Tag *)); + ctx.tags[ctx.ta] = cho_tag_new(); + ctx.state = STATE_MARKUP_TAG_START; if (fseek(fp, -1, SEEK_CUR)) { LOG_DEBUG("fseek failed."); return NULL; @@ -5145,340 +5159,340 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } case STATE_MARKUP_TAG_START: { - if (buf == '>') { - tag_start[t] = 0; - t = 0; + if (c == '>') { + tag_start[ctx.t] = 0; + ctx.t = 0; if (!strcmp(tag_start, "img")) { cho_log(LOG_ERR, "'img' tag has to have at least the 'src' attribute."); return NULL; } - tags[ta]->name = strdup(tag_start); - tag_style = cho_style_parse(tag_start, NULL, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence); + ctx.tags[ctx.ta]->name = strdup(tag_start); + tag_style = cho_style_parse(tag_start, NULL, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; } - tags[ta]->style = tag_style; - switch (state_before_tag) { + ctx.tags[ctx.ta]->style = tag_style; + switch (ctx.state_before_tag) { case STATE_LYRICS: - cho_style_free((*lines)[li]->items[ly]->u.text->style); - (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_copy(tag_style); break; case STATE_CHORD: - cho_style_free((*lines)[li]->text_above[c]->u.chord->style); - (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style = cho_style_copy(tag_style); break; case STATE_ANNOTATION: - if (ann > 0) { - (*lines)[li]->text_above[c]->u.annot->text = erealloc((*lines)[li]->text_above[c]->u.annot->text, (ann+1) * sizeof(char)); - (*lines)[li]->text_above[c]->u.annot->text[ann] = 0; - ann = 0; - c++; - (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *)); - (*lines)[li]->text_above[c] = emalloc(sizeof(struct ChoLineItemAbove)); - (*lines)[li]->text_above[c]->is_chord = false; - (*lines)[li]->text_above[c]->position = text_above_pos; - (*lines)[li]->text_above[c]->u.annot = cho_text_new(); + if (ctx.ann > 0) { + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text = erealloc((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text, (ctx.ann+1) * sizeof(char)); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->text[ctx.ann] = 0; + ctx.ann = 0; + ctx.lia++; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = emalloc(sizeof(struct ChoLineItemAbove)); + (*lines)[ctx.li]->text_above[ctx.lia]->is_chord = false; + (*lines)[ctx.li]->text_above[ctx.lia]->position = ctx.text_above_pos; + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot = cho_text_new(); } - cho_style_free((*lines)[li]->text_above[c]->u.annot->style); - (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style = cho_style_copy(tag_style); break; case STATE_DIRECTIVE_VALUE: - directive_has_tag = true; + ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]); + cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } memset(tag_start, 0, strlen(tag_start)); - state = state_before_tag; + ctx.state = ctx.state_before_tag; break; } - if (is_whitespace(buf)) { - tag_start[t] = 0; - t = 0; - tags[ta]->name = strdup(tag_start); - tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *)); - tags[ta]->attrs[at] = cho_tag_attr_new(); - state = STATE_MARKUP_ATTR_NAME; + if (is_whitespace(c)) { + tag_start[ctx.t] = 0; + ctx.t = 0; + ctx.tags[ctx.ta]->name = strdup(tag_start); + ctx.tags[ctx.ta]->attrs = erealloc(ctx.tags[ctx.ta]->attrs, (ctx.at+1) * sizeof(struct Attr *)); + ctx.tags[ctx.ta]->attrs[ctx.at] = cho_tag_attr_new(); + ctx.state = STATE_MARKUP_ATTR_NAME; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_MARKUP_TAG_START; - state = STATE_BACKSLASH; - t--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_MARKUP_TAG_START; + ctx.state = STATE_BACKSLASH; + ctx.t--; break; } cho_log(LOG_ERR, "Newline character inside a tag name is invalid."); return NULL; } - if (t == 5) { + if (ctx.t == 5) { cho_log(LOG_ERR, "Start tag name is too long."); return NULL; } - tag_start[t] = buf; - t++; + tag_start[ctx.t] = c; + ctx.t++; break; } case STATE_MARKUP_TAG_END: { - if (buf == '>') { - tag_end[t] = 0; - t = 0; - if (!cho_tag_close_last_unclosed(tag_end, tags, ta)) { + if (c == '>') { + tag_end[ctx.t] = 0; + ctx.t = 0; + if (!cho_tag_close_last_unclosed(tag_end, ctx.tags, ctx.ta)) { LOG_DEBUG("cho_tag_close_last_unclosed failed."); return NULL; } memset(tag_end, 0, strlen(tag_end)); - state = state_before_tag; + ctx.state = ctx.state_before_tag; break; } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_MARKUP_TAG_END; - state = STATE_BACKSLASH; - t--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_MARKUP_TAG_END; + ctx.state = STATE_BACKSLASH; + ctx.t--; break; } cho_log(LOG_ERR, "Newline character inside a tag name is invalid."); return NULL; } - if (t == 5) { + if (ctx.t == 5) { cho_log(LOG_ERR, "End tag name is too long."); return NULL; } - tag_end[t] = buf; - t++; + tag_end[ctx.t] = c; + ctx.t++; break; } case STATE_MARKUP_ATTR_NAME: { - if (buf == '=') { - tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); - tags[ta]->attrs[at]->name[atn] = 0; - atn = 0; - state = STATE_MARKUP_ATTR_VALUE; + if (c == '=') { + ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; + ctx.atn = 0; + ctx.state = STATE_MARKUP_ATTR_VALUE; break; } - if (is_whitespace(buf)) { - if (at == 0) { - if (!tags[ta]->attrs[at]->name) { + if (is_whitespace(c)) { + if (ctx.at == 0) { + if (!ctx.tags[ctx.ta]->attrs[ctx.at]->name) { break; } else { - tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); - tags[ta]->attrs[at]->name[atn] = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start); + ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } } - if (tags[ta]->attrs[at-1]->name && tags[ta]->attrs[at-1]->value) { + if (ctx.tags[ctx.ta]->attrs[ctx.at-1]->name && ctx.tags[ctx.ta]->attrs[ctx.at-1]->value) { break; } - if (!tags[ta]->attrs[at-1]->name && !tags[ta]->attrs[at-1]->value) { + if (!ctx.tags[ctx.ta]->attrs[ctx.at-1]->name && !ctx.tags[ctx.ta]->attrs[ctx.at-1]->value) { break; } - tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); - tags[ta]->attrs[at]->name[atn] = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start); + ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } - if (buf == '>') { - if (tags[ta]->attrs[at-1]->value) { - cho_tag_attr_free(tags[ta]->attrs[at]); - tags[ta]->attrs[at] = NULL; - atn = 0; - if (!strcmp(tags[ta]->name, "img")) { - cho_text_free((*lines)[li]->items[ly]->u.text); - (*lines)[li]->items[ly]->is_text = false; - image = cho_image_tag_parse(tags[ta]->attrs); + if (c == '>') { + if (ctx.tags[ctx.ta]->attrs[ctx.at-1]->value) { + cho_tag_attr_free(ctx.tags[ctx.ta]->attrs[ctx.at]); + ctx.tags[ctx.ta]->attrs[ctx.at] = NULL; + ctx.atn = 0; + if (!strcmp(ctx.tags[ctx.ta]->name, "img")) { + cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); + (*lines)[ctx.li]->items[ctx.lii]->is_text = false; + image = cho_image_tag_parse(ctx.tags[ctx.ta]->attrs); if (!image) { LOG_DEBUG("cho_image_tag_parse failed."); return NULL; } - (*lines)[li]->items[ly]->u.image = image; - ly++; - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii]->u.image = image; + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } else { - tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence); + tag_style = cho_style_parse(tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; } - tags[ta]->style = tag_style; - switch (state_before_tag) { + ctx.tags[ctx.ta]->style = tag_style; + switch (ctx.state_before_tag) { case STATE_LYRICS: - cho_style_free((*lines)[li]->items[ly]->u.text->style); - (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_copy(tag_style); break; case STATE_CHORD: - cho_style_free((*lines)[li]->text_above[c]->u.chord->style); - (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style = cho_style_copy(tag_style); break; case STATE_ANNOTATION: - cho_style_free((*lines)[li]->text_above[c]->u.annot->style); - (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style = cho_style_copy(tag_style); break; case STATE_DIRECTIVE_VALUE: - directive_has_tag = true; + ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]); + cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } } - at = 0; + ctx.at = 0; memset(tag_start, 0, strlen(tag_start)); - state = state_before_tag; + ctx.state = ctx.state_before_tag; break; } else { - tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); - tags[ta]->attrs[at]->name[atn] = 0; - atn = 0; - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start); + ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = 0; + ctx.atn = 0; + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } } - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_MARKUP_ATTR_NAME; - state = STATE_BACKSLASH; - atn--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_MARKUP_ATTR_NAME; + ctx.state = STATE_BACKSLASH; + ctx.atn--; break; } cho_log(LOG_ERR, "Newline character inside an tag attribute name is invalid."); return NULL; } - tags[ta]->attrs[at]->name = erealloc(tags[ta]->attrs[at]->name, (atn+1) * sizeof(char)); - tags[ta]->attrs[at]->name[atn] = buf; - atn++; + ctx.tags[ctx.ta]->attrs[ctx.at]->name = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->name, (ctx.atn+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->name[ctx.atn] = c; + ctx.atn++; break; } case STATE_MARKUP_ATTR_VALUE: { - if (buf == '\n') { - if (prev_buf == '\\') { - state_before_backslash = STATE_MARKUP_ATTR_VALUE; - state = STATE_BACKSLASH; - atv--; + if (c == '\n') { + if (prev_c == '\\') { + ctx.state_before_backslash = STATE_MARKUP_ATTR_VALUE; + ctx.state = STATE_BACKSLASH; + ctx.atv--; break; } cho_log(LOG_ERR, "Newline character inside an attribute value is invalid."); return NULL; } if (avs == -1) { - if (is_whitespace(buf)) { + if (is_whitespace(c)) { cho_log(LOG_ERR, "Whitespace character after equals sign is invalid."); return NULL; } - if (buf == '>') { - cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", tags[ta]->attrs[at]->name, tag_start); + if (c == '>') { + cho_log(LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); return NULL; } - if (buf == '\'') { + if (c == '\'') { avs = AVS_APOSTROPHE; - } else if (buf == '"') { + } else if (c == '"') { avs = AVS_QUOTATION_MARK; } else { avs = AVS_UNQUOTED; - tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char)); - tags[ta]->attrs[at]->value[atv] = buf; - atv++; + ctx.tags[ctx.ta]->attrs[ctx.at]->value = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->value, (ctx.atv+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->value[ctx.atv] = c; + ctx.atv++; } break; } - if (avs == AVS_UNQUOTED && buf == '>') { - tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char)); - tags[ta]->attrs[at]->value[atv] = 0; - atv = 0; - at++; - tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *)); - tags[ta]->attrs[at] = NULL; - if (!strcmp(tags[ta]->name, "img")) { - cho_text_free((*lines)[li]->items[ly]->u.text); - (*lines)[li]->items[ly]->is_text = false; - image = cho_image_tag_parse(tags[ta]->attrs); + if (avs == AVS_UNQUOTED && c == '>') { + ctx.tags[ctx.ta]->attrs[ctx.at]->value = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->value, (ctx.atv+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->value[ctx.atv] = 0; + ctx.atv = 0; + ctx.at++; + ctx.tags[ctx.ta]->attrs = erealloc(ctx.tags[ctx.ta]->attrs, (ctx.at+1) * sizeof(struct Attr *)); + ctx.tags[ctx.ta]->attrs[ctx.at] = NULL; + if (!strcmp(ctx.tags[ctx.ta]->name, "img")) { + cho_text_free((*lines)[ctx.li]->items[ctx.lii]->u.text); + (*lines)[ctx.li]->items[ctx.lii]->is_text = false; + image = cho_image_tag_parse(ctx.tags[ctx.ta]->attrs); if (!image) { LOG_DEBUG("cho_image_tag_parse failed."); return NULL; } - (*lines)[li]->items[ly]->u.image = image; - ly++; - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = cho_line_item_new(); + (*lines)[ctx.li]->items[ctx.lii]->u.image = image; + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(); } else { - tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1), &tags[ta]->style_presence); + tag_style = cho_style_parse(tag_start, ctx.tags[ctx.ta]->attrs, cho_tag_style_inherit(ctx.tags, ctx.ta-1), &ctx.tags[ctx.ta]->style_presence); if (!tag_style) { LOG_DEBUG("cho_style_parse failed."); return NULL; } - tags[ta]->style = tag_style; - switch (state_before_tag) { + ctx.tags[ctx.ta]->style = tag_style; + switch (ctx.state_before_tag) { case STATE_LYRICS: - cho_style_free((*lines)[li]->items[ly]->u.text->style); - (*lines)[li]->items[ly]->u.text->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); + (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_copy(tag_style); break; case STATE_CHORD: - cho_style_free((*lines)[li]->text_above[c]->u.chord->style); - (*lines)[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->style = cho_style_copy(tag_style); break; case STATE_ANNOTATION: - cho_style_free((*lines)[li]->text_above[c]->u.annot->style); - (*lines)[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); + cho_style_free((*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style); + (*lines)[ctx.li]->text_above[ctx.lia]->u.annot->style = cho_style_copy(tag_style); break; case STATE_DIRECTIVE_VALUE: - directive_has_tag = true; + ctx.directive_has_tag = true; break; default: - cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[state_before_tag]); + cho_log(LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); return NULL; } } - at = 0; + ctx.at = 0; avs = -1; memset(tag_start, 0, strlen(tag_start)); - state = state_before_tag; + ctx.state = ctx.state_before_tag; break; } if ( - (avs == AVS_APOSTROPHE && buf == '\'') || - (avs == AVS_QUOTATION_MARK && buf == '"') || - (avs == AVS_UNQUOTED && (buf == ' ' || buf == '\t')) + (avs == AVS_APOSTROPHE && c == '\'') || + (avs == AVS_QUOTATION_MARK && c == '"') || + (avs == AVS_UNQUOTED && (c == ' ' || c == '\t')) ) { - tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char)); - tags[ta]->attrs[at]->value[atv] = 0; - atv = 0; - at++; - tags[ta]->attrs = erealloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *)); - tags[ta]->attrs[at] = cho_tag_attr_new(); + ctx.tags[ctx.ta]->attrs[ctx.at]->value = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->value, (ctx.atv+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->value[ctx.atv] = 0; + ctx.atv = 0; + ctx.at++; + ctx.tags[ctx.ta]->attrs = erealloc(ctx.tags[ctx.ta]->attrs, (ctx.at+1) * sizeof(struct Attr *)); + ctx.tags[ctx.ta]->attrs[ctx.at] = cho_tag_attr_new(); avs = -1; - state = STATE_MARKUP_ATTR_NAME; + ctx.state = STATE_MARKUP_ATTR_NAME; break; } - tags[ta]->attrs[at]->value = erealloc(tags[ta]->attrs[at]->value, (atv+1) * sizeof(char)); - tags[ta]->attrs[at]->value[atv] = buf; - atv++; + ctx.tags[ctx.ta]->attrs[ctx.at]->value = erealloc(ctx.tags[ctx.ta]->attrs[ctx.at]->value, (ctx.atv+1) * sizeof(char)); + ctx.tags[ctx.ta]->attrs[ctx.at]->value[ctx.atv] = c; + ctx.atv++; break; } case STATE_COMMENT: { - if (buf == '\n') { - state = state_before_comment; + if (c == '\n') { + ctx.state = ctx.state_before_comment; break; } break; } case STATE_MAYBE_METADATA_SUBSTITUTION: { - if (buf == '{') { - state = STATE_METADATA_SUBSTITUTION; + if (c == '{') { + ctx.state = STATE_METADATA_SUBSTITUTION; break; } - switch (state_before_metadata_substitution) { + switch (ctx.state_before_metadata_substitution) { case STATE_LYRICS: - (*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++; + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = '%'; + ctx.te++; break; default: } - state = state_before_metadata_substitution; + ctx.state = ctx.state_before_metadata_substitution; if (fseek(fp, -1, SEEK_CUR)) { LOG_DEBUG("fseek failed."); perror("fseek"); @@ -5487,10 +5501,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) break; } case STATE_METADATA_SUBSTITUTION: { - if (buf == '}') { - if (nested_level == 0) { - metadata_substitution[ms] = 0; - ms = 0; + if (c == '}') { + if (ctx.nested_level == 0) { + metadata_substitution[ctx.ms] = 0; + ctx.ms = 0; printf("substitution: '%s'\n", metadata_substitution); /* char *substituted = cho_metadata_substitution_parse( metadata_substitution, @@ -5498,75 +5512,75 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) state_before_metadata_substitution ); */ // Append 'substituted' to whatever text - state = state_before_metadata_substitution; + ctx.state = ctx.state_before_metadata_substitution; break; } - nested_level--; + ctx.nested_level--; } - if (prev_buf == '%' && buf == '{') { - nested_level++; + if (prev_c == '%' && c == '{') { + ctx.nested_level++; } - if (ms > 4094) { + if (ctx.ms > 4094) { cho_log(LOG_ERR, "Metadata substitution can't be greater than 4095 bytes."); return NULL; } - metadata_substitution[ms] = buf; - ms++; + metadata_substitution[ctx.ms] = c; + ctx.ms++; break; } } - prev_buf = buf; + prev_c = c; } else { break; } } int e = 0; - while (e <= ta) { - cho_tag_free(tags[e]); + while (e <= ctx.ta) { + cho_tag_free(ctx.tags[e]); e++; } - free(tags); - if ((*lines)[li]->items[ly]->is_text) { - if ((*lines)[li]->items[ly]->u.text->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; - ly++; - (*lines)[li]->items = erealloc((*lines)[li]->items, (ly+1) * sizeof(struct ChoLineItem *)); - (*lines)[li]->items[ly] = NULL; - (*lines)[li]->text_above = erealloc((*lines)[li]->text_above, (c+1) * sizeof(struct ChoLineItemAbove *)); - (*lines)[li]->text_above[c] = NULL; - li++; - *lines = erealloc(*lines, (li+1) * sizeof(struct ChoLine *)); - (*lines)[li] = NULL; + free(ctx.tags); + if ((*lines)[ctx.li]->items[ctx.lii]->is_text) { + if ((*lines)[ctx.li]->items[ctx.lii]->u.text->text) { + (*lines)[ctx.li]->items[ctx.lii]->u.text->text = erealloc((*lines)[ctx.li]->items[ctx.lii]->u.text->text, (ctx.te+1) * sizeof(char)); + (*lines)[ctx.li]->items[ctx.lii]->u.text->text[ctx.te] = 0; + ctx.lii++; + (*lines)[ctx.li]->items = erealloc((*lines)[ctx.li]->items, (ctx.lii+1) * sizeof(struct ChoLineItem *)); + (*lines)[ctx.li]->items[ctx.lii] = NULL; + (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItemAbove *)); + (*lines)[ctx.li]->text_above[ctx.lia] = NULL; + ctx.li++; + *lines = erealloc(*lines, (ctx.li+1) * sizeof(struct ChoLine *)); + (*lines)[ctx.li] = NULL; } else { - cho_line_item_free((*lines)[li]->items[ly]); - free((*lines)[li]->items); - free((*lines)[li]->text_above); - free((*lines)[li]); - (*lines)[li] = NULL; + cho_line_item_free((*lines)[ctx.li]->items[ctx.lii]); + free((*lines)[ctx.li]->items); + free((*lines)[ctx.li]->text_above); + free((*lines)[ctx.li]); + (*lines)[ctx.li] = NULL; } } if (!cho_style_reset_default()) { LOG_DEBUG("cho_style_reset_default failed."); return NULL; } - songs[so]->metadata = erealloc(songs[so]->metadata, (m+1) * sizeof(struct ChoMetadata *)); - songs[so]->metadata[m] = NULL; - se++; - songs[so]->sections = erealloc(songs[so]->sections, (se+1) * sizeof(struct ChoSection *)); - songs[so]->sections[se] = NULL; - songs[so]->diagrams = erealloc(songs[so]->diagrams, (dia+1) * sizeof(struct ChordDiagram *)); - songs[so]->diagrams[dia] = NULL; - so++; - songs = erealloc(songs, (so+1) * sizeof(struct ChoSong *)); - songs[so] = NULL; + ctx.songs[ctx.so]->metadata = erealloc(ctx.songs[ctx.so]->metadata, (ctx.m+1) * sizeof(struct ChoMetadata *)); + ctx.songs[ctx.so]->metadata[ctx.m] = NULL; + ctx.se++; + ctx.songs[ctx.so]->sections = erealloc(ctx.songs[ctx.so]->sections, (ctx.se+1) * sizeof(struct ChoSection *)); + ctx.songs[ctx.so]->sections[ctx.se] = NULL; + ctx.songs[ctx.so]->diagrams = erealloc(ctx.songs[ctx.so]->diagrams, (ctx.dia+1) * sizeof(struct ChordDiagram *)); + ctx.songs[ctx.so]->diagrams[ctx.dia] = NULL; + ctx.so++; + ctx.songs = erealloc(ctx.songs, (ctx.so+1) * sizeof(struct ChoSong *)); + ctx.songs[ctx.so] = NULL; g_current_ttype = TT_TEXT; g_prev_ttype = TT_TEXT; g_config = NULL; g_chordpro_filepath = NULL; - free(g_transpose_history); - g_transpose_history = NULL; - g_transpose = NULL; + free(ctx.transpose_history); + ctx.transpose_history = NULL; + ctx.transpose = NULL; g_line_number = 1; for (e = 0; e<g_ia; e++) { cho_image_free(g_image_assets[e]); @@ -5575,12 +5589,12 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) g_image_assets = NULL; g_ia = 0; bool exist_title = false; - for (so = 0; songs[so]; so++) { - for (m = 0; songs[so]->metadata[m]; m++) { + for (ctx.so = 0; ctx.songs[ctx.so]; ctx.so++) { + for (ctx.m = 0; ctx.songs[ctx.so]->metadata[ctx.m]; ctx.m++) { if ( - !strcmp(songs[so]->metadata[m]->name, "title") && - songs[so]->metadata[m]->value && - strcmp(songs[so]->metadata[m]->value, "") != 0 + !strcmp(ctx.songs[ctx.so]->metadata[ctx.m]->name, "title") && + ctx.songs[ctx.so]->metadata[ctx.m]->value && + strcmp(ctx.songs[ctx.so]->metadata[ctx.m]->value, "") != 0 ) { exist_title = true; } @@ -5593,7 +5607,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) } exist_title = false; } - return songs; + return ctx.songs; } #ifdef DEBUG diff --git a/src/chordpro.h b/src/chordpro.h @@ -129,6 +129,42 @@ struct Tag { bool is_closed; }; +struct ChoContext { + bool is_chord_already_initialized; + bool is_maybe_end_of_tab_directive; + bool directive_has_tag; + enum State state; + enum State state_before_comment; + enum State state_before_tag; + enum State state_before_backslash; + enum State state_before_metadata_substitution; + index_t ann; // annotation + index_t at; // struct Attr + index_t atn; // struct Attr.name + index_t atv; // struct Attr.value + index_t ch; // struct ChoChord + index_t dia; // struct ChordDiagram + index_t dn; // char directive_name + index_t dv; // char directive_value + index_t li; // struct ChoLine + index_t lia; // struct ChoLineItemAbove + index_t lii; // struct ChoLineItem + index_t m; // struct ChoMetadata + index_t ms; // metadata_substitution + index_t se; // struct ChoSection + index_t so; // struct ChoSong + index_t t; // char tag_start/tag_end + index_t ta; // struct Tag + index_t te; // struct ChoText + index_t th; // transpose_history + int text_above_pos; + int nested_level; + int *transpose_history; + int *transpose; + struct ChoSong **songs; + struct Tag **tags; +}; + void cho_log_enable_info_logs(void); struct ChoSong **cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config); diff --git a/src/types.h b/src/types.h @@ -3,6 +3,9 @@ #ifndef _TYPES_H_ #define _TYPES_H_ +// used as an index in an array +typedef int index_t; + enum TextType : int8_t { TT_CHORD, TT_ANNOT,