Team Fortress 2 Source Code as on 22/4/2020
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.

565 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. /*
  9. *
  10. * Copyright (c) 1998-9
  11. * Dr John Maddock
  12. *
  13. * Permission to use, copy, modify, distribute and sell this software
  14. * and its documentation for any purpose is hereby granted without fee,
  15. * provided that the above copyright notice appear in all copies and
  16. * that both that copyright notice and this permission notice appear
  17. * in supporting documentation. Dr John Maddock makes no representations
  18. * about the suitability of this software for any purpose.
  19. * It is provided "as is" without express or implied warranty.
  20. *
  21. */
  22. /*
  23. * FILE regfmt.h
  24. * VERSION 2.12
  25. *
  26. * Provides formatting output routines for search and replace
  27. * operations. Note this is an internal header file included
  28. * by regex.h, do not include on its own.
  29. */
  30. #ifndef REGFMT_H
  31. #define REGFMT_H
  32. JM_NAMESPACE(__JM)
  33. template <class O, class I>
  34. O RE_CALL re_copy_out(O out, I first, I last)
  35. {
  36. while(first != last)
  37. {
  38. *out = *first;
  39. ++out;
  40. ++first;
  41. }
  42. return out;
  43. }
  44. template <class charT>
  45. void RE_CALL re_skip_format(const charT*& fmt
  46. #ifdef RE_LOCALE_CPP
  47. , const __JM_STD::locale& l
  48. #endif
  49. )
  50. {
  51. #ifdef JM_NO_TEMPLATE_TYPENAME
  52. typedef char_regex_traits<charT> re_traits_type;
  53. #else
  54. typedef typename char_regex_traits<charT> re_traits_type;
  55. #endif
  56. unsigned int parens = 0;
  57. unsigned int c;
  58. while(*fmt)
  59. {
  60. c = re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l));
  61. if((c == syntax_colon) && (parens == 0))
  62. {
  63. ++fmt;
  64. return;
  65. }
  66. else if(c == syntax_close_bracket)
  67. {
  68. if(parens == 0)
  69. {
  70. ++fmt;
  71. return;
  72. }
  73. --parens;
  74. }
  75. else if(c == syntax_open_bracket)
  76. ++parens;
  77. else if(c == syntax_slash)
  78. {
  79. ++fmt;
  80. if(*fmt == 0)
  81. return;
  82. }
  83. ++fmt;
  84. }
  85. }
  86. #ifdef JM_NO_OI_ASSIGN
  87. //
  88. // ugly hack for buggy output iterators
  89. template <class T>
  90. inline void oi_assign(T* p, T v)
  91. {
  92. jm_destroy(p);
  93. jm_construct(p, v);
  94. }
  95. #else
  96. template <class T>
  97. inline void oi_assign(T* p, T v)
  98. {
  99. //
  100. // if you get a compile time error in here then you either
  101. // need to rewrite your output iterator to make it assignable
  102. // (as is required by the standard), or define JM_NO_OI_ASSIGN
  103. // to use the ugly hack above
  104. *p = v;
  105. }
  106. #endif
  107. #if defined(JM_NO_TEMPLATE_SWITCH_MERGE) && !defined(JM_NO_NAMESPACES)
  108. //
  109. // Ugly ugly hack,
  110. // template don't merge if they contain switch statements so declare these
  111. // templates in unnamed namespace (ie with internal linkage), each translation
  112. // unit then gets its own local copy, it works seemlessly but bloats the app.
  113. namespace{
  114. #endif
  115. //
  116. // algorithm reg_format:
  117. // takes the result of a match and a format string
  118. // and merges them to produce a new string which
  119. // is sent to an OutputIterator,
  120. // __reg_format_aux does the actual work:
  121. //
  122. template <class OutputIterator, class iterator, class Allocator, class charT>
  123. OutputIterator RE_CALL __reg_format_aux(OutputIterator out,
  124. const reg_match<iterator, Allocator>& m,
  125. const charT*& fmt,
  126. bool isif
  127. #ifdef RE_LOCALE_CPP
  128. , const __JM_STD::locale& l
  129. #endif
  130. )
  131. {
  132. #ifdef JM_NO_TEMPLATE_TYPENAME
  133. typedef char_regex_traits<charT> re_traits_type;
  134. #else
  135. typedef typename char_regex_traits<charT> re_traits_type;
  136. #endif
  137. const charT* fmt_end = fmt;
  138. while(*fmt_end) ++ fmt_end;
  139. while(*fmt)
  140. {
  141. switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)))
  142. {
  143. case syntax_dollar:
  144. ++fmt;
  145. if(*fmt == 0) // oops trailing $
  146. {
  147. --fmt;
  148. *out = *fmt;
  149. ++out;
  150. return out;
  151. }
  152. switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)))
  153. {
  154. case syntax_start_buffer:
  155. oi_assign(&out, re_copy_out(out, iterator(m[-1].first), iterator(m[-1].second)));
  156. ++fmt;
  157. continue;
  158. case syntax_end_buffer:
  159. oi_assign(&out, re_copy_out(out, iterator(m[-2].first), iterator(m[-2].second)));
  160. ++fmt;
  161. continue;
  162. case syntax_digit:
  163. {
  164. unsigned int index = re_traits_type::toi(fmt, fmt_end, 10 MAYBE_PASS_LOCALE(l));
  165. oi_assign(&out, re_copy_out(out, iterator(m[index].first), iterator(m[index].second)));
  166. continue;
  167. }
  168. }
  169. // anything else:
  170. if(*fmt == '&')
  171. {
  172. oi_assign(&out, re_copy_out(out, iterator(m[0].first), iterator(m[0].second)));
  173. ++fmt;
  174. }
  175. else
  176. {
  177. // probably an error, treat as a literal '$'
  178. --fmt;
  179. *out = *fmt;
  180. ++out;
  181. ++fmt;
  182. }
  183. continue;
  184. case syntax_slash:
  185. {
  186. // escape sequence:
  187. charT c;
  188. ++fmt;
  189. if(*fmt == 0)
  190. {
  191. --fmt;
  192. *out = *fmt;
  193. ++out;
  194. ++fmt;
  195. return out;
  196. }
  197. switch(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)))
  198. {
  199. case syntax_a:
  200. c = '\a';
  201. ++fmt;
  202. break;
  203. case syntax_f:
  204. c = '\f';
  205. ++fmt;
  206. break;
  207. case syntax_n:
  208. c = '\n';
  209. ++fmt;
  210. break;
  211. case syntax_r:
  212. c = '\r';
  213. ++fmt;
  214. break;
  215. case syntax_t:
  216. c = '\t';
  217. ++fmt;
  218. break;
  219. case syntax_v:
  220. c = '\v';
  221. ++fmt;
  222. break;
  223. case syntax_x:
  224. ++fmt;
  225. if(fmt == fmt_end)
  226. {
  227. *out = *--fmt;
  228. ++out;
  229. return out;
  230. }
  231. // maybe have \x{ddd}
  232. if(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) == syntax_open_brace)
  233. {
  234. ++fmt;
  235. if(fmt == fmt_end)
  236. {
  237. fmt -= 2;
  238. *out = *fmt;
  239. ++out;
  240. ++fmt;
  241. continue;
  242. }
  243. if(re_traits_type::is_class(*fmt, char_class_xdigit MAYBE_PASS_LOCALE(l)) == false)
  244. {
  245. fmt -= 2;
  246. *out = *fmt;
  247. ++out;
  248. ++fmt;
  249. continue;
  250. }
  251. c = (charT)re_traits_type::toi(fmt, fmt_end, -16 MAYBE_PASS_LOCALE(l));
  252. if(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) != syntax_close_brace)
  253. {
  254. while(re_traits_type::syntax_type(*fmt MAYBE_PASS_LOCALE(l)) != syntax_slash)
  255. --fmt;
  256. ++fmt;
  257. *out = *fmt;
  258. ++out;
  259. ++fmt;
  260. continue;
  261. }
  262. ++fmt;
  263. break;
  264. }
  265. else
  266. {
  267. if(re_traits_type::is_class(*fmt, char_class_xdigit MAYBE_PASS_LOCALE(l)) == false)
  268. {
  269. --fmt;
  270. *out = *fmt;
  271. ++out;
  272. ++fmt;
  273. continue;
  274. }
  275. c = (charT)re_traits_type::toi(fmt, fmt_end, -16 MAYBE_PASS_LOCALE(l));
  276. }
  277. break;
  278. case syntax_c:
  279. ++fmt;
  280. if(fmt == fmt_end)
  281. {
  282. --fmt;
  283. *out = *fmt;
  284. ++out;
  285. return out;
  286. }
  287. if(((typename re_traits_type::uchar_type)(*fmt) < (typename re_traits_type::uchar_type)'@')
  288. || ((typename re_traits_type::uchar_type)(*fmt) > (typename re_traits_type::uchar_type)127) )
  289. {
  290. --fmt;
  291. *out = *fmt;
  292. ++out;
  293. ++fmt;
  294. break;
  295. }
  296. c = (charT)((typename re_traits_type::uchar_type)(*fmt) - (typename re_traits_type::uchar_type)'@');
  297. ++fmt;
  298. break;
  299. case syntax_e:
  300. c = (charT)27;
  301. ++fmt;
  302. break;
  303. case syntax_digit:
  304. c = (charT)re_traits_type::toi(fmt, fmt_end, -8 MAYBE_PASS_LOCALE(l));
  305. break;
  306. default:
  307. c = *fmt;
  308. ++fmt;
  309. }
  310. *out = c;
  311. continue;
  312. }
  313. case syntax_open_bracket:
  314. ++fmt; // recurse
  315. oi_assign(&out, __reg_format_aux(out, m, fmt, false MAYBE_PASS_LOCALE(l)));
  316. continue;
  317. case syntax_close_bracket:
  318. ++fmt; // return from recursion
  319. return out;
  320. case syntax_colon:
  321. if(isif)
  322. {
  323. ++fmt;
  324. return out;
  325. }
  326. *out = *fmt;
  327. ++out;
  328. ++fmt;
  329. continue;
  330. case syntax_question:
  331. {
  332. ++fmt;
  333. if(*fmt == 0)
  334. {
  335. --fmt;
  336. *out = *fmt;
  337. ++out;
  338. ++fmt;
  339. return out;
  340. }
  341. unsigned int id = re_traits_type::toi(fmt, fmt_end, 10 MAYBE_PASS_LOCALE(l));
  342. if(m[id].matched)
  343. {
  344. oi_assign(&out, __reg_format_aux(out, m, fmt, true MAYBE_PASS_LOCALE(l)));
  345. if(re_traits_type::syntax_type(*(fmt-1) MAYBE_PASS_LOCALE(l)) == syntax_colon)
  346. re_skip_format(fmt MAYBE_PASS_LOCALE(l));
  347. }
  348. else
  349. {
  350. re_skip_format(fmt MAYBE_PASS_LOCALE(l));
  351. if(re_traits_type::syntax_type(*(fmt-1) MAYBE_PASS_LOCALE(l)) == syntax_colon)
  352. oi_assign(&out, __reg_format_aux(out, m, fmt, true MAYBE_PASS_LOCALE(l)));
  353. }
  354. return out;
  355. }
  356. default:
  357. *out = *fmt;
  358. ++out;
  359. ++fmt;
  360. }
  361. }
  362. return out;
  363. }
  364. #if defined(JM_NO_TEMPLATE_SWITCH_MERGE) && !defined(JM_NO_NAMESPACES)
  365. } // namespace
  366. #endif
  367. template <class OutputIterator, class iterator, class Allocator, class charT>
  368. OutputIterator RE_CALL reg_format(OutputIterator out,
  369. const reg_match<iterator, Allocator>& m,
  370. const charT* fmt
  371. #ifdef RE_LOCALE_CPP
  372. , __JM_STD::locale locale_inst = __JM_STD::locale()
  373. #endif
  374. )
  375. {
  376. //
  377. // start by updating the locale:
  378. //
  379. #if defined(RE_LOCALE_C) || defined(RE_LOCALE_W32)
  380. static re_initialiser<charT> locale_initialiser;
  381. locale_initialiser.update();
  382. #else
  383. if(JM_HAS_FACET(locale_inst, regfacet<charT>) == false)
  384. {
  385. #ifdef _MSC_VER
  386. locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet<charT>());
  387. #else
  388. locale_inst = __JM_STD::locale(locale_inst, new regfacet<charT>());
  389. #endif
  390. }
  391. JM_USE_FACET(locale_inst, regfacet<charT>).update(locale_inst);
  392. #endif
  393. return __reg_format_aux(out, m, fmt, false MAYBE_PASS_LOCALE(locale_inst));
  394. }
  395. template <class S>
  396. class string_out_iterator
  397. {
  398. S* out;
  399. public:
  400. string_out_iterator(S& s) : out(&s) {}
  401. string_out_iterator& operator++() { return *this; }
  402. string_out_iterator& operator++(int) { return *this; }
  403. string_out_iterator& operator*() { return *this; }
  404. string_out_iterator& operator=(typename S::value_type v)
  405. {
  406. out->append(1, v);
  407. return *this;
  408. }
  409. };
  410. #ifndef JM_NO_STRING_DEF_ARGS
  411. template <class iterator, class Allocator, class charT>
  412. __JM_STD::basic_string<charT> RE_CALL reg_format(const reg_match<iterator, Allocator>& m, const charT* fmt
  413. #ifdef RE_LOCALE_CPP
  414. , __JM_STD::locale locale_inst = __JM_STD::locale()
  415. #endif
  416. )
  417. {
  418. __JM_STD::basic_string<charT> result;
  419. string_out_iterator<__JM_STD::basic_string<charT> > i(result);
  420. reg_format(i, m, fmt MAYBE_PASS_LOCALE(locale_inst));
  421. return result;
  422. }
  423. #elif !defined(JM_NO_STRING_H)
  424. template <class iterator, class Allocator>
  425. __JM_STD::string RE_CALL reg_format(const reg_match<iterator, Allocator>& m, const char* fmt
  426. #ifdef RE_LOCALE_CPP
  427. , __JM_STD::locale locale_inst = __JM_STD::locale()
  428. #endif
  429. )
  430. {
  431. __JM_STD::string result;
  432. string_out_iterator<__JM_STD::string> i(result);
  433. reg_format(i, m, fmt MAYBE_PASS_LOCALE(locale_inst));
  434. return result;
  435. }
  436. #endif
  437. template <class OutputIterator, class iterator, class charT, class Allocator>
  438. class merge_out_predicate
  439. {
  440. OutputIterator* out;
  441. iterator* last;
  442. const charT* fmt;
  443. bool copy_none;
  444. #ifdef RE_LOCALE_CPP
  445. const __JM_STD::locale& l;
  446. #endif
  447. public:
  448. merge_out_predicate(OutputIterator& o, iterator& pi, const charT* f, bool c
  449. #ifdef RE_LOCALE_CPP
  450. , const __JM_STD::locale& loc
  451. #endif
  452. ) : out(&o), last(&pi), fmt(f), copy_none(c)
  453. #ifdef RE_LOCALE_CPP
  454. , l(loc)
  455. #endif
  456. {}
  457. ~merge_out_predicate() {}
  458. bool RE_CALL operator()(const __JM::reg_match<iterator, Allocator>& m)
  459. {
  460. const charT* f = fmt;
  461. if(copy_none)
  462. oi_assign(out, re_copy_out(*out, iterator(m[-1].first), iterator(m[-1].second)));
  463. oi_assign(out, __reg_format_aux(*out, m, f, false MAYBE_PASS_LOCALE(l)));
  464. *last = m[-2].first;
  465. return true;
  466. }
  467. };
  468. template <class OutputIterator, class iterator, class traits, class Allocator, class charT>
  469. OutputIterator RE_CALL reg_merge(OutputIterator out,
  470. iterator first,
  471. iterator last,
  472. const reg_expression<charT, traits, Allocator>& e,
  473. const charT* fmt,
  474. bool copy = true,
  475. unsigned int flags = match_default)
  476. {
  477. //
  478. // start by updating the locale:
  479. //
  480. #if defined(RE_LOCALE_C) || defined(RE_LOCALE_W32)
  481. static re_initialiser<charT> locale_initialiser;
  482. locale_initialiser.update();
  483. #else
  484. __JM_STD::locale locale_inst(e.locale());
  485. if(JM_HAS_FACET(locale_inst, regfacet<charT>) == false)
  486. {
  487. #ifdef _MSC_VER
  488. locale_inst = __JM_STD::_ADDFAC(locale_inst, new regfacet<charT>());
  489. #else
  490. locale_inst = __JM_STD::locale(locale_inst, new regfacet<charT>());
  491. #endif
  492. }
  493. JM_USE_FACET(locale_inst, regfacet<charT>).update(locale_inst);
  494. #endif
  495. iterator l = first;
  496. merge_out_predicate<OutputIterator, iterator, charT, Allocator> oi(out, l, fmt, copy MAYBE_PASS_LOCALE(locale_inst));
  497. reg_grep(oi, first, last, e, flags);
  498. return copy ? re_copy_out(out, l, last) : out;
  499. }
  500. #ifndef JM_NO_STRING_DEF_ARGS
  501. template <class traits, class Allocator, class charT>
  502. __JM_STD::basic_string<charT> RE_CALL reg_merge(const __JM_STD::basic_string<charT>& s,
  503. const reg_expression<charT, traits, Allocator>& e,
  504. const charT* fmt,
  505. bool copy = true,
  506. unsigned int flags = match_default)
  507. {
  508. __JM_STD::basic_string<charT> result;
  509. string_out_iterator<__JM_STD::basic_string<charT> > i(result);
  510. reg_merge(i, s.begin(), s.end(), e, fmt, copy, flags);
  511. return result;
  512. }
  513. #elif !defined(JM_NO_STRING_H)
  514. template <class traits, class Allocator>
  515. __JM_STD::string RE_CALL reg_merge(const __JM_STD::string& s,
  516. const reg_expression<char, traits, Allocator>& e,
  517. const char* fmt,
  518. bool copy = true,
  519. unsigned int flags = match_default)
  520. {
  521. __JM_STD::string result;
  522. string_out_iterator<__JM_STD::string> i(result);
  523. reg_merge(i, s.begin(), s.end(), e, fmt, copy, flags);
  524. return result;
  525. }
  526. #endif
  527. JM_END_NAMESPACE
  528. #endif