diff --git a/SConstruct b/SConstruct index 64e43c632..2125b1f25 100644 --- a/SConstruct +++ b/SConstruct @@ -219,6 +219,7 @@ pretty_dep_names = { 'freetype-config':'freetype-config program | try setting FREETYPE_CONFIG SCons option', 'osm':'more info: http://trac.mapnik.org/wiki/OsmPlugin', 'curl':'libcurl is required for the "osm" plugin - more info: http://trac.mapnik.org/wiki/OsmPlugin', + 'boost_regex_icu':'libboost_regex built with optional ICU unicode support is needed for unicode regex support in mapnik.', } def pretty_dep(dep): @@ -786,6 +787,27 @@ int main() if major >= 4 and minor >= 2: return True return False + +def boost_regex_has_icu(context): + ret = context.TryRun(""" + +#include +#include + +int main() +{ + UnicodeString ustr; + boost::u32regex pattern = boost::make_u32regex(ustr); + return 0; +} + +""", '.cpp') + # hack to avoid printed output + context.Message('Checking if boost_regex was built with ICU unicode support... ') + context.Result(ret[0]) + if ret[0]: + return True + return False conf_tests = { 'prioritize_paths' : prioritize_paths, 'CheckPKGConfig' : CheckPKGConfig, @@ -799,7 +821,8 @@ conf_tests = { 'prioritize_paths' : prioritize_paths, 'ogr_enabled' : ogr_enabled, 'get_pkg_lib' : get_pkg_lib, 'rollback_option' : rollback_option, - 'icu_at_least_four_two' : icu_at_least_four_two + 'icu_at_least_four_two' : icu_at_least_four_two, + 'boost_regex_has_icu' : boost_regex_has_icu, } @@ -880,7 +903,7 @@ if not preconfigured: # set any custom cxxflags to come first env.Append(CXXFLAGS = env['CUSTOM_CXXFLAGS']) - + # Solaris & Sun Studio settings (the `SUNCC` flag will only be # set if the `CXX` option begins with `CC`) SOLARIS = env['PLATFORM'] == 'SunOS' @@ -924,6 +947,7 @@ if not preconfigured: env.Append(CXXFLAGS = '-DU_HIDE_DRAFT_API') env.Append(CXXFLAGS = '-DUDISABLE_RENAMING') if os.path.exists(env['ICU_LIB_NAME']): + #-sICU_LINK=" -L/usr/lib -licucore env['ICU_LIB_NAME'] = os.path.basename(env['ICU_LIB_NAME']).replace('.dylib','').replace('lib','') LIBSHEADERS = [ @@ -1017,6 +1041,14 @@ if not preconfigured: else: color_print(4,'Could not find optional header or shared library for boost %s' % libinfo[0]) env['SKIPPED_DEPS'].append('boost ' + libinfo[0]) + + if env['ICU_LIB_NAME'] not in env['MISSING_DEPS']: + # http://lists.boost.org/Archives/boost/2009/03/150076.php + if conf.boost_regex_has_icu(): + # TODO - should avoid having this be globally defined... + env.Append(CXXFLAGS = '-DBOOST_REGEX_HAS_ICU') + else: + env['SKIPPED_DEPS'].append('boost_regex_icu') env['REQUESTED_PLUGINS'] = [ driver.strip() for driver in Split(env['INPUT_PLUGINS'])] diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index 098477130..ad8cfad30 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -27,7 +27,10 @@ // boost #include +//#include +#if defined(BOOST_REGEX_HAS_ICU) #include +#endif namespace mapnik { @@ -76,13 +79,24 @@ struct evaluate : boost::static_visitor value_type operator() (regex_match_node const& x) const { value_type v = boost::apply_visitor(evaluate(feature_),x.expr); +#if defined(BOOST_REGEX_HAS_ICU) return boost::u32regex_match(v.to_unicode(),x.pattern); +#else + return boost::regex_match(v.to_string(),x.pattern); +#endif + } value_type operator() (regex_replace_node const& x) const { value_type v = boost::apply_visitor(evaluate(feature_),x.expr); +#if defined(BOOST_REGEX_HAS_ICU) return boost::u32regex_replace(v.to_unicode(),x.pattern,x.format); +#else + std::string repl = boost::regex_replace(v.to_string(),x.pattern,x.format); + mapnik::transcoder tr_("utf8"); + return tr_.transcode(repl.c_str()); +#endif } feature_type const& feature_; diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index f846850f4..bfb8a22d6 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -87,7 +87,11 @@ struct regex_match_impl template expr_node operator() (T0 & node, T1 const& pattern) const { +#if defined(BOOST_REGEX_HAS_ICU) return regex_match_node(node,tr_.transcode(pattern.c_str())); +#else + return regex_match_node(node,pattern); +#endif } mapnik::transcoder const& tr_; @@ -107,7 +111,11 @@ struct regex_replace_impl template expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const { +#if defined(BOOST_REGEX_HAS_ICU) return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str())); +#else + return regex_replace_node(node,pattern,format); +#endif } mapnik::transcoder const& tr_; diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp index 9b6cab489..e8bbda615 100644 --- a/include/mapnik/expression_node.hpp +++ b/include/mapnik/expression_node.hpp @@ -30,7 +30,9 @@ #include #include #include +#if defined(BOOST_REGEX_HAS_ICU) #include +#endif #include namespace mapnik @@ -225,6 +227,7 @@ struct binary_node expr_node left,right; }; +#if defined(BOOST_REGEX_HAS_ICU) struct regex_match_node { regex_match_node (expr_node const& a, UnicodeString const& ustr) @@ -235,6 +238,7 @@ struct regex_match_node boost::u32regex pattern; }; + struct regex_replace_node { regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f) @@ -246,8 +250,31 @@ struct regex_replace_node boost::u32regex pattern; UnicodeString format; }; +#else +struct regex_match_node +{ + regex_match_node (expr_node const& a, std::string const& str) + : expr(a), + pattern(str) {} + + expr_node expr; + boost::regex pattern; +}; +struct regex_replace_node +{ + regex_replace_node (expr_node const& a, std::string const& str, std::string const& f) + : expr(a), + pattern(str), + format(f) {} + + expr_node expr; + boost::regex pattern; + std::string format; +}; +#endif + struct function_call { template diff --git a/src/expression_string.cpp b/src/expression_string.cpp index 7d231010e..b3d5dcc0b 100644 --- a/src/expression_string.cpp +++ b/src/expression_string.cpp @@ -76,34 +76,38 @@ struct expression_string : boost::static_visitor void operator() (regex_match_node const & x) const { -// TODO - replace with pre ICU 4.2 compatible fromUTF32() -#if (U_ICU_VERSION_MAJOR_NUM >= 4) && (U_ICU_VERSION_MINOR_NUM >=2) boost::apply_visitor(expression_string(str_),x.expr); str_ +=".match('"; +#if defined(BOOST_REGEX_HAS_ICU) std::string utf8; UnicodeString ustr = UnicodeString::fromUTF32( &x.pattern.str()[0] ,x.pattern.str().length()); to_utf8(ustr,utf8); str_ += utf8; - str_ +="')"; +#else + str_ += x.pattern.str(); #endif + str_ +="')"; } void operator() (regex_replace_node const & x) const { -// TODO - replace with pre ICU 4.2 compatible fromUTF32() -#if (U_ICU_VERSION_MAJOR_NUM >= 4) && (U_ICU_VERSION_MINOR_NUM >=2) boost::apply_visitor(expression_string(str_),x.expr); str_ +=".replace("; + str_ += "'"; +#if defined(BOOST_REGEX_HAS_ICU) std::string utf8; UnicodeString ustr = UnicodeString::fromUTF32( &x.pattern.str()[0] ,x.pattern.str().length()); to_utf8(ustr,utf8); - str_ += "'"; str_ += utf8; str_ +="','"; to_utf8(x.format ,utf8); str_ += utf8; - str_ +="')"; +#else + str_ += x.pattern.str(); + str_ +="','"; + str_ += x.pattern.str(); #endif + str_ +="')"; } private: