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