35#ifdef HAVE_DL_ITERATE_PHDR
47static void globfree(glob_t *pglob);
48static int glob(
GVC_t *
gvc,
char *,
int,
int (*errfunc)(
const char *,
int),
57#include <mach-o/dyld.h>
101 const char *package_path,
121static void separator(
int *nest,
char **tokens) {
146 if (c ==
' ' || c ==
'\n' || c ==
'\t') {
159static char *token(
int *nest,
char **tokens) {
164 if (c ==
'#' || c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'{' || c ==
'}')
169 separator(nest, tokens);
174static int gvconfig_plugin_install_from_config(
GVC_t *
gvc,
char *
s) {
177 separator(&nest, &
s);
179 char *
const package_path = token(&nest, &
s);
180 char *
const name = nest == 0 ? token(&nest, &
s) :
"x";
182 gvplugin_package_record(gvc, package_path, name);
184 const char *api = token(&nest, &
s);
186 if (gv_api == (
api_t)-1) {
187 agerrorf(
"config error: %s %s not found\n", package_path, api);
192 const char *
const type = token(&nest, &
s);
193 const int quality = nest == 2 ? atoi(token(&nest, &
s)) : 0;
196 agerrorf(
"config error: %s %s %s\n", package_path, api,
type);
214 package = gvplugin_package_record(gvc, package_path, library->packagename);
216 for (i = 0; types[i].
type; i++) {
231 if (name[0] ==
'g' && strstr(name,
"_LTX_library"))
236static void gvconfig_write_library_config(
GVC_t *
gvc,
char *lib_path,
241 fprintf(f,
"%s %s {\n", lib_path, library->
packagename);
244 for (
size_t i = 0; types[i].
type; i++) {
248 fprintf(f,
"#FAILS");
249 fprintf(f,
"\t\t%s %d\n", types[i].
type, types[i].quality);
257#define DOTLIBS "/.libs"
259#ifdef HAVE_DL_ITERATE_PHDR
260static int line_callback(
struct dl_phdr_info *
info,
size_t size,
void *xb) {
261 const char *p =
info->dlpi_name;
262 const char *
const tmp = strstr(p,
"/libgvc.");
266 for (slash = tmp - 1; *slash !=
'/'; --slash)
269 if (strncmp(slash, DOTLIBS, (
size_t)(tmp - slash)) != 0) {
272 agxbprint(xb,
"%.*s/graphviz", (
int)(tmp - p), p);
282 static atomic_flag dirShown;
284 const char *
const gvbindir = getenv(
"GVBINDIR");
285 if (gvbindir !=
NULL) {
292 MEMORY_BASIC_INFORMATION mbi;
294 agerrorf(
"failed to get handle for executable.\n");
298 char line[BSZ] = {0};
299 r = GetModuleFileName((HMODULE)mbi.AllocationBase, line, BSZ);
300 if (!r || (r == BSZ)) {
301 agerrorf(
"failed to get path for executable.\n");
304 s = strrchr(line,
'\\');
306 agerrorf(
"no slash in path %s.\n", line);
314 uint32_t i, c = _dyld_image_count();
316 for (i = 0; i < c; ++i) {
317 const char *p = _dyld_get_image_name(i);
318 const char *tmp = strstr(p,
"/libgvc.");
322 const char *
s = tmp - 1;
324 while (*
s !=
'/' &&
s > p)
333 agxbprint(&libdir,
"%.*s/graphviz", (
int)ind, p);
337#elif defined(HAVE_DL_ITERATE_PHDR)
338 dl_iterate_phdr(line_callback, &libdir);
340 FILE *f =
gv_fopen(
"/proc/self/maps",
"r");
343 char line[BSZ] = {0};
344 if (!fgets(line,
sizeof(line), f))
346 if (!strstr(line,
" r-xp "))
348 char *p = strchr(line,
'/');
351 char *tmp = strstr(p,
"/libgvc.");
355 if (strcmp(strrchr(p,
'/'), DOTLIBS) == 0)
370 fprintf(stderr,
"libdir = \"%s\"\n", dir);
378static bool is_plugin(
const char *filepath) {
380 if (filepath ==
NULL) {
385#if defined(DARWIN_DYLIB)
386 static const char SUFFIX[] =
".dylib";
387#elif defined(__MINGW32__) || defined(__CYGWIN__) || defined(_WIN32)
388 static const char SUFFIX[] =
".dll";
390 static const char SUFFIX[] =
"";
394 size_t len = strlen(filepath);
395 if (
len < strlen(SUFFIX) ||
396 strcmp(filepath +
len - strlen(SUFFIX), SUFFIX) != 0) {
399 len -= strlen(SUFFIX);
401#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
404#elif defined(GVPLUGIN_VERSION)
406#define STRINGIZE_(x) #x
407#define STRINGIZE(x) STRINGIZE_(x)
408 static const char VERSION[] = STRINGIZE(GVPLUGIN_VERSION);
413 if (
len < strlen(VERSION) ||
417 len -= strlen(VERSION);
431#if defined(DARWIN_DYLIB)
435#elif defined(__MINGW32__) || defined(__CYGWIN__)
444 static const char SO[] =
".so.";
453static void config_rescan(
GVC_t *
gvc,
char *config_path) {
459#if defined(DARWIN_DYLIB)
460 char *plugin_glob =
"libgvplugin_*";
461#elif defined(__MINGW32__)
462 char *plugin_glob =
"libgvplugin_*";
463#elif defined(__CYGWIN__)
464 char *plugin_glob =
"cyggvplugin_*";
466 char *plugin_glob =
"gvplugin_*";
468 char *plugin_glob =
"libgvplugin_*";
474 agerrorf(
"failed to open %s for write.\n", config_path);
479 "# This file was generated by \"dot -c\" at time of install.\n\n");
480 fprintf(f,
"# You may temporarily disable a plugin by removing or "
482 fprintf(f,
"# a line in this file, or you can modify its \"quality\" value "
484 fprintf(f,
"# default plugin selection.\n\n");
485 fprintf(f,
"# Manual edits to this file **will be lost** on upgrade.\n\n");
497 rc = glob(
gvc,
agxbuse(&config_glob), GLOB_NOSORT,
NULL, &globbuf);
499 rc = glob(
agxbuse(&config_glob), 0,
NULL, &globbuf);
502 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
503 if (is_plugin(globbuf.gl_pathv[i])) {
512 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
513 if (is_plugin(globbuf.gl_pathv[i])) {
520 gvconfig_write_library_config(
gvc, p, library, f);
538 struct stat config_st;
540 char *config_text =
NULL;
542 char *config_file_name = GVPLUGIN_CONFIG_FILE;
554 if (access(libdir, F_OK) < 0) {
574 "config rescan performed without any prior first scan");
589 }
else if (config_st.st_size == 0) {
592 config_text =
gv_alloc((
size_t)config_st.st_size + 1);
593 size_t sz = fread(config_text, 1, (
size_t)config_st.st_size, f);
598 config_text[sz] =
'\0';
599 rc = gvconfig_plugin_install_from_config(
gvc, config_text);
628 int (*errfunc)(
const char *,
int), glob_t *pglob) {
636 pglob->gl_pathv =
NULL;
641 for (
size_t i = 0; pattern[i] !=
'\0'; ++i) {
642 if (pattern[i] ==
'/') {
648 HANDLE h = FindFirstFile(pattern, &wfd);
649 if (h == INVALID_HANDLE_VALUE)
656 }
while (FindNextFile(h, &wfd));
659 LIST_DETACH(&strs, &pglob->gl_pathv, &pglob->gl_pathc);
665static void globfree(glob_t *pglob) {
666 for (
int i = 0; i < pglob->gl_pathc; i++)
667 free(pglob->gl_pathv[i]);
668 free(pglob->gl_pathv);
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
static size_t agxbput_n(agxbuf *xb, const char *s, size_t ssz)
append string s of length ssz into xb
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static void agxbclear(agxbuf *xb)
resets pointer to data
static WUR char * agxbuse(agxbuf *xb)
static char * agxbdisown(agxbuf *xb)
Memory allocation wrappers that exit on failure.
static char * gv_strdup(const char *original)
static void * gv_alloc(size_t size)
static NORETURN void graphviz_exit(int status)
static double len(glCompPoint p)
void agerrorf(const char *fmt,...)
replacements for ctype.h functions
static bool gv_isdigit(int c)
FILE * gv_fopen(const char *filename, const char *mode)
wrapper around fopen for internal library usage
static gvplugin_package_t * gvplugin_package_record(GVC_t *gvc, const char *package_path, const char *name)
void gvconfig(GVC_t *gvc, bool rescan)
void textfont_dict_open(GVC_t *gvc)
void gvconfig_plugin_install_from_library(GVC_t *gvc, char *package_path, gvplugin_library_t *library)
static void gvconfig_plugin_install_builtins(GVC_t *gvc)
gvplugin_library_t * gvplugin_library_load(GVC_t *gvc, const char *pathname)
api_t gvplugin_api(const char *str)
gvplugin_available_t * gvplugin_load(GVC_t *gvc, api_t api, const char *type, FILE *debug)
int gvtextlayout_select(GVC_t *gvc)
char * gvplugin_api_name(api_t api)
bool gvplugin_install(GVC_t *gvc, api_t api, const char *typestr, int quality, gvplugin_package_t *package, gvplugin_installed_t *typeptr)
WUR char * gvconfig_libdir(GVC_t *gvc)
The return value is heap-allocated and should be freed by the caller.
static gvplugin_api_t apis[]
type-generic dynamically expanding list
#define LIST_DETACH(list, datap, sizep)
#define LIST_APPEND(list,...)
File system path helpers.
#define PATH_SEPARATOR
character for separating directory components in a file system path
static bool startswith(const char *s, const char *prefix)
does the string s begin with the string prefix?
const lt_symlist_t * builtins
gvplugin_package_t * packages
gvplugin_installed_t * types
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t