lorid

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

commit e73a5b4e11157ed6734cfa45f25aeefa8b863f93
parent 79d702872859401b1ebc23c112e3e067f3878994
Author: nibo <nibo@relim.de>
Date:   Thu, 17 Jul 2025 15:58:43 +0200

WIP: Free memory in case of error in src/out_pdf.c

Also refactor some functions.

Diffstat:
Msrc/out_pdf.c | 270++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 150 insertions(+), 120 deletions(-)

diff --git a/src/out_pdf.c b/src/out_pdf.c @@ -83,40 +83,41 @@ out_pdf_fnt_obj_get_by_name(struct PDFContext *ctx, const char *name) return ctx->fonts[i]->value; } } - printf("name '%s'\n", name); return NULL; } static char * fnt_name_create(struct Font *font) { + const char *c; + char *f; char *name = str_normalize(font->name); const char *family = cho_font_family_to_config_string(font->family); const char *style = cho_font_style_to_config_string(font->style); const char *weight = cho_font_weight_to_config_string(font->weight); size_t len = strlen(name) + strlen(family) + strlen(style) + strlen(weight); - int n = 0; - int i; char *fnt_name = emalloc((len + 4) * sizeof(char)); - for (i = 0; name[i]; i++, n++) { - fnt_name[n] = name[i]; + + f = fnt_name; + for (c = name; *c; c++, f++) { + *f = *c; } - fnt_name[n] = '-'; - n++; - for (i = 0; family[i]; i++, n++) { - fnt_name[n] = family[i]; + *f = '-'; + f++; + for (c = family; *c; c++, f++) { + *f = *c; } - fnt_name[n] = '-'; - n++; - for (i = 0; style[i]; i++, n++) { - fnt_name[n] = style[i]; + *f = '-'; + f++; + for (c = style; *c; c++, f++) { + *f = *c; } - fnt_name[n] = '-'; - n++; - for (i = 0; weight[i]; i++, n++) { - fnt_name[n] = weight[i]; + *f = '-'; + f++; + for (c = weight; *c; c++, f++) { + *f = *c; } - fnt_name[n] = 0; + *f = '\0'; free(name); return fnt_name; } @@ -162,6 +163,7 @@ fonts_get_all(struct ChoSong **songs, struct Config *config) struct ChoStyle *style; bool added; int i; + for (so = songs; *so; so++) { for (i = 0; i < TEXT_TYPE_LENGTH; i++) { if ((*so)->present_text_types[i]) { @@ -225,9 +227,11 @@ fontpath_count_fonts(FcChar8 *path) { int count; FcFontSet *set; + set = FcFontSetCreate(); if (!FcFileScan(set, NULL, NULL, NULL, path, false)) { LOG_DEBUG("fontpath_count_fonts failed."); + FcFontSetDestroy(set); return -1; } count = set->nfont; @@ -276,9 +280,6 @@ fontpath_find(struct Font *font, enum FontType font_type) case FONT_STYLE_ITALIC: style.u.i = FC_SLANT_ITALIC; break; - default: - util_log(NULL, 0, LOG_ERR, "Invalid font style value '%d'.", font->style); - return NULL; } FcPatternAdd(pattern, FC_SLANT, style, FcFalse); FcValue weight; @@ -290,9 +291,6 @@ fontpath_find(struct Font *font, enum FontType font_type) case FONT_WEIGHT_BOLD: weight.u.i = FC_WEIGHT_BOLD; break; - default: - util_log(NULL, 0, LOG_ERR, "Invalid font weight value '%d'.", font->weight); - return NULL; } FcPatternAdd(pattern, FC_WEIGHT, weight, FcFalse); FcFontSet *set = FcFontList(NULL, pattern, obj); @@ -318,15 +316,16 @@ fontpath_find(struct Font *font, enum FontType font_type) static bool pdf_load_chord_diagram_fonts(struct PDFContext *ctx) { - struct Obj *fnt; char *fontpath; const char *font_name; + struct Obj *fnt; struct Font font = { .name = DEFAULT_FONT, .family = FONT_FAMILY_NORMAL, .style = FONT_STYLE_ROMAN, .weight = FONT_WEIGHT_REGULAR }; + fnt = obj_new(); fnt->name = strdup("chord-diagram-regular-font"); if ((font_name = is_base_font(&font))) { @@ -338,6 +337,7 @@ pdf_load_chord_diagram_fonts(struct PDFContext *ctx) fontpath = fontpath_find(&font, FONT_TYPE_OTF); if (!fontpath) { LOG_DEBUG("fontpath_find failed."); + obj_free(fnt); return false; } } @@ -367,12 +367,13 @@ font_name_is_path(const char *name) static bool pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) { - char *fontpath; + char *fontpath = NULL; char **fontpaths = NULL; const char *name; int index; struct Font **f; struct Obj *fnt; + for (f = needed_fonts; *f; f++) { if (font_name_is_path((*f)->name)) { fontpath = filepath_resolve_tilde((*f)->name); @@ -383,7 +384,7 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) fnt->value = pdfioFileCreateFontObjFromFile(ctx->pdf_file, fontpath, true); if (!fnt->value) { LOG_DEBUG("pdfioFileCreateFontObjFromFile failed."); - return false; + goto ERR; } strs_add(&fontpaths, fontpath); util_log(NULL, 0, LOG_INFO, "Loaded font from '%s'.", (*f)->name); @@ -400,7 +401,7 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) fnt->value = pdfioFileCreateFontObjFromBase(ctx->pdf_file, name); if (!fnt->value) { LOG_DEBUG("pdfioFileCreateFontObjFromBase failed."); - return false; + goto ERR; } objs_add_obj(&ctx->fonts, fnt); } else { @@ -413,7 +414,7 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) fnt->value = pdfioFileCreateFontObjFromFile(ctx->pdf_file, fontpath, true); if (!fnt->value) { LOG_DEBUG("pdfioFileCreateFontObjFromFile failed."); - return false; + goto ERR; } strs_add(&fontpaths, fontpath); util_log(NULL, 0, LOG_INFO, "Loaded font from '%s'.", fontpath); @@ -433,7 +434,7 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) fnt->value = pdfioFileCreateFontObjFromFile(ctx->pdf_file, fontpath, true); if (!fnt->value) { LOG_DEBUG("pdfioFileCreateFontObjFromFile failed."); - return false; + goto ERR; } strs_add(&fontpaths, fontpath); util_log(NULL, 0, LOG_INFO, "Loaded font from '%s'.", fontpath); @@ -446,7 +447,7 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) } else { util_log(NULL, 0, LOG_ERR, "Didn't find font file for following font:"); cho_font_print(*f); - return false; + goto ERR; } } } @@ -454,33 +455,35 @@ pdf_load_fonts(struct PDFContext *ctx, struct Font **needed_fonts) if (ctx->config->output->diagram->show) { if (!pdf_load_chord_diagram_fonts(ctx)) { LOG_DEBUG("pdf_load_chord_diagram_fonts failed."); - return false; + goto ERR; } } strs_free(fontpaths); return true; + ERR: + strs_free(fontpaths); + objs_free(ctx->fonts); + obj_free(fnt); + free(fontpath); + return false; } static char * pdf_filename_generate_from_songs(struct PDFContext *ctx, struct ChoSong **songs) { - char *filename; - char *normalized_title; - char *title; + char *filename, *normalized_title, *title; struct ChoStyle *unused; - int len = cho_song_count(songs); - if (len == 0) + int len; + + len = cho_song_count(songs); + if (len == 0) { return NULL; + } if (len == 1) { if (!cho_metadata_value(songs[0]->metadata, "title", ctx->config->metadata_separator, &title, &unused)) { LOG_DEBUG("cho_metadata_value failed."); return NULL; } - if (!title) { - /* INFO: unreachable because the parser already checks the presence of the 'title' directive */ - util_log(NULL, 0, LOG_ERR, "Song has no title."); - return NULL; - } normalized_title = str_normalize(title); filename = file_extension_replace_or_add(normalized_title, "pdf"); free(normalized_title); @@ -499,15 +502,17 @@ pdf_filepath_create( ) { char *pdf_filepath = NULL; - char *pdf_filename, *tmp; + char *filepath = NULL; + char *filename = NULL; + char *tmp = NULL; enum FileType type; if (cho_filepath) { - pdf_filepath = file_extension_replace_or_add(cho_filepath, "pdf"); - pdf_filename = filepath_basename(pdf_filepath); + filepath = file_extension_replace_or_add(cho_filepath, "pdf"); + filename = filepath_basename(filepath); } else { - pdf_filename = pdf_filename_generate_from_songs(ctx, songs); - if (!pdf_filename) { + filename = pdf_filename_generate_from_songs(ctx, songs); + if (!filename) { LOG_DEBUG("pdf_filename_generate_from_songs failed."); return NULL; } @@ -515,46 +520,44 @@ pdf_filepath_create( if (out) { type = file_type(out); switch (type) { - case FILE_TYPE_ERROR: + case FILE_TYPE_ERROR: { tmp = filepath_dirname(out); type = file_type(tmp); switch (type) { case FILE_TYPE_FOLDER: - free(pdf_filepath); - free(pdf_filename); - free(tmp); - return strdup(out); + pdf_filepath = strdup(out); + break; default: - free(tmp); util_log(NULL, 0, LOG_ERR, "The -o/--output value '%s' is not an existing folder.", out); - return NULL; } break; - case FILE_TYPE_REG_FILE: - free(pdf_filepath); - free(pdf_filename); - return strdup(out); - case FILE_TYPE_FOLDER: - tmp = filepath_add_ending_slash_if_missing(out); - tmp = erealloc(tmp, (strlen(tmp)+strlen(pdf_filename)+1) * sizeof(char)); - strcat(tmp, pdf_filename); - free(pdf_filename); - free(pdf_filepath); - return tmp; - case FILE_TYPE_OTHER: + } + case FILE_TYPE_REG_FILE: { + pdf_filepath = strdup(out); + break; + } + case FILE_TYPE_FOLDER: { + pdf_filepath = filepath_add_ending_slash_if_missing(out); + pdf_filepath = erealloc(pdf_filepath, (strlen(pdf_filepath)+strlen(filename)+1) * sizeof(char)); + strcat(pdf_filepath, filename); + break; + } + case FILE_TYPE_OTHER: { util_log(NULL, 0, LOG_ERR, "Invalid argument --output/-o value. It doesn't refer to a folder or regular file."); - return NULL; - default: - util_log(NULL, 0, LOG_ERR, "Invalid enum FileType value '%d'.", type); - return NULL; + break; + } } } else { - if (pdf_filepath) { - free(pdf_filename); - return pdf_filepath; + if (filepath) { + pdf_filepath = strdup(filepath); + } else { + pdf_filepath = strdup(filename); } - return pdf_filename; } + free(filepath); + free(filename); + free(tmp); + return pdf_filepath; } static bool @@ -572,6 +575,7 @@ pdf_font_set(struct PDFContext *ctx, pdfio_stream_t *stream, struct Font *font) } if (!pdfioContentSetTextFont(stream, name, font->size)) { LOG_DEBUG("pdfioContentSetTextFont failed."); + free(name); return false; } strcpy(ctx->current_font_name, name); @@ -588,6 +592,7 @@ text_width(struct PDFContext *ctx, const char *text, struct ChoStyle *style) pdfio_obj_t *font_obj = out_pdf_fnt_obj_get_by_name(ctx, name); if (!font_obj) { LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); + free(name); return -1.0; } free(name); @@ -604,6 +609,7 @@ text_above_width(struct PDFContext *ctx, struct ChoLineItemAbove *above) width = text_width(ctx, name, above->u.chord->style); if (width == ERROR) { LOG_DEBUG("text_width failed."); + free(name); return ERROR; } free(name); @@ -644,6 +650,7 @@ text_find_fitting( strcpy((char *)&tmp, str); double width; int i; + do { i = find_whitespace((const char *)&tmp, start); if (i == -1) { @@ -671,6 +678,7 @@ pdf_draw_line( ) { double red, green, blue; + switch (line_location) { case LINE_LOCATION_UNDER: red = text->style->underline_color->red / 255.0; @@ -718,6 +726,7 @@ pdf_draw_rectangle( { double height; double red, green, blue; + red = text->style->background_color->red / 255.0; green = text->style->background_color->green / 255.0; blue = text->style->background_color->blue / 255.0; @@ -751,6 +760,7 @@ pdf_text_show(struct PDFContext *ctx, pdfio_stream_t *stream, struct PDFText *te { double red, green, blue; bool unicode; + if (!pdf_font_set(ctx, stream, text->style->font)) { LOG_DEBUG("pdf_font_set failed."); return false; @@ -843,6 +853,7 @@ annot_page_link_add( pdfio_rect_t rect; pdfio_dict_t *annot; pdfio_array_t *destination; + rect.x1 = MARGIN_HORIZONTAL; rect.x2 = MARGIN_HORIZONTAL + LINE_WIDTH; rect.y1 = ctx->t_ctx.y - 2.0; @@ -893,6 +904,7 @@ annot_url_link_add( { pdfio_rect_t rect; pdfio_dict_t *annot, *action; + rect.x1 = c_ctx->x; rect.x2 = c_ctx->x + width; rect.y1 = c_ctx->y - 2.0; @@ -937,12 +949,8 @@ pdf_set_title(struct PDFContext *ctx, struct ChoSong **songs) LOG_DEBUG("cho_metadata_value failed."); return false; } - if (title) { - pdfioFileSetTitle(ctx->pdf_file, title); - free(title); - return true; - } - return false; + pdfioFileSetTitle(ctx->pdf_file, title); + free(title); } return true; } @@ -956,9 +964,11 @@ pdf_page_create( { pdfio_dict_t *page_dict; pdfio_stream_t *page_stream; - pdfio_array_t *color_array = pdfioArrayCreateColorFromStandard(ctx->pdf_file, 3, PDFIO_CS_ADOBE); + pdfio_array_t *color_array; struct Obj **f; struct PDFImage **i; + + color_array = pdfioArrayCreateColorFromStandard(ctx->pdf_file, 3, PDFIO_CS_ADOBE); page_dict = pdfioDictCreate(ctx->pdf_file); if (!pdfioPageDictAddColorSpace(page_dict, "rgbcolorspace", color_array)) { LOG_DEBUG("pdfioPageDictAddColorSpace failed."); @@ -1040,6 +1050,7 @@ image_name(struct PDFContext *ctx, struct ChoImage *image) char tmp[PATH_MAX]; char *image_path; struct stat s; + if (strchr(image->src, '/')) { image_path = image->src; } else { @@ -1069,6 +1080,7 @@ pdf_load_images(struct PDFContext *ctx, struct Obj ***images, struct ChoSong **s char filepath[PATH_MAX]; char *name; char *image_filepath; + for (s = songs; *s; s++) { for (se = (*s)->sections; *se; se++) { for (li = (*se)->lines; *li; li++) { @@ -1095,6 +1107,7 @@ pdf_load_images(struct PDFContext *ctx, struct Obj ***images, struct ChoSong **s (*images)[i]->value = pdfioFileCreateImageObjFromFile(ctx->pdf_file, image_filepath, true); if (!(*images)[i]->value) { LOG_DEBUG("pdfioFileCreateImageObjFromFile failed."); + free(name); return false; } util_log(NULL, 0, LOG_INFO, "Loaded image from '%s'.", image_filepath); @@ -1110,24 +1123,26 @@ pdf_load_images(struct PDFContext *ctx, struct Obj ***images, struct ChoSong **s return true; } -static bool -pdf_get_chords(struct ChoSong *song, struct ChoChord ***chords) +static struct ChoChord ** +pdf_get_chords(struct ChoSong *song) { struct ChoSection **se; struct ChoLine **li; struct ChoLineItemAbove **above; + struct ChoChord **chords = NULL; + for (se = song->sections; *se; se++) { for (li = (*se)->lines; *li; li++) { for (above = (*li)->text_above; *above; above++) { if ((*above)->is_chord) { - if (!cho_chords_has(*chords, (*above)->u.chord)) { - cho_chords_add(chords, (*above)->u.chord); + if (!cho_chords_has(chords, (*above)->u.chord)) { + cho_chords_add(&chords, (*above)->u.chord); } } } } } - return true; + return chords; } static double @@ -1147,6 +1162,7 @@ line_width_until_text_above( pdfio_obj_t *font_obj; pdfio_obj_t *obj; struct ChoText *text; + for (i = 0; items[i]; i++) { if (items[i]->is_text) { for (k = 0; items[i]->u.text->text[k]; k++) { @@ -1174,8 +1190,10 @@ line_width_until_text_above( font_obj = out_pdf_fnt_obj_get_by_name(ctx, name); if (!font_obj) { LOG_DEBUG("out_pdf_fnt_obj_get_by_name failed."); + free(name); return ERROR; } + free(name); if (save_i == i) { char tmp[strlen(text->text)+1]; strcpy((char *)&tmp, text->text); @@ -1184,7 +1202,6 @@ line_width_until_text_above( } else { width += pdfioContentTextMeasure(font_obj, text->text, text->style->font->size); } - free(name); } else { name = image_name(ctx, items[i]->u.image); if (!name) { @@ -1194,6 +1211,7 @@ line_width_until_text_above( obj = objs_get_obj(img_objs, name); if (!obj) { LOG_DEBUG("objs_get_obj failed."); + free(name); return ERROR; } width += image_width(items[i]->u.image, obj); @@ -1252,6 +1270,9 @@ pdf_text_free(struct PDFText *text) static void toc_entry_free(struct TocEntry *entry) { + if (!entry) { + return; + } free(entry->title); free(entry); } @@ -1425,24 +1446,25 @@ item_width( struct Obj **img_objs ) { + char *name; double width; + pdfio_obj_t *obj; + struct SpaceNeeded **s; + if (item->is_text) { width = text_width(ctx, item->u.text->text, item->u.text->style); if (width == ERROR) { LOG_DEBUG("text_width failed."); return ERROR; } - struct SpaceNeeded **s; - if ((s = spaces)) { - for (; *s; s++) { + if (spaces) { + for (s = spaces; *s; s++) { if ((*s)->line_item_index == i) { width += (*s)->amount; } } } } else { - char *name; - pdfio_obj_t *obj; name = image_name(ctx, item->u.image); if (!name) { LOG_DEBUG("image_name failed."); @@ -1451,6 +1473,7 @@ item_width( obj = objs_get_obj(img_objs, name); if (!obj) { LOG_DEBUG("objs_get_obj failed."); + free(name); return ERROR; } free(name); @@ -1467,32 +1490,33 @@ items_find_position_to_break_line( struct Obj **img_objs ) { - struct CharPosition *pos = emalloc(sizeof(struct CharPosition)); + int i; + double d; + double width = 0.0; + struct CharPosition *pos; + + pos = emalloc(sizeof(struct CharPosition)); pos->line_item_index = EMPTY_INT; pos->text_index = EMPTY_INT; - double width = 0.0; - double d; - struct ChoLineItem **it = items; - int i; - for (i = 0; it[i]; i++) { - d = item_width(ctx, it[i], i, spaces, img_objs); + for (i = 0; items[i]; i++) { + d = item_width(ctx, items[i], i, spaces, img_objs); if (d == ERROR) { LOG_DEBUG("item_width failed."); - return NULL; + goto ERR; } if (width + d > LINE_WIDTH) { - if (it[i]->is_text) { + if (items[i]->is_text) { pos->line_item_index = i; pos->text_index = text_find_fitting( ctx, - it[i]->u.text->text, - it[i]->u.text->style, + items[i]->u.text->text, + items[i]->u.text->style, width, LINE_WIDTH ); if (pos->text_index == EMPTY_INT) { LOG_DEBUG("text_find_fitting failed."); - return NULL; + goto ERR; } } else { pos->line_item_index = i; @@ -1504,6 +1528,9 @@ items_find_position_to_break_line( } } return pos; + ERR: + free(pos); + return NULL; } static double @@ -1515,12 +1542,14 @@ images_find_biggest_height( ) { struct ChoLineItem **it; - char *name; pdfio_obj_t *obj; + char *name; int i = 0; double end = line_item_index; double biggest = 0.0; double height; + + // TODO: Why 10000? if (end == -1) { end = 10000; } @@ -1534,6 +1563,7 @@ images_find_biggest_height( obj = objs_get_obj(img_objs, name); if (!obj) { LOG_DEBUG("objs_get_obj failed."); + free(name); return ERROR; } height = image_height((*it)->u.image, obj); @@ -1555,6 +1585,7 @@ text_above_find_index_to_break_line( { int position = 0; int i, k; + if (pos->text_index == -1) { for (i = 0; items[i]; i++) { if (pos->line_item_index == i) { @@ -1591,7 +1622,7 @@ text_above_find_index_to_break_line( static void text_above_update_positions(struct ChoLineItemAbove **aboves, size_t consumed_lyrics) { - struct ChoLineItemAbove **a = aboves; + struct ChoLineItemAbove **a; for (a = aboves; *a; a++) { (*a)->position -= consumed_lyrics + 1; // why plus one? } @@ -1611,6 +1642,7 @@ handle_index(int index, char a, char b, char c) { int i = 0; static char str[16]; + memset(&str, 0, sizeof(str)); switch (index) { case 1: @@ -1666,7 +1698,6 @@ numeral_system_western_arabic_to_roman(unsigned int n) static char roman[64]; int k; int r = 0; - memset(&str, 0, sizeof(str)); char i = 'I'; char v = 'V'; char x = 'X'; @@ -1734,11 +1765,13 @@ pdf_page_add_page_no( page_no = numeral_system_number_to_str(numeral_system, c_ctx->page+1); if (!page_no) { LOG_DEBUG("numeral_system_number_to_str failed."); + cho_style_free(style); return false; } width = text_width(ctx, page_no, style); if (width == ERROR) { LOG_DEBUG("text_width failed."); + cho_style_free(style); return false; } *texts = erealloc(*texts, (c_ctx->text+1) * sizeof(struct PDFText *)); @@ -1758,9 +1791,6 @@ pdf_page_add_page_no( case ALIGNMENT_RIGHT: x = MEDIABOX_WIDTH - MARGIN_HORIZONTAL / 2 - width; break; - default: - util_log(NULL, 0, LOG_ERR, "Invalid Alignment enum value '%d'.", ctx->config->output->page_no->align); - return false; } (*texts)[c_ctx->text]->x = x; c_ctx->text++; @@ -1813,17 +1843,20 @@ pdf_toc_page_count( double max_title_width ) { + int index; int page = 0; double y = MEDIABOX_HEIGHT - MARGIN_TOP; double width; + char *t; struct TocEntry **toc; + for (toc = entries; *toc; toc++) { + char tmp[strlen((*toc)->title)+1]; + if (y < MARGIN_BOTTOM) { y = MEDIABOX_HEIGHT - MARGIN_TOP; page++; } - int index; - char tmp[strlen((*toc)->title)+1]; strcpy((char *)&tmp, (*toc)->title); width = text_width(ctx, (*toc)->title, style); if (width == ERROR) { @@ -1832,7 +1865,7 @@ pdf_toc_page_count( } width += MARGIN_HORIZONTAL; if (width > max_title_width) { - char *t = (char *)&tmp; + t = (char *)&tmp; while (width > max_title_width) { index = text_find_fitting(ctx, t, style, MARGIN_HORIZONTAL, max_title_width); if (index == EMPTY_INT) { @@ -1862,7 +1895,6 @@ toc_dots_create(double available_width, double dot_width) available_width -= MARGIN_HORIZONTAL; int dot_count; static char dots[1024]; - memset(&dots, 0, sizeof(dots)); dot_count = (int)floor(available_width / dot_width); if (dot_count > 1023) { return NULL; @@ -1872,6 +1904,7 @@ toc_dots_create(double available_width, double dot_width) return dots; } +// HERE static bool pdf_texts_add_toc_entry( struct PDFContext *ctx, @@ -2398,11 +2431,8 @@ pdf_body_create( int s; for (s = 0; songs[s]; s++) { if (show_diagram) { - struct ChoChord **chords = NULL; - if (!pdf_get_chords(songs[s], &chords)) { - LOG_DEBUG("pdf_get_chords failed."); - return false; - } + struct ChoChord **chords; + chords = pdf_get_chords(songs[s]); if (chords) { qsort(chords, cho_chord_count(chords), sizeof(struct ChoChord *), cho_chord_compare); dgrams = chord_diagrams_create(ctx->config, &chords, songs[s]->diagrams); @@ -2412,8 +2442,8 @@ pdf_body_create( ctx->b_ctx.diagram++; } free(dgrams); + cho_chords_free(chords); } - cho_chords_free(chords); } if (!cho_metadata_value(songs[s]->metadata, "title", ctx->config->metadata_separator, &metadata, &metadata_style)) { LOG_DEBUG("cho_metadata_value failed.");