From: Reinhold Kainhofer Date: Fri, 9 Sep 2011 16:46:25 +0000 (+0200) Subject: Fix 380: Auto-detect all cyclic references in markups X-Git-Tag: release/2.15.12-1~9 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=e2ebf5785dd8eb5b195b614e7dca4f2a19363fc0;p=lilypond.git Fix 380: Auto-detect all cyclic references in markups Use a hare+tortoise-like algorithm to detect cyclic references in markups. --- diff --git a/input/regression/header-cyclic-reference.ly b/input/regression/header-cyclic-reference.ly new file mode 100644 index 0000000000..03bd5c3f60 --- /dev/null +++ b/input/regression/header-cyclic-reference.ly @@ -0,0 +1,15 @@ +\version "2.15.11" +#(ly:set-option 'warning-as-error #f) + +\header { + texidoc = "Cyclic references in header fields should cause a warning, but +not crash LilyPond with an endless loop" + + title = \markup {Cyclic reference to \fromproperty #'header:title } + + composer = \markup {Cyclic reference to \fromproperty #'header:temp } + temp = \markup {Cyclic reference to \fromproperty #'header:composer } +} +\score { + { c' d' e' f' } +} diff --git a/input/regression/markup-cyclic-reference.ly b/input/regression/markup-cyclic-reference.ly new file mode 100644 index 0000000000..f4495db1ce --- /dev/null +++ b/input/regression/markup-cyclic-reference.ly @@ -0,0 +1,24 @@ +\version "2.15.11" +#(ly:set-option 'warning-as-error #f) + +\header { + texidoc = "Cyclic markup definitions should cause a warning, but +not crash LilyPond with an endless loop" +} + +% A simple markup function that calls itself in a loop. +#(define-markup-command (cycle layout props m) + (markup?) + (interpret-markup layout props (make-cycle-markup m))) + +% Two simple markup functions that call each other in a loop. +#(define-markup-command (cycleI layout props m) + (markup?) + (interpret-markup layout props (make-cycleII-markup m))) +#(define-markup-command (cycleII layout props m) + (markup?) + (interpret-markup layout props (make-cycleI-markup m))) + + +\markup { \cycle "a" } +\markup { \cycleI "a" } diff --git a/lily/text-interface.cc b/lily/text-interface.cc index 8071df3cb8..5bd13641d7 100644 --- a/lily/text-interface.cc +++ b/lily/text-interface.cc @@ -101,7 +101,27 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup) if (!is_markup (markup)) programming_error ("markup head has no markup signature"); - return scm_apply_2 (func, layout_smob, props, args); + /* Use a hare/tortoise algorithm to detect whether we are in a cycle, + * i.e. whether we have already encountered the same markup in the + * current branch of the markup tree structure. */ + static vector encountered_markups; + size_t depth = encountered_markups.size (); + if (depth > 0) + { + int slow = depth / 2; + if (ly_is_equal (encountered_markups[slow], markup)) + { + string name = ly_symbol2string (scm_procedure_name (func)); + // TODO: Also print the arguments of the markup! + non_fatal_error (_f("Cyclic markup detected: %s", name)); + return Stencil().smobbed_copy (); + } + } + + encountered_markups.push_back (markup); + SCM retval = scm_apply_2 (func, layout_smob, props, args); + encountered_markups.pop_back (); + return retval; } else {