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