/*
- main.cc -- implement main () entrypoint.
+ This file is part of LilyPond, the GNU music typesetter.
- source file of the GNU LilyPond music typesetter
+ Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
- (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ LilyPond is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ LilyPond is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.hh"
+#include "lily-guile.hh"
#include <cassert>
#include <clocale>
#include <cstring>
+#include <cerrno>
+#include <cstdio>
+using namespace std;
+
#include <unistd.h>
-#include <errno.h>
-#include <pwd.h>
-#include <grp.h>
#include <sys/types.h>
-
#include "config.hh"
+#if HAVE_GRP_H
+#include <grp.h>
+#endif
+#if HAVE_PWD_H
+#include <pwd.h>
+#endif
#if HAVE_GETTEXT
#include <libintl.h>
#endif
#include "all-font-metrics.hh"
#include "file-name.hh"
+#include "freetype.hh"
#include "getopt-long.hh"
#include "global-ctor.hh"
-#include "kpath.hh"
-#include "lily-guile.hh"
+#include "international.hh"
#include "lily-version.hh"
#include "misc.hh"
#include "output-def.hh"
-#include "warn.hh"
-#include "freetype.hh"
+#include "program-option.hh"
+#include "relocate.hh"
#include "string-convert.hh"
+#include "version.hh"
+#include "warn.hh"
/*
* Global options that can be overridden through command line.
*/
/* Names of header fields to be dumped to a separate file. */
-Array<String> dump_header_fieldnames_global;
+//vector<string> dump_header_fieldnames_global; // moved to global-data.cc
/* Name of initialisation file. */
-String init_name_global;
+//string init_name_global; // moved to global-data.cc
-/* Selected output format.
- One of tex, ps, scm, as.
-*/
-String output_backend_global = "ps";
-String output_format_global = "pdf";
-bool is_pango_format_global;
+/* Output formats to generate. */
+//string output_format_global = ""; // moved to global-data.cc
/* Current output name. */
-String output_name_global;
+//string output_name_global; // moved to global-data.cc
/* Run in safe mode? */
-bool be_safe_global = false;
+//bool be_safe_global = false; // moved to global-data.cc
-/* Verbose progress indication? */
-bool be_verbose_global = false;
-
-/* Scheme code to execute before parsing, after .scm init
- This is where -e arguments are appended to.
-*/
-String init_scheme_code_string = "(begin #t ";
+/* Provide URI links to the original file */
+bool point_and_click_global = true;
-bool make_preview = false;
-bool make_pages = true;
+/* Scheme code to execute before parsing, after .scm init.
+ This is where -e arguments are appended to. */
+//string init_scheme_code_global; // moved to global-data.cc
+//string init_scheme_variables_global; // moved to global-data.cc
+//bool relocate_binary = true; // moved to global-data.cc
/*
* Miscellaneous global stuff.
*/
-File_path global_path;
-
+//File_path global_path; // moved to global-data.cc
/*
* File globals.
*/
-static char const *AUTHORS =
-" Han-Wen Nienhuys <hanwen@cs.uu.nl>\n"
-" Jan Nieuwenhuizen <janneke@gnu.org>\n";
+static char const *AUTHORS
+ = " Han-Wen Nienhuys <hanwen@xs4all.nl>\n"
+ " Jan Nieuwenhuizen <janneke@gnu.org>\n";
static char const *PROGRAM_NAME = "lilypond";
static char const *PROGRAM_URL = "http://lilypond.org";
-static char const *NOTICE =
-_f ("This program is free software. It is covered by the GNU General Public\n"
- "License and you are welcome to change it and/or distribute copies of it\n"
- "under certain conditions. Invoke as `%s --warranty' for more\n"
- "information.\n", "lilypond").to_str0 ();
-
-static char const *WARRANTY =
-_i (" This program is free software; you can redistribute it and/or\n"
- "modify it under the terms of the GNU General Public License version 2\n"
- "as published by the Free Software Foundation.\n"
- "\n"
- " This program is distributed in the hope that it will be useful,\n"
- "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
- "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
- "General Public License for more details.\n"
- "\n"
- " You should have received a copy (refer to the file COPYING) of the\n"
- "GNU General Public License along with this program; if not, write to\n"
- "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
- "Boston, MA 02111-1307, USA.\n");
-
+static char const *NOTICE
+ = _i ("This program is free software. It is covered by the GNU General Public\n"
+ "License and you are welcome to change it and/or distribute copies of it\n"
+ "under certain conditions. Invoke as `%s --warranty' for more\n"
+ "information.\n");
+
+static char const *WARRANTY
+ = _i (" This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License as \n"
+ "published by the Free Software Foundation, either version 3 of\n"
+ "the License, or (at your option) any later version.\n"
+ "\n"
+ " This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
+ "General Public License for more details.\n"
+ "\n"
+ " You should have received a copy of the\n"
+ "GNU General Public License along with this program; if not, write to\n"
+ "the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n"
+ "Boston, MA 02111-1307, USA.\n");
/* Where the init files live. Typically:
LILYPOND_DATADIR = /usr/share/lilypond
- LOCAL_LILYPOND_DATADIR = /usr/share/lilypond/<VERSION> */
-char const *prefix_directories[] = {LILYPOND_DATADIR, LOCAL_LILYPOND_DATADIR, 0};
+*/
+//string lilypond_datadir; // moved to global-data.cc
-/* The jail specification: USER,GROUP,JAIL,DIR. */
-String jail_spec;
+/* The jail specification: USER, GROUP, JAIL, DIR. */
+string jail_spec;
/* The option parser */
static Getopt_long *option_parser = 0;
/* Internationalisation kludge in two steps:
- * use _i () to get entry in POT file
- * call gettext () explicitely for actual "translation" */
+ * use _i () to get entry in POT file
+ * call gettext () explicitly for actual "translation" */
-static Long_option_init options_static[] =
+/*
+ Data to be used to display when
+ -h command line option is detected.
+*/
+static Long_option_init options_static[]
+=
+{
{
- {_i ("EXT"), "backend", 'b', _i ("select backend to use")},
- {_i ("EXPR"), "evaluate", 'e',
- _i ("set option, use -e '(ly:option-usage)' for help")},
- /* Bug in option parser: --output =foe is taken as an abbreviation
- for --output-format. */
- {_i ("EXTs"), "formats", 'f', _i ("list of formats to dump")},
- {0, "help", 'h', _i ("print this help")},
- {_i ("FIELD"), "header", 'H', _i ("write header field to BASENAME.FIELD")},
- {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
- {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
- {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
- {_i ("USER,GROUP,JAIL,DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP and cd into DIR")},
- {0, "preview", 'p', _i ("generate a preview")},
- {0, "no-pages", 0, _i ("don't generate full pages")},
- {0, "png", 0, _i ("generate PNG")},
- {0, "ps", 0, _i ("generate PostScript")},
- {0, "dvi", 0, _i ("generate DVI")},
- {0, "pdf", 0, _i ("generate PDF (default)")},
- {0, "tex", 0, _i ("generate TeX")},
- {0, "safe-mode", 's', _i ("run in safe mode")},
- {0, "version", 'v', _i ("print version number")},
- {0, "verbose", 'V', _i ("be verbose")},
- {0, "warranty", 'w', _i ("show warranty and copyright")},
- {0, 0, 0, 0}
- };
+ _i ("SYM[=VAL]"), "define-default", 'd',
+ _i ("set Scheme option SYM to VAL (default: #t).\n"
+ "Use -dhelp for help.")
+ },
+
+ {_i ("EXPR"), "evaluate", 'e', _i ("evaluate scheme code")},
+ /* Bug in option parser: --output =foe is taken as an abbreviation
+ for --output-format. */
+ {_i ("FORMATs"), "formats", 'f', _i ("dump FORMAT,... Also as separate options:")},
+ {0, "pdf", 0, _i ("generate PDF (default)")},
+ {0, "png", 0, _i ("generate PNG")},
+ {0, "ps", 0, _i ("generate PostScript")},
+ {0, "help", 'h', _i ("show this help and exit")},
+ {
+ _i ("FIELD"), "header", 'H', _i ("dump header field FIELD to file\n"
+ "named BASENAME.FIELD")
+ },
+ {_i ("DIR"), "include", 'I', _i ("add DIR to search path")},
+ {_i ("FILE"), "init", 'i', _i ("use FILE as init file")},
+#if HAVE_CHROOT
+ {
+ _i ("USER, GROUP, JAIL, DIR"), "jail", 'j', _i ("chroot to JAIL, become USER:GROUP\n"
+ "and cd into DIR")
+ },
+#endif
+ {
+ _i ("LOGLEVEL"), "loglevel", 'l', _i ("print log messages according to"
+ " LOGLEVEL. Possible values are:\n"
+ "NONE, ERROR, WARNING, BASIC, PROGRESS, INFO (default) and DEBUG.")
+ },
+ {_i ("FILE"), "output", 'o', _i ("write output to FILE (suffix will be added)")},
+ {0, "relocate", 0, _i ("relocate using directory of lilypond program")},
+ {0, "silent", 's', _i ("no progress, only error messages (equivalent to loglevel=ERROR)")},
+ {0, "version", 'v', _i ("show version number and exit")},
+ {0, "verbose", 'V', _i ("be verbose (equivalent to loglevel=DEBUG)")},
+ {0, "warranty", 'w', _i ("show warranty and copyright")},
+ {0, 0, 0, 0}
+};
+
+char const *LILYPOND_DATADIR = PACKAGE_DATADIR "/" TOPLEVEL_VERSION;
+
+/* x86 defaults to using 80-bit extended precision arithmetic. This can cause
+ problems because the truncation from 80 bits to 64 bits can occur in
+ unpredictable places. To get around this, we tell the x87 FPU to use only
+ double precision. Note that this is not needed for x86_64 because that uses
+ the SSE unit by default instead of the x87 FPU. */
+#if ((defined (__x86__) || defined (__i386__)) \
+ && defined (HAVE_FPU_CONTROL_H) && (HAVE_FPU_CONTROL_H == 1))
+
+#include <fpu_control.h>
+static void
+configure_fpu ()
+{
+ fpu_control_t fpu_control = 0x027f;
+ _FPU_SETCW (fpu_control);
+}
+
+#else
+
+static void
+configure_fpu ()
+{
+}
+
+#endif /* defined(__x86__) || defined(__i386__) */
+
+static void
+env_var_info (FILE *out, char const *key)
+/*
+ * Retrieve value of an OS environment variable.
+ * Parameter:
+ * key, the name of an environment variable.
+ */
+{
+ if (char const *value = getenv (key))
+ fprintf (out, "%s=\"%s\"\n", key, value);
+}
static void
dir_info (FILE *out)
+/*
+ * Print out information re directories being used by LilyPond
+ * for this session.
+ */
{
fputs ("\n", out);
- fprintf (out, "LILYPOND_DATADIR =\"%s\"\n", LILYPOND_DATADIR);
- fprintf (out, "LOCAL_LILYPOND_DATADIR =\"\%s\"\n", LOCAL_LILYPOND_DATADIR);
- fprintf (out, "LOCALEDIR =\"%s\"\n", LOCALEDIR);
+ fprintf (out, "LILYPOND_DATADIR=\"%s\"\n", LILYPOND_DATADIR);
+ env_var_info (out, "LILYPONDPREFIX");
+ env_var_info (out, "LILYPOND_DATADIR");
+ fprintf (out, "LOCALEDIR=\"%s\"\n", LOCALEDIR);
- char *lilypond_prefix = getenv ("LILYPONDPREFIX");
- fprintf (out, "LILYPONDPREFIX =\"%s\"\n",
- (lilypond_prefix ? lilypond_prefix : ""));
+ fprintf (out, "\nEffective prefix: \"%s\"\n", lilypond_datadir.c_str ());
+
+ if (relocate_binary)
+ {
+ env_var_info (out, "FONTCONFIG_FILE");
+ env_var_info (out, "FONTCONFIG_PATH");
+ env_var_info (out, "GS_FONTPATH");
+ env_var_info (out, "GS_LIB");
+ env_var_info (out, "GUILE_LOAD_PATH");
+ env_var_info (out, "PANGO_RC_FILE");
+ env_var_info (out, "PANGO_PREFIX");
+ env_var_info (out, "PATH");
+ }
}
static void
copyright ()
+/*
+ * Print out LilyPond copyright info.
+ */
{
- printf (_f ("Copyright (c) %s by\n%s and others.",
- "1996--2005",
- AUTHORS).to_str0 ());
+ /* Do not update the copyright years here, run `make grand-replace' */
+ printf ("%s", (_f ("Copyright (c) %s by\n%s and others.", "1996--2014",
+ AUTHORS).c_str ()));
printf ("\n");
}
static void
identify (FILE *out)
+/*
+ * Print out LilyPond version string.
+ */
{
- fputs (gnu_lilypond_version_string ().to_str0 (), out);
+ fputs (gnu_lilypond_version_string ().c_str (), out);
fputs ("\n", out);
}
-
+
static void
+/*
+ * Print copyright and program name
+ */
notice ()
{
identify (stdout);
- printf (_f (NOTICE, PROGRAM_NAME).to_str0 ());
printf ("\n");
copyright ();
+ printf ("\n");
+ puts (_f (NOTICE, PROGRAM_NAME).c_str ());
}
-static void
-usage ()
+LY_DEFINE (ly_usage, "ly:usage",
+ 0, 0, 0, (),
+ "Print usage message.")
+/*
+ * ly_usage: Routine to output standard information when LilyPond is run without a
+ * source file to compile.
+ * Also callable as ly:usage from Scheme.
+ */
{
/* No version number or newline here. It confuses help2man. */
- printf (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).to_str0 ());
+ printf ("%s", (_f ("Usage: %s [OPTION]... FILE...", PROGRAM_NAME).c_str ()));
printf ("\n\n");
- printf (_ ("Typeset music and/or produce MIDI from FILE.").to_str0 ());
+ printf ("%s", (_ ("Typeset music and/or produce MIDI from FILE.").c_str ()));
printf ("\n\n");
- printf (_ ("LilyPond produces beautiful music notation.").to_str0 ());
+ printf ("%s", (_ ("LilyPond produces beautiful music notation.").c_str ()));
printf ("\n");
- printf (_f ("For more information, see %s", PROGRAM_URL).to_str0 ());
+ printf ("%s", (_f ("For more information, see %s", PROGRAM_URL).c_str ()));
printf ("\n\n");
- printf (_ ("Options:").to_str0 ());
+ printf ("%s", (_ ("Options:").c_str ()));
printf ("\n");
- printf (Long_option_init::table_string (options_static).to_str0 ());
+ printf ("%s", Long_option_init::table_string (options_static).c_str ());
printf ("\n");
- printf (_f ("Report bugs to %s.", "bug-lilypond@gnu.org").to_str0 ());
+ /* Translators, please translate this string as
+ "Report bugs in English via %s",
+ or if there is a LilyPond users list or forum in your language
+ "Report bugs in English via %s or in YOUR_LANG via URI" */
+ printf ("%s", (_f ("Report bugs via %s",
+ "http://post.gmane.org/post.php?group=gmane.comp.gnu.lilypond.bugs"
+ ).c_str ()));
printf ("\n");
printf ("\n");
+ return SCM_UNSPECIFIED;
}
static void
warranty ()
+/*
+ * Prints out LilyPond warranty information
+ */
{
identify (stdout);
printf ("\n");
copyright ();
printf ("\n");
- printf (_ (WARRANTY).to_str0 ());
+ printf ("%s", (_ (WARRANTY).c_str ()));
}
static void
-setup_paths ()
-{
- if (char const *lilypond_prefix = getenv ("LILYPONDPREFIX"))
- prefix_directories[1] = lilypond_prefix;
-
- global_path.append ("");
-
- /* Adding mf/out make lilypond unchanged source directory, when setting
- LILYPONDPREFIX to lilypond-x.y.z */
- char *suffixes[] = {"ly", "cff", "otf", "mf/out", "scm", "tfm", "ps", "svg",
- 0};
-
- for (unsigned i = 0; prefix_directories[i]; i++)
- for (char **s = suffixes; *s; s++)
- {
- String p = prefix_directories[i] + to_string ('/') + String (*s);
- global_path.prepend (p);
-
-#if !KPATHSEA
- /* Urg: GNU make's $ (word) index starts at 1 */
- int i = 1;
- while (global_path.try_append (p + to_string (".") + to_string (i)))
- i++;
-#endif
- }
-}
-
-static void
-prepend_load_path (String dir)
+prepend_scheme_list (const string &dir, const string &scmlist)
+/*
+ * Inserts an item at the front of a Scheme list, e.g. %load-path
+ * Parameters:
+ * dir: The directory to add to the front of the list
+ * scmlist: The Scheme list onto which to prepend the directory
+ */
{
- String s = "(set! %load-path (cons \"" + dir + "\" %load-path))";
- scm_c_eval_string (s.to_str0 ());
+ SCM var = scm_c_lookup (scmlist.c_str());
+ scm_variable_set_x (var, scm_cons (scm_from_locale_string (dir.c_str()),
+ scm_variable_ref (var)));
+ /* string setcmd =
+ "(set! " + scmlist + " (cons \"" + dir + "\" " + scmlist +"))";
+ scm_c_eval_string (setcmd.c_str());*/
}
void init_global_tweak_registry ();
void init_fontconfig ();
-
+#if HAVE_CHROOT
static void
do_chroot_jail ()
{
- /* Now we chroot, setuid/setgrp and chdir. If something goes wrong, we exit (this is a
- security-sensitive area). First we split jail_spec into its components, then we
- retrieve the user/group id (necessarily *before* chroot'ing!) and finally we perform
- the actual actions. */
+ /* Now we chroot, setuid/setgrp and chdir. If something goes wrong,
+ we exit (this is a security-sensitive area). First we split
+ jail_spec into its components, then we retrieve the user/group id
+ (necessarily *before* chroot'ing) and finally we perform the
+ actual actions. */
- Array<String> components = String_convert::split(jail_spec, ',');
- if (components.size() < 3)
- {
- error (_ ("too few elements in jail specification"));
- exit(1);
- }
- if (components.size() > 4)
+ enum Jail
+ {
+ USER_NAME, GROUP_NAME, JAIL, DIR, JAIL_MAX
+ };
+
+ vector<string> components = string_split (jail_spec, ',');
+ if (components.size () != JAIL_MAX)
{
- error (_ ("too many elements in jail specification"));
- exit(1);
+ error (_f ("expected %d arguments with jail, found: %u", JAIL_MAX,
+ (unsigned) components.size ()));
+ exit (2);
}
- int uid, gid;
- char *user_name = components[0].get_str0 ();
- char *group_name = components[1].get_str0 ();
- char *jail = components[2].get_str0 ();
- char *wd = components[3].get_str0 ();
-
+ /* Hmm. */
errno = 0;
- struct passwd *passwd = getpwnam(user_name);
- if (passwd == NULL)
+
+ int uid;
+ if (passwd *passwd = getpwnam (components[USER_NAME].c_str ()))
+ uid = passwd->pw_uid;
+ else
{
- if (errno == 0)
- error (_ ("user not found"));
- else
- error(_f ("can't get user id from user name (%s)", strerror (errno)));
+ if (errno == 0)
+ error (_f ("no such user: %s", components[USER_NAME]));
+ else
+ error (_f ("cannot get user id from user name: %s: %s",
+ components[USER_NAME],
+ strerror (errno)));
exit (3);
}
- uid = passwd->pw_uid;
+ /* Hmm. */
errno = 0;
- struct group *group = getgrnam(group_name);
- if (group == NULL)
+
+ int gid;
+ if (group *group = getgrnam (components[GROUP_NAME].c_str ()))
+ gid = group->gr_gid;
+ else
{
- if (errno == 0)
- error (_ ("group not found"));
- else
- error(_f ("can't get group id from group name (%s)", strerror (errno)));
+ if (errno == 0)
+ error (_f ("no such group: %s", components[GROUP_NAME]));
+ else
+ error (_f ("cannot get group id from group name: %s: %s",
+ components[GROUP_NAME],
+ strerror (errno)));
exit (3);
}
- gid = group->gr_gid;
- if (chroot (jail))
+ if (chroot (components[JAIL].c_str ()))
{
- error (_f ("can't chroot (%s)", strerror (errno)));
+ error (_f ("cannot chroot to: %s: %s", components[JAIL],
+ strerror (errno)));
exit (3);
}
if (setgid (gid))
{
- error (_f ("can't change group id (%s)", strerror (errno)));
+ error (_f ("cannot change group id to: %d: %s", gid, strerror (errno)));
exit (3);
}
if (setuid (uid))
{
- error (_f ("can't change user id (%s)", strerror (errno)));
+ error (_f ("cannot change user id to: %d: %s", uid, strerror (errno)));
exit (3);
}
- if (chdir (wd))
+ if (chdir (components[DIR].c_str ()))
{
- error (_f ("can't change working directory (%s)", strerror (errno)));
+ error (_f ("cannot change working directory to: %s: %s", components[DIR],
+ strerror (errno)));
exit (3);
}
}
-
+#endif
static void
main_with_guile (void *, int, char **)
+/*
+ * main-with-guile is invoked as a callback via scm_boot_guile from
+ * main.
+ * scm_boot_guile will have passed its data, argc and argv parameters
+ * to main_with_guile.
+ */
{
- /* Engravers use lily.scm contents, need to make Guile find it.
- Prepend onto GUILE %load-path, very ugh. */
- for (unsigned i = 0; prefix_directories[i]; i++)
- {
- prepend_load_path (prefix_directories[i]);
- /* Junk this. We should make real modules iso. just loading files. */
- prepend_load_path (String (prefix_directories[i]) + "/scm");
- }
+ /* Engravers use lily.scm contents, so we need to make Guile find it.
+ Prepend onto GUILE %load-path.
+ %load-path is the symbol Guile searches for .scm files
+ %load-compiled-path is the symbol Guile V2 searches for .go files
+ */
+ string scm_pct_load_path = "%load-path";
+ string scm_pct_load_compiled_path = "%load-compiled-path";
+
+ prepend_scheme_list (lilypond_datadir, scm_pct_load_path );
+ prepend_scheme_list (lilypond_datadir + "/scm", scm_pct_load_path);
+
+#if (GUILE2)
+ /*
+ Just as ughy - prepend "/scm/out" onto GUILE V2+ %load-compiled-path
+ and set %compile-fallback-path to our scm/out directory
+ */
+ /*
+ %load-compiled-path is the symbol Guile V2 searches for .go files
+ */
+ prepend_scheme_list (lilypond_datadir + "/scm/out",
+ scm_pct_load_compiled_path);
+ /*
+ %compile-fallback-path is the guile cache root for auto-compiled files
+ */
+
+ string scm_pct_fallback_path = "%compile-fallback-path";
+ string ly_scm_go_dir = lilypond_datadir + "/scm/out";
+ //string scm_pct_set_fallback = "(set! " + scm_pct_fallback_path +
+ // " \"" + lilypond_datadir + "/scm/out\")";
+ //scm_c_eval_string (scm_pct_set_fallback.c_str() );
+ scm_primitive_eval
+ (scm_list_3 (scm_from_locale_symbol ("set!"),
+ scm_from_locale_symbol ("%compile-fallback-path"),
+ scm_from_locale_string (ly_scm_go_dir.c_str())));
+#endif
- if (be_verbose_global)
+ if (is_loglevel (LOG_DEBUG))
dir_info (stderr);
+ init_scheme_variables_global = "(list " + init_scheme_variables_global + ")";
+ init_scheme_code_global = "(begin " + init_scheme_code_global + ")";
+
ly_c_init_guile ();
call_constructors ();
- init_global_tweak_registry ();
init_fontconfig ();
- init_freetype ();
-
- is_pango_format_global = (output_backend_global != "tex"
- && output_backend_global != "texstr");
- all_fonts_global = new All_font_metrics (global_path.to_string ());
-
- init_scheme_code_string += ")";
- scm_c_eval_string ((char*) init_scheme_code_string.to_str0 ());
+ init_freetype ();
+ ly_reset_all_fonts ();
- /* We accept multiple independent music files on the command line to
+ /*
+ We accept multiple independent music files on the command line to
reduce compile time when processing lots of small files.
- Starting the GUILE engine is very time consuming. */
+ This way we don't have to start the Guile/Scheme interpreter more than once, as
+ starting the GUILE engine is very time consuming.
+ */
SCM files = SCM_EOL;
SCM *tail = &files;
while (char const *arg = option_parser->get_next_arg ())
{
- *tail = scm_cons (scm_makfrom0str (arg), SCM_EOL);
+ *tail = scm_cons (scm_from_locale_string (arg), SCM_EOL);
tail = SCM_CDRLOC (*tail);
}
+
delete option_parser;
option_parser = 0;
- if (files == SCM_EOL)
- {
- /* No FILE arguments is now a usage error to help newbies. If you
- want a filter, you're not a newbie and should know to use file
- argument `-'. */
- usage ();
- exit (2);
- }
-
- if (! jail_spec.is_empty ())
- do_chroot_jail ();
-
+#if HAVE_CHROOT
+ if (!jail_spec.empty ())
+ do_chroot_jail ();
+#endif
+ /*
+ Now execute the Scheme entry-point declared in
+ lily.scm (lilypond-main)
+ */
+ // These commands moved to lily_guile_v2.scm
+ // SCM rep_mod = scm_c_resolve_module ("system repl repl");
+ // scm_c_use_module ("system repl repl");
+ // SCM err_handling_mod = scm_c_resolve_module ("system repl error-handling");
+ // SCM call_with_error_handling = scm_c_module_lookup (err_handling_mod, "call-with-error-handling");
+ // SCM result = scm_call_1 (
+ // scm_variable_ref (call_with_error_handling),
+ // scm_call_1 (ly_lily_module_constant ("lilypond-main"), files));
SCM result = scm_call_1 (ly_lily_module_constant ("lilypond-main"), files);
(void) result;
-
/* Unreachable. */
exit (0);
}
static void
setup_localisation ()
+/*
+ * Set up local language text locale (if available from configure)
+ * Implicit inputs:
+ * HAVE_GETTEXT: Internationalization available for a local language.
+ */
{
#if HAVE_GETTEXT
/* Enable locales */
setlocale (LC_ALL, "");
-
+
/* FIXME: check if this is still true.
- Disable localisation of float values. This breaks TeX output. */
+ Disable localisation of float values. */
setlocale (LC_NUMERIC, "C");
-
- String name (PACKAGE);
- name.to_lower ();
- bindtextdomain (name.to_str0 (), LOCALEDIR);
- textdomain (name.to_str0 ());
+
+#if GUILEV2
+ // In order not to have this porting aid backfire to GUILE1 usage,
+ // this is only compiled in the GUILEV2 version. It should
+ // eventually be replaced with proper multibyte communication with
+ // GUILE2, but in the mean time it seems that this is the least
+ // invasive path to get comparable results between the
+ // not-really-multibyte-supporting GUILE1 and GUILE2
+
+ /* Disable character sets */
+ setlocale (LC_CTYPE, "C");
+ /* But our text domain is in UTF-8 */
+ bind_textdomain_codeset ("lilypond", "UTF-8");
+#endif
+
+ string localedir = LOCALEDIR;
+ if (char const *env = getenv ("LILYPOND_LOCALEDIR"))
+ localedir = env;
+
+ bindtextdomain ("lilypond", localedir.c_str ());
+ textdomain ("lilypond");
#endif
}
static void
-add_output_format (String format)
+add_output_format (const string &format)
+/*
+ * Capture information internally from command-line options
+ * re output format.
+ *
+ */
{
if (output_format_global != "")
output_format_global += ",";
output_format_global += format;
}
-
static void
parse_argv (int argc, char **argv)
+/*
+ * Parse command-line options
+ * also, if -h (help), -v (version) or -w (warranty) is detected,
+ * output the usage information and exit.
+ */
{
- bool help_b = false;
+ bool show_help = false;
option_parser = new Getopt_long (argc, argv, options_static);
while (Long_option_init const *opt = (*option_parser) ())
{
switch (opt->shortname_char_)
- {
- case 0:
- if (String (opt->longname_str0_) == "png"
- || String (opt->longname_str0_) == "pdf"
- || String (opt->longname_str0_) == "ps"
- || String (opt->longname_str0_) == "dvi"
- || String (opt->longname_str0_) == "tex")
- {
- add_output_format (opt->longname_str0_);
- }
- else if (String (opt->longname_str0_) == "preview")
- make_preview = true;
- else if (String (opt->longname_str0_) == "no-pages")
- make_pages = false;
- break;
-
- case 'v':
- notice ();
- exit (0);
- break;
- case 'o':
- {
- String s = option_parser->optional_argument_str0_;
- File_name file_name (s);
- output_name_global = file_name.to_string ();
- }
- break;
- case 'j':
- jail_spec = option_parser->optional_argument_str0_;
- break;
- case 'e':
- init_scheme_code_string += option_parser->optional_argument_str0_;
- break;
- case 'w':
- warranty ();
- exit (0);
- break;
-
- case 'b':
- output_backend_global = option_parser->optional_argument_str0_;
- break;
-
- case 'f':
- output_format_global = option_parser->optional_argument_str0_;
- break;
-
- case 'H':
- dump_header_fieldnames_global
- .push (option_parser->optional_argument_str0_);
- break;
- case 'I':
- global_path.append (option_parser->optional_argument_str0_);
- break;
- case 'i':
- init_name_global = option_parser->optional_argument_str0_;
- break;
- case 'h':
- help_b = true;
- break;
- case 'V':
- be_verbose_global = true;
- break;
- case 's':
- be_safe_global = true;
- break;
- case 'p':
- make_preview = true;
- break;
- default:
- programming_error (to_string ("unhandled short option: %c",
- opt->shortname_char_));
- assert (false);
- break;
- }
+ {
+ case 0:
+ if (string (opt->longname_str0_) == "pdf"
+ || string (opt->longname_str0_) == "png"
+ || string (opt->longname_str0_) == "ps")
+ add_output_format (opt->longname_str0_);
+ else if (string (opt->longname_str0_) == "relocate")
+ relocate_binary = true;
+ break;
+
+ case 'd':
+ {
+ string arg (option_parser->optional_argument_str0_);
+ ssize eq = arg.find ('=');
+
+ string key = arg;
+ string val = "#t";
+
+ if (eq != NPOS)
+ {
+ key = arg.substr (0, eq);
+ val = arg.substr (eq + 1, arg.length () - 1);
+ }
+
+ init_scheme_variables_global
+ += "(cons \'" + key + " '" + val + ")\n";
+ }
+ break;
+
+ case 'v':
+ notice ();
+ exit (0);
+ break;
+ case 'o':
+ {
+ string s = option_parser->optional_argument_str0_;
+ File_name file_name (s);
+ output_name_global = file_name.to_string ();
+ }
+ break;
+ case 'j':
+ jail_spec = option_parser->optional_argument_str0_;
+ break;
+
+ case 'e':
+ init_scheme_code_global
+ += option_parser->optional_argument_str0_ + string (" ");
+ break;
+ case 'w':
+ warranty ();
+ exit (0);
+ break;
+
+ case 'f':
+ {
+ vector<string> components
+ = string_split (option_parser->optional_argument_str0_, ',');
+ for (vsize i = 0; i < components.size (); i++)
+ add_output_format (components[i]);
+ }
+ break;
+
+ case 'H':
+ dump_header_fieldnames_global
+ .push_back (option_parser->optional_argument_str0_);
+ break;
+ case 'I':
+ global_path.append (option_parser->optional_argument_str0_);
+ break;
+ case 'i':
+ init_name_global = option_parser->optional_argument_str0_;
+ break;
+ case 'h':
+ show_help = true;
+ break;
+ case 'V':
+ set_loglevel (LOGLEVEL_DEBUG);
+ break;
+ case 's':
+ set_loglevel (LOGLEVEL_ERROR);
+ break;
+ case 'l':
+ set_loglevel (option_parser->optional_argument_str0_);
+ break;
+ default:
+ programming_error (to_string ("unhandled short option: %c",
+ opt->shortname_char_));
+ assert (false);
+ break;
+ }
}
- if (help_b)
+ if (output_format_global == "")
+ output_format_global = "pdf";
+
+ if (show_help)
{
- identify (stdout);
- usage ();
- if (be_verbose_global)
- dir_info (stdout);
+ ly_usage ();
+ if (is_loglevel (LOG_DEBUG))
+ dir_info (stdout);
exit (0);
}
}
+/*
+ T1686 Add two new routines called by setup_guile_env
+*/
+
+void
+setup_guile_gc_env ()
+/*
+ * Set up environment variables relevant to the
+ * Garbage Collector
+ */
+{
+ char const *yield = getenv ("LILYPOND_GC_YIELD");
+ bool overwrite = true;
+ if (!yield)
+ {
+ yield = "65";
+ overwrite = false;
+ }
+
+ sane_putenv ("GUILE_MIN_YIELD_1", yield, overwrite);
+ sane_putenv ("GUILE_MIN_YIELD_2", yield, overwrite);
+ sane_putenv ("GUILE_MIN_YIELD_MALLOC", yield, overwrite);
+
+ sane_putenv ("GUILE_INIT_SEGMENT_SIZE_1",
+ "10485760", overwrite);
+ sane_putenv ("GUILE_MAX_SEGMENT_SIZE",
+ "104857600", overwrite);
+}
+
+
+void
+setup_guile_v2_env ()
+/*
+ * Set up environment variables relevant to compiling
+ * Scheme files for Guile V2.
+ */
+{
+ sane_putenv("GUILE_AUTO_COMPILE", "0", true); // disable auto-compile
+ sane_putenv("GUILE_WARN_DEPRECATED",
+ "detailed", "true"); // set Guile to info re deprecation
+ /*
+ Set root for Guile %compile-fallback to
+ Lilypond root for its data.
+ */
+ sane_putenv("XDG_CACHE_HOME",
+ lilypond_datadir, true);
+}
+
+void
+setup_guile_env ()
+/*
+ * Set up environment variables relevant to Scheme
+ */
+{
+
+ setup_guile_gc_env (); // configure garbage collector
+#if (GUILEV2)
+ setup_guile_v2_env (); // configure Guile V2 behaviour
+#endif
+}
+
+//vector<string> start_environment_global;
+
int
-main (int argc, char **argv)
+main (int argc, char **argv, char **envp)
+/*
+ * Main entry-point for LilyPond executable image
+ * Parameters:
+ * argc: Count of arguments on the command line
+ * argv: Vector of string arguments on command line
+ * envp: Point to vector of OS environment variables
+ */
{
+ configure_fpu ();
+ /*
+ Process environment variables
+ */
+ for (char **p = envp; *p; p++)
+ start_environment_global.push_back (*p);
+ /*
+ Handle old-style environment equivalent to
+ old-style -V or --verbose command arguments.
+ Set it to the equivalent for --loglevel-DEBUG
+ */
+ if (getenv ("LILYPOND_VERBOSE"))
+ set_loglevel (LOGLEVEL_DEBUG);
+ if (getenv ("LILYPOND_LOGLEVEL"))
+ set_loglevel (getenv ("LILYPOND_LOGLEVEL"));
+
setup_localisation ();
- setup_paths ();
parse_argv (argc, argv);
- identify (stderr);
- initialize_kpathsea (argv[0]);
-
+ if (isatty (STDIN_FILENO) && (is_loglevel (LOG_BASIC)))
+ identify (stderr);
+
+ setup_paths (argv[0]);
+ setup_guile_env (); // set up environment variables to pass into Guile API
+ /*
+ * Start up Guile API using main_with_guile as a callback.
+ */
+#if (GUILEV2)
+ /* Debugging aid.
+ Set it on by default for Guile V2
+ while migration in progress.
+ */
+ try
+ {
+ scm_boot_guile (argc, argv, main_with_guile, 0);
+ }
+ catch (exception e)
+ {
+ error (_f ("exception caught: %s", e.what ()));
+ };
+#else
scm_boot_guile (argc, argv, main_with_guile, 0);
+#endif
- /* Unreachable */
- return 0;
+ /* Only reachable if GUILE exits. That is an error. */
+ return 1;
}