30#ifdef HAVE_DL_ITERATE_PHDR
44static void globfree (glob_t* pglob);
45static int glob (
GVC_t *
gvc,
char*,
int,
int (*errfunc)(
const char *,
int), glob_t*);
53#include <mach-o/dyld.h>
97 const char *package_path,
117static void separator(
int *nest,
char **tokens)
143 if (c ==
' ' || c ==
'\n' || c ==
'\t') {
156static char *token(
int *nest,
char **tokens)
163 || c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'{' || c ==
'}')
168 separator(nest, tokens);
173static int gvconfig_plugin_install_from_config(
GVC_t *
gvc,
char *
s)
175 char *package_path, *name;
181 separator(&nest, &
s);
183 package_path = token(&nest, &
s);
185 name = token(&nest, &
s);
188 package = gvplugin_package_record(gvc, package_path, name);
190 const char *api = token(&nest, &
s);
192 if (gv_api == (
api_t)-1) {
193 agerrorf(
"config error: %s %s not found\n", package_path, api);
198 type = token(&nest, &
s);
200 quality = atoi(token(&nest, &
s));
205 agerrorf(
"config error: %s %s %s\n", package_path, api,
type);
223 package = gvplugin_package_record(gvc, package_path, library->packagename);
225 for (i = 0; types[i].
type; i++) {
227 types[i].
quality, package, &types[i]);
240 if (name[0] ==
'g' && strstr(name,
"_LTX_library"))
245static void gvconfig_write_library_config(
GVC_t *
gvc,
char *lib_path,
250 fprintf(f,
"%s %s {\n", lib_path, library->
packagename);
253 for (
size_t i = 0; types[i].
type; i++) {
257 fprintf(f,
"#FAILS");
258 fprintf(f,
"\t\t%s %d\n", types[i].
type, types[i].quality);
266#define DOTLIBS "/.libs"
268#ifdef HAVE_DL_ITERATE_PHDR
269static int line_callback(
struct dl_phdr_info *
info,
size_t size,
void *line)
271 const char *p =
info->dlpi_name;
272 char *tmp = strstr(p,
"/libgvc.");
277 if (strcmp(strrchr(p,
'/'), DOTLIBS) != 0) {
278 memmove(line, p, strlen(p) + 1);
279 strcat(line,
"/graphviz");
289 static char line[
BSZ];
291 static bool dirShown =
false;
294 libdir=getenv(
"GVBINDIR");
300 MEMORY_BASIC_INFORMATION mbi;
302 agerrorf(
"failed to get handle for executable.\n");
305 r = GetModuleFileName ((HMODULE)mbi.AllocationBase, line,
BSZ);
306 if (!r || (r ==
BSZ)) {
307 agerrorf(
"failed to get path for executable.\n");
310 s = strrchr(line,
'\\');
312 agerrorf(
"no slash in path %s.\n", line);
320 uint32_t i, c = _dyld_image_count();
322 for (i = 0; i < c; ++i) {
323 const char *p = _dyld_get_image_name(i);
324 const char* tmp = strstr(p,
"/libgvc.");
328 const char *
s = tmp - 1;
330 while (*
s !=
'/' &&
s > p)
s--;
336 len = ind +
sizeof(
"/graphviz");
342 memmove(libdir, p, ind);
345 strcpy(libdir+ind,
"/graphviz");
349#elif defined(HAVE_DL_ITERATE_PHDR)
350 dl_iterate_phdr(line_callback, line);
353 FILE* f = fopen (
"/proc/self/maps",
"r");
356 if (!fgets (line,
sizeof (line), f))
358 if (!strstr (line,
" r-xp "))
360 char *p = strchr(line,
'/');
363 char* tmp = strstr(p,
"/libgvc.");
367 if (strcmp(strrchr(p,
'/'),
"/.libs") == 0)
369 memmove(line, p, strlen(p) + 1);
370 strcat(line,
"/graphviz");
382 fprintf (stderr,
"libdir = \"%s\"\n", (libdir ? libdir :
"<null>"));
391static bool is_plugin(
const char *filepath) {
393 if (filepath ==
NULL) {
398#if defined(DARWIN_DYLIB)
399 static const char SUFFIX[] =
".dylib";
400#elif defined(__MINGW32__) || defined(__CYGWIN__) || defined(_WIN32)
401 static const char SUFFIX[] =
".dll";
403 static const char SUFFIX[] =
"";
407 size_t len = strlen(filepath);
408 if (
len < strlen(SUFFIX)
409 || strcmp(filepath +
len - strlen(SUFFIX), SUFFIX) != 0) {
412 len -= strlen(SUFFIX);
414#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
417#elif defined(GVPLUGIN_VERSION)
419 #define STRINGIZE_(x) #x
420 #define STRINGIZE(x) STRINGIZE_(x)
421 static const char VERSION[] = STRINGIZE(GVPLUGIN_VERSION);
426 if (
len < strlen(VERSION)
430 len -= strlen(VERSION);
444#if defined(DARWIN_DYLIB)
448#elif defined(__MINGW32__) || defined(__CYGWIN__)
456#elif ((defined(__hpux__) || defined(__hpux)) && !(defined(__ia64)))
457 static const char SL[] =
".sl.";
462 static const char SO[] =
".so.";
471static void config_rescan(
GVC_t *
gvc,
char *config_path)
478#if defined(DARWIN_DYLIB)
479 char *plugin_glob =
"libgvplugin_*";
480#elif defined(__MINGW32__)
481 char *plugin_glob =
"libgvplugin_*";
482#elif defined(__CYGWIN__)
483 char *plugin_glob =
"cyggvplugin_*";
485 char *plugin_glob =
"gvplugin_*";
487 char *plugin_glob =
"libgvplugin_*";
491 f = fopen(config_path,
"w");
493 agerrorf(
"failed to open %s for write.\n", config_path);
497 fprintf(f,
"# This file was generated by \"dot -c\" at time of install.\n\n");
498 fprintf(f,
"# You may temporarily disable a plugin by removing or commenting out\n");
499 fprintf(f,
"# a line in this file, or you can modify its \"quality\" value to affect\n");
500 fprintf(f,
"# default plugin selection.\n\n");
501 fprintf(f,
"# Manual edits to this file **will be lost** on upgrade.\n\n");
512 rc = glob(
gvc,
agxbuse(&config_glob), GLOB_NOSORT,
NULL, &globbuf);
514 rc = glob(
agxbuse(&config_glob), 0,
NULL, &globbuf);
517 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
518 if (is_plugin(globbuf.gl_pathv[i])) {
526 for (
size_t i = 0; i < globbuf.gl_pathc; i++) {
527 if (is_plugin(globbuf.gl_pathv[i])) {
530 char *p = strrchr(globbuf.gl_pathv[i],
DIRSEP[0]);
534 gvconfig_write_library_config(
gvc, p, library, f);
553 struct stat config_st;
555 char *config_text =
NULL;
557 char *config_file_name = GVPLUGIN_CONFIG_FILE;
569 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);
640glob (
GVC_t*
gvc,
char* pattern,
int flags,
int (*errfunc)(
const char *,
int), glob_t *pglob)
650 pglob->gl_pathv =
NULL;
652 h = FindFirstFile (pattern, &wfd);
653 if (h == INVALID_HANDLE_VALUE)
return GLOB_NOMATCH;
656 if (
cnt >= arrsize-1) {
658 char **new_str = realloc(
str, arrsize *
sizeof(
char*));
659 if (!new_str)
goto oom;
662 str[
cnt] =
malloc (strlen(libdir)+1+strlen(wfd.cFileName)+1);
666 strcat(
str[
cnt],wfd.cFileName);
668 }
while (FindNextFile (h, &wfd));
671 pglob->gl_pathc =
cnt;
672 pglob->gl_pathv = realloc(
str, (
cnt+1)*
sizeof(
char*));
677 for (
int i = 0; i <
cnt; ++i)
684globfree (glob_t* pglob)
687 for (i = 0; i < pglob->gl_pathc; i++)
688 free (pglob->gl_pathv[i]);
689 free (pglob->gl_pathv);
static void agxbfree(agxbuf *xb)
free any malloced resources
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
static 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)
static int cnt(Dict_t *d, Dtlink_t **set)
void agerrorf(const char *fmt,...)
replacements for ctype.h functions
static bool gv_isdigit(int c)
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)
char * gvconfig_libdir(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)
static gvplugin_api_t apis[]
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