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