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