35#ifdef HAVE_DL_ITERATE_PHDR
49static void globfree (glob_t* pglob);
50static int glob (
GVC_t *
gvc,
char*,
int,
int (*errfunc)(
const char *,
int), glob_t*);
58#include <mach-o/dyld.h>
102 const char *package_path,
122static void separator(
int *nest,
char **tokens)
148 if (c ==
' ' || c ==
'\n' || c ==
'\t') {
161static char *token(
int *nest,
char **tokens)
168 || c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'{' || c ==
'}')
173 separator(nest, tokens);
178static int gvconfig_plugin_install_from_config(
GVC_t *
gvc,
char *
s)
180 char *package_path, *name;
186 separator(&nest, &
s);
188 package_path = token(&nest, &
s);
190 name = token(&nest, &
s);
193 package = gvplugin_package_record(gvc, package_path, name);
195 const char *api = token(&nest, &
s);
197 if (gv_api == (
api_t)-1) {
198 agerrorf(
"config error: %s %s not found\n", package_path, api);
203 type = token(&nest, &
s);
205 quality = atoi(token(&nest, &
s));
210 agerrorf(
"config error: %s %s %s\n", package_path, api,
type);
228 package = gvplugin_package_record(gvc, package_path, library->packagename);
230 for (i = 0; types[i].
type; i++) {
232 types[i].
quality, package, &types[i]);
245 if (name[0] ==
'g' && strstr(name,
"_LTX_library"))
250static void gvconfig_write_library_config(
GVC_t *
gvc,
char *lib_path,
255 fprintf(f,
"%s %s {\n", lib_path, library->
packagename);
258 for (
size_t i = 0; types[i].
type; i++) {
262 fprintf(f,
"#FAILS");
263 fprintf(f,
"\t\t%s %d\n", types[i].
type, types[i].quality);
271#define DOTLIBS "/.libs"
273#ifdef HAVE_DL_ITERATE_PHDR
274static int line_callback(
struct dl_phdr_info *
info,
size_t size,
void *line)
276 const char *p =
info->dlpi_name;
278 const char *
const tmp = strstr(p,
"/libgvc.");
282 for (slash = tmp - 1; *slash !=
'/'; --slash);
284 if (strncmp(slash, DOTLIBS, (
size_t)(tmp - slash)) != 0) {
287 agxbprint(xb,
"%.*s/graphviz", (
int)(tmp - p), p);
298 static atomic_flag dirShown;
300 const char *
const gvbindir = getenv(
"GVBINDIR");
301 if (gvbindir !=
NULL) {
308 MEMORY_BASIC_INFORMATION mbi;
310 agerrorf(
"failed to get handle for executable.\n");
314 char line[BSZ] = {0};
315 r = GetModuleFileName((HMODULE)mbi.AllocationBase, line, BSZ);
316 if (!r || (r == BSZ)) {
317 agerrorf(
"failed to get path for executable.\n");
320 s = strrchr(line,
'\\');
322 agerrorf(
"no slash in path %s.\n", line);
330 uint32_t i, c = _dyld_image_count();
332 for (i = 0; i < c; ++i) {
333 const char *p = _dyld_get_image_name(i);
334 const char* tmp = strstr(p,
"/libgvc.");
338 const char *
s = tmp - 1;
340 while (*
s !=
'/' &&
s > p)
s--;
348 agxbprint(&libdir,
"%.*s/graphviz", (
int)ind, p);
352#elif defined(HAVE_DL_ITERATE_PHDR)
353 dl_iterate_phdr(line_callback, &libdir);
355 FILE* f =
gv_fopen(
"/proc/self/maps",
"r");
358 char line[BSZ] = {0};
359 if (!fgets(line,
sizeof (line), f))
361 if (!strstr(line,
" r-xp "))
363 char *p = strchr(line,
'/');
366 char* tmp = strstr(p,
"/libgvc.");
370 if (strcmp(strrchr(p,
'/'), DOTLIBS) == 0)
385 fprintf(stderr,
"libdir = \"%s\"\n", dir);
393static bool is_plugin(
const char *filepath) {
395 if (filepath ==
NULL) {
400#if defined(DARWIN_DYLIB)
401 static const char SUFFIX[] =
".dylib";
402#elif defined(__MINGW32__) || defined(__CYGWIN__) || defined(_WIN32)
403 static const char SUFFIX[] =
".dll";
405 static const char SUFFIX[] =
"";
409 size_t len = strlen(filepath);
410 if (
len < strlen(SUFFIX)
411 || strcmp(filepath +
len - strlen(SUFFIX), SUFFIX) != 0) {
414 len -= strlen(SUFFIX);
416#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
419#elif defined(GVPLUGIN_VERSION)
421 #define STRINGIZE_(x) #x
422 #define STRINGIZE(x) STRINGIZE_(x)
423 static const char VERSION[] = STRINGIZE(GVPLUGIN_VERSION);
428 if (
len < strlen(VERSION)
432 len -= strlen(VERSION);
446#if defined(DARWIN_DYLIB)
450#elif defined(__MINGW32__) || defined(__CYGWIN__)
459 static const char SO[] =
".so.";
468static void config_rescan(
GVC_t *
gvc,
char *config_path)
475#if defined(DARWIN_DYLIB)
476 char *plugin_glob =
"libgvplugin_*";
477#elif defined(__MINGW32__)
478 char *plugin_glob =
"libgvplugin_*";
479#elif defined(__CYGWIN__)
480 char *plugin_glob =
"cyggvplugin_*";
482 char *plugin_glob =
"gvplugin_*";
484 char *plugin_glob =
"libgvplugin_*";
490 agerrorf(
"failed to open %s for write.\n", config_path);
494 fprintf(f,
"# This file was generated by \"dot -c\" at time of install.\n\n");
495 fprintf(f,
"# You may temporarily disable a plugin by removing or commenting out\n");
496 fprintf(f,
"# a line in this file, or you can modify its \"quality\" value to affect\n");
497 fprintf(f,
"# default plugin selection.\n\n");
498 fprintf(f,
"# Manual edits to this file **will be lost** on upgrade.\n\n");
510 rc = glob(
gvc,
agxbuse(&config_glob), GLOB_NOSORT,
NULL, &globbuf);
512 rc = glob(
agxbuse(&config_glob), 0,
NULL, &globbuf);
515 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
516 if (is_plugin(globbuf.gl_pathv[i])) {
524 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
525 if (is_plugin(globbuf.gl_pathv[i])) {
532 gvconfig_write_library_config(
gvc, p, library, f);
551 struct stat config_st;
553 char *config_text =
NULL;
555 char *config_file_name = GVPLUGIN_CONFIG_FILE;
567 if (access(libdir, F_OK) < 0) {
585 "config rescan performed without any prior first scan");
602 else if (config_st.st_size == 0) {
606 config_text =
gv_alloc((
size_t)config_st.st_size + 1);
607 size_t sz = fread(config_text, 1, (
size_t)config_st.st_size, f);
613 config_text[sz] =
'\0';
614 rc = gvconfig_plugin_install_from_config(
gvc, config_text);
642glob (
GVC_t*
gvc,
char* pattern,
int flags,
int (*errfunc)(
const char *,
int), glob_t *pglob)
653 pglob->gl_pathv =
NULL;
658 for (
size_t i = 0; pattern[i] !=
'\0'; ++i) {
659 if (pattern[i] ==
'/') {
665 h = FindFirstFile (pattern, &wfd);
666 if (h == INVALID_HANDLE_VALUE)
return GLOB_NOMATCH;
670 strlen(libdir) + 1 + strlen(wfd.cFileName) + 1;
671 char *
const entry =
malloc(size);
675 snprintf(entry, size,
"%s%c%s", libdir,
PATH_SEPARATOR, wfd.cFileName);
680 }
while (FindNextFile (h, &wfd));
685 LIST_DETACH(&strs, &pglob->gl_pathv, &pglob->gl_pathc);
697globfree (glob_t* pglob)
700 for (i = 0; i < pglob->gl_pathc; i++)
701 free (pglob->gl_pathv[i]);
702 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_TRY_APPEND(list, item)
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