//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// /* * * Copyright (c) 1998-9 * Dr John Maddock * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Dr John Maddock makes no representations * about the suitability of this software for any purpose. * It is provided "as is" without express or implied warranty. * */ /* * FILE regfmt.h * VERSION 2.12 * * Provides formatting output routines for search and replace * operations. Note this is an internal header file included * by regex.h, do not include on its own. */ #ifndef REGFMT_H #define REGFMT_H JM_NAMESPACE(__JM) template O RE_CALL re_copy_out(O out, I first, I last) { while(first != last) { *out = *first; ++out; ++first; } return out; } template void RE_CALL re_skip_format(const charT*& fmt #ifdef RE_LOCALE_CPP , const __JM_STD::locale& l #endif ) { #ifdef JM_NO_TEMPLATE_TYPENAME typedef char_regex_traits re_traits_type; #else typedef typename char_regex_traits re_traits_type; #endif unsigned int parens = 0; unsigned int c; while(*fmt) { c = re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)); if((c == syntax_colon) && (parens == 0)) { ++fmt; return; } else if(c == syntax_close_bracket) { if(parens == 0) { ++fmt; return; } --parens; } else if(c == syntax_open_bracket) ++parens; else if(c == syntax_slash) { ++fmt; if(*fmt == 0) return; } ++fmt; } } #ifdef JM_NO_OI_ASSIGN // // ugly hack for buggy output iterators template inline void oi_assign(T* p, T v) { jm_destroy(p); jm_construct(p, v); } #else template inline void oi_assign(T* p, T v) { // // if you get a compile time error in here then you either // need to rewrite your output iterator to make it assignable // (as is required by the standard), or define JM_NO_OI_ASSIGN // to use the ugly hack above *p = v; } #endif #if defined(JM_NO_TEMPLATE_SWITCH_MERGE) && !defined(JM_NO_NAMESPACES) // // Ugly ugly hack, // template don't merge if they contain switch statements so declare these // templates in unnamed namespace (ie with internal linkage), each translation // unit then gets its own local copy, it works seemlessly but bloats the app. namespace{ #endif // // algorithm reg_format: // takes the result of a match and a format string // and merges them to produce a new string which // is sent to an OutputIterator, // __reg_format_aux does the actual work: // template OutputIterator RE_CALL __reg_format_aux(OutputIterator out, const reg_match& m, const charT*& fmt, bool isif #ifdef RE_LOCALE_CPP , const __JM_STD::locale& l #endif ) { #ifdef JM_NO_TEMPLATE_TYPENAME typedef char_regex_traits re_traits_type; #else typedef typename char_regex_traits re_traits_type; #endif const charT* fmt_end = fmt; while(*fmt_end) ++ fmt_end; while(*fmt) { switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l))) { case syntax_dollar: ++fmt; if(*fmt == 0) // oops trailing $ { --fmt; *out = *fmt; ++out; return out; } switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l))) { case syntax_start_buffer: oi_assign(&out, re_copy_out(out, iterator(m[-1].first), iterator(m[-1].second))); ++fmt; continue; case syntax_end_buffer: oi_assign(&out, re_copy_out(out, iterator(m[-2].first), iterator(m[-2].second))); ++fmt; continue; case syntax_digit: { unsigned int index = re_traits_type::toi(fmt, fmt_end, 10 MAYBE_PASS_LOCALE(l)); oi_assign(&out, re_copy_out(out, iterator(m[index].first), iterator(m[index].second))); continue; } } // anything else: if(*fmt == '&') { oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second))); ++fmt; } else { // probably an error, treat as a literal '$' --fmt; *out = *fmt; ++out; ++fmt; } continue; case syntax_slash: { // escape sequence: charT c; ++fmt; if(*fmt == 0) { --fmt; *out = *fmt; ++out; ++fmt; return out; } switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l))) { case syntax_a: c = '\a'; ++fmt; break; case syntax_f: c = '\f'; ++fmt; break; case syntax_n: c = '\n'; ++fmt; break; case syntax_r: c = '\r'; ++fmt; break; case syntax_t: c = '\t'; ++fmt; break; case syntax_v: c = '\v'; ++fmt; break; case syntax_x: ++fmt; if(fmt == fmt_end) { *out = *--fmt; ++out; return out; } // maybe have \x{ddd} if(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) == syntax_open_brace) { ++fmt; if(fmt == fmt_end) { fmt -= 2; *out = *fmt; ++out; ++fmt; continue; } if(re_traits_type::is_class(*fmt, char_class_xdigit MAYBE_PASS_LOCALE(l)) == false) { fmt -= 2; *out = *fmt; ++out; ++fmt; continue; } c = (charT)re_traits_type::toi(fmt, fmt_end, -16 MAYBE_PASS_LOCALE(l)); if(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) != syntax_close_brace) { while(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) != syntax_slash) --fmt; ++fmt; *out = *fmt; ++out; ++fmt; continue; } ++fmt; break; } else { if(re_traits_type::is_class(*fmt, char_class_xdigit MAYBE_PASS_LOCALE(l)) == false) { --fmt; *out = *fmt; ++out; ++fmt; continue; } c = (charT)re_traits_type::toi(fmt, fmt_end, -16 MAYBE_PASS_LOCALE(l)); } break; case syntax_c: ++fmt; if(fmt == fmt_end) { --fmt; *out = *fmt; ++out; return out; } if(((typename re_traits_type::uchar_type)(*fmt) < (typename re_traits_type::uchar_type)'@') || ((typename re_traits_type::uchar_type)(*fmt) > (typename re_traits_type::uchar_type)127) ) { --fmt; *out = *fmt; ++out; ++fmt; break; } c = (charT)((typename re_traits_type::uchar_type)(*fmt) - (typename re_traits_type::uchar_type)'@'); ++fmt; break; case syntax_e: c = (charT)27; ++fmt; break; case syntax_digit: c = (charT)re_traits_type::toi(fmt, fmt_end, -8 MAYBE_PASS_LOCALE(l)); break; default: c = *fmt; ++fmt; } *out = c; continue; } case syntax_open_bracket: ++fmt; // recurse oi_assign(&out, __reg_format_aux(out, m, fmt, false MAYBE_PASS_LOCALE(l))); continue; case syntax_close_bracket: ++fmt; // return from recursion return out; case syntax_colon: if(isif) { ++fmt; return out; } *out = *fmt; ++out; ++fmt; continue; case syntax_question: { ++fmt; if(*fmt == 0) { --fmt; *out = *fmt; ++out; ++fmt; return out; } unsigned int id = re_traits_type::toi(fmt, fmt_end, 10 MAYBE_PASS_LOCALE(l)); if(m[id].matched) { oi_assign(&out, __reg_format_aux(out, m, fmt, true MAYBE_PASS_LOCALE(l))); if(re_traits_type::syntax_type(*(fmt-1) MAYBE_PASS_LOCALE(l)) == syntax_colon) re_skip_format(fmt MAYBE_PASS_LOCALE(l)); } else { re_skip_format(fmt MAYBE_PASS_LOCALE(l)); if(re_traits_type::syntax_type(*(fmt-1) MAYBE_PASS_LOCALE(l)) == syntax_colon) oi_assign(&out, __reg_format_aux(out, m, fmt, true MAYBE_PASS_LOCALE(l))); } return out; } default: *out = *fmt; ++out; ++fmt; } } return out; } #if defined(JM_NO_TEMPLATE_SWITCH_MERGE) && !defined(JM_NO_NAMESPACES) } // namespace #endif template OutputIterator RE_CALL reg_format(OutputIterator out, const reg_match& m, const charT* fmt #ifdef RE_LOCALE_CPP , __JM_STD::locale locale_inst = __JM_STD::locale() #endif ) { // // start by updating the locale: // #if defined(RE_LOCALE_C) || defined(RE_LOCALE_W32) static re_initialiser locale_initialiser; locale_initialiser.update(); #else if(JM_HAS_FACET(locale_inst, regfacet) == false) { #ifdef _MSC_VER locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet()); #else locale_inst = __JM_STD::locale(locale_inst, new regfacet()); #endif } JM_USE_FACET(locale_inst, regfacet).update(locale_inst); #endif return __reg_format_aux(out, m, fmt, false MAYBE_PASS_LOCALE(locale_inst)); } template class string_out_iterator { S* out; public: string_out_iterator(S& s) : out(&s) {} string_out_iterator& operator++() { return *this; } string_out_iterator& operator++(int) { return *this; } string_out_iterator& operator*() { return *this; } string_out_iterator& operator=(typename S::value_type v) { out->append(1, v); return *this; } }; #ifndef JM_NO_STRING_DEF_ARGS template __JM_STD::basic_string RE_CALL reg_format(const reg_match& m, const charT* fmt #ifdef RE_LOCALE_CPP , __JM_STD::locale locale_inst = __JM_STD::locale() #endif ) { __JM_STD::basic_string result; string_out_iterator<__JM_STD::basic_string > i(result); reg_format(i, m, fmt MAYBE_PASS_LOCALE(locale_inst)); return result; } #elif !defined(JM_NO_STRING_H) template __JM_STD::string RE_CALL reg_format(const reg_match& m, const char* fmt #ifdef RE_LOCALE_CPP , __JM_STD::locale locale_inst = __JM_STD::locale() #endif ) { __JM_STD::string result; string_out_iterator<__JM_STD::string> i(result); reg_format(i, m, fmt MAYBE_PASS_LOCALE(locale_inst)); return result; } #endif template class merge_out_predicate { OutputIterator* out; iterator* last; const charT* fmt; bool copy_none; #ifdef RE_LOCALE_CPP const __JM_STD::locale& l; #endif public: merge_out_predicate(OutputIterator& o, iterator& pi, const charT* f, bool c #ifdef RE_LOCALE_CPP , const __JM_STD::locale& loc #endif ) : out(&o), last(&pi), fmt(f), copy_none(c) #ifdef RE_LOCALE_CPP , l(loc) #endif {} ~merge_out_predicate() {} bool RE_CALL operator()(const __JM::reg_match& m) { const charT* f = fmt; if(copy_none) oi_assign(out, re_copy_out(*out, iterator(m[-1].first), iterator(m[-1].second))); oi_assign(out, __reg_format_aux(*out, m, f, false MAYBE_PASS_LOCALE(l))); *last = m[-2].first; return true; } }; template OutputIterator RE_CALL reg_merge(OutputIterator out, iterator first, iterator last, const reg_expression& e, const charT* fmt, bool copy = true, unsigned int flags = match_default) { // // start by updating the locale: // #if defined(RE_LOCALE_C) || defined(RE_LOCALE_W32) static re_initialiser locale_initialiser; locale_initialiser.update(); #else __JM_STD::locale locale_inst(e.locale()); if(JM_HAS_FACET(locale_inst, regfacet) == false) { #ifdef _MSC_VER locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet()); #else locale_inst = __JM_STD::locale(locale_inst, new regfacet()); #endif } JM_USE_FACET(locale_inst, regfacet).update(locale_inst); #endif iterator l = first; merge_out_predicate oi(out, l, fmt, copy MAYBE_PASS_LOCALE(locale_inst)); reg_grep(oi, first, last, e, flags); return copy ? re_copy_out(out, l, last) : out; } #ifndef JM_NO_STRING_DEF_ARGS template __JM_STD::basic_string RE_CALL reg_merge(const __JM_STD::basic_string& s, const reg_expression& e, const charT* fmt, bool copy = true, unsigned int flags = match_default) { __JM_STD::basic_string result; string_out_iterator<__JM_STD::basic_string > i(result); reg_merge(i, s.begin(), s.end(), e, fmt, copy, flags); return result; } #elif !defined(JM_NO_STRING_H) template __JM_STD::string RE_CALL reg_merge(const __JM_STD::string& s, const reg_expression& e, const char* fmt, bool copy = true, unsigned int flags = match_default) { __JM_STD::string result; string_out_iterator<__JM_STD::string> i(result); reg_merge(i, s.begin(), s.end(), e, fmt, copy, flags); return result; } #endif JM_END_NAMESPACE #endif