]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
* lily/include/lily-guile.hh: many new ly_ functions. Thanks to
[lilypond.git] / lily / main.cc
1 /*
2   main.cc -- implement main () entrypoint.
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <assert.h>
12 #include <locale.h>
13 #include <string.h>
14
15 #include "config.h"
16
17 #if HAVE_GETTEXT
18 #include <libintl.h>
19 #endif
20
21 #include "lily-guile.hh"
22 #include "lily-version.hh"
23 #include "all-font-metrics.hh"
24 #include "getopt-long.hh"
25 #include "misc.hh"
26 #include "string.hh"
27 #include "main.hh"
28 #include "file-path.hh"
29 #include "input-file-results.hh"
30 #include "warn.hh"
31 #include "lily-guile.hh"
32 #include "paper-def.hh"
33 #include "midi-def.hh"
34 #include "global-ctor.hh"
35 #include "kpath.hh"
36
37 Array<String> failed_files;
38
39 /*
40  * Global options that can be overridden through command line.
41  */
42
43 /* Write dependencies file? */
44 bool dependency_global_b = false;
45
46 /* Prepend to dependencies */
47 String dependency_prefix_global;
48
49 /* Names of header fields to be dumped to a separate file. */
50 Array<String> dump_header_fieldnames_global;
51
52 /* Name of initialisation file. */
53 String init_name_global;
54
55 /* Do not calculate and write paper output? */
56 bool no_paper_global_b = false;
57
58 /* Selected output format.
59    One of tex, ps, scm, as. */
60 String output_format_global = "tex";
61
62 /* Current output name. */
63 String output_name_global;
64
65 /* Run in safe mode? */
66 bool safe_global_b = false;
67
68 /* Verbose progress indication? */
69 bool verbose_global_b = false;
70
71 /* Scheme code to execute before parsing, after .scm init */
72 String init_scheme_code_string = "(begin #t ";
73
74
75 /*
76  * Miscellaneous global stuff.
77  */
78
79 int exit_status_global;
80 File_path global_path;
81
82 /* Number of current score output block.  If there's more than one
83    score block, this counter will be added to the output filename. */
84 int score_count_global;
85
86
87 /*
88  * File globals.
89  */
90
91 static char const *AUTHORS =
92 "  Han-Wen Nienhuys <hanwen@cs.uu.nl>\n"
93 "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
94
95 static char const *PROGRAM_NAME = "lilypond-bin";
96 static char const *PROGRAM_URL = "http://lilypond.org";
97
98 static char const *NOTICE =
99 _i ("This program is free software.  It is covered by the GNU General Public\n"
100     "License and you are welcome to change it and/or distribute copies of it\n"
101     "under certain conditions.  Invoke as `lilypond-bin --warranty' for more\n"
102     "information.\n");
103   
104 static char const *WARRANTY =
105 _i ("    This program is free software; you can redistribute it and/or\n"
106     "modify it under the terms of the GNU General Public License version 2\n"
107     "as published by the Free Software Foundation.\n"
108     "\n"
109     "    This program is distributed in the hope that it will be useful,\n"
110     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
111     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
112     "General Public License for more details.\n"
113     "\n"
114     "    You should have received a copy (refer to the file COPYING) of the\n"
115     "GNU General Public License along with this program; if not, write to\n"
116     "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
117     "Boston, MA 02111-1307, USA.\n");
118
119
120 /* Where the init files live.  Typically:
121    LILYPOND_DATADIR = /usr/share/lilypond
122    LOCAL_LILYPOND_DATADIR = /usr/share/lilypond/<VERSION> */
123 char const *prefix_directory[] = {LILYPOND_DATADIR, LOCAL_LILYPOND_DATADIR, 0};
124
125 /*  The option parser */
126 static Getopt_long *option_parser = 0;
127
128 /* Internationalisation kludge in two steps:
129    * use _i () to get entry in POT file
130    * call gettext () explicitely for actual "translation"  */
131
132 static Long_option_init options_static[] =
133   {
134     {_i ("EXPR"), "evaluate", 'e',
135      _i ("set options, use -e '(ly-option-usage)' for help")},
136     /* Bug in option parser: --output=foe is taken as an abbreviation
137        for --output-format.  */
138     {_i ("EXT"), "format", 'f', _i ("use output format EXT")},
139     {0, "help", 'h',  _i ("print this help")},
140     {_i ("FIELD"), "header", 'H',  _i ("write header field to BASENAME.FIELD")},
141     {_i ("DIR"), "include", 'I',  _i ("add DIR to search path")},
142     {_i ("FILE"), "init", 'i',  _i ("use FILE as init file")},
143     {0, "dependencies", 'M',  _i ("write Makefile dependencies")},
144     {0, "no-paper", 'm',  _i ("produce MIDI output only")},
145     {_i ("FILE"), "output", 'o',  _i ("write output to FILE")},
146     {_i ("DIR"), "dep-prefix", 'P',  _i ("prepend DIR to dependencies")},
147     {0, "safe-mode", 's',  _i ("run in safe mode")},
148     {0, "version", 'v',  _i ("print version number")},
149     {0, "verbose", 'V', _i ("be verbose")},
150     {0, "warranty", 'w',  _i ("show warranty and copyright")},
151     {0,0,0,0}
152   };
153
154 static void
155 dir_info (FILE *out)
156 {
157   fputs ("\n", out);
158   fprintf (out, "lilypond_datadir: `%s'\n", LILYPOND_DATADIR);
159   fprintf (out, "local_lilypond_datadir: `%s'\n", LOCAL_LILYPOND_DATADIR);
160   fprintf (out, "localedir: `%s'\n", LOCALEDIR);
161
162   char *lilypond_prefix = getenv ("LILYPONDPREFIX");
163   fprintf (out, "LILYPONDPREFIX: `%s'\n",
164            (lilypond_prefix ? lilypond_prefix : ""));
165 }
166
167 static void
168 copyright ()
169 {
170   printf (_f ("Copyright (c) %s by\n%s  and others.",
171               "1996--2004",
172               AUTHORS).to_str0 ());
173   printf ("\n");
174 }
175
176 static void
177 identify (FILE *out)
178 {
179   fputs (gnu_lilypond_version_string ().to_str0 (), out);
180 }
181  
182 static void
183 notice ()
184 {
185   identify (stdout);
186   printf ("\n");
187   printf (_f (NOTICE, PROGRAM_NAME).to_str0 ());
188   printf ("\n");
189   copyright ();
190 }
191
192 static void
193 usage ()
194 {
195   /* No version number or newline here.  It confuses help2man.  */
196   printf (_f ("Usage: %s [OPTIONS]... FILE...", PROGRAM_NAME).to_str0 ());
197   printf ("\n\n");
198   printf (_ ("Typeset music and/or produce MIDI from FILE.").to_str0 ());
199   printf ("\n\n");
200   printf (_ ("LilyPond produces beautiful music notation.").to_str0 ());
201   printf ("\n");
202   printf (_f ("For more information, see %s", PROGRAM_URL).to_str0 ());
203   printf ("\n\n");
204   printf (_ ("Options:").to_str0 ());
205   printf ("\n");
206   printf (Long_option_init::table_string (options_static).to_str0 ());
207   printf ("\n");
208   printf (_f ("Report bugs to %s.", "bug-lilypond@gnu.org").to_str0 ());
209   printf ("\n");
210   printf ("\n");
211 }
212
213 static void
214 warranty ()
215 {
216   identify (stdout);
217   printf ("\n");
218   copyright ();
219   printf ("\n");
220   printf (_ (WARRANTY).to_str0 ());
221 }
222
223 static void
224 setup_paths ()
225 {
226   if (char const *lilypond_prefix = getenv ("LILYPONDPREFIX"))
227     prefix_directory[1] = lilypond_prefix;
228
229   global_path.add ("");
230
231   /* Adding mf/out make lilypond unchanged source directory, when setting
232      LILYPONDPREFIX to lilypond-x.y.z */
233   char *suffixes[] = {"ly", "afm", "mf/out", "scm", "tfm", "ps", 0};
234
235   for (unsigned i = 0; prefix_directory[i]; i++)
236     for (char **s = suffixes; *s; s++)
237       {
238         String p = prefix_directory[i] + to_string ('/') + String (*s);
239         global_path.prepend (p);
240         
241 #if !KPATHSEA
242         /* Urg: GNU make's $ (word) index starts at 1 */
243         int i  = 1;
244         while (global_path.try_add (p + to_string (".") + to_string (i)))
245           i++;
246 #endif
247       }
248 }
249   
250 static void
251 prepend_load_path (String dir)
252 {
253   String s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
254   scm_c_eval_string (s.to_str0 ());
255 }
256
257 static void
258 main_with_guile (void *, int, char **)
259 {
260   /* Engravers use lily.scm contents, need to make Guile find it.
261      Prepend onto GUILE %load-path, very ugh. */
262   for (unsigned i = 0; prefix_directory[i]; i++)
263     {
264       prepend_load_path (prefix_directory[i]);
265       /* Junk this.  We should make real modules iso. just loading files. */
266       prepend_load_path (String (prefix_directory[i]) + "/scm");
267     }
268
269   if (verbose_global_b)
270     dir_info (stderr);
271
272   ly_init_guile ();
273   call_constructors ();
274   progress_indication ("\n");
275
276   all_fonts_global = new All_font_metrics (global_path.to_string ());
277
278   init_scheme_code_string += ")";
279   scm_c_eval_string ((char*) init_scheme_code_string.to_str0 ());
280
281   /* We accept multiple independent music files on the command line to
282      reduce compile time when processing lots of small files.
283      Starting the GUILE engine is very time consuming.  */
284   bool first = true;
285   while (char const *arg = option_parser->get_next_arg ())
286     {
287 #if 0
288       /* Code to debug memory leaks.  Cannot call from within .ly
289          since then we get the protects from the parser state too.  */
290       scm_gc ();
291       scm_call_0 (ly_scheme_function ("dump-gc-protects"));
292 #endif
293       do_one_file (arg);
294       first = false;
295     }
296   delete option_parser;
297   option_parser = 0;
298
299   /* No FILE arguments is now a usage error to help newbies.  If you
300      want a filter, you're not a newbie and should know to use file
301      argument `-'.  */
302   if (first)
303     {
304       usage ();
305       exit (2);
306     }
307
308   if (exit_status_global)
309     {
310       printf ("Failed files: ");
311       for (int i = 0; i < failed_files.size (); i++)
312         printf ("%s ", failed_files[i].to_str0 ());
313       printf ("\n");
314     }
315   exit (exit_status_global);
316 }
317
318 static void
319 setup_localisation ()
320 {
321 #if HAVE_GETTEXT
322   /* Enable locales */
323   setlocale (LC_ALL, "");
324   
325   /* FIXME: check if this is still true.
326     Disable localisation of float values.  This breaks TeX output.  */
327   setlocale (LC_NUMERIC, "C");
328   
329   String name (PACKAGE);
330   name.to_lower ();
331   bindtextdomain (name.to_str0 (), LOCALEDIR);
332   textdomain (name.to_str0 ());
333 #endif
334 }
335
336 static void
337 parse_argv (int argc, char **argv)
338 {
339   bool help_b = false;
340   option_parser = new Getopt_long (argc, argv, options_static);
341   while (Long_option_init const * opt = (*option_parser) ())
342     {
343       switch (opt->shortname_char_)
344         {
345         case 'v':
346           notice ();
347           exit (0);
348           break;
349         case 'o':
350           {
351             String s = option_parser->optional_argument_str0_;
352             Path p = split_path (s);
353             if (s != "-" && p.ext.is_empty ())
354               p.ext = output_format_global;
355             output_name_global = p.to_string ();
356           }
357           break;
358         case 'e':
359           init_scheme_code_string += option_parser->optional_argument_str0_;
360           break;
361         case 'w':
362           warranty ();
363           exit (0);
364           break;
365         case 'f':
366           if (option_parser->optional_argument_str0_ == "help")
367             {
368               printf (_ ("This option is for developers only.").to_str0 ());
369               printf (_ ("Read the sources for more information.").to_str0 ());
370               exit (0);
371             }
372           output_format_global = option_parser->optional_argument_str0_;
373           break;
374         case 'P':
375             dependency_prefix_global = option_parser->optional_argument_str0_;
376           break;
377         case 'H':
378           dump_header_fieldnames_global
379             .push (option_parser->optional_argument_str0_);
380           break;
381         case 'I':
382           global_path.push (option_parser->optional_argument_str0_);
383           break;
384         case 'i':
385           init_name_global = option_parser->optional_argument_str0_;
386           break;
387         case 'h':
388           help_b = true;
389           break;
390         case 'V':
391           verbose_global_b = true;
392           break;
393         case 's':
394           safe_global_b = true;
395           break;
396         case 'M':
397           dependency_global_b = true;
398           break; 
399         case 'm':
400           no_paper_global_b = true;
401           break;
402         default:
403           assert (false);
404           break;
405         }
406     }
407
408   if (help_b)
409     {
410       usage ();
411       if (verbose_global_b)
412         dir_info (stdout);
413       exit (0);
414     }
415 }
416
417 int
418 main (int argc, char **argv)
419 {
420   setup_localisation ();  
421   setup_paths ();
422   parse_argv (argc, argv);
423   initialize_kpathsea (argv[0]);
424
425   scm_boot_guile (argc, argv, main_with_guile, 0);
426
427   /* Unreachable */
428   return 0;
429 }