From 6a519db71998fbb8d2ea4fdd749494d77bf2e98f Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 8 Jan 2023 15:44:39 +0100 Subject: Improve libfonts_get_default_font_name and draft implementation of libfonts_get_default_font MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- Makefile | 1 + common.h | 2 + libfonts.h | 41 ++------ libfonts_get_default_font.c | 210 +++++++++++++++++++++++++++++++++++++++ libfonts_get_default_font_name.c | 93 ++++++----------- 5 files changed, 254 insertions(+), 93 deletions(-) create mode 100644 libfonts_get_default_font.c diff --git a/Makefile b/Makefile index 1724961..6a96f96 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ OBJ =\ libfonts_calculate_subpixel_order.o\ libfonts_decode_font_description.o\ libfonts_encode_font_description.o\ + libfonts_get_default_font.o\ libfonts_get_default_font_name.o\ libfonts_get_output_dpi.o\ libfonts_get_subpixel_order_class.o\ diff --git a/common.h b/common.h index a940151..4937a76 100644 --- a/common.h +++ b/common.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/libfonts.h b/libfonts.h index 2caaced..25341ed 100644 --- a/libfonts.h +++ b/libfonts.h @@ -1576,49 +1576,30 @@ struct libfonts_font_description { * Get the font a default font name aliases to * * @param font The default font - * @param name Output buffer for the font the default font is an alias - * for; will always be NUL-terminated (unless `size` is 0) - * @param size Buffer size of `name` - * @return The minimum value required on `size` for a - * complete output to `name`, or -1 on failure + * @return The font the default font is an alias for + * (shall be deallocated using free(3) when no + * longer used), or `NULL` on failure; in the + * case that no font is found, `NULL` with be + * returned without modifying `errno` * * @throws EINVAL Unrecognised value on `font` */ -ssize_t libfonts_get_default_font(enum libfonts_default_font, char *, size_t); -/* TODO implement libfonts_get_default_font - * - * /etc/libfonts/default-fonts.conf - * - * sans-serif = $FONTNAME - * serif = $FONTNAME - * monospace = $FONTNAME - * - * fallback, look in /etc/libfonts/default-fonts/sans-serif/ - * /etc/libfonts/default-fonts/serif/ - * /etc/libfonts/default-fonts/monospace/ - * - * as a last resort look around for some - * font that matches the specification as - * well as possible - */ +char *libfonts_get_default_font(enum libfonts_default_font); /** * Get the alias for a default font * * @param font The default font - * @param name Output buffer for the font name; will always - * be NUL-terminated (unless `size` is 0) - * @param size Buffer size of `name` * @param index The index of the alias (some default fonts * have multiple aliases) - * @return The minimum value required on `size` for a - * complete output to `name`, 0 if `index` is - * equal to or greater than the number of - * aliases, or -1 on failure + * @param namep Output parameter for the font name + * @return If the alias exists, or 0 if `index` is equal to + * or greater than the number of aliases, or + * -1 on failure * * @throws EINVAL Unrecognised value on `font` */ -ssize_t libfonts_get_default_font_name(enum libfonts_default_font, char *, size_t, size_t); +int libfonts_get_default_font_name(enum libfonts_default_font, size_t, const char **); /** * Get a default font a font name represents diff --git a/libfonts_get_default_font.c b/libfonts_get_default_font.c new file mode 100644 index 0000000..d27e661 --- /dev/null +++ b/libfonts_get_default_font.c @@ -0,0 +1,210 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + + +static char * +find(const char *dir_part1, const char *dir_part2, const char *dir_part3) +{ + return NULL; /* TODO */ +} + +static char * +gethome(void) +{ + uid_t uid = getuid(); + size_t size = 512; + char *buf = NULL, *new; + char *ret = NULL; + struct passwd pw, *pwp; + int err; + + goto beginning; + + do { + if (size > SIZE_MAX / 2) + goto enomem; + size *= 2; + beginning: + new = realloc(buf, size); + if (!new) { + enomem: + free(buf); + errno = ENOMEM; + return NULL; + } + buf = new; + } while ((err = getpwuid_r(uid, &pw, buf, size, &pwp)) == ERANGE); + if (err) { + free(buf); + return NULL; + } + + if (pwp && pwp->pw_dir) + ret = strdup(pwp->pw_dir); + free(buf); + return ret; +} + +static char * +getn(const char *file_part1, size_t file_part1_len, const char *file_part2, const char *name) +{ + size_t file_part2_len = strlen(file_part2); + char *path; + + if (file_part1_len > SIZE_MAX - file_part2_len - 1) + goto enomem; + + path = malloc(file_part1_len + file_part2_len + 1); + if (!path) { + enomem: + errno = ENOMEM; + return NULL; + } + + memcpy(path, file_part1, file_part1_len); + memcpy(&path[file_part1_len], file_part2, file_part2_len + 1); + + /* TODO + * sans-serif = $FONTNAME + * serif = $FONTNAME + * monospace = $FONTNAME + */ + + free(path); + return NULL; +} + +static char * +get(const char *file_part1, const char *file_part2, const char *name) +{ + return getn(file_part1, strlen(file_part1), file_part2, name); +} + +char * +libfonts_get_default_font(enum libfonts_default_font font) +{ + const char *env, *var, *next; + char *ret, *home = NULL; + int saved_errno = errno; + size_t len; + + if (font == LIBFONTS_DEFAULT_SANS_SERIF) { + env = "LIBFONTS_DEFAULT_SANS_SERIF"; + var = "sans-serif"; + } else if (font == LIBFONTS_DEFAULT_SERIF) { + env = "LIBFONTS_DEFAULT_SERIF"; + var = "serif"; + } else if (font == LIBFONTS_DEFAULT_MONOSPACE) { + env = "LIBFONTS_DEFAULT_MONOSPACE"; + var = "monospace"; + } else { + errno = EINVAL; + return NULL; + } + + ret = getenv(env); + if (ret && *ret) + return strdup(ret); + + env = getenv("XDG_CONFIG_HOME"); + if (env && *env) { + ret = get(env, "/libfonts/default-fonts.conf", var); + if (ret) + goto out; + } + + env = getenv("HOME"); + if (env && *env) { + ret = get(env, "/.config/libfonts/default-fonts.conf", var); + if (ret) + goto out; + ret = get(env, "/.libfonts/default-fonts.conf", var); + if (ret) + goto out; + } + + home = gethome(); + if (home && *home) { + ret = get(home, "/.config/libfonts/default-fonts.conf", var); + if (ret) + goto out; + ret = get(home, "/.libfonts/default-fonts.conf", var); + if (ret) + goto out; + } + + env = getenv("XDG_CONFIG_HOME"); + if (env && *env) { + ret = find(env, "/libfonts/", var); + if (ret) + goto out; + } + + env = getenv("HOME"); + if (env && *env) { + ret = find(env, "/.config/libfonts/", var); + if (ret) + goto out; + ret = find(env, "/.libfonts/", var); + if (ret) + goto out; + } + + if (home && *home) { + ret = find(env, "/.config/libfonts/", var); + if (ret) + goto out; + ret = find(env, "/.libfonts/", var); + if (ret) + goto out; + } + + env = getenv("XDG_CONFIG_DIRS"); + if (env && *env) { + do { + next = strchr(&env[1], ':'); + len = next ? (size_t)(next - env) : strlen(env); + if (len) { + ret = getn(env, len, "/libfonts/default-fonts.conf", var); + if (ret) + goto out; + } + env += len + 1; + } while (next); + } + + ret = get("/etc", "/libfonts/default-fonts.conf", var); + if (ret) + goto out; + + ret = find("/etc", "/libfonts/", var); + if (ret) + goto out; + + /* TODO + * as a last resort look around for some + * font that matches the specification as + * well as possible + */ + + ret = NULL; + +out: + free(home); + errno = saved_errno; + return ret; +} + + +#else + + +int +main(void) +{ + return 0; /* TODO add test */ +} + + +#endif diff --git a/libfonts_get_default_font_name.c b/libfonts_get_default_font_name.c index 9165d8a..66d14cb 100644 --- a/libfonts_get_default_font_name.c +++ b/libfonts_get_default_font_name.c @@ -3,11 +3,10 @@ #ifndef TEST -ssize_t -libfonts_get_default_font_name(enum libfonts_default_font font, char *name, size_t size, size_t index) +int +libfonts_get_default_font_name(enum libfonts_default_font font, size_t index, const char **namep) { - const char *alias; - size_t len; + const char *alias = NULL; if (font == LIBFONTS_DEFAULT_SANS_SERIF) { if (index == 0) @@ -16,37 +15,25 @@ libfonts_get_default_font_name(enum libfonts_default_font font, char *name, size alias = "sans serif"; else if (index == 2) alias = "sans"; - else - return 0; } else if (font == LIBFONTS_DEFAULT_SERIF) { if (index == 0) alias = "serif"; - else - return 0; } else if (font == LIBFONTS_DEFAULT_MONOSPACE) { if (index == 0) alias = "monospace"; else if (index == 1) alias = "monospaced"; - else - return 0; } else { errno = EINVAL; return -1; } - len = strlen(alias); - if (size) { - size -= 1; - if (size > len) - size = len; - memcpy(name, alias, size); - name[size] = '\0'; - } - return (ssize_t)(len + 1); + if (namep) + *namep = alias; + return alias != NULL; } @@ -56,68 +43,48 @@ libfonts_get_default_font_name(enum libfonts_default_font font, char *name, size int main(void) { -#define T(FONT, INDEX, SIZE, NAME, NAMELEN)\ + const char *r; + +#define T(FONT, INDEX, NAME)\ do {\ errno = 0;\ - ASSERT(libfonts_get_default_font_name(FONT, buf, SIZE, INDEX) == NAMELEN);\ - ASSERT(!buf[SIZE - 1]);\ - ASSERT(!strcmp(buf, NAME));\ + ASSERT(libfonts_get_default_font_name(FONT, INDEX, &r) == 1);\ + ASSERT(r != NULL);\ + ASSERT(!strcmp(r, NAME));\ + ASSERT(!errno);\ + ASSERT(libfonts_get_default_font_name(FONT, INDEX, NULL) == 1);\ ASSERT(!errno);\ } while (0) -#define X(FONT, INDEX, SIZE)\ +#define X(FONT, INDEX)\ do {\ errno = 0;\ - ASSERT(libfonts_get_default_font_name(FONT, buf, SIZE, INDEX) == 0);\ - ASSERT(!buf[SIZE - 1]);\ + ASSERT(libfonts_get_default_font_name(FONT, INDEX, &r) == 0);\ + ASSERT(r == NULL);\ + ASSERT(!errno);\ + ASSERT(libfonts_get_default_font_name(FONT, INDEX, NULL) == 0);\ ASSERT(!errno);\ } while (0) - char buf[50]; - errno = 0; - ASSERT(libfonts_get_default_font_name(-1, buf, sizeof(buf), 0) == -1); + ASSERT(libfonts_get_default_font_name(-1, 0, &r) == -1); ASSERT(errno == EINVAL); errno = 0; - ASSERT(libfonts_get_default_font_name(99, buf, sizeof(buf), 0) == -1); + ASSERT(libfonts_get_default_font_name(99, 0, &r) == -1); ASSERT(errno == EINVAL); - T(LIBFONTS_DEFAULT_SANS_SERIF, 0, sizeof(buf), "sans-serif", 11); - T(LIBFONTS_DEFAULT_SANS_SERIF, 1, sizeof(buf), "sans serif", 11); - T(LIBFONTS_DEFAULT_SANS_SERIF, 2, sizeof(buf), "sans", 5); - X(LIBFONTS_DEFAULT_SANS_SERIF, 3, sizeof(buf)); - - T(LIBFONTS_DEFAULT_SERIF, 0, sizeof(buf), "serif", 6); - X(LIBFONTS_DEFAULT_SERIF, 1, sizeof(buf)); - - T(LIBFONTS_DEFAULT_MONOSPACE, 0, sizeof(buf), "monospace", 10); - T(LIBFONTS_DEFAULT_MONOSPACE, 1, sizeof(buf), "monospaced", 11); - X(LIBFONTS_DEFAULT_MONOSPACE, 2, sizeof(buf)); - - T(LIBFONTS_DEFAULT_SANS_SERIF, 0, 4, "san", 11); - T(LIBFONTS_DEFAULT_SANS_SERIF, 1, 4, "san", 11); - T(LIBFONTS_DEFAULT_SANS_SERIF, 2, 4, "san", 5); - X(LIBFONTS_DEFAULT_SANS_SERIF, 3, 4); - - T(LIBFONTS_DEFAULT_SERIF, 0, 4, "ser", 6); - X(LIBFONTS_DEFAULT_SERIF, 1, 4); - - T(LIBFONTS_DEFAULT_MONOSPACE, 0, 4, "mon", 10); - T(LIBFONTS_DEFAULT_MONOSPACE, 1, 4, "mon", 11); - X(LIBFONTS_DEFAULT_MONOSPACE, 2, 4); - - errno = 0; - - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_SANS_SERIF, NULL, 0, 0) == 11); - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_SERIF, NULL, 0, 0) == 6); - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_MONOSPACE, NULL, 0, 0) == 10); + T(LIBFONTS_DEFAULT_SANS_SERIF, 0, "sans-serif"); + T(LIBFONTS_DEFAULT_SANS_SERIF, 1, "sans serif"); + T(LIBFONTS_DEFAULT_SANS_SERIF, 2, "sans"); + X(LIBFONTS_DEFAULT_SANS_SERIF, 3); - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_SANS_SERIF, NULL, 0, 3) == 0); - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_SERIF, NULL, 0, 1) == 0); - ASSERT(libfonts_get_default_font_name(LIBFONTS_DEFAULT_MONOSPACE, NULL, 0, 2) == 0); + T(LIBFONTS_DEFAULT_SERIF, 0, "serif"); + X(LIBFONTS_DEFAULT_SERIF, 1); - ASSERT(!errno); + T(LIBFONTS_DEFAULT_MONOSPACE, 0, "monospace"); + T(LIBFONTS_DEFAULT_MONOSPACE, 1, "monospaced"); + X(LIBFONTS_DEFAULT_MONOSPACE, 2); return 0; } -- cgit v1.2.3-70-g09d2