]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
* lily/my-lily-parser.cc: remove paper_description function
[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    This is where -e arguments are appended to.
73 */
74 String init_scheme_code_string = "(begin #t ";
75
76
77
78 /*
79  * Miscellaneous global stuff.
80  */
81
82 int exit_status_global;
83 File_path global_path;
84
85
86 /*
87  * File globals.
88  */
89
90 static char const *AUTHORS =
91 "  Han-Wen Nienhuys <hanwen@cs.uu.nl>\n"
92 "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
93
94 static char const *PROGRAM_NAME = "lilypond-bin";
95 static char const *PROGRAM_URL = "http://lilypond.org";
96
97 static char const *NOTICE =
98 _i ("This program is free software.  It is covered by the GNU General Public\n"
99     "License and you are welcome to change it and/or distribute copies of it\n"
100     "under certain conditions.  Invoke as `lilypond-bin --warranty' for more\n"
101     "information.\n");
102   
103 static char const *WARRANTY =
104 _i ("    This program is free software; you can redistribute it and/or\n"
105     "modify it under the terms of the GNU General Public License version 2\n"
106     "as published by the Free Software Foundation.\n"
107     "\n"
108     "    This program is distributed in the hope that it will be useful,\n"
109     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
110     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
111     "General Public License for more details.\n"
112     "\n"
113     "    You should have received a copy (refer to the file COPYING) of the\n"
114     "GNU General Public License along with this program; if not, write to\n"
115     "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
116     "Boston, MA 02111-1307, USA.\n");
117
118
119 /* Where the init files live.  Typically:
120    LILYPOND_DATADIR = /usr/share/lilypond
121    LOCAL_LILYPOND_DATADIR = /usr/share/lilypond/<VERSION> */
122 char const *prefix_directory[] = {LILYPOND_DATADIR, LOCAL_LILYPOND_DATADIR, 0};
123
124 /*  The option parser */
125 static Getopt_long *option_parser = 0;
126
127 /* Internationalisation kludge in two steps:
128    * use _i () to get entry in POT file
129    * call gettext () explicitely for actual "translation"  */
130
131 static Long_option_init options_static[] =
132   {
133     {_i ("EXPR"), "evaluate", 'e',
134      _i ("set options, use -e '(ly-option-usage)' for help")},
135     /* Bug in option parser: --output=foe is taken as an abbreviation
136        for --output-format.  */
137     {_i ("EXT"), "format", 'f', _i ("use output format EXT")},
138     {0, "help", 'h',  _i ("print this help")},
139     {_i ("FIELD"), "header", 'H',  _i ("write header field to BASENAME.FIELD")},
140     {_i ("DIR"), "include", 'I',  _i ("add DIR to search path")},
141     {_i ("FILE"), "init", 'i',  _i ("use FILE as init file")},
142     {0, "dependencies", 'M',  _i ("write Makefile dependencies")},
143     {0, "no-paper", 'm',  _i ("produce MIDI output only")},
144     {_i ("FILE"), "output", 'o',  _i ("write output to FILE")},
145     {_i ("DIR"), "dep-prefix", 'P',  _i ("prepend DIR to dependencies")},
146     {0, "safe-mode", 's',  _i ("run in safe mode")},
147     {0, "version", 'v',  _i ("print version number")},
148     {0, "verbose", 'V', _i ("be verbose")},
149     {0, "warranty", 'w',  _i ("show warranty and copyright")},
150     {0,0,0,0}
151   };
152
153 static void
154 dir_info (FILE *out)
155 {
156   fputs ("\n", out);
157   fprintf (out, "lilypond_datadir: `%s'\n", LILYPOND_DATADIR);
158   fprintf (out, "local_lilypond_datadir: `%s'\n", LOCAL_LILYPOND_DATADIR);
159   fprintf (out, "localedir: `%s'\n", LOCALEDIR);
160
161   char *lilypond_prefix = getenv ("LILYPONDPREFIX");
162   fprintf (out, "LILYPONDPREFIX: `%s'\n",
163            (lilypond_prefix ? lilypond_prefix : ""));
164 }
165
166 static void
167 copyright ()
168 {
169   printf (_f ("Copyright (c) %s by\n%s  and others.",
170               "1996--2004",
171               AUTHORS).to_str0 ());
172   printf ("\n");
173 }
174
175 static void
176 identify (FILE *out)
177 {
178   fputs (gnu_lilypond_version_string ().to_str0 (), out);
179 }
180  
181 static void
182 notice ()
183 {
184   identify (stdout);
185   printf ("\n");
186   printf (_f (NOTICE, PROGRAM_NAME).to_str0 ());
187   printf ("\n");
188   copyright ();
189 }
190
191 static void
192 usage ()
193 {
194   /* No version number or newline here.  It confuses help2man.  */
195   printf (_f ("Usage: %s [OPTIONS]... FILE...", PROGRAM_NAME).to_str0 ());
196   printf ("\n\n");
197   printf (_ ("Typeset music and/or produce MIDI from FILE.").to_str0 ());
198   printf ("\n\n");
199   printf (_ ("LilyPond produces beautiful music notation.").to_str0 ());
200   printf ("\n");
201   printf (_f ("For more information, see %s", PROGRAM_URL).to_str0 ());
202   printf ("\n\n");
203   printf (_ ("Options:").to_str0 ());
204   printf ("\n");
205   printf (Long_option_init::table_string (options_static).to_str0 ());
206   printf ("\n");
207   printf (_f ("Report bugs to %s.", "bug-lilypond@gnu.org").to_str0 ());
208   printf ("\n");
209   printf ("\n");
210 }
211
212 static void
213 warranty ()
214 {
215   identify (stdout);
216   printf ("\n");
217   copyright ();
218   printf ("\n");
219   printf (_ (WARRANTY).to_str0 ());
220 }
221
222 static void
223 setup_paths ()
224 {
225   if (char const *lilypond_prefix = getenv ("LILYPONDPREFIX"))
226     prefix_directory[1] = lilypond_prefix;
227
228   global_path.add ("");
229
230   /* Adding mf/out make lilypond unchanged source directory, when setting
231      LILYPONDPREFIX to lilypond-x.y.z */
232   char *suffixes[] = {"ly", "afm", "mf/out", "scm", "tfm", "ps", 0};
233
234   for (unsigned i = 0; prefix_directory[i]; i++)
235     for (char **s = suffixes; *s; s++)
236       {
237         String p = prefix_directory[i] + to_string ('/') + String (*s);
238         global_path.prepend (p);
239         
240 #if !KPATHSEA
241         /* Urg: GNU make's $ (word) index starts at 1 */
242         int i  = 1;
243         while (global_path.try_add (p + to_string (".") + to_string (i)))
244           i++;
245 #endif
246       }
247 }
248   
249 static void
250 prepend_load_path (String dir)
251 {
252   String s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
253   scm_c_eval_string (s.to_str0 ());
254 }
255
256 static void
257 main_with_guile (void *, int, char **)
258 {
259   /* Engravers use lily.scm contents, need to make Guile find it.
260      Prepend onto GUILE %load-path, very ugh. */
261   for (unsigned i = 0; prefix_directory[i]; i++)
262     {
263       prepend_load_path (prefix_directory[i]);
264       /* Junk this.  We should make real modules iso. just loading files. */
265       prepend_load_path (String (prefix_directory[i]) + "/scm");
266     }
267
268
269   if (verbose_global_b)
270     dir_info (stderr);
271
272   ly_c_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       ly_parse_file (scm_makfrom0str (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 }