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:
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;