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