You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
566 lines
16 KiB
566 lines
16 KiB
5 years ago
|
//========= 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 <class O, class I>
|
||
|
O RE_CALL re_copy_out(O out, I first, I last)
|
||
|
{
|
||
|
while(first != last)
|
||
|
{
|
||
|
*out = *first;
|
||
|
++out;
|
||
|
++first;
|
||
|
}
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
template <class charT>
|
||
|
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<charT> re_traits_type;
|
||
|
#else
|
||
|
typedef typename char_regex_traits<charT> 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 <class T>
|
||
|
inline void oi_assign(T* p, T v)
|
||
|
{
|
||
|
jm_destroy(p);
|
||
|
jm_construct(p, v);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
template <class T>
|
||
|
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 <class OutputIterator, class iterator, class Allocator, class charT>
|
||
|
OutputIterator RE_CALL __reg_format_aux(OutputIterator out,
|
||
|
const reg_match<iterator, Allocator>& 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<charT> re_traits_type;
|
||
|
#else
|
||
|
typedef typename char_regex_traits<charT> 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 <class OutputIterator, class iterator, class Allocator, class charT>
|
||
|
OutputIterator RE_CALL reg_format(OutputIterator out,
|
||
|
const reg_match<iterator, Allocator>& 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<charT> locale_initialiser;
|
||
|
locale_initialiser.update();
|
||
|
#else
|
||
|
if(JM_HAS_FACET(locale_inst, regfacet<charT>) == false)
|
||
|
{
|
||
|
#ifdef _MSC_VER
|
||
|
locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet<charT>());
|
||
|
#else
|
||
|
locale_inst = __JM_STD::locale(locale_inst, new regfacet<charT>());
|
||
|
#endif
|
||
|
}
|
||
|
JM_USE_FACET(locale_inst, regfacet<charT>).update(locale_inst);
|
||
|
#endif
|
||
|
return __reg_format_aux(out, m, fmt, false MAYBE_PASS_LOCALE(locale_inst));
|
||
|
}
|
||
|
|
||
|
template <class S>
|
||
|
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 <class iterator, class Allocator, class charT>
|
||
|
__JM_STD::basic_string<charT> RE_CALL reg_format(const reg_match<iterator, Allocator>& m, const charT* fmt
|
||
|
#ifdef RE_LOCALE_CPP
|
||
|
, __JM_STD::locale locale_inst = __JM_STD::locale()
|
||
|
#endif
|
||
|
)
|
||
|
{
|
||
|
__JM_STD::basic_string<charT> result;
|
||
|
string_out_iterator<__JM_STD::basic_string<charT> > i(result);
|
||
|
reg_format(i, m, fmt MAYBE_PASS_LOCALE(locale_inst));
|
||
|
return result;
|
||
|
}
|
||
|
#elif !defined(JM_NO_STRING_H)
|
||
|
template <class iterator, class Allocator>
|
||
|
__JM_STD::string RE_CALL reg_format(const reg_match<iterator, Allocator>& 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 OutputIterator, class iterator, class charT, class Allocator>
|
||
|
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<iterator, Allocator>& 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 <class OutputIterator, class iterator, class traits, class Allocator, class charT>
|
||
|
OutputIterator RE_CALL reg_merge(OutputIterator out,
|
||
|
iterator first,
|
||
|
iterator last,
|
||
|
const reg_expression<charT, traits, Allocator>& 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<charT> locale_initialiser;
|
||
|
locale_initialiser.update();
|
||
|
#else
|
||
|
__JM_STD::locale locale_inst(e.locale());
|
||
|
if(JM_HAS_FACET(locale_inst, regfacet<charT>) == false)
|
||
|
{
|
||
|
#ifdef _MSC_VER
|
||
|
locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet<charT>());
|
||
|
#else
|
||
|
locale_inst = __JM_STD::locale(locale_inst, new regfacet<charT>());
|
||
|
#endif
|
||
|
}
|
||
|
JM_USE_FACET(locale_inst, regfacet<charT>).update(locale_inst);
|
||
|
#endif
|
||
|
iterator l = first;
|
||
|
merge_out_predicate<OutputIterator, iterator, charT, Allocator> 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 <class traits, class Allocator, class charT>
|
||
|
__JM_STD::basic_string<charT> RE_CALL reg_merge(const __JM_STD::basic_string<charT>& s,
|
||
|
const reg_expression<charT, traits, Allocator>& e,
|
||
|
const charT* fmt,
|
||
|
bool copy = true,
|
||
|
unsigned int flags = match_default)
|
||
|
{
|
||
|
__JM_STD::basic_string<charT> result;
|
||
|
string_out_iterator<__JM_STD::basic_string<charT> > i(result);
|
||
|
reg_merge(i, s.begin(), s.end(), e, fmt, copy, flags);
|
||
|
return result;
|
||
|
}
|
||
|
#elif !defined(JM_NO_STRING_H)
|
||
|
template <class traits, class Allocator>
|
||
|
__JM_STD::string RE_CALL reg_merge(const __JM_STD::string& s,
|
||
|
const reg_expression<char, traits, Allocator>& 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
|
||
|
|
||
|
|
||
|
|