]> git.donarmstrong.com Git - lilypond.git/blob - kpath-guile/kpath.c
*** empty log message ***
[lilypond.git] / kpath-guile / kpath.c
1 /*
2   kpath.c --  implement kpathsea bindings
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9
10 #include <libguile.h>
11
12 #include "config.hh"
13
14 #if KPATHSEA
15
16 #include "guile-compatibility.hh"
17
18 #include <dlfcn.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 /* The (?) problem, as far as I (?) can tell, is that MacOS X has its
23    getopt prototype in <unistd.h>, while I think other operating
24    systems have it in other places. <unistd.h> is included by
25    kpathsea.h, so you end up renaming both conflicting prototypes to
26    KPATHSEA_HAS_GETOPT_PROTOTYPE_PROBLEM.
27
28    I (?) found a somewhat more elegant patch for this: Just #include
29    <unistd.h> before defining KPATHSEA_HAS_GETOPT_PROTOTYPE_PROBLEM.  */
30
31 #include <unistd.h>     
32
33 #define popen KPATHSEA_HAS_POPEN_PROTOTYPE_PROBLEM
34 #define pclose KPATHSEA_HAS_PCLOSE_PROTOTYPE_PROBLEM
35 #define getopt KPATHSEA_HAS_GETOPT_PROTOTYPE_PROBLEM
36
37 #if HAVE_KPATHSEA_KPATHSEA_H
38 #include <kpathsea/kpathsea.h>
39 #include <kpathsea/tex-file.h>
40 #endif
41
42 static void *kpathsea_handle = 0;
43 static char *(*dl_kpse_find_file) (char const*, kpse_file_format_type, boolean) = 0;
44 static void (*dl_kpse_maketex_option) (char const*, boolean) = 0;
45 static void (*dl_kpse_set_program_name) (char const*, char const*) = 0;
46 static char const *(*dl_kpse_init_format) (kpse_file_format_type) = 0;
47 static char *(*dl_kpse_var_expand) (char const*) = 0;
48 static kpse_format_info_type (*dl_kpse_format_info)[kpse_last_format] = 0;
49
50 kpse_file_format_type
51 kpathsea_find_format (const char* name)
52 {
53   int i;
54   int len = strlen (name);
55   for (i = 0; i < kpse_last_format; i++)
56     {
57        if (!(*dl_kpse_format_info)[i].type)
58         (*dl_kpse_init_format) ((kpse_file_format_type) i);
59
60        char const **suffixes[] = { (*dl_kpse_format_info)[i].suffix,
61                                    (*dl_kpse_format_info)[i].alt_suffix };
62        for (int j = 0; j < 2; j++)
63         for (char const **p = suffixes[j]; p && *p; p++)
64           {
65             int suflen = strlen (*p);
66             
67             if (!strncmp (name + len - suflen, *p, suflen))
68               return (kpse_file_format_type) i;
69           }
70     }
71   return kpse_last_format;
72 }
73
74 //         "Return the absolute file name of @var{name}, "
75 //         "or @code{#f} if not found.")
76 SCM
77 ly_kpathsea_find_file (SCM name)
78 {
79   SCM_ASSERT_TYPE (scm_is_string (name), name, SCM_ARG1, __FUNCTION__, "string");
80
81   char const *nm = scm_i_string_chars (name);
82   char *p = (*dl_kpse_find_file) (nm, kpathsea_find_format (nm), true);
83   if (p)
84     return scm_makfrom0str (p);
85   return SCM_BOOL_F;
86 }
87
88 //   "Return the expanded version  @var{var}.")
89 SCM ly_kpathsea_expand_variable (SCM var)
90 {
91   SCM_ASSERT_TYPE (scm_is_string (var), var, SCM_ARG1, __FUNCTION__, "string");
92
93   char const *nm = scm_i_string_chars (var);
94   char *result = (*dl_kpse_var_expand) (nm);
95   SCM ret = scm_makfrom0str (result);
96   free (result);
97
98   return ret;
99 }
100
101
102 static char const* LIBKPATHSEA = "libkpathsea.so";
103
104 int
105 open_library ()
106 {
107 #if HAVE_LIBKPATHSEA_SO
108   struct
109   {
110     void **func_pointer;
111     char const *name; 
112   } symbols[] = {
113     {(void*)&dl_kpse_find_file, "kpse_find_file"},
114     {(void*)&dl_kpse_set_program_name, "kpse_set_program_name"},
115     {(void*)&dl_kpse_format_info, "kpse_format_info"},
116     {(void*)&dl_kpse_init_format, "kpse_init_format"},
117     {(void*)&dl_kpse_maketex_option, "kpse_maketex_option"},
118     {(void*)&dl_kpse_var_expand, "kpse_var_expand"},
119     {0,0}
120   };
121
122
123   dlerror ();
124   kpathsea_handle = dlopen (LIBKPATHSEA, RTLD_LAZY);
125   if (!kpathsea_handle)
126     {
127       /*
128         todo i18n.
129        */
130       fprintf (stderr, "can't dlopen: %s: %s", LIBKPATHSEA, dlerror ());
131       fprintf (stderr,"install package: %s or %s",
132                "libkpathsea3 (teTeX 2.x)",
133                "libkpathsea4 (teTeX 3.x)");
134
135       return 1;
136     }
137
138   for (int i = 0; symbols[i].func_pointer; i++)
139     {
140       dlerror ();
141       *symbols[i].func_pointer = dlsym (kpathsea_handle, symbols[i].name);
142       if (!symbols[i].func_pointer)
143         {
144           fprintf(stderr, "no such symbol: %s: %s",
145                   symbols[i].name,
146                   dlerror ());
147           return 1;
148         }
149     }
150   return 0;
151 #else
152   dl_kpse_find_file = &kpse_find_file;
153   dl_kpse_set_program_name = &kpse_set_program_name;
154   dl_kpse_format_info = &kpse_format_info;
155   dl_kpse_init_format = &kpse_init_format;
156   dl_kpse_maketex_option = &kpse_maketex_option;
157   dl_kpse_var_expand = &kpse_var_expand;
158   return 0;
159 #endif
160 }
161
162 void
163 initialize_kpathsea ()
164 {
165   if (open_library ())
166     {
167       fprintf (stderr, "Error opening kpathsea library. Aborting");
168       exit (1);
169     }
170
171   (*dl_kpse_set_program_name) ("lilypond", "lilypond");
172   (*dl_kpse_maketex_option) ("tfm", TRUE);
173   
174   SCM find = scm_c_define_gsubr ("ly:kpathsea-find-file", 1, 0, 0,
175                                  ly_kpathsea_find_file);
176   scm_c_export ("ly:kpathsea-find-file", NULL);
177   SCM expand = scm_c_define_gsubr ("ly:kpathsea-expand-variable", 1, 0, 0,
178                                    ly_kpathsea_expand_variable);
179   scm_c_export ("ly:kpathsea-expand-variable", NULL);
180 }
181
182 #endif