Skip to content

Instantly share code, notes, and snippets.

@flibitijibibo
Created July 18, 2019 16:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save flibitijibibo/93efa0332f251de6f413b83f2c84bd47 to your computer and use it in GitHub Desktop.
Save flibitijibibo/93efa0332f251de6f413b83f2c84bd47 to your computer and use it in GitHub Desktop.
Replacement for hardcoded font paths
/* findDejaVuSans - Quick function to find DejaVuSans.ttf
*
* Copyright (c) 2019 Ethan Lee
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in a
* product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*
* Ethan "flibitijibibo" Lee <flibitijibibo@flibitijibibo.com>
*
*/
/* Replace your existing DejaVuSans.ttf path with:
*
* char fontPath[PATH_MAX];
* findDejaVuSans(fontPath, sizeof(fontPath));
*
* Be sure to only call this function once!
*/
#include <fontconfig/fontconfig.h>
#ifdef USE_SDL2
#include <SDL.h>
#define PRINTFILE(name) SDL_snprintf(path, len, "%s", name)
#define LOADSO(name) sofile = SDL_LoadObject(name)
#define LOADFN(name) SDL_LoadFunction(sofile, name)
#define UNLOADSO SDL_UnloadObject(sofile)
#else
#include <dlfcn.h>
#include <stdio.h>
#define PRINTFILE(name) snprintf(path, len, "%s", name)
#define LOADSO(name) sofile = dlopen(name, RTLD_NOW | RTLD_LOCAL)
#define LOADFN(name) dlsym(sofile, name)
#define UNLOADSO dlclose(sofile)
#endif
static inline void findDejaVuSans(char *path, size_t len)
{
/* libfontconfig */
void* sofile;
FcPattern* (*fcNameParse)(const FcChar8*);
FcBool (*fcConfigSubstitute)(FcConfig*, FcPattern*, FcMatchKind);
void (*fcDefaultSubstitute)(FcPattern*);
FcPattern* (*fcFontMatch)(FcConfig*, FcPattern*, FcResult*);
FcFontSet* (*fcFontSetCreate)(void);
FcBool (*fcFontSetAdd)(FcFontSet*, FcPattern*);
void (*fcPatternDestroy)(FcPattern*);
FcChar8* (*fcPatternFormat)(FcPattern*, const FcChar8*);
void (*fcStrFree)(FcChar8*);
void (*fcFontSetDestroy)(FcFontSet*);
void (*fcFini)(void);
FcPattern *parse = NULL, *match;
FcFontSet *set = NULL;
FcResult result;
FcChar8 *file = NULL;
/* Dynamically load Fontconfig */
LOADSO("libfontconfig.so.1");
if (sofile == NULL)
{
/* Couldn't find libfontconfig */
goto fdvsError;
}
fcNameParse = LOADFN("FcNameParse");
fcConfigSubstitute = LOADFN("FcConfigSubstitute");
fcDefaultSubstitute = LOADFN("FcDefaultSubstitute");
fcFontMatch = LOADFN("FcFontMatch");
fcFontSetCreate = LOADFN("FcFontSetCreate");
fcFontSetAdd = LOADFN("FcFontSetAdd");
fcPatternDestroy = LOADFN("FcPatternDestroy");
fcPatternFormat = LOADFN("FcPatternFormat");
fcStrFree = LOADFN("FcStrFree");
fcFontSetDestroy = LOADFN("FcFontSetDestroy");
fcFini = LOADFN("FcFini");
if ( (fcNameParse == NULL) ||
(fcConfigSubstitute == NULL) ||
(fcDefaultSubstitute == NULL) ||
(fcFontMatch == NULL) ||
(fcFontSetCreate == NULL) ||
(fcFontSetAdd == NULL) ||
(fcPatternDestroy == NULL) ||
(fcPatternFormat == NULL) ||
(fcStrFree == NULL) ||
(fcFontSetDestroy == NULL) ||
(fcFini == NULL) )
{
/* Couldn't find Fontconfig functions */
goto fdvsError;
}
/* Search setup */
parse = fcNameParse((const FcChar8*) "DejaVuSans.ttf");
if (parse == NULL)
{
/* Couldn't even parse the font name */
goto fdvsError;
}
if (fcConfigSubstitute(0, parse, FcMatchPattern) == FcFalse)
{
/* Allocation failure */
goto fdvsError;
}
fcDefaultSubstitute(parse);
/* Execute search */
match = fcFontMatch(0, parse, &result);
if (match == NULL)
{
/* Didn't find a match */
fcPatternDestroy(parse);
fcFini();
goto fdvsError;
}
set = fcFontSetCreate();
if (set == NULL)
{
/* Allocation failure */
goto fdvsError;
}
if (fcFontSetAdd(set, match) == FcFalse)
{
/* Allocation failure */
goto fdvsError;
}
fcPatternDestroy(parse);
parse = NULL;
/* Generate file path string */
file = fcPatternFormat(set->fonts[0], (const FcChar8*) "%{file}");
if (file == NULL || file[0] == '\0')
{
/* Invalid format? Allocation failure? */
fcFontSetDestroy(set);
if (file != NULL)
{
fcStrFree(file);
}
fcFini();
goto fdvsError;
}
/* Write path, clean up. We out. */
PRINTFILE(file);
fcStrFree(file);
fcFontSetDestroy(set);
fcFini();
UNLOADSO;
return;
fdvsError:
if (sofile != NULL)
{
UNLOADSO;
}
/* Screw it, just write the SteamOS location */
PRINTFILE("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
}
#if 0 /* Example Program */
#include <stdio.h>
#include <limits.h>
int main(int argc, char **argv)
{
char path[PATH_MAX];
findDejaVuSans(path, sizeof(path));
printf("%s\n", path);
return 0;
}
#endif /* Example Program */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment