]> git.donarmstrong.com Git - lilypond.git/blob - lily/main.cc
patch::: 1.3.130.jcn3
[lilypond.git] / lily / main.cc
1 /*
2   main.cc -- implement main: entrypoints
3
4   source file of the GNU LilyPond music typesetter
5
6   (c)  1997--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include <stdlib.h>
10 #include <iostream.h>
11 #include <assert.h>
12 #include <locale.h>
13
14 #include "config.h"
15
16 #if HAVE_GETTEXT
17 #include <libintl.h>
18 #endif
19
20 #include "lily-guile.hh"
21 #include "lily-version.hh"
22 #include "all-font-metrics.hh"
23 #include "getopt-long.hh"
24 #include "misc.hh"
25 #include "string.hh"
26 #include "main.hh"
27 #include "file-path.hh"
28 #include "file-results.hh"
29 #include "debug.hh"
30 #include "lily-guile.hh"
31 #include "paper-def.hh"
32 #include "midi-def.hh"
33 #include "global-ctor.hh"
34 #include "kpath.hh"
35
36
37 /*
38   Global options that can be overridden through command line.
39 */
40
41 /* Write dependencies file? */
42 bool dependency_global_b = false;
43
44 /* Names of header fields to be dumped to a separate file. */
45 Array<String> dump_header_fieldnames_global;
46
47 /* Name of initialisation file. */
48 String init_name_global;
49
50 /* Do not calculate and write paper output? */
51 bool no_paper_global_b = false;
52
53 /* Do not write timestamps in output? */
54 bool no_timestamps_global_b = false;
55
56 /* Selected output format.
57    One of tex, ps, scm, as. */
58 String output_format_global = "tex";
59
60 /* Current output name. */
61 String output_name_global;
62
63 /* Run in safe mode? -- FIXME: should be re-analised */
64 bool safe_global_b = false;
65
66 /* Verbose progress indication? */
67 bool verbose_global_b = false;
68
69
70
71 /*
72   Misc. global stuff.
73  */
74
75
76 All_font_metrics *all_fonts_global_p;
77 int exit_status_global;
78 File_path global_path;
79
80 /* Number of current score output block.  If there's more than one
81    score block, this counter will be added to the output filename. */
82 int score_count_global;
83
84
85
86 /*
87   File globals.
88  */
89
90 /*  The option parser */
91 static Getopt_long *oparser_p_static = 0;
92
93 /*
94  Internationalisation kludge in two steps:
95    * use _i () to get entry in POT file
96    * call gettext () explicitely for actual "translation"
97
98  Note: these messages all start with lower case (ie, don't
99        follow regular localisation guidelines).
100  */
101 static Long_option_init options_static[] = {
102   {_i ("EXT"), "output-format", 'f',  _i ("use output format EXT (scm, ps, tex or as)")},
103   {0, "help", 'h',  _i ("this help")},
104   {_i ("FIELD"), "header", 'H',  _i ("write header field to BASENAME.FIELD")},
105   {_i ("DIR"), "include", 'I',  _i ("add DIR to search path")},
106   {_i ("FILE"), "init", 'i',  _i ("use FILE as init file")},
107   {0, "dependencies", 'M',  _i ("write Makefile dependencies for every input file")},
108   {0, "no-paper", 'm',  _i ("produce MIDI output only")},
109   {_i ("NAME"), "output", 'o',  _i ("write output to NAME")},
110   {0, "safe", 's',  _i ("inhibit file output naming and exporting")},
111   {0, "no-timestamps", 'T',  _i ("don't timestamp the output")},
112   {0, "version", 'v',  _i ("print version number")},
113   {0, "verbose", 'V', _i("verbose")},
114   {0, "warranty", 'w',  _i ("show warranty and copyright")},
115   {0,0,0, 0}
116 };
117
118 void
119 identify (ostream* os)
120 {
121   *os << gnu_lilypond_version_str ();
122 }
123
124 void
125 usage ()
126 {
127   
128   /*
129     No version number or newline here. It confuses help2man
130    */
131   cout << _f ("Usage: %s [OPTION]... [FILE]...", "lilypond");
132   cout << "\n\n";
133   cout << _ ("Typeset music and or play MIDI from FILE");
134   cout << "\n\n";
135   cout << 
136 _(
137 "LilyPond is a music typesetter.  It produces beautiful sheet music\n"
138 "using a high level description file as input.  LilyPond is part of \n"
139 "the GNU Project.\n"
140 );
141
142   cout << '\n';
143   cout << _ ("Options:");
144   cout << '\n';
145   cout << Long_option_init::table_str (options_static);
146   cout << '\n';
147   cout << _ ("This binary was compiled with the following options:") 
148     << " " <<
149 #ifdef NDEBUG
150     "NDEBUG "
151 #endif
152 #ifdef NPRINT
153     "NPRINT "
154 #endif
155 #ifdef STRING_UTILS_INLINED
156     "STRING_UTILS_INLINED "
157 #endif
158     "\n"
159     "datadir: `" DIR_DATADIR "'\n"
160     "localedir: `" DIR_LOCALEDIR "'\n"
161     "\n";
162
163
164   cout << endl;
165
166   cout << _f ("Report bugs to %s", "bug-gnu-music@gnu.org") << endl;
167 }
168
169 void
170 version ()
171 {
172   identify (&cout);
173   cout << '\n';
174   cout << _f (""
175   "This is free software.  It is covered by the GNU General Public License,\n"
176   "and you are welcome to change it and/or distribute copies of it under\n"
177   "certain conditions.  Invoke as `%s --warranty' for more information.\n",
178     "lilypond");
179   cout << endl;
180
181   cout << _f ("Copyright (c) %s by", "1996--2000");
182   cout << '\n';
183   cout << "  Han-Wen Nienhuys <hanwen@cs.uu.nl>\n";
184   cout << "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
185 }
186
187 void
188 notice ()
189 {
190   cout << '\n';
191   cout << _ ("GNU LilyPond -- The music typesetter");
192   cout << '\n';
193   cout << _f ("Copyright (c) %s by", "1996--2000");
194   cout << '\n';
195   cout << "  Han-Wen Nienhuys <hanwen@cs.uu.nl>\n";
196   cout << "  Jan Nieuwenhuizen <janneke@gnu.org>\n";
197   cout << '\n';
198   cout << _ (
199              "    This program is free software; you can redistribute it and/or\n"
200              "modify it under the terms of the GNU General Public License version 2\n"
201              "as published by the Free Software Foundation.\n"
202              "\n"
203              "    This program is distributed in the hope that it will be useful,\n"
204              "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
205              "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n"
206              "General Public License for more details.\n"
207              "\n"
208              "    You should have received a copy (refer to the file COPYING) of the\n"
209              "GNU General Public License along with this program; if not, write to\n"
210              "the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,\n"
211              "USA.\n");
212 }
213
214 void
215 setup_paths ()
216 {
217   // facilitate binary distributions
218   char const *env_lily = getenv ("LILYPONDPREFIX");
219   String prefix_directory;
220   if (env_lily)
221     prefix_directory = env_lily;
222
223 #if HAVE_GETTEXT
224   setlocale (LC_ALL, ""); /* enable locales */
225   setlocale (LC_NUMERIC, "C"); /* musn't have comma's in TeX output... */
226   String lily_locale_dir;
227   String name (PACKAGE);
228   name.to_lower ();
229
230   /*
231     urg; what *do* we want with $LILYPONDPREFIX, DIR_DATADIR and $prefix/share
232     handy for multiple source-dir runs, though...
233    */
234   if (!prefix_directory.empty_b())
235     {
236       lily_locale_dir = prefix_directory + "/share/locale";
237       bindtextdomain (name.ch_C (), lily_locale_dir.ch_C());
238     }
239   else
240     bindtextdomain (name.ch_C (), DIR_LOCALEDIR);
241   textdomain (name.ch_C ());
242 #endif
243
244   global_path.add ("");
245   // must override (come before) "/usr/local/share/lilypond"!
246   char const *env_sz = getenv ("LILYINCLUDE");
247   if (env_sz)
248     global_path.parse_path (env_sz);
249
250
251   /*
252     Should use kpathsea, this is getting out of hand.  
253    */
254   char *suffixes[] = {"ly", "afm", "scm", "tfm", "ps", 0};
255   String prefix = prefix_directory;
256   if (prefix.empty_b ())
257     prefix =  DIR_DATADIR;
258   for (char **s = suffixes; *s; s++)
259     {
260       String p =  prefix + to_str ('/') + String (*s);
261       global_path.add (p);
262
263 #if !KPATHSEA
264       /* Urg: GNU make's $(word) index starts at 1 */
265       int i  = 1;
266       while (global_path.try_add (p + to_str (".") + to_str (i)))
267         i++;
268 #endif
269     }
270 }
271
272 /**
273   Make input file name from command argument.
274
275   Path describes file name with added default extension,
276   ".ly" if none.  "-" is stdin.
277  */
278 Path
279 distill_inname (String str)
280 {
281   Path p = split_path (str);
282   if (str.empty_b () || str == "-")
283     p.base = "-";
284   else
285     {
286       String orig_ext = p.ext;
287       char const *extensions[] = {"ly", "fly", "sly", "", 0};
288       for (int i = 0; extensions[i]; i++)
289         {
290           p.ext = orig_ext;
291           if (*extensions[i] && !p.ext.empty_b ())
292             p.ext += ".";
293           p.ext += extensions[i];
294           if (!global_path.find (p.str ()).empty_b ())
295               break;
296         }
297       /* Reshuffle extension */
298       p = split_path (p.str ());
299     }
300   return p;
301 }
302
303 String
304 format_to_ext (String format)
305 {
306   if (format == "tex")
307     /* .lytex change in separate (revertable) patch: 1.3.130.jcn4 */
308     return "tex"; // "lytex";
309   return format;
310 }
311
312 void
313 main_prog (int, char**)
314 {
315   /*
316     need to do this first. Engravers use lily.scm contents.
317    */
318   init_lily_guile ();
319   if (verbose_global_b)
320     progress_indication ("\n");
321   read_lily_scm_file ("lily.scm");
322   cout << endl;
323
324   call_constructors ();
325   all_fonts_global_p = new All_font_metrics (global_path.str ());
326
327   int p=0;
328   const char *arg ;
329   while ((arg = oparser_p_static->get_next_arg ()) || p == 0)
330     {
331       String infile;
332       
333       if (arg)
334         infile = arg;
335       else
336         infile = "-";
337         
338       // What/when was this supposed to do?
339       // It looks like it reset the outname_str_global for every new
340       // file, but only if user didn't specify a outname?  Huh?
341       // if (outname_str_global == "")
342       {
343         Midi_def::reset_score_count ();
344         Paper_def::reset_score_count ();
345       }
346
347       Path inpath = distill_inname (infile);
348
349       /* By default, use base name of input file for output file name */
350       Path outpath = inpath;
351       if (inpath.str () != "-")
352         outpath.ext = format_to_ext (output_format_global);
353
354       /* By default, write output to cwd; do not copy directory part
355          of input file name */
356       outpath.root = "";
357       outpath.dir = "";
358       
359       if (!output_name_global.empty_b ())
360         outpath = split_path (output_name_global);
361       
362       String init;
363       if (!init_name_global.empty_b ())
364         init = init_name_global;
365       else if (!inpath.ext.empty_b ())
366         init = "init." + inpath.ext;
367       else
368         init = "init.ly";
369         
370       /* Burp: output name communication goes through _global */
371       String save_output_name_global = output_name_global;
372       output_name_global = outpath.str ();
373       do_one_file (init, inpath.str ());
374       output_name_global = save_output_name_global;
375       
376       p++;
377     }
378   delete oparser_p_static;
379   exit (exit_status_global);
380 }
381
382
383 int
384 main (int argc, char **argv)
385 {
386   debug_init ();                // should be first (can see that; but Why?)
387   setup_paths ();
388
389   /*
390     prepare guile for heavy mem usage.
391
392     putenv is POSIX, setenv is BSD 4.3
393    */
394   putenv ("GUILE_INIT_SEGMENT_SIZE_1=4194304");
395   putenv ("GUILE_MAX_SEGMENT_SIZE=8388608");
396
397   ly_init_kpath (argv[0]);
398   
399   oparser_p_static = new Getopt_long(argc, argv, options_static);
400   while (Long_option_init const * opt = (*oparser_p_static)())
401     {
402       switch (opt->shortname_ch_)
403         {
404         case 'v':
405           version ();
406           exit (0);             // we print a version anyway.
407           break;
408         case 'o':
409           {
410             String s = oparser_p_static->optional_argument_ch_C_;
411             Path p = split_path (s);
412             if (p.ext.empty_b ())
413               p.ext = format_to_ext (output_format_global);
414             output_name_global = p.str ();
415           }
416           break;
417         case 'w':
418           notice ();
419           exit (0);
420           break;
421         case 'f':
422             output_format_global = oparser_p_static->optional_argument_ch_C_;
423           break;
424         case 'H':
425           dump_header_fieldnames_global.push (oparser_p_static->optional_argument_ch_C_);
426           break;
427         case 'I':
428           global_path.push (oparser_p_static->optional_argument_ch_C_);
429           break;
430         case 'i':
431           init_name_global = oparser_p_static->optional_argument_ch_C_;
432           break;
433         case 'h':
434           usage ();
435           exit (0);
436           break;
437         case 'V':
438           verbose_global_b = true;
439           break;
440         case 's':
441           safe_global_b = true;
442           break;
443         case 'M':
444           dependency_global_b = true;
445           break; 
446         case 'm':
447           no_paper_global_b = true;
448           break;
449         case 'T':
450           no_timestamps_global_b = true;
451           break;
452         default:
453           assert (false);
454           break;
455         }
456     }
457   identify (&cerr);
458
459 #ifdef WINNT
460   gh_enter (argc, argv, main_prog);
461 #else
462   gh_enter (argc, argv, (void(*)(int, char**))main_prog);
463 #endif
464
465   return 0;                     // unreachable
466 }
467
468