lorid

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

commit 363db8ac933bf0edddf320e7a999abaed7fe6756
parent fdafe328e5c6b9b4c4cc7d300cde2f922753e84b
Author: nibo <nibo@relim.de>
Date:   Wed, 23 Oct 2024 14:35:03 +0200

Add 'cho_image_tag_parse'

Diffstat:
Mchordpro.c | 434+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mchordpro.h | 21+++++++++++----------
Mout_pdf.c | 2+-
Mutil.c | 95+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Mutil.h | 30+++++++++++++-----------------
5 files changed, 425 insertions(+), 157 deletions(-)

diff --git a/chordpro.c b/chordpro.c @@ -595,6 +595,9 @@ cho_font_copy(struct Font *font) void cho_font_free(struct Font *font) { + if (!font) { + return; + } free(font->name); free(font); } @@ -602,6 +605,9 @@ cho_font_free(struct Font *font) void cho_fonts_free(struct Font **fonts) { + if (!fonts) { + return; + } struct Font **start = fonts; while (*fonts) { cho_font_free(*fonts); @@ -925,6 +931,9 @@ cho_style_new_default(void) void cho_style_free(struct Style *style) { + if (!style) { + return; + } cho_font_free(style->font); free(style->foreground_color); free(style->background_color); @@ -1419,6 +1428,9 @@ cho_tag_attr_new(void) static void cho_tag_attr_free(struct Attr *attr) { + if (!attr) { + return; + } free(attr->name); free(attr->value); free(attr); @@ -1427,6 +1439,9 @@ cho_tag_attr_free(struct Attr *attr) static void cho_tag_attrs_free(struct Attr **attrs) { + if (!attrs) { + return; + } struct Attr **start = attrs; while (*attrs) { cho_tag_attr_free(*attrs); @@ -1449,8 +1464,13 @@ cho_tag_new(void) static void cho_tag_free(struct Tag *tag) { + if (!tag) { + return; + } free(tag->name); - cho_style_free(tag->style); + if (tag->style) { + cho_style_free(tag->style); + } if (tag->attrs) cho_tag_attrs_free(tag->attrs); free(tag); @@ -1502,6 +1522,9 @@ cho_metadata_new(void) static void cho_metadata_free(struct ChoMetadata *meta) { + if (!meta) { + return; + } free(meta->name); free(meta->value); if (meta->style) { @@ -1696,6 +1719,9 @@ cho_chord_complete(struct ChoChord *first, struct ChoChord *second) static void cho_chord_free(struct ChoChord *chord) { + if (!chord) { + return; + } cho_style_free(chord->style); free(chord->name); free(chord->root); @@ -1947,16 +1973,20 @@ cho_image_new(void) image->x = NULL; image->y = NULL; image->anchor = AN_FLOAT; - image->dx = EMPTY; - image->dy = EMPTY; - image->w = EMPTY; - image->h = EMPTY; + image->dx = NULL; + image->dy = NULL; + image->w = NULL; + image->h = NULL; + image->bbox = false; return image; } static void cho_image_free(struct ChoImage *image) { + if (!image) { + return; + } free(image->id); free(image->src); if (image->width) { @@ -1971,13 +2001,25 @@ cho_image_free(struct ChoImage *image) if (image->spread_space) { free(image->spread_space); } + free(image->href); if (image->x) { free(image->x); } if (image->y) { free(image->y); } - free(image->href); + if (image->dx) { + free(image->dx); + } + if (image->dy) { + free(image->dy); + } + if (image->w) { + free(image->w); + } + if (image->h) { + free(image->h); + } free(image); } @@ -1988,20 +2030,21 @@ cho_image_copy(struct ChoImage *image) copy->is_asset = image->is_asset; copy->id = strdup(image->id); copy->src = strdup(image->src); - copy->width = double_or_percent_copy(image->width); - copy->height = double_or_percent_copy(image->height); - copy->scale = double_or_percent_copy(image->scale); + copy->width = size_copy(image->width); + copy->height = size_copy(image->height); + copy->scale = size_copy(image->scale); copy->align = image->align; copy->border = image->border; - copy->spread_space = double_or_percent_copy(image->spread_space); + copy->spread_space = size_copy(image->spread_space); copy->href = strdup(image->href); - copy->x = double_or_percent_copy(image->x); - copy->y = double_or_percent_copy(image->y); + copy->x = size_copy(image->x); + copy->y = size_copy(image->y); copy->anchor = image->anchor; - copy->dx = image->dx; - copy->dy = image->dy; - copy->w = image->w; - copy->h = image->h; + copy->dx = size_copy(image->dx); + copy->dy = size_copy(image->dy); + copy->w = size_copy(image->w); + copy->h = size_copy(image->h); + copy->bbox = image->bbox; return copy; } @@ -2034,24 +2077,24 @@ cho_debug_image_print(struct ChoImage *image) printf("src: NULL\n"); } if (image->width) { - printf("width: %s\n", double_or_percent_to_string(image->width)); + printf("width: %s\n", size_to_string(image->width)); } else { printf("width: NULL\n"); } if (image->height) { - printf("height: %s\n", double_or_percent_to_string(image->height)); + printf("height: %s\n", size_to_string(image->height)); } else { printf("height: NULL\n"); } if (image->scale) { - printf("scale: %s\n", double_or_percent_to_string(image->scale)); + printf("scale: %s\n", size_to_string(image->scale)); } else { printf("scale: NULL\n"); } printf("align: %s\n", alignment_enums[image->align]); printf("border: %.1f\n", image->border); if (image->spread_space) { - printf("spread_space: %s\n", double_or_percent_to_string(image->spread_space)); + printf("spread_space: %s\n", size_to_string(image->spread_space)); } else { printf("spread_space: NULL\n"); } @@ -2061,20 +2104,37 @@ cho_debug_image_print(struct ChoImage *image) printf("href: NULL\n"); } if (image->x) { - printf("x: %s\n", double_or_percent_to_string(image->x)); + printf("x: %s\n", size_to_string(image->x)); } else { printf("x: NULL\n"); } if (image->y) { - printf("y: %s\n", double_or_percent_to_string(image->y)); + printf("y: %s\n", size_to_string(image->y)); } else { printf("y: NULL\n"); } printf("anchor: %s\n", anchor_enums[image->anchor]); - printf("dx: %.1f\n", image->dx); - printf("dy: %.1f\n", image->dy); - printf("w: %.1f\n", image->w); - printf("h: %.1f\n", image->h); + if (image->dx) { + printf("dx: %s\n", size_to_string(image->dx)); + } else { + printf("dx: NULL\n"); + } + if (image->dy) { + printf("dy: %s\n", size_to_string(image->dy)); + } else { + printf("dy: NULL\n"); + } + if (image->w) { + printf("w: %s\n", size_to_string(image->w)); + } else { + printf("w: NULL\n"); + } + if (image->h) { + printf("h: %s\n", size_to_string(image->h)); + } else { + printf("h: NULL\n"); + } + printf("bbox: %d\n", image->bbox); printf("---- END IMAGE ------\n"); } #endif /* DEBUG */ @@ -2083,6 +2143,7 @@ static bool cho_image_option_parse(struct ChoImage *image, const char *name, const char *value) { char *endptr; + struct Size *size; if (!strcmp(name, "id")) { image->id = strdup(value); } else @@ -2090,25 +2151,40 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val image->src = strdup(value); } else if (!strcmp(name, "width")) { - image->width = double_or_percent_create(value); - if (!image->width) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'width' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'width' in image directive. Allowed types are: points, percentage."); + return false; + } + image->width = size; } else if (!strcmp(name, "height")) { - image->height = double_or_percent_create(value); - if (!image->height) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'height' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'height' in image directive. Allowed types are: point, percentage."); + return false; + } + image->height = size; } else if (!strcmp(name, "scale")) { - image->scale = double_or_percent_create(value); - if (!image->scale) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'scale' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'scale' in image directive. Allowed types are: point, percentage."); + return false; + } + image->scale = size; } else if (!strcmp(name, "align")) { if (!strcmp(value, "left")) { @@ -2132,28 +2208,43 @@ cho_image_option_parse(struct ChoImage *image, const char *name, const char *val } } else if (!strcmp(name, "spread")) { - image->spread_space = double_or_percent_create(value); - if (!image->spread_space) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'spread' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'spread' in image directive. Allowed types are: point, percentage."); + return false; + } + image->spread_space = size; } else if (!strcmp(name, "href")) { image->href = strdup(value); } else if (!strcmp(name, "x")) { - image->x = double_or_percent_create(value); - if (!image->x) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'x' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'x' in image directive. Allowed types are: point, percentage."); + return false; + } + image->x = size; } else if (!strcmp(name, "y")) { - image->y = double_or_percent_create(value); - if (!image->y) { + size = size_create(value); + if (!size) { cho_log(LOG_ERR, "Invalid value in option 'y' in image directive."); return false; } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in option 'y' in image directive. Allowed types are: point, percentage."); + return false; + } + image->y = size; } else if (!strcmp(name, "anchor")) { if (!strcmp(value, "paper")) { @@ -2291,9 +2382,134 @@ cho_image_directive_parse(const char *str) return image; } -/* static struct ChoImage *cho_image_tag_parse(const char *str) +static struct ChoImage * +cho_image_tag_parse(struct Attr **attrs) { -} */ + struct ChoImage *image = cho_image_new(); + struct Size *size; + int a; + for (a = 0; attrs[a]; a++) { + if (!strcmp(attrs[a]->name, "src")) { + image->src = strdup(attrs[a]->value); + } else + if (!strcmp(attrs[a]->name, "id")) { + image->id = strdup(attrs[a]->value); + } else + if (!strcmp(attrs[a]->name, "width")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'width' in 'img' tag."); + return false; + } + if (size->type == ST_PERCENT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'width' in 'img' tag. Allowed types are: point, em, ex."); + return false; + } + image->width = size; + } else + if (!strcmp(attrs[a]->name, "height")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'height' in 'img' tag."); + return false; + } + if (size->type == ST_PERCENT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'height' in 'img' tag. Allowed types are: point, em, ex."); + return false; + } + image->height = size; + } else + if (!strcmp(attrs[a]->name, "dx")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'dx' in 'img' tag."); + return false; + } + if (size->type == ST_PERCENT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'dx' in 'img' tag. Allowed types are: point, em, ex."); + return false; + } + image->dx = size; + } else + if (!strcmp(attrs[a]->name, "dy")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'dy' in 'img' tag."); + return false; + } + if (size->type == ST_PERCENT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'dy' in 'img' tag. Allowed types are: point, em, ex."); + return false; + } + image->dy = size; + } else + if (!strcmp(attrs[a]->name, "scale")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'scale' in 'img' tag."); + return false; + } + if (size->type == ST_EM || size->type == ST_EX) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'scale' in 'img' tag. Allowed types are: point, percent"); + return false; + } + image->scale = size; + } else + if (!strcmp(attrs[a]->name, "align")) { + if (!strcmp(attrs[a]->value, "left")) { + image->align = A_LEFT; + } else + if (!strcmp(attrs[a]->value, "right")) { + image->align = A_RIGHT; + } else + if (!strcmp(attrs[a]->value, "center")) { + image->align = A_CENTER; + } else { + cho_log(LOG_ERR, "Invalid value in attribute 'align' in 'img' tag."); + return NULL; + } + } else + if (!strcmp(attrs[a]->name, "bbox")) { + if (!strcmp(attrs[a]->value, "1")) { + image->bbox = true; + } else + if (!strcmp(attrs[a]->value, "0")) { + image->bbox = false; + } else { + cho_log(LOG_ERR, "Invalid value in attribute 'bbox' in 'img' tag."); + return NULL; + } + } else + if (!strcmp(attrs[a]->name, "w")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'w' in 'img' tag."); + return false; + } + if (size->type != ST_POINT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'w' in 'img' tag. Allowed type is: point"); + return false; + } + image->w = size; + } else + if (!strcmp(attrs[a]->name, "h")) { + size = size_create(attrs[a]->value); + if (!size) { + cho_log(LOG_ERR, "Invalid value in attribute 'h' in 'img' tag."); + return false; + } + if (size->type != ST_POINT) { + cho_log(LOG_ERR, "Invalid type of value in attribute 'h' in 'img' tag. Allowed type is: point"); + return false; + } + image->h = size; + } else { + cho_log(LOG_ERR, "Invalid attribute '%s' in 'img' tag.", attrs[a]->name); + return NULL; + } + } + return image; +} static struct ChoText * cho_text_new(void) @@ -2307,6 +2523,9 @@ cho_text_new(void) static void cho_text_free(struct ChoText *text) { + if (!text) { + return; + } cho_style_free(text->style); free(text->text); free(text); @@ -2333,6 +2552,9 @@ cho_text_above_count(struct ChoLineItemAbove **text_above) static void cho_text_above_free(struct ChoLineItemAbove *text_above) { + if (!text_above) { + return; + } if (text_above->is_chord) { cho_chord_free(text_above->u.chord); } else { @@ -2367,10 +2589,15 @@ cho_line_item_new(void) static void cho_line_item_free(struct ChoLineItem *item) { + if (!item) { + return; + } if (item->is_text) { cho_text_free(item->u.text); } else { - cho_image_free(item->u.image); + if (item->u.image) { + cho_image_free(item->u.image); + } } free(item); } @@ -2402,6 +2629,9 @@ cho_line_new(void) static void cho_line_free(struct ChoLine *line) { + if (!line) { + return; + } struct ChoLineItem **start_items = line->items; while (*line->items) { cho_line_item_free(*line->items); @@ -2448,6 +2678,9 @@ cho_section_new(void) static void cho_section_free(struct ChoSection *section) { + if (!section) { + return; + } if (section->label) { cho_text_free(section->label); } @@ -2515,6 +2748,9 @@ cho_song_count(struct ChoSong **songs) static void cho_song_free(struct ChoSong *song) { + if (!song) { + return; + } struct ChoMetadata **start_meta = song->metadata; struct ChoSection **start_section = song->sections; while (*song->metadata) { @@ -2533,6 +2769,9 @@ cho_song_free(struct ChoSong *song) void cho_songs_free(struct ChoSong **songs) { + if (!songs) { + return; + } struct ChoSong **start_song = songs; while (*songs) { cho_song_free(*songs); @@ -2570,6 +2809,9 @@ cho_directive_new(void) static void cho_directive_free(struct ChoDirective *directive) { + if (!directive) { + return; + } cho_style_free(directive->style); free(directive); } @@ -3052,7 +3294,7 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) te--; break; } - if (ta > -1 && !tags[ta]->is_closed) { + if (ta > -1 && !tags[ta]->is_closed && strcmp(tags[ta]->name, "img")) { cho_log(LOG_ERR, "Tag has to be closed on same line."); return NULL; } @@ -3769,6 +4011,10 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (buf == '>') { tag_start[t] = 0; 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)); if (!tag_style) { @@ -3885,28 +4131,36 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) if (tags[ta]->attrs[at-1]->value) { cho_tag_attr_free(tags[ta]->attrs[at]); tags[ta]->attrs[at] = NULL; - tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); - if (!tag_style) { - LOG_DEBUG("cho_style_parse failed."); - return NULL; - } - tags[ta]->style = tag_style; - switch (prev_state) { - case STATE_LYRICS: - cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style); - songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style); - break; - case STATE_CHORD: - cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style); - songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); - break; - case STATE_ANNOTATION: - cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style); - songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); - break; - default: - cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); - return NULL; + if (!strcmp(tags[ta]->name, "img")) { + cho_text_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text); + songs[so]->sections[se]->lines[li]->items[ly]->is_text = false; + image = cho_image_tag_parse(tags[ta]->attrs); + songs[so]->sections[se]->lines[li]->items[ly]->u.image = image; + printf("img tag with attr.\n"); + } else { + tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); + if (!tag_style) { + LOG_DEBUG("cho_style_parse failed."); + return NULL; + } + tags[ta]->style = tag_style; + switch (prev_state) { + case STATE_LYRICS: + cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style); + songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style); + break; + case STATE_CHORD: + cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style); + songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); + break; + case STATE_ANNOTATION: + cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style); + songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); + break; + default: + cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); + return NULL; + } } at = 0; memset(tag_start, 0, strlen(tag_start)); @@ -3961,28 +4215,36 @@ cho_songs_parse(FILE *fp, const char *chordpro_filepath, struct Config *config) at++; tags[ta]->attrs = realloc(tags[ta]->attrs, (at+1) * sizeof(struct Attr *)); tags[ta]->attrs[at] = NULL; - tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); - if (!tag_style) { - LOG_DEBUG("cho_style_parse failed."); - return NULL; - } - tags[ta]->style = tag_style; - switch (prev_state) { - case STATE_LYRICS: - cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style); - songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style); - break; - case STATE_CHORD: - cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style); - songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); - break; - case STATE_ANNOTATION: - cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style); - songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); - break; - default: - cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); - return NULL; + if (!strcmp(tags[ta]->name, "img")) { + cho_text_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text); + songs[so]->sections[se]->lines[li]->items[ly]->is_text = false; + image = cho_image_tag_parse(tags[ta]->attrs); + songs[so]->sections[se]->lines[li]->items[ly]->u.image = image; + printf("img tag with attr.\n"); + } else { + tag_style = cho_style_parse(tag_start, tags[ta]->attrs, cho_tag_style_inherit(tags, ta-1)); + if (!tag_style) { + LOG_DEBUG("cho_style_parse failed."); + return NULL; + } + tags[ta]->style = tag_style; + switch (prev_state) { + case STATE_LYRICS: + cho_style_free(songs[so]->sections[se]->lines[li]->items[ly]->u.text->style); + songs[so]->sections[se]->lines[li]->items[ly]->u.text->style = cho_style_copy(tag_style); + break; + case STATE_CHORD: + cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style); + songs[so]->sections[se]->lines[li]->text_above[c]->u.chord->style = cho_style_copy(tag_style); + break; + case STATE_ANNOTATION: + cho_style_free(songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style); + songs[so]->sections[se]->lines[li]->text_above[c]->u.annot->style = cho_style_copy(tag_style); + break; + default: + cho_log(LOG_ERR, "Invalid prev_state '%s'.", state_enums[prev_state]); + return NULL; + } } at = 0; avs = AVS_NO; diff --git a/chordpro.h b/chordpro.h @@ -146,20 +146,21 @@ struct ChoImage { bool is_asset; char *id; char *src; - struct DoubleOrPercent *width; - struct DoubleOrPercent *height; - struct DoubleOrPercent *scale; + struct Size *width; + struct Size *height; + struct Size *scale; enum Alignment align; double border; - struct DoubleOrPercent *spread_space; + struct Size *spread_space; char *href; - struct DoubleOrPercent *x; - struct DoubleOrPercent *y; + struct Size *x; + struct Size *y; enum Anchor anchor; - double dx; - double dy; - double w; - double h; + struct Size *dx; + struct Size *dy; + struct Size *w; + struct Size *h; + bool bbox; }; enum AttrValueSyntax { diff --git a/out_pdf.c b/out_pdf.c @@ -1055,7 +1055,7 @@ text_create(struct ChoSong **songs, struct Config *config) text[t]->lines[tl]->items = NULL; for (ly = 0; lines[li]->items[ly]; ly++) { if (!lines[li]->items[ly]->is_text) { - printf("src: %s\n", lines[li]->items[ly]->u.image->src); + // printf("src: %s\n", lines[li]->items[ly]->u.image->src); continue; } // out_pdf_text_find_fitting_length(lines[li]->lyrics[ly]); diff --git a/util.c b/util.c @@ -276,59 +276,68 @@ filepath_dirname(const char *path) return dirname; } -const char * -double_or_percent_to_string(struct DoubleOrPercent *dop) +static const char * +size_type_to_string(enum SizeType type) { - static char str[8+1]; - if (dop->is_percent) { - sprintf((char *)&str, "%d%%", dop->u.p); - } else { - if (dop->u.d > 999999) { - sprintf((char *)&str, ">999.999"); - } else { - sprintf((char *)&str, "%.1f", dop->u.d); - } + switch (type) { + case ST_PERCENT: + return "%"; + case ST_EM: + return "em"; + case ST_EX: + return "ex"; + default: + return ""; } - return str; } -struct DoubleOrPercent * -double_or_percent_copy(struct DoubleOrPercent *dop) +struct Size * +size_create(const char *str) { - struct DoubleOrPercent *copy = malloc(sizeof(struct DoubleOrPercent)); - if (dop->is_percent) { - copy->is_percent = true; - copy->u.p = dop->u.p; - } else { - copy->is_percent = false; - copy->u.d = dop->u.d; + size_t len = strlen(str); + struct Size *size = malloc(sizeof(struct Size)); + char *endptr; + double d; + d = strtod(str, &endptr); + if (str == endptr || errno == ERANGE) { + LOG_DEBUG("strtod failed."); + return NULL; + } + size->d = d; + size->type = ST_POINT; + if (len > 1 && str[len-1] == '%') { + if (size->d < 1.0 || size->d > 100.0) { + util_log(LOG_ERR, "invalid percentage."); + return NULL; + } + size->type = ST_PERCENT; + } else + if (len > 2 && str[len-2] == 'e' && str[len-1] == 'm') { + size->type = ST_EM; + } else + if (len > 2 && str[len-2] == 'e' && str[len-1] == 'x') { + size->type = ST_EX; } + return size; +} + +struct Size * +size_copy(struct Size *size) +{ + struct Size *copy = malloc(sizeof(struct Size)); + copy->type = size->type; + copy->d = size->d; return copy; } -struct DoubleOrPercent * -double_or_percent_create(const char *str) +const char * +size_to_string(struct Size *size) { - struct DoubleOrPercent *dop = malloc(sizeof(struct DoubleOrPercent)); - size_t len = strlen(str); - if (str[len-1] == '%') { - short p = str_parse_as_percent(str); - if (p == -1) { - LOG_DEBUG("str_parse_as_percent failed."); - return NULL; - } - dop->u.p = p; - dop->is_percent = true; + static char str[10+1]; + if (size->d > 999999) { + sprintf((char *)&str, ">999.999"); } else { - char *endptr; - double d; - d = strtod(str, &endptr); - if (str == endptr || errno == ERANGE) { - LOG_DEBUG("strtod failed."); - return NULL; - } - dop->u.d = d; - dop->is_percent = false; + sprintf((char *)&str, "%.1f%s", size->d, size_type_to_string(size->type)); } - return dop; + return str; } diff --git a/util.h b/util.h @@ -17,20 +17,16 @@ enum FileType { F_OTHER }; -/* - INFO: Typically I would directly calculate the percent - and store it as a double but I can't do that here because - the percent refers to something in the pdf that will be - generated. At parsing stage there is no information about - the pdf. -*/ - -struct DoubleOrPercent { - bool is_percent; - union { - double d; - short p; - } u; +enum SizeType { + ST_POINT, + ST_PERCENT, + ST_EM, + ST_EX +}; + +struct Size { + enum SizeType type; + double d; }; void util_log(enum LogLevel level, const char *msg, ...); @@ -48,6 +44,6 @@ char *filepath_add_ending_slash_if_missing(const char *path); char *filepath_basename(const char *path); char *filepath_dirname(const char *path); -const char *double_or_percent_to_string(struct DoubleOrPercent *dop); -struct DoubleOrPercent *double_or_percent_copy(struct DoubleOrPercent *dop); -struct DoubleOrPercent *double_or_percent_create(const char *str); +struct Size *size_create(const char *str); +struct Size *size_copy(struct Size *size); +const char *size_to_string(struct Size *size);