]> git.donarmstrong.com Git - lilypond.git/blob - lily/relocate.cc
0f01eff06ca554e19bd957180d63df022d6747df
[lilypond.git] / lily / relocate.cc
1 /*
2   relocate.cc -- implement relocation based on argv0
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2005--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7
8 */
9
10 #include "relocate.hh"
11
12 #include "config.hh"
13
14
15 /* TODO: autoconf support */
16
17 #include <sys/types.h>
18 #include <dirent.h>
19
20 #if HAVE_GETTEXT
21 #include <libintl.h>
22 #endif
23
24 #include "file-name.hh"
25 #include "file-path.hh"
26 #include "international.hh"
27 #include "lily-guile.hh"
28 #include "lily-version.hh"
29 #include "main.hh"
30 #include "version.hh"
31 #include "warn.hh"
32
33 #define FRAMEWORKDIR ".."
34
35
36 int
37 sane_putenv (char const *key, string value, bool overwrite)
38 {
39   if (overwrite || !getenv (key))
40     {
41       string combine = string (key) + "=" + value;
42       char *s = strdup (combine.c_str ());
43
44       if (be_verbose_global)
45         progress_indication (_f ("Setting %s to %s\n" , key, value.c_str ())); 
46                              
47       return putenv (s);
48     }
49   
50   return -1;
51 }
52
53 static int
54 set_env_file (char const *key, string value, bool overwrite = false)
55 {
56   if (is_file (value))
57     return sane_putenv (key, value, overwrite);
58   else if (be_verbose_global)
59     warning (_f ("no such file: %s for %s", value, key));
60   return -1;
61 }
62
63 static int
64 set_env_dir (char const *key, string value)
65 {
66   if (is_dir (value))
67     return sane_putenv (key, value, false);
68   else if (be_verbose_global)
69     warning (_f ("no such directory: %s for %s", value, key));
70   return -1;
71 }
72
73 static int
74 prepend_env_path (char const *key, string value)
75 {
76   if (is_dir (value))
77     {
78       if (be_verbose_global)
79         progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ())); 
80
81       if (char const *cur = getenv (key))
82         value += to_string (PATHSEP) + cur;
83
84       return sane_putenv (key, value.c_str (), true);
85     }
86   else if (be_verbose_global)
87     warning (_f ("no such directory: %s for %s", value, key));
88   return -1;
89 }
90
91 #ifdef __MINGW32__
92 #include <winbase.h>
93 #endif
94
95 void
96 prefix_relocation (string prefix)
97 {
98   if (be_verbose_global)
99     warning (_f ("Relocation: compile prefix=%s, new prefix=%s",
100                  prefix_directory,
101                  prefix.c_str ()));
102   
103   string bindir = prefix + "/bin";
104   string datadir = prefix + "/share";
105   string localedir = datadir + "/locale";
106   string lilypond_datadir = datadir + "/lilypond/";
107
108   if (is_dir (lilypond_datadir + "/" + TOPLEVEL_VERSION))
109     prefix_directory = lilypond_datadir + "/" + TOPLEVEL_VERSION;
110   else if (is_dir (lilypond_datadir + "/current"))
111     prefix_directory = lilypond_datadir + "/current";
112
113 #if HAVE_GETTEXT
114   if (is_dir (localedir))
115     bindtextdomain ("lilypond", localedir.c_str ());
116 #endif
117
118   prepend_env_path ("PATH", bindir);
119 }
120
121 void
122 framework_relocation (string prefix)
123 {
124   if (be_verbose_global)
125     warning (_f ("Relocation: framework_prefix=%s", prefix));
126
127   sane_putenv ("INSTALLER_PREFIX", prefix, true);
128                
129   read_relocation_dir (prefix + "/etc/relocate/");
130
131   string bindir = prefix + "/bin";
132
133 #ifdef OLD_RELOCATION
134   string datadir = prefix + "/share";
135   string libdir = prefix + "/lib";
136   string sysconfdir = prefix + "/etc";
137   
138   /* need otherwise dynamic .so's aren't found.   */
139   prepend_env_path ("DYLD_LIBRARY_PATH", libdir);
140   
141   set_env_file ("FONTCONFIG_FILE", sysconfdir + "/fonts/fonts.conf", true);
142   set_env_dir ("FONTCONFIG_PATH", sysconfdir + "/fonts");
143
144 #ifdef __MINGW32__
145   char font_dir[PATH_MAX];
146   ExpandEnvironmentStrings ("%windir%/fonts", font_dir, sizeof (font_dir));
147   prepend_env_path ("GS_FONTPATH", font_dir);
148 #endif
149
150   string gs_version =
151 #ifdef GHOSTSCRIPT_VERSION
152     GHOSTSCRIPT_VERSION
153 #else
154     "ghostscript-version-undefined"
155 #endif
156     ;
157   
158   if (char const *cur = getenv ("LILYPOND_GS_VERSION"))
159     gs_version = cur;
160   
161   prepend_env_path ("GS_FONTPATH", datadir + "/ghostscript/" + gs_version + "/fonts");
162   prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/Resource");
163   prepend_env_path ("GS_LIB", datadir + "/ghostscript/" + gs_version + "/lib");
164
165   prepend_env_path ("GS_FONTPATH", datadir + "/gs/fonts");
166   prepend_env_path ("GS_LIB", datadir + "/gs/Resource");
167   prepend_env_path ("GS_LIB", datadir + "/gs/lib");
168   
169   prepend_env_path ("GUILE_LOAD_PATH", datadir
170                     + to_string ("/guile/%d.%d",
171                                  SCM_MAJOR_VERSION, SCM_MINOR_VERSION));
172   set_env_file ("PANGO_RC_FILE", sysconfdir + "/pango/pangorc");
173   set_env_dir ("PANGO_PREFIX", prefix);
174
175 #endif
176   
177   
178   prepend_env_path ("PATH", bindir);
179 }
180
181 void
182 setup_paths (char const *argv0_ptr)
183 {
184   File_name argv0_filename (argv0_ptr);
185   
186   prefix_directory = LILYPOND_DATADIR;
187   if (relocate_binary
188       && getenv ("LILYPOND_RELOCATE_PREFIX"))
189     {
190       string prefix = getenv ("LILYPOND_RELOCATE_PREFIX");
191 #ifdef __MINGW32__
192       /* Normalize file name.  */
193       prefix = File_name (prefix).to_string ();
194 #endif /* __MINGW32__ */
195       prefix_relocation (prefix);
196       string bindir = prefix + "/bin";
197       framework_relocation (bindir);
198     }
199   else if (relocate_binary)
200     {
201       string argv0_abs;
202       if (argv0_filename.is_absolute ())
203         {
204           argv0_abs = argv0_filename.to_string ();
205           if (be_verbose_global)
206             warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
207         }
208       else if (argv0_filename.dir_.length ())
209         {
210           argv0_abs = get_working_directory ()
211             + "/" + string (argv0_filename.to_string ());
212           if (be_verbose_global)
213             warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
214         }
215       else
216         {
217           /* Find absolute ARGV0 name, using PATH.  */
218           File_path path;
219           path.parse_path (getenv ("PATH"));
220
221           if (be_verbose_global)
222             warning (_f ("Relocation: from PATH=%s\nargv0=%s",
223                          path.to_string ().c_str (), argv0_ptr));
224
225 #ifndef __MINGW32__
226           argv0_abs = path.find (argv0_filename.to_string ());
227 #else /* __MINGW32__ */
228           char const *ext[] = {"exe", "", 0 };
229           argv0_abs = path.find (argv0_filename.to_string (), ext);
230 #endif /* __MINGW32__ */
231
232           if (argv0_abs.empty ())
233             programming_error ("can't find absolute argv0.");
234         }
235
236       string bindir = dir_name (argv0_abs);
237       string argv0_prefix = dir_name (bindir);
238       string compile_prefix = dir_name (dir_name (dir_name (prefix_directory)));
239       if (argv0_prefix != compile_prefix)
240         prefix_relocation (argv0_prefix);
241       if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
242         framework_relocation (bindir + "/" + FRAMEWORKDIR);
243     }
244
245   /* FIXME: use LILYPOND_DATADIR.  */
246   if (char const *env = getenv ("LILYPONDPREFIX"))
247     {
248
249 #ifdef __MINGW32__
250       /* Normalize file name.  */
251       prefix_directory = File_name (env).to_string ();
252 #else
253       prefix_directory = env;
254 #endif
255     }
256
257   global_path.append ("");
258
259
260   /*
261     When running from build dir, a full LILYPOND_PREFIX is set-up at
262
263         $(OUTBASE)/share/lilypond/TOPLEVEL_VERSION
264
265      This historical hack will allow the shorthand
266
267         LILYPONDPREFIX=out lily/out/lilypond ...
268
269   */
270   
271   string build_prefix_current = prefix_directory + "/share/lilypond/" "current";
272   string build_prefix_version = prefix_directory + "/share/lilypond/" TOPLEVEL_VERSION;
273   if (is_dir (build_prefix_version.c_str ()))
274     prefix_directory = build_prefix_version;
275   else if (is_dir (build_prefix_current.c_str ()))
276     prefix_directory = build_prefix_current;
277   
278   /* Adding mf/out make lilypond unchanged source directory, when setting
279      LILYPONDPREFIX to lilypond-x.y.z */
280   char const *suffixes[] = {"ly", "ps", "scm", 0 };
281   
282   vector<string> dirs;
283   for (char const **s = suffixes; *s; s++)
284     {
285       string path = prefix_directory + to_string ('/') + string (*s);
286       dirs.push_back (path);
287     }
288   
289   dirs.push_back (prefix_directory + "/fonts/otf/");
290   dirs.push_back (prefix_directory + "/fonts/type1/");
291   dirs.push_back (prefix_directory + "/fonts/svg/");
292   
293   for (vsize i = 0; i < dirs.size (); i++)
294     global_path.prepend (dirs[i]);
295 }
296
297
298
299 string
300 expand_environment_variables (string orig)
301 {
302   const char *start_ptr = orig.c_str();
303   const char *ptr = orig.c_str();
304   size_t len = orig.length();
305
306   string out;
307   while (ptr < start_ptr + len)
308     {
309       char *dollar = strchr (ptr, '$');
310       
311       if (dollar != NULL)
312         {
313           char *start_var = dollar + 1;
314           char *end_var = start_var;
315           char *start_next = end_var;
316           
317           out += string (ptr, dollar - ptr);
318           ptr = dollar;
319
320           if (*start_var == '{')
321             {
322               start_var ++;
323               
324               end_var = strchr (start_var, '}');
325               
326               if (end_var == NULL)
327                 {
328                   end_var = start_var + len;
329                   start_next = end_var;
330                 }
331               else
332                 {
333                   start_next = end_var + 1; 
334                 }
335             }
336           else 
337             {
338               /*
339                 Hmm. what to do for $1 , $~ etc.?
340                */
341               do
342                 {
343                   end_var ++;
344                 }
345               while (isalnum (*end_var) || *end_var == '_');
346               start_next = end_var;
347             }
348
349           if (start_var < end_var)
350             {
351               string var_name (start_var, end_var - start_var);
352               const char *value = getenv (var_name.c_str());
353               if (value != NULL)
354                 out += string (value);
355
356               ptr = start_next;
357             }
358         }
359       else
360         break;
361
362     }
363
364   out += ptr;
365
366   return out;
367 }
368
369
370 string
371 read_line (FILE *f)
372 {
373   string out;
374   
375   int c = 0;
376   while ((c = fgetc (f)) != EOF && c != '\n')
377     out += c;
378
379   return out;
380 }
381
382 void
383 read_relocation_file (string filename)
384 {
385   if (be_verbose_global)
386     progress_indication (_f ("Relocation file %s\n", filename.c_str ()));
387       
388   char const *cname = filename.c_str ();
389   FILE *f = fopen (cname, "r");
390   if (!f)
391     error (_f ("can't open file %s", cname));
392
393   while (!feof (f))
394     {
395       string line = read_line (f);
396       size_t idx = line.find (' ');
397       if (idx == NPOS)
398         continue;
399       
400       string command = line.substr (0, idx);
401       line = line.substr (idx + 1);
402       
403       if (idx == NPOS)
404         continue;
405       idx = line.find ('=');
406
407       string variable = line.substr (0, idx);
408       string value = line.substr (idx + 1);
409
410       value = expand_environment_variables (value);
411
412       if (command == "set")
413         sane_putenv (variable.c_str(), value, true);
414       else if (command == "setdir")
415         set_env_dir (variable.c_str(), value);
416       else if (command == "setfile")
417         set_env_file (variable.c_str(), value);
418       else if (command == "prependdir")
419         prepend_env_path (variable.c_str (), value);
420       else
421         error ( _f("Unknown relocation command %s", command));
422     }
423
424   fclose (f);
425 }
426
427 void
428 read_relocation_dir (string dirname)
429 {
430   DIR *dir = opendir  (dirname.c_str ());
431
432   while (struct dirent *ent = readdir (dir))
433     {
434       File_name name (ent->d_name);
435       if (name.ext_ == "reloc")
436         {
437           read_relocation_file (dirname + "/" + name.to_string ());
438         }
439     }
440 }