2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--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/>.
30 #include <sys/types.h>
43 #include "all-font-metrics.hh"
44 #include "file-name.hh"
45 #include "freetype.hh"
46 #include "getopt-long.hh"
47 #include "global-ctor.hh"
48 #include "international.hh"
49 #include "lily-version.hh"
51 #include "output-def.hh"
52 #include "program-option.hh"
53 #include "relocate.hh"
54 #include "string-convert.hh"
59 * Global options that can be overridden through command line.
62 /* Names of header fields to be dumped to a separate file. */
63 vector<string> dump_header_fieldnames_global;
65 /* Name of initialisation file. */
66 string init_name_global;
69 /* Output formats to generate. */
70 string output_format_global = "";
72 /* Current output name. */
73 string output_name_global;
75 /* Run in safe mode? */
76 bool be_safe_global = false;
78 /* Provide URI links to the original file */
79 bool point_and_click_global = true;
81 /* Verbose progress indication? */
82 bool be_verbose_global = false;
84 /* Scheme code to execute before parsing, after .scm init.
85 This is where -e arguments are appended to. */
86 string init_scheme_code_global;
87 string init_scheme_variables_global;
89 bool relocate_binary = true;
93 * Miscellaneous global stuff.
95 File_path global_path;
101 static char const *AUTHORS
102 = " Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
103 " Jan Nieuwenhuizen <janneke@gnu.org>\n";
105 static char const *PROGRAM_NAME = "lilypond";
106 static char const *PROGRAM_URL = "http://lilypond.org";
108 static char const *NOTICE
109 = _i ("This program is free software. It is covered by the GNU General Public\n"
110 "License and you are welcome to change it and/or distribute copies of it\n"
111 "under certain conditions. Invoke as `%s --warranty' for more\n"
114 static char const *WARRANTY
115 = _i (" This program is free software; you can redistribute it and/or\n"
116 "modify it under the terms of the GNU General Public License as \n"
117 "published by the Free Software Foundation, either version 3 of\n"
118 "the License, or (at your option) any later version.\n"
120 " This program is distributed in the hope that it will be useful,\n"
121 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
122 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
123 "General Public License for more details.\n"
125 " You should have received a copy of the\n"
126 "GNU General Public License along with this program; if not, write to\n"
127 "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
128 "Boston, MA 02111-1307, USA.\n");
130 /* Where the init files live. Typically:
131 LILYPOND_DATADIR = /usr/share/lilypond
133 string lilypond_datadir;
135 /* The jail specification: USER, GROUP, JAIL, DIR. */
138 /* The option parser */
139 static Getopt_long *option_parser = 0;
141 /* Internationalisation kludge in two steps:
142 * use _i () to get entry in POT file
143 * call gettext () explicitly for actual "translation" */
145 static Long_option_init options_static[]
147 {_i ("SYM[=VAL]"), "define-default", 'd',
148 _i ("set Scheme option SYM to VAL (default: #t).\n"
149 "Use -dhelp for help.")},
151 {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
152 /* Bug in option parser: --output =foe is taken as an abbreviation
153 for --output-format. */
154 {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,... Also as separate options:")},
155 {0, "pdf", 0, _i ("generate PDF (default)")},
156 {0, "png", 0, _i ("generate PNG")},
157 {0, "ps", 0, _i ("generate PostScript")},
158 {0, "help", 'h', _i ("show this help and exit")},
159 {_i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
160 "named BASENAME.FIELD")},
161 {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
162 {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
164 {_i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
167 {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
168 {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
169 {0, "version", 'v', _i ("show version number and exit")},
170 {0, "verbose", 'V', _i ("be verbose")},
171 {0, "warranty", 'w', _i ("show warranty and copyright")},
175 char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
178 /* x86 defaults to using 80-bit extended precision arithmetic. This can cause
179 problems because the truncation from 80 bits to 64 bits can occur in
180 unpredictable places. To get around this, we tell the x87 FPU to use only
181 double precision. Note that this is not needed for x86_64 because that uses
182 the SSE unit by default instead of the x87 FPU. */
183 #if ((defined(__x86__) || defined(__i386__)) \
184 && defined(HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
186 #include <fpu_control.h>
190 fpu_control_t fpu_control = 0x027f;
191 _FPU_SETCW (fpu_control);
201 #endif /* defined(__x86__) || defined(__i386__) */
205 env_var_info (FILE *out, char const *key)
207 if (char const *value = getenv (key))
208 fprintf (out, "%s=\"%s\"\n", key, value);
215 fprintf (out, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR);
216 env_var_info (out, "LILYPONDPREFIX");
217 env_var_info (out, "LILYPOND_DATADIR");
218 fprintf (out, "LOCALEDIR=\"%s\"\n", LOCALEDIR);
220 fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
224 env_var_info (out, "FONTCONFIG_FILE");
225 env_var_info (out, "FONTCONFIG_PATH");
226 env_var_info (out, "GS_FONTPATH");
227 env_var_info (out, "GS_LIB");
228 env_var_info (out, "GUILE_LOAD_PATH");
229 env_var_info (out, "PANGO_RC_FILE");
230 env_var_info (out, "PANGO_PREFIX");
231 env_var_info (out, "PATH");
238 /* Do not update the copyright years here, run `make grand-replace' */
239 printf ("%s", (_f ("Copyright (c) %s by\n%s and others.", "1996--2011",
247 fputs (gnu_lilypond_version_string ().c_str (), out);
258 puts (_f (NOTICE, PROGRAM_NAME).c_str ());
261 LY_DEFINE (ly_usage, "ly:usage",
263 "Print usage message.")
265 /* No version number or newline here. It confuses help2man. */
266 printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ()));
268 printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
270 printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
272 printf ("%s", (_f ("For more information, see %s", PROGRAM_URL).c_str ()));
274 printf ("%s", (_ ("Options:").c_str ()));
276 printf ("%s", Long_option_init::table_string (options_static).c_str ());
278 /* Translators, please translate this string as
279 "Report bugs in English via %s",
280 or if there is a LilyPond users list or forum in your language
281 "Report bugs in English via %s or in YOUR_LANG via URI" */
282 printf ("%s", (_f ("Report bugs via %s",
283 "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
287 return SCM_UNSPECIFIED;
297 printf ("%s", (_ (WARRANTY).c_str ()));
301 prepend_load_path (string dir)
303 string s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
304 scm_c_eval_string (s.c_str ());
307 void init_global_tweak_registry ();
308 void init_fontconfig ();
314 /* Now we chroot, setuid/setgrp and chdir. If something goes wrong,
315 we exit (this is a security-sensitive area). First we split
316 jail_spec into its components, then we retrieve the user/group id
317 (necessarily *before* chroot'ing) and finally we perform the
322 USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
325 vector<string> components = string_split (jail_spec, ',');
326 if (components.size () != JAIL_MAX)
328 error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
329 (unsigned) components.size ()));
337 if (passwd * passwd = getpwnam (components[USER_NAME].c_str ()))
338 uid = passwd->pw_uid;
342 error (_f ("no such user: %s", components[USER_NAME]));
344 error (_f ("cannot get user id from user name: %s: %s",
345 components[USER_NAME],
354 if (group * group = getgrnam (components[GROUP_NAME].c_str ()))
359 error (_f ("no such group: %s", components[GROUP_NAME]));
361 error (_f ("cannot get group id from group name: %s: %s",
362 components[GROUP_NAME],
367 if (chroot (components[JAIL].c_str ()))
369 error (_f ("cannot chroot to: %s: %s", components[JAIL],
376 error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
382 error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
386 if (chdir (components[DIR].c_str ()))
388 error (_f ("cannot change working directory to: %s: %s", components[DIR],
396 main_with_guile (void *, int, char **)
398 /* Engravers use lily.scm contents, need to make Guile find it.
399 Prepend onto GUILE %load-path, very ugh. */
401 prepend_load_path (lilypond_datadir);
402 prepend_load_path (lilypond_datadir + "/scm");
404 if (be_verbose_global)
407 init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
408 init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
411 call_constructors ();
415 ly_reset_all_fonts ();
417 /* We accept multiple independent music files on the command line to
418 reduce compile time when processing lots of small files.
419 Starting the GUILE engine is very time consuming. */
423 while (char const *arg = option_parser->get_next_arg ())
425 *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
426 tail = SCM_CDRLOC (*tail);
429 delete option_parser;
433 if (!jail_spec.empty ())
437 SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
445 setup_localisation ()
449 setlocale (LC_ALL, "");
451 /* FIXME: check if this is still true.
452 Disable localisation of float values. */
453 setlocale (LC_NUMERIC, "C");
455 string localedir = LOCALEDIR;
456 if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
459 bindtextdomain ("lilypond", localedir.c_str ());
460 textdomain ("lilypond");
465 add_output_format (string format)
467 if (output_format_global != "")
468 output_format_global += ",";
469 output_format_global += format;
473 parse_argv (int argc, char **argv)
475 bool show_help = false;
476 option_parser = new Getopt_long (argc, argv, options_static);
477 while (Long_option_init const *opt = (*option_parser) ())
479 switch (opt->shortname_char_)
482 if (string (opt->longname_str0_) == "pdf"
483 || string (opt->longname_str0_) == "png"
484 || string (opt->longname_str0_) == "ps")
485 add_output_format (opt->longname_str0_);
486 else if (string (opt->longname_str0_) == "relocate")
487 relocate_binary = true;
492 string arg (option_parser->optional_argument_str0_);
493 ssize eq = arg.find ('=');
500 key = arg.substr (0, eq);
501 val = arg.substr (eq + 1, arg.length () - 1);
504 init_scheme_variables_global
505 += "(cons \'" + key + " '" + val + ")\n";
515 string s = option_parser->optional_argument_str0_;
516 File_name file_name (s);
517 output_name_global = file_name.to_string ();
521 jail_spec = option_parser->optional_argument_str0_;
525 init_scheme_code_global
526 += option_parser->optional_argument_str0_ + string (" ");
535 vector<string> components
536 = string_split (option_parser->optional_argument_str0_, ',');
537 for (vsize i = 0; i < components.size (); i++)
538 add_output_format (components[i]);
543 dump_header_fieldnames_global
544 .push_back (option_parser->optional_argument_str0_);
547 global_path.append (option_parser->optional_argument_str0_);
550 init_name_global = option_parser->optional_argument_str0_;
556 be_verbose_global = true;
559 programming_error (to_string ("unhandled short option: %c",
560 opt->shortname_char_));
566 if (output_format_global == "")
567 output_format_global = "pdf";
572 if (be_verbose_global)
581 char const *yield = getenv ("LILYPOND_GC_YIELD");
582 bool overwrite = true;
589 sane_putenv ("GUILE_MIN_YIELD_1", yield, overwrite);
590 sane_putenv ("GUILE_MIN_YIELD_2", yield, overwrite);
591 sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield, overwrite);
594 sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
595 "10485760", overwrite);
596 sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
597 "104857600", overwrite);
600 vector<string> start_environment_global;
603 main (int argc, char **argv, char **envp)
607 for (char **p = envp; *p; p++)
608 start_environment_global.push_back(*p);
610 if (getenv ("LILYPOND_VERBOSE"))
611 be_verbose_global = true;
613 setup_localisation ();
614 parse_argv (argc, argv);
615 if (isatty (STDIN_FILENO))
618 setup_paths (argv[0]);
625 scm_boot_guile (argc, argv, main_with_guile, 0);
629 error (_f ("exception caught: %s", e.what ()));
632 scm_boot_guile (argc, argv, main_with_guile, 0);
635 /* Only reachable if GUILE exits. That is an error. */