00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020
00021 #include <string.h>
00022
00023 #ifdef ENABLE_LTDL
00024 #include <sys/types.h>
00025 #ifdef WIN32
00026 #include <windows.h>
00027 #define GLOB_NOSPACE 1
00028 #define GLOB_ABORTED 2
00029 #define GLOB_NOMATCH 3
00030 #define GLOB_NOSORT 4
00031 #define DMKEY "Software\\Microsoft" //key to look for library dir
00032 #include <regex_win32.c>
00033 typedef struct {
00034 int gl_pathc;
00035 int gl_matchc;
00036 int gl_offs;
00037 int gl_flags;
00038 char **gl_pathv;
00039 } glob_t;
00040 static void globfree (glob_t* pglob);
00041 static int glob (char*, int, int (*errfunc)(const char *, int), glob_t*);
00042 #else
00043 #include <regex.h>
00044 #include <glob.h>
00045 #endif
00046 #include <sys/stat.h>
00047 #ifdef HAVE_UNISTD_H
00048 #include <unistd.h>
00049 #endif
00050 #endif
00051
00052 #include "memory.h"
00053 #include "const.h"
00054 #include "types.h"
00055 #include "graph.h"
00056
00057 #include "gvplugin.h"
00058 #include "gvcjob.h"
00059 #include "gvcint.h"
00060 #include "gvcproc.h"
00061
00062 extern const int Demand_Loading;
00063
00064 #ifdef WITH_CODEGENS
00065 extern codegen_t HPGL_CodeGen, MIF_CodeGen, MP_CodeGen, PIC_CodeGen, DIA_CodeGen, VTX_CodeGen;
00066 #endif
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 #ifdef ENABLE_LTDL
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107 static void separator(int *nest, char **tokens)
00108 {
00109 char c, *s;
00110
00111 s = *tokens;
00112 while ((c = *s)) {
00113
00114 if (c == '#') {
00115 s++;
00116 while ((c = *s)) {
00117 s++;
00118 if (c == '\n')
00119 break;
00120 }
00121 continue;
00122 }
00123 if (c == '{') {
00124 (*nest)++;
00125 s++;
00126 continue;
00127 }
00128 if (c == '}') {
00129 (*nest)--;
00130 s++;
00131 continue;
00132 }
00133 if (c == ' ' || c == '\n' || c == '\t') {
00134 s++;
00135 continue;
00136 }
00137 break;
00138 }
00139 *tokens = s;
00140 }
00141
00142
00143
00144
00145
00146 static char *token(int *nest, char **tokens)
00147 {
00148 char c, *s, *t;
00149
00150 s = t = *tokens;
00151 while ((c = *s)) {
00152 if (c == '#'
00153 || c == ' ' || c == '\t' || c == '\n' || c == '{' || c == '}')
00154 break;
00155 s++;
00156 }
00157 *tokens = s;
00158 separator(nest, tokens);
00159 *s = '\0';
00160 return t;
00161 }
00162
00163 static int gvconfig_plugin_install_from_config(GVC_t * gvc, char *s)
00164 {
00165 char *path, *packagename, *api, *type;
00166 api_t gv_api;
00167 int quality, rc;
00168 int nest = 0;
00169
00170 separator(&nest, &s);
00171 while (*s) {
00172 path = token(&nest, &s);
00173 if (nest == 0)
00174 packagename = token(&nest, &s);
00175 else
00176 packagename = "x";
00177 do {
00178 api = token(&nest, &s);
00179 gv_api = gvplugin_api(api);
00180 if (gv_api == -1) {
00181 agerr(AGERR, "invalid api in config: %s %s\n", path, api);
00182 return 0;
00183 }
00184 do {
00185 if (nest == 2) {
00186 type = token(&nest, &s);
00187 if (nest == 2)
00188 quality = atoi(token(&nest, &s));
00189 else
00190 quality = 0;
00191 rc = gvplugin_install (gvc, gv_api,
00192 type, quality, packagename, path, NULL);
00193 if (!rc) {
00194 agerr(AGERR, "config error: %s %s %s\n", path, api, type);
00195 return 0;
00196 }
00197 }
00198 } while (nest == 2);
00199 } while (nest == 1);
00200 }
00201 return 1;
00202 }
00203 #endif
00204
00205 static void gvconfig_plugin_install_from_library(GVC_t * gvc, char *path, gvplugin_library_t *library)
00206 {
00207 gvplugin_api_t *apis;
00208 gvplugin_installed_t *types;
00209 int i;
00210
00211 for (apis = library->apis; (types = apis->types); apis++) {
00212 for (i = 0; types[i].type; i++) {
00213
00214
00215
00216 gvplugin_install(gvc, apis->api, types[i].type,
00217 types[i].quality, library->packagename, path, &types[i]);
00218 }
00219 }
00220 }
00221
00222 static void gvconfig_plugin_install_builtins(GVC_t * gvc)
00223 {
00224 const lt_symlist_t *s;
00225 const char *name;
00226
00227
00228
00229
00230 #if defined(GVDLL) && !defined(ENABLE_LTDL)
00231 init_lt_preloaded_symbols();
00232 #endif
00233 s = lt_preloaded_symbols;
00234 for (s = lt_preloaded_symbols; (name = s->name); s++)
00235 if (name[0] == 'g' && strstr(name, "_LTX_library"))
00236 gvconfig_plugin_install_from_library(gvc, NULL,
00237 (gvplugin_library_t *)(s->address));
00238 }
00239
00240 #ifdef ENABLE_LTDL
00241 static void gvconfig_write_library_config(GVC_t *gvc, char *path, gvplugin_library_t *library, FILE *f)
00242 {
00243 gvplugin_api_t *apis;
00244 gvplugin_installed_t *types;
00245 int i;
00246
00247 fprintf(f, "%s %s {\n", path, library->packagename);
00248 for (apis = library->apis; (types = apis->types); apis++) {
00249 fprintf(f, "\t%s {\n", gvplugin_api_name(apis->api));
00250 for (i = 0; types[i].type; i++) {
00251 #if 0
00252
00253
00254
00255
00256 if (! (gvplugin_load(gvc, apis->api, types[i].type)))
00257 fprintf(f, "#FAILS");
00258 #endif
00259 fprintf(f, "\t\t%s %d\n", types[i].type, types[i].quality);
00260 }
00261 fputs ("\t}\n", f);
00262 }
00263 fputs ("}\n", f);
00264 }
00265
00266 #define BSZ 1024
00267
00268 char * gvconfig_libdir(void)
00269 {
00270 static char line[BSZ];
00271 static char *libdir;
00272 char *path, *tmp;
00273 FILE *f;
00274
00275 if (!libdir) {
00276 #ifdef WIN32
00277 libdir=getenv("GVBINDIR");
00278 if (!libdir) {
00279 int r;
00280 char* s;
00281 HMODULE hm = GetModuleHandle (NULL);
00282 if (!hm) {
00283 agerr(AGERR,"failed to get handle for executable.\n");
00284 return 0;
00285 }
00286 r = GetModuleFileName (hm, line, BSZ);
00287 if (!r || (r == BSZ)) {
00288 agerr(AGERR,"failed to get path for executable.\n");
00289 return 0;
00290 }
00291 s = strrchr(line,'\\');
00292 if (!s) {
00293 agerr(AGERR,"no slash in path %s.\n", line);
00294 return 0;
00295 }
00296 *s = '\0';
00297 libdir = line;
00298 }
00299 #else
00300
00301 libdir = GVLIBDIR;
00302 f = fopen ("/proc/self/maps", "r");
00303 if (f) {
00304 while (!feof (f)) {
00305 if (!fgets (line, sizeof (line), f))
00306 continue;
00307 if (!strstr (line, " r-xp "))
00308 continue;
00309 path = strchr (line, '/');
00310 if (!path)
00311 continue;
00312 tmp = strstr (path, "/libgvc.");
00313 if (tmp) {
00314 *tmp = 0;
00315
00316 if (strcmp(strrchr(path,'/'), "/.libs") == 0)
00317 continue;
00318 strcpy(line, path);
00319 strcat(line, "/graphviz");
00320 libdir = line;
00321 break;
00322 }
00323 }
00324 fclose (f);
00325 }
00326 #endif
00327 }
00328 return libdir;
00329 }
00330 #endif
00331
00332 #ifdef ENABLE_LTDL
00333 static void config_rescan(GVC_t *gvc, char *config_path)
00334 {
00335 FILE *f = NULL;
00336 glob_t globbuf;
00337 char *config_glob, *config_re, *path, *libdir;
00338 int i, rc, re_status;
00339 gvplugin_library_t *library;
00340 regex_t re;
00341 #ifndef WIN32
00342 char *plugin_glob = "libgvplugin_*";
00343 #endif
00344 #if defined(DARWIN_DYLIB)
00345 char *plugin_re_beg = "[^0-9]\\.";
00346 char *plugin_re_end = "\\.dylib$";
00347 #elif defined(__MINGW32__)
00348 char *plugin_glob = "libgvplugin_*";
00349 char *plugin_re_beg = "[^0-9]-";
00350 char *plugin_re_end = "\\.dll$";
00351 #elif defined(__CYGWIN__)
00352 plugin_glob = "cyggvplugin_*";
00353 char *plugin_re_beg = "[^0-9]-";
00354 char *plugin_re_end = "\\.dll$";
00355 #elif defined(WIN32)
00356 char *plugin_glob = "gvplugin_*";
00357 char *plugin_re_beg = "[^0-9]";
00358 char *plugin_re_end = "\\.dll$";
00359 #elif defined(__hpux__) || defined(__hpux)
00360 char *plugin_re_beg = "\\.sl\\.";
00361 char *plugin_re_end = "$";
00362 #else
00363
00364 char *plugin_re_beg = "\\.so\\.";
00365 char *plugin_re_end= "$";
00366 #endif
00367
00368 if (config_path) {
00369 f = fopen(config_path,"w");
00370 if (!f) {
00371 agerr(AGERR,"failed to open %s for write.\n", config_path);
00372 }
00373
00374 fprintf(f, "# This file was generated by \"dot -c\" at time of install.\n\n");
00375 fprintf(f, "# You may temporarily disable a plugin by removing or commenting out\n");
00376 fprintf(f, "# a line in this file, or you can modify its \"quality\" value to affect\n");
00377 fprintf(f, "# default plugin selection.\n\n");
00378 fprintf(f, "# Manual edits to this file **will be lost** on upgrade.\n\n");
00379 }
00380
00381 libdir = gvconfig_libdir();
00382
00383 config_re = gmalloc(strlen(plugin_re_beg) + 20 + strlen(plugin_re_end) + 1);
00384
00385 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
00386 sprintf(config_re,"%s%s", plugin_re_beg, plugin_re_end);
00387 #elif defined(GVPLUGIN_VERSION)
00388 sprintf(config_re,"%s%d%s", plugin_re_beg, GVPLUGIN_VERSION, plugin_re_end);
00389 #else
00390 sprintf(config_re,"%s[0-9]+%s", plugin_re_beg, plugin_re_end);
00391 #endif
00392
00393 if (regcomp(&re, config_re, REG_EXTENDED|REG_NOSUB) != 0) {
00394 agerr(AGERR,"cannot compile regular expression %s", config_re);
00395 }
00396
00397 config_glob = gmalloc(strlen(libdir) + 1 + strlen(plugin_glob) + 1);
00398 strcpy(config_glob, libdir);
00399 strcat(config_glob, DIRSEP);
00400 strcat(config_glob, plugin_glob);
00401
00402
00403 rc = glob(config_glob, GLOB_NOSORT, NULL, &globbuf);
00404 if (rc == 0) {
00405 for (i = 0; i < globbuf.gl_pathc; i++) {
00406 re_status = regexec(&re, globbuf.gl_pathv[i], (size_t) 0, NULL, 0);
00407 if (re_status == 0) {
00408 library = gvplugin_library_load(gvc, globbuf.gl_pathv[i]);
00409 if (library) {
00410 gvconfig_plugin_install_from_library(gvc, globbuf.gl_pathv[i], library);
00411 path = strrchr(globbuf.gl_pathv[i],DIRSEP[0]);
00412 if (path)
00413 path++;
00414 if (f && path)
00415 gvconfig_write_library_config(gvc, path, library, f);
00416 }
00417 }
00418 }
00419 }
00420 regfree(&re);
00421 globfree(&globbuf);
00422 free(config_glob);
00423 free(config_re);
00424 if (f)
00425 fclose(f);
00426 }
00427 #endif
00428
00429 #ifdef WITH_CODEGENS
00430
00431 #define MAX_CODEGENS 100
00432
00433 static codegen_info_t cg[MAX_CODEGENS] = {
00434 {&HPGL_CodeGen, "hpgl", HPGL},
00435 {&HPGL_CodeGen, "pcl", PCL},
00436 {&MIF_CodeGen, "mif", MIF},
00437 {&PIC_CodeGen, "pic", PIC_format},
00438 {&VTX_CodeGen, "vtx", VTX},
00439 {&MP_CodeGen, "mp", METAPOST},
00440 #ifdef HAVE_LIBZ
00441 {&DIA_CodeGen, "dia", DIA},
00442 #endif
00443 {NULL, NULL, 0}
00444 };
00445
00446 codegen_info_t *first_codegen(void)
00447 {
00448 return cg;
00449 }
00450
00451 codegen_info_t *next_codegen(codegen_info_t * p)
00452 {
00453 ++p;
00454 return p;
00455 }
00456 #endif
00457
00458
00459
00460
00461 void gvconfig(GVC_t * gvc, boolean rescan)
00462 {
00463 #if 0
00464 gvplugin_library_t **libraryp;
00465 #endif
00466 #ifdef ENABLE_LTDL
00467 int sz, rc;
00468 struct stat config_st, libdir_st;
00469 FILE *f = NULL;
00470 char *config_text = NULL;
00471 char *libdir;
00472 char *config_file_name = "config";
00473
00474 #define MAX_SZ_CONFIG 100000
00475 #endif
00476
00477 #ifdef WITH_CODEGENS
00478 codegen_info_t *p;
00479
00480 for (p = cg; p->name; ++p)
00481 gvplugin_install(gvc, API_device, p->name, 0,
00482 "cg", NULL, (gvplugin_installed_t *) p);
00483 #endif
00484
00485
00486 gvconfig_plugin_install_builtins(gvc);
00487
00488 gvc->config_found = FALSE;
00489 #ifdef ENABLE_LTDL
00490 if (Demand_Loading) {
00491
00492 libdir = gvconfig_libdir();
00493 rc = stat(libdir, &libdir_st);
00494 if (rc == -1) {
00495
00496 return;
00497 }
00498
00499 if (! gvc->config_path) {
00500 gvc->config_path = gmalloc(strlen(libdir) + 1 + strlen(config_file_name) + 1);
00501 strcpy(gvc->config_path, libdir);
00502 strcat(gvc->config_path, DIRSEP);
00503 strcat(gvc->config_path, config_file_name);
00504 }
00505
00506 if (rescan) {
00507 config_rescan(gvc, gvc->config_path);
00508 gvc->config_found = TRUE;
00509 return;
00510 }
00511
00512
00513
00514 rc = stat(gvc->config_path, &config_st);
00515 if (rc == -1) {
00516
00517 return;
00518 }
00519 else if (config_st.st_size > MAX_SZ_CONFIG) {
00520 agerr(AGERR,"%s is bigger than I can handle.\n", gvc->config_path);
00521 }
00522 else {
00523 f = fopen(gvc->config_path,"r");
00524 if (!f) {
00525 agerr (AGERR,"failed to open %s for read.\n", gvc->config_path);
00526 }
00527 else {
00528 config_text = gmalloc(config_st.st_size + 1);
00529 sz = fread(config_text, 1, config_st.st_size, f);
00530 if (sz == 0) {
00531 agerr(AGERR,"%s is zero sized, or other read error.\n", gvc->config_path);
00532 free(config_text);
00533 }
00534 else {
00535 gvc->config_found = TRUE;
00536 config_text[sz] = '\0';
00537 rc = gvconfig_plugin_install_from_config(gvc, config_text);
00538
00539 }
00540 }
00541 if (f)
00542 fclose(f);
00543 }
00544 }
00545 #endif
00546 gvtextlayout_select(gvc);
00547 }
00548
00549 #ifdef ENABLE_LTDL
00550 #ifdef WIN32
00551
00552
00553
00554
00555
00556
00557
00558 char * gvconfig_libdir(void);
00559
00560 static int
00561 glob (char* pattern, int flags, int (*errfunc)(const char *, int),
00562 glob_t *pglob)
00563 {
00564 char* libdir;
00565 WIN32_FIND_DATA wfd;
00566 HANDLE h;
00567 char** str=0;
00568 int arrsize=0;
00569 int cnt = 0;
00570
00571 pglob->gl_pathc = 0;
00572 pglob->gl_pathv = NULL;
00573
00574 h = FindFirstFile (pattern, &wfd);
00575 if (h == INVALID_HANDLE_VALUE) return GLOB_NOMATCH;
00576 libdir = gvconfig_libdir();
00577 do {
00578 if (cnt >= arrsize-1) {
00579 arrsize += 512;
00580 if (str) str = (char**)realloc (str, arrsize*sizeof(char*));
00581 else str = (char**)malloc (arrsize*sizeof(char*));
00582 if (!str) return GLOB_NOSPACE;
00583 }
00584 str[cnt] = (char*)malloc (strlen(libdir)+1+strlen(wfd.cFileName)+1);
00585 if (!str[cnt]) return GLOB_NOSPACE;
00586 strcpy(str[cnt],libdir);
00587 strcat(str[cnt],DIRSEP);
00588 strcat(str[cnt],wfd.cFileName);
00589 cnt++;
00590 } while (FindNextFile (h, &wfd));
00591 str[cnt] = 0;
00592
00593 pglob->gl_pathc = cnt;
00594 pglob->gl_pathv = (char**)realloc(str, (cnt+1)*sizeof(char*));
00595
00596 return 0;
00597 }
00598
00599 static void
00600 globfree (glob_t* pglob)
00601 {
00602 int i;
00603 for (i = 0; i < pglob->gl_pathc; i++)
00604 free (pglob->gl_pathv[i]);
00605 if (pglob->gl_pathv)
00606 free (pglob->gl_pathv);
00607 }
00608 #endif
00609 #endif