]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
Imported Upstream version 2.14.2
[lilypond.git] / lily / main.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "main.hh"
21
22 #include <cassert>
23 #include <clocale>
24 #include <cstring>
25 #include <cerrno>
26 #include <cstdio>
27 using namespace std;
28
29 #include <unistd.h>
30 #include <sys/types.h>
31 #include "config.hh"
32
33 #if HAVE_GRP_H
34 #include <grp.h>
35 #endif
36 #if HAVE_PWD_H
37 #include <pwd.h>
38 #endif
39 #if HAVE_GETTEXT
40 #include <libintl.h>
41 #endif
42
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"
50 #include "misc.hh"
51 #include "output-def.hh"
52 #include "program-option.hh"
53 #include "relocate.hh"
54 #include "string-convert.hh"
55 #include "version.hh"
56 #include "warn.hh"
57
58 /*
59  * Global options that can be overridden through command line.
60  */
61
62 /* Names of header fields to be dumped to a separate file. */
63 vector<string> dump_header_fieldnames_global;
64
65 /* Name of initialisation file. */
66 string init_name_global;
67
68
69 /* Output formats to generate.  */
70 string output_format_global = "";
71
72 /* Current output name. */
73 string output_name_global;
74
75 /* Run in safe mode? */
76 bool be_safe_global = false;
77
78 /* Provide URI links to the original file */
79 bool point_and_click_global = true;
80
81 /* Verbose progress indication? */
82 bool be_verbose_global = false;
83
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;
88
89 bool relocate_binary = true;
90
91
92 /*
93  * Miscellaneous global stuff.
94  */
95 File_path global_path;
96
97 /*
98  * File globals.
99  */
100
101 static char const *AUTHORS
102 = "  Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
103   "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
104
105 static char const *PROGRAM_NAME = "lilypond";
106 static char const *PROGRAM_URL = "http://lilypond.org";
107
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"
112       "information.\n");
113
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"
119       "\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"
124       "\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");
129
130 /* Where the init files live.  Typically:
131    LILYPOND_DATADIR = /usr/share/lilypond
132 */
133 string lilypond_datadir;
134
135 /* The jail specification: USER, GROUP, JAIL, DIR. */
136 string jail_spec;
137
138 /*  The option parser */
139 static Getopt_long *option_parser = 0;
140
141 /* Internationalisation kludge in two steps:
142  * use _i () to get entry in POT file
143  * call gettext () explicitly for actual "translation"  */
144
145 static Long_option_init options_static[]
146 = {
147   {_i ("SYM[=VAL]"), "define-default", 'd',
148    _i ("set Scheme option SYM to VAL (default: #t).\n"
149        "Use -dhelp for help.")},
150
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")},
163 #if HAVE_CHROOT
164   {_i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
165                                                 "and cd into DIR")},
166 #endif
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")},
172   {0, 0, 0, 0}
173 };
174
175 char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
176
177
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))
185
186 #include <fpu_control.h>
187 static void
188 configure_fpu ()
189 {
190   fpu_control_t fpu_control = 0x027f;
191   _FPU_SETCW (fpu_control);
192 }
193
194 #else
195
196 static void
197 configure_fpu ()
198 {
199 }
200
201 #endif /* defined(__x86__) || defined(__i386__) */
202
203
204 static void
205 env_var_info (FILE *out, char const *key)
206 {
207   if (char const *value = getenv (key))
208     fprintf (out, "%s=\"%s\"\n", key, value);
209 }
210
211 static void
212 dir_info (FILE *out)
213 {
214   fputs ("\n", out);
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);
219
220   fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
221
222   if (relocate_binary)
223     {
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");
232     }
233 }
234
235 static void
236 copyright ()
237 {
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",
240                      AUTHORS).c_str ()));
241   printf ("\n");
242 }
243
244 static void
245 identify (FILE *out)
246 {
247   fputs (gnu_lilypond_version_string ().c_str (), out);
248   fputs ("\n", out);
249 }
250
251 static void
252 notice ()
253 {
254   identify (stdout);
255   printf ("\n");
256   copyright ();
257   printf ("\n");
258   puts (_f (NOTICE, PROGRAM_NAME).c_str ());
259 }
260
261 LY_DEFINE (ly_usage, "ly:usage",
262            0, 0, 0, (),
263            "Print usage message.")
264 {
265   /* No version number or newline here.  It confuses help2man.  */
266   printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ()));
267   printf ("\n\n");
268   printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
269   printf ("\n\n");
270   printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
271   printf ("\n");
272   printf ("%s", (_f ("For more information, see %s", PROGRAM_URL).c_str ()));
273   printf ("\n\n");
274   printf ("%s", (_ ("Options:").c_str ()));
275   printf ("\n");
276   printf ("%s", Long_option_init::table_string (options_static).c_str ());
277   printf ("\n");
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"
284                      ).c_str ()));
285   printf ("\n");
286   printf ("\n");
287   return SCM_UNSPECIFIED;
288 }
289
290 static void
291 warranty ()
292 {
293   identify (stdout);
294   printf ("\n");
295   copyright ();
296   printf ("\n");
297   printf ("%s", (_ (WARRANTY).c_str ()));
298 }
299
300 static void
301 prepend_load_path (string dir)
302 {
303   string s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
304   scm_c_eval_string (s.c_str ());
305 }
306
307 void init_global_tweak_registry ();
308 void init_fontconfig ();
309
310 #if HAVE_CHROOT
311 static void
312 do_chroot_jail ()
313 {
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
318      actual actions.  */
319
320   enum Jail
321     {
322       USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
323     };
324
325   vector<string> components = string_split (jail_spec, ',');
326   if (components.size () != JAIL_MAX)
327     {
328       error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
329                  (unsigned) components.size ()));
330       exit (2);
331     }
332
333   /* Hmm.  */
334   errno = 0;
335
336   int uid;
337   if (passwd * passwd = getpwnam (components[USER_NAME].c_str ()))
338     uid = passwd->pw_uid;
339   else
340     {
341       if (errno == 0)
342         error (_f ("no such user: %s", components[USER_NAME]));
343       else
344         error (_f ("cannot get user id from user name: %s: %s",
345                    components[USER_NAME],
346                    strerror (errno)));
347       exit (3);
348     }
349
350   /* Hmm.  */
351   errno = 0;
352
353   int gid;
354   if (group * group = getgrnam (components[GROUP_NAME].c_str ()))
355     gid = group->gr_gid;
356   else
357     {
358       if (errno == 0)
359         error (_f ("no such group: %s", components[GROUP_NAME]));
360       else
361         error (_f ("cannot get group id from group name: %s: %s",
362                    components[GROUP_NAME],
363                    strerror (errno)));
364       exit (3);
365     }
366
367   if (chroot (components[JAIL].c_str ()))
368     {
369       error (_f ("cannot chroot to: %s: %s", components[JAIL],
370                  strerror (errno)));
371       exit (3);
372     }
373
374   if (setgid (gid))
375     {
376       error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
377       exit (3);
378     }
379
380   if (setuid (uid))
381     {
382       error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
383       exit (3);
384     }
385
386   if (chdir (components[DIR].c_str ()))
387     {
388       error (_f ("cannot change working directory to: %s: %s", components[DIR],
389                  strerror (errno)));
390       exit (3);
391     }
392 }
393 #endif
394
395 static void
396 main_with_guile (void *, int, char **)
397 {
398   /* Engravers use lily.scm contents, need to make Guile find it.
399      Prepend onto GUILE %load-path, very ugh. */
400
401   prepend_load_path (lilypond_datadir);
402   prepend_load_path (lilypond_datadir + "/scm");
403
404   if (be_verbose_global)
405     dir_info (stderr);
406
407   init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
408   init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
409
410   ly_c_init_guile ();
411   call_constructors ();
412   init_fontconfig ();
413
414   init_freetype ();
415   ly_reset_all_fonts ();
416
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.  */
420
421   SCM files = SCM_EOL;
422   SCM *tail = &files;
423   while (char const *arg = option_parser->get_next_arg ())
424     {
425       *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
426       tail = SCM_CDRLOC (*tail);
427     }
428
429   delete option_parser;
430   option_parser = 0;
431
432 #if HAVE_CHROOT
433   if (!jail_spec.empty ())
434     do_chroot_jail ();
435 #endif
436
437   SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
438   (void) result;
439
440   /* Unreachable.  */
441   exit (0);
442 }
443
444 static void
445 setup_localisation ()
446 {
447 #if HAVE_GETTEXT
448   /* Enable locales */
449   setlocale (LC_ALL, "");
450
451   /* FIXME: check if this is still true.
452      Disable localisation of float values. */
453   setlocale (LC_NUMERIC, "C");
454
455   string localedir = LOCALEDIR;
456   if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
457     localedir = env;
458
459   bindtextdomain ("lilypond", localedir.c_str ());
460   textdomain ("lilypond");
461 #endif
462 }
463
464 static void
465 add_output_format (string format)
466 {
467   if (output_format_global != "")
468     output_format_global += ",";
469   output_format_global += format;
470 }
471
472 static void
473 parse_argv (int argc, char **argv)
474 {
475   bool show_help = false;
476   option_parser = new Getopt_long (argc, argv, options_static);
477   while (Long_option_init const *opt = (*option_parser) ())
478     {
479       switch (opt->shortname_char_)
480         {
481         case 0:
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;
488           break;
489
490         case 'd':
491           {
492             string arg (option_parser->optional_argument_str0_);
493             ssize eq = arg.find ('=');
494
495             string key = arg;
496             string val = "#t";
497
498             if (eq != NPOS)
499               {
500                 key = arg.substr (0, eq);
501                 val = arg.substr (eq + 1, arg.length () - 1);
502               }
503
504             init_scheme_variables_global
505               += "(cons \'" + key + " '" + val + ")\n";
506           }
507           break;
508
509         case 'v':
510           notice ();
511           exit (0);
512           break;
513         case 'o':
514           {
515             string s = option_parser->optional_argument_str0_;
516             File_name file_name (s);
517             output_name_global = file_name.to_string ();
518           }
519           break;
520         case 'j':
521           jail_spec = option_parser->optional_argument_str0_;
522           break;
523
524         case 'e':
525           init_scheme_code_global
526             += option_parser->optional_argument_str0_ + string (" ");
527           break;
528         case 'w':
529           warranty ();
530           exit (0);
531           break;
532
533         case 'f':
534           {
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]);
539           }
540           break;
541
542         case 'H':
543           dump_header_fieldnames_global
544             .push_back (option_parser->optional_argument_str0_);
545           break;
546         case 'I':
547           global_path.append (option_parser->optional_argument_str0_);
548           break;
549         case 'i':
550           init_name_global = option_parser->optional_argument_str0_;
551           break;
552         case 'h':
553           show_help = true;
554           break;
555         case 'V':
556           be_verbose_global = true;
557           break;
558         default:
559           programming_error (to_string ("unhandled short option: %c",
560                                         opt->shortname_char_));
561           assert (false);
562           break;
563         }
564     }
565
566   if (output_format_global == "")
567     output_format_global = "pdf";
568
569   if (show_help)
570     {
571       ly_usage ();
572       if (be_verbose_global)
573         dir_info (stdout);
574       exit (0);
575     }
576 }
577
578 void
579 setup_guile_env ()
580 {
581   char const *yield = getenv ("LILYPOND_GC_YIELD");
582   bool overwrite = true;
583   if (!yield)
584     {
585       yield = "65";
586       overwrite = false;
587     }
588
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);
592
593
594   sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
595                "10485760", overwrite);
596   sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
597                "104857600", overwrite);
598 }
599
600 vector<string> start_environment_global;
601
602 int
603 main (int argc, char **argv, char **envp)
604 {
605   configure_fpu();
606
607   for (char **p = envp; *p; p++)
608     start_environment_global.push_back(*p);
609
610   if (getenv ("LILYPOND_VERBOSE"))
611     be_verbose_global = true;
612
613   setup_localisation ();
614   parse_argv (argc, argv);
615   if (isatty (STDIN_FILENO))
616     identify (stderr);
617
618   setup_paths (argv[0]);
619   setup_guile_env ();
620
621 #if 0
622   /* Debugging aid.  */
623   try
624     {
625       scm_boot_guile (argc, argv, main_with_guile, 0);
626     }
627   catch (exception e)
628     {
629       error (_f ("exception caught: %s", e.what ()));
630     };
631 #else
632   scm_boot_guile (argc, argv, main_with_guile, 0);
633 #endif
634
635   /* Only reachable if GUILE exits.  That is an error.  */
636   return 1;
637 }