X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;ds=sidebyside;f=lily%2Ftext-interface.cc;h=c406beaab5436a9a053883651ff02d1b5364ed87;hb=7e3df6b879dcd850a4e7645b1afc151111c77436;hp=5bd13641d737d3bb25dcd08cb6cc3d411a581b8b;hpb=e2ebf5785dd8eb5b195b614e7dca4f2a19363fc0;p=lilypond.git diff --git a/lily/text-interface.cc b/lily/text-interface.cc index 5bd13641d7..c406beaab5 100644 --- a/lily/text-interface.cc +++ b/lily/text-interface.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1998--2011 Han-Wen Nienhuys + Copyright (C) 1998--2012 Han-Wen Nienhuys Jan Nieuwenhuizen LilyPond is free software: you can redistribute it and/or modify @@ -19,7 +19,9 @@ */ #include "text-interface.hh" +#include "skyline-pair.hh" +#include "lookup.hh" #include "config.hh" #include "font-interface.hh" #include "grob.hh" @@ -28,26 +30,39 @@ #include "modified-font-metric.hh" #include "output-def.hh" #include "pango-font.hh" +#include "program-option.hh" #include "international.hh" #include "warn.hh" static void -replace_whitespace (string *str) +replace_special_characters (string &str, SCM props) { - vsize i = 0; - vsize n = str->size (); + SCM replacement_alist = ly_chain_assoc_get (ly_symbol2scm ("replacement-alist"), + props, + SCM_EOL); - while (i < n) + int max_length = 0; + for (SCM s = replacement_alist; scm_is_pair (s); s = scm_cdr (s)) { - char cur = (*str)[i]; - - // avoid the locale-dependent isspace - if (cur == '\n' || cur == '\t' || cur == '\v') - (*str)[i] = ' '; - - vsize char_len = utf8_char_len (cur); + max_length = max (max_length, scm_to_int + (scm_string_length (scm_caar (s)))); + } - i += char_len; + for (vsize i = 0; i < str.size (); i++) + { + /* Don't match in mid-UTF-8 */ + if ((str[i] & 0xc0) == 0x80) + continue; + for (vsize j = max_length + 1; j--;) + { + if (j > str.size () - i) + continue; + string dummy = str.substr (i, j); + SCM ligature = ly_assoc_get (ly_string2scm (dummy), + replacement_alist, SCM_BOOL_F); + if (scm_is_true (ligature)) + str.replace (i, j, robust_scm2string (ligature, "")); + } } } @@ -64,7 +79,7 @@ Text_interface::interpret_string (SCM layout_smob, Output_def *layout = unsmob_output_def (layout_smob); Font_metric *fm = select_encoded_font (layout, props); - replace_whitespace (&str); + replace_special_characters (str, props); /* We want to filter strings with a music font that pass through @@ -94,12 +109,10 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup) { if (scm_is_string (markup)) return interpret_string (layout_smob, props, markup); - else if (scm_is_pair (markup)) + else if (is_markup (markup)) { SCM func = scm_car (markup); SCM args = scm_cdr (markup); - if (!is_markup (markup)) - programming_error ("markup head has no markup signature"); /* 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 @@ -113,11 +126,24 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM 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 (); + non_fatal_error (_f ("Cyclic markup detected: %s", name)); + return Stencil ().smobbed_copy (); } } + /* Check for non-terminating markups, e.g. recursive calls with + * changing arguments */ + SCM opt_depth = ly_get_option (ly_symbol2scm ("max-markup-depth")); + size_t max_depth = robust_scm2int (opt_depth, 1024); + if (depth > max_depth) + { + string name = ly_symbol2string (scm_procedure_name (func)); + // TODO: Also print the arguments of the markup! + non_fatal_error (_f ("Markup depth exceeds maximal value of %d; " + "Markup: %s", max_depth, name.c_str ())); + return Stencil ().smobbed_copy (); + } + encountered_markups.push_back (markup); SCM retval = scm_apply_2 (func, layout_smob, props, args); encountered_markups.pop_back (); @@ -125,7 +151,7 @@ Text_interface::interpret_markup (SCM layout_smob, SCM props, SCM markup) } else { - programming_error ("Object is not a markup. "); + programming_error ("Object is not a markup."); scm_puts ("This object should be a markup: ", scm_current_error_port ()); scm_display (markup, scm_current_error_port ()); scm_puts ("\n", scm_current_error_port ()); @@ -149,11 +175,14 @@ Text_interface::print (SCM grob) bool Text_interface::is_markup (SCM x) { - return (scm_is_string (x) - || (scm_is_pair (x) - && SCM_BOOL_F - != scm_object_property (scm_car (x), - ly_symbol2scm ("markup-signature")))); + return scm_is_string (x) + || (scm_is_pair (x) + && scm_is_true + (scm_object_property (scm_car (x), + ly_symbol2scm ("markup-signature"))) + && scm_is_false + (scm_object_property (scm_car (x), + ly_symbol2scm ("markup-list-command")))); } bool @@ -174,6 +203,7 @@ ADD_INTERFACE (Text_interface, /* properties */ "baseline-skip " + "replacement-alist " "text " "word-space " "text-direction "