2 main.cc -- implement main () entrypoint.
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
19 #include <sys/types.h>
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"
40 #include "output-def.hh"
41 #include "program-option.hh"
42 #include "relocate.hh"
43 #include "string-convert.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;
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"
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"
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"
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. */
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 () explicitely 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")},
152 {_i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
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")},
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);
182 static void configure_fpu() {
185 #endif /* defined(__x86__) || defined(__i386__) */
189 env_var_info (FILE *out, char const *key)
191 if (char const *value = getenv (key))
192 fprintf (out, "%s=\"%s\"\n", key, value);
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 ());
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");
222 printf (_f ("Copyright (c) %s by\n%s and others.",
231 fputs (gnu_lilypond_version_string ().c_str (), out);
242 puts (_f (NOTICE, PROGRAM_NAME).c_str ());
245 LY_DEFINE (ly_usage, "ly:usage",
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 ());
252 printf (_ ("Typeset music and/or produce MIDI from FILE.").c_str ());
254 printf (_ ("LilyPond produces beautiful music notation.").c_str ());
256 printf (_f ("For more information, see %s", PROGRAM_URL).c_str ());
258 printf (_ ("Options:").c_str ());
260 printf (Long_option_init::table_string (options_static).c_str ());
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"
271 return SCM_UNSPECIFIED;
281 printf (_ (WARRANTY).c_str ());
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 ();
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
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 ()));
321 if (passwd * passwd = getpwnam (components[USER_NAME].c_str ()))
322 uid = passwd->pw_uid;
326 error (_f ("no such user: %s", components[USER_NAME]));
328 error (_f ("cannot get user id from user name: %s: %s",
329 components[USER_NAME],
338 if (group * group = getgrnam (components[GROUP_NAME].c_str ()))
343 error (_f ("no such group: %s", components[GROUP_NAME]));
345 error (_f ("cannot get group id from group name: %s: %s",
346 components[GROUP_NAME],
351 if (chroot (components[JAIL].c_str ()))
353 error (_f ("cannot chroot to: %s: %s", components[JAIL],
360 error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
366 error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
370 if (chdir (components[DIR].c_str ()))
372 error (_f ("cannot change working directory to: %s: %s", components[DIR],
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)
391 init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
392 init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
395 call_constructors ();
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. */
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;
417 if (!jail_spec.empty ())
421 SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
429 setup_localisation ()
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"))
443 bindtextdomain ("lilypond", localedir.c_str ());
444 textdomain ("lilypond");
449 add_output_format (string format)
451 if (output_format_global != "")
452 output_format_global += ",";
453 output_format_global += format;
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_)
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;
476 string arg (option_parser->optional_argument_str0_);
477 ssize eq = arg.find ('=');
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";
499 string s = option_parser->optional_argument_str0_;
500 File_name file_name (s);
501 output_name_global = file_name.to_string ();
505 jail_spec = option_parser->optional_argument_str0_;
509 init_scheme_code_global += option_parser->optional_argument_str0_ + string (" ");
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]);
526 dump_header_fieldnames_global
527 .push_back (option_parser->optional_argument_str0_);
530 global_path.append (option_parser->optional_argument_str0_);
533 init_name_global = option_parser->optional_argument_str0_;
539 be_verbose_global = true;
542 programming_error (to_string ("unhandled short option: %c",
543 opt->shortname_char_));
549 if (output_format_global == "")
550 output_format_global = "pdf";
555 if (be_verbose_global)
564 const char *yield = getenv ("LILYPOND_GC_YIELD");
565 bool overwrite = true;
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)
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))
601 setup_paths (argv[0]);
608 scm_boot_guile (argc, argv, main_with_guile, 0);
612 error (_f ("exception caught: %s", e.what ()));
615 scm_boot_guile (argc, argv, main_with_guile, 0);
618 /* Only reachable if GUILE exits. That is an error. */