Typos: Lilypond -> LilyPond, explicite -> explicit, fix docstring
[lilypond/mpolesky.git] / lily / main.cc
blob1413854b1b33ce8de7ba25942259989e8c677552
1 /*
2 main.cc -- implement main () entrypoint.
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "main.hh"
11 #include <cassert>
12 #include <clocale>
13 #include <cstring>
14 #include <cerrno>
15 #include <cstdio>
16 using namespace std;
18 #include <unistd.h>
19 #include <sys/types.h>
20 #include "config.hh"
22 #if HAVE_GRP_H
23 #include <grp.h>
24 #endif
25 #if HAVE_PWD_H
26 #include <pwd.h>
27 #endif
28 #if HAVE_GETTEXT
29 #include <libintl.h>
30 #endif
32 #include "all-font-metrics.hh"
33 #include "file-name.hh"
34 #include "freetype.hh"
35 #include "getopt-long.hh"
36 #include "global-ctor.hh"
37 #include "international.hh"
38 #include "lily-version.hh"
39 #include "misc.hh"
40 #include "output-def.hh"
41 #include "program-option.hh"
42 #include "relocate.hh"
43 #include "string-convert.hh"
44 #include "version.hh"
45 #include "warn.hh"
48 * Global options that can be overridden through command line.
51 /* Names of header fields to be dumped to a separate file. */
52 vector<string> dump_header_fieldnames_global;
54 /* Name of initialisation file. */
55 string init_name_global;
58 /* Output formats to generate. */
59 string output_format_global = "";
61 /* Current output name. */
62 string output_name_global;
64 /* Run in safe mode? */
65 bool be_safe_global = false;
67 /* Provide URI links to the original file */
68 bool point_and_click_global = true;
70 /* Verbose progress indication? */
71 bool be_verbose_global = false;
73 /* Scheme code to execute before parsing, after .scm init.
74 This is where -e arguments are appended to. */
75 string init_scheme_code_global;
76 string init_scheme_variables_global;
78 bool relocate_binary = true;
82 * Miscellaneous global stuff.
84 File_path global_path;
87 * File globals.
90 static char const *AUTHORS
91 = " Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
92 " Jan Nieuwenhuizen <janneke@gnu.org>\n";
94 static char const *PROGRAM_NAME = "lilypond";
95 static char const *PROGRAM_URL = "http://lilypond.org";
97 static char const *NOTICE
98 = _i ("This program is free software. It is covered by the GNU General Public\n"
99 "License and you are welcome to change it and/or distribute copies of it\n"
100 "under certain conditions. Invoke as `%s --warranty' for more\n"
101 "information.\n");
103 static char const *WARRANTY
104 = _i (" This program is free software; you can redistribute it and/or\n"
105 "modify it under the terms of the GNU General Public License version 2\n"
106 "as published by the Free Software Foundation.\n"
107 "\n"
108 " This program is distributed in the hope that it will be useful,\n"
109 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
110 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
111 "General Public License for more details.\n"
112 "\n"
113 " You should have received a copy of the\n"
114 "GNU General Public License along with this program; if not, write to\n"
115 "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
116 "Boston, MA 02111-1307, USA.\n");
118 /* Where the init files live. Typically:
119 LILYPOND_DATADIR = /usr/share/lilypond
121 string lilypond_datadir;
123 /* The jail specification: USER, GROUP, JAIL, DIR. */
124 string jail_spec;
126 /* The option parser */
127 static Getopt_long *option_parser = 0;
129 /* Internationalisation kludge in two steps:
130 * use _i () to get entry in POT file
131 * call gettext () explicitly for actual "translation" */
133 static Long_option_init options_static[]
135 {_i ("SYM[=VAL]"), "define-default", 'd',
136 _i ("set Scheme option SYM to VAL (default: #t).\n"
137 "Use -dhelp for help.")},
139 {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
140 /* Bug in option parser: --output =foe is taken as an abbreviation
141 for --output-format. */
142 {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,... Also as separate options:")},
143 {0, "pdf", 0, _i ("generate PDF (default)")},
144 {0, "png", 0, _i ("generate PNG")},
145 {0, "ps", 0, _i ("generate PostScript")},
146 {0, "help", 'h', _i ("show this help and exit")},
147 {_i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
148 "named BASENAME.FIELD")},
149 {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
150 {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
151 #if HAVE_CHROOT
152 {_i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
153 "and cd into DIR")},
154 #endif
155 {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
156 {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
157 {0, "version", 'v', _i ("show version number and exit")},
158 {0, "verbose", 'V', _i ("be verbose")},
159 {0, "warranty", 'w', _i ("show warranty and copyright")},
160 {0, 0, 0, 0}
163 char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
166 /* x86 defaults to using 80-bit extended precision arithmetic. This can cause
167 problems because the truncation from 80 bits to 64 bits can occur in
168 unpredictable places. To get around this, we tell the x87 FPU to use only
169 double precision. Note that this is not needed for x86_64 because that uses
170 the SSE unit by default instead of the x87 FPU. */
171 #if ((defined(__x86__) || defined(__i386__)) \
172 && defined(HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
174 #include <fpu_control.h>
175 static void configure_fpu() {
176 fpu_control_t fpu_control = 0x027f;
177 _FPU_SETCW (fpu_control);
180 #else
182 static void configure_fpu() {
185 #endif /* defined(__x86__) || defined(__i386__) */
188 static void
189 env_var_info (FILE *out, char const *key)
191 if (char const *value = getenv (key))
192 fprintf (out, "%s=\"%s\"\n", key, value);
195 static void
196 dir_info (FILE *out)
198 fputs ("\n", out);
199 fprintf (out, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR);
200 env_var_info (out, "LILYPONDPREFIX");
201 env_var_info (out, "LILYPOND_DATADIR");
202 fprintf (out, "LOCALEDIR=\"%s\"\n", LOCALEDIR);
204 fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
206 if (relocate_binary)
208 env_var_info (out, "FONTCONFIG_FILE");
209 env_var_info (out, "FONTCONFIG_PATH");
210 env_var_info (out, "GS_FONTPATH");
211 env_var_info (out, "GS_LIB");
212 env_var_info (out, "GUILE_LOAD_PATH");
213 env_var_info (out, "PANGO_RC_FILE");
214 env_var_info (out, "PANGO_PREFIX");
215 env_var_info (out, "PATH");
219 static void
220 copyright ()
222 /* Do not update the copyright years here, run grand-replace.sh. */
223 printf (_f ("Copyright (c) %s by\n%s and others.", "1996--2009",
224 AUTHORS).c_str ());
225 printf ("\n");
228 static void
229 identify (FILE *out)
231 fputs (gnu_lilypond_version_string ().c_str (), out);
232 fputs ("\n", out);
235 static void
236 notice ()
238 identify (stdout);
239 printf ("\n");
240 copyright ();
241 printf ("\n");
242 puts (_f (NOTICE, PROGRAM_NAME).c_str ());
245 LY_DEFINE (ly_usage, "ly:usage",
246 0, 0, 0, (),
247 "Print usage message.")
249 /* No version number or newline here. It confuses help2man. */
250 printf (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ());
251 printf ("\n\n");
252 printf (_ ("Typeset music and/or produce MIDI from FILE.").c_str ());
253 printf ("\n\n");
254 printf (_ ("LilyPond produces beautiful music notation.").c_str ());
255 printf ("\n");
256 printf (_f ("For more information, see %s", PROGRAM_URL).c_str ());
257 printf ("\n\n");
258 printf (_ ("Options:").c_str ());
259 printf ("\n");
260 printf (Long_option_init::table_string (options_static).c_str ());
261 printf ("\n");
262 /* Translators, please translate this string as
263 "Report bugs in English via %s",
264 or if there is a LilyPond users list or forum in your language
265 "Report bugs in English via %s or in YOUR_LANG via URI" */
266 printf (_f ("Report bugs via %s",
267 "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
268 ).c_str ());
269 printf ("\n");
270 printf ("\n");
271 return SCM_UNSPECIFIED;
274 static void
275 warranty ()
277 identify (stdout);
278 printf ("\n");
279 copyright ();
280 printf ("\n");
281 printf (_ (WARRANTY).c_str ());
284 static void
285 prepend_load_path (string dir)
287 string s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
288 scm_c_eval_string (s.c_str ());
291 void init_global_tweak_registry ();
292 void init_fontconfig ();
294 #if HAVE_CHROOT
295 static void
296 do_chroot_jail ()
298 /* Now we chroot, setuid/setgrp and chdir. If something goes wrong,
299 we exit (this is a security-sensitive area). First we split
300 jail_spec into its components, then we retrieve the user/group id
301 (necessarily *before* chroot'ing) and finally we perform the
302 actual actions. */
304 enum Jail
306 USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
309 vector<string> components = string_split (jail_spec, ',');
310 if (components.size () != JAIL_MAX)
312 error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
313 (unsigned) components.size ()));
314 exit (2);
317 /* Hmm. */
318 errno = 0;
320 int uid;
321 if (passwd * passwd = getpwnam (components[USER_NAME].c_str ()))
322 uid = passwd->pw_uid;
323 else
325 if (errno == 0)
326 error (_f ("no such user: %s", components[USER_NAME]));
327 else
328 error (_f ("cannot get user id from user name: %s: %s",
329 components[USER_NAME],
330 strerror (errno)));
331 exit (3);
334 /* Hmm. */
335 errno = 0;
337 int gid;
338 if (group * group = getgrnam (components[GROUP_NAME].c_str ()))
339 gid = group->gr_gid;
340 else
342 if (errno == 0)
343 error (_f ("no such group: %s", components[GROUP_NAME]));
344 else
345 error (_f ("cannot get group id from group name: %s: %s",
346 components[GROUP_NAME],
347 strerror (errno)));
348 exit (3);
351 if (chroot (components[JAIL].c_str ()))
353 error (_f ("cannot chroot to: %s: %s", components[JAIL],
354 strerror (errno)));
355 exit (3);
358 if (setgid (gid))
360 error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
361 exit (3);
364 if (setuid (uid))
366 error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
367 exit (3);
370 if (chdir (components[DIR].c_str ()))
372 error (_f ("cannot change working directory to: %s: %s", components[DIR],
373 strerror (errno)));
374 exit (3);
377 #endif
379 static void
380 main_with_guile (void *, int, char **)
382 /* Engravers use lily.scm contents, need to make Guile find it.
383 Prepend onto GUILE %load-path, very ugh. */
385 prepend_load_path (lilypond_datadir);
386 prepend_load_path (lilypond_datadir + "/scm");
388 if (be_verbose_global)
389 dir_info (stderr);
391 init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
392 init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
394 ly_c_init_guile ();
395 call_constructors ();
396 init_fontconfig ();
398 init_freetype ();
399 ly_reset_all_fonts ();
401 /* We accept multiple independent music files on the command line to
402 reduce compile time when processing lots of small files.
403 Starting the GUILE engine is very time consuming. */
405 SCM files = SCM_EOL;
406 SCM *tail = &files;
407 while (char const *arg = option_parser->get_next_arg ())
409 *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
410 tail = SCM_CDRLOC (*tail);
413 delete option_parser;
414 option_parser = 0;
416 #if HAVE_CHROOT
417 if (!jail_spec.empty ())
418 do_chroot_jail ();
419 #endif
421 SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
422 (void) result;
424 /* Unreachable. */
425 exit (0);
428 static void
429 setup_localisation ()
431 #if HAVE_GETTEXT
432 /* Enable locales */
433 setlocale (LC_ALL, "");
435 /* FIXME: check if this is still true.
436 Disable localisation of float values. */
437 setlocale (LC_NUMERIC, "C");
439 string localedir = LOCALEDIR;
440 if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
441 localedir = env;
443 bindtextdomain ("lilypond", localedir.c_str ());
444 textdomain ("lilypond");
445 #endif
448 static void
449 add_output_format (string format)
451 if (output_format_global != "")
452 output_format_global += ",";
453 output_format_global += format;
456 static void
457 parse_argv (int argc, char **argv)
459 bool show_help = false;
460 option_parser = new Getopt_long (argc, argv, options_static);
461 while (Long_option_init const *opt = (*option_parser) ())
463 switch (opt->shortname_char_)
465 case 0:
466 if (string (opt->longname_str0_) == "pdf"
467 || string (opt->longname_str0_) == "png"
468 || string (opt->longname_str0_) == "ps")
469 add_output_format (opt->longname_str0_);
470 else if (string (opt->longname_str0_) == "relocate")
471 relocate_binary = true;
472 break;
474 case 'd':
476 string arg (option_parser->optional_argument_str0_);
477 ssize eq = arg.find ('=');
479 string key = arg;
480 string val = "#t";
482 if (eq != NPOS)
484 key = arg.substr (0, eq);
485 val = arg.substr (eq + 1, arg.length () - 1);
488 init_scheme_variables_global
489 += "(cons \'" + key + " '" + val + ")\n";
491 break;
493 case 'v':
494 notice ();
495 exit (0);
496 break;
497 case 'o':
499 string s = option_parser->optional_argument_str0_;
500 File_name file_name (s);
501 output_name_global = file_name.to_string ();
503 break;
504 case 'j':
505 jail_spec = option_parser->optional_argument_str0_;
506 break;
508 case 'e':
509 init_scheme_code_global += option_parser->optional_argument_str0_ + string (" ");
510 break;
511 case 'w':
512 warranty ();
513 exit (0);
514 break;
516 case 'f':
518 vector<string> components
519 = string_split (option_parser->optional_argument_str0_, ',');
520 for (vsize i = 0; i < components.size (); i++)
521 add_output_format (components[i]);
523 break;
525 case 'H':
526 dump_header_fieldnames_global
527 .push_back (option_parser->optional_argument_str0_);
528 break;
529 case 'I':
530 global_path.append (option_parser->optional_argument_str0_);
531 break;
532 case 'i':
533 init_name_global = option_parser->optional_argument_str0_;
534 break;
535 case 'h':
536 show_help = true;
537 break;
538 case 'V':
539 be_verbose_global = true;
540 break;
541 default:
542 programming_error (to_string ("unhandled short option: %c",
543 opt->shortname_char_));
544 assert (false);
545 break;
549 if (output_format_global == "")
550 output_format_global = "pdf";
552 if (show_help)
554 ly_usage ();
555 if (be_verbose_global)
556 dir_info (stdout);
557 exit (0);
561 void
562 setup_guile_env ()
564 const char *yield = getenv ("LILYPOND_GC_YIELD");
565 bool overwrite = true;
566 if (!yield)
568 yield = "65";
569 overwrite = false;
572 sane_putenv ("GUILE_MIN_YIELD_1", yield, overwrite);
573 sane_putenv ("GUILE_MIN_YIELD_2", yield, overwrite);
574 sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield, overwrite);
577 sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
578 "10485760", overwrite);
579 sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
580 "104857600", overwrite);
583 vector<string> start_environment_global;
586 main (int argc, char **argv, char **envp)
588 configure_fpu();
590 for (char **p = envp; *p; p++)
591 start_environment_global.push_back(*p);
593 if (getenv ("LILYPOND_VERBOSE"))
594 be_verbose_global = true;
596 setup_localisation ();
597 parse_argv (argc, argv);
598 if (isatty (STDIN_FILENO))
599 identify (stderr);
601 setup_paths (argv[0]);
602 setup_guile_env ();
604 #if 0
605 /* Debugging aid. */
608 scm_boot_guile (argc, argv, main_with_guile, 0);
610 catch (exception e)
612 error (_f ("exception caught: %s", e.what ()));
614 #else
615 scm_boot_guile (argc, argv, main_with_guile, 0);
616 #endif
618 /* Only reachable if GUILE exits. That is an error. */
619 return 1;