2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 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 version 2\n"
117 "as published by the Free Software Foundation.\n"
119 " This program is distributed in the hope that it will be useful,\n"
120 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
121 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
122 "General Public License for more details.\n"
124 " You should have received a copy of the\n"
125 "GNU General Public License along with this program; if not, write to\n"
126 "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
127 "Boston, MA 02111-1307, USA.\n");
129 /* Where the init files live. Typically:
130 LILYPOND_DATADIR = /usr/share/lilypond
132 string lilypond_datadir
;
134 /* The jail specification: USER, GROUP, JAIL, DIR. */
137 /* The option parser */
138 static Getopt_long
*option_parser
= 0;
140 /* Internationalisation kludge in two steps:
141 * use _i () to get entry in POT file
142 * call gettext () explicitly for actual "translation" */
144 static Long_option_init options_static
[]
146 {_i ("SYM[=VAL]"), "define-default", 'd',
147 _i ("set Scheme option SYM to VAL (default: #t).\n"
148 "Use -dhelp for help.")},
150 {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
151 /* Bug in option parser: --output =foe is taken as an abbreviation
152 for --output-format. */
153 {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,... Also as separate options:")},
154 {0, "pdf", 0, _i ("generate PDF (default)")},
155 {0, "png", 0, _i ("generate PNG")},
156 {0, "ps", 0, _i ("generate PostScript")},
157 {0, "help", 'h', _i ("show this help and exit")},
158 {_i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
159 "named BASENAME.FIELD")},
160 {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
161 {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
163 {_i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
166 {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
167 {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
168 {0, "version", 'v', _i ("show version number and exit")},
169 {0, "verbose", 'V', _i ("be verbose")},
170 {0, "warranty", 'w', _i ("show warranty and copyright")},
174 char const *LILYPOND_DATADIR
= PACKAGE_DATADIR
"/" TOPLEVEL_VERSION
;
177 /* x86 defaults to using 80-bit extended precision arithmetic. This can cause
178 problems because the truncation from 80 bits to 64 bits can occur in
179 unpredictable places. To get around this, we tell the x87 FPU to use only
180 double precision. Note that this is not needed for x86_64 because that uses
181 the SSE unit by default instead of the x87 FPU. */
182 #if ((defined(__x86__) || defined(__i386__)) \
183 && defined(HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
185 #include <fpu_control.h>
189 fpu_control_t fpu_control
= 0x027f;
190 _FPU_SETCW (fpu_control
);
200 #endif /* defined(__x86__) || defined(__i386__) */
204 env_var_info (FILE *out
, char const *key
)
206 if (char const *value
= getenv (key
))
207 fprintf (out
, "%s=\"%s\"\n", key
, value
);
214 fprintf (out
, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR
);
215 env_var_info (out
, "LILYPONDPREFIX");
216 env_var_info (out
, "LILYPOND_DATADIR");
217 fprintf (out
, "LOCALEDIR=\"%s\"\n", LOCALEDIR
);
219 fprintf (out
, "\nEffective prefix: \"%s\"\n", lilypond_datadir
.c_str ());
223 env_var_info (out
, "FONTCONFIG_FILE");
224 env_var_info (out
, "FONTCONFIG_PATH");
225 env_var_info (out
, "GS_FONTPATH");
226 env_var_info (out
, "GS_LIB");
227 env_var_info (out
, "GUILE_LOAD_PATH");
228 env_var_info (out
, "PANGO_RC_FILE");
229 env_var_info (out
, "PANGO_PREFIX");
230 env_var_info (out
, "PATH");
237 /* Do not update the copyright years here, run `make grand-replace' */
238 printf ("%s", (_f ("Copyright (c) %s by\n%s and others.", "1996--2010",
246 fputs (gnu_lilypond_version_string ().c_str (), out
);
257 puts (_f (NOTICE
, PROGRAM_NAME
).c_str ());
260 LY_DEFINE (ly_usage
, "ly:usage",
262 "Print usage message.")
264 /* No version number or newline here. It confuses help2man. */
265 printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME
).c_str ()));
267 printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
269 printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
271 printf ("%s", (_f ("For more information, see %s", PROGRAM_URL
).c_str ()));
273 printf ("%s", (_ ("Options:").c_str ()));
275 printf ("%s", Long_option_init::table_string (options_static
).c_str ());
277 /* Translators, please translate this string as
278 "Report bugs in English via %s",
279 or if there is a LilyPond users list or forum in your language
280 "Report bugs in English via %s or in YOUR_LANG via URI" */
281 printf ("%s", (_f ("Report bugs via %s",
282 "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
286 return SCM_UNSPECIFIED
;
296 printf ("%s", (_ (WARRANTY
).c_str ()));
300 prepend_load_path (string dir
)
302 string s
= "(set! %load-path (cons \"" + dir
+ "\" %load-path))";
303 scm_c_eval_string (s
.c_str ());
306 void init_global_tweak_registry ();
307 void init_fontconfig ();
313 /* Now we chroot, setuid/setgrp and chdir. If something goes wrong,
314 we exit (this is a security-sensitive area). First we split
315 jail_spec into its components, then we retrieve the user/group id
316 (necessarily *before* chroot'ing) and finally we perform the
321 USER_NAME
, GROUP_NAME
, JAIL
, DIR, JAIL_MAX
324 vector
<string
> components
= string_split (jail_spec
, ',');
325 if (components
.size () != JAIL_MAX
)
327 error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX
,
328 (unsigned) components
.size ()));
336 if (passwd
* passwd
= getpwnam (components
[USER_NAME
].c_str ()))
337 uid
= passwd
->pw_uid
;
341 error (_f ("no such user: %s", components
[USER_NAME
]));
343 error (_f ("cannot get user id from user name: %s: %s",
344 components
[USER_NAME
],
353 if (group
* group
= getgrnam (components
[GROUP_NAME
].c_str ()))
358 error (_f ("no such group: %s", components
[GROUP_NAME
]));
360 error (_f ("cannot get group id from group name: %s: %s",
361 components
[GROUP_NAME
],
366 if (chroot (components
[JAIL
].c_str ()))
368 error (_f ("cannot chroot to: %s: %s", components
[JAIL
],
375 error (_f ("cannot change group id to: %d: %s", gid
, strerror (errno
)));
381 error (_f ("cannot change user id to: %d: %s", uid
, strerror (errno
)));
385 if (chdir (components
[DIR].c_str ()))
387 error (_f ("cannot change working directory to: %s: %s", components
[DIR],
395 main_with_guile (void *, int, char **)
397 /* Engravers use lily.scm contents, need to make Guile find it.
398 Prepend onto GUILE %load-path, very ugh. */
400 prepend_load_path (lilypond_datadir
);
401 prepend_load_path (lilypond_datadir
+ "/scm");
403 if (be_verbose_global
)
406 init_scheme_variables_global
= "(list " + init_scheme_variables_global
+ ")";
407 init_scheme_code_global
= "(begin " + init_scheme_code_global
+ ")";
410 call_constructors ();
414 ly_reset_all_fonts ();
416 /* We accept multiple independent music files on the command line to
417 reduce compile time when processing lots of small files.
418 Starting the GUILE engine is very time consuming. */
422 while (char const *arg
= option_parser
->get_next_arg ())
424 *tail
= scm_cons (scm_from_locale_string (arg
), SCM_EOL
);
425 tail
= SCM_CDRLOC (*tail
);
428 delete option_parser
;
432 if (!jail_spec
.empty ())
436 SCM result
= scm_call_1 (ly_lily_module_constant ("lilypond-main"), files
);
444 setup_localisation ()
448 setlocale (LC_ALL
, "");
450 /* FIXME: check if this is still true.
451 Disable localisation of float values. */
452 setlocale (LC_NUMERIC
, "C");
454 string localedir
= LOCALEDIR
;
455 if (char const *env
= getenv ("LILYPOND_LOCALEDIR"))
458 bindtextdomain ("lilypond", localedir
.c_str ());
459 textdomain ("lilypond");
464 add_output_format (string format
)
466 if (output_format_global
!= "")
467 output_format_global
+= ",";
468 output_format_global
+= format
;
472 parse_argv (int argc
, char **argv
)
474 bool show_help
= false;
475 option_parser
= new Getopt_long (argc
, argv
, options_static
);
476 while (Long_option_init
const *opt
= (*option_parser
) ())
478 switch (opt
->shortname_char_
)
481 if (string (opt
->longname_str0_
) == "pdf"
482 || string (opt
->longname_str0_
) == "png"
483 || string (opt
->longname_str0_
) == "ps")
484 add_output_format (opt
->longname_str0_
);
485 else if (string (opt
->longname_str0_
) == "relocate")
486 relocate_binary
= true;
491 string
arg (option_parser
->optional_argument_str0_
);
492 ssize eq
= arg
.find ('=');
499 key
= arg
.substr (0, eq
);
500 val
= arg
.substr (eq
+ 1, arg
.length () - 1);
503 init_scheme_variables_global
504 += "(cons \'" + key
+ " '" + val
+ ")\n";
514 string s
= option_parser
->optional_argument_str0_
;
515 File_name
file_name (s
);
516 output_name_global
= file_name
.to_string ();
520 jail_spec
= option_parser
->optional_argument_str0_
;
524 init_scheme_code_global
525 += option_parser
->optional_argument_str0_
+ string (" ");
534 vector
<string
> components
535 = string_split (option_parser
->optional_argument_str0_
, ',');
536 for (vsize i
= 0; i
< components
.size (); i
++)
537 add_output_format (components
[i
]);
542 dump_header_fieldnames_global
543 .push_back (option_parser
->optional_argument_str0_
);
546 global_path
.append (option_parser
->optional_argument_str0_
);
549 init_name_global
= option_parser
->optional_argument_str0_
;
555 be_verbose_global
= true;
558 programming_error (to_string ("unhandled short option: %c",
559 opt
->shortname_char_
));
565 if (output_format_global
== "")
566 output_format_global
= "pdf";
571 if (be_verbose_global
)
580 char const *yield
= getenv ("LILYPOND_GC_YIELD");
581 bool overwrite
= true;
588 sane_putenv ("GUILE_MIN_YIELD_1", yield
, overwrite
);
589 sane_putenv ("GUILE_MIN_YIELD_2", yield
, overwrite
);
590 sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield
, overwrite
);
593 sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
594 "10485760", overwrite
);
595 sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
596 "104857600", overwrite
);
599 vector
<string
> start_environment_global
;
602 main (int argc
, char **argv
, char **envp
)
606 for (char **p
= envp
; *p
; p
++)
607 start_environment_global
.push_back(*p
);
609 if (getenv ("LILYPOND_VERBOSE"))
610 be_verbose_global
= true;
612 setup_localisation ();
613 parse_argv (argc
, argv
);
614 if (isatty (STDIN_FILENO
))
617 setup_paths (argv
[0]);
624 scm_boot_guile (argc
, argv
, main_with_guile
, 0);
628 error (_f ("exception caught: %s", e
.what ()));
631 scm_boot_guile (argc
, argv
, main_with_guile
, 0);
634 /* Only reachable if GUILE exits. That is an error. */