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