lorid

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

commit 84d3e643712b914f2c74244dcaf72f876ec2133b
parent 6b9e0a31f4ba113e1d99921344c2eab1d28bd3f4
Author: nibo <nibo@relim.de>
Date:   Fri,  1 Aug 2025 18:00:33 +0200

Remove by accident added file src/some.c

Diffstat:
Dsrc/some.c | 1715-------------------------------------------------------------------------------
1 file changed, 0 insertions(+), 1715 deletions(-)

diff --git a/src/some.c b/src/some.c @@ -1,1715 +0,0 @@ -{ - enum AttrValueSyntax avs = ATTRIBUTE_VALUE_SYNTAX_UNINITIALIZED; - enum GridToken token; - struct Attr **directive_attrs = NULL; - struct ChoStyle *tag_style; - struct StyleProperty sprop; - struct ChoChord *tmp_chord; - struct ChoSection *chorus; - struct ChoImage *image; - struct ChordDiagram *diagram; - struct ChoDirective *directive = NULL; - struct ChoMetadata *metadata = NULL; - struct ChoLine ***lines; - struct ChoContext ctx; - bool err; - char *metadata_value, *shape; - char *stripped_directive_value = NULL; - char *label = NULL; - char directive_name[128]; - char directive_value[4096]; - char chord[CHORD_LEN]; - char tag_start[6]; - char tag_end[6]; - char custom_directive[64]; - char metadata_substitution[4096]; - char grid_token[CHORD_LEN]; - char c = 0; - char prev_c = '\n'; - int transpose; - - if (!cho_context_init(&ctx, config, chordpro_filepath)) { - LOG_DEBUG("cho_context_init failed."); - return NULL; - } - - 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); - ctx.songs[ctx.so]->present_text_types[TEXT_TYPE_TOC] = config->output->toc->show; - for (; *str; str++) { - c = *str; - // printf("state: %s, c: %c\n", state_enums[ctx.state], c); - if (c == '\r') { - continue; - } - switch (ctx.state) { - case STATE_LYRICS: { - if (prev_c == '\n' && c == '#') { - ctx.state_before_comment = STATE_LYRICS; - ctx.state = STATE_COMMENT; - break; - } - if (prev_c == '\n' && c == '{') { - ctx.state = STATE_DIRECTIVE_NAME; - break; - } - if (c == '[') { - ctx.state = STATE_CHORD; - break; - } - 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 { - ctx.lii++; - } - } else { - ctx.lii++; - } - 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); - ctx.state_before_tag = STATE_LYRICS; - ctx.state = STATE_MARKUP_TAG; - break; - } - if (c == '%') { - ctx.state_before_metadata_substitution = STATE_LYRICS; - ctx.state = STATE_MAYBE_METADATA_SUBSTITUTION; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_LYRICS; - ctx.state = STATE_BACKSLASH; - ctx.te--; // INFO: This will later overwrite the backslash - break; - } - if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.ta]->name, "img")) { - // TODO: This seems to be unreachable - cho_log(&ctx, LOG_ERR, "Tag has to be closed on same line."); - return NULL; - } - 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)[ctx.li]->text_above && - (*lines)[ctx.li]->btype == BREAK_TYPE_LINE - ) { - 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(&ctx); - break; - } - } - } else { - ctx.lii++; - } - } else { - 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; - 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(&ctx); - break; - } - (*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(c)) { - str--; - ctx.state = ctx.state_before_backslash; - break; - } - break; - } - case STATE_DIRECTIVE_NAME: { - if (c == '}') { - directive_name[ctx.dn] = 0; - ctx.dn = 0; - directive = cho_directive_parse(&ctx, directive_name); - /* printf( - "directive: '%s'\ndtype: %s, stype: %s, position: %s\n", - directive_name, cho_debug_dtype(directive->dtype), cho_debug_the_stype(directive->stype), cho_debug_the_pos(directive->position) - ); */ - switch (directive->dtype) { - case DIRECTIVE_TYPE_ENVIRONMENT: { - ctx.current_ttype = directive->ttype; - switch (directive->position) { - case POSITION_START: { - if (directive->stype == SECTION_TYPE_CUSTOM) { - memset(custom_directive, 0, sizeof(custom_directive)); - strcpy(custom_directive, &directive_name[9]); - } - 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)[ctx.li] = cho_line_new(); - (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); - ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; - switch (directive->stype) { - case SECTION_TYPE_TAB: - ctx.state = STATE_TAB; - break; - case SECTION_TYPE_GRID: - ctx.state = STATE_GRID; - break; - default: - ctx.state = STATE_LYRICS; - } - break; - } - case POSITION_END: { - if (directive->stype == ctx.songs[ctx.so]->sections[ctx.se]->type) { - if (directive->stype == SECTION_TYPE_CUSTOM) { - if (strcmp(custom_directive, &directive_name[7]) != 0) { - break; - } - } - if (directive->stype == SECTION_TYPE_GRID) { - ctx.grid.bar_line_symbol_count = 0; - ctx.grid.tokens_per_cell = 0; - ctx.grid.expected_tokens_per_cell = 0; - } - 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)[ctx.li] = cho_line_new(); - (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); - ctx.state = STATE_LYRICS; - } else { - const char *section_type = section_types[directive->stype]; - if (section_type[0] == 0) { - cho_log(&ctx, LOG_ERR, "Can't close a section that wasn't opened earlier."); - } else { - cho_log(&ctx, LOG_ERR, "Can't close a %s section that wasn't opened earlier.", section_type); - } - goto ERR; - } - break; - } - case POSITION_NO: { - /* INFO: {chorus} */ - chorus = cho_find_previous_chorus(ctx.songs[ctx.so]->sections, ctx.se); - if (chorus) { - if (config->output->chorus->quote) { - 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.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)[ctx.li] = cho_line_new(); - (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); - } else { - if (chorus->label) { - label = strdup(chorus->label->text); - } else { - label = strdup(config->output->chorus->label); - } - 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 { - ctx.lii++; - } - } else { - 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(&ctx); - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - ctx.current_ttype = TEXT_TYPE_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; - ctx.te += strlen(label); - } - } else { - if (config->output->chorus->quote) { - cho_log(&ctx, LOG_WARN, "Can't quote chorus because it's not defined previously."); - } - label = strdup(config->output->chorus->label); - 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 { - ctx.lii++; - } - } else { - 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(&ctx); - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - ctx.current_ttype = TEXT_TYPE_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = label; - ctx.te += strlen(label); - } - break; - } - } - break; - } - case DIRECTIVE_TYPE_METADATA: - cho_log(&ctx, LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); - break; - case DIRECTIVE_TYPE_FORMATTING: - cho_log(&ctx, LOG_WARN, "Formatting directive '%s' has no value.", directive_name); - break; - case DIRECTIVE_TYPE_IMAGE: - cho_log(&ctx, LOG_ERR, "Directive 'image' has no value."); - goto ERR; - case DIRECTIVE_TYPE_PREAMBLE: { - // INFO: The only preamble directive is 'new_song' - 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."); - goto ERR; - } - for (int e = 0; e<ctx.ia; e++) { - cho_image_free(ctx.image_assets[e]); - } - free(ctx.image_assets); - ctx.image_assets = NULL; - ctx.ia = 0; - ctx.so++; - ctx.songs = erealloc(ctx.songs, (ctx.so+1) * sizeof(struct ChoSong *)); - ctx.songs[ctx.so] = cho_song_new(&ctx); - if (!ctx.songs[ctx.so]) { - LOG_DEBUG("cho_song_new failed."); - goto ERR; - } - free(ctx.transpose_history); - ctx.th = 0; - 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.se = 0; - ctx.li = 0; - ctx.lii = 0; - // ctx.m = 0; - 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(&ctx); - break; - } - case DIRECTIVE_TYPE_FONT: { - sprop.ttype = directive->ttype; - sprop.type = directive->sprop; - switch (directive->sprop) { - case STYLE_PROPERTY_TYPE_FONT: - sprop.u.font_name = NULL; - break; - case STYLE_PROPERTY_TYPE_SIZE: - sprop.u.font_size = EMPTY_DOUBLE; - break; - case STYLE_PROPERTY_TYPE_COLOR: - sprop.u.foreground_color = NULL; - break; - } - if (!cho_style_change_default(sprop)) { - LOG_DEBUG("cho_style_change_default failed."); - goto ERR; - } - break; - } - case DIRECTIVE_TYPE_CHORD: { - switch (directive->ctype) { - case CHORD_DIRECTIVE_TRANSPOSE: - ctx.transpose--; - ctx.th--; - break; - case CHORD_DIRECTIVE_DEFINE: - cho_log(&ctx, LOG_WARN, "Ignoring chord directive '%s' because it has no value.", directive_name); - break; - } - break; - } - case DIRECTIVE_TYPE_OUTPUT: - (*lines)[ctx.li]->btype = directive->btype; - break; - case DIRECTIVE_TYPE_EXTENSION: - // INFO: Such a directive should not be logged. - break; - case DIRECTIVE_TYPE_CUSTOM: - cho_log(&ctx, LOG_INFO, "Ignoring custom directive '%s'.", directive_name); - break; - } - cho_directive_free(directive); - directive = NULL; - break; - } - if (c == '{') { - cho_log(&ctx, LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); - goto ERR; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_DIRECTIVE_NAME; - ctx.state = STATE_BACKSLASH; - ctx.dn--; - break; - } - cho_log(&ctx, LOG_ERR, "Can't have a newline in a directive name."); - goto ERR; - } - if (c == ':' || c == ' ') { - directive_name[ctx.dn] = 0; - ctx.dn = 0; - ctx.state = STATE_DIRECTIVE_VALUE; - break; - } - directive_name[ctx.dn] = c; - ctx.dn++; - break; - } - case STATE_DIRECTIVE_VALUE: { - if (c == '}') { - directive_value[ctx.dv] = 0; - ctx.dv = 0; - stripped_directive_value = str_remove_leading_whitespace(directive_value); - directive = cho_directive_parse(&ctx, directive_name); - /* printf( - "directive: '%s'\ndtype: %s, stype: %s, position: %s\n", - directive_name, dtype(directive->dtype), the_stype(directive->stype), pos(directive->position) - ); */ - switch (directive->dtype) { - case DIRECTIVE_TYPE_ENVIRONMENT: { - if (strlen(stripped_directive_value) > 0) { - ctx.songs[ctx.so]->present_text_types[TEXT_TYPE_LABEL] = true; - } - ctx.current_ttype = directive->ttype; - switch (directive->position) { - case POSITION_START: { - if (directive->stype == SECTION_TYPE_CUSTOM) { - memset(custom_directive, 0, sizeof(custom_directive)); - strcpy(custom_directive, &directive_name[9]); - } - 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; - - if (strchr(stripped_directive_value, '=')) { - directive_attrs = cho_attrs_parse(&ctx, stripped_directive_value, directive_name); - if (!directive_attrs) { - LOG_DEBUG("cho_attrs_parse failed."); - goto ERR; - } - label = cho_attrs_get(directive_attrs, "label"); - if (directive->stype == SECTION_TYPE_GRID) { - shape = cho_attrs_get(directive_attrs, "shape"); - if (shape) { - if (!cho_grid_shape_parse_and_set(&ctx, shape)) { - LOG_DEBUG("cho_grid_parse_and_set_shape failed."); - goto ERR; - } - } - } - } else { - if (directive->stype == SECTION_TYPE_GRID) { - int index = str_index_of(stripped_directive_value, ' '); - if (index != -1) { - stripped_directive_value[index] = 0; - label = &stripped_directive_value[index+1]; - } - if (!cho_grid_shape_parse_and_set(&ctx, stripped_directive_value)) { - LOG_DEBUG("cho_grid_parse_and_set_shape failed."); - goto ERR; - } - } else { - label = stripped_directive_value; - } - } - if (label) { - ctx.songs[ctx.so]->sections[ctx.se]->label = emalloc(sizeof(struct ChoText)); - ctx.songs[ctx.so]->sections[ctx.se]->label->text = strdup(label); - ctx.prev_ttype = ctx.current_ttype; - ctx.current_ttype = TEXT_TYPE_LABEL; - ctx.songs[ctx.so]->sections[ctx.se]->label->style = cho_style_new_default(&ctx); - ctx.current_ttype = ctx.prev_ttype; - label = NULL; - } - cho_tag_attrs_free(directive_attrs); - directive_attrs = NULL; - 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; - } - ctx.li = 0; - lines = &ctx.songs[ctx.so]->sections[ctx.se]->lines; - *lines = emalloc(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(&ctx); - ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; - break; - } - case POSITION_END: { - cho_log(&ctx, LOG_ERR, "A directive that closes a section can't have arguments."); - goto ERR; - } - case POSITION_NO: { - /* INFO: {chorus: ...} */ - label = strdup(stripped_directive_value); - chorus = cho_find_previous_chorus(ctx.songs[ctx.so]->sections, ctx.se); - if (chorus) { - if (config->output->chorus->quote) { - 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.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)[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 { - ctx.current_ttype = TEXT_TYPE_LABEL; - ctx.songs[ctx.so]->sections[ctx.se]->label = cho_text_new(&ctx); - ctx.songs[ctx.so]->sections[ctx.se]->label->text = 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; - } - 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)[ctx.li] = cho_line_new(); - (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); - } else { - 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 { - ctx.lii++; - } - } else { - 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(&ctx); - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - ctx.current_ttype = TEXT_TYPE_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*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; - } - ctx.te += strlen(label); - } - } else { - if (config->output->chorus->quote) { - cho_log(&ctx, LOG_WARN, "Can't quote chorus because it's not defined previously."); - } - 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 { - ctx.lii++; - } - } else { - 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(&ctx); - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - ctx.current_ttype = TEXT_TYPE_LABEL; - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*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.te += strlen(label); - } - break; - } - } - break; - } - case DIRECTIVE_TYPE_METADATA: { - metadata_value = strdup(stripped_directive_value); - if (strlen(metadata_value) == 0) { - cho_log(&ctx, LOG_WARN, "Ignoring metadata directive '%s' because it has no value.", directive_name); - free(metadata_value); - break; - } - switch (directive->meta) { - case METADATA_DIRECTIVE_TITLE: - 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); - 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[TEXT_TYPE_TITLE] = true; - break; - case METADATA_DIRECTIVE_SUBTITLE: - 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); - 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[TEXT_TYPE_SUBTITLE] = true; - break; - case METADATA_DIRECTIVE_OTHER: { - if (!strcmp(directive_name, "meta")) { - metadata = cho_metadata_split(&ctx, directive_value); - if (!metadata) { - LOG_DEBUG("cho_metadata_split failed."); - goto ERR; - } - 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 { - 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); - ctx.songs[ctx.so]->metadata[ctx.m]->name = strdup(directive_name); - ctx.songs[ctx.so]->metadata[ctx.m]->value = metadata_value; - } - } - } - 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; - } - ctx.m++; - break; - } - case DIRECTIVE_TYPE_FORMATTING: { - 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 { - ctx.lii++; - } - } else { - 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(&ctx); - 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; - } - ctx.te += strlen(stripped_directive_value); - ctx.songs[ctx.so]->present_text_types[directive->ttype] = true; - break; - } - case DIRECTIVE_TYPE_IMAGE: { - if (strchr(directive_value, '=')) { - image = cho_image_directive_parse(&ctx, directive_value); - if (!image) { - LOG_DEBUG("cho_image_directive_parse failed."); - goto ERR; - } - } else { - image = cho_image_new(); - image->src = strdup(stripped_directive_value); - } - if (image->is_asset) { - ctx.image_assets = erealloc(ctx.image_assets, (ctx.ia+1) * sizeof(struct ChoImage *)); - ctx.image_assets[ctx.ia] = image; - ctx.ia++; - } else { - 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; - } - 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(&ctx); - 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; - } - case DIRECTIVE_TYPE_PREAMBLE: - cho_log(&ctx, LOG_ERR, "Preamble directive '%s' can't have a value.", directive_name); - goto ERR; - case DIRECTIVE_TYPE_FONT: { - sprop.ttype = directive->ttype; - char *dir_value = strdup(stripped_directive_value); - switch (directive->sprop) { - case STYLE_PROPERTY_TYPE_FONT: - sprop.u.font_name = emalloc((strlen(dir_value)+1) * sizeof(char)); - strcpy(sprop.u.font_name, dir_value); - sprop.type = STYLE_PROPERTY_TYPE_FONT; - break; - case STYLE_PROPERTY_TYPE_SIZE: - sprop.u.font_size = strtod(dir_value, NULL); - if (sprop.u.font_size == 0.0) { - cho_log(&ctx, LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); - goto ERR; - } - sprop.type = STYLE_PROPERTY_TYPE_SIZE; - break; - case STYLE_PROPERTY_TYPE_COLOR: - sprop.u.foreground_color = cho_color_parse(dir_value); - if (sprop.u.foreground_color == NULL) { - cho_log(&ctx, LOG_ERR, "Font directive '%s' has an invalid value.", directive_name); - goto ERR; - } - sprop.type = STYLE_PROPERTY_TYPE_COLOR; - break; - default: - cho_log(&ctx, LOG_ERR, "Invalid style property type '%d'.", directive->sprop); - goto ERR; - } - if (!cho_style_change_default(sprop)) { - LOG_DEBUG("cho_style_change_default failed."); - goto ERR; - } - if (sprop.type == STYLE_PROPERTY_TYPE_FONT) { - free(sprop.u.font_name); - } else if (sprop.type == STYLE_PROPERTY_TYPE_COLOR) { - free(sprop.u.foreground_color); - } - free(dir_value); - break; - } - case DIRECTIVE_TYPE_CHORD: { - switch (directive->ctype) { - case CHORD_DIRECTIVE_TRANSPOSE: - if (!transposition_parse(directive_value, &transpose)) { - LOG_DEBUG("transposition_parse failed."); - cho_log(&ctx, LOG_ERR, "Directive 'transpose' has an invalid value."); - goto ERR; - } - 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 CHORD_DIRECTIVE_DEFINE: - diagram = cho_chord_diagram_parse(&ctx, directive_value, ctx.songs[ctx.so]->diagrams, ctx.dia); - if (!diagram) { - LOG_DEBUG("cho_chord_diagram_parse failed."); - goto ERR; - } - // debug_chord_diagram_print(diagram); - 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; - } - case DIRECTIVE_TYPE_OUTPUT: - cho_log(&ctx, LOG_ERR, "Directive '%s' can't have a value.", directive_name); - goto ERR; - case DIRECTIVE_TYPE_EXTENSION: - // INFO: Such a directive should not be logged. - break; - case DIRECTIVE_TYPE_CUSTOM: - cho_log(&ctx, LOG_INFO, "Ignoring custom directive '%s'.", directive_name); - break; - } - switch (directive->stype) { - case SECTION_TYPE_TAB: - ctx.state = STATE_TAB; - break; - case SECTION_TYPE_GRID: - ctx.state = STATE_GRID; - break; - default: - ctx.state = STATE_LYRICS; - } - memset(directive_value, 0, strlen(directive_value)); - free(stripped_directive_value); - stripped_directive_value = NULL; - cho_directive_free(directive); - directive = NULL; - break; - } - if (c == '%') { - ctx.state_before_metadata_substitution = STATE_DIRECTIVE_VALUE; - ctx.state = STATE_MAYBE_METADATA_SUBSTITUTION; - break; - } - if (c == '<') { - ctx.state_before_tag = STATE_DIRECTIVE_VALUE; - ctx.state = STATE_MARKUP_TAG; - break; - } - if (c == '{') { - cho_log(&ctx, LOG_ERR, "Can't start a new directive if the previous one is not yet closed."); - goto ERR; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_DIRECTIVE_VALUE; - ctx.state = STATE_BACKSLASH; - ctx.dv--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside a directive value is invalid."); - goto ERR; - } - if (ctx.dv > 4094) { - cho_log(&ctx, LOG_ERR, "Directive value can't be greater than 4095 bytes."); - goto ERR; - } - directive_value[ctx.dv] = c; - ctx.dv++; - break; - } - case STATE_CHORD: { - if (c == ']') { - chord[ctx.ch] = 0; - ctx.ch = 0; - ctx.prev_ttype = ctx.current_ttype; - ctx.current_ttype = TEXT_TYPE_CHORD; - 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(&ctx, LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); - } - cho_chord_free(tmp_chord); - ctx.is_chord_already_initialized = false; - } else { - (*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(&ctx, LOG_INFO, "Didn't recognize the chord '%s'.", (*lines)[ctx.li]->text_above[ctx.lia]->u.chord->name); - } - } - ctx.songs[ctx.so]->present_text_types[TEXT_TYPE_CHORD] = true; - memset(chord, 0, strlen(chord)); - ctx.lia++; - ctx.current_ttype = ctx.prev_ttype; - ctx.state = STATE_LYRICS; - break; - } - if (prev_c == '[' && c == '*') { - ctx.prev_ttype = ctx.current_ttype; - ctx.current_ttype = TEXT_TYPE_ANNOT; - (*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); - ctx.state = STATE_ANNOTATION; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_CHORD; - ctx.state = STATE_BACKSLASH; - ctx.ch--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside a chord is invalid."); - goto ERR; - } - if (c == '[') { - cho_log(&ctx, LOG_ERR, "Can't start a new chord/annotation if the previous one is not yet closed."); - goto ERR; - } - 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); - ctx.is_chord_already_initialized = true; - } - ctx.state_before_tag = STATE_CHORD; - ctx.state = STATE_MARKUP_TAG; - break; - } - if (ctx.ch > CHORD_LEN-2) { - cho_log(&ctx, LOG_ERR, "Chord can't be greater than %d bytes.", CHORD_LEN-1); - goto ERR; - } - chord[ctx.ch] = c; - ctx.ch++; - break; - } - case STATE_ANNOTATION: { - 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[TEXT_TYPE_ANNOT] = true; - ctx.ann = 0; - ctx.lia++; - ctx.current_ttype = ctx.prev_ttype; - ctx.state = STATE_LYRICS; - break; - } - if (c == '<') { - ctx.state_before_tag = STATE_ANNOTATION; - ctx.state = STATE_MARKUP_TAG; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_ANNOTATION; - ctx.state = STATE_BACKSLASH; - ctx.ann--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside an annotation is invalid."); - goto ERR; - } - (*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_c == '\n' && c == '#') { - ctx.state_before_comment = STATE_TAB; - ctx.state = STATE_COMMENT; - break; - } - 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)[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)[ctx.li] = cho_line_new(); - (*lines)[ctx.li]->items = emalloc(sizeof(struct ChoLineItem *)); - (*lines)[ctx.li]->items[ctx.lii] = cho_line_item_new(&ctx); - ctx.current_ttype = TEXT_TYPE_TEXT; - ctx.state = STATE_LYRICS; - break; - } else { - (*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++, 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)[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 (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++, 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)[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[ctx.dn] = c; - ctx.dn++; - break; - } - if (prev_c == '\n' && c == '{') { - ctx.is_maybe_end_of_tab_directive = true; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_TAB; - ctx.state = STATE_BACKSLASH; - // INFO: This will later overwrite the backslash - ctx.te--; - break; - } - if (ctx.ta > -1 && !ctx.tags[ctx.ta]->is_closed && strcmp(ctx.tags[ctx.ta]->name, "img")) { - cho_log(&ctx, LOG_ERR, "Tag has to be closed on same line."); - goto ERR; - } - 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)[ctx.li]->text_above && - (*lines)[ctx.li]->btype == BREAK_TYPE_LINE - ) { - 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(&ctx); - break; - } - } - } else { - ctx.lii++; - } - } else { - 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; - 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(&ctx); - break; - } - (*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_GRID: { - if (prev_c == '\n' && c == '#') { - ctx.state_before_comment = STATE_GRID; - ctx.state = STATE_COMMENT; - break; - } - if (prev_c == '\n' && c == '{') { - ctx.state = STATE_DIRECTIVE_NAME; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c != '}') { - grid_token[ctx.gt] = 0; - ctx.gt = 0; - if (grid_token[0] == 0) { - break; - } - token = cho_grid_token_parse(&ctx, grid_token, &err); - if (err) { - cho_log(&ctx, LOG_ERR, "Invalid token '%s' in grid section.", grid_token); - goto ERR; - } - if (token == GRID_TOKEN_BAR_LINE_SYMBOL) { - ctx.grid.bar_line_symbol_count++; - ctx.grid.bar_line_symbol_in_line_count++; - if (ctx.grid.bar_line_symbol_count == 2) { - ctx.grid.expected_tokens_per_cell = ctx.grid.tokens_per_cell; - } else { - if (ctx.grid.bar_line_symbol_in_line_count > 1 && ctx.grid.expected_tokens_per_cell != ctx.grid.tokens_per_cell) { - cho_log( - &ctx, - LOG_ERR, - "Grid cell no. %d has %d tokens but should have %d tokens.", - ctx.grid.bar_line_symbol_in_line_count - 1, - ctx.grid.tokens_per_cell, - ctx.grid.expected_tokens_per_cell - ); - goto ERR; - } - } - ctx.grid.tokens_per_cell = 0; - } else { - ctx.grid.tokens_per_cell++; - } - if (token == GRID_TOKEN_PLACEHOLDER) { - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(" "); - } else { - ctx.prev_ttype = ctx.current_ttype; - ctx.current_ttype = TEXT_TYPE_GRID; - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(grid_token); - ctx.current_ttype = ctx.prev_ttype; - } - 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; - (*lines)[ctx.li]->text_above = erealloc((*lines)[ctx.li]->text_above, (ctx.lia+1) * sizeof(struct ChoLineItem *)); - (*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(&ctx); - ctx.grid.bar_line_symbol_in_line_count = 0; - } - break; - } - if (c == ' ') { - grid_token[ctx.gt] = 0; - ctx.gt = 0; - if (grid_token[0] == 0) { - break; - } - token = cho_grid_token_parse(&ctx, grid_token, &err); - if (err) { - cho_log(&ctx, LOG_ERR, "Invalid token '%s' in grid section.", grid_token); - goto ERR; - } - if (token == GRID_TOKEN_BAR_LINE_SYMBOL) { - ctx.grid.bar_line_symbol_count++; - ctx.grid.bar_line_symbol_in_line_count++; - if (ctx.grid.bar_line_symbol_count == 2) { - ctx.grid.expected_tokens_per_cell = ctx.grid.tokens_per_cell; - } else { - if (ctx.grid.bar_line_symbol_in_line_count > 1 && ctx.grid.expected_tokens_per_cell != ctx.grid.tokens_per_cell) { - cho_log( - &ctx, - LOG_ERR, - "Grid cell no. %d has %d tokens but should have %d tokens.", - ctx.grid.bar_line_symbol_in_line_count - 1, - ctx.grid.tokens_per_cell, - ctx.grid.expected_tokens_per_cell - ); - goto ERR; - } - } - ctx.grid.tokens_per_cell = 0; - } else { - ctx.grid.tokens_per_cell++; - } - if (token == GRID_TOKEN_PLACEHOLDER) { - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(" "); - } else { - ctx.prev_ttype = ctx.current_ttype; - ctx.current_ttype = TEXT_TYPE_GRID; - cho_style_free((*lines)[ctx.li]->items[ctx.lii]->u.text->style); - (*lines)[ctx.li]->items[ctx.lii]->u.text->style = cho_style_new_default(&ctx); - (*lines)[ctx.li]->items[ctx.lii]->u.text->text = strdup(grid_token); - ctx.current_ttype = ctx.prev_ttype; - } - 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(&ctx); - break; - } - grid_token[ctx.gt] = c; - ctx.gt++; - break; - } - case STATE_MARKUP_TAG: { - if (c == '/') { - ctx.state = STATE_MARKUP_TAG_END; - break; - } - 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; - str--; - break; - } - case STATE_MARKUP_TAG_START: { - if (c == '>') { - tag_start[ctx.t] = 0; - ctx.t = 0; - if (!strcmp(tag_start, "img")) { - cho_log(&ctx, LOG_ERR, "'img' tag has to have at least the 'src' attribute."); - goto ERR; - } - ctx.tags[ctx.ta]->name = strdup(tag_start); - tag_style = cho_style_parse(&ctx, 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."); - goto ERR; - } - ctx.tags[ctx.ta]->style = tag_style; - switch (ctx.state_before_tag) { - case STATE_LYRICS: - 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)[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 (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(&ctx); - } - 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: - ctx.directive_has_tag = true; - break; - default: - cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); - goto ERR; - } - memset(tag_start, 0, strlen(tag_start)); - ctx.state = ctx.state_before_tag; - break; - } - 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 (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_MARKUP_TAG_START; - ctx.state = STATE_BACKSLASH; - ctx.t--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside a tag name is invalid."); - goto ERR; - } - if (ctx.t == 5) { - cho_log(&ctx, LOG_ERR, "Start tag name is too long."); - goto ERR; - } - tag_start[ctx.t] = c; - ctx.t++; - break; - } - case STATE_MARKUP_TAG_END: { - if (c == '>') { - tag_end[ctx.t] = 0; - ctx.t = 0; - if (!cho_tag_close_last_unclosed(&ctx, tag_end, ctx.tags, ctx.ta)) { - LOG_DEBUG("cho_tag_close_last_unclosed failed."); - goto ERR; - } - memset(tag_end, 0, strlen(tag_end)); - ctx.state = ctx.state_before_tag; - break; - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_MARKUP_TAG_END; - ctx.state = STATE_BACKSLASH; - ctx.t--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside a tag name is invalid."); - goto ERR; - } - if (ctx.t == 5) { - cho_log(&ctx, LOG_ERR, "End tag name is too long."); - goto ERR; - } - tag_end[ctx.t] = c; - ctx.t++; - break; - } - case STATE_MARKUP_ATTR_NAME: { - 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(c)) { - if (ctx.at == 0) { - if (!ctx.tags[ctx.ta]->attrs[ctx.at]->name) { - break; - } else { - 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(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); - goto ERR; - } - } - if (ctx.tags[ctx.ta]->attrs[ctx.at-1]->name && ctx.tags[ctx.ta]->attrs[ctx.at-1]->value) { - break; - } - if (!ctx.tags[ctx.ta]->attrs[ctx.at-1]->name && !ctx.tags[ctx.ta]->attrs[ctx.at-1]->value) { - break; - } - 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(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); - goto ERR; - } - 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, ctx.tags[ctx.ta]->attrs); - if (!image) { - LOG_DEBUG("cho_image_tag_parse failed."); - goto ERR; - } - (*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(&ctx); - } else { - tag_style = cho_style_parse(&ctx, 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."); - goto ERR; - } - ctx.tags[ctx.ta]->style = tag_style; - switch (ctx.state_before_tag) { - case STATE_LYRICS: - 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)[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)[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: - ctx.directive_has_tag = true; - break; - default: - cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); - goto ERR; - } - } - ctx.at = 0; - memset(tag_start, 0, strlen(tag_start)); - ctx.state = ctx.state_before_tag; - break; - } else { - 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(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); - goto ERR; - } - } - if (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_MARKUP_ATTR_NAME; - ctx.state = STATE_BACKSLASH; - ctx.atn--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside an tag attribute name is invalid."); - goto ERR; - } - 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 (c == '\n') { - ctx.line_no++; - if (prev_c == '\\') { - ctx.state_before_backslash = STATE_MARKUP_ATTR_VALUE; - ctx.state = STATE_BACKSLASH; - ctx.atv--; - break; - } - cho_log(&ctx, LOG_ERR, "Newline character inside an attribute value is invalid."); - goto ERR; - } - if (avs == ATTRIBUTE_VALUE_SYNTAX_UNINITIALIZED) { - if (is_whitespace(c)) { - cho_log(&ctx, LOG_ERR, "Whitespace character after equals sign is invalid."); - goto ERR; - } - if (c == '>') { - cho_log(&ctx, LOG_ERR, "Attribute with name '%s' of tag '%s' has no value.", ctx.tags[ctx.ta]->attrs[ctx.at]->name, tag_start); - goto ERR; - } - if (c == '\'') { - avs = ATTRIBUTE_VALUE_SYNTAX_APOSTROPHE; - } else if (c == '"') { - avs = ATTRIBUTE_VALUE_SYNTAX_QUOTATION_MARK; - } else { - avs = ATTRIBUTE_VALUE_SYNTAX_UNQUOTED; - if (c == '%') { - ctx.state_before_metadata_substitution = STATE_MARKUP_ATTR_VALUE; - ctx.state = STATE_MAYBE_METADATA_SUBSTITUTION; - break; - } - 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 == ATTRIBUTE_VALUE_SYNTAX_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, ctx.tags[ctx.ta]->attrs); - if (!image) { - LOG_DEBUG("cho_image_tag_parse failed."); - goto ERR; - } - (*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(&ctx); - } else { - tag_style = cho_style_parse(&ctx, 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."); - goto ERR; - } - ctx.tags[ctx.ta]->style = tag_style; - switch (ctx.state_before_tag) { - case STATE_LYRICS: - 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)[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)[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: - ctx.directive_has_tag = true; - break; - default: - cho_log(&ctx, LOG_ERR, "Invalid state_before_tag '%s'.", state_enums[ctx.state_before_tag]); - goto ERR; - } - } - ctx.at = 0; - avs = ATTRIBUTE_VALUE_SYNTAX_UNINITIALIZED; - memset(tag_start, 0, strlen(tag_start)); - ctx.state = ctx.state_before_tag; - break; - } - if ( - (avs == ATTRIBUTE_VALUE_SYNTAX_APOSTROPHE && c == '\'') || - (avs == ATTRIBUTE_VALUE_SYNTAX_QUOTATION_MARK && c == '"') || - (avs == ATTRIBUTE_VALUE_SYNTAX_UNQUOTED && (c == ' ' || c == '\t')) - ) { - 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 = ATTRIBUTE_VALUE_SYNTAX_UNINITIALIZED; - ctx.state = STATE_MARKUP_ATTR_NAME; - break; - } - if (c == '%') { - ctx.state_before_metadata_substitution = STATE_MARKUP_ATTR_VALUE; - ctx.state = STATE_MAYBE_METADATA_SUBSTITUTION; - break; - } - 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 (c == '\n') { - ctx.line_no++; - ctx.state = ctx.state_before_comment; - break; - } - break; - } - case STATE_MAYBE_METADATA_SUBSTITUTION: { - if (c == '{') { - metadata_substitution[ctx.ms] = '%'; - ctx.ms++; - metadata_substitution[ctx.ms] = '{'; - ctx.ms++; - ctx.state = STATE_METADATA_SUBSTITUTION; - break; - } - switch (ctx.state_before_metadata_substitution) { - case STATE_LYRICS: - (*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; - case STATE_DIRECTIVE_VALUE: - directive_value[ctx.dv] = '%'; - ctx.dv++; - break; - case STATE_MARKUP_ATTR_VALUE: - 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] = '%'; - break; - default: - } - ctx.state = ctx.state_before_metadata_substitution; - str--; - break; - } - case STATE_METADATA_SUBSTITUTION: { - if (prev_c != '\\' && c == '}') { - if (ctx.nested_level == 0) { - metadata_substitution[ctx.ms] = '}'; - ctx.ms++; - metadata_substitution[ctx.ms] = 0; - ctx.ms = 0; - char *substituted = cho_metadata_substitution_parse( - &ctx, - metadata_substitution, - NULL, - ctx.state_before_metadata_substitution - ); - if (!substituted) { - LOG_DEBUG("cho_metadata_substitution_parse failed."); - goto ERR; - } - char *ch; - switch (ctx.state_before_metadata_substitution) { - case STATE_LYRICS: - for (ch = substituted; *ch; ch++) { - (*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] = *ch; - ctx.te++; - } - break; - case STATE_DIRECTIVE_VALUE: - for (ch = substituted; *ch; ch++) { - directive_value[ctx.dv] = *ch; - ctx.dv++; - } - break; - case STATE_MARKUP_ATTR_VALUE: - for (ch = substituted; *ch; ch++) { - 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] = *ch; - ctx.atv++; - } - break; - default: - } - free(substituted); - ctx.state = ctx.state_before_metadata_substitution; - break; - } - ctx.nested_level--; - } - if (prev_c == '%' && c == '{') { - ctx.nested_level++; - } - if (ctx.ms > 4094) { - cho_log(&ctx, LOG_ERR, "Metadata substitution can't be greater than 4095 bytes."); - goto ERR; - } - metadata_substitution[ctx.ms] = c; - ctx.ms++; - break; - } - } - prev_c = c; - } - if (!cho_style_reset_default()) { - LOG_DEBUG("cho_style_reset_default failed."); - goto ERR; - } - cho_songs_close(&ctx, lines); - cho_context_cleanup(&ctx); - bool exist_title = false; - 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(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; - } - } - if (!exist_title) { - /* INFO: This cho_log() is not line specific. It's a workaround. */ - ctx.line_no = 0; - cho_log(&ctx, LOG_ERR, "Song has no title."); - goto ERR; - } - exist_title = false; - } - return ctx.songs; - ERR: - cho_songs_close(&ctx, lines); - cho_context_cleanup(&ctx); - for (int e = 0; e<=ctx.so; e++) { - cho_song_free(ctx.songs[e]); - } - free(ctx.songs); - free(stripped_directive_value); - cho_directive_free(directive); - cho_tag_attrs_free(directive_attrs); - return NULL; -}