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