]> git.donarmstrong.com Git - lilypond.git/blob - scm/lily.scm
Run scripts/auxiliar/fixscm.sh scm/*.scm
[lilypond.git] / scm / lily.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 1998--2012 Jan Nieuwenhuizen <janneke@gnu.org>
4 ;;;; 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 ;; Internationalisation: (_i "to be translated") gets an entry in the
20 ;; POT file; (gettext ...) must be invoked explicitly to do the actual
21 ;; "translation".
22 ;;
23 ;; (define-macro (_i x) x)
24 ;; (define-macro-public _i (x) x)
25 ;; (define-public-macro _i (x) x)
26 ;; Abbrv-PWR!
27
28 (defmacro-public _i (x) x)
29
30 ;;; Boolean thunk - are we integrating Guile V2.0 or higher with LilyPond?
31 (define-public (guile-v2)
32   (string>? (version) "1.9.10"))
33
34 (read-enable 'positions)
35 (if (not (guile-v2))
36     (debug-enable 'debug)
37     (begin
38       (debug-enable 'backtrace)
39       (debug-set! show-file-name #t)))
40
41 (define-public PLATFORM
42   (string->symbol
43    (string-downcase
44     (car (string-tokenize (utsname:sysname (uname)))))))
45
46 ;;
47 ;; Session-handling variables and procedures.
48 ;;
49 ;;  A "session" corresponds to one .ly file processed on a LilyPond
50 ;;  command line.  Every session gets to see a reasonably fresh state
51 ;;  of LilyPond and should work independently from previous files.
52 ;;
53 ;;  Session management relies on cooperation, namely the user not
54 ;;  trying to change variables and data structures internal to
55 ;;  LilyPond.  It is not proof against in-place modification of data
56 ;;  structures (as they are just reinitialized with the original
57 ;;  identities), and it is not proof against tampering with internals.
58 ;;
59 ;;  As a consequence, session management is not sufficient for
60 ;;  separating multiple independent .ly files in "-dsafe" mode: you
61 ;;  should give each its own LilyPond process when reliable separation
62 ;;  is mandatory.
63 ;;
64 ;;  For standard tasks and programming practices, multiple sessions in
65 ;;  the same LilyPond job should work reasonably independently and
66 ;;  without "bleed-over" while still loading and compiling the
67 ;;  relevant .scm and .ly files only once.
68 ;;
69
70 (define lilypond-declarations '())
71 (define after-session-hook (make-hook))
72
73 (define-public (call-after-session thunk)
74   (if (ly:undead? lilypond-declarations)
75       (ly:error (_ "call-after-session used after session start")))
76   (add-hook! after-session-hook thunk #t))
77
78 (defmacro-public define-session (name value)
79   "This defines a variable @var{name} with the starting value
80 @var{value} that is reinitialized at the start of each session.
81 A@tie{}session basically corresponds to one LilyPond file on the
82 command line.  The value is recorded at the start of the first session
83 after loading all initialization files and before loading the user
84 file and is reinstated for all of the following sessions.  This
85 happens just by replacing the value, not by copying structures, so you
86 should not destructively modify them.  For example, lists defined in
87 this manner should be changed within a session only be adding material
88 to their front or replacing them altogether, not by modifying parts of
89 them.  It is an error to call @code{define-session} after the first
90 session has started."
91   (define (add-session-variable name value)
92     (if (ly:undead? lilypond-declarations)
93         (ly:error (_ "define-session used after session start")))
94     (let ((var (make-variable value)))
95       (module-add! (current-module) name var)
96       (set! lilypond-declarations (cons var lilypond-declarations))))
97   `(,add-session-variable ',name ,value))
98
99 (defmacro-public define-session-public (name value)
100   "Like @code{define-session}, but also exports @var{name}."
101   `(begin
102      (define-session ,name ,value)
103      (export ,name)))
104
105 (define (session-terminate)
106   (if (ly:undead? lilypond-declarations)
107       (begin
108         (for-each
109          (lambda (p) (variable-set! (cadr p) (cddr p)))
110          (ly:get-undead lilypond-declarations))
111         (run-hook after-session-hook))))
112
113 (define lilypond-interfaces #f)
114
115 (define-public (session-initialize thunk)
116   "Initialize this session.  The first session in a LilyPond run is
117 initialized by calling @var{thunk}, then recording the values of all
118 variables in the current module as well as those defined with
119 @code{define-session}.  Subsequent calls of @code{session-initialize}
120 ignore @var{thunk} and instead just reinitialize all recorded
121 variables to their value after the initial call of @var{thunk}."
122
123   ;; We need to save the variables of the current module along with
124   ;; their values: functions defined in the module might refer to the
125   ;; variables.
126
127   ;; The entries in lilypond-declarations consist of a cons* consisting
128   ;; of symbol, variable, and value.  Variables defined with
129   ;; define-session have the symbol set to #f.
130
131   (if (ly:undead? lilypond-declarations)
132       (begin
133         (module-use-interfaces! (current-module) (reverse lilypond-interfaces))
134         (for-each
135          (lambda (p)
136            (let ((var (cadr p))
137                  (val (cddr p)))
138              (variable-set! var val)
139              (if (car p)
140                  (module-add! (current-module) (car p) var))))
141          (ly:get-undead lilypond-declarations)))
142       (begin
143         (thunk)
144         (set! lilypond-interfaces
145               (filter (lambda (m) (eq? 'interface (module-kind m)))
146                       (module-uses (current-module))))
147         (let ((decl (map! (lambda (v)
148                             (cons* #f v (variable-ref v)))
149                           lilypond-declarations)))
150           (module-for-each
151            (lambda (s v)
152              (let ((val (variable-ref v)))
153                (if (not (ly:lily-parser? val))
154                    (set! decl
155                          (cons
156                           (cons* s v val)
157                           decl)))))
158            (current-module))
159           (set! lilypond-declarations (ly:make-undead decl))))))
160
161 (define scheme-options-definitions
162   `(
163     ;; NAMING: either
164
165     ;; - [subject-]object-object-verb +"ing"
166     ;; - [subject-]-verb-object-object
167
168     ;; Avoid overlong lines in `lilypond -dhelp'!  Strings should not
169     ;; be longer than 48 characters per line.
170
171     (anti-alias-factor 1
172                        "Render at higher resolution (using given factor)
173 and scale down result to prevent jaggies in
174 PNG images.")
175     (aux-files
176      #t
177      "Create .tex, .texi, .count files in the
178 EPS backend.")
179     (backend
180      ps
181      "Select backend.  Possible values: 'eps, 'null,
182 'ps, 'scm, 'socket, 'svg.")
183     (check-internal-types
184      #f
185      "Check every property assignment for types.")
186     (clip-systems
187      #f
188      "Generate cut-out snippets of a score.")
189     (datadir
190      #f
191      "LilyPond prefix for data files (read-only).")
192     (debug-gc
193      #f
194      "Dump memory debugging statistics.")
195     (debug-gc-assert-parsed-dead
196      #f
197      "For memory debugging: Ensure that all
198 references to parsed objects are dead.  This is
199 an internal option, and is switched on
200 automatically for `-ddebug-gc'.")
201     (debug-lexer
202      #f
203      "Debug the flex lexer.")
204     (debug-page-breaking-scoring
205      #f
206      "Dump scores for many different page breaking
207 configurations.")
208     (debug-parser
209      #f
210      "Debug the bison parser.")
211     (debug-property-callbacks
212      #f
213      "Debug cyclic callback chains.")
214     (debug-skylines
215      #f
216      "Debug skylines.")
217     (delete-intermediate-files
218      #t
219      "Delete unusable, intermediate PostScript files.")
220     (dump-profile
221      #f
222      "Dump memory and time information for each file.")
223     (dump-cpu-profile
224      #f
225      "Dump timing information (system-dependent).")
226     (dump-signatures
227      #f
228      "Dump output signatures of each system.  Used for
229 regression testing.")
230     (eps-box-padding
231      #f
232      "Pad left edge of the output EPS bounding box by
233 given amount (in mm).")
234     (gs-load-fonts
235      #f
236      "Load fonts via Ghostscript.")
237     (gs-load-lily-fonts
238      #f
239      "Load only LilyPond fonts via Ghostscript.")
240     (gui
241      #f
242      "Run LilyPond from a GUI and redirect stderr to
243 a log file.")
244     (help
245      #f
246      "Show this help.")
247     (include-book-title-preview
248      #t
249      "Include book titles in preview images.")
250     (include-eps-fonts
251      #t
252      "Include fonts in separate-system EPS files.")
253     (include-settings
254      #f
255      "Include file for global settings, included before the score is processed.")
256     (job-count
257      #f
258      "Process in parallel, using the given number of
259 jobs.")
260     (log-file
261      #f
262      "If string FOO is given as argument, redirect
263 output to log file `FOO.log'.")
264     (max-markup-depth
265      1024
266      "Maximum depth for the markup tree. If a markup has more levels,
267 assume it will not terminate on its own, print a warning and return a
268 null markup instead.")
269     (midi-extension ,(if (eq? PLATFORM 'windows)
270                          "mid"
271                          "midi")
272                     "Set the default file extension for MIDI output
273 file to given string.")
274     (music-strings-to-paths
275      #f
276      "Convert text strings to paths when glyphs belong
277 to a music font.")
278     (point-and-click
279      #t
280      "Add point & click links to PDF output.")
281     (paper-size
282      "a4"
283      "Set default paper size.")
284     (pixmap-format
285      "png16m"
286      "Set GhostScript's output format for pixel images.")
287     (preview
288      #f
289      "Create preview images also.")
290     (print-pages
291      #t
292      "Print pages in the normal way.")
293     (protected-scheme-parsing
294      #t
295      "Continue when errors in inline scheme are caught
296 in the parser.  If #f, halt on errors and print
297 a stack trace.")
298     (profile-property-accesses
299      #f
300      "Keep statistics of get_property() calls.")
301     (resolution
302      101
303      "Set resolution for generating PNG pixmaps to
304 given value (in dpi).")
305     (read-file-list
306      #f
307      "Specify name of a file which contains a list of
308 input files to be processed.")
309     (relative-includes
310      #f
311      "When processing an \\include command, look for
312 the included file relative to the current file\
313 \n(instead of the root file)")
314     (safe
315      #f
316      "Run in safer mode.")
317     (separate-log-files
318      #f
319      "For input files `FILE1.ly', `FILE2.ly', ...
320 output log data to files `FILE1.log',
321 `FILE2.log', ...")
322     (show-available-fonts
323      #f
324      "List available font names.")
325     (strict-infinity-checking
326      #f
327      "Force a crash on encountering Inf and NaN
328 floating point exceptions.")
329     (strip-output-dir
330      #t
331      "Don't use directories from input files while
332 constructing output file names.")
333     (svg-woff
334      #f
335      "Use woff font files in SVG backend.")
336     (trace-memory-frequency
337      #f
338      "Record Scheme cell usage this many times per
339 second.  Dump results to `FILE.stacks' and
340 `FILE.graph'.")
341     (trace-scheme-coverage
342      #f
343      "Record coverage of Scheme files in `FILE.cov'.")
344     (verbose ,(ly:verbose-output?)
345              "Verbose output, i.e. loglevel at least DEBUG (read-only).")
346     (warning-as-error
347      #f
348      "Change all warning and programming_error
349 messages into errors.")
350     ))
351
352 ;; Need to do this in the beginning.  Other parts of the Scheme
353 ;; initialization depend on these options.
354
355 (for-each (lambda (x)
356             (ly:add-option (car x) (cadr x) (caddr x)))
357           scheme-options-definitions)
358
359 (for-each (lambda (x)
360             (ly:set-option (car x) (cdr x)))
361           (eval-string (ly:command-line-options)))
362
363 (debug-set! stack 0)
364
365 (if (defined? 'set-debug-cell-accesses!)
366     (set-debug-cell-accesses! #f))
367
368 ;;(set-debug-cell-accesses! 1000)
369
370 (use-modules (ice-9 regex)
371              (ice-9 safe)
372              (ice-9 format)
373              (ice-9 rdelim)
374              (ice-9 optargs)
375              (oop goops)
376              (srfi srfi-1)
377              (srfi srfi-13)
378              (srfi srfi-14)
379              (scm clip-region)
380              (scm memory-trace)
381              (scm coverage)
382              (scm safe-utility-defs))
383
384 (define-public _ gettext)
385 ;;; There are new modules defined in Guile V2.0 which we need to use.
386 ;;
387 ;;  Modules and scheme files loaded by lily.scm use currying
388 ;;  in Guile V2 this needs a module which is not present in Guile V1.8
389 ;;
390
391 (cond
392  ((guile-v2)
393   (ly:debug (_ "Using (ice-9 curried-definitions) module\n"))
394   (use-modules (ice-9 curried-definitions)))
395  (else
396   (ly:debug (_ "Guile 1.8\n"))))
397
398 ;; TODO add in modules for V1.8.7 deprecated in V2.0 and integrated
399 ;; into Guile base code, like (ice-9 syncase).
400 ;;
401
402 (define-public fancy-format
403   format)
404
405 (define-public (ergonomic-simple-format dest . rest)
406   "Like ice-9's @code{format}, but without the memory consumption."
407   (if (string? dest)
408       (apply simple-format (cons #f (cons dest rest)))
409       (apply simple-format (cons dest rest))))
410
411 (define format
412   ergonomic-simple-format)
413
414 ;; my display
415 (define-public (myd k v)
416   (display k)
417   (display ": ")
418   (display v)
419   (display ", ")
420   v)
421
422 (define-public (print . args)
423   (apply format (cons (current-output-port) args)))
424
425
426 ;;; General settings.
427 ;;;
428 ;;; Debugging evaluator is slower.  This should have a more sensible
429 ;;; default.
430
431
432 (if (or (ly:get-option 'verbose)
433         (ly:get-option 'trace-memory-frequency)
434         (ly:get-option 'trace-scheme-coverage))
435     (begin
436       (ly:set-option 'protected-scheme-parsing #f)
437       (debug-enable 'backtrace)
438       (read-enable 'positions)))
439
440 (if (ly:get-option 'trace-scheme-coverage)
441     (coverage:enable))
442
443 (define-public parser #f)
444
445 (define music-string-to-path-backends
446   '(svg))
447
448 (if (memq (ly:get-option 'backend) music-string-to-path-backends)
449     (ly:set-option 'music-strings-to-paths #t))
450
451 (define-public (ly:load x)
452   (let* ((file-name (%search-load-path x)))
453     (ly:debug "[~A" file-name)
454     (if (not file-name)
455         (ly:error (_ "cannot find: ~A") x))
456     (primitive-load-path file-name)  ;; to support Guile V2 autocompile
457     ;; TODO: Any chance to use ly:debug here? Need to extend it to prevent
458     ;;       a newline in this case
459     (if (ly:get-option 'verbose)
460         (ly:progress "]\n"))))
461
462 (define-public DOS
463   (let ((platform (string-tokenize
464                    (vector-ref (uname) 0) char-set:letter+digit)))
465     (if (null? (cdr platform)) #f
466         (member (string-downcase (cadr platform)) '("95" "98" "me")))))
467
468 (define (slashify x)
469   (if (string-index x #\\)
470       x
471       (string-regexp-substitute
472        "//*" "/"
473        (string-regexp-substitute "\\\\" "/" x))))
474
475 (define-public (ly-getcwd)
476   (if (eq? PLATFORM 'windows)
477       (slashify (getcwd))
478       (getcwd)))
479
480 (define-public (is-absolute? file-name)
481   (let ((file-name-length (string-length file-name)))
482     (if (= file-name-length 0)
483         #f
484         (or (eq? (string-ref file-name 0) #\/)
485             (and (eq? PLATFORM 'windows)
486                  (> file-name-length 2)
487                  (eq? (string-ref file-name 1) #\:)
488                  (eq? (string-ref file-name 2) #\/))))))
489
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
491 ;;; If necessary, emulate Guile V2 module_export_all! for Guile V1.8.n
492 (cond-expand
493  ((not guile-v2)
494   (define (module-export-all! mod)
495     (define (fresh-interface!)
496       (let ((iface (make-module)))
497         (set-module-name! iface (module-name mod))
498         ;; for guile 2: (set-module-version! iface (module-version mod))
499         (set-module-kind! iface 'interface)
500         (set-module-public-interface! mod iface)
501         iface))
502     (let ((iface (or (module-public-interface mod)
503                      (fresh-interface!))))
504       (set-module-obarray! iface (module-obarray mod))))))
505
506
507 (define-safe-public (lilypond-version)
508   (string-join
509    (map (lambda (x) (if (symbol? x)
510                         (symbol->string x)
511                         (number->string x)))
512         (ly:version))
513    "."))
514
515 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
516 ;; init pitch system
517
518 (ly:set-default-scale (ly:make-scale #(0 1 2 5/2 7/2 9/2 11/2)))
519
520 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
521 ;; other files.
522
523 ;;
524 ;;  List of Scheme files to be loaded into the (lily) module.
525 ;;
526 ;;  - Library definitions, need to be at the head of the list
527 (define init-scheme-files-lib
528   '("lily-library.scm"
529     "output-lib.scm"))
530 ;;  - Files containing definitions used later by other files later in load
531 (define init-scheme-files-used
532   '("markup-macros.scm"
533     "parser-ly-from-scheme.scm"))
534 ;;  - Main body of files to be loaded
535 (define init-scheme-files-body
536   '("file-cache.scm"
537     "define-event-classes.scm"
538     "define-music-callbacks.scm"
539     "define-music-types.scm"
540     "define-note-names.scm"
541     "c++.scm"
542     "chord-entry.scm"
543     "skyline.scm"
544     "stencil.scm"
545     "define-markup-commands.scm"
546     "markup.scm"
547     "modal-transforms.scm"
548     "chord-generic-names.scm"
549     "chord-ignatzek-names.scm"
550     "music-functions.scm"
551     "part-combiner.scm"
552     "autochange.scm"
553     "define-music-properties.scm"
554     "time-signature-settings.scm"
555     "auto-beam.scm"
556     "chord-name.scm"
557     "bezier-tools.scm"
558     "ly-syntax-constructors.scm"
559
560     "define-context-properties.scm"
561     "translation-functions.scm"
562     "script.scm"
563     "midi.scm"
564     "layout-beam.scm"
565     "parser-clef.scm"
566     "layout-slur.scm"
567     "font.scm"
568     "encoding.scm"
569
570     "bar-line.scm"
571     "flag-styles.scm"
572     "fret-diagrams.scm"
573     "tablature.scm"
574     "harp-pedals.scm"
575     "define-woodwind-diagrams.scm"
576     "display-woodwind-diagrams.scm"
577     "predefined-fretboards.scm"
578     "define-grob-properties.scm"
579     "define-grobs.scm"
580     "define-grob-interfaces.scm"
581     "define-stencil-commands.scm"
582     "scheme-engravers.scm"
583     "titling.scm"
584     "text.scm"
585
586     "paper.scm"
587     "backend-library.scm"
588     "x11-color.scm"))
589 ;;  - Files to be loaded last
590 (define init-scheme-files-tail
591   ;;  - must be after everything has been defined
592   '("safe-lily.scm"))
593 ;;
594 ;; Now construct the load list
595 ;;
596 (define init-scheme-files
597   (append init-scheme-files-lib
598           init-scheme-files-used
599           init-scheme-files-body
600           init-scheme-files-tail))
601
602 (for-each ly:load init-scheme-files)
603
604 (define-public r5rs-primary-predicates
605   `((,boolean? . "boolean")
606     (,char? . "character")
607     (,number? . "number")
608     (,pair? . "pair")
609     (,port? . "port")
610     (,procedure? . "procedure")
611     (,string? . "string")
612     (,symbol? . "symbol")
613     (,vector? . "vector")))
614
615 (define-public r5rs-secondary-predicates
616   `((,char-alphabetic? . "alphabetic character")
617     (,char-lower-case? . "lower-case character")
618     (,char-numeric? . "numeric character")
619     (,char-upper-case? . "upper-case character")
620     (,char-whitespace? . "whitespace character")
621
622     (,complex? . "complex number")
623     (,even? . "even number")
624     (,exact? . "exact number")
625     (,inexact? . "inexact number")
626     (,integer? . "integer")
627     (,negative? . "negative number")
628     (,odd? . "odd number")
629     (,positive? . "positive number")
630     (,rational? . "rational number")
631     (,real? . "real number")
632     (,zero? . "zero")
633
634     (,list? . "list")
635     (,null? . "null")
636
637     (,input-port? . "input port")
638     (,output-port? . "output port")
639
640     ;; would this ever be used?
641     (,eof-object? . "end-of-file object")
642     ))
643
644 (define-public guile-predicates
645   `((,hash-table? . "hash table")
646     ))
647
648 (define-public lilypond-scheme-predicates
649   `((,boolean-or-symbol? . "boolean or symbol")
650     (,color? . "color")
651     (,cheap-list? . "list")
652     (,fraction? . "fraction, as pair")
653     (,grob-list? . "list of grobs")
654     (,index? . "non-negative integer")
655     (,markup? . "markup")
656     (,markup-command-list? . "markup command list")
657     (,markup-list? . "markup list")
658     (,moment-pair? . "pair of moment objects")
659     (,number-list? . "number list")
660     (,number-or-grob? . "number or grob")
661     (,number-or-markup? . "number or markup")
662     (,number-or-pair? . "number or pair")
663     (,number-or-string? . "number or string")
664     (,number-pair? . "pair of numbers")
665     (,rhythmic-location? . "rhythmic location")
666     (,scheme? . "any type")
667     (,string-or-pair? . "string or pair")
668     (,string-or-music? . "string or music")
669     (,string-or-symbol? . "string or symbol")
670     (,symbol-list? . "symbol list")
671     (,symbol-list-or-music? . "symbol list or music")
672     (,symbol-list-or-symbol? . "symbol list or symbol")
673     (,void? . "void")
674     ))
675
676 (define-public lilypond-exported-predicates
677   `((,ly:book? . "book")
678     (,ly:box? . "box")
679     (,ly:context? . "context")
680     (,ly:context-def? . "context definition")
681     (,ly:context-mod? . "context modification")
682     (,ly:dimension? . "dimension, in staff space")
683     (,ly:dir? . "direction")
684     (,ly:dispatcher? . "dispatcher")
685     (,ly:duration? . "duration")
686     (,ly:event? . "post event")
687     (,ly:font-metric? . "font metric")
688     (,ly:grob? . "graphical (layout) object")
689     (,ly:grob-array? . "array of grobs")
690     (,ly:input-location? . "input location")
691     (,ly:item? . "item")
692     (,ly:iterator? . "iterator")
693     (,ly:lily-lexer? . "lily-lexer")
694     (,ly:lily-parser? . "lily-parser")
695     (,ly:listener? . "listener")
696     (,ly:moment? . "moment")
697     (,ly:music? . "music")
698     (,ly:music-function? . "music function")
699     (,ly:music-list? . "list of music objects")
700     (,ly:music-output? . "music output")
701     (,ly:otf-font? . "OpenType font")
702     (,ly:output-def? . "output definition")
703     (,ly:page-marker? . "page marker")
704     (,ly:pango-font? . "pango font")
705     (,ly:paper-book? . "paper book")
706     (,ly:paper-system? . "paper-system Prob")
707     (,ly:pitch? . "pitch")
708     (,ly:prob? . "property object")
709     (,ly:score? . "score")
710     (,ly:simple-closure? . "simple closure")
711     (,ly:skyline? . "skyline")
712     (,ly:skyline-pair? . "pair of skylines")
713     (,ly:source-file? . "source file")
714     (,ly:spanner? . "spanner")
715     (,ly:spring? . "spring")
716     (,ly:stencil? . "stencil")
717     (,ly:stream-event? . "stream event")
718     (,ly:translator? . "translator")
719     (,ly:translator-group? . "translator group")
720     (,ly:unpure-pure-container? . "unpure/pure container")
721     ))
722
723
724 (set! type-p-name-alist
725       (append r5rs-primary-predicates
726               r5rs-secondary-predicates
727               guile-predicates
728               lilypond-scheme-predicates
729               lilypond-exported-predicates))
730
731
732 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
733 ;; timing
734
735 (define (profile-measurements)
736   (let* ((t (times))
737          (stats (gc-stats)))
738     (list (- (+ (tms:cutime t)
739                 (tms:utime t))
740              (assoc-get 'gc-time-taken stats))
741           (assoc-get 'total-cells-allocated  stats 0))))
742
743 (define (dump-profile base last this)
744   (let* ((outname (format #f "~a.profile" (dir-basename base ".ly")))
745          (diff (map (lambda (y) (apply - y)) (zip this last))))
746     (ly:progress "\nWriting timing to ~a..." outname)
747     (format (open-file outname "w")
748             "time: ~a\ncells: ~a\n"
749             (if (ly:get-option 'dump-cpu-profile)
750                 (car diff)
751                 0)
752             (cadr diff))))
753
754 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
755 ;; debug memory leaks
756
757 (define gc-dumping
758   #f)
759
760 (define gc-protect-stat-count
761   0)
762
763 ;; Undead objects that should be ignored after the first time round
764 (define gc-zombies
765   (make-weak-key-hash-table 0))
766
767 (define-public (dump-live-object-stats outfile)
768   (for-each (lambda (x)
769               (format outfile "~a: ~a\n" (car x) (cdr x)))
770             (sort (gc-live-object-stats)
771                   (lambda (x y)
772                     (string<? (car x) (car y))))))
773
774 (define-public (dump-gc-protects)
775   (set! gc-protect-stat-count (1+ gc-protect-stat-count))
776   (let* ((protects (sort (hash-table->alist (ly:protects))
777                          (lambda (a b)
778                            (< (object-address (car a))
779                               (object-address (car b))))))
780          (out-file-name (string-append
781                          "gcstat-" (number->string gc-protect-stat-count)
782                          ".scm"))
783          (outfile (open-file out-file-name "w")))
784     (set! gc-dumping #t)
785     (ly:progress "Dumping GC statistics ~a...\n" out-file-name)
786     (for-each (lambda (y)
787                 (let ((x (car y))
788                       (c (cdr y)))
789                   (format outfile "~a (~a) = ~a\n" (object-address x) c x)))
790               (filter
791                (lambda (x)
792                  (not (symbol? (car x))))
793                protects))
794     (format outfile "\nprotected symbols: ~a\n"
795             (apply + (map (lambda (obj-count)
796                             (if (symbol? (car obj-count))
797                                 (cdr obj-count)
798                                 0))
799                           protects)))
800
801     ;; (display (ly:smob-protects))
802     (newline outfile)
803     (if (defined? 'gc-live-object-stats)
804         (let* ((stats #f))
805           (ly:progress "Live object statistics: GC'ing\n")
806           (ly:reset-all-fonts)
807           (gc)
808           (gc)
809           (ly:progress "Asserting dead objects\n")
810           (ly:set-option 'debug-gc-assert-parsed-dead #t)
811           (gc)
812           (ly:set-option 'debug-gc-assert-parsed-dead #f)
813           (for-each
814            (lambda (x)
815              (if (not (hashq-ref gc-zombies x))
816                  (begin
817                    (ly:programming-error "Parsed object should be dead: ~a" x)
818                    (hashq-set! gc-zombies x #t))))
819            (ly:parsed-undead-list!))
820           (set! stats (gc-live-object-stats))
821           (ly:progress "Dumping live object statistics.\n")
822           (dump-live-object-stats outfile)))
823     (newline outfile)
824     (let* ((stats (gc-stats)))
825       (for-each (lambda (sym)
826                   (format outfile "~a ~a ~a\n"
827                           gc-protect-stat-count
828                           sym
829                           (assoc-get sym stats "?")))
830                 '(protected-objects bytes-malloced cell-heap-size)))
831     (set! gc-dumping #f)
832     (close-port outfile)))
833
834 (define (check-memory)
835   "Read `/proc/self' to check up on memory use."
836   (define (gulp-file name)
837     (let* ((file (open-input-file name))
838            (text (read-delimited "" file)))
839       (close file)
840       text))
841
842   (let* ((stat (gulp-file "/proc/self/status"))
843          (lines (string-split stat #\newline))
844          (interesting (filter identity
845                               (map
846                                (lambda (l)
847                                  (string-match "^VmData:[ \t]*([0-9]*) kB" l))
848                                lines)))
849          (mem (string->number (match:substring (car interesting) 1))))
850     (format #t "VMDATA: ~a\n" mem)
851     (display (gc-stats))
852     (newline)
853     (if (> mem 500000)
854         (begin (dump-gc-protects)
855                (raise 1)))))
856
857 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
858
859 (define (multi-fork count)
860   "Split this process into COUNT helpers.  Returns either a list of
861 PIDs or the number of the process."
862   (define (helper count acc)
863     (if (> count 0)
864         (let* ((pid (primitive-fork)))
865           (if (= pid 0)
866               (1- count)
867               (helper (1- count) (cons pid acc))))
868         acc))
869
870   (helper count '()))
871
872 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
873
874 (define* (ly:exit status #:optional (silently #f))
875   "Exit function for lilypond"
876   (if (not silently)
877       (case status
878         ((0) (ly:basic-progress (_ "Success: compilation successfully completed")))
879         ((1) (ly:warning (_ "Compilation completed with warnings or errors")))
880         (else (ly:message ""))))
881   (exit status))
882
883 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
884
885 (define-public (lilypond-main files)
886   "Entry point for LilyPond."
887   (eval-string (ly:command-line-code))
888   (if (ly:get-option 'help)
889       (begin (ly:option-usage)
890              (ly:exit 0 #t)))
891   (if (ly:get-option 'show-available-fonts)
892       (begin (ly:font-config-display-fonts)
893              (ly:exit 0 #t)))
894   (if (ly:get-option 'gui)
895       (gui-main files))
896   (if (null? files)
897       (begin (ly:usage)
898              (ly:exit 2 #t)))
899   (if (ly:get-option 'read-file-list)
900       (set! files
901             (filter (lambda (s)
902                       (> (string-length s) 0))
903                     (apply append
904                            (map (lambda (f)
905                                   (string-split (string-delete (ly:gulp-file f) #\cr) #\nl))
906                                 files)))))
907   (if (and (number? (ly:get-option 'job-count))
908            (>= (length files) (ly:get-option 'job-count)))
909       (let* ((count (ly:get-option 'job-count))
910              (split-todo (split-list files count))
911              (joblist (multi-fork count))
912              (errors '()))
913         (if (not (string-or-symbol? (ly:get-option 'log-file)))
914             (ly:set-option 'log-file "lilypond-multi-run"))
915         (if (number? joblist)
916             (begin (ly:set-option
917                     'log-file (format #f "~a-~a"
918                                       (ly:get-option 'log-file) joblist))
919                    (set! files (vector-ref split-todo joblist)))
920             (begin (ly:progress "\nForking into jobs:  ~a\n" joblist)
921                    (for-each
922                     (lambda (pid)
923                       (let* ((stat (cdr (waitpid pid))))
924                         (if (not (= stat 0))
925                             (set! errors
926                                   (acons (list-element-index joblist pid)
927                                          stat errors)))))
928                     joblist)
929                    (for-each
930                     (lambda (x)
931                       (let* ((job (car x))
932                              (state (cdr x))
933                              (logfile (format #f "~a-~a.log"
934                                               (ly:get-option 'log-file) job))
935                              (log (ly:gulp-file logfile))
936                              (len (string-length log))
937                              (tail (substring  log (max 0 (- len 1024)))))
938                         (if (status:term-sig state)
939                             (ly:message
940                              "\n\n~a\n"
941                              (format #f (_ "job ~a terminated with signal: ~a")
942                                      job (status:term-sig state)))
943                             (ly:message
944                              (_ "logfile ~a (exit ~a):\n~a")
945                              logfile (status:exit-val state) tail))))
946                     errors)
947                    (if (pair? errors)
948                        (ly:error "Children ~a exited with errors."
949                                  (map car errors)))
950                    ;; must overwrite individual entries
951                    (if (ly:get-option 'dump-profile)
952                        (dump-profile "lily-run-total"
953                                      '(0 0) (profile-measurements)))
954                    (if (null? errors)
955                        (ly:exit 0 #f)
956                        (ly:exit 1 #f))))))
957
958   (if (string-or-symbol? (ly:get-option 'log-file))
959       (ly:stderr-redirect (format #f "~a.log" (ly:get-option 'log-file)) "w"))
960   (let ((failed (lilypond-all files)))
961     (if (ly:get-option 'trace-scheme-coverage)
962         (begin
963           (coverage:show-all (lambda (f)
964                                (string-contains f "lilypond")))))
965     (if (pair? failed)
966         (begin (ly:error (_ "failed files: ~S") (string-join failed))
967                (ly:exit 1 #f))
968         (begin
969           (ly:exit 0 #f)))))
970
971
972 (define-public (lilypond-all files)
973   (let* ((failed '())
974          (separate-logs (ly:get-option 'separate-log-files))
975          (ping-log
976           (and separate-logs
977                (if (string-or-symbol? (ly:get-option 'log-file))
978                    (open-file (format #f "~a.log" (ly:get-option 'log-file))
979                               "a")
980                    (fdes->outport 2))))
981          (do-measurements (ly:get-option 'dump-profile))
982          (handler (lambda (key failed-file)
983                     (set! failed (append (list failed-file) failed)))))
984     (gc)
985     (for-each
986      (lambda (x)
987        (let* ((start-measurements (if do-measurements
988                                       (profile-measurements)
989                                       #f))
990               (base (dir-basename x ".ly"))
991               (all-settings (ly:all-options)))
992          (if separate-logs
993              (ly:stderr-redirect (format #f "~a.log" base) "w"))
994          (if ping-log
995              (format ping-log "Processing ~a\n" base))
996          (if (ly:get-option 'trace-memory-frequency)
997              (mtrace:start-trace  (ly:get-option 'trace-memory-frequency)))
998          (lilypond-file handler x)
999          (ly:check-expected-warnings)
1000          (session-terminate)
1001          (if start-measurements
1002              (dump-profile x start-measurements (profile-measurements)))
1003          (if (ly:get-option 'trace-memory-frequency)
1004              (begin (mtrace:stop-trace)
1005                     (mtrace:dump-results base)))
1006          (for-each (lambda (s)
1007                      (ly:set-option (car s) (cdr s)))
1008                    all-settings)
1009          (ly:set-option 'debug-gc-assert-parsed-dead #t)
1010          (gc)
1011          (ly:set-option 'debug-gc-assert-parsed-dead #f)
1012          (for-each
1013           (lambda (x)
1014             (if (not (hashq-ref gc-zombies x))
1015                 (begin
1016                   (ly:programming-error "Parsed object should be dead: ~a" x)
1017                   (hashq-set! gc-zombies x #t))))
1018           (ly:parsed-undead-list!))
1019          (if (ly:get-option 'debug-gc)
1020              (dump-gc-protects)
1021              (ly:reset-all-fonts))
1022          (flush-all-ports)))
1023      files)
1024
1025     ;; Ensure a notice re failed files is written to aggregate logfile.
1026     (if ping-log
1027         (format ping-log "Failed files: ~a\n" failed))
1028     (if (ly:get-option 'dump-profile)
1029         (dump-profile "lily-run-total" '(0 0) (profile-measurements)))
1030     failed))
1031
1032 (define (lilypond-file handler file-name)
1033   (catch 'ly-file-failed
1034          (lambda () (ly:parse-file file-name))
1035          (lambda (x . args) (handler x file-name))))
1036
1037 (use-modules (scm editor))
1038
1039 (define-public (gui-main files)
1040   (if (null? files)
1041       (gui-no-files-handler))
1042   (if (not (string? (ly:get-option 'log-file)))
1043       (let* ((base (dir-basename (car files) ".ly"))
1044              (log-name (string-append base ".log")))
1045         (if (not (ly:get-option 'gui))
1046             (ly:message (_ "Redirecting output to ~a...") log-name))
1047         (ly:stderr-redirect log-name "w")
1048         (ly:message "# -*-compilation-*-"))
1049       (let ((failed (lilypond-all files)))
1050         (if (pair? failed)
1051             (begin
1052               ;; ugh
1053               (ly:stderr-redirect "foo" "r")
1054               (system (get-editor-command log-name 0 0 0))
1055               (ly:error (_ "failed files: ~S") (string-join failed))
1056               ;; not reached?
1057               (exit 1))
1058             (ly:exit 0 #f)))))
1059
1060 (define (gui-no-files-handler)
1061   (let* ((ly (string-append (ly:effective-prefix) "/ly/"))
1062          ;; FIXME: soft-code, localize
1063          (welcome-ly (string-append ly "Welcome_to_LilyPond.ly"))
1064          (cmd (get-editor-command welcome-ly 0 0 0)))
1065     (ly:message (_ "Invoking `~a'...\n") cmd)
1066     (system cmd)
1067     (ly:exit 1 #f)))