Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / relocate.cc
blob628187363bd39aa8417064146bf779189f5cbfdd
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2005--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
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.
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.
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/>.
20 #include "relocate.hh"
22 #include "config.hh"
25 /* TODO: autoconf support */
27 #include <sys/types.h>
28 #include <dirent.h>
30 #if HAVE_GETTEXT
31 #include <libintl.h>
32 #endif
34 #include "file-name.hh"
35 #include "file-path.hh"
36 #include "international.hh"
37 #include "lily-guile.hh"
38 #include "lily-version.hh"
39 #include "main.hh"
40 #include "version.hh"
41 #include "warn.hh"
43 #define FRAMEWORKDIR ".."
45 int
46 sane_putenv (char const *key, string value, bool overwrite)
48 if (overwrite || !getenv (key))
50 string combine = string (key) + "=" + value;
51 char *s = strdup (combine.c_str ());
53 if (be_verbose_global)
54 progress_indication (_f ("Setting %s to %s" , key, value.c_str ())
55 + "\n");
57 int retval = putenv (s);
59 unfortunately, we can't portably free S here,
60 due to various bugs in glibc prior to 2.1.1
61 */
62 return retval;
65 return -1;
68 static int
69 set_env_file (char const *key, string value, bool overwrite = false)
71 if (is_file (value))
72 return sane_putenv (key, value, overwrite);
73 else if (be_verbose_global)
74 warning (_f ("no such file: %s for %s", value, key));
75 return -1;
78 static int
79 set_env_dir (char const *key, string value)
81 if (is_dir (value))
82 return sane_putenv (key, value, false);
83 else if (be_verbose_global)
84 warning (_f ("no such directory: %s for %s", value, key));
85 return -1;
88 static int
89 prepend_env_path (char const *key, string value)
91 if (is_dir (value))
93 if (be_verbose_global)
94 progress_indication (_f ("%s=%s (prepend)\n", key, value.c_str ()));
96 if (char const *cur = getenv (key))
97 value += to_string (PATHSEP) + cur;
99 return sane_putenv (key, value.c_str (), true);
101 else if (be_verbose_global)
102 warning (_f ("no such directory: %s for %s", value, key));
103 return -1;
106 #ifdef __MINGW32__
107 #include <winbase.h>
108 #endif
110 static void
111 prefix_relocation (string prefix)
113 string bindir = prefix + "/bin";
114 string datadir = prefix + "/share";
115 string localedir = datadir + "/locale";
116 string package_datadir = datadir + "/lilypond/";
117 string old_lilypond_datadir = lilypond_datadir;
119 if (is_dir (package_datadir + "/" + TOPLEVEL_VERSION))
120 lilypond_datadir = package_datadir + "/" + TOPLEVEL_VERSION;
121 else if (is_dir (package_datadir + "/current"))
122 lilypond_datadir = package_datadir + "/current";
123 else
124 warning (_f ("not relocating, no %s/ or current/ found under %s",
125 TOPLEVEL_VERSION, package_datadir.c_str ()));
127 #if HAVE_GETTEXT
128 if (is_dir (localedir))
129 bindtextdomain ("lilypond", localedir.c_str ());
130 #endif
132 prepend_env_path ("PATH", bindir);
134 if (be_verbose_global)
135 warning (_f ("Relocation: compile datadir=%s, new datadir=%s",
136 old_lilypond_datadir.c_str (),
137 lilypond_datadir.c_str ()));
141 UGH : this is a complete mess.
144 static void
145 framework_relocation (string prefix)
147 if (be_verbose_global)
148 warning (_f ("Relocation: framework_prefix=%s", prefix));
150 sane_putenv ("INSTALLER_PREFIX", prefix, true);
152 read_relocation_dir (prefix + "/etc/relocate/");
154 string bindir = prefix + "/bin";
156 prepend_env_path ("PATH", bindir);
160 UGH : this is a complete mess.
162 void
163 setup_paths (char const *argv0_ptr)
165 File_name argv0_filename (argv0_ptr);
167 if (relocate_binary)
169 string prefix_directory;
170 if (getenv ("LILYPOND_RELOCATE_PREFIX"))
172 prefix_directory = getenv ("LILYPOND_RELOCATE_PREFIX");
173 #ifdef __MINGW32__
174 /* Normalize file name. */
175 prefix_directory = File_name (prefix_directory).to_string ();
176 #endif /* __MINGW32__ */
178 prefix_relocation (prefix_directory);
179 string bindir = prefix_directory + "/bin";
180 framework_relocation (bindir);
182 else if (relocate_binary)
184 string argv0_abs;
185 if (argv0_filename.is_absolute ())
187 argv0_abs = argv0_filename.to_string ();
188 if (be_verbose_global)
189 warning (_f ("Relocation: is absolute: argv0=%s", argv0_ptr));
191 else if (argv0_filename.dir_.length ())
193 argv0_abs = get_working_directory ()
194 + "/" + string (argv0_filename.to_string ());
195 if (be_verbose_global)
196 warning (_f ("Relocation: from cwd: argv0=%s", argv0_ptr));
198 else
200 /* Find absolute ARGV0 name, using PATH. */
201 File_path path;
202 path.parse_path (getenv ("PATH"));
204 #ifndef __MINGW32__
205 argv0_abs = path.find (argv0_filename.to_string ());
206 #else /* __MINGW32__ */
207 path.prepend (get_working_directory ());
208 char const *ext[] = {"exe", "", 0 };
209 argv0_abs = path.find (argv0_filename.to_string (), ext);
210 #endif /* __MINGW32__ */
212 if (be_verbose_global)
213 warning (_f ("Relocation: from PATH=%s\nargv0=%s",
214 path.to_string ().c_str (), argv0_ptr));
216 if (argv0_abs.empty ())
217 programming_error ("cannot find absolute argv0");
220 string bindir = dir_name (argv0_abs);
221 string argv0_prefix = dir_name (bindir);
222 string compile_prefix = dir_name (dir_name (dir_name (lilypond_datadir)));
223 if (argv0_prefix != compile_prefix)
225 prefix_relocation (argv0_prefix);
226 prefix_directory = argv0_prefix;
228 if (argv0_prefix != compile_prefix || string (FRAMEWORKDIR) != "..")
230 framework_relocation (bindir + "/" + FRAMEWORKDIR);
231 prefix_directory = bindir + "/" + FRAMEWORKDIR;
235 lilypond_datadir = prefix_directory
236 + "/share/lilypond/" TOPLEVEL_VERSION;
239 if (getenv ("LILYPONDPREFIX"))
240 error (_ ("LILYPONDPREFIX is obsolete, use LILYPOND_DATADIR"));
242 if (char const *env = getenv ("LILYPOND_DATADIR"))
244 /* Normalize file name. */
245 lilypond_datadir = File_name (env).to_string ();
248 /* When running from build dir, a full LILYPOND_DATADIR is set-up at
249 $(OUTBASE)/{share, lib}/lilypond/current. Configure lily using
250 ./configure --prefix=$(pwd)/out */
251 string build_datadir_current = dir_name (lilypond_datadir) + "/current";
252 if (!is_dir (lilypond_datadir.c_str ())
253 && is_dir (build_datadir_current.c_str ()))
254 lilypond_datadir = build_datadir_current;
257 lilypond_datadir = File_name (lilypond_datadir).canonicalized().to_string();
259 global_path.append ("");
261 /* Adding mf/out make lilypond unchanged source directory, when setting
262 LILYPONDPREFIX to lilypond-x.y.z */
263 char const *suffixes[] = {"ly", "ps", "scm", 0 };
265 vector<string> dirs;
266 for (char const **s = suffixes; *s; s++)
268 string path = lilypond_datadir + to_string ('/') + string (*s);
269 dirs.push_back (path);
272 dirs.push_back (lilypond_datadir + "/fonts/otf/");
273 dirs.push_back (lilypond_datadir + "/fonts/type1/");
274 dirs.push_back (lilypond_datadir + "/fonts/svg/");
276 for (vsize i = 0; i < dirs.size (); i++)
277 global_path.prepend (dirs[i]);
280 string
281 expand_environment_variables (string orig)
283 char const *start_ptr = orig.c_str ();
284 char const *ptr = orig.c_str ();
285 size_t len = orig.length ();
287 string out;
288 while (ptr < start_ptr + len)
290 char const *dollar = strchr (ptr, '$');
292 if (dollar != NULL)
294 char const *start_var = dollar + 1;
295 char const *end_var = start_var;
296 char const *start_next = end_var;
298 out += string (ptr, dollar - ptr);
299 ptr = dollar;
301 if (*start_var == '{')
303 start_var ++;
305 end_var = strchr (start_var, '}');
307 if (end_var == NULL)
309 end_var = start_var + len;
310 start_next = end_var;
312 else
314 start_next = end_var + 1;
317 else
320 Hmm. what to do for $1 , $~ etc.?
324 end_var ++;
326 while (isalnum (*end_var) || *end_var == '_');
327 start_next = end_var;
330 if (start_var < end_var)
332 string var_name (start_var, end_var - start_var);
333 char const *value = getenv (var_name.c_str ());
334 if (value != NULL)
335 out += string (value);
337 ptr = start_next;
340 else
341 break;
345 out += ptr;
347 return out;
350 // Ugh - very inefficient, but safer than fgets.
351 static string
352 read_line (FILE *f)
354 string out;
356 int c = 0;
357 while ((c = fgetc (f)) != EOF && c != '\n')
358 out += char(c);
360 return out;
363 void
364 read_relocation_file (string filename)
366 if (be_verbose_global)
367 progress_indication (_f ("Relocation file: %s", filename.c_str ())
368 + "\n");
370 char const *cname = filename.c_str ();
371 FILE *f = fopen (cname, "r");
372 if (!f)
373 error (_f ("cannot open file: `%s'", cname));
375 while (!feof (f))
377 string line = read_line (f);
378 size_t idx = line.find (' ');
379 if (idx == NPOS)
380 continue;
382 string command = line.substr (0, idx);
383 line = line.substr (idx + 1);
385 if (idx == NPOS)
386 continue;
387 idx = line.find ('=');
389 string variable = line.substr (0, idx);
390 string value = line.substr (idx + 1);
392 value = expand_environment_variables (value);
394 if (command == "set")
395 sane_putenv (variable.c_str (), value, true);
396 else if (command == "setdir")
397 set_env_dir (variable.c_str (), value);
398 else if (command == "setfile")
399 set_env_file (variable.c_str (), value);
400 else if (command == "prependdir")
401 prepend_env_path (variable.c_str (), value);
402 else
403 error (_f ("Unknown relocation command %s", command));
406 fclose (f);
409 void
410 read_relocation_dir (string dirname)
412 if (DIR *dir = opendir (dirname.c_str ()))
413 while (struct dirent *ent = readdir (dir))
415 File_name name (ent->d_name);
416 if (name.ext_ == "reloc")
417 read_relocation_file (dirname + "/" + name.to_string ());