lorid

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

commit bc18e8c019758420021bc718a4b4b88bec9d3fd0
parent 6cb239b9a0befa2d4ad01df052dd7ad3ecee957e
Author: nibo <nibo@relim.de>
Date:   Tue, 25 Mar 2025 12:17:59 +0100

Merge src/types.h with src/util.* into src/core.*

Diffstat:
MMakefile | 2+-
Msrc/chord_diagram.c | 3+--
Msrc/chordpro.c | 9++++-----
Msrc/chordpro.h | 2+-
Msrc/config.c | 12+++---------
Msrc/config.h | 2+-
Asrc/core.c | 620+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core.h | 419+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lorid.c | 11++++++-----
Msrc/out_pdf.c | 29+++++++++++++++--------------
Msrc/out_pdf.h | 2+-
Msrc/util.c | 2+-
12 files changed, 1073 insertions(+), 40 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,7 +3,7 @@ PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man CFLAGS = -std=c2x -pedantic -Wall -Wextra LDFLAGS = -lpdfio -ltoml -lfontconfig -lgrapheme -lm -SRC = src/util.c src/config.c src/chordpro.c src/chord_diagram.c src/out_pdf.c src/lorid.c +SRC = src/core.c src/config.c src/chordpro.c src/chord_diagram.c src/out_pdf.c src/lorid.c # Control whether log messages are colored. COLOR = 0 diff --git a/src/chord_diagram.c b/src/chord_diagram.c @@ -2,9 +2,8 @@ #include <ctype.h> #include <pdfio.h> #include <pdfio-content.h> -#include "types.h" +#include "core.h" #include "out_pdf.h" -#include "util.h" #include "config.h" #include "chordpro.h" #include "chord_diagram.h" diff --git a/src/chordpro.c b/src/chordpro.c @@ -9,9 +9,8 @@ #include <errno.h> #include <limits.h> #include <time.h> -#include "types.h" +#include "core.h" #include "chordpro.h" -#include "util.h" #include "chord_diagram.h" #include "config.h" @@ -20,7 +19,7 @@ static const char *font_styles[] = { "normal", "oblique", "italic" }; static const char *font_weights[] = { "normal", "bold" }; static const char *line_styles[] = { "single", "double", "none" }; static const char *chord_qualifiers[] = { "m", "", "+", "°" }; -static const char *instruments[] = { "guitar", "keyboard", "mandolin", "ukulele" }; +extern const struct InstrumentInfo instruments[]; static const char *state_enums[] = { "STATE_LYRICS", @@ -3661,7 +3660,7 @@ cho_chord_diagram_parse( cho_log(ctx, LOG_ERR, "Can't copy the diagram for the chord '%s'" "because no previous definition was found and also" "no predefined chord diagram for the instrument '%s'" - "was found.", chord_to_copy, instruments[ins]); + "was found.", chord_to_copy, instruments[ins].name); return NULL; } i = 0; @@ -3751,7 +3750,7 @@ cho_chord_diagram_parse( cho_log(ctx, LOG_ERR, "Can't copy the diagram for the chord '%s' because" "no previous definition was found and also no predefined" "chord diagram for the instrument '%s' was found.", - chord_to_copy, instruments[ins]); + chord_to_copy, instruments[ins].name); return NULL; } break; diff --git a/src/chordpro.h b/src/chordpro.h @@ -1,5 +1,5 @@ #include <stdint.h> -#include "types.h" +#include "core.h" #ifndef _CHORDPRO_H_ #define _CHORDPRO_H_ diff --git a/src/config.c b/src/config.c @@ -4,12 +4,13 @@ #include <string.h> #include <toml.h> #include <linux/limits.h> -#include "types.h" +#include "core.h" #include "config.h" #include "chordpro.h" -#include "util.h" #include "chord_diagram.h" +extern const struct InstrumentInfo instruments[]; + static const char *notation_systems[] = { "common", "german", @@ -24,13 +25,6 @@ static const char *parse_modes[] = { "relaxed" }; -static const struct InstrumentInfo instruments[] = { - { .name = "guitar", .description = "Guitar, 6 strings, standard tuning", .tuning = "E2 A2 D3 G3 B3 E4" }, - { .name = "keyboard", .description = "Piano", .tuning = "" }, - { .name = "mandolin", .description = "Mandolin, 4 strings, standard tuning", .tuning = "G D A E" }, - { .name = "ukulele", .description = "Ukulele, 4 strings, standard tuning", .tuning = "G C E A" } -}; - static const char *text_types[] = { "chord", "annotation", "chorus", "footer", "grid", "tab", "toc", "toc_title", "text", diff --git a/src/config.h b/src/config.h @@ -1,4 +1,4 @@ -#include "types.h" +#include "core.h" #ifndef _CONFIG_H_ #define _CONFIG_H_ diff --git a/src/core.c b/src/core.c @@ -0,0 +1,620 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <stdarg.h> +#include <unistd.h> +#include <ctype.h> +#include <string.h> +#include <sys/stat.h> +#include <errno.h> +#include <assert.h> +#include <limits.h> +#include "core.h" + +const struct InstrumentInfo instruments[] = { + { .name = "guitar", .description = "Guitar, 6 strings, standard tuning", .tuning = "E2 A2 D3 G3 B3 E4" }, + { .name = "keyboard", .description = "Piano", .tuning = "" }, + { .name = "mandolin", .description = "Mandolin, 4 strings, standard tuning", .tuning = "G D A E" }, + { .name = "ukulele", .description = "Ukulele, 4 strings, standard tuning", .tuning = "G C E A" } +}; + +static bool g_show_info_logs = false; + +void +util_log_enable_info_logs(void) +{ + g_show_info_logs = true; +} + +void * +emalloc(size_t size) +{ + void *ptr = malloc(size); + if (!ptr) { + perror("malloc failed"); + exit(1); + } + return ptr; +} + +void * +erealloc(void *ptr, size_t size) +{ + void *tmp = realloc(ptr, size); + if (!tmp) { + perror("realloc failed"); + exit(1); + } + return tmp; +} + +static void +log_without_color( + const char *file, + size_t line_no, + enum LogLevel level, + const char *msg, + va_list va +) +{ + if (file) { + fprintf(stderr, "%s", file); + } + if (line_no > 0) { + fprintf(stderr, ":%ld", line_no); + } + const char *log_level = ""; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + break; + case LOG_WARN: + log_level = "WARN"; + break; + case LOG_ERR: + log_level = " ERR"; + break; + case LOG_TODO: + log_level = "TODO"; + break; + } + fprintf(stderr, "%s: ", log_level); + // va_list va; + // va_start(va, msg); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); +} + +#if COLOR == 1 +static void +log_with_color( + const char *file, + size_t line_no, + enum LogLevel level, + const char *msg, + va_list va +) +{ + if (file) { + fprintf(stderr, "\033[1m%s\033[0m", file); + if (line_no > 0) { + fprintf(stderr, "\033[1;:%ld\033[0m", line_no); + } + } + const char *log_level = ""; + const char *color = ""; + switch (level) { + case LOG_INFO: + log_level = "INFO"; + color = "37"; + break; + case LOG_WARN: + log_level = "WARN"; + color = "33"; + break; + case LOG_ERR: + log_level = " ERR"; + color = "31"; + break; + case LOG_TODO: + log_level = "TODO"; + color = "34"; + break; + } + fprintf(stderr, " \033[1;%sm%s\033[0m: ", color, log_level); + vfprintf(stderr, msg, va); + fprintf(stderr, "\n"); +} +#endif + +void +util_vlog( + const char *file, + size_t line_no, + enum LogLevel level, + const char *msg, + va_list va +) +{ + if (level == LOG_INFO && !g_show_info_logs) { + return; + } +#if COLOR == 1 + if (isatty(2)) { + log_with_color(file, line_no, level, msg, va); + } else { + log_without_color(file, line_no, level, msg, va); + } +#else + log_without_color(file, line_no, level, msg, va); +#endif +} + +void +util_log( + const char *file, + size_t line_no, + enum LogLevel level, + const char *msg, + ... +) +{ + va_list va; + va_start(va, msg); + util_vlog(file, line_no, level, msg, va); +} + +bool +str_starts_with(const char *str, const char *part) +{ + unsigned int i; + size_t part_len = strlen(part); + if (part_len > strlen(str)) + return false; + for (i=0; i<part_len; i++) { + if (str[i] != part[i]) + return false; + } + return true; +} + +char * +str_normalize(const char *str) +{ + char *normalized = NULL; + char c; + int n = 0; + int i; + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '/' || str[i] == '.') { + normalized = erealloc(normalized, (n+1) * sizeof(char)); + normalized[n] = '-'; + n++; + continue; + } + if (str[i] == '\'' || str[i] == ',') + continue; + c = (char)tolower(str[i]); + normalized = erealloc(normalized, (n+1) * sizeof(char)); + normalized[n] = c; + n++; + } + normalized = erealloc(normalized, (n+1) * sizeof(char)); + normalized[n] = 0; + return normalized; +} + +char * +str_trim(const char *str) +{ + char *trimmed = NULL; + int begin = 0; + int end = 0; + int len = (int)strlen(str); + for (int i=0; i<len; i++) { + if ( + str[i] == ' ' || + str[i] == '\n' || + str[i] == '\t' || + str[i] == '\r' + ) + begin++; + else + break; + } + for (int i=len-1; i>=0; i--) { + if ( + str[i] == ' '|| + str[i] == '\n' || + str[i] == '\t' || + str[i] == '\r' + ) + end++; + else + break; + } + int k = 0; + for (int i=0; i<len; i++) { + if (i >= begin && i < len - end) { + trimmed = erealloc(trimmed, (k+1) * sizeof(char)); + trimmed[k] = str[i]; + k++; + } + } + trimmed = erealloc(trimmed, (k+1) * sizeof(char)); + trimmed[k] = 0; + return trimmed; +} + +char * +str_remove_leading_whitespace(const char *str) +{ + int i = 0; + while (str[i] == ' ' || str[i] == '\t') { + i++; + } + return strdup(&str[i]); +} + +int +str_compare(const char *a, const char *b) +{ + if (a && b) { + return strcmp(a, b); + } else + if (!a && !b) { + return 0; + } else + if (a && !b) { + return 1; + } else + if (!a && b) { + return -1; + } + assert(false); +} + +long +str_to_number(const char *str) +{ + long n; + char *endptr; + n = strtol(str, &endptr, 10); + if (str == endptr) { + return -1; + } + if ((n == LONG_MIN || n == LONG_MAX) && errno == ERANGE) { + return -1; + } + return n; +} + +bool +strs_has(char **strs, const char *str) +{ + if (!strs) { + return false; + } + char **s; + for (s = strs; *s; s++) { + if (!strcmp(*s, str)) { + return true; + } + } + return false; +} + +void +strs_add(char ***strs, const char *str) +{ + int i = 0; + if (*strs) { + char **s; + for (s = *strs; *s; s++, i++); + } + *strs = erealloc(*strs, (i+2) * sizeof(char *)); + (*strs)[i] = strdup(str); + (*strs)[i+1] = NULL; +} + +int +strs_get_index_if_in(char **strs, const char *str) +{ + if (!strs) { + return -1; + } + int i; + for (i = 0; strs[i]; i++) { + if (!strcmp(strs[i], str)) { + return i; + } + } + return -1; +} + +void +strs_free(char **strs) +{ + if (!strs) { + return; + } + char **s; + for (s = strs; *s; s++) { + free(*s); + } + free(strs); +} + +enum FileType +file_type(const char *path) +{ + struct stat s; + if (stat(path, &s) != 0) { + return F_ERROR; + } + if (S_ISDIR(s.st_mode)) { + return F_FOLDER; + } + if (S_ISREG(s.st_mode)) { + return F_REG_FILE; + } + return F_OTHER; +} + +char * +file_read(FILE *fp) +{ + char *str = NULL; + char buf; + size_t read; + int i = 0; + while (1) { + read = fread(&buf, 1, 1, fp); + if (read == 1) { + str = erealloc(str, (i+1) * sizeof(char)); + str[i] = buf; + i++; + } else { + str = erealloc(str, (i+1) * sizeof(char)); + str[i] = 0; + break; + } + } + return str; +} + +char * +file_extension_replace_or_add(const char *filepath, const char *extension) +{ + size_t extension_len = strlen(extension); + char *new = NULL; + int mark = -1; + int i, k; + int path_len; + for (i = 0; filepath[i]; i++) { + if (filepath[i] == '.') { + mark = i; + } + } + if (mark == -1) { + path_len = (int)strlen(filepath); + new = emalloc((path_len+2+extension_len) * sizeof(char)); + for (i = 0; i < path_len; i++) { + new[i] = filepath[i]; + } + new[i] = '.'; + i++; + for (k = 0; extension[k]; k++, i++) { + new[i] = extension[k]; + } + new[i] = 0; + } else { + new = emalloc((mark+2+extension_len) * sizeof(char)); + for (i = 0; i <= mark; i++) { + new[i] = filepath[i]; + } + for (k = 0; extension[k]; k++, i++) { + new[i] = extension[k]; + } + new[i] = 0; + } + return new; +} + +bool +file_extension_equals(const char *filepath, const char *extension) +{ + int mark = -1; + int i; + for (i = strlen(filepath)-1; i >= 0; i--) { + if (filepath[i] == '.') { + mark = i; + break; + } + } + if (!strcmp(&filepath[mark+1], extension)) { + return true; + } + return false; +} + +char * +filepath_add_ending_slash_if_missing(const char *path) +{ + size_t len = strlen(path); + if (path[len-1] == '/') { + return strdup(path); + } else { + char *path_with_slash = emalloc((len+2) * sizeof(char)); + strcpy(path_with_slash, path); + path_with_slash[len] = '/'; + path_with_slash[len+1] = 0; + return path_with_slash; + } +} + +char * +filepath_basename(const char *path) +{ + int begin = 0; + int i; + for (i = 0; path[i]; i++) { + if (path[i] == '/') { + begin = i+1; + } + } + return strdup(&path[begin]); +} + +char * +filepath_dirname(const char *path) +{ + char *dirname; + int i, end = 0; + for (i = 0; path[i]; i++) { + if (path[i] == '/') { + end = i; + } + } + if (end == 0) { + dirname = emalloc(2 * sizeof(char)); + dirname[0] = '.'; + dirname[1] = 0; + return dirname; + } + dirname = emalloc((end+1)* sizeof(char)); + for (i = 0; i < end; i++) { + dirname[i] = path[i]; + } + dirname[i] = 0; + return dirname; +} + +char * +filepath_resolve_tilde(const char *path) +{ + char *home; + char *str = NULL; + if (*path == '~') { + home = getenv("HOME"); + if (!home) { + LOG_DEBUG("getenv failed."); + return NULL; + } + str = erealloc(str, (strlen(home)+strlen(path)) * sizeof(char)); + strcpy(str, home); + strcat(str, &path[1]); + return str; + } else { + return strdup(path); + } +} + +static const char * +size_type_to_string(enum SizeType type) +{ + switch (type) { + case ST_PERCENT: + return "%"; + case ST_EM: + return "em"; + case ST_EX: + return "ex"; + default: + return ""; + } +} + +struct Size * +size_create(const char *str) +{ + size_t len = strlen(str); + struct Size *size = emalloc(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(NULL, 0, LOG_ERR, "invalid percentage."); + return NULL; + } + size->d = d / 100.0; + 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 = emalloc(sizeof(struct Size)); + copy->type = size->type; + copy->d = size->d; + return copy; +} + +const char * +size_to_string(struct Size *size) +{ + static char str[10+1]; + if (size->d > 999999) { + sprintf((char *)&str, ">999.999"); + } else { + sprintf((char *)&str, "%.1f%s", size->d, size_type_to_string(size->type)); + } + return str; +} + +const char * +is_base_font(struct Font *font) +{ + if (!strcmp(font->name, "Courier")) { + if (font->style == FS_ITALIC && font->weight == FW_BOLD) { + return "Courier-BoldItalic"; + } else + if (font->style == FS_ITALIC) { + return "Courier-Italic"; + } else + if (font->weight == FW_BOLD) { + return "Courier-Bold"; + } + return "Courier"; + } else + if (!strcmp(font->name, "Helvetica")) { + if (font->style == FS_OBLIQUE && font->weight == FW_BOLD) { + return "Helvetica-BoldOblique"; + } else + if (font->style == FS_OBLIQUE) { + return "Helvetica-Oblique"; + } else + if (font->weight == FW_BOLD) { + return "Helvetica-Bold"; + } + return "Helvetica"; + } else + if (!strcmp(font->name, "Times")) { + if (font->style == FS_ITALIC && font->weight == FW_BOLD) { + return "Times-BoldItalic"; + } else + if (font->style == FS_ITALIC) { + return "Times-Italic"; + } else + if (font->weight == FW_BOLD) { + return "Times-Bold"; + } + return "Times-Roman"; + } + return NULL; +} diff --git a/src/core.h b/src/core.h @@ -0,0 +1,419 @@ +#include <stdint.h> +#include <stdarg.h> + +#ifndef _CORE_H_ +#define _CORE_H_ + +#ifdef DEBUG +#define LOG_DEBUG(msg) fprintf(stderr, msg"\n") +#else +#define LOG_DEBUG(msg) +#endif + +#define LENGTH(x) (sizeof x / sizeof x[0]) + +#define COLOR_BOLD_RED "\033[1;31m" +#define COLOR_BOLD_ORANGE "\033[1;33m" +#define COLOR_BOLD_WHITE "\033[1;37m" +#define COLOR_BOLD_BLUE "\033[1;34m" +#define COLOR_RESET "\033[0m" + +enum TextType { + TT_CHORD, + TT_ANNOT, + TT_CHORUS, + TT_FOOTER, + TT_GRID, + TT_TAB, + TT_TOC, + TT_TOC_TITLE, + TT_TEXT, + TT_TITLE, + TT_SUBTITLE, + TT_LABEL, + TT_COMMENT, + TT_COMMENT_ITALIC, + TT_COMMENT_BOX, + TT_LENGTH +}; + +enum Alignment { + A_LEFT, + A_CENTER, + A_RIGHT +}; + +enum Anchor { + AN_PAPER, + AN_PAGE, + AN_COLUMN, + AN_LINE, + AN_FLOAT +}; + +enum BreakType { + BT_LINE, + BT_PAGE, + BT_COLUMN +}; + +enum ChordDiagramContent { + CDC_UNINITIALIZED, + CDC_STRING, + CDC_KEYBOARD, + CDC_CHORD_MAP +}; + +enum ChordQualifier { + CQ_MIN, + CQ_MAJ, + CQ_AUG, + CQ_DIM +}; + +enum SectionType { + ST_NEWSONG, + ST_CHORUS, + ST_VERSE, + ST_BRIDGE, + ST_TAB, + ST_GRID, + ST_CUSTOM +}; + +enum SizeType { + ST_POINT, + ST_PERCENT, + ST_EM, + ST_EX +}; + +enum FontFamily { + FF_NORMAL, + FF_SANS, + FF_SERIF, + FF_MONOSPACE +}; + +enum FontStyle { + FS_ROMAN, + FS_OBLIQUE, + FS_ITALIC +}; + +enum FontWeight { + FW_REGULAR, + FW_BOLD +}; + +enum LineStyle { + LS_SINGLE, + LS_DOUBLE, + LS_NONE +}; + +enum NoteType { + NT_NOTE, + NT_SHARP, + NT_FLAT +}; + +struct FontPresence { + bool name; + bool family; + bool style; + bool weight; + bool size; +}; + +struct ChoStylePresence { + struct FontPresence font; + bool foreground_color; + bool background_color; + bool underline_style; + bool underline_color; + bool overline_style; + bool overline_color; + bool strikethrough; + bool strikethrough_color; + bool boxed; + bool boxed_color; + bool rise; + bool href; +}; + +struct Font { + char *name; + enum FontFamily family; + enum FontStyle style; + enum FontWeight weight; + double size; +}; + +struct RGBColor { + uint8_t red; + uint8_t green; + uint8_t blue; +}; + +struct ChoStyle { + struct Font *font; + struct RGBColor *foreground_color; + struct RGBColor *background_color; + struct RGBColor *underline_color; + struct RGBColor *overline_color; + struct RGBColor *strikethrough_color; + struct RGBColor *boxed_color; + char *href; + enum LineStyle underline_style; + enum LineStyle overline_style; + bool strikethrough; + bool boxed; + double rise; +}; + +struct ChoChord { + struct ChoStyle *style; + bool is_canonical; + char *name; + char *root; + enum ChordQualifier qual; + char *ext; + char *bass; + char *display; +}; + +struct ChoText { + struct ChoStyle *style; + char *text; +}; + +struct ChoLineItem { + bool is_text; + union { + struct ChoImage *image; + struct ChoText *text; + } u; +}; + +struct ChoLineItemAbove { + int position; + bool is_chord; + union { + struct ChoChord *chord; + struct ChoText *annot; + } u; +}; + +struct ChoLine { + struct ChoLineItemAbove **text_above; + struct ChoLineItem **items; + enum BreakType btype; +}; + +struct ChoMetadata { + char *name; + char *value; + struct ChoStyle *style; +}; + +struct ChoSection { + enum SectionType type; + struct ChoText *label; + struct ChoLine **lines; +}; + +struct ChoSong { + struct ChoMetadata **metadata; + struct ChoSection **sections; + struct ChordDiagram **diagrams; + bool present_text_types[TT_LENGTH]; +}; + +struct ChoImage { + bool is_asset; + char *id; + char *src; + struct Size *width; + struct Size *height; + struct Size *width_scale; + struct Size *height_scale; + enum Alignment align; + double border; + struct Size *spread_space; + char *href; + struct Size *x; + struct Size *y; + enum Anchor anchor; + struct Size *dx; + struct Size *dy; + struct Size *w; + struct Size *h; + bool bbox; +}; + +struct Size { + enum SizeType type; + double d; +}; + +struct StringDiagram { + char *name; + int8_t base_fret; + int8_t frets[12]; + int8_t fingers[12]; +}; + +struct KeyboardDiagram { + char *name; + int8_t keys[24]; +}; + +struct ChordMap { + char *name; + char *display; +}; + +struct ChordDiagram { + bool show; + struct RGBColor *color; + enum ChordDiagramContent type; + union { + struct StringDiagram *sd; + struct KeyboardDiagram *kd; + struct ChordMap *cm; + } u; +}; + +enum NotationSystem { + NS_COMMON, + NS_GERMAN, + NS_SCANDINAVIAN, + NS_LATIN, + NS_ROMAN, + NS_NASHVILLE, + NS_CUSTOM +}; + +enum ParseMode { + PM_STRICT, + PM_RELAXED +}; + +enum Instrument { + INS_GUITAR, + INS_KEYBOARD, + INS_MANDOLIN, + INS_UKULELE +}; + +struct InstrumentInfo { + char *name; + char *description; + char *tuning; +}; + +struct Note { + char *note; + char *sharp; + char *flat; +}; + +struct ConfigChords { + enum NotationSystem notation_system; + enum ParseMode mode; +}; + +struct ConfigChorus { + char *label; + bool quote; +}; + +struct ConfigParser { + struct ConfigChords *chords; + struct Note **notes; +}; + +struct ConfigChordDiagram { + bool show; + enum Instrument instrument; +}; + +struct ConfigToc { + bool show; + char *title; +}; + +struct ConfigPageNo { + bool show; + enum Alignment align; +}; + +struct ConfigOutput { + struct ConfigChorus *chorus; + struct ConfigToc *toc; + struct ConfigChordDiagram *diagram; + struct ConfigPageNo *page_no; + struct ChoStyle *styles[TT_LENGTH]; + struct Note **notes; + enum NotationSystem notation_system; + bool start_song_on_new_page; +}; + +struct Config { + char *metadata_separator; + struct ConfigOutput *output; + struct ConfigParser *parser; +}; + +enum LogLevel { + LOG_INFO, + LOG_WARN, + LOG_ERR, + LOG_TODO +}; + +enum FileType { + F_ERROR, + F_FOLDER, + F_REG_FILE, + F_OTHER +}; + +void util_log_enable_info_logs(void); + +void *emalloc(size_t size); +void *erealloc(void *ptr, size_t size); +void util_vlog(const char *file, size_t line_no, enum LogLevel level, const char *msg, va_list va); +void util_log(const char *file, size_t line_no, enum LogLevel level, const char *msg, ...); + +bool str_starts_with(const char *str, const char *part); +char *str_normalize(const char *str); +char *str_trim(const char *str); +char *str_remove_leading_whitespace(const char *str); +int str_compare(const char *a, const char *b); +long str_to_number(const char *str); + +bool strs_has(char **strs, const char *str); +void strs_add(char ***strs, const char *str); +int strs_get_index_if_in(char **strs, const char *str); +void strs_free(char **strs); + + +enum FileType file_type(const char *path); +char *file_read(FILE *fp); +char *file_extension_replace_or_add(const char *filepath, const char *extension); +bool file_extension_equals(const char *filepath, const char *extension); + +char *filepath_add_ending_slash_if_missing(const char *path); +char *filepath_basename(const char *path); +char *filepath_dirname(const char *path); +char *filepath_resolve_tilde(const char *path); + +struct Size *size_create(const char *str); +struct Size *size_copy(struct Size *size); +const char *size_to_string(struct Size *size); + +const char *is_base_font(struct Font *font); + +#endif /* _CORE_H_ */ diff --git a/src/lorid.c b/src/lorid.c @@ -3,11 +3,10 @@ #include <stdbool.h> #include <string.h> #include <getopt.h> -#include "types.h" +#include "core.h" #include "chordpro.h" #include "config.h" #include "out_pdf.h" -#include "util.h" int main(int argc, char *argv[]) @@ -25,8 +24,10 @@ main(int argc, char *argv[]) const char *chordpro_filepath = NULL; char *config_filepath = NULL; char *output = NULL; - char *input; - struct ChoSong **so, **all_songs = NULL, **songs = NULL; + char *input, *pdf_filename; + struct ChoSong **all_songs = NULL; + struct ChoSong **songs = NULL; + struct ChoSong **so; int s = 0; FILE *fp; while ((o = getopt_long(argc, argv, "pc:o:Vvh", long_options, &option_index)) != -1) { @@ -110,7 +111,7 @@ main(int argc, char *argv[]) all_songs[s] = NULL; } qsort(all_songs, cho_song_count(all_songs), sizeof(struct ChoSong *), cho_song_compare); - char *pdf_filename = out_pdf_create(chordpro_filepath, output, all_songs, config); + pdf_filename = out_pdf_create(chordpro_filepath, output, all_songs, config); if (!pdf_filename) { LOG_DEBUG("out_pdf_new failed."); return 1; diff --git a/src/out_pdf.c b/src/out_pdf.c @@ -9,11 +9,10 @@ #include <grapheme.h> #include <math.h> #include <linux/limits.h> -#include "types.h" +#include "core.h" #include "out_pdf.h" #include "chordpro.h" #include "config.h" -#include "util.h" #include "chord_diagram.h" static struct Obj **g_fonts = NULL; @@ -268,10 +267,11 @@ fontpath_find(struct Font *font, enum FontType font_type) } FcValue type; type.type = FcTypeString; - if (font_type == FT_OTF) + if (font_type == FT_OTF) { type.u.s = (FcChar8 *)"CFF"; - else + } else { type.u.s = (FcChar8 *)"TrueType"; + } FcPatternAdd(pattern, FC_FONTFORMAT, type, FcFalse); FcValue style; style.type = FcTypeInteger; @@ -2312,6 +2312,8 @@ pdf_content_create( struct PDFImage ***imgs; struct PDFContext ctx; struct ChordDiagram ***diagrams, **dgrams, **d; + char *metadata; + struct ChoStyle *metadata_style; bool show_diagram = config->output->diagram->show; bool start_song_on_new_page = config->output->start_song_on_new_page; double width, height; @@ -2352,29 +2354,27 @@ pdf_content_create( } cho_chords_free(chords); } - char *value; - struct ChoStyle *value_style; - if (!cho_metadata_value(songs[s]->metadata, "title", config->metadata_separator, &value, &value_style)) { + if (!cho_metadata_value(songs[s]->metadata, "title", config->metadata_separator, &metadata, &metadata_style)) { LOG_DEBUG("cho_metadata_value failed."); return false; } ctx.content->toc = erealloc(ctx.content->toc, (ctx.toc_entry+1) * sizeof(struct TocEntry *)); ctx.content->toc[ctx.toc_entry] = emalloc(sizeof(struct TocEntry)); - ctx.content->toc[ctx.toc_entry]->title = strdup(value); + ctx.content->toc[ctx.toc_entry]->title = strdup(metadata); ctx.content->toc[ctx.toc_entry]->page_index = ctx.page; ctx.content->toc[ctx.toc_entry]->page_y = ctx.y; ctx.toc_entry++; - if (!pdf_texts_add_text(&ctx, value, value_style, A_CENTER, NUS_WESTERN_ARABIC)) { + if (!pdf_texts_add_text(&ctx, metadata, metadata_style, A_CENTER, NUS_WESTERN_ARABIC)) { LOG_DEBUG("pdf_texts_add_text(title) failed."); return false; } - free(value); - if (cho_metadata_value(songs[s]->metadata, "subtitle", config->metadata_separator, &value, &value_style)) { - if (!pdf_texts_add_text(&ctx, value, value_style, A_CENTER, NUS_WESTERN_ARABIC)) { + free(metadata); + if (cho_metadata_value(songs[s]->metadata, "subtitle", config->metadata_separator, &metadata, &metadata_style)) { + if (!pdf_texts_add_text(&ctx, metadata, metadata_style, A_CENTER, NUS_WESTERN_ARABIC)) { LOG_DEBUG("pdf_texts_add_text(subtitle) failed."); return false; } - free(value); + free(metadata); } texts = &ctx.content->pages[ctx.page]->texts; imgs = &ctx.content->pages[ctx.page]->images; @@ -2490,8 +2490,9 @@ pdf_content_create( ctx.y = MEDIABOX_HEIGHT - MARGIN_TOP; if (text_above_exist) { /* INFO: chords/annotations and their corresponding lyrics won't be splitted */ + int p; double prev_y = (*texts)[ctx.text-1]->y; - for (int p = ctx.text-1; prev_y == (*texts)[p]->y; p--) { + for (p = ctx.text-1; prev_y == (*texts)[p]->y; p--) { (*texts)[p]->y = ctx.y; tmp = erealloc(tmp, (tm+1) * sizeof(struct PDFText *)); tmp[tm] = (*texts)[p]; diff --git a/src/out_pdf.h b/src/out_pdf.h @@ -1,5 +1,5 @@ #include <pdfio.h> -#include "types.h" +#include "core.h" #include "chordpro.h" #define MEDIABOX_HEIGHT 841.995 diff --git a/src/util.c b/src/util.c @@ -9,7 +9,7 @@ #include <errno.h> #include <assert.h> #include <limits.h> -#include "types.h" +#include "core.h" #include "util.h" static bool g_show_info_logs = false;