]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
Doc-fr: update for 2.16.1 (second part)
[lilypond.git] / lily / main.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2012 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 /* Output formats to generate.  */
69 string output_format_global = "";
70
71 /* Current output name. */
72 string output_name_global;
73
74 /* Run in safe mode? */
75 bool be_safe_global = false;
76
77 /* Scheme code to execute before parsing, after .scm init.
78    This is where -e arguments are appended to.  */
79 string init_scheme_code_global;
80 string init_scheme_variables_global;
81
82 bool relocate_binary = true;
83
84 /*
85  * Miscellaneous global stuff.
86  */
87 File_path global_path;
88
89 /*
90  * File globals.
91  */
92
93 static char const *AUTHORS
94   = "  Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
95     "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
96
97 static char const *PROGRAM_NAME = "lilypond";
98 static char const *PROGRAM_URL = "http://lilypond.org";
99
100 static char const *NOTICE
101   = _i ("This program is free software.  It is covered by the GNU General Public\n"
102         "License and you are welcome to change it and/or distribute copies of it\n"
103         "under certain conditions.  Invoke as `%s --warranty' for more\n"
104         "information.\n");
105
106 static char const *WARRANTY
107   = _i ("    This program is free software; you can redistribute it and/or\n"
108         "modify it under the terms of the GNU General Public License as \n"
109         "published by the Free Software Foundation, either version 3 of\n"
110         "the License, or (at your option) any later version.\n"
111         "\n"
112         "    This program is distributed in the hope that it will be useful,\n"
113         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
114         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
115         "General Public License for more details.\n"
116         "\n"
117         "    You should have received a copy of the\n"
118         "GNU General Public License along with this program; if not, write to\n"
119         "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
120         "Boston, MA 02111-1307, USA.\n");
121
122 /* Where the init files live.  Typically:
123    LILYPOND_DATADIR = /usr/share/lilypond
124 */
125 string lilypond_datadir;
126
127 /* The jail specification: USER, GROUP, JAIL, DIR. */
128 string jail_spec;
129
130 /*  The option parser */
131 static Getopt_long *option_parser = 0;
132
133 /* Internationalisation kludge in two steps:
134  * use _i () to get entry in POT file
135  * call gettext () explicitly for actual "translation"  */
136
137 static Long_option_init options_static[]
138 =
139 {
140   {
141     _i ("SYM[=VAL]"), "define-default", 'd',
142     _i ("set Scheme option SYM to VAL (default: #t).\n"
143     "Use -dhelp for help.")
144   },
145
146   {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
147   /* Bug in option parser: --output =foe is taken as an abbreviation
148      for --output-format.  */
149   {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,...  Also as separate options:")},
150   {0, "pdf", 0, _i ("generate PDF (default)")},
151   {0, "png", 0, _i ("generate PNG")},
152   {0, "ps", 0, _i ("generate PostScript")},
153   {0, "help", 'h', _i ("show this help and exit")},
154   {
155     _i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
156     "named BASENAME.FIELD")
157   },
158   {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
159   {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
160 #if HAVE_CHROOT
161   {
162     _i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
163     "and cd into DIR")
164   },
165 #endif
166   {
167     _i ("LOGLEVEL"), "loglevel", 'l', _i ("print log messages according to"
168     " LOGLEVEL.  Possible values are:\n"
169     "NONE, ERROR, WARNING, BASIC, PROGRESS, INFO (default) and DEBUG.")
170   },
171   {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
172   {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
173   {0, "silent", 's', _i ("no progress, only error messages (equivalent to loglevel=ERROR)")},
174   {0, "version", 'v', _i ("show version number and exit")},
175   {0, "verbose", 'V', _i ("be verbose (equivalent to loglevel=DEBUG)")},
176   {0, "warranty", 'w', _i ("show warranty and copyright")},
177   {0, 0, 0, 0}
178 };
179
180 char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
181
182 /* x86 defaults to using 80-bit extended precision arithmetic. This can cause
183    problems because the truncation from 80 bits to 64 bits can occur in
184    unpredictable places. To get around this, we tell the x87 FPU to use only
185    double precision. Note that this is not needed for x86_64 because that uses
186    the SSE unit by default instead of the x87 FPU. */
187 #if ((defined (__x86__) || defined (__i386__)) \
188   && defined (HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
189
190 #include <fpu_control.h>
191 static void
192 configure_fpu ()
193 {
194   fpu_control_t fpu_control = 0x027f;
195   _FPU_SETCW (fpu_control);
196 }
197
198 #else
199
200 static void
201 configure_fpu ()
202 {
203 }
204
205 #endif /* defined(__x86__) || defined(__i386__) */
206
207 static void
208 env_var_info (FILE *out, char const *key)
209 {
210   if (char const *value = getenv (key))
211     fprintf (out, "%s=\"%s\"\n", key, value);
212 }
213
214 static void
215 dir_info (FILE *out)
216 {
217   fputs ("\n", out);
218   fprintf (out, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR);
219   env_var_info (out, "LILYPONDPREFIX");
220   env_var_info (out, "LILYPOND_DATADIR");
221   fprintf (out, "LOCALEDIR=\"%s\"\n", LOCALEDIR);
222
223   fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
224
225   if (relocate_binary)
226     {
227       env_var_info (out, "FONTCONFIG_FILE");
228       env_var_info (out, "FONTCONFIG_PATH");
229       env_var_info (out, "GS_FONTPATH");
230       env_var_info (out, "GS_LIB");
231       env_var_info (out, "GUILE_LOAD_PATH");
232       env_var_info (out, "PANGO_RC_FILE");
233       env_var_info (out, "PANGO_PREFIX");
234       env_var_info (out, "PATH");
235     }
236 }
237
238 static void
239 copyright ()
240 {
241   /* Do not update the copyright years here, run `make grand-replace'  */
242   printf ("%s", (_f ("Copyright (c) %s by\n%s  and others.", "1996--2012",
243                      AUTHORS).c_str ()));
244   printf ("\n");
245 }
246
247 static void
248 identify (FILE *out)
249 {
250   fputs (gnu_lilypond_version_string ().c_str (), out);
251   fputs ("\n", out);
252 }
253
254 static void
255 notice ()
256 {
257   identify (stdout);
258   printf ("\n");
259   copyright ();
260   printf ("\n");
261   puts (_f (NOTICE, PROGRAM_NAME).c_str ());
262 }
263
264 LY_DEFINE (ly_usage, "ly:usage",
265            0, 0, 0, (),
266            "Print usage message.")
267 {
268   /* No version number or newline here.  It confuses help2man.  */
269   printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ()));
270   printf ("\n\n");
271   printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
272   printf ("\n\n");
273   printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
274   printf ("\n");
275   printf ("%s", (_f ("For more information, see %s", PROGRAM_URL).c_str ()));
276   printf ("\n\n");
277   printf ("%s", (_ ("Options:").c_str ()));
278   printf ("\n");
279   printf ("%s", Long_option_init::table_string (options_static).c_str ());
280   printf ("\n");
281   /* Translators, please translate this string as
282      "Report bugs in English via %s",
283      or if there is a LilyPond users list or forum in your language
284      "Report bugs in English via %s or in YOUR_LANG via URI"  */
285   printf ("%s", (_f ("Report bugs via %s",
286                      "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
287                     ).c_str ()));
288   printf ("\n");
289   printf ("\n");
290   return SCM_UNSPECIFIED;
291 }
292
293 static void
294 warranty ()
295 {
296   identify (stdout);
297   printf ("\n");
298   copyright ();
299   printf ("\n");
300   printf ("%s", (_ (WARRANTY).c_str ()));
301 }
302
303 static void
304 prepend_load_path (string dir)
305 {
306   string s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
307   scm_c_eval_string (s.c_str ());
308 }
309
310 void init_global_tweak_registry ();
311 void init_fontconfig ();
312
313 #if HAVE_CHROOT
314 static void
315 do_chroot_jail ()
316 {
317   /* Now we chroot, setuid/setgrp and chdir.  If something goes wrong,
318      we exit (this is a security-sensitive area).  First we split
319      jail_spec into its components, then we retrieve the user/group id
320      (necessarily *before* chroot'ing) and finally we perform the
321      actual actions.  */
322
323   enum Jail
324   {
325     USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
326   };
327
328   vector<string> components = string_split (jail_spec, ',');
329   if (components.size () != JAIL_MAX)
330     {
331       error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
332                  (unsigned) components.size ()));
333       exit (2);
334     }
335
336   /* Hmm.  */
337   errno = 0;
338
339   int uid;
340   if (passwd *passwd = getpwnam (components[USER_NAME].c_str ()))
341     uid = passwd->pw_uid;
342   else
343     {
344       if (errno == 0)
345         error (_f ("no such user: %s", components[USER_NAME]));
346       else
347         error (_f ("cannot get user id from user name: %s: %s",
348                    components[USER_NAME],
349                    strerror (errno)));
350       exit (3);
351     }
352
353   /* Hmm.  */
354   errno = 0;
355
356   int gid;
357   if (group *group = getgrnam (components[GROUP_NAME].c_str ()))
358     gid = group->gr_gid;
359   else
360     {
361       if (errno == 0)
362         error (_f ("no such group: %s", components[GROUP_NAME]));
363       else
364         error (_f ("cannot get group id from group name: %s: %s",
365                    components[GROUP_NAME],
366                    strerror (errno)));
367       exit (3);
368     }
369
370   if (chroot (components[JAIL].c_str ()))
371     {
372       error (_f ("cannot chroot to: %s: %s", components[JAIL],
373                  strerror (errno)));
374       exit (3);
375     }
376
377   if (setgid (gid))
378     {
379       error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
380       exit (3);
381     }
382
383   if (setuid (uid))
384     {
385       error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
386       exit (3);
387     }
388
389   if (chdir (components[DIR].c_str ()))
390     {
391       error (_f ("cannot change working directory to: %s: %s", components[DIR],
392                  strerror (errno)));
393       exit (3);
394     }
395 }
396 #endif
397
398 static void
399 main_with_guile (void *, int, char **)
400 {
401   /* Engravers use lily.scm contents, need to make Guile find it.
402      Prepend onto GUILE %load-path, very ugh. */
403
404   prepend_load_path (lilypond_datadir);
405   prepend_load_path (lilypond_datadir + "/scm");
406
407   if (is_loglevel (LOG_DEBUG))
408     dir_info (stderr);
409
410   init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
411   init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
412
413   ly_c_init_guile ();
414   call_constructors ();
415   init_fontconfig ();
416
417   init_freetype ();
418   ly_reset_all_fonts ();
419
420   /* We accept multiple independent music files on the command line to
421      reduce compile time when processing lots of small files.
422      Starting the GUILE engine is very time consuming.  */
423
424   SCM files = SCM_EOL;
425   SCM *tail = &files;
426   while (char const *arg = option_parser->get_next_arg ())
427     {
428       *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
429       tail = SCM_CDRLOC (*tail);
430     }
431
432   delete option_parser;
433   option_parser = 0;
434
435 #if HAVE_CHROOT
436   if (!jail_spec.empty ())
437     do_chroot_jail ();
438 #endif
439
440   SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
441   (void) result;
442
443   /* Unreachable.  */
444   exit (0);
445 }
446
447 static void
448 setup_localisation ()
449 {
450 #if HAVE_GETTEXT
451   /* Enable locales */
452   setlocale (LC_ALL, "");
453
454   /* FIXME: check if this is still true.
455      Disable localisation of float values. */
456   setlocale (LC_NUMERIC, "C");
457
458   string localedir = LOCALEDIR;
459   if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
460     localedir = env;
461
462   bindtextdomain ("lilypond", localedir.c_str ());
463   textdomain ("lilypond");
464 #endif
465 }
466
467 static void
468 add_output_format (string format)
469 {
470   if (output_format_global != "")
471     output_format_global += ",";
472   output_format_global += format;
473 }
474
475 static void
476 parse_argv (int argc, char **argv)
477 {
478   bool show_help = false;
479   option_parser = new Getopt_long (argc, argv, options_static);
480   while (Long_option_init const *opt = (*option_parser) ())
481     {
482       switch (opt->shortname_char_)
483         {
484         case 0:
485           if (string (opt->longname_str0_) == "pdf"
486               || string (opt->longname_str0_) == "png"
487               || string (opt->longname_str0_) == "ps")
488             add_output_format (opt->longname_str0_);
489           else if (string (opt->longname_str0_) == "relocate")
490             relocate_binary = true;
491           break;
492
493         case 'd':
494           {
495             string arg (option_parser->optional_argument_str0_);
496             ssize eq = arg.find ('=');
497
498             string key = arg;
499             string val = "#t";
500
501             if (eq != NPOS)
502               {
503                 key = arg.substr (0, eq);
504                 val = arg.substr (eq + 1, arg.length () - 1);
505               }
506
507             init_scheme_variables_global
508             += "(cons \'" + key + " '" + val + ")\n";
509           }
510           break;
511
512         case 'v':
513           notice ();
514           exit (0);
515           break;
516         case 'o':
517           {
518             string s = option_parser->optional_argument_str0_;
519             File_name file_name (s);
520             output_name_global = file_name.to_string ();
521           }
522           break;
523         case 'j':
524           jail_spec = option_parser->optional_argument_str0_;
525           break;
526
527         case 'e':
528           init_scheme_code_global
529           += option_parser->optional_argument_str0_ + string (" ");
530           break;
531         case 'w':
532           warranty ();
533           exit (0);
534           break;
535
536         case 'f':
537           {
538             vector<string> components
539               = string_split (option_parser->optional_argument_str0_, ',');
540             for (vsize i = 0; i < components.size (); i++)
541               add_output_format (components[i]);
542           }
543           break;
544
545         case 'H':
546           dump_header_fieldnames_global
547           .push_back (option_parser->optional_argument_str0_);
548           break;
549         case 'I':
550           global_path.append (option_parser->optional_argument_str0_);
551           break;
552         case 'i':
553           init_name_global = option_parser->optional_argument_str0_;
554           break;
555         case 'h':
556           show_help = true;
557           break;
558         case 'V':
559           set_loglevel (LOGLEVEL_DEBUG);
560           break;
561         case 's':
562           set_loglevel (LOGLEVEL_ERROR);
563           break;
564         case 'l':
565           set_loglevel (option_parser->optional_argument_str0_);
566           break;
567         default:
568           programming_error (to_string ("unhandled short option: %c",
569                                         opt->shortname_char_));
570           assert (false);
571           break;
572         }
573     }
574
575   if (output_format_global == "")
576     output_format_global = "pdf";
577
578   if (show_help)
579     {
580       ly_usage ();
581       if (is_loglevel (LOG_DEBUG))
582         dir_info (stdout);
583       exit (0);
584     }
585 }
586
587 void
588 setup_guile_env ()
589 {
590   char const *yield = getenv ("LILYPOND_GC_YIELD");
591   bool overwrite = true;
592   if (!yield)
593     {
594       yield = "65";
595       overwrite = false;
596     }
597
598   sane_putenv ("GUILE_MIN_YIELD_1", yield, overwrite);
599   sane_putenv ("GUILE_MIN_YIELD_2", yield, overwrite);
600   sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield, overwrite);
601
602   sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
603                "10485760", overwrite);
604   sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
605                "104857600", overwrite);
606 }
607
608 vector<string> start_environment_global;
609
610 int
611 main (int argc, char **argv, char **envp)
612 {
613   configure_fpu ();
614
615   for (char **p = envp; *p; p++)
616     start_environment_global.push_back (*p);
617
618   if (getenv ("LILYPOND_VERBOSE"))
619     set_loglevel (LOGLEVEL_DEBUG);
620   if (getenv ("LILYPOND_LOGLEVEL"))
621     set_loglevel (getenv ("LILYPOND_LOGLEVEL"));
622
623   setup_localisation ();
624   parse_argv (argc, argv);
625   if (isatty (STDIN_FILENO) && (is_loglevel (LOG_BASIC)))
626     identify (stderr);
627
628   setup_paths (argv[0]);
629   setup_guile_env ();
630
631 #if 0
632   /* Debugging aid.  */
633   try
634     {
635       scm_boot_guile (argc, argv, main_with_guile, 0);
636     }
637   catch (exception e)
638     {
639       error (_f ("exception caught: %s", e.what ()));
640     };
641 #else
642   scm_boot_guile (argc, argv, main_with_guile, 0);
643 #endif
644
645   /* Only reachable if GUILE exits.  That is an error.  */
646   return 1;
647 }