From eb15434a8e2ec8844f734b97888b3e4944be7b55 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 31 Oct 2023 16:47:10 +0400 Subject: [PATCH] Syntax highlight --- .../Sources/ChatController.swift | 20 +- .../AttachmentTextInputPanelNode.swift | 24 +- .../Sources/ChatTextFormat.swift | 18 +- .../Sources/CreatePollTextInputItem.swift | 23 +- submodules/Display/Source/TextNode.swift | 95 +- .../Pasteboard/Sources/Pasteboard.swift | 9 +- .../Sources/Account/AccountManager.swift | 1 + .../AccountManager/AccountManagerImpl.swift | 16 +- .../DerivedDataMessageAttribute.swift | 41 + ...yncCore_StandaloneAccountTransaction.swift | 20 + .../Messages/TelegramEngineMessages.swift | 16 + .../Sources/ChatInputTextNode.swift | 50 +- .../ChatMessageTextBubbleContentNode.swift | 40 +- .../TelegramUI/Sources/ChatController.swift | 16 +- .../Sources/ChatTextInputPanelNode.swift | 45 +- submodules/TextFormat/BUILD | 2 + .../Sources/ChatTextInputAttributes.swift | 71 +- .../Sources/GenerateTextEntities.swift | 40 +- .../Sources/StringWithAppliedEntities.swift | 295 +- .../TextInputMenu/Sources/TextInputMenu.swift | 37 +- third-party/boost_regex/BUILD | 26 + .../boost_regex/include/boost/cregex.hpp | 43 + third-party/boost_regex/include/boost/regex.h | 100 + .../boost_regex/include/boost/regex.hpp | 41 + .../include/boost/regex/concepts.hpp | 1134 ++++++ .../include/boost/regex/config.hpp | 480 +++ .../include/boost/regex/config/borland.hpp | 72 + .../include/boost/regex/config/cwchar.hpp | 207 ++ .../boost_regex/include/boost/regex/icu.hpp | 30 + .../boost_regex/include/boost/regex/mfc.hpp | 186 + .../include/boost/regex/pattern_except.hpp | 32 + .../boost/regex/pending/object_cache.hpp | 29 + .../boost/regex/pending/static_mutex.hpp | 182 + .../boost/regex/pending/unicode_iterator.hpp | 32 + .../include/boost/regex/regex_traits.hpp | 39 + .../boost_regex/include/boost/regex/user.hpp | 95 + .../include/boost/regex/v4/basic_regex.hpp | 797 +++++ .../boost/regex/v4/basic_regex_creator.hpp | 1598 +++++++++ .../boost/regex/v4/basic_regex_parser.hpp | 3174 +++++++++++++++++ .../include/boost/regex/v4/c_regex_traits.hpp | 511 +++ .../boost/regex/v4/char_regex_traits.hpp | 81 + .../boost/regex/v4/cpp_regex_traits.hpp | 1237 +++++++ .../include/boost/regex/v4/cregex.hpp | 213 ++ .../include/boost/regex/v4/error_type.hpp | 59 + .../include/boost/regex/v4/icu.hpp | 1516 ++++++++ .../boost/regex/v4/indexed_bit_flag.hpp | 54 + .../boost/regex/v4/iterator_category.hpp | 91 + .../boost/regex/v4/iterator_traits.hpp | 135 + .../include/boost/regex/v4/match_flags.hpp | 161 + .../include/boost/regex/v4/match_results.hpp | 716 ++++ .../boost/regex/v4/mem_block_cache.hpp | 183 + .../include/boost/regex/v4/object_cache.hpp | 171 + .../include/boost/regex/v4/pattern_except.hpp | 128 + .../include/boost/regex/v4/perl_matcher.hpp | 645 ++++ .../boost/regex/v4/perl_matcher_common.hpp | 1030 ++++++ .../regex/v4/perl_matcher_non_recursive.hpp | 1947 ++++++++++ .../boost/regex/v4/perl_matcher_recursive.hpp | 1131 ++++++ .../boost/regex/v4/primary_transform.hpp | 146 + .../include/boost/regex/v4/protected_call.hpp | 83 + .../include/boost/regex/v4/regbase.hpp | 180 + .../include/boost/regex/v4/regex.hpp | 166 + .../include/boost/regex/v4/regex_format.hpp | 1158 ++++++ .../include/boost/regex/v4/regex_fwd.hpp | 73 + .../include/boost/regex/v4/regex_grep.hpp | 155 + .../include/boost/regex/v4/regex_iterator.hpp | 195 + .../include/boost/regex/v4/regex_match.hpp | 382 ++ .../include/boost/regex/v4/regex_merge.hpp | 93 + .../boost/regex/v4/regex_raw_buffer.hpp | 241 ++ .../include/boost/regex/v4/regex_replace.hpp | 99 + .../include/boost/regex/v4/regex_search.hpp | 217 ++ .../include/boost/regex/v4/regex_split.hpp | 174 + .../boost/regex/v4/regex_token_iterator.hpp | 327 ++ .../include/boost/regex/v4/regex_traits.hpp | 189 + .../boost/regex/v4/regex_traits_defaults.hpp | 997 ++++++ .../boost/regex/v4/regex_workaround.hpp | 237 ++ .../include/boost/regex/v4/states.hpp | 321 ++ .../include/boost/regex/v4/sub_match.hpp | 516 +++ .../include/boost/regex/v4/syntax_type.hpp | 105 + .../boost/regex/v4/u32regex_iterator.hpp | 185 + .../regex/v4/u32regex_token_iterator.hpp | 360 ++ .../boost/regex/v4/unicode_iterator.hpp | 871 +++++ .../boost/regex/v4/w32_regex_traits.hpp | 1229 +++++++ .../include/boost/regex/v5/basic_regex.hpp | 734 ++++ .../boost/regex/v5/basic_regex_creator.hpp | 1576 ++++++++ .../boost/regex/v5/basic_regex_parser.hpp | 3130 ++++++++++++++++ .../include/boost/regex/v5/c_regex_traits.hpp | 474 +++ .../boost/regex/v5/char_regex_traits.hpp | 59 + .../boost/regex/v5/cpp_regex_traits.hpp | 1040 ++++++ .../include/boost/regex/v5/cregex.hpp | 195 + .../include/boost/regex/v5/error_type.hpp | 59 + .../include/boost/regex/v5/icu.hpp | 1402 ++++++++ .../boost/regex/v5/iterator_category.hpp | 84 + .../boost/regex/v5/iterator_traits.hpp | 32 + .../include/boost/regex/v5/match_flags.hpp | 156 + .../include/boost/regex/v5/match_results.hpp | 667 ++++ .../boost/regex/v5/mem_block_cache.hpp | 173 + .../include/boost/regex/v5/object_cache.hpp | 160 + .../include/boost/regex/v5/pattern_except.hpp | 106 + .../include/boost/regex/v5/perl_matcher.hpp | 576 +++ .../boost/regex/v5/perl_matcher_common.hpp | 921 +++++ .../regex/v5/perl_matcher_non_recursive.hpp | 1874 ++++++++++ .../boost/regex/v5/primary_transform.hpp | 120 + .../include/boost/regex/v5/regbase.hpp | 158 + .../include/boost/regex/v5/regex.hpp | 106 + .../include/boost/regex/v5/regex_format.hpp | 1124 ++++++ .../include/boost/regex/v5/regex_fwd.hpp | 73 + .../include/boost/regex/v5/regex_grep.hpp | 98 + .../include/boost/regex/v5/regex_iterator.hpp | 173 + .../include/boost/regex/v5/regex_match.hpp | 92 + .../include/boost/regex/v5/regex_merge.hpp | 71 + .../boost/regex/v5/regex_raw_buffer.hpp | 213 ++ .../include/boost/regex/v5/regex_replace.hpp | 77 + .../include/boost/regex/v5/regex_search.hpp | 103 + .../include/boost/regex/v5/regex_split.hpp | 152 + .../boost/regex/v5/regex_token_iterator.hpp | 255 ++ .../include/boost/regex/v5/regex_traits.hpp | 130 + .../boost/regex/v5/regex_traits_defaults.hpp | 996 ++++++ .../boost/regex/v5/regex_workaround.hpp | 159 + .../include/boost/regex/v5/states.hpp | 299 ++ .../include/boost/regex/v5/sub_match.hpp | 382 ++ .../include/boost/regex/v5/syntax_type.hpp | 105 + .../boost/regex/v5/u32regex_iterator.hpp | 177 + .../regex/v5/u32regex_token_iterator.hpp | 312 ++ .../boost/regex/v5/unicode_iterator.hpp | 862 +++++ .../boost/regex/v5/w32_regex_traits.hpp | 1311 +++++++ .../boost_regex/include/boost/regex_fwd.hpp | 37 + third-party/libprisma/BUILD | 76 + third-party/libprisma/Resources/grammars.dat | Bin 0 -> 620919 bytes third-party/libprisma/Sources/Highlight.cpp | 42 + third-party/libprisma/Sources/Highlight.h | 146 + .../libprisma/Sources/LanguageTree.cpp | 184 + third-party/libprisma/Sources/LanguageTree.h | 60 + .../libprisma/Sources/SyntaxHighlighter.cpp | 199 ++ .../libprisma/Sources/SyntaxHighlighter.h | 33 + third-party/libprisma/Sources/Syntaxer.mm | 245 ++ third-party/libprisma/Sources/TokenList.cpp | 71 + third-party/libprisma/Sources/TokenList.h | 170 + .../libprisma/include/libprisma/Syntaxer.h | 27 + 138 files changed, 49922 insertions(+), 218 deletions(-) create mode 100644 submodules/TelegramCore/Sources/SyncCore/DerivedDataMessageAttribute.swift create mode 100644 third-party/boost_regex/BUILD create mode 100644 third-party/boost_regex/include/boost/cregex.hpp create mode 100644 third-party/boost_regex/include/boost/regex.h create mode 100644 third-party/boost_regex/include/boost/regex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/concepts.hpp create mode 100644 third-party/boost_regex/include/boost/regex/config.hpp create mode 100644 third-party/boost_regex/include/boost/regex/config/borland.hpp create mode 100644 third-party/boost_regex/include/boost/regex/config/cwchar.hpp create mode 100644 third-party/boost_regex/include/boost/regex/icu.hpp create mode 100644 third-party/boost_regex/include/boost/regex/mfc.hpp create mode 100644 third-party/boost_regex/include/boost/regex/pattern_except.hpp create mode 100644 third-party/boost_regex/include/boost/regex/pending/object_cache.hpp create mode 100644 third-party/boost_regex/include/boost/regex/pending/static_mutex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/pending/unicode_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/user.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/basic_regex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/basic_regex_creator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/basic_regex_parser.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/c_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/char_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/cpp_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/cregex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/error_type.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/icu.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/indexed_bit_flag.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/iterator_category.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/iterator_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/match_flags.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/match_results.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/mem_block_cache.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/object_cache.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/pattern_except.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/perl_matcher.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/perl_matcher_common.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/perl_matcher_non_recursive.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/perl_matcher_recursive.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/primary_transform.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/protected_call.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regbase.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_format.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_fwd.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_grep.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_match.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_merge.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_raw_buffer.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_replace.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_search.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_split.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_token_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_traits_defaults.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/regex_workaround.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/states.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/sub_match.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/syntax_type.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/u32regex_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/u32regex_token_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/unicode_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v4/w32_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/basic_regex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/basic_regex_creator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/basic_regex_parser.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/c_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/char_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/cpp_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/cregex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/error_type.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/icu.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/iterator_category.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/iterator_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/match_flags.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/match_results.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/mem_block_cache.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/object_cache.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/pattern_except.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/perl_matcher.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/perl_matcher_common.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/perl_matcher_non_recursive.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/primary_transform.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regbase.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_format.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_fwd.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_grep.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_match.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_merge.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_raw_buffer.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_replace.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_search.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_split.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_token_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_traits_defaults.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/regex_workaround.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/states.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/sub_match.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/syntax_type.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/u32regex_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/u32regex_token_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/unicode_iterator.hpp create mode 100644 third-party/boost_regex/include/boost/regex/v5/w32_regex_traits.hpp create mode 100644 third-party/boost_regex/include/boost/regex_fwd.hpp create mode 100644 third-party/libprisma/BUILD create mode 100644 third-party/libprisma/Resources/grammars.dat create mode 100644 third-party/libprisma/Sources/Highlight.cpp create mode 100644 third-party/libprisma/Sources/Highlight.h create mode 100644 third-party/libprisma/Sources/LanguageTree.cpp create mode 100644 third-party/libprisma/Sources/LanguageTree.h create mode 100644 third-party/libprisma/Sources/SyntaxHighlighter.cpp create mode 100644 third-party/libprisma/Sources/SyntaxHighlighter.h create mode 100644 third-party/libprisma/Sources/Syntaxer.mm create mode 100644 third-party/libprisma/Sources/TokenList.cpp create mode 100644 third-party/libprisma/Sources/TokenList.h create mode 100644 third-party/libprisma/include/libprisma/Syntaxer.h diff --git a/submodules/AccountContext/Sources/ChatController.swift b/submodules/AccountContext/Sources/ChatController.swift index c324d80809..d19f931c0c 100644 --- a/submodules/AccountContext/Sources/ChatController.swift +++ b/submodules/AccountContext/Sources/ChatController.swift @@ -322,6 +322,7 @@ public enum ChatTextInputStateTextAttributeType: Codable, Equatable { case underline case spoiler case quote + case codeBlock(language: String?) public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) @@ -351,6 +352,8 @@ public enum ChatTextInputStateTextAttributeType: Codable, Equatable { self = .spoiler case 9: self = .quote + case 10: + self = .codeBlock(language: try container.decodeIfPresent(String.self, forKey: "l")) default: assertionFailure() self = .bold @@ -384,6 +387,9 @@ public enum ChatTextInputStateTextAttributeType: Codable, Equatable { try container.encode(8 as Int32, forKey: "t") case .quote: try container.encode(9 as Int32, forKey: "t") + case let .codeBlock(language): + try container.encode(10 as Int32, forKey: "t") + try container.encodeIfPresent(language, forKey: "l") } } } @@ -457,9 +463,13 @@ public struct ChatTextInputStateText: Codable, Equatable { parsedAttributes.append(ChatTextInputStateTextAttribute(type: .underline, range: range.location ..< (range.location + range.length))) } else if key == ChatTextInputAttributes.spoiler { parsedAttributes.append(ChatTextInputStateTextAttribute(type: .spoiler, range: range.location ..< (range.location + range.length))) - } else if key == ChatTextInputAttributes.quote, let value = value as? ChatTextInputTextQuoteAttribute { - let _ = value - parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote, range: range.location ..< (range.location + range.length))) + } else if key == ChatTextInputAttributes.block, let value = value as? ChatTextInputTextQuoteAttribute { + switch value.kind { + case .quote: + parsedAttributes.append(ChatTextInputStateTextAttribute(type: .quote, range: range.location ..< (range.location + range.length))) + case let .code(language): + parsedAttributes.append(ChatTextInputStateTextAttribute(type: .codeBlock(language: language), range: range.location ..< (range.location + range.length))) + } } } }) @@ -505,7 +515,9 @@ public struct ChatTextInputStateText: Codable, Equatable { case .spoiler: result.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: NSRange(location: attribute.range.lowerBound, length: attribute.range.count)) case .quote: - result.addAttribute(ChatTextInputAttributes.quote, value: ChatTextInputTextQuoteAttribute(), range: NSRange(location: attribute.range.lowerBound, length: attribute.range.count)) + result.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote), range: NSRange(location: attribute.range.lowerBound, length: attribute.range.count)) + case let .codeBlock(language): + result.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: language)), range: NSRange(location: attribute.range.lowerBound, length: attribute.range.count)) } } return result diff --git a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift index d4e5df3f7b..e49ca54d11 100644 --- a/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift +++ b/submodules/AttachmentTextInputPanelNode/Sources/AttachmentTextInputPanelNode.swift @@ -1473,7 +1473,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS return ASEditableTextNodeTargetForAction(target: nil) } } - } else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) || action == #selector(self.formatAttributesQuote(_:)) { + } else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) || action == #selector(self.formatAttributesQuote(_:)) || action == #selector(self.formatAttributesCodeBlock(_:)) { if case .format = self.inputMenu.state { return ASEditableTextNodeTargetForAction(target: self) } else { @@ -1586,21 +1586,21 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS @objc func formatAttributesBold(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold, value: nil), inputMode) } } @objc func formatAttributesItalic(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic, value: nil), inputMode) } } @objc func formatAttributesMonospace(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace, value: nil), inputMode) } } @@ -1616,14 +1616,14 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS @objc func formatAttributesStrikethrough(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough, value: nil), inputMode) } } @objc func formatAttributesUnderline(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline, value: nil), inputMode) } } @@ -1640,7 +1640,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS } self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler, value: nil), inputMode) } self.updateSpoilersRevealed(animated: animated) @@ -1650,7 +1650,15 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.quote), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote)), inputMode) + } + } + + @objc func formatAttributesCodeBlock(_ sender: Any) { + self.inputMenu.back() + + self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: nil))), inputMode) } } diff --git a/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift b/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift index 68b3c7170a..fb7d690634 100644 --- a/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift +++ b/submodules/ChatPresentationInterfaceState/Sources/ChatTextFormat.swift @@ -3,7 +3,7 @@ import TextFormat import TelegramCore import AccountContext -public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, attribute: NSAttributedString.Key) -> ChatTextInputState { +public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, attribute: NSAttributedString.Key, value: Any?) -> ChatTextInputState { if !state.selectionRange.isEmpty { let nsRange = NSRange(location: state.selectionRange.lowerBound, length: state.selectionRange.count) var addAttribute = true @@ -21,7 +21,7 @@ public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, att let result = NSMutableAttributedString(attributedString: state.inputText) for attribute in attributesToRemove { - if attribute == ChatTextInputAttributes.quote { + if attribute == ChatTextInputAttributes.block { var removeRange = nsRange var selectionIndex = nsRange.upperBound @@ -55,9 +55,9 @@ public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, att // Prevent merge back result.enumerateAttributes(in: NSRange(location: selectionIndex, length: result.length - selectionIndex), options: .longestEffectiveRangeNotRequired) { attributes, range, _ in for (key, value) in attributes { - if let _ = value as? ChatTextInputTextQuoteAttribute { + if let value = value as? ChatTextInputTextQuoteAttribute { result.removeAttribute(key, range: range) - result.addAttribute(key, value: ChatTextInputTextQuoteAttribute(), range: range) + result.addAttribute(key, value: ChatTextInputTextQuoteAttribute(kind: value.kind), range: range) } } } @@ -69,8 +69,8 @@ public func chatTextInputAddFormattingAttribute(_ state: ChatTextInputState, att } if addAttribute { - if attribute == ChatTextInputAttributes.quote { - result.addAttribute(attribute, value: ChatTextInputTextQuoteAttribute(), range: nsRange) + if attribute == ChatTextInputAttributes.block { + result.addAttribute(attribute, value: value ?? ChatTextInputTextQuoteAttribute(kind: .quote), range: nsRange) var selectionIndex = nsRange.upperBound if nsRange.upperBound != result.length && (result.string as NSString).character(at: nsRange.upperBound) != 0x0a { result.insert(NSAttributedString(string: "\n"), at: nsRange.upperBound) @@ -173,7 +173,7 @@ public func chatTextInputAddMentionAttribute(_ state: ChatTextInputState, peer: } } -public func chatTextInputAddQuoteAttribute(_ state: ChatTextInputState, selectionRange: Range) -> ChatTextInputState { +public func chatTextInputAddQuoteAttribute(_ state: ChatTextInputState, selectionRange: Range, kind: ChatTextInputTextQuoteAttribute.Kind) -> ChatTextInputState { if selectionRange.isEmpty { return state } @@ -182,7 +182,7 @@ public func chatTextInputAddQuoteAttribute(_ state: ChatTextInputState, selectio var attributesToRemove: [(NSAttributedString.Key, NSRange)] = [] state.inputText.enumerateAttributes(in: nsRange, options: .longestEffectiveRangeNotRequired) { attributes, range, stop in for (key, _) in attributes { - if key == ChatTextInputAttributes.quote { + if key == ChatTextInputAttributes.block { attributesToRemove.append((key, range)) quoteRange = quoteRange.union(range) } else { @@ -195,6 +195,6 @@ public func chatTextInputAddQuoteAttribute(_ state: ChatTextInputState, selectio for (attribute, range) in attributesToRemove { result.removeAttribute(attribute, range: range) } - result.addAttribute(ChatTextInputAttributes.quote, value: ChatTextInputTextQuoteAttribute(), range: nsRange) + result.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: kind), range: nsRange) return ChatTextInputState(inputText: result, selectionRange: selectionRange) } diff --git a/submodules/ComposePollUI/Sources/CreatePollTextInputItem.swift b/submodules/ComposePollUI/Sources/CreatePollTextInputItem.swift index 74c6f78c9f..509b9b23de 100644 --- a/submodules/ComposePollUI/Sources/CreatePollTextInputItem.swift +++ b/submodules/ComposePollUI/Sources/CreatePollTextInputItem.swift @@ -510,21 +510,21 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe @objc func formatAttributesBold(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.bold) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.bold, value: nil) } } @objc func formatAttributesItalic(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.italic) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.italic, value: nil) } } @objc func formatAttributesMonospace(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.monospace) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.monospace, value: nil) } } @@ -536,28 +536,35 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe @objc func formatAttributesStrikethrough(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.strikethrough) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.strikethrough, value: nil) } } @objc func formatAttributesUnderline(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.underline) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.underline, value: nil) } } @objc func formatAttributesSpoiler(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.spoiler) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.spoiler, value: nil) } } @objc func formatAttributesQuote(_ sender: Any) { self.inputMenu.back() if let item = self.item { - chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.quote) + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote)) + } + } + + @objc func formatAttributesCodeBlock(_ sender: Any) { + self.inputMenu.back() + if let item = self.item { + chatTextInputAddFormattingAttribute(item: item, textNode: self.textNode, theme: item.presentationData.theme, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: nil))) } } @@ -639,7 +646,7 @@ public class CreatePollTextInputItemNode: ListViewItemNode, ASEditableTextNodeDe } } -private func chatTextInputAddFormattingAttribute(item: CreatePollTextInputItem, textNode: EditableTextNode, theme: PresentationTheme, attribute: NSAttributedString.Key) { +private func chatTextInputAddFormattingAttribute(item: CreatePollTextInputItem, textNode: EditableTextNode, theme: PresentationTheme, attribute: NSAttributedString.Key, value: Any?) { if let currentText = textNode.attributedText, textNode.selectedRange.length > 0 { let nsRange = NSRange(location: textNode.selectedRange.location, length: textNode.selectedRange.length) var addAttribute = true diff --git a/submodules/Display/Source/TextNode.swift b/submodules/Display/Source/TextNode.swift index cfc904d4a3..a31009bd8e 100644 --- a/submodules/Display/Source/TextNode.swift +++ b/submodules/Display/Source/TextNode.swift @@ -68,12 +68,19 @@ public struct TextRangeRectEdge: Equatable { } public final class TextNodeBlockQuoteData: NSObject { + public enum Kind: Equatable { + case quote + case code(language: String?) + } + + public let kind: Kind public let title: NSAttributedString? public let color: UIColor public let secondaryColor: UIColor? public let tertiaryColor: UIColor? - public init(title: NSAttributedString?, color: UIColor, secondaryColor: UIColor?, tertiaryColor: UIColor?) { + public init(kind: Kind, title: NSAttributedString?, color: UIColor, secondaryColor: UIColor?, tertiaryColor: UIColor?) { + self.kind = kind self.title = title self.color = color self.secondaryColor = secondaryColor @@ -87,6 +94,9 @@ public final class TextNodeBlockQuoteData: NSObject { return false } + if self.kind != other.kind { + return false + } if let lhsTitle = self.title, let rhsTitle = other.title { if !lhsTitle.isEqual(to: rhsTitle) { return false @@ -148,12 +158,14 @@ private final class TextNodeLine { private final class TextNodeBlockQuote { let frame: CGRect + let data: TextNodeBlockQuoteData let tintColor: UIColor let secondaryTintColor: UIColor? let tertiaryTintColor: UIColor? - init(frame: CGRect, tintColor: UIColor, secondaryTintColor: UIColor?, tertiaryTintColor: UIColor?) { + init(frame: CGRect, data: TextNodeBlockQuoteData, tintColor: UIColor, secondaryTintColor: UIColor?, tertiaryTintColor: UIColor?) { self.frame = frame + self.data = data self.tintColor = tintColor self.secondaryTintColor = secondaryTintColor self.tertiaryTintColor = tertiaryTintColor @@ -1224,7 +1236,7 @@ open class TextNode: ASDisplayNode { let title: NSAttributedString? let substring: NSAttributedString let firstCharacterOffset: Int - let isBlockQuote: Bool + let blockQuote: TextNodeBlockQuoteData? let tintColor: UIColor? let secondaryTintColor: UIColor? let tertiaryTintColor: UIColor? @@ -1249,7 +1261,7 @@ open class TextNode: ASDisplayNode { length: effectiveRange.location - segmentCharacterOffset )), firstCharacterOffset: segmentCharacterOffset, - isBlockQuote: false, + blockQuote: nil, tintColor: nil, secondaryTintColor: nil, tertiaryTintColor: nil @@ -1262,7 +1274,7 @@ open class TextNode: ASDisplayNode { title: value.title, substring: attributedString.attributedSubstring(from: effectiveRange), firstCharacterOffset: effectiveRange.location, - isBlockQuote: true, + blockQuote: value, tintColor: value.color, secondaryTintColor: value.secondaryColor, tertiaryTintColor: value.tertiaryColor @@ -1277,7 +1289,7 @@ open class TextNode: ASDisplayNode { title: nil, substring: attributedString.attributedSubstring(from: effectiveRange), firstCharacterOffset: effectiveRange.location, - isBlockQuote: false, + blockQuote: nil, tintColor: nil, secondaryTintColor: nil, tertiaryTintColor: nil @@ -1294,7 +1306,7 @@ open class TextNode: ASDisplayNode { length: wholeStringLength - segmentCharacterOffset )), firstCharacterOffset: segmentCharacterOffset, - isBlockQuote: false, + blockQuote: nil, tintColor: nil, secondaryTintColor: nil, tertiaryTintColor: nil @@ -1311,7 +1323,7 @@ open class TextNode: ASDisplayNode { var tintColor: UIColor? var secondaryTintColor: UIColor? var tertiaryTintColor: UIColor? - var isBlockQuote: Bool = false + var blockQuote: TextNodeBlockQuoteData? var additionalWidth: CGFloat = 0.0 } @@ -1319,7 +1331,7 @@ open class TextNode: ASDisplayNode { for segment in stringSegments { var calculatedSegment = CalculatedSegment() - calculatedSegment.isBlockQuote = segment.isBlockQuote + calculatedSegment.blockQuote = segment.blockQuote calculatedSegment.tintColor = segment.tintColor calculatedSegment.secondaryTintColor = segment.secondaryTintColor calculatedSegment.tertiaryTintColor = segment.tertiaryTintColor @@ -1335,13 +1347,21 @@ open class TextNode: ASDisplayNode { var constrainedSegmentWidth = constrainedSize.width var additionalOffsetX: CGFloat = 0.0 - if segment.isBlockQuote { + if segment.blockQuote != nil { additionalOffsetX += blockQuoteLeftInset constrainedSegmentWidth -= additionalOffsetX + blockQuoteLeftInset + blockQuoteRightInset calculatedSegment.additionalWidth += blockQuoteLeftInset + blockQuoteRightInset } - var additionalSegmentRightInset = blockQuoteIconInset + var additionalSegmentRightInset: CGFloat = 0.0 + if let blockQuote = segment.blockQuote { + switch blockQuote.kind { + case .quote: + additionalSegmentRightInset = blockQuoteIconInset + case .code: + break + } + } if let title = segment.title { let rawTitleLine = CTLineCreateWithAttributedString(title) @@ -1391,7 +1411,7 @@ open class TextNode: ASDisplayNode { ascent: lineAscent, descent: lineDescent, range: NSRange(location: currentLineStartIndex, length: lineCharacterCount), - isRTL: isRTL && !segment.isBlockQuote, + isRTL: isRTL && segment.blockQuote == nil, strikethroughs: [], spoilers: [], spoilerWords: [], @@ -1432,11 +1452,11 @@ open class TextNode: ASDisplayNode { for i in 0 ..< calculatedSegments.count { let segment = calculatedSegments[i] if i != 0 { - if segment.isBlockQuote { + if segment.blockQuote != nil { size.height += 6.0 } } else { - if segment.isBlockQuote { + if segment.blockQuote != nil { size.height += 7.0 } } @@ -1524,17 +1544,17 @@ open class TextNode: ASDisplayNode { let blockMaxY = size.height - insets.bottom if i != calculatedSegments.count - 1 { - if segment.isBlockQuote { + if segment.blockQuote != nil { size.height += 8.0 } } else { - if segment.isBlockQuote { + if segment.blockQuote != nil { size.height += 6.0 } } - if segment.isBlockQuote, let tintColor = segment.tintColor { - blockQuotes.append(TextNodeBlockQuote(frame: CGRect(origin: CGPoint(x: 0.0, y: blockMinY - 2.0), size: CGSize(width: blockWidth, height: blockMaxY - (blockMinY - 2.0) + 4.0)), tintColor: tintColor, secondaryTintColor: segment.secondaryTintColor, tertiaryTintColor: segment.tertiaryTintColor)) + if let blockQuote = segment.blockQuote, let tintColor = segment.tintColor { + blockQuotes.append(TextNodeBlockQuote(frame: CGRect(origin: CGPoint(x: 0.0, y: blockMinY - 2.0), size: CGSize(width: blockWidth, height: blockMaxY - (blockMinY - 2.0) + 4.0)), data: blockQuote, tintColor: tintColor, secondaryTintColor: segment.secondaryTintColor, tertiaryTintColor: segment.tertiaryTintColor)) } } @@ -1973,10 +1993,6 @@ open class TextNode: ASDisplayNode { layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth) - if headIndent > 0.0 { - //blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) - } - var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { @@ -2086,10 +2102,6 @@ open class TextNode: ASDisplayNode { layoutSize.height += fontLineHeight layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth + headIndent) - if headIndent > 0.0 { - //blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) - } - var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { @@ -2217,15 +2229,20 @@ open class TextNode: ASDisplayNode { context.setFillColor(blockQuote.tintColor.cgColor) - let quoteRect = CGRect(origin: CGPoint(x: blockFrame.maxX - 4.0 - quoteIcon.size.width, y: blockFrame.minY + 4.0), size: quoteIcon.size) - context.saveGState() - context.translateBy(x: quoteRect.midX, y: quoteRect.midY) - context.scaleBy(x: 1.0, y: -1.0) - context.translateBy(x: -quoteRect.midX, y: -quoteRect.midY) - context.clip(to: quoteRect, mask: quoteIcon.cgImage!) - context.fill(quoteRect) - context.restoreGState() - context.resetClip() + switch blockQuote.data.kind { + case .quote: + let quoteRect = CGRect(origin: CGPoint(x: blockFrame.maxX - 4.0 - quoteIcon.size.width, y: blockFrame.minY + 4.0), size: quoteIcon.size) + context.saveGState() + context.translateBy(x: quoteRect.midX, y: quoteRect.midY) + context.scaleBy(x: 1.0, y: -1.0) + context.translateBy(x: -quoteRect.midX, y: -quoteRect.midY) + context.clip(to: quoteRect, mask: quoteIcon.cgImage!) + context.fill(quoteRect) + context.restoreGState() + context.resetClip() + case .code: + break + } let lineFrame = CGRect(origin: CGPoint(x: blockFrame.minX, y: blockFrame.minY), size: CGSize(width: lineWidth, height: blockFrame.height)) context.move(to: CGPoint(x: lineFrame.minX, y: lineFrame.minY + radius)) @@ -2906,10 +2923,6 @@ open class TextView: UIView { layoutSize.height += fontLineHeight + fontLineSpacing layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth) - if headIndent > 0.0 { - //blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) - } - var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { @@ -3009,10 +3022,6 @@ open class TextView: UIView { layoutSize.height += fontLineHeight layoutSize.width = max(layoutSize.width, lineWidth + lineAdditionalWidth) - if headIndent > 0.0 { - //blockQuotes.append(TextNodeBlockQuote(frame: lineFrame)) - } - var isRTL = false let glyphRuns = CTLineGetGlyphRuns(coreTextLine) as NSArray if glyphRuns.count != 0 { diff --git a/submodules/Pasteboard/Sources/Pasteboard.swift b/submodules/Pasteboard/Sources/Pasteboard.swift index 93c62c6ac7..bbd784a466 100644 --- a/submodules/Pasteboard/Sources/Pasteboard.swift +++ b/submodules/Pasteboard/Sources/Pasteboard.swift @@ -17,11 +17,6 @@ private func rtfStringWithAppliedEntities(_ text: String, entities: [MessageText } }) test.removeAttribute(ChatTextInputAttributes.customEmoji, range: NSRange(location: 0, length: test.length)) - - test.enumerateAttribute(ChatTextInputAttributes.quote, in: NSRange(location: 0, length: sourceString.length), using: { value, range, _ in - if value != nil { - } - }) if let data = try? test.data(from: NSRange(location: 0, length: test.length), documentAttributes: [NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf]) { if var rtf = String(data: data, encoding: .windowsCP1252) { @@ -81,8 +76,8 @@ private func chatInputStateString(attributedString: NSAttributedString) -> NSAtt if let value = attributes[ChatTextInputAttributes.customEmoji] as? ChatTextInputTextCustomEmojiAttribute { string.addAttribute(ChatTextInputAttributes.customEmoji, value: value, range: range) } - if let value = attributes[ChatTextInputAttributes.quote] as? ChatTextInputTextQuoteAttribute { - string.addAttribute(ChatTextInputAttributes.quote, value: value, range: range) + if let value = attributes[ChatTextInputAttributes.block] as? ChatTextInputTextQuoteAttribute { + string.addAttribute(ChatTextInputAttributes.block, value: value, range: range) } }) return string diff --git a/submodules/TelegramCore/Sources/Account/AccountManager.swift b/submodules/TelegramCore/Sources/Account/AccountManager.swift index 2d474719ce..62b6b1e633 100644 --- a/submodules/TelegramCore/Sources/Account/AccountManager.swift +++ b/submodules/TelegramCore/Sources/Account/AccountManager.swift @@ -203,6 +203,7 @@ private var declaredEncodables: Void = { declareEncodable(MapVenue.self, f: { MapVenue(decoder: $0) }) declareEncodable(TelegramMediaGiveaway.self, f: { TelegramMediaGiveaway(decoder: $0) }) declareEncodable(WebpagePreviewMessageAttribute.self, f: { WebpagePreviewMessageAttribute(decoder: $0) }) + declareEncodable(DerivedDataMessageAttribute.self, f: { DerivedDataMessageAttribute(decoder: $0) }) return }() diff --git a/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift b/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift index 3b013823b0..ae16e37e3a 100644 --- a/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift +++ b/submodules/TelegramCore/Sources/AccountManager/AccountManagerImpl.swift @@ -130,12 +130,18 @@ final class AccountManagerImpl { } } catch let e { postboxLog("load atomic state error: \(e)") - var legacyRecordDict: [AccountRecordId: AccountRecord] = [:] - for record in self.legacyRecordTable.getRecords() { - legacyRecordDict[record.id] = record + postboxLogSync() + + if removeDatabaseOnError { + var legacyRecordDict: [AccountRecordId: AccountRecord] = [:] + for record in self.legacyRecordTable.getRecords() { + legacyRecordDict[record.id] = record + } + self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount(), accessChallengeData: self.legacyMetadataTable.getAccessChallengeData()) + self.syncAtomicStateToFile() + } else { + preconditionFailure() } - self.currentAtomicState = AccountManagerAtomicState(records: legacyRecordDict, currentRecordId: self.legacyMetadataTable.getCurrentAccountId(), currentAuthRecord: self.legacyMetadataTable.getCurrentAuthAccount(), accessChallengeData: self.legacyMetadataTable.getAccessChallengeData()) - self.syncAtomicStateToFile() } let tableAccessChallengeData = self.legacyMetadataTable.getAccessChallengeData() diff --git a/submodules/TelegramCore/Sources/SyncCore/DerivedDataMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/DerivedDataMessageAttribute.swift new file mode 100644 index 0000000000..5f1004f7d3 --- /dev/null +++ b/submodules/TelegramCore/Sources/SyncCore/DerivedDataMessageAttribute.swift @@ -0,0 +1,41 @@ +import Foundation +import Postbox + +public class DerivedDataMessageAttribute: MessageAttribute { + private struct EntryData: PostboxCoding { + var data: CodableEntry + + init(data: CodableEntry) { + self.data = data + } + + init(decoder: PostboxDecoder) { + self.data = CodableEntry(data: decoder.decodeDataForKey("d") ?? Data()) + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeData(self.data.data, forKey: "d") + } + } + + public let data: [String: CodableEntry] + + public init(data: [String: CodableEntry]) { + self.data = data + } + + required public init(decoder: PostboxDecoder) { + let data = decoder.decodeObjectDictionaryForKey("d", keyDecoder: { key in + return key.decodeStringForKey("k", orElse: "") + }, valueDecoder: { value in + return EntryData(data: CodableEntry(data: value.decodeDataForKey("d") ?? Data())) + }) + self.data = data.mapValues(\.data) + } + + public func encode(_ encoder: PostboxEncoder) { + encoder.encodeObjectDictionary(self.data.mapValues(EntryData.init(data:)), forKey: "d", keyEncoder: { k, e in + e.encodeString(k, forKey: "k") + }) + } +} diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift index a66bfe2507..cde89cff88 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_StandaloneAccountTransaction.swift @@ -113,6 +113,13 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = { break } } + var derivedData: DerivedDataMessageAttribute? + for attribute in previous { + if let attribute = attribute as? DerivedDataMessageAttribute { + derivedData = attribute + break + } + } if let audioTranscription = audioTranscription { var found = false @@ -127,6 +134,19 @@ public let telegramPostboxSeedConfiguration: SeedConfiguration = { updated.append(audioTranscription) } } + if let derivedData = derivedData { + var found = false + for i in 0 ..< updated.count { + if let attribute = updated[i] as? DerivedDataMessageAttribute { + updated[i] = derivedData + found = true + break + } + } + if !found { + updated.append(derivedData) + } + } }, decodeMessageThreadInfo: { entry in guard let data = entry.get(MessageHistoryThreadData.self) else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 8e83c8c381..4b01661341 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -491,6 +491,22 @@ public extension TelegramEngine { |> ignoreValues } + public func storeLocallyDerivedData(messageId: MessageId, data: [String: CodableEntry]) -> Signal { + return self.account.postbox.transaction { transaction -> Void in + transaction.updateMessage(messageId, update: { currentMessage in + let storeForwardInfo = currentMessage.forwardInfo.flatMap(StoreMessageForwardInfo.init) + var attributes = currentMessage.attributes.filter { !($0 is DerivedDataMessageAttribute) } + + if !data.isEmpty { + attributes.append(DerivedDataMessageAttribute(data: data)) + } + + return .update(StoreMessage(id: currentMessage.id, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: currentMessage.tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + |> ignoreValues + } + public func rateAudioTranscription(messageId: MessageId, id: Int64, isGood: Bool) -> Signal { return _internal_rateAudioTranscription(postbox: self.account.postbox, network: self.account.network, messageId: messageId, id: id, isGood: isGood) } diff --git a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift index cebdc34511..c4bf235e6b 100644 --- a/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatInputTextNode/Sources/ChatInputTextNode.swift @@ -5,6 +5,7 @@ import Display import AppBundle import ChatInputTextViewImpl import MessageInlineBlockBackgroundView +import TextFormat public protocol ChatInputTextNodeDelegate: AnyObject { func chatInputTextNodeDidUpdateText() @@ -232,7 +233,7 @@ private final class ChatInputTextContainer: NSTextContainer { let index = Int(characterIndex) if index >= 0 && index < string.length { let attributes = textStorage.attributes(at: index, effectiveRange: nil) - let blockQuote = attributes[NSAttributedString.Key(rawValue: "Attribute__Blockquote")] as? NSObject + let blockQuote = attributes[NSAttributedString.Key(rawValue: "Attribute__Blockquote")] as? ChatTextInputTextQuoteAttribute if let blockQuote { result.origin.x += 9.0 result.size.width -= 9.0 @@ -253,7 +254,7 @@ private final class ChatInputTextContainer: NSTextContainer { } } - if (isFirstLine) { + if isFirstLine, case .quote = blockQuote.kind { result.size.width -= 18.0 } } @@ -638,9 +639,7 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele var validBlockQuotes: [Int] = [] self.textStorage.enumerateAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), in: NSRange(location: 0, length: self.textStorage.length), using: { value, range, _ in - if let value { - let _ = value - + if let value = value as? ChatTextInputTextQuoteAttribute { let glyphRange = self.customLayoutManager.glyphRange(forCharacterRange: range, actualCharacterRange: nil) if self.customLayoutManager.isValidGlyphIndex(glyphRange.location) && self.customLayoutManager.isValidGlyphIndex(glyphRange.location + glyphRange.length - 1) { } else { @@ -681,15 +680,18 @@ public final class ChatInputTextView: ChatInputTextViewImpl, NSLayoutManagerDele boundingRect.origin.x -= 4.0 boundingRect.size.width += 4.0 - boundingRect.size.width += 18.0 - boundingRect.size.width = min(boundingRect.size.width, self.bounds.width - 18.0) + if case .quote = value.kind { + boundingRect.size.width += 18.0 + boundingRect.size.width = min(boundingRect.size.width, self.bounds.width - 18.0) + } + boundingRect.size.width = min(boundingRect.size.width, self.bounds.width) boundingRect.origin.y -= 4.0 boundingRect.size.height += 8.0 blockQuote.frame = boundingRect if let theme = self.theme { - blockQuote.update(size: boundingRect.size, theme: theme.quote) + blockQuote.update(value: value, size: boundingRect.size, theme: theme.quote) } validBlockQuotes.append(blockQuoteIndex) @@ -816,7 +818,7 @@ private final class QuoteBackgroundView: UIView { fatalError("init(coder:) has not been implemented") } - func update(size: CGSize, theme: ChatInputTextView.Theme.Quote) { + func update(value: ChatTextInputTextQuoteAttribute, size: CGSize, theme: ChatInputTextView.Theme.Quote) { if self.theme != theme { self.theme = theme @@ -828,16 +830,26 @@ private final class QuoteBackgroundView: UIView { var primaryColor: UIColor var secondaryColor: UIColor? var tertiaryColor: UIColor? - switch theme.lineStyle { - case let .solid(color): - primaryColor = color - case let .doubleDashed(mainColor, secondaryColorValue): - primaryColor = mainColor - secondaryColor = secondaryColorValue - case let .tripleDashed(mainColor, secondaryColorValue, tertiaryColorValue): - primaryColor = mainColor - secondaryColor = secondaryColorValue - tertiaryColor = tertiaryColorValue + + switch value.kind { + case .quote: + self.iconView.isHidden = false + + switch theme.lineStyle { + case let .solid(color): + primaryColor = color + case let .doubleDashed(mainColor, secondaryColorValue): + primaryColor = mainColor + secondaryColor = secondaryColorValue + case let .tripleDashed(mainColor, secondaryColorValue, tertiaryColorValue): + primaryColor = mainColor + secondaryColor = secondaryColorValue + tertiaryColor = tertiaryColorValue + } + case .code: + self.iconView.isHidden = true + + primaryColor = .gray } self.backgroundView.update( diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift index 838dc25275..2075a5907d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode/Sources/ChatMessageTextBubbleContentNode.swift @@ -81,6 +81,8 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { private var linkProgressView: TextLoadingEffectView? private var linkProgressDisposable: Disposable? + private var codeHighlightState: (id: EngineMessage.Id, specs: [CachedMessageSyntaxHighlight.Spec], disposable: Disposable)? + override public var visibility: ListViewItemNodeVisibility { didSet { if oldValue != self.visibility { @@ -129,6 +131,7 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { deinit { self.linkPreviewOptionsDisposable?.dispose() self.linkProgressDisposable?.dispose() + self.codeHighlightState?.disposable.dispose() } override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { @@ -374,6 +377,9 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { let textFont = item.presentationData.messageFont + var codeHighlightSpecs: [CachedMessageSyntaxHighlight.Spec] = [] + var cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? + if let entities = entities { var underlineLinks = true if !messageTheme.primaryTextColor.isEqual(messageTheme.linkTextColor) { @@ -406,7 +412,21 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { } } - attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: mainColor, baseQuoteSecondaryTintColor: secondaryColor, baseQuoteTertiaryTintColor: tertiaryColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, underlineLinks: underlineLinks, message: item.message, adjustQuoteFontSize: true) + let codeBlockColor = messageTheme.secondaryTextColor + + codeHighlightSpecs = extractMessageSyntaxHighlightSpecs(text: rawText, entities: entities) + + if !codeHighlightSpecs.isEmpty { + for attribute in message.attributes { + if let attribute = attribute as? DerivedDataMessageAttribute { + if let value = attribute.data["code"]?.get(CachedMessageSyntaxHighlight.self) { + cachedMessageSyntaxHighlight = value + } + } + } + } + + attributedText = stringWithAppliedEntities(rawText, entities: entities, baseColor: messageTheme.primaryTextColor, linkColor: messageTheme.linkTextColor, baseQuoteTintColor: mainColor, baseQuoteSecondaryTintColor: secondaryColor, baseQuoteTertiaryTintColor: tertiaryColor, baseCodeBlockColor: codeBlockColor, baseFont: textFont, linkFont: textFont, boldFont: item.presentationData.messageBoldFont, italicFont: item.presentationData.messageItalicFont, boldItalicFont: item.presentationData.messageBoldItalicFont, fixedFont: item.presentationData.messageFixedFont, blockQuoteFont: item.presentationData.messageBlockQuoteFont, underlineLinks: underlineLinks, message: item.message, adjustQuoteFontSize: true, cachedMessageSyntaxHighlight: cachedMessageSyntaxHighlight) } else if !rawText.isEmpty { attributedText = NSAttributedString(string: rawText, font: textFont, textColor: messageTheme.primaryTextColor) } else { @@ -695,6 +715,24 @@ public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode { if let linkPreviewHighlightText = strongSelf.linkPreviewHighlightText { strongSelf.updateLinkPreviewTextHighlightState(text: linkPreviewHighlightText) } + + if !codeHighlightSpecs.isEmpty { + if let current = strongSelf.codeHighlightState, current.id == message.id, current.specs == codeHighlightSpecs { + } else { + if let codeHighlightState = strongSelf.codeHighlightState { + strongSelf.codeHighlightState = nil + codeHighlightState.disposable.dispose() + } + + let disposable = MetaDisposable() + strongSelf.codeHighlightState = (message.id, codeHighlightSpecs, disposable) + disposable.set(asyncUpdateMessageSyntaxHighlight(engine: item.context.engine, messageId: message.id, current: cachedMessageSyntaxHighlight, specs: codeHighlightSpecs).startStrict(completed: { + })) + } + } else if let codeHighlightState = strongSelf.codeHighlightState { + strongSelf.codeHighlightState = nil + codeHighlightState.disposable.dispose() + } } }) }) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 70bec1f7b7..e444d1462c 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -10870,8 +10870,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let updatedText = NSMutableAttributedString(attributedString: text) if range.lowerBound < inputText.length { - if let quote = inputText.attribute(ChatTextInputAttributes.quote, at: range.lowerBound, effectiveRange: nil) { - updatedText.addAttribute(ChatTextInputAttributes.quote, value: quote, range: NSRange(location: 0, length: updatedText.length)) + if let quote = inputText.attribute(ChatTextInputAttributes.block, at: range.lowerBound, effectiveRange: nil) { + updatedText.addAttribute(ChatTextInputAttributes.block, value: quote, range: NSRange(location: 0, length: updatedText.length)) } } inputText.replaceCharacters(in: NSMakeRange(range.lowerBound, range.count), with: updatedText) @@ -18161,42 +18161,42 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G KeyShortcut(input: "B", modifiers: [.command], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold, value: nil), inputMode) } } }), KeyShortcut(input: "I", modifiers: [.command], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic, value: nil), inputMode) } } }), KeyShortcut(input: "M", modifiers: [.shift, .command], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace, value: nil), inputMode) } } }), KeyShortcut(input: "U", modifiers: [.command], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline, value: nil), inputMode) } } }), KeyShortcut(input: "X", modifiers: [.command, .shift], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough, value: nil), inputMode) } } }), KeyShortcut(input: "P", modifiers: [.command, .shift], action: { [weak self] in if let strongSelf = self { strongSelf.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler, value: nil), inputMode) } } }), diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index d522560103..ed10c8204b 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -3663,7 +3663,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch return ASEditableTextNodeTargetForAction(target: nil) } } - } else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) || action == #selector(self.formatAttributesQuote(_:)) { + } else if action == #selector(self.formatAttributesBold(_:)) || action == #selector(self.formatAttributesItalic(_:)) || action == #selector(self.formatAttributesMonospace(_:)) || action == #selector(self.formatAttributesLink(_:)) || action == #selector(self.formatAttributesStrikethrough(_:)) || action == #selector(self.formatAttributesUnderline(_:)) || action == #selector(self.formatAttributesSpoiler(_:)) || action == #selector(self.formatAttributesQuote(_:)) || action == #selector(self.formatAttributesCodeBlock(_:)) { if case .format = self.inputMenu.state { if action == #selector(self.formatAttributesSpoiler(_:)), let selectedRange = self.textInputNode?.selectedRange { var intersectsMonospace = false @@ -3680,6 +3680,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch } else if action == #selector(self.formatAttributesQuote(_:)), let selectedRange = self.textInputNode?.selectedRange { let _ = selectedRange return ASEditableTextNodeTargetForAction(target: self) + } else if action == #selector(self.formatAttributesCodeBlock(_:)), let selectedRange = self.textInputNode?.selectedRange { + let _ = selectedRange + return ASEditableTextNodeTargetForAction(target: self) } else if action == #selector(self.formatAttributesMonospace(_:)), let selectedRange = self.textInputNode?.selectedRange { var intersectsSpoiler = false self.inputTextState.inputText.enumerateAttributes(in: selectedRange, options: [], using: { attributes, _, _ in @@ -3727,17 +3730,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch if editableTextNode.attributedText == nil || editableTextNode.attributedText!.length == 0 || editableTextNode.selectedRange.length == 0 { } else { - var hasQuoteSelected = false - let selectedRange = editableTextNode.selectedRange - if let attributedText = editableTextNode.attributedText, selectedRange.lowerBound >= 0, selectedRange.lowerBound < attributedText.length, selectedRange.upperBound >= 0, selectedRange.upperBound < attributedText.length { - attributedText.enumerateAttribute(ChatTextInputAttributes.quote, in: selectedRange, using: { value, _, _ in - if value is ChatTextInputTextQuoteAttribute { - hasQuoteSelected = true - } - }) - } - let _ = hasQuoteSelected - var children: [UIAction] = [] children.append(UIAction(title: self.strings?.TextFormat_Quote ?? "Quote", image: nil) { [weak self] (action) in @@ -3792,6 +3784,13 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch } ] as [UIAction]) + //TODO:localize + children.append(UIAction(title: "Code", image: nil) { [weak self] (action) in + if let strongSelf = self { + strongSelf.formatAttributesCodeBlock(strongSelf) + } + }) + let formatMenu = UIMenu(title: self.strings?.TextFormat_Format ?? "Format", image: nil, children: children) actions.insert(formatMenu, at: 1) } @@ -3837,21 +3836,21 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch @objc func formatAttributesBold(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.bold, value: nil), inputMode) } } @objc func formatAttributesItalic(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.italic, value: nil), inputMode) } } @objc func formatAttributesMonospace(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.monospace, value: nil), inputMode) } } @@ -3863,14 +3862,14 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch @objc func formatAttributesStrikethrough(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.strikethrough, value: nil), inputMode) } } @objc func formatAttributesUnderline(_ sender: Any) { self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.underline, value: nil), inputMode) } } @@ -3878,7 +3877,15 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch self.inputMenu.back() self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.quote), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote)), inputMode) + } + } + + @objc func formatAttributesCodeBlock(_ sender: Any) { + self.inputMenu.back() + + self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: nil))), inputMode) } } @@ -3895,7 +3902,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch } self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in - return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler), inputMode) + return (chatTextInputAddFormattingAttribute(current, attribute: ChatTextInputAttributes.spoiler, value: nil), inputMode) } self.updateSpoilersRevealed(animated: animated) diff --git a/submodules/TextFormat/BUILD b/submodules/TextFormat/BUILD index 99474d4fed..08d1dba76c 100644 --- a/submodules/TextFormat/BUILD +++ b/submodules/TextFormat/BUILD @@ -10,11 +10,13 @@ swift_library( "-warnings-as-errors", ], deps = [ + "//submodules/SSignalKit/SwiftSignalKit", "//submodules/TelegramCore:TelegramCore", "//submodules/Display:Display", "//submodules/TelegramPresentationData:TelegramPresentationData", "//submodules/Markdown:Markdown", "//submodules/Emoji:Emoji", + "//third-party/libprisma", ], visibility = [ "//visibility:public", diff --git a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift index ba9a8fbd57..a836f1cb22 100644 --- a/submodules/TextFormat/Sources/ChatTextInputAttributes.swift +++ b/submodules/TextFormat/Sources/ChatTextInputAttributes.swift @@ -19,10 +19,9 @@ public struct ChatTextInputAttributes { public static let textUrl = NSAttributedString.Key(rawValue: "Attribute__TextUrl") public static let spoiler = NSAttributedString.Key(rawValue: "Attribute__Spoiler") public static let customEmoji = NSAttributedString.Key(rawValue: "Attribute__CustomEmoji") - public static let code = NSAttributedString.Key(rawValue: "Attribute__Code") - public static let quote = NSAttributedString.Key(rawValue: "Attribute__Blockquote") + public static let block = NSAttributedString.Key(rawValue: "Attribute__Blockquote") - public static let allAttributes = [ChatTextInputAttributes.bold, ChatTextInputAttributes.italic, ChatTextInputAttributes.monospace, ChatTextInputAttributes.strikethrough, ChatTextInputAttributes.underline, ChatTextInputAttributes.textMention, ChatTextInputAttributes.textUrl, ChatTextInputAttributes.spoiler, ChatTextInputAttributes.customEmoji, ChatTextInputAttributes.code, ChatTextInputAttributes.quote] + public static let allAttributes = [ChatTextInputAttributes.bold, ChatTextInputAttributes.italic, ChatTextInputAttributes.monospace, ChatTextInputAttributes.strikethrough, ChatTextInputAttributes.underline, ChatTextInputAttributes.textMention, ChatTextInputAttributes.textUrl, ChatTextInputAttributes.spoiler, ChatTextInputAttributes.customEmoji, ChatTextInputAttributes.block] } public let originalTextAttributeKey = NSAttributedString.Key(rawValue: "Attribute__OriginalText") @@ -149,15 +148,9 @@ public func textAttributedStringForStateText(_ stateText: NSAttributedString, fo } else if key == ChatTextInputAttributes.customEmoji { result.addAttribute(key, value: value, range: range) result.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.clear, range: range) - } else if key == ChatTextInputAttributes.quote { + } else if key == ChatTextInputAttributes.block { fontAttributes.insert(.blockQuote) result.addAttribute(key, value: value, range: range) - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.firstLineHeadIndent = 8.0 - paragraphStyle.headIndent = 8.0 - //paragraphStyle.paragraphSpacing = 8.0 - //paragraphStyle.paragraphSpacingBefore = 8.0 - //result.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range) } } @@ -244,7 +237,16 @@ public final class ChatTextInputTextUrlAttribute: NSObject { } public final class ChatTextInputTextQuoteAttribute: NSObject { - override public init() { + public enum Kind: Equatable { + case quote + case code(language: String?) + } + + public let kind: Kind + + public init(kind: Kind) { + self.kind = kind + super.init() } @@ -253,7 +255,9 @@ public final class ChatTextInputTextQuoteAttribute: NSObject { return false } - let _ = other + if self.kind != other.kind { + return false + } return true } @@ -587,7 +591,7 @@ private func quoteRangesEqual(_ lhs: [(NSRange, ChatTextInputTextQuoteAttribute) private func refreshBlockQuotes(text: NSString, initialAttributedText: NSAttributedString, attributedText: NSMutableAttributedString, fullRange: NSRange) { var quoteRanges: [(NSRange, ChatTextInputTextQuoteAttribute)] = [] initialAttributedText.enumerateAttributes(in: fullRange, using: { dict, range, _ in - if let value = dict[ChatTextInputAttributes.quote] as? ChatTextInputTextQuoteAttribute { + if let value = dict[ChatTextInputAttributes.block] as? ChatTextInputTextQuoteAttribute { quoteRanges.append((range, value)) } }) @@ -638,10 +642,9 @@ private func refreshBlockQuotes(text: NSString, initialAttributedText: NSAttribu } if !quoteRangesEqual(quoteRanges, initialQuoteRanges) { - attributedText.removeAttribute(ChatTextInputAttributes.quote, range: fullRange) + attributedText.removeAttribute(ChatTextInputAttributes.block, range: fullRange) for (range, attribute) in quoteRanges { - let _ = attribute - attributedText.addAttribute(ChatTextInputAttributes.quote, value: ChatTextInputTextQuoteAttribute(), range: range) + attributedText.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: attribute.kind), range: range) } } } @@ -695,7 +698,7 @@ public func refreshChatTextInputAttributes(textView: UITextView, primaryTextColo textView.textStorage.removeAttribute(ChatTextInputAttributes.textUrl, range: fullRange) textView.textStorage.removeAttribute(ChatTextInputAttributes.spoiler, range: fullRange) textView.textStorage.removeAttribute(ChatTextInputAttributes.customEmoji, range: fullRange) - textView.textStorage.removeAttribute(ChatTextInputAttributes.quote, range: fullRange) + textView.textStorage.removeAttribute(ChatTextInputAttributes.block, range: fullRange) textView.textStorage.addAttribute(NSAttributedString.Key.font, value: Font.regular(baseFontSize), range: fullRange) textView.textStorage.addAttribute(NSAttributedString.Key.foregroundColor, value: primaryTextColor, range: fullRange) @@ -739,15 +742,9 @@ public func refreshChatTextInputAttributes(textView: UITextView, primaryTextColo } else if key == ChatTextInputAttributes.customEmoji, let value = value as? ChatTextInputTextCustomEmojiAttribute { textView.textStorage.addAttribute(key, value: value, range: range) textView.textStorage.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.clear, range: range) - } else if key == ChatTextInputAttributes.quote { + } else if key == ChatTextInputAttributes.block { fontAttributes.insert(.blockQuote) textView.textStorage.addAttribute(key, value: value, range: range) - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.firstLineHeadIndent = 8.0 - paragraphStyle.headIndent = 8.0 - //paragraphStyle.paragraphSpacing = 8.0 - //paragraphStyle.paragraphSpacingBefore = 8.0 - //textView.textStorage.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range) } } @@ -858,13 +855,6 @@ public func refreshGenericTextInputAttributes(_ textView: UITextView, theme: Pre } else { textView.textStorage.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.clear, range: range) } - } else if key == ChatTextInputAttributes.quote { - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.firstLineHeadIndent = 8.0 - paragraphStyle.headIndent = 8.0 - //paragraphStyle.paragraphSpacing = 8.0 - //paragraphStyle.paragraphSpacingBefore = 8.0 - //textView.textStorage.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range) } } @@ -1056,8 +1046,21 @@ public func convertMarkdownToAttributes(_ text: NSAttributedString) -> NSAttribu stringOffset -= match.range(at: 2).length + match.range(at: 4).length - let substring = string.substring(with: match.range(at: 1)) + text + string.substring(with: match.range(at: 5)) - result.append(NSAttributedString(string: substring, attributes: [ChatTextInputAttributes.code: true as NSNumber])) + var substring = (string.substring(with: match.range(at: 1)).trimmingCharacters(in: .whitespacesAndNewlines) + text + string.substring(with: match.range(at: 5))) as NSString + + var language: String? + let newlineRange = substring.range(of: "\n") + if newlineRange.location != NSNotFound { + if newlineRange.location != 0 { + language = substring.substring(with: NSRange(location: 0, length: newlineRange.location)) + } + substring = substring.substring(with: NSRange(location: newlineRange.upperBound, length: substring.length - newlineRange.upperBound)) as NSString + } + if substring.hasSuffix("\n") { + substring = substring.substring(with: NSRange(location: 0, length: substring.length - 1)) as NSString + } + + result.append(NSAttributedString(string: substring as String, attributes: [ChatTextInputAttributes.block: ChatTextInputTextQuoteAttribute(kind: .code(language: language))])) offsetRanges.append((NSMakeRange(matchIndex + match.range(at: 1).length, text.count), 6)) } } @@ -1090,7 +1093,7 @@ public func convertMarkdownToAttributes(_ text: NSAttributedString) -> NSAttribu case "`": textInputAttribute = ChatTextInputAttributes.monospace case "```": - textInputAttribute = ChatTextInputAttributes.code + textInputAttribute = ChatTextInputAttributes.block case "**": textInputAttribute = ChatTextInputAttributes.bold case "__": diff --git a/submodules/TextFormat/Sources/GenerateTextEntities.swift b/submodules/TextFormat/Sources/GenerateTextEntities.swift index 4e7fd0356f..f04532aa5c 100644 --- a/submodules/TextFormat/Sources/GenerateTextEntities.swift +++ b/submodules/TextFormat/Sources/GenerateTextEntities.swift @@ -167,10 +167,13 @@ public func generateChatInputTextEntities(_ text: NSAttributedString, maxAnimate entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .Spoiler)) } else if key == ChatTextInputAttributes.customEmoji, let value = value as? ChatTextInputTextCustomEmojiAttribute { entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .CustomEmoji(stickerPack: nil, fileId: value.fileId))) - } else if key == ChatTextInputAttributes.code { - entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .Code)) - } else if key == ChatTextInputAttributes.quote { - entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .BlockQuote)) + } else if key == ChatTextInputAttributes.block, let value = value as? ChatTextInputTextQuoteAttribute { + switch value.kind { + case .quote: + entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .BlockQuote)) + case let .code(language): + entities.append(MessageTextEntity(range: range.lowerBound ..< range.upperBound, type: .Pre(language: language))) + } } } }) @@ -210,6 +213,35 @@ public func generateChatInputTextEntities(_ text: NSAttributedString, maxAnimate } } + while true { + var hadReductions = false + + scan: for i in 0 ..< entities.count { + if case let .Pre(language) = entities[i].type { + inner: for j in 0 ..< entities.count { + if j == i { + continue inner + } + if case .Pre(language) = entities[j].type { + if entities[i].range.upperBound == entities[j].range.lowerBound || entities[i].range.lowerBound == entities[j].range.upperBound { + entities[i].range = min(entities[i].range.lowerBound, entities[j].range.lowerBound) ..< max(entities[i].range.upperBound, entities[j].range.upperBound) + entities.remove(at: j) + + hadReductions = true + break scan + } + } + } + + break scan + } + } + + if !hadReductions { + break + } + } + return entities } diff --git a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift index c55343b4e3..03321b3641 100644 --- a/submodules/TextFormat/Sources/StringWithAppliedEntities.swift +++ b/submodules/TextFormat/Sources/StringWithAppliedEntities.swift @@ -3,6 +3,8 @@ import UIKit import Postbox import TelegramCore import Display +import libprisma +import SwiftSignalKit public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [MessageTextEntity]) -> NSAttributedString { var nsString: NSString? @@ -26,28 +28,30 @@ public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [M range.length = stringLength - range.location } switch entity.type { - case .Url, .Email, .PhoneNumber, .Mention, .Hashtag, .BotCommand: - break - case .Bold: - string.addAttribute(ChatTextInputAttributes.bold, value: true as NSNumber, range: range) - case .Italic: - string.addAttribute(ChatTextInputAttributes.italic, value: true as NSNumber, range: range) - case let .TextMention(peerId): - string.addAttribute(ChatTextInputAttributes.textMention, value: ChatTextInputTextMentionAttribute(peerId: peerId), range: range) - case let .TextUrl(url): - string.addAttribute(ChatTextInputAttributes.textUrl, value: ChatTextInputTextUrlAttribute(url: url), range: range) - case .Code, .Pre: - string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range) - case .Strikethrough: - string.addAttribute(ChatTextInputAttributes.strikethrough, value: true as NSNumber, range: range) - case .Underline: - string.addAttribute(ChatTextInputAttributes.underline, value: true as NSNumber, range: range) - case .Spoiler: - string.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: range) - case let .CustomEmoji(_, fileId): - string.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: nil), range: range) - case .BlockQuote: - string.addAttribute(ChatTextInputAttributes.quote, value: ChatTextInputTextQuoteAttribute(), range: range) + case .Url, .Email, .PhoneNumber, .Mention, .Hashtag, .BotCommand: + break + case .Bold: + string.addAttribute(ChatTextInputAttributes.bold, value: true as NSNumber, range: range) + case .Italic: + string.addAttribute(ChatTextInputAttributes.italic, value: true as NSNumber, range: range) + case let .TextMention(peerId): + string.addAttribute(ChatTextInputAttributes.textMention, value: ChatTextInputTextMentionAttribute(peerId: peerId), range: range) + case let .TextUrl(url): + string.addAttribute(ChatTextInputAttributes.textUrl, value: ChatTextInputTextUrlAttribute(url: url), range: range) + case .Code: + string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range) + case .Strikethrough: + string.addAttribute(ChatTextInputAttributes.strikethrough, value: true as NSNumber, range: range) + case .Underline: + string.addAttribute(ChatTextInputAttributes.underline, value: true as NSNumber, range: range) + case .Spoiler: + string.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: range) + case let .CustomEmoji(_, fileId): + string.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: fileId, file: nil), range: range) + case let .Pre(language): + string.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .code(language: language)), range: range) + case .BlockQuote: + string.addAttribute(ChatTextInputAttributes.block, value: ChatTextInputTextQuoteAttribute(kind: .quote), range: range) default: break } @@ -55,7 +59,9 @@ public func chatInputStateStringWithAppliedEntities(_ text: String, entities: [M return string } -public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false) -> NSAttributedString { +private let syntaxHighlighter = Syntaxer() + +public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEntity], baseColor: UIColor, linkColor: UIColor, baseQuoteTintColor: UIColor? = nil, baseQuoteSecondaryTintColor: UIColor? = nil, baseQuoteTertiaryTintColor: UIColor? = nil, baseCodeBlockColor: UIColor? = nil, baseFont: UIFont, linkFont: UIFont, boldFont: UIFont, italicFont: UIFont, boldItalicFont: UIFont, fixedFont: UIFont, blockQuoteFont: UIFont, underlineLinks: Bool = true, external: Bool = false, message: Message?, entityFiles: [MediaId: TelegramMediaFile] = [:], adjustQuoteFontSize: Bool = false, cachedMessageSyntaxHighlight: CachedMessageSyntaxHighlight? = nil) -> NSAttributedString { let baseQuoteTintColor = baseQuoteTintColor ?? baseColor var nsString: NSString? @@ -199,22 +205,21 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti nsString = text as NSString } string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.BotCommand), value: nsString!.substring(with: range), range: range) - case .Pre: - addFontAttributes(range, .monospace) - if nsString == nil { - nsString = text as NSString - } - string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Pre), value: nsString!.substring(with: range), range: range) case .Code: + addFontAttributes(range, .monospace) + string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Code), value: nsString!.substring(with: range), range: range) + case let .Pre(language): addFontAttributes(range, .monospace) if nsString == nil { nsString = text as NSString } - string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.Code), value: nsString!.substring(with: range), range: range) + if let baseCodeBlockColor { + string.addAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), value: TextNodeBlockQuoteData(kind: .code(language: language), title: nil, color: baseCodeBlockColor, secondaryColor: nil, tertiaryColor: nil), range: range) + } case .BlockQuote: addFontAttributes(range, .blockQuote) - string.addAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), value: TextNodeBlockQuoteData(title: nil, color: baseQuoteTintColor, secondaryColor: baseQuoteSecondaryTintColor, tertiaryColor: baseQuoteTertiaryTintColor), range: range) + string.addAttribute(NSAttributedString.Key(rawValue: "Attribute__Blockquote"), value: TextNodeBlockQuoteData(kind: .quote, title: nil, color: baseQuoteTintColor, secondaryColor: baseQuoteSecondaryTintColor, tertiaryColor: baseQuoteTertiaryTintColor), range: range) case .BankCard: string.addAttribute(NSAttributedString.Key.foregroundColor, value: linkColor, range: range) if underlineLinks && underlineAllLinks { @@ -298,5 +303,233 @@ public func stringWithAppliedEntities(_ text: String, entities: [MessageTextEnti setFont(range: NSRange(location: currentAttributeSpan.startIndex, length: fontAttributeMask.count - currentAttributeSpan.startIndex), fontAttributes: currentAttributeSpan.attributes) } } + + string.enumerateAttribute(NSAttributedString.Key("Attribute__Blockquote"), in: NSRange(location: 0, length: string.length), using: { value, range, _ in + guard let value = value as? TextNodeBlockQuoteData, case let .code(language) = value.kind, let language, !language.isEmpty else { + return + } + + let codeText = (string.string as NSString).substring(with: range) + if let cachedMessageSyntaxHighlight, let entry = cachedMessageSyntaxHighlight.values[CachedMessageSyntaxHighlight.Spec(language: language, text: codeText)] { + for entity in entry.entities { + string.addAttribute(.foregroundColor, value: UIColor(rgb: UInt32(bitPattern: entity.color)), range: NSRange(location: range.location + entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound)) + } + } + }) + return string } + +public final class MessageSyntaxHighlight: Codable, Equatable { + public struct Entity: Codable, Equatable { + private enum CodingKeys: String, CodingKey { + case color = "c" + case rangeLow = "r" + case rangeLength = "rl" + } + + public var color: Int32 + public var range: Range + + public init(color: Int32, range: Range) { + self.color = color + self.range = range + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.color = try container.decode(Int32.self, forKey: .color) + let rangeLow = Int(try container.decode(Int32.self, forKey: .rangeLow)) + let rangeLength = Int(try container.decode(Int32.self, forKey: .rangeLength)) + self.range = rangeLow ..< (rangeLow + rangeLength) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.color, forKey: .color) + try container.encode(Int32(self.range.lowerBound), forKey: .rangeLow) + try container.encode(Int32(self.range.upperBound - self.range.lowerBound), forKey: .rangeLength) + } + } + + private enum CodingKeys: String, CodingKey { + case entities = "e" + } + + public let entities: [Entity] + + public init(entities: [Entity]) { + self.entities = entities + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.entities = try container.decode([Entity].self, forKey: .entities) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.entities, forKey: .entities) + } + + public static func ==(lhs: MessageSyntaxHighlight, rhs: MessageSyntaxHighlight) -> Bool { + if lhs.entities != rhs.entities { + return false + } + return true + } +} + +public final class CachedMessageSyntaxHighlight: Codable, Equatable { + public struct Spec: Hashable, Codable { + private enum CodingKeys: String, CodingKey { + case language = "l" + case text = "t" + } + + public var language: String + public var text: String + + public init(language: String, text: String) { + self.language = language + self.text = text + } + } + + private enum CodingKeys: String, CodingKey { + case values = "v" + } + + private struct CodingValueEntry: Codable { + private enum CodingKeys: String, CodingKey { + case key = "k" + case value = "v" + } + + let key: Spec + let value: MessageSyntaxHighlight + + init(key: Spec, value: MessageSyntaxHighlight) { + self.key = key + self.value = value + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.key = try container.decode(Spec.self, forKey: .key) + self.value = try container.decode(MessageSyntaxHighlight.self, forKey: .value) + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.key, forKey: .key) + try container.encode(self.value, forKey: .value) + } + } + + public let values: [Spec: MessageSyntaxHighlight] + + public init(values: [Spec: MessageSyntaxHighlight]) { + self.values = values + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let valueEntries = try container.decode([CodingValueEntry].self, forKey: .values) + var values: [Spec: MessageSyntaxHighlight] = [:] + for entry in valueEntries { + values[entry.key] = entry.value + } + self.values = values + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + let valueEntries = self.values.map { CodingValueEntry(key: $0.key, value: $0.value) } + try container.encode(valueEntries, forKey: .values) + } + + public static func ==(lhs: CachedMessageSyntaxHighlight, rhs: CachedMessageSyntaxHighlight) -> Bool { + if lhs.values != rhs.values { + return false + } + return true + } +} + +private let messageSyntaxHighlightQueue = Queue(name: "MessageSyntaxHighlight") + +public func extractMessageSyntaxHighlightSpecs(text: String, entities: [MessageTextEntity]) -> [CachedMessageSyntaxHighlight.Spec] { + if entities.isEmpty { + return [] + } + var result: [CachedMessageSyntaxHighlight.Spec] = [] + let nsString = text as NSString + for entity in entities { + if case let .Pre(language) = entity.type, let language, !language.isEmpty { + var range = entity.range + if range.lowerBound < 0 { + range = 0 ..< range.upperBound + } + if range.upperBound > nsString.length { + range = range.lowerBound ..< nsString.length + } + if range.upperBound != range.lowerBound { + result.append(CachedMessageSyntaxHighlight.Spec(language: language, text: nsString.substring(with: NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound)))) + } + } + } + + return result +} + +private let internalFixedCodeFont = Font.regular(17.0) + +public func asyncUpdateMessageSyntaxHighlight(engine: TelegramEngine, messageId: EngineMessage.Id, current: CachedMessageSyntaxHighlight?, specs: [CachedMessageSyntaxHighlight.Spec]) -> Signal { + if let current, !specs.contains(where: { current.values[$0] == nil }) { + return .complete() + } + + return Signal { subscriber in + var updated: [CachedMessageSyntaxHighlight.Spec: MessageSyntaxHighlight] = [:] + + let theme = SyntaxterTheme(dark: false, textColor: .black, textFont: internalFixedCodeFont, italicFont: internalFixedCodeFont, mediumFont: internalFixedCodeFont) + + for spec in specs { + if let value = current?.values[spec] { + updated[spec] = value + } else { + var entities: [MessageSyntaxHighlight.Entity] = [] + + if let syntaxHighlighter { + if let highlightedString = syntaxHighlighter.syntax(spec.text, language: spec.language, theme: theme) { + highlightedString.enumerateAttribute(.foregroundColor, in: NSRange(location: 0, length: highlightedString.length), using: { value, subRange, _ in + if let value = value as? UIColor, value != .black { + entities.append(MessageSyntaxHighlight.Entity(color: Int32(bitPattern: value.rgb), range: subRange.lowerBound ..< subRange.upperBound)) + } + }) + } + } + + updated[spec] = MessageSyntaxHighlight(entities: entities) + } + } + + if let entry = CodableEntry(CachedMessageSyntaxHighlight(values: updated)) { + return engine.messages.storeLocallyDerivedData(messageId: messageId, data: ["code": entry]).start(completed: { + subscriber.putCompletion() + }) + } else { + return EmptyDisposable + } + } + |> runOn(messageSyntaxHighlightQueue) +} diff --git a/submodules/TextInputMenu/Sources/TextInputMenu.swift b/submodules/TextInputMenu/Sources/TextInputMenu.swift index 6046e69d6d..343316b9f8 100644 --- a/submodules/TextInputMenu/Sources/TextInputMenu.swift +++ b/submodules/TextInputMenu/Sources/TextInputMenu.swift @@ -25,28 +25,29 @@ public final class TextInputMenu { didSet { if self.state != oldValue { switch self.state { - case .inactive: - UIMenuController.shared.menuItems = [] - case .general: - UIMenuController.shared.menuItems = [] - case .format: - var menuItems: [UIMenuItem] = [ - UIMenuItem(title: self.stringBold, action: Selector(("formatAttributesBold:"))), - UIMenuItem(title: self.stringItalic, action: Selector(("formatAttributesItalic:"))), - UIMenuItem(title: self.stringMonospace, action: Selector(("formatAttributesMonospace:"))), - UIMenuItem(title: self.stringLink, action: Selector(("formatAttributesLink:"))), - UIMenuItem(title: self.stringStrikethrough, action: Selector(("formatAttributesStrikethrough:"))), - UIMenuItem(title: self.stringUnderline, action: Selector(("formatAttributesUnderline:"))) - ] - if self.hasSpoilers { - menuItems.insert(UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:"))), at: 0) - } + case .inactive: + UIMenuController.shared.menuItems = [] + case .general: + UIMenuController.shared.menuItems = [] + case .format: + var menuItems: [UIMenuItem] = [ + UIMenuItem(title: self.stringBold, action: Selector(("formatAttributesBold:"))), + UIMenuItem(title: self.stringItalic, action: Selector(("formatAttributesItalic:"))), + UIMenuItem(title: self.stringMonospace, action: Selector(("formatAttributesMonospace:"))), + UIMenuItem(title: self.stringLink, action: Selector(("formatAttributesLink:"))), + UIMenuItem(title: self.stringStrikethrough, action: Selector(("formatAttributesStrikethrough:"))), + UIMenuItem(title: self.stringUnderline, action: Selector(("formatAttributesUnderline:"))) + ] + if self.hasSpoilers { + menuItems.insert(UIMenuItem(title: self.stringSpoiler, action: Selector(("formatAttributesSpoiler:"))), at: 0) + } if self.hasQuotes { menuItems.insert(UIMenuItem(title: self.stringQuote, action: Selector(("formatAttributesQuote:"))), at: 0) + //TODO:localize + menuItems.append(UIMenuItem(title: "Code", action: Selector(("formatAttributesCodeBlock:")))) } - UIMenuController.shared.menuItems = menuItems + UIMenuController.shared.menuItems = menuItems } - } } } diff --git a/third-party/boost_regex/BUILD b/third-party/boost_regex/BUILD new file mode 100644 index 0000000000..6378492f2d --- /dev/null +++ b/third-party/boost_regex/BUILD @@ -0,0 +1,26 @@ + +objc_library( + name = "boost_regex", + enable_modules = True, + module_name = "boost_regex", + srcs = glob([ + "Sources/**/*.c", + "Sources/**/*.cpp", + "Sources/**/*.h", + "Sources/**/*.hpp", + ]), + hdrs = glob([ + "include/boost_regex/*.h", + ]), + includes = [ + "include", + ], + copts = [ + "-Ithird-party/boost_regex/include", + ], + deps = [ + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/third-party/boost_regex/include/boost/cregex.hpp b/third-party/boost_regex/include/boost/cregex.hpp new file mode 100644 index 0000000000..78012dd658 --- /dev/null +++ b/third-party/boost_regex/include/boost/cregex.hpp @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/libs/regex for most recent version. + * FILE cregex.cpp + * VERSION see + * DESCRIPTION: Declares POSIX API functions + * + boost::RegEx high level wrapper. + */ + +#ifndef BOOST_RE_CREGEX_HPP +#define BOOST_RE_CREGEX_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif /* include guard */ + + + + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex.h b/third-party/boost_regex/include/boost/regex.h new file mode 100644 index 0000000000..52af275cfa --- /dev/null +++ b/third-party/boost_regex/include/boost/regex.h @@ -0,0 +1,100 @@ +/* + * + * Copyright (c) 1998-2000 + * Dr John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/libs/regex for documentation. + * FILE regex.h + * VERSION 3.12 + * DESCRIPTION: Declares POSIX API functions + */ + +#ifndef BOOST_RE_REGEX_H +#define BOOST_RE_REGEX_H + +#include + +/* +* add using declarations to bring POSIX API functions into +* global scope, only if this is C++ (and not C). +*/ +#ifdef __cplusplus + +using boost::regoff_t; +using boost::regex_tA; +using boost::regmatch_t; +using boost::REG_BASIC; +using boost::REG_EXTENDED; +using boost::REG_ICASE; +using boost::REG_NOSUB; +using boost::REG_NEWLINE; +using boost::REG_NOSPEC; +using boost::REG_PEND; +using boost::REG_DUMP; +using boost::REG_NOCOLLATE; +using boost::REG_ESCAPE_IN_LISTS; +using boost::REG_NEWLINE_ALT; +using boost::REG_PERL; +using boost::REG_AWK; +using boost::REG_GREP; +using boost::REG_EGREP; +using boost::REG_ASSERT; +using boost::REG_INVARG; +using boost::REG_ATOI; +using boost::REG_ITOA; + +using boost::REG_NOTBOL; +using boost::REG_NOTEOL; +using boost::REG_STARTEND; + +using boost::reg_comp_flags; +using boost::reg_exec_flags; +using boost::regcompA; +using boost::regerrorA; +using boost::regexecA; +using boost::regfreeA; + +#ifndef BOOST_NO_WREGEX +using boost::regcompW; +using boost::regerrorW; +using boost::regexecW; +using boost::regfreeW; +using boost::regex_tW; +#endif + +using boost::REG_NOERROR; +using boost::REG_NOMATCH; +using boost::REG_BADPAT; +using boost::REG_ECOLLATE; +using boost::REG_ECTYPE; +using boost::REG_EESCAPE; +using boost::REG_ESUBREG; +using boost::REG_EBRACK; +using boost::REG_EPAREN; +using boost::REG_EBRACE; +using boost::REG_BADBR; +using boost::REG_ERANGE; +using boost::REG_ESPACE; +using boost::REG_BADRPT; +using boost::REG_EEND; +using boost::REG_ESIZE; +using boost::REG_ERPAREN; +using boost::REG_EMPTY; +using boost::REG_E_MEMORY; +using boost::REG_E_UNKNOWN; +using boost::reg_errcode_t; + +#endif /* __cplusplus */ + +#endif /* BOOST_RE_REGEX_H */ + + + + diff --git a/third-party/boost_regex/include/boost/regex.hpp b/third-party/boost_regex/include/boost/regex.hpp new file mode 100644 index 0000000000..b0c8bf13c7 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex.hpp @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/libs/regex for documentation. + * FILE regex.cpp + * VERSION see + * DESCRIPTION: Declares boost::basic_regex<> and associated + * functions and classes. This header is the main + * entry point for the template regex code. + */ + + +/* start with C compatibility API */ + +#ifndef BOOST_RE_REGEX_HPP +#define BOOST_RE_REGEX_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif // include + + + + diff --git a/third-party/boost_regex/include/boost/regex/concepts.hpp b/third-party/boost_regex/include/boost/regex/concepts.hpp new file mode 100644 index 0000000000..2eafac1b57 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/concepts.hpp @@ -0,0 +1,1134 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE concepts.hpp + * VERSION see + * DESCRIPTION: Declares regular expression concepts. + */ + +#ifndef BOOST_REGEX_CONCEPTS_HPP_INCLUDED +#define BOOST_REGEX_CONCEPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#ifndef BOOST_TEST_TR1_REGEX +#include +#endif +#include +#include +#include + +#ifdef BOOST_REGEX_CXX03 +#define RW_NS boost +#else +#define RW_NS std +#endif + +namespace boost{ + +// +// bitmask_archetype: +// this can be either an integer type, an enum, or a std::bitset, +// we use the latter as the architype as it offers the "strictest" +// of the possible interfaces: +// +typedef std::bitset<512> bitmask_archetype; +// +// char_architype: +// A strict model for the character type interface. +// +struct char_architype +{ + // default constructable: + char_architype(); + // copy constructable / assignable: + char_architype(const char_architype&); + char_architype& operator=(const char_architype&); + // constructable from an integral value: + char_architype(unsigned long val); + // comparable: + bool operator==(const char_architype&)const; + bool operator!=(const char_architype&)const; + bool operator<(const char_architype&)const; + bool operator<=(const char_architype&)const; + bool operator>=(const char_architype&)const; + bool operator>(const char_architype&)const; + // conversion to integral type: + operator long()const; +}; +inline long hash_value(char_architype val) +{ return val; } +// +// char_architype can not be used with basic_string: +// +} // namespace boost +namespace std{ + template<> struct char_traits + { + // The intent is that this template is not instantiated, + // but this typedef gives us a chance of compilation in + // case it is: + typedef boost::char_architype char_type; + }; +} +// +// Allocator architype: +// +template +class allocator_architype +{ +public: + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef unsigned size_type; + typedef int difference_type; + + template + struct rebind + { + typedef allocator_architype other; + }; + + pointer address(reference r){ return &r; } + const_pointer address(const_reference r) { return &r; } + pointer allocate(size_type n) { return static_cast(std::malloc(n)); } + pointer allocate(size_type n, pointer) { return static_cast(std::malloc(n)); } + void deallocate(pointer p, size_type) { std::free(p); } + size_type max_size()const { return UINT_MAX; } + + allocator_architype(){} + allocator_architype(const allocator_architype&){} + + template + allocator_architype(const allocator_architype&){} + + void construct(pointer p, const_reference r) { new (p)T(r); } + void destroy(pointer p) { p->~T(); } +}; + +template +bool operator == (const allocator_architype&, const allocator_architype&) {return true; } +template +bool operator != (const allocator_architype&, const allocator_architype&) { return false; } + +namespace boost{ +// +// regex_traits_architype: +// A strict interpretation of the regular expression traits class requirements. +// +template +struct regex_traits_architype +{ +public: + regex_traits_architype(){} + typedef charT char_type; + // typedef std::size_t size_type; + typedef std::vector string_type; + typedef copy_constructible_archetype > locale_type; + typedef bitmask_archetype char_class_type; + + static std::size_t length(const char_type* ) { return 0; } + + charT translate(charT ) const { return charT(); } + charT translate_nocase(charT ) const { return static_object::get(); } + + template + string_type transform(ForwardIterator , ForwardIterator ) const + { return static_object::get(); } + template + string_type transform_primary(ForwardIterator , ForwardIterator ) const + { return static_object::get(); } + + template + char_class_type lookup_classname(ForwardIterator , ForwardIterator ) const + { return static_object::get(); } + template + string_type lookup_collatename(ForwardIterator , ForwardIterator ) const + { return static_object::get(); } + + bool isctype(charT, char_class_type) const + { return false; } + int value(charT, int) const + { return 0; } + + locale_type imbue(locale_type l) + { return l; } + locale_type getloc()const + { return static_object::get(); } + +private: + // this type is not copyable: + regex_traits_architype(const regex_traits_architype&){} + regex_traits_architype& operator=(const regex_traits_architype&){ return *this; } +}; + +// +// alter this to std::tr1, to test a std implementation: +// +#ifndef BOOST_TEST_TR1_REGEX +namespace global_regex_namespace = ::boost; +#else +namespace global_regex_namespace = ::std::tr1; +#endif + +template +struct BitmaskConcept +{ + void constraints() + { + function_requires >(); + function_requires >(); + + m_mask1 = m_mask2 | m_mask3; + m_mask1 = m_mask2 & m_mask3; + m_mask1 = m_mask2 ^ m_mask3; + + m_mask1 = ~m_mask2; + + m_mask1 |= m_mask2; + m_mask1 &= m_mask2; + m_mask1 ^= m_mask2; + } + Bitmask m_mask1, m_mask2, m_mask3; +}; + +template +struct RegexTraitsConcept +{ + RegexTraitsConcept(); + // required typedefs: + typedef typename traits::char_type char_type; + // typedef typename traits::size_type size_type; + typedef typename traits::string_type string_type; + typedef typename traits::locale_type locale_type; + typedef typename traits::char_class_type char_class_type; + + void constraints() + { + //function_requires >(); + function_requires >(); + function_requires >(); + function_requires >(); + function_requires >(); + function_requires >(); + + std::size_t n = traits::length(m_pointer); + ignore_unused_variable_warning(n); + + char_type c = m_ctraits.translate(m_char); + ignore_unused_variable_warning(c); + c = m_ctraits.translate_nocase(m_char); + + //string_type::foobar bar; + string_type s1 = m_ctraits.transform(m_pointer, m_pointer); + ignore_unused_variable_warning(s1); + + string_type s2 = m_ctraits.transform_primary(m_pointer, m_pointer); + ignore_unused_variable_warning(s2); + + char_class_type cc = m_ctraits.lookup_classname(m_pointer, m_pointer); + ignore_unused_variable_warning(cc); + + string_type s3 = m_ctraits.lookup_collatename(m_pointer, m_pointer); + ignore_unused_variable_warning(s3); + + bool b = m_ctraits.isctype(m_char, cc); + ignore_unused_variable_warning(b); + + int v = m_ctraits.value(m_char, 16); + ignore_unused_variable_warning(v); + + locale_type l(m_ctraits.getloc()); + m_traits.imbue(l); + ignore_unused_variable_warning(l); + } + traits m_traits; + const traits m_ctraits; + const char_type* m_pointer; + char_type m_char; +private: + RegexTraitsConcept& operator=(RegexTraitsConcept&); +}; + +// +// helper class to compute what traits class a regular expression type is using: +// +template +struct regex_traits_computer; + +template +struct regex_traits_computer< global_regex_namespace::basic_regex > +{ + typedef traits type; +}; + +// +// BaseRegexConcept does not test anything dependent on basic_string, +// in case our charT does not have an associated char_traits: +// +template +struct BaseRegexConcept +{ + typedef typename Regex::value_type value_type; + //typedef typename Regex::size_type size_type; + typedef typename Regex::flag_type flag_type; + typedef typename Regex::locale_type locale_type; + typedef input_iterator_archetype input_iterator_type; + + // derived test types: + typedef const value_type* pointer_type; + typedef bidirectional_iterator_archetype BidiIterator; + typedef global_regex_namespace::sub_match sub_match_type; + typedef global_regex_namespace::match_results > match_results_type; + typedef global_regex_namespace::match_results match_results_default_type; + typedef output_iterator_archetype OutIterator; + typedef typename regex_traits_computer::type traits_type; + typedef global_regex_namespace::regex_iterator regex_iterator_type; + typedef global_regex_namespace::regex_token_iterator regex_token_iterator_type; + + void global_constraints() + { + // + // test non-template components: + // + function_requires >(); + global_regex_namespace::regex_constants::syntax_option_type opts + = global_regex_namespace::regex_constants::icase + | global_regex_namespace::regex_constants::nosubs + | global_regex_namespace::regex_constants::optimize + | global_regex_namespace::regex_constants::collate + | global_regex_namespace::regex_constants::ECMAScript + | global_regex_namespace::regex_constants::basic + | global_regex_namespace::regex_constants::extended + | global_regex_namespace::regex_constants::awk + | global_regex_namespace::regex_constants::grep + | global_regex_namespace::regex_constants::egrep; + ignore_unused_variable_warning(opts); + + function_requires >(); + global_regex_namespace::regex_constants::match_flag_type mopts + = global_regex_namespace::regex_constants::match_default + | global_regex_namespace::regex_constants::match_not_bol + | global_regex_namespace::regex_constants::match_not_eol + | global_regex_namespace::regex_constants::match_not_bow + | global_regex_namespace::regex_constants::match_not_eow + | global_regex_namespace::regex_constants::match_any + | global_regex_namespace::regex_constants::match_not_null + | global_regex_namespace::regex_constants::match_continuous + | global_regex_namespace::regex_constants::match_prev_avail + | global_regex_namespace::regex_constants::format_default + | global_regex_namespace::regex_constants::format_sed + | global_regex_namespace::regex_constants::format_no_copy + | global_regex_namespace::regex_constants::format_first_only; + ignore_unused_variable_warning(mopts); + + BOOST_STATIC_ASSERT((::boost::is_enum::value)); + global_regex_namespace::regex_constants::error_type e1 = global_regex_namespace::regex_constants::error_collate; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_ctype; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_escape; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_backref; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_brack; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_paren; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_brace; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_badbrace; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_range; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_space; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_badrepeat; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_complexity; + ignore_unused_variable_warning(e1); + e1 = global_regex_namespace::regex_constants::error_stack; + ignore_unused_variable_warning(e1); + + BOOST_STATIC_ASSERT((::boost::is_base_and_derived::value )); + const global_regex_namespace::regex_error except(e1); + e1 = except.code(); + + typedef typename Regex::value_type regex_value_type; + function_requires< RegexTraitsConcept > >(); + function_requires< BaseRegexConcept > >(); + } + void constraints() + { + global_constraints(); + + BOOST_STATIC_ASSERT((::boost::is_same< flag_type, global_regex_namespace::regex_constants::syntax_option_type>::value)); + flag_type opts + = Regex::icase + | Regex::nosubs + | Regex::optimize + | Regex::collate + | Regex::ECMAScript + | Regex::basic + | Regex::extended + | Regex::awk + | Regex::grep + | Regex::egrep; + ignore_unused_variable_warning(opts); + + function_requires >(); + function_requires >(); + + // Regex constructors: + Regex e1(m_pointer); + ignore_unused_variable_warning(e1); + Regex e2(m_pointer, m_flags); + ignore_unused_variable_warning(e2); + Regex e3(m_pointer, m_size, m_flags); + ignore_unused_variable_warning(e3); + Regex e4(in1, in2); + ignore_unused_variable_warning(e4); + Regex e5(in1, in2, m_flags); + ignore_unused_variable_warning(e5); + + // assign etc: + Regex e; + e = m_pointer; + e = e1; + e.assign(e1); + e.assign(m_pointer); + e.assign(m_pointer, m_flags); + e.assign(m_pointer, m_size, m_flags); + e.assign(in1, in2); + e.assign(in1, in2, m_flags); + + // access: + const Regex ce; + typename Regex::size_type i = ce.mark_count(); + ignore_unused_variable_warning(i); + m_flags = ce.flags(); + e.imbue(ce.getloc()); + e.swap(e1); + + global_regex_namespace::swap(e, e1); + + // sub_match: + BOOST_STATIC_ASSERT((::boost::is_base_and_derived, sub_match_type>::value)); + typedef typename sub_match_type::value_type sub_value_type; + typedef typename sub_match_type::difference_type sub_diff_type; + typedef typename sub_match_type::iterator sub_iter_type; + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + bool b = m_sub.matched; + ignore_unused_variable_warning(b); + BidiIterator bi = m_sub.first; + ignore_unused_variable_warning(bi); + bi = m_sub.second; + ignore_unused_variable_warning(bi); + sub_diff_type diff = m_sub.length(); + ignore_unused_variable_warning(diff); + // match_results tests - some typedefs are not used, however these + // guarante that they exist (some compilers may warn on non-usage) + typedef typename match_results_type::value_type mr_value_type; + typedef typename match_results_type::const_reference mr_const_reference; + typedef typename match_results_type::reference mr_reference; + typedef typename match_results_type::const_iterator mr_const_iterator; + typedef typename match_results_type::iterator mr_iterator; + typedef typename match_results_type::difference_type mr_difference_type; + typedef typename match_results_type::size_type mr_size_type; + typedef typename match_results_type::allocator_type mr_allocator_type; + typedef typename match_results_type::char_type mr_char_type; + typedef typename match_results_type::string_type mr_string_type; + + match_results_type m1; + mr_allocator_type at; + match_results_type m2(at); + match_results_type m3(m1); + m1 = m2; + + int ival = 0; + + mr_size_type mrs = m_cresults.size(); + ignore_unused_variable_warning(mrs); + mrs = m_cresults.max_size(); + ignore_unused_variable_warning(mrs); + b = m_cresults.empty(); + ignore_unused_variable_warning(b); + mr_difference_type mrd = m_cresults.length(); + ignore_unused_variable_warning(mrd); + mrd = m_cresults.length(ival); + ignore_unused_variable_warning(mrd); + mrd = m_cresults.position(); + ignore_unused_variable_warning(mrd); + mrd = m_cresults.position(mrs); + ignore_unused_variable_warning(mrd); + + mr_const_reference mrcr = m_cresults[ival]; + ignore_unused_variable_warning(mrcr); + mr_const_reference mrcr2 = m_cresults.prefix(); + ignore_unused_variable_warning(mrcr2); + mr_const_reference mrcr3 = m_cresults.suffix(); + ignore_unused_variable_warning(mrcr3); + mr_const_iterator mrci = m_cresults.begin(); + ignore_unused_variable_warning(mrci); + mrci = m_cresults.end(); + ignore_unused_variable_warning(mrci); + + (void) m_cresults.get_allocator(); + m_results.swap(m_results); + global_regex_namespace::swap(m_results, m_results); + + // regex_match: + b = global_regex_namespace::regex_match(m_in, m_in, m_results, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_in, m_in, m_results, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_in, m_in, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_in, m_in, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_pointer, m_pmatch, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_pointer, m_pmatch, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_pointer, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_pointer, e, m_mft); + ignore_unused_variable_warning(b); + // regex_search: + b = global_regex_namespace::regex_search(m_in, m_in, m_results, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_in, m_in, m_results, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_in, m_in, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_in, m_in, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_pointer, m_pmatch, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_pointer, m_pmatch, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_pointer, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_pointer, e, m_mft); + ignore_unused_variable_warning(b); + + // regex_iterator: + typedef typename regex_iterator_type::regex_type rit_regex_type; + typedef typename regex_iterator_type::value_type rit_value_type; + typedef typename regex_iterator_type::difference_type rit_difference_type; + typedef typename regex_iterator_type::pointer rit_pointer; + typedef typename regex_iterator_type::reference rit_reference; + typedef typename regex_iterator_type::iterator_category rit_iterator_category; + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_convertible::value)); + // this takes care of most of the checks needed: + function_requires >(); + regex_iterator_type iter1(m_in, m_in, e); + ignore_unused_variable_warning(iter1); + regex_iterator_type iter2(m_in, m_in, e, m_mft); + ignore_unused_variable_warning(iter2); + + // regex_token_iterator: + typedef typename regex_token_iterator_type::regex_type rtit_regex_type; + typedef typename regex_token_iterator_type::value_type rtit_value_type; + typedef typename regex_token_iterator_type::difference_type rtit_difference_type; + typedef typename regex_token_iterator_type::pointer rtit_pointer; + typedef typename regex_token_iterator_type::reference rtit_reference; + typedef typename regex_token_iterator_type::iterator_category rtit_iterator_category; + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_same::value)); + BOOST_STATIC_ASSERT((::boost::is_convertible::value)); + // this takes care of most of the checks needed: + function_requires >(); + regex_token_iterator_type ti1(m_in, m_in, e); + ignore_unused_variable_warning(ti1); + regex_token_iterator_type ti2(m_in, m_in, e, 0); + ignore_unused_variable_warning(ti2); + regex_token_iterator_type ti3(m_in, m_in, e, 0, m_mft); + ignore_unused_variable_warning(ti3); + std::vector subs; + regex_token_iterator_type ti4(m_in, m_in, e, subs); + ignore_unused_variable_warning(ti4); + regex_token_iterator_type ti5(m_in, m_in, e, subs, m_mft); + ignore_unused_variable_warning(ti5); + static const int i_array[3] = { 1, 2, 3, }; + regex_token_iterator_type ti6(m_in, m_in, e, i_array); + ignore_unused_variable_warning(ti6); + regex_token_iterator_type ti7(m_in, m_in, e, i_array, m_mft); + ignore_unused_variable_warning(ti7); + } + + pointer_type m_pointer; + flag_type m_flags; + std::size_t m_size; + input_iterator_type in1, in2; + const sub_match_type m_sub; + const value_type m_char; + match_results_type m_results; + const match_results_type m_cresults; + OutIterator m_out; + BidiIterator m_in; + global_regex_namespace::regex_constants::match_flag_type m_mft; + global_regex_namespace::match_results< + pointer_type, + allocator_architype > > + m_pmatch; + + BaseRegexConcept(); + BaseRegexConcept(const BaseRegexConcept&); + BaseRegexConcept& operator=(const BaseRegexConcept&); +}; + +// +// RegexConcept: +// Test every interface in the std: +// +template +struct RegexConcept +{ + typedef typename Regex::value_type value_type; + //typedef typename Regex::size_type size_type; + typedef typename Regex::flag_type flag_type; + typedef typename Regex::locale_type locale_type; + + // derived test types: + typedef const value_type* pointer_type; + typedef std::basic_string string_type; + typedef boost::bidirectional_iterator_archetype BidiIterator; + typedef global_regex_namespace::sub_match sub_match_type; + typedef global_regex_namespace::match_results > match_results_type; + typedef output_iterator_archetype OutIterator; + + + void constraints() + { + function_requires >(); + // string based construct: + Regex e1(m_string); + ignore_unused_variable_warning(e1); + Regex e2(m_string, m_flags); + ignore_unused_variable_warning(e2); + + // assign etc: + Regex e; + e = m_string; + e.assign(m_string); + e.assign(m_string, m_flags); + + // sub_match: + string_type s(m_sub); + ignore_unused_variable_warning(s); + s = m_sub.str(); + ignore_unused_variable_warning(s); + int i = m_sub.compare(m_string); + ignore_unused_variable_warning(i); + + int i2 = m_sub.compare(m_sub); + ignore_unused_variable_warning(i2); + i2 = m_sub.compare(m_pointer); + ignore_unused_variable_warning(i2); + + bool b = m_sub == m_sub; + ignore_unused_variable_warning(b); + b = m_sub != m_sub; + ignore_unused_variable_warning(b); + b = m_sub <= m_sub; + ignore_unused_variable_warning(b); + b = m_sub <= m_sub; + ignore_unused_variable_warning(b); + b = m_sub > m_sub; + ignore_unused_variable_warning(b); + b = m_sub >= m_sub; + ignore_unused_variable_warning(b); + + b = m_sub == m_pointer; + ignore_unused_variable_warning(b); + b = m_sub != m_pointer; + ignore_unused_variable_warning(b); + b = m_sub <= m_pointer; + ignore_unused_variable_warning(b); + b = m_sub <= m_pointer; + ignore_unused_variable_warning(b); + b = m_sub > m_pointer; + ignore_unused_variable_warning(b); + b = m_sub >= m_pointer; + ignore_unused_variable_warning(b); + + b = m_pointer == m_sub; + ignore_unused_variable_warning(b); + b = m_pointer != m_sub; + ignore_unused_variable_warning(b); + b = m_pointer <= m_sub; + ignore_unused_variable_warning(b); + b = m_pointer <= m_sub; + ignore_unused_variable_warning(b); + b = m_pointer > m_sub; + ignore_unused_variable_warning(b); + b = m_pointer >= m_sub; + ignore_unused_variable_warning(b); + + b = m_sub == m_char; + ignore_unused_variable_warning(b); + b = m_sub != m_char; + ignore_unused_variable_warning(b); + b = m_sub <= m_char; + ignore_unused_variable_warning(b); + b = m_sub <= m_char; + ignore_unused_variable_warning(b); + b = m_sub > m_char; + ignore_unused_variable_warning(b); + b = m_sub >= m_char; + ignore_unused_variable_warning(b); + + b = m_char == m_sub; + ignore_unused_variable_warning(b); + b = m_char != m_sub; + ignore_unused_variable_warning(b); + b = m_char <= m_sub; + ignore_unused_variable_warning(b); + b = m_char <= m_sub; + ignore_unused_variable_warning(b); + b = m_char > m_sub; + ignore_unused_variable_warning(b); + b = m_char >= m_sub; + ignore_unused_variable_warning(b); + + b = m_sub == m_string; + ignore_unused_variable_warning(b); + b = m_sub != m_string; + ignore_unused_variable_warning(b); + b = m_sub <= m_string; + ignore_unused_variable_warning(b); + b = m_sub <= m_string; + ignore_unused_variable_warning(b); + b = m_sub > m_string; + ignore_unused_variable_warning(b); + b = m_sub >= m_string; + ignore_unused_variable_warning(b); + + b = m_string == m_sub; + ignore_unused_variable_warning(b); + b = m_string != m_sub; + ignore_unused_variable_warning(b); + b = m_string <= m_sub; + ignore_unused_variable_warning(b); + b = m_string <= m_sub; + ignore_unused_variable_warning(b); + b = m_string > m_sub; + ignore_unused_variable_warning(b); + b = m_string >= m_sub; + ignore_unused_variable_warning(b); + + // match results: + m_string = m_results.str(); + ignore_unused_variable_warning(m_string); + m_string = m_results.str(0); + ignore_unused_variable_warning(m_string); + m_out = m_cresults.format(m_out, m_string); + m_out = m_cresults.format(m_out, m_string, m_mft); + m_string = m_cresults.format(m_string); + ignore_unused_variable_warning(m_string); + m_string = m_cresults.format(m_string, m_mft); + ignore_unused_variable_warning(m_string); + + // regex_match: + b = global_regex_namespace::regex_match(m_string, m_smatch, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_string, m_smatch, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_string, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_match(m_string, e, m_mft); + ignore_unused_variable_warning(b); + + // regex_search: + b = global_regex_namespace::regex_search(m_string, m_smatch, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_string, m_smatch, e, m_mft); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_string, e); + ignore_unused_variable_warning(b); + b = global_regex_namespace::regex_search(m_string, e, m_mft); + ignore_unused_variable_warning(b); + + // regex_replace: + m_out = global_regex_namespace::regex_replace(m_out, m_in, m_in, e, m_string, m_mft); + m_out = global_regex_namespace::regex_replace(m_out, m_in, m_in, e, m_string); + m_string = global_regex_namespace::regex_replace(m_string, e, m_string, m_mft); + ignore_unused_variable_warning(m_string); + m_string = global_regex_namespace::regex_replace(m_string, e, m_string); + ignore_unused_variable_warning(m_string); + + } + + flag_type m_flags; + string_type m_string; + const sub_match_type m_sub; + match_results_type m_results; + pointer_type m_pointer; + value_type m_char; + const match_results_type m_cresults; + OutIterator m_out; + BidiIterator m_in; + global_regex_namespace::regex_constants::match_flag_type m_mft; + global_regex_namespace::match_results > > m_smatch; + + RegexConcept(); + RegexConcept(const RegexConcept&); + RegexConcept& operator=(const RegexConcept&); +}; + +#ifndef BOOST_REGEX_TEST_STD + +template +struct functor1 +{ + typedef typename M::char_type char_type; + const char_type* operator()(const M&)const + { + static const char_type c = static_cast(0); + return &c; + } +}; +template +struct functor1b +{ + typedef typename M::char_type char_type; + std::vector operator()(const M&)const + { + static const std::vector c; + return c; + } +}; +template +struct functor2 +{ + template + O operator()(const M& /*m*/, O i)const + { + return i; + } +}; +template +struct functor3 +{ + template + O operator()(const M& /*m*/, O i, regex_constants::match_flag_type)const + { + return i; + } +}; + +// +// BoostRegexConcept: +// Test every interface in the Boost implementation: +// +template +struct BoostRegexConcept +{ + typedef typename Regex::value_type value_type; + typedef typename Regex::size_type size_type; + typedef typename Regex::flag_type flag_type; + typedef typename Regex::locale_type locale_type; + + // derived test types: + typedef const value_type* pointer_type; + typedef std::basic_string string_type; + typedef typename Regex::const_iterator const_iterator; + typedef bidirectional_iterator_archetype BidiIterator; + typedef output_iterator_archetype OutputIterator; + typedef global_regex_namespace::sub_match sub_match_type; + typedef global_regex_namespace::match_results > match_results_type; + typedef global_regex_namespace::match_results match_results_default_type; + + void constraints() + { + global_regex_namespace::regex_constants::match_flag_type mopts + = global_regex_namespace::regex_constants::match_default + | global_regex_namespace::regex_constants::match_not_bol + | global_regex_namespace::regex_constants::match_not_eol + | global_regex_namespace::regex_constants::match_not_bow + | global_regex_namespace::regex_constants::match_not_eow + | global_regex_namespace::regex_constants::match_any + | global_regex_namespace::regex_constants::match_not_null + | global_regex_namespace::regex_constants::match_continuous + | global_regex_namespace::regex_constants::match_partial + | global_regex_namespace::regex_constants::match_prev_avail + | global_regex_namespace::regex_constants::format_default + | global_regex_namespace::regex_constants::format_sed + | global_regex_namespace::regex_constants::format_perl + | global_regex_namespace::regex_constants::format_no_copy + | global_regex_namespace::regex_constants::format_first_only; + + (void)mopts; + + function_requires >(); + const global_regex_namespace::regex_error except(global_regex_namespace::regex_constants::error_collate); + std::ptrdiff_t pt = except.position(); + ignore_unused_variable_warning(pt); + const Regex ce, ce2; +#ifndef BOOST_NO_STD_LOCALE + m_stream << ce; +#endif + unsigned i = ce.error_code(); + ignore_unused_variable_warning(i); + pointer_type p = ce.expression(); + ignore_unused_variable_warning(p); + int i2 = ce.compare(ce2); + ignore_unused_variable_warning(i2); + bool b = ce == ce2; + ignore_unused_variable_warning(b); + b = ce.empty(); + ignore_unused_variable_warning(b); + b = ce != ce2; + ignore_unused_variable_warning(b); + b = ce < ce2; + ignore_unused_variable_warning(b); + b = ce > ce2; + ignore_unused_variable_warning(b); + b = ce <= ce2; + ignore_unused_variable_warning(b); + b = ce >= ce2; + ignore_unused_variable_warning(b); + i = ce.status(); + ignore_unused_variable_warning(i); + size_type s = ce.max_size(); + ignore_unused_variable_warning(s); + s = ce.size(); + ignore_unused_variable_warning(s); + const_iterator pi = ce.begin(); + ignore_unused_variable_warning(pi); + pi = ce.end(); + ignore_unused_variable_warning(pi); + string_type s2 = ce.str(); + ignore_unused_variable_warning(s2); + + m_string = m_sub + m_sub; + ignore_unused_variable_warning(m_string); + m_string = m_sub + m_pointer; + ignore_unused_variable_warning(m_string); + m_string = m_pointer + m_sub; + ignore_unused_variable_warning(m_string); + m_string = m_sub + m_string; + ignore_unused_variable_warning(m_string); + m_string = m_string + m_sub; + ignore_unused_variable_warning(m_string); + m_string = m_sub + m_char; + ignore_unused_variable_warning(m_string); + m_string = m_char + m_sub; + ignore_unused_variable_warning(m_string); + + // Named sub-expressions: + m_sub = m_cresults[&m_char]; + ignore_unused_variable_warning(m_sub); + m_sub = m_cresults[m_string]; + ignore_unused_variable_warning(m_sub); + m_sub = m_cresults[""]; + ignore_unused_variable_warning(m_sub); + m_sub = m_cresults[std::string("")]; + ignore_unused_variable_warning(m_sub); + m_string = m_cresults.str(&m_char); + ignore_unused_variable_warning(m_string); + m_string = m_cresults.str(m_string); + ignore_unused_variable_warning(m_string); + m_string = m_cresults.str(""); + ignore_unused_variable_warning(m_string); + m_string = m_cresults.str(std::string("")); + ignore_unused_variable_warning(m_string); + + typename match_results_type::difference_type diff; + diff = m_cresults.length(&m_char); + ignore_unused_variable_warning(diff); + diff = m_cresults.length(m_string); + ignore_unused_variable_warning(diff); + diff = m_cresults.length(""); + ignore_unused_variable_warning(diff); + diff = m_cresults.length(std::string("")); + ignore_unused_variable_warning(diff); + diff = m_cresults.position(&m_char); + ignore_unused_variable_warning(diff); + diff = m_cresults.position(m_string); + ignore_unused_variable_warning(diff); + diff = m_cresults.position(""); + ignore_unused_variable_warning(diff); + diff = m_cresults.position(std::string("")); + ignore_unused_variable_warning(diff); + +#ifndef BOOST_NO_STD_LOCALE + m_stream << m_sub; + m_stream << m_cresults; +#endif + // + // Extended formatting with a functor: + // + regex_constants::match_flag_type f = regex_constants::match_default; + OutputIterator out = static_object::get(); + + functor3 func3; + functor2 func2; + functor1 func1; + + functor3 func3b; + functor2 func2b; + functor1 func1b; + + out = regex_format(out, m_cresults, func3b, f); + out = regex_format(out, m_cresults, func3b); + out = regex_format(out, m_cresults, func2b, f); + out = regex_format(out, m_cresults, func2b); + out = regex_format(out, m_cresults, func1b, f); + out = regex_format(out, m_cresults, func1b); + out = regex_format(out, m_cresults, RW_NS::ref(func3b), f); + out = regex_format(out, m_cresults, RW_NS::ref(func3b)); + out = regex_format(out, m_cresults, RW_NS::ref(func2b), f); + out = regex_format(out, m_cresults, RW_NS::ref(func2b)); + out = regex_format(out, m_cresults, RW_NS::ref(func1b), f); + out = regex_format(out, m_cresults, RW_NS::ref(func1b)); + out = regex_format(out, m_cresults, RW_NS::cref(func3b), f); + out = regex_format(out, m_cresults, RW_NS::cref(func3b)); + out = regex_format(out, m_cresults, RW_NS::cref(func2b), f); + out = regex_format(out, m_cresults, RW_NS::cref(func2b)); + out = regex_format(out, m_cresults, RW_NS::cref(func1b), f); + out = regex_format(out, m_cresults, RW_NS::cref(func1b)); + m_string += regex_format(m_cresults, func3b, f); + m_string += regex_format(m_cresults, func3b); + m_string += regex_format(m_cresults, func2b, f); + m_string += regex_format(m_cresults, func2b); + m_string += regex_format(m_cresults, func1b, f); + m_string += regex_format(m_cresults, func1b); + m_string += regex_format(m_cresults, RW_NS::ref(func3b), f); + m_string += regex_format(m_cresults, RW_NS::ref(func3b)); + m_string += regex_format(m_cresults, RW_NS::ref(func2b), f); + m_string += regex_format(m_cresults, RW_NS::ref(func2b)); + m_string += regex_format(m_cresults, RW_NS::ref(func1b), f); + m_string += regex_format(m_cresults, RW_NS::ref(func1b)); + m_string += regex_format(m_cresults, RW_NS::cref(func3b), f); + m_string += regex_format(m_cresults, RW_NS::cref(func3b)); + m_string += regex_format(m_cresults, RW_NS::cref(func2b), f); + m_string += regex_format(m_cresults, RW_NS::cref(func2b)); + m_string += regex_format(m_cresults, RW_NS::cref(func1b), f); + m_string += regex_format(m_cresults, RW_NS::cref(func1b)); + + out = m_cresults.format(out, func3b, f); + out = m_cresults.format(out, func3b); + out = m_cresults.format(out, func2b, f); + out = m_cresults.format(out, func2b); + out = m_cresults.format(out, func1b, f); + out = m_cresults.format(out, func1b); + out = m_cresults.format(out, RW_NS::ref(func3b), f); + out = m_cresults.format(out, RW_NS::ref(func3b)); + out = m_cresults.format(out, RW_NS::ref(func2b), f); + out = m_cresults.format(out, RW_NS::ref(func2b)); + out = m_cresults.format(out, RW_NS::ref(func1b), f); + out = m_cresults.format(out, RW_NS::ref(func1b)); + out = m_cresults.format(out, RW_NS::cref(func3b), f); + out = m_cresults.format(out, RW_NS::cref(func3b)); + out = m_cresults.format(out, RW_NS::cref(func2b), f); + out = m_cresults.format(out, RW_NS::cref(func2b)); + out = m_cresults.format(out, RW_NS::cref(func1b), f); + out = m_cresults.format(out, RW_NS::cref(func1b)); + + m_string += m_cresults.format(func3b, f); + m_string += m_cresults.format(func3b); + m_string += m_cresults.format(func2b, f); + m_string += m_cresults.format(func2b); + m_string += m_cresults.format(func1b, f); + m_string += m_cresults.format(func1b); + m_string += m_cresults.format(RW_NS::ref(func3b), f); + m_string += m_cresults.format(RW_NS::ref(func3b)); + m_string += m_cresults.format(RW_NS::ref(func2b), f); + m_string += m_cresults.format(RW_NS::ref(func2b)); + m_string += m_cresults.format(RW_NS::ref(func1b), f); + m_string += m_cresults.format(RW_NS::ref(func1b)); + m_string += m_cresults.format(RW_NS::cref(func3b), f); + m_string += m_cresults.format(RW_NS::cref(func3b)); + m_string += m_cresults.format(RW_NS::cref(func2b), f); + m_string += m_cresults.format(RW_NS::cref(func2b)); + m_string += m_cresults.format(RW_NS::cref(func1b), f); + m_string += m_cresults.format(RW_NS::cref(func1b)); + + out = regex_replace(out, m_in, m_in, ce, func3, f); + out = regex_replace(out, m_in, m_in, ce, func3); + out = regex_replace(out, m_in, m_in, ce, func2, f); + out = regex_replace(out, m_in, m_in, ce, func2); + out = regex_replace(out, m_in, m_in, ce, func1, f); + out = regex_replace(out, m_in, m_in, ce, func1); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func3), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func3)); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func2), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func2)); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func1), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::ref(func1)); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func3), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func3)); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func2), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func2)); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func1), f); + out = regex_replace(out, m_in, m_in, ce, RW_NS::cref(func1)); + + functor3 > func3s; + functor2 > func2s; + functor1 > func1s; + m_string += regex_replace(m_string, ce, func3s, f); + m_string += regex_replace(m_string, ce, func3s); + m_string += regex_replace(m_string, ce, func2s, f); + m_string += regex_replace(m_string, ce, func2s); + m_string += regex_replace(m_string, ce, func1s, f); + m_string += regex_replace(m_string, ce, func1s); + m_string += regex_replace(m_string, ce, RW_NS::ref(func3s), f); + m_string += regex_replace(m_string, ce, RW_NS::ref(func3s)); + m_string += regex_replace(m_string, ce, RW_NS::ref(func2s), f); + m_string += regex_replace(m_string, ce, RW_NS::ref(func2s)); + m_string += regex_replace(m_string, ce, RW_NS::ref(func1s), f); + m_string += regex_replace(m_string, ce, RW_NS::ref(func1s)); + m_string += regex_replace(m_string, ce, RW_NS::cref(func3s), f); + m_string += regex_replace(m_string, ce, RW_NS::cref(func3s)); + m_string += regex_replace(m_string, ce, RW_NS::cref(func2s), f); + m_string += regex_replace(m_string, ce, RW_NS::cref(func2s)); + m_string += regex_replace(m_string, ce, RW_NS::cref(func1s), f); + m_string += regex_replace(m_string, ce, RW_NS::cref(func1s)); + } + + std::basic_ostream m_stream; + sub_match_type m_sub; + pointer_type m_pointer; + string_type m_string; + const value_type m_char; + match_results_type m_results; + const match_results_type m_cresults; + BidiIterator m_in; + + BoostRegexConcept(); + BoostRegexConcept(const BoostRegexConcept&); + BoostRegexConcept& operator=(const BoostRegexConcept&); +}; + +#endif // BOOST_REGEX_TEST_STD + +} + +#endif diff --git a/third-party/boost_regex/include/boost/regex/config.hpp b/third-party/boost_regex/include/boost/regex/config.hpp new file mode 100644 index 0000000000..bed485fa12 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/config.hpp @@ -0,0 +1,480 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE config.hpp + * VERSION see + * DESCRIPTION: regex extended config setup. + */ + +#ifndef BOOST_REGEX_CONFIG_HPP +#define BOOST_REGEX_CONFIG_HPP + +#if !((__cplusplus >= 201103L) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(BOOST_REGEX_CXX03)) +# define BOOST_REGEX_CXX03 +#endif + +#if defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_CXX03) +# define BOOST_REGEX_CXX03 +#endif + +#if defined(__has_include) +#if !defined(BOOST_REGEX_STANDALONE) && !__has_include() +#define BOOST_REGEX_STANDALONE +#endif +#endif + +/* + * Borland C++ Fix/error check + * this has to go *before* we include any std lib headers: + */ +#if defined(__BORLANDC__) && !defined(__clang__) +# include +#endif +#ifndef BOOST_REGEX_STANDALONE +#include +#endif + +/************************************************************************* +* +* Asserts: +* +*************************************************************************/ + +#ifdef BOOST_REGEX_STANDALONE +#include +# define BOOST_REGEX_ASSERT(x) assert(x) +#else +#include +# define BOOST_REGEX_ASSERT(x) BOOST_ASSERT(x) +#endif + +/***************************************************************************** + * + * Include all the headers we need here: + * + ****************************************************************************/ + +#ifdef __cplusplus + +# ifndef BOOST_REGEX_USER_CONFIG +# define BOOST_REGEX_USER_CONFIG +# endif + +# include BOOST_REGEX_USER_CONFIG + +#ifndef BOOST_REGEX_STANDALONE +# include +# include +#endif + +#else + /* + * C build, + * don't include because that may + * do C++ specific things in future... + */ +# include +# include +# ifdef _MSC_VER +# define BOOST_MSVC _MSC_VER +# endif +#endif + + +/**************************************************************************** +* +* Legacy support: +* +*******************************************************************************/ + +#if defined(BOOST_NO_STD_LOCALE) || defined(BOOST_NO_CXX11_HDR_MUTEX) || defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) \ + || defined(BOOST_NO_CXX11_HDR_ATOMIC) || defined(BOOST_NO_CXX11_ALLOCATOR) || defined(BOOST_NO_CXX11_SMART_PTR) \ + || defined(BOOST_NO_CXX11_STATIC_ASSERT) || defined(BOOST_NO_NOEXCEPT) +#ifndef BOOST_REGEX_CXX03 +# define BOOST_REGEX_CXX03 +#endif +#endif + +/***************************************************************************** + * + * Boilerplate regex config options: + * + ****************************************************************************/ + +/* Obsolete macro, use BOOST_VERSION instead: */ +#define BOOST_RE_VERSION 500 + +/* fix: */ +#if defined(_UNICODE) && !defined(UNICODE) +#define UNICODE +#endif + +#define BOOST_REGEX_JOIN(X, Y) BOOST_REGEX_DO_JOIN(X, Y) +#define BOOST_REGEX_DO_JOIN(X, Y) BOOST_REGEX_DO_JOIN2(X,Y) +#define BOOST_REGEX_DO_JOIN2(X, Y) X##Y + +#ifdef BOOST_FALLTHROUGH +# define BOOST_REGEX_FALLTHROUGH BOOST_FALLTHROUGH +#else + +#if defined(__clang__) && (__cplusplus >= 201103L) && defined(__has_warning) +# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +# define BOOST_REGEX_FALLTHROUGH [[clang::fallthrough]] +# endif +#endif +#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703) +# define BOOST_REGEX_FALLTHROUGH [[fallthrough]] +#endif +#if !defined(BOOST_REGEX_FALLTHROUGH) && defined(__GNUC__) && (__GNUC__ >= 7) +# define BOOST_REGEX_FALLTHROUGH __attribute__((fallthrough)) +#endif + +#if !defined(BOOST_REGEX_FALLTHROUGH) +# define BOOST_REGEX_FALLTHROUGH +#endif +#endif + +#ifdef BOOST_NORETURN +# define BOOST_REGEX_NORETURN BOOST_NORETURN +#else +# define BOOST_REGEX_NORETURN +#endif + + +/* +* Define a macro for the namespace that details are placed in, this includes the Boost +* version number to avoid mismatched header and library versions: +*/ +#define BOOST_REGEX_DETAIL_NS BOOST_REGEX_JOIN(re_detail_, BOOST_RE_VERSION) + +/* + * Fix for gcc prior to 3.4: std::ctype doesn't allow + * masks to be combined, for example: + * std::use_facet >.is(std::ctype_base::lower|std::ctype_base::upper, L'a'); + * returns *false*. + */ +#if defined(__GLIBCPP__) && defined(BOOST_REGEX_CXX03) +# define BOOST_REGEX_BUGGY_CTYPE_FACET +#endif + +/* + * If there isn't good enough wide character support then there will + * be no wide character regular expressions: + */ +#if (defined(BOOST_NO_CWCHAR) || defined(BOOST_NO_CWCTYPE) || defined(BOOST_NO_STD_WSTRING)) +# if !defined(BOOST_NO_WREGEX) +# define BOOST_NO_WREGEX +# endif +#else +# if defined(__sgi) && (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) + /* STLPort on IRIX is misconfigured: does not compile + * as a temporary fix include instead and prevent inclusion + * of STLPort version of */ +# include +# define __STLPORT_CWCTYPE +# define _STLP_CWCTYPE +# endif + +#if defined(__cplusplus) && defined(BOOST_REGEX_CXX03) +# include +#endif + +#endif + +/* + * If Win32 support has been disabled for boost in general, then + * it is for regex in particular: + */ +#if defined(BOOST_DISABLE_WIN32) && !defined(BOOST_REGEX_NO_W32) +# define BOOST_REGEX_NO_W32 +#endif + +/* disable our own file-iterators and mapfiles if we can't + * support them: */ +#if defined(_WIN32) +# if defined(BOOST_REGEX_NO_W32) || BOOST_PLAT_WINDOWS_RUNTIME +# define BOOST_REGEX_NO_FILEITER +# endif +#else /* defined(_WIN32) */ +# if !defined(BOOST_HAS_DIRENT_H) +# define BOOST_REGEX_NO_FILEITER +# endif +#endif + +/* backwards compatibitity: */ +#if defined(BOOST_RE_NO_LIB) +# define BOOST_REGEX_NO_LIB +#endif + +#if defined(__GNUC__) && !defined(_MSC_VER) && (defined(_WIN32) || defined(__CYGWIN__)) +/* gcc on win32 has problems if you include + (sporadically generates bad code). */ +# define BOOST_REGEX_NO_W32 +#endif +#if defined(__COMO__) && !defined(BOOST_REGEX_NO_W32) && !defined(_MSC_EXTENSIONS) +# define BOOST_REGEX_NO_W32 +#endif + +#ifdef BOOST_REGEX_STANDALONE +# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__) +# define BOOST_REGEX_MSVC _MSC_VER +#endif +#elif defined(BOOST_MSVC) +# define BOOST_REGEX_MSVC BOOST_MSVC +#endif + + +/***************************************************************************** + * + * Set up dll import/export options: + * + ****************************************************************************/ + +#if (defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && !defined(BOOST_REGEX_STATIC_LINK) && defined(BOOST_SYMBOL_IMPORT) +# if defined(BOOST_REGEX_SOURCE) +# define BOOST_REGEX_BUILD_DLL +# define BOOST_REGEX_DECL BOOST_SYMBOL_EXPORT +# else +# define BOOST_REGEX_DECL BOOST_SYMBOL_IMPORT +# endif +#else +# define BOOST_REGEX_DECL +#endif + +#ifdef BOOST_REGEX_CXX03 +#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus) +# define BOOST_LIB_NAME boost_regex +# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# ifdef BOOST_REGEX_DIAG +# define BOOST_LIB_DIAGNOSTIC +# endif +# include +#endif +#endif + +/***************************************************************************** + * + * Set up function call type: + * + ****************************************************************************/ + +#if defined(_MSC_VER) && defined(_MSC_EXTENSIONS) +#if defined(_DEBUG) || defined(__MSVC_RUNTIME_CHECKS) || defined(_MANAGED) || defined(BOOST_REGEX_NO_FASTCALL) +# define BOOST_REGEX_CALL __cdecl +#else +# define BOOST_REGEX_CALL __fastcall +#endif +# define BOOST_REGEX_CCALL __cdecl +#endif + +#if defined(__BORLANDC__) && !defined(BOOST_DISABLE_WIN32) +#if defined(__clang__) +# define BOOST_REGEX_CALL __cdecl +# define BOOST_REGEX_CCALL __cdecl +#else +# define BOOST_REGEX_CALL __fastcall +# define BOOST_REGEX_CCALL __stdcall +#endif +#endif + +#ifndef BOOST_REGEX_CALL +# define BOOST_REGEX_CALL +#endif +#ifndef BOOST_REGEX_CCALL +#define BOOST_REGEX_CCALL +#endif + +/***************************************************************************** + * + * Set up localisation model: + * + ****************************************************************************/ + +/* backwards compatibility: */ +#ifdef BOOST_RE_LOCALE_C +# define BOOST_REGEX_USE_C_LOCALE +#endif + +#ifdef BOOST_RE_LOCALE_CPP +# define BOOST_REGEX_USE_CPP_LOCALE +#endif + +#if defined(__CYGWIN__) +# define BOOST_REGEX_USE_C_LOCALE +#endif + +/* use C++ locale when targeting windows store */ +#if BOOST_PLAT_WINDOWS_RUNTIME +# define BOOST_REGEX_USE_CPP_LOCALE +# define BOOST_REGEX_NO_WIN32_LOCALE +#endif + +/* Win32 defaults to native Win32 locale: */ +#if defined(_WIN32) && \ + !defined(BOOST_REGEX_USE_WIN32_LOCALE) && \ + !defined(BOOST_REGEX_USE_C_LOCALE) && \ + !defined(BOOST_REGEX_USE_CPP_LOCALE) && \ + !defined(BOOST_REGEX_NO_W32) && \ + !defined(BOOST_REGEX_NO_WIN32_LOCALE) +# define BOOST_REGEX_USE_WIN32_LOCALE +#endif +/* otherwise use C++ locale if supported: */ +#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE) && !defined(BOOST_NO_STD_LOCALE) +# define BOOST_REGEX_USE_CPP_LOCALE +#endif +/* otherwise use C locale: */ +#if !defined(BOOST_REGEX_USE_WIN32_LOCALE) && !defined(BOOST_REGEX_USE_C_LOCALE) && !defined(BOOST_REGEX_USE_CPP_LOCALE) +# define BOOST_REGEX_USE_C_LOCALE +#endif + +#ifndef BOOST_REGEX_MAX_STATE_COUNT +# define BOOST_REGEX_MAX_STATE_COUNT 100000000 +#endif + + +/***************************************************************************** + * + * Error Handling for exception free compilers: + * + ****************************************************************************/ + +#ifdef BOOST_NO_EXCEPTIONS +/* + * If there are no exceptions then we must report critical-errors + * the only way we know how; by terminating. + */ +#include +#include +#include + +# define BOOST_REGEX_NOEH_ASSERT(x)\ +if(0 == (x))\ +{\ + std::string s("Error: critical regex++ failure in: ");\ + s.append(#x);\ + std::runtime_error e(s);\ + boost::throw_exception(e);\ +} +#else +/* + * With exceptions then error handling is taken care of and + * there is no need for these checks: + */ +# define BOOST_REGEX_NOEH_ASSERT(x) +#endif + + +/***************************************************************************** + * + * Stack protection under MS Windows: + * + ****************************************************************************/ + +#if !defined(BOOST_REGEX_NO_W32) && !defined(BOOST_REGEX_V3) +# if(defined(_WIN32) || defined(_WIN64) || defined(_WINCE)) \ + && !(defined(__GNUC__) || defined(__BORLANDC__) && defined(__clang__)) \ + && !(defined(__BORLANDC__) && (__BORLANDC__ >= 0x600)) \ + && !(defined(__MWERKS__) && (__MWERKS__ <= 0x3003)) +# define BOOST_REGEX_HAS_MS_STACK_GUARD +# endif +#elif defined(BOOST_REGEX_HAS_MS_STACK_GUARD) +# undef BOOST_REGEX_HAS_MS_STACK_GUARD +#endif + +#if defined(__cplusplus) && defined(BOOST_REGEX_HAS_MS_STACK_GUARD) + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +BOOST_REGEX_DECL void BOOST_REGEX_CALL reset_stack_guard_page(); + +} +} + +#endif + + +/***************************************************************************** + * + * Algorithm selection and configuration. + * These options are now obsolete for C++11 and later (regex v5). + * + ****************************************************************************/ + +#if !defined(BOOST_REGEX_RECURSIVE) && !defined(BOOST_REGEX_NON_RECURSIVE) +# if defined(BOOST_REGEX_HAS_MS_STACK_GUARD) && !defined(_STLP_DEBUG) && !defined(__STL_DEBUG) && !(defined(_MSC_VER) && (_MSC_VER >= 1400)) && defined(BOOST_REGEX_CXX03) +# define BOOST_REGEX_RECURSIVE +# else +# define BOOST_REGEX_NON_RECURSIVE +# endif +#endif + +#ifdef BOOST_REGEX_NON_RECURSIVE +# ifdef BOOST_REGEX_RECURSIVE +# error "Can't set both BOOST_REGEX_RECURSIVE and BOOST_REGEX_NON_RECURSIVE" +# endif +# ifndef BOOST_REGEX_BLOCKSIZE +# define BOOST_REGEX_BLOCKSIZE 4096 +# endif +# if BOOST_REGEX_BLOCKSIZE < 512 +# error "BOOST_REGEX_BLOCKSIZE must be at least 512" +# endif +# ifndef BOOST_REGEX_MAX_BLOCKS +# define BOOST_REGEX_MAX_BLOCKS 1024 +# endif +# ifdef BOOST_REGEX_HAS_MS_STACK_GUARD +# undef BOOST_REGEX_HAS_MS_STACK_GUARD +# endif +# ifndef BOOST_REGEX_MAX_CACHE_BLOCKS +# define BOOST_REGEX_MAX_CACHE_BLOCKS 16 +# endif +#endif + + +/***************************************************************************** + * + * Diagnostics: + * + ****************************************************************************/ + +#ifdef BOOST_REGEX_CONFIG_INFO +BOOST_REGEX_DECL void BOOST_REGEX_CALL print_regex_library_info(); +#endif + +#if defined(BOOST_REGEX_DIAG) +# pragma message ("BOOST_REGEX_DECL" BOOST_STRINGIZE(=BOOST_REGEX_DECL)) +# pragma message ("BOOST_REGEX_CALL" BOOST_STRINGIZE(=BOOST_REGEX_CALL)) +# pragma message ("BOOST_REGEX_CCALL" BOOST_STRINGIZE(=BOOST_REGEX_CCALL)) +#ifdef BOOST_REGEX_USE_C_LOCALE +# pragma message ("Using C locale in regex traits class") +#elif BOOST_REGEX_USE_CPP_LOCALE +# pragma message ("Using C++ locale in regex traits class") +#else +# pragma message ("Using Win32 locale in regex traits class") +#endif +#if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) +# pragma message ("Dynamic linking enabled") +#endif +#if defined(BOOST_REGEX_NO_LIB) || defined(BOOST_ALL_NO_LIB) +# pragma message ("Auto-linking disabled") +#endif +#ifdef BOOST_REGEX_NO_EXTERNAL_TEMPLATES +# pragma message ("Extern templates disabled") +#endif + +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/config/borland.hpp b/third-party/boost_regex/include/boost/regex/config/borland.hpp new file mode 100644 index 0000000000..981113e5cf --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/config/borland.hpp @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE boost/regex/config/borland.hpp + * VERSION see + * DESCRIPTION: regex borland-specific config setup. + */ + + +#if defined(__BORLANDC__) && !defined(__clang__) +# if (__BORLANDC__ == 0x550) || (__BORLANDC__ == 0x551) + // problems with std::basic_string and dll RTL: +# if defined(_RTLDLL) && defined(_RWSTD_COMPILE_INSTANTIATE) +# ifdef BOOST_REGEX_BUILD_DLL +# error _RWSTD_COMPILE_INSTANTIATE must not be defined when building regex++ as a DLL +# else +# pragma message("Defining _RWSTD_COMPILE_INSTANTIATE when linking to the DLL version of the RTL may produce memory corruption problems in std::basic_string, as a result of separate versions of basic_string's static data in the RTL and you're exe/dll: be warned!!") +# endif +# endif +# ifndef _RTLDLL + // this is harmless for a staic link: +# define _RWSTD_COMPILE_INSTANTIATE +# endif + // external templates cause problems for some reason: +# define BOOST_REGEX_NO_EXTERNAL_TEMPLATES +# endif +# if (__BORLANDC__ <= 0x540) && !defined(BOOST_REGEX_NO_LIB) && !defined(_NO_VCL) + // C++ Builder 4 and earlier, we can't tell whether we should be using + // the VCL runtime or not, do a static link instead: +# define BOOST_REGEX_STATIC_LINK +# endif + // + // VCL support: + // if we're building a console app then there can't be any VCL (can there?) +# if !defined(__CONSOLE__) && !defined(_NO_VCL) +# define BOOST_REGEX_USE_VCL +# endif + // + // if this isn't Win32 then don't automatically select link + // libraries: + // +# ifndef _Windows +# ifndef BOOST_REGEX_NO_LIB +# define BOOST_REGEX_NO_LIB +# endif +# ifndef BOOST_REGEX_STATIC_LINK +# define BOOST_REGEX_STATIC_LINK +# endif +# endif + +#if __BORLANDC__ < 0x600 +// +// string workarounds: +// +#include +#undef strcmp +#undef strcpy +#endif + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/config/cwchar.hpp b/third-party/boost_regex/include/boost/regex/config/cwchar.hpp new file mode 100644 index 0000000000..a55089d0ab --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/config/cwchar.hpp @@ -0,0 +1,207 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE boost/regex/config/cwchar.hpp + * VERSION see + * DESCRIPTION: regex wide character string fixes. + */ + +#ifndef BOOST_REGEX_CONFIG_CWCHAR_HPP +#define BOOST_REGEX_CONFIG_CWCHAR_HPP + +#include +#include +#include + +#if defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER) +// apparently this is required for the RW STL on Linux: +#undef iswalnum +#undef iswalpha +#undef iswblank +#undef iswcntrl +#undef iswdigit +#undef iswgraph +#undef iswlower +#undef iswprint +#undef iswprint +#undef iswpunct +#undef iswspace +#undef iswupper +#undef iswxdigit +#undef iswctype +#undef towlower +#undef towupper +#undef towctrans +#undef wctrans +#undef wctype +#endif + +namespace std{ + +#ifndef BOOST_NO_STDC_NAMESPACE +extern "C"{ +#endif + +#ifdef iswalnum +inline int (iswalnum)(wint_t i) +{ return iswalnum(i); } +#undef iswalnum +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswalnum; +#endif + +#ifdef iswalpha +inline int (iswalpha)(wint_t i) +{ return iswalpha(i); } +#undef iswalpha +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswalpha; +#endif + +#ifdef iswcntrl +inline int (iswcntrl)(wint_t i) +{ return iswcntrl(i); } +#undef iswcntrl +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswcntrl; +#endif + +#ifdef iswdigit +inline int (iswdigit)(wint_t i) +{ return iswdigit(i); } +#undef iswdigit +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswdigit; +#endif + +#ifdef iswgraph +inline int (iswgraph)(wint_t i) +{ return iswgraph(i); } +#undef iswgraph +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswgraph; +#endif + +#ifdef iswlower +inline int (iswlower)(wint_t i) +{ return iswlower(i); } +#undef iswlower +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswlower; +#endif + +#ifdef iswprint +inline int (iswprint)(wint_t i) +{ return iswprint(i); } +#undef iswprint +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswprint; +#endif + +#ifdef iswpunct +inline int (iswpunct)(wint_t i) +{ return iswpunct(i); } +#undef iswpunct +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswpunct; +#endif + +#ifdef iswspace +inline int (iswspace)(wint_t i) +{ return iswspace(i); } +#undef iswspace +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswspace; +#endif + +#ifdef iswupper +inline int (iswupper)(wint_t i) +{ return iswupper(i); } +#undef iswupper +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswupper; +#endif + +#ifdef iswxdigit +inline int (iswxdigit)(wint_t i) +{ return iswxdigit(i); } +#undef iswxdigit +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::iswxdigit; +#endif + +#ifdef towlower +inline wint_t (towlower)(wint_t i) +{ return towlower(i); } +#undef towlower +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::towlower; +#endif + +#ifdef towupper +inline wint_t (towupper)(wint_t i) +{ return towupper(i); } +#undef towupper +#elif defined(BOOST_NO_STDC_NAMESPACE) +using :: towupper; +#endif + +#ifdef wcscmp +inline int (wcscmp)(const wchar_t *p1, const wchar_t *p2) +{ return wcscmp(p1,p2); } +#undef wcscmp +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::wcscmp; +#endif + +#ifdef wcscoll +inline int (wcscoll)(const wchar_t *p1, const wchar_t *p2) +{ return wcscoll(p1,p2); } +#undef wcscoll +#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(UNDER_CE) +using ::wcscoll; +#endif + +#ifdef wcscpy +inline wchar_t *(wcscpy)(wchar_t *p1, const wchar_t *p2) +{ return wcscpy(p1,p2); } +#undef wcscpy +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::wcscpy; +#endif + +#ifdef wcslen +inline size_t (wcslen)(const wchar_t *p) +{ return wcslen(p); } +#undef wcslen +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::wcslen; +#endif + +#ifdef wcsxfrm +size_t wcsxfrm(wchar_t *p1, const wchar_t *p2, size_t s) +{ return wcsxfrm(p1,p2,s); } +#undef wcsxfrm +#elif defined(BOOST_NO_STDC_NAMESPACE) +using ::wcsxfrm; +#endif + + +#ifndef BOOST_NO_STDC_NAMESPACE +} // extern "C" +#endif + +} // namespace std + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/icu.hpp b/third-party/boost_regex/include/boost/regex/icu.hpp new file mode 100644 index 0000000000..b312612d19 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/icu.hpp @@ -0,0 +1,30 @@ +/* + * + * Copyright (c) 2020 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE icu.hpp + * VERSION see + * DESCRIPTION: Unicode regular expressions on top of the ICU Library. + */ + +#ifndef BOOST_REGEX_ICU_HPP +#define BOOST_REGEX_ICU_HPP + +#include + +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/mfc.hpp b/third-party/boost_regex/include/boost/regex/mfc.hpp new file mode 100644 index 0000000000..d780673931 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/mfc.hpp @@ -0,0 +1,186 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE mfc.hpp + * VERSION see + * DESCRIPTION: Overloads and helpers for using MFC/ATL string types with Boost.Regex. + */ + +#ifndef BOOST_REGEX_MFC_HPP +#define BOOST_REGEX_MFC_HPP + +#include +#include + +namespace boost{ + +// +// define the types used for TCHAR's: +typedef basic_regex tregex; +typedef match_results tmatch; +typedef regex_iterator tregex_iterator; +typedef regex_token_iterator tregex_token_iterator; + +// Obsolete. Remove +#define SIMPLE_STRING_PARAM class B, bool b +#define SIMPLE_STRING_ARG_LIST B, b + +// +// define regex creation functions: +// +template +inline basic_regex +make_regex(const ATL::CSimpleStringT& s, ::boost::regex_constants::syntax_option_type f = boost::regex_constants::normal) +{ + basic_regex result(s.GetString(), s.GetString() + s.GetLength(), f); + return result; +} +// +// regex_match overloads: +// +template +inline bool regex_match(const ATL::CSimpleStringT& s, + match_results& what, + const basic_regex& e, + boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + return ::boost::regex_match(s.GetString(), + s.GetString() + s.GetLength(), + what, + e, + f); +} + +template +inline bool regex_match(const ATL::CSimpleStringT& s, + const basic_regex& e, + boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + return ::boost::regex_match(s.GetString(), + s.GetString() + s.GetLength(), + e, + f); +} +// +// regex_search overloads: +// +template +inline bool regex_search(const ATL::CSimpleStringT& s, + match_results& what, + const basic_regex& e, + boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + return ::boost::regex_search(s.GetString(), + s.GetString() + s.GetLength(), + what, + e, + f); +} + +template +inline bool regex_search(const ATL::CSimpleStringT& s, + const basic_regex& e, + boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + return ::boost::regex_search(s.GetString(), + s.GetString() + s.GetLength(), + e, + f); +} +// +// regex_iterator creation: +// +template +inline regex_iterator +make_regex_iterator(const ATL::CSimpleStringT& s, const basic_regex& e, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + regex_iterator result(s.GetString(), s.GetString() + s.GetLength(), e, f); + return result; +} + +template +inline regex_token_iterator + make_regex_token_iterator(const ATL::CSimpleStringT& s, const basic_regex& e, int sub = 0, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + regex_token_iterator result(s.GetString(), s.GetString() + s.GetLength(), e, sub, f); + return result; +} + +template +inline regex_token_iterator +make_regex_token_iterator(const ATL::CSimpleStringT& s, const basic_regex& e, const std::vector& subs, ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + regex_token_iterator result(s.GetString(), s.GetString() + s.GetLength(), e, subs, f); + return result; +} + +template +inline regex_token_iterator +make_regex_token_iterator(const ATL::CSimpleStringT& s, const basic_regex& e, const int (& subs)[N], ::boost::regex_constants::match_flag_type f = boost::regex_constants::match_default) +{ + regex_token_iterator result(s.GetString(), s.GetString() + s.GetLength(), e, subs, f); + return result; +} + +template +OutputIterator regex_replace(OutputIterator out, + BidirectionalIterator first, + BidirectionalIterator last, + const basic_regex& e, + const ATL::CSimpleStringT& fmt, + match_flag_type flags = match_default) +{ + return ::boost::regex_replace(out, first, last, e, fmt.GetString(), flags); +} + +namespace BOOST_REGEX_DETAIL_NS{ + +template +class mfc_string_out_iterator +{ + ATL::CSimpleStringT* out; +public: + mfc_string_out_iterator(ATL::CSimpleStringT& s) : out(&s) {} + mfc_string_out_iterator& operator++() { return *this; } + mfc_string_out_iterator& operator++(int) { return *this; } + mfc_string_out_iterator& operator*() { return *this; } + mfc_string_out_iterator& operator=(B v) + { + out->AppendChar(v); + return *this; + } + typedef std::ptrdiff_t difference_type; + typedef B value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::output_iterator_tag iterator_category; +}; + +} + +template +ATL::CSimpleStringT regex_replace(const ATL::CSimpleStringT& s, + const basic_regex& e, + const ATL::CSimpleStringT& fmt, + match_flag_type flags = match_default) +{ + ATL::CSimpleStringT result(s.GetManager()); + BOOST_REGEX_DETAIL_NS::mfc_string_out_iterator i(result); + regex_replace(i, s.GetString(), s.GetString() + s.GetLength(), e, fmt.GetString(), flags); + return result; +} + +} // namespace boost. + +#endif diff --git a/third-party/boost_regex/include/boost/regex/pattern_except.hpp b/third-party/boost_regex/include/boost/regex/pattern_except.hpp new file mode 100644 index 0000000000..f2af1afe64 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/pattern_except.hpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE pattern_except.hpp + * VERSION see + * DESCRIPTION: Declares pattern-matching exception classes. + */ + +#ifndef BOOST_RE_PAT_EXCEPT_HPP +#define BOOST_RE_PAT_EXCEPT_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/pending/object_cache.hpp b/third-party/boost_regex/include/boost/regex/pending/object_cache.hpp new file mode 100644 index 0000000000..0ddbdadfa3 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/pending/object_cache.hpp @@ -0,0 +1,29 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE object_cache.hpp + * VERSION see + * DESCRIPTION: Implements a generic object cache. + */ + +#ifndef BOOST_REGEX_OBJECT_CACHE_HPP +#define BOOST_REGEX_OBJECT_CACHE_HPP + +#include +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/pending/static_mutex.hpp b/third-party/boost_regex/include/boost/regex/pending/static_mutex.hpp new file mode 100644 index 0000000000..344926f6ab --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/pending/static_mutex.hpp @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE static_mutex.hpp + * VERSION see + * DESCRIPTION: Declares static_mutex lock type, there are three different + * implementations: POSIX pthreads, WIN32 threads, and portable, + * these are described in more detail below. + */ + +#ifndef BOOST_REGEX_STATIC_MUTEX_HPP +#define BOOST_REGEX_STATIC_MUTEX_HPP + +#include +#include // dll import/export options. + +#ifdef BOOST_HAS_PTHREADS +#include +#endif + +#if defined(BOOST_HAS_PTHREADS) && defined(PTHREAD_MUTEX_INITIALIZER) +// +// pthreads version: +// simple wrap around a pthread_mutex_t initialized with +// PTHREAD_MUTEX_INITIALIZER. +// +namespace boost{ + +class static_mutex; + +#define BOOST_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER, } + +class BOOST_REGEX_DECL scoped_static_mutex_lock +{ +public: + scoped_static_mutex_lock(static_mutex& mut, bool lk = true); + ~scoped_static_mutex_lock(); + inline bool locked()const + { + return m_have_lock; + } + inline operator void const*()const + { + return locked() ? this : 0; + } + void lock(); + void unlock(); +private: + static_mutex& m_mutex; + bool m_have_lock; +}; + +class static_mutex +{ +public: + typedef scoped_static_mutex_lock scoped_lock; + pthread_mutex_t m_mutex; +}; + +} // namespace boost +#elif defined(BOOST_HAS_WINTHREADS) +// +// Win32 version: +// Use a 32-bit int as a lock, along with a test-and-set +// implementation using InterlockedCompareExchange. +// + +#include + +namespace boost{ + +class BOOST_REGEX_DECL scoped_static_mutex_lock; + +class static_mutex +{ +public: + typedef scoped_static_mutex_lock scoped_lock; + boost::int32_t m_mutex; +}; + +#define BOOST_STATIC_MUTEX_INIT { 0, } + +class BOOST_REGEX_DECL scoped_static_mutex_lock +{ +public: + scoped_static_mutex_lock(static_mutex& mut, bool lk = true); + ~scoped_static_mutex_lock(); + operator void const*()const + { + return locked() ? this : 0; + } + bool locked()const + { + return m_have_lock; + } + void lock(); + void unlock(); +private: + static_mutex& m_mutex; + bool m_have_lock; + scoped_static_mutex_lock(const scoped_static_mutex_lock&); + scoped_static_mutex_lock& operator=(const scoped_static_mutex_lock&); +}; + +} // namespace + +#else +// +// Portable version of a static mutex based on Boost.Thread library: +// This has to use a single mutex shared by all instances of static_mutex +// because boost::call_once doesn't alow us to pass instance information +// down to the initialisation proceedure. In fact the initialisation routine +// may need to be called more than once - but only once per instance. +// +// Since this preprocessor path is almost never taken, we hide these header +// dependencies so that build tools don't find them. +// +#define BOOST_REGEX_H1 +#define BOOST_REGEX_H2 +#define BOOST_REGEX_H3 +#include BOOST_REGEX_H1 +#include BOOST_REGEX_H2 +#include BOOST_REGEX_H3 +#undef BOOST_REGEX_H1 +#undef BOOST_REGEX_H2 +#undef BOOST_REGEX_H3 + +namespace boost{ + +class BOOST_REGEX_DECL scoped_static_mutex_lock; +extern "C" BOOST_REGEX_DECL void boost_regex_free_static_mutex(); + +class BOOST_REGEX_DECL static_mutex +{ +public: + typedef scoped_static_mutex_lock scoped_lock; + static void init(); + static boost::recursive_mutex* m_pmutex; + static boost::once_flag m_once; +}; + +#define BOOST_STATIC_MUTEX_INIT { } + +class BOOST_REGEX_DECL scoped_static_mutex_lock +{ +public: + scoped_static_mutex_lock(static_mutex& mut, bool lk = true); + ~scoped_static_mutex_lock(); + operator void const*()const; + bool locked()const; + void lock(); + void unlock(); +private: + boost::unique_lock* m_plock; + bool m_have_lock; +}; + +inline scoped_static_mutex_lock::operator void const*()const +{ + return locked() ? this : 0; +} + +inline bool scoped_static_mutex_lock::locked()const +{ + return m_have_lock; +} + +} // namespace + +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/pending/unicode_iterator.hpp b/third-party/boost_regex/include/boost/regex/pending/unicode_iterator.hpp new file mode 100644 index 0000000000..a565570a22 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/pending/unicode_iterator.hpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 2020 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE unicode_iterator.hpp + * VERSION see + * DESCRIPTION: Iterator adapters for converting between different Unicode encodings. + */ + +#ifndef BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP +#define BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP + +#include + +#if defined(BOOST_REGEX_CXX03) +#include +#else +#include +#endif + + +#endif // BOOST_REGEX_PENDING_UNICODE_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/regex_traits.hpp b/third-party/boost_regex/include/boost/regex/regex_traits.hpp new file mode 100644 index 0000000000..2b383160c1 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/regex_traits.hpp @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits classes. + */ + +#ifndef BOOST_REGEX_TRAITS_HPP +#define BOOST_REGEX_TRAITS_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +# include +#endif + +# ifndef BOOST_REGEX_TRAITS_HPP_INCLUDED +#ifdef BOOST_REGEX_CXX03 +# include +#else +# include +#endif +# endif + +#endif // include + + + + + diff --git a/third-party/boost_regex/include/boost/regex/user.hpp b/third-party/boost_regex/include/boost/regex/user.hpp new file mode 100644 index 0000000000..4b159bc581 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/user.hpp @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE user.hpp + * VERSION see + * DESCRIPTION: User settable options. + */ + +// define if you want the regex library to use the C locale +// even on Win32: +// #define BOOST_REGEX_USE_C_LOCALE + +// define this is you want the regex library to use the C++ +// locale: +// #define BOOST_REGEX_USE_CPP_LOCALE + +// define this if the runtime library is a dll, and you +// want BOOST_REGEX_DYN_LINK to set up dll exports/imports +// with __declspec(dllexport)/__declspec(dllimport.) +// #define BOOST_REGEX_HAS_DLL_RUNTIME + +// define this if you want to dynamically link to regex, +// if the runtime library is also a dll (Probably Win32 specific, +// and has no effect unless BOOST_REGEX_HAS_DLL_RUNTIME is set): +// #define BOOST_REGEX_DYN_LINK + +// define this if you don't want the lib to automatically +// select its link libraries: +// #define BOOST_REGEX_NO_LIB + +// define this if templates with switch statements cause problems: +// #define BOOST_REGEX_NO_TEMPLATE_SWITCH_MERGE + +// define this to disable Win32 support when available: +// #define BOOST_REGEX_NO_W32 + +// define this if bool is not a real type: +// #define BOOST_REGEX_NO_BOOL + +// define this if no template instances are to be placed in +// the library rather than users object files: +// #define BOOST_REGEX_NO_EXTERNAL_TEMPLATES + +// define this if the forward declarations in regex_fwd.hpp +// cause more problems than they are worth: +// #define BOOST_REGEX_NO_FWD + +// define this if your compiler supports MS Windows structured +// exception handling. +// #define BOOST_REGEX_HAS_MS_STACK_GUARD + +// define this if you want to use the recursive algorithm +// even if BOOST_REGEX_HAS_MS_STACK_GUARD is not defined. +// NOTE: OBSOLETE!! +// #define BOOST_REGEX_RECURSIVE + +// define this if you want to use the non-recursive +// algorithm, even if the recursive version would be the default. +// NOTE: OBSOLETE!! +// #define BOOST_REGEX_NON_RECURSIVE + +// define this if you want to set the size of the memory blocks +// used by the non-recursive algorithm. +// #define BOOST_REGEX_BLOCKSIZE 4096 + +// define this if you want to set the maximum number of memory blocks +// used by the non-recursive algorithm. +// #define BOOST_REGEX_MAX_BLOCKS 1024 + +// define this if you want to set the maximum number of memory blocks +// cached by the non-recursive algorithm: Normally this is 16, but can be +// higher if you have multiple threads all using boost.regex, or lower +// if you don't want boost.regex to cache memory. +// #define BOOST_REGEX_MAX_CACHE_BLOCKS 16 + +// define this if you want to be able to access extended capture +// information in your sub_match's (caution this will slow things +// down quite a bit). +// #define BOOST_REGEX_MATCH_EXTRA + +// define this if you want to enable support for Unicode via ICU. +// #define BOOST_HAS_ICU + +// define this if you want regex to use __cdecl calling convensions, even when __fastcall is available: +// #define BOOST_REGEX_NO_FASTCALL diff --git a/third-party/boost_regex/include/boost/regex/v4/basic_regex.hpp b/third-party/boost_regex/include/boost/regex/v4/basic_regex.hpp new file mode 100644 index 0000000000..0408a7543c --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/basic_regex.hpp @@ -0,0 +1,797 @@ +/* + * + * Copyright (c) 1998-2004 John Maddock + * Copyright 2011 Garmin Ltd. or its subsidiaries + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/ for most recent version. + * FILE basic_regex.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex. + */ + +#ifndef BOOST_REGEX_V4_BASIC_REGEX_HPP +#define BOOST_REGEX_V4_BASIC_REGEX_HPP + +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251) +#if BOOST_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +#if BOOST_MSVC < 1600 +#pragma warning(disable : 4660) +#endif +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// forward declaration, we will need this one later: +// +template +class basic_regex_parser; + +template +void bubble_down_one(I first, I last) +{ + if(first != last) + { + I next = last - 1; + while((next != first) && (*next < *(next-1))) + { + (next-1)->swap(*next); + --next; + } + } +} + +static const int hash_value_mask = 1 << (std::numeric_limits::digits - 1); + +template +inline int hash_value_from_capture_name(Iterator i, Iterator j) +{ + std::size_t r = boost::hash_range(i, j); + r %= ((std::numeric_limits::max)()); + return static_cast(r) | hash_value_mask; +} + +class named_subexpressions +{ +public: + struct name + { + template + name(const charT* i, const charT* j, int idx) + : index(idx) + { + hash = hash_value_from_capture_name(i, j); + } + name(int h, int idx) + : index(idx), hash(h) + { + } + int index; + int hash; + bool operator < (const name& other)const + { + return hash < other.hash; + } + bool operator == (const name& other)const + { + return hash == other.hash; + } + void swap(name& other) + { + std::swap(index, other.index); + std::swap(hash, other.hash); + } + }; + + typedef std::vector::const_iterator const_iterator; + typedef std::pair range_type; + + named_subexpressions(){} + + template + void set_name(const charT* i, const charT* j, int index) + { + m_sub_names.push_back(name(i, j, index)); + bubble_down_one(m_sub_names.begin(), m_sub_names.end()); + } + template + int get_id(const charT* i, const charT* j)const + { + name t(i, j, 0); + typename std::vector::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t); + if((pos != m_sub_names.end()) && (*pos == t)) + { + return pos->index; + } + return -1; + } + template + range_type equal_range(const charT* i, const charT* j)const + { + name t(i, j, 0); + return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t); + } + int get_id(int h)const + { + name t(h, 0); + std::vector::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t); + if((pos != m_sub_names.end()) && (*pos == t)) + { + return pos->index; + } + return -1; + } + range_type equal_range(int h)const + { + name t(h, 0); + return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t); + } +private: + std::vector m_sub_names; +}; + +// +// class regex_data: +// represents the data we wish to expose to the matching algorithms. +// +template +struct regex_data : public named_subexpressions +{ + typedef regex_constants::syntax_option_type flag_type; + typedef std::size_t size_type; + + regex_data(const ::boost::shared_ptr< + ::boost::regex_traits_wrapper >& t) + : m_ptraits(t), m_flags(0), m_status(0), m_expression(0), m_expression_len(0), + m_mark_count(0), m_first_state(0), m_restart_type(0), +#if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) && !(defined(BOOST_MSVC) && (BOOST_MSVC < 1900)) + m_startmap{ 0 }, +#endif + m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {} + regex_data() + : m_ptraits(new ::boost::regex_traits_wrapper()), m_flags(0), m_status(0), m_expression(0), m_expression_len(0), + m_mark_count(0), m_first_state(0), m_restart_type(0), +#if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) && !(defined(BOOST_MSVC) && (BOOST_MSVC < 1900)) + m_startmap{ 0 }, +#endif + m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {} + + ::boost::shared_ptr< + ::boost::regex_traits_wrapper + > m_ptraits; // traits class instance + flag_type m_flags; // flags with which we were compiled + int m_status; // error code (0 implies OK). + const charT* m_expression; // the original expression + std::ptrdiff_t m_expression_len; // the length of the original expression + size_type m_mark_count; // the number of marked sub-expressions + BOOST_REGEX_DETAIL_NS::re_syntax_base* m_first_state; // the first state of the machine + unsigned m_restart_type; // search optimisation type + unsigned char m_startmap[1 << CHAR_BIT]; // which characters can start a match + unsigned int m_can_be_null; // whether we can match a null string + BOOST_REGEX_DETAIL_NS::raw_storage m_data; // the buffer in which our states are constructed + typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character + std::vector< + std::pair< + std::size_t, std::size_t> > m_subs; // Position of sub-expressions within the *string*. + bool m_has_recursions; // whether we have recursive expressions; + bool m_disable_match_any; // when set we need to disable the match_any flag as it causes different/buggy behaviour. +}; +// +// class basic_regex_implementation +// pimpl implementation class for basic_regex. +// +template +class basic_regex_implementation + : public regex_data +{ +public: + typedef regex_constants::syntax_option_type flag_type; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef typename traits::locale_type locale_type; + typedef const charT* const_iterator; + + basic_regex_implementation(){} + basic_regex_implementation(const ::boost::shared_ptr< + ::boost::regex_traits_wrapper >& t) + : regex_data(t) {} + void assign(const charT* arg_first, + const charT* arg_last, + flag_type f) + { + regex_data* pdat = this; + basic_regex_parser parser(pdat); + parser.parse(arg_first, arg_last, f); + } + + locale_type BOOST_REGEX_CALL imbue(locale_type l) + { + return this->m_ptraits->imbue(l); + } + locale_type BOOST_REGEX_CALL getloc()const + { + return this->m_ptraits->getloc(); + } + std::basic_string BOOST_REGEX_CALL str()const + { + std::basic_string result; + if(this->m_status == 0) + result = std::basic_string(this->m_expression, this->m_expression_len); + return result; + } + const_iterator BOOST_REGEX_CALL expression()const + { + return this->m_expression; + } + std::pair BOOST_REGEX_CALL subexpression(std::size_t n)const + { + const std::pair& pi = this->m_subs.at(n); + std::pair p(expression() + pi.first, expression() + pi.second); + return p; + } + // + // begin, end: + const_iterator BOOST_REGEX_CALL begin()const + { + return (this->m_status ? 0 : this->m_expression); + } + const_iterator BOOST_REGEX_CALL end()const + { + return (this->m_status ? 0 : this->m_expression + this->m_expression_len); + } + flag_type BOOST_REGEX_CALL flags()const + { + return this->m_flags; + } + size_type BOOST_REGEX_CALL size()const + { + return this->m_expression_len; + } + int BOOST_REGEX_CALL status()const + { + return this->m_status; + } + size_type BOOST_REGEX_CALL mark_count()const + { + return this->m_mark_count - 1; + } + const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const + { + return this->m_first_state; + } + unsigned get_restart_type()const + { + return this->m_restart_type; + } + const unsigned char* get_map()const + { + return this->m_startmap; + } + const ::boost::regex_traits_wrapper& get_traits()const + { + return *(this->m_ptraits); + } + bool can_be_null()const + { + return this->m_can_be_null; + } + const regex_data& get_data()const + { + basic_regex_implementation const* p = this; + return *static_cast*>(p); + } +}; + +} // namespace BOOST_REGEX_DETAIL_NS +// +// class basic_regex: +// represents the compiled +// regular expression: +// + +#ifdef BOOST_REGEX_NO_FWD +template > +#else +template +#endif +class basic_regex : public regbase +{ +public: + // typedefs: + typedef std::size_t traits_size_type; + typedef typename traits::string_type traits_string_type; + typedef charT char_type; + typedef traits traits_type; + + typedef charT value_type; + typedef charT& reference; + typedef const charT& const_reference; + typedef const charT* const_iterator; + typedef const_iterator iterator; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef regex_constants::syntax_option_type flag_type; + // locale_type + // placeholder for actual locale type used by the + // traits class to localise *this. + typedef typename traits::locale_type locale_type; + +public: + explicit basic_regex(){} + explicit basic_regex(const charT* p, flag_type f = regex_constants::normal) + { + assign(p, f); + } + basic_regex(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + { + assign(p1, p2, f); + } + basic_regex(const charT* p, size_type len, flag_type f) + { + assign(p, len, f); + } + basic_regex(const basic_regex& that) + : m_pimpl(that.m_pimpl) {} + ~basic_regex(){} + basic_regex& BOOST_REGEX_CALL operator=(const basic_regex& that) + { + return assign(that); + } + basic_regex& BOOST_REGEX_CALL operator=(const charT* ptr) + { + return assign(ptr); + } + + // + // assign: + basic_regex& assign(const basic_regex& that) + { + m_pimpl = that.m_pimpl; + return *this; + } + basic_regex& assign(const charT* p, flag_type f = regex_constants::normal) + { + return assign(p, p + traits::length(p), f); + } + basic_regex& assign(const charT* p, size_type len, flag_type f) + { + return assign(p, p + len, f); + } +private: + basic_regex& do_assign(const charT* p1, + const charT* p2, + flag_type f); +public: + basic_regex& assign(const charT* p1, + const charT* p2, + flag_type f = regex_constants::normal) + { + return do_assign(p1, p2, f); + } +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + + template + unsigned int BOOST_REGEX_CALL set_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + { + return set_expression(p.data(), p.data() + p.size(), f); + } + + template + explicit basic_regex(const std::basic_string& p, flag_type f = regex_constants::normal) + { + assign(p, f); + } + + template + basic_regex(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal) + { + typedef typename traits::string_type seq_type; + seq_type a(arg_first, arg_last); + if(!a.empty()) + assign(static_cast(&*a.begin()), static_cast(&*a.begin() + a.size()), f); + else + assign(static_cast(0), static_cast(0), f); + } + + template + basic_regex& BOOST_REGEX_CALL operator=(const std::basic_string& p) + { + return assign(p.data(), p.data() + p.size(), regex_constants::normal); + } + + template + basic_regex& BOOST_REGEX_CALL assign( + const std::basic_string& s, + flag_type f = regex_constants::normal) + { + return assign(s.data(), s.data() + s.size(), f); + } + + template + basic_regex& BOOST_REGEX_CALL assign(InputIterator arg_first, + InputIterator arg_last, + flag_type f = regex_constants::normal) + { + typedef typename traits::string_type seq_type; + seq_type a(arg_first, arg_last); + if(a.size()) + { + const charT* p1 = &*a.begin(); + const charT* p2 = &*a.begin() + a.size(); + return assign(p1, p2, f); + } + return assign(static_cast(0), static_cast(0), f); + } +#else + unsigned int BOOST_REGEX_CALL set_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + { + return set_expression(p.data(), p.data() + p.size(), f); + } + + basic_regex(const std::basic_string& p, flag_type f = regex_constants::normal) + { + assign(p, f); + } + + basic_regex& BOOST_REGEX_CALL operator=(const std::basic_string& p) + { + return assign(p.data(), p.data() + p.size(), regex_constants::normal); + } + + basic_regex& BOOST_REGEX_CALL assign( + const std::basic_string& s, + flag_type f = regex_constants::normal) + { + return assign(s.data(), s.data() + s.size(), f); + } + +#endif + + // + // locale: + locale_type BOOST_REGEX_CALL imbue(locale_type l); + locale_type BOOST_REGEX_CALL getloc()const + { + return m_pimpl.get() ? m_pimpl->getloc() : locale_type(); + } + // + // getflags: + // retained for backwards compatibility only, "flags" + // is now the preferred name: + flag_type BOOST_REGEX_CALL getflags()const + { + return flags(); + } + flag_type BOOST_REGEX_CALL flags()const + { + return m_pimpl.get() ? m_pimpl->flags() : 0; + } + // + // str: + std::basic_string BOOST_REGEX_CALL str()const + { + return m_pimpl.get() ? m_pimpl->str() : std::basic_string(); + } + // + // begin, end, subexpression: + std::pair BOOST_REGEX_CALL subexpression(std::size_t n)const + { + if(!m_pimpl.get()) + boost::throw_exception(std::logic_error("Can't access subexpressions in an invalid regex.")); + return m_pimpl->subexpression(n); + } + const_iterator BOOST_REGEX_CALL begin()const + { + return (m_pimpl.get() ? m_pimpl->begin() : 0); + } + const_iterator BOOST_REGEX_CALL end()const + { + return (m_pimpl.get() ? m_pimpl->end() : 0); + } + // + // swap: + void BOOST_REGEX_CALL swap(basic_regex& that)throw() + { + m_pimpl.swap(that.m_pimpl); + } + // + // size: + size_type BOOST_REGEX_CALL size()const + { + return (m_pimpl.get() ? m_pimpl->size() : 0); + } + // + // max_size: + size_type BOOST_REGEX_CALL max_size()const + { + return UINT_MAX; + } + // + // empty: + bool BOOST_REGEX_CALL empty()const + { + return (m_pimpl.get() ? 0 != m_pimpl->status() : true); + } + + size_type BOOST_REGEX_CALL mark_count()const + { + return (m_pimpl.get() ? m_pimpl->mark_count() : 0); + } + + int status()const + { + return (m_pimpl.get() ? m_pimpl->status() : regex_constants::error_empty); + } + + int BOOST_REGEX_CALL compare(const basic_regex& that) const + { + if(m_pimpl.get() == that.m_pimpl.get()) + return 0; + if(!m_pimpl.get()) + return -1; + if(!that.m_pimpl.get()) + return 1; + if(status() != that.status()) + return status() - that.status(); + if(flags() != that.flags()) + return flags() - that.flags(); + return str().compare(that.str()); + } + bool BOOST_REGEX_CALL operator==(const basic_regex& e)const + { + return compare(e) == 0; + } + bool BOOST_REGEX_CALL operator != (const basic_regex& e)const + { + return compare(e) != 0; + } + bool BOOST_REGEX_CALL operator<(const basic_regex& e)const + { + return compare(e) < 0; + } + bool BOOST_REGEX_CALL operator>(const basic_regex& e)const + { + return compare(e) > 0; + } + bool BOOST_REGEX_CALL operator<=(const basic_regex& e)const + { + return compare(e) <= 0; + } + bool BOOST_REGEX_CALL operator>=(const basic_regex& e)const + { + return compare(e) >= 0; + } + + // + // The following are deprecated as public interfaces + // but are available for compatibility with earlier versions. + const charT* BOOST_REGEX_CALL expression()const + { + return (m_pimpl.get() && !m_pimpl->status() ? m_pimpl->expression() : 0); + } + unsigned int BOOST_REGEX_CALL set_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + { + assign(p1, p2, f | regex_constants::no_except); + return status(); + } + unsigned int BOOST_REGEX_CALL set_expression(const charT* p, flag_type f = regex_constants::normal) + { + assign(p, f | regex_constants::no_except); + return status(); + } + unsigned int BOOST_REGEX_CALL error_code()const + { + return status(); + } + // + // private access methods: + // + const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_first_state(); + } + unsigned get_restart_type()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_restart_type(); + } + const unsigned char* get_map()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_map(); + } + const ::boost::regex_traits_wrapper& get_traits()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_traits(); + } + bool can_be_null()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->can_be_null(); + } + const BOOST_REGEX_DETAIL_NS::regex_data& get_data()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_data(); + } + boost::shared_ptr get_named_subs()const + { + return m_pimpl; + } + +private: + shared_ptr > m_pimpl; +}; + +// +// out of line members; +// these are the only members that mutate the basic_regex object, +// and are designed to provide the strong exception guarantee +// (in the event of a throw, the state of the object remains unchanged). +// +template +basic_regex& basic_regex::do_assign(const charT* p1, + const charT* p2, + flag_type f) +{ + shared_ptr > temp; + if(!m_pimpl.get()) + { + temp = shared_ptr >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation()); + } + else + { + temp = shared_ptr >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation(m_pimpl->m_ptraits)); + } + temp->assign(p1, p2, f); + temp.swap(m_pimpl); + return *this; +} + +template +typename basic_regex::locale_type BOOST_REGEX_CALL basic_regex::imbue(locale_type l) +{ + shared_ptr > temp(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation()); + locale_type result = temp->imbue(l); + temp.swap(m_pimpl); + return result; +} + +// +// non-members: +// +template +void swap(basic_regex& e1, basic_regex& e2) +{ + e1.swap(e2); +} + +#ifndef BOOST_NO_STD_LOCALE +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const basic_regex& e) +{ + return (os << e.str()); +} +#else +template +std::ostream& operator << (std::ostream& os, const basic_regex& e) +{ + return (os << e.str()); +} +#endif + +// +// class reg_expression: +// this is provided for backwards compatibility only, +// it is deprecated, no not use! +// +#ifdef BOOST_REGEX_NO_FWD +template > +#else +template +#endif +class reg_expression : public basic_regex +{ +public: + typedef typename basic_regex::flag_type flag_type; + typedef typename basic_regex::size_type size_type; + explicit reg_expression(){} + explicit reg_expression(const charT* p, flag_type f = regex_constants::normal) + : basic_regex(p, f){} + reg_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + : basic_regex(p1, p2, f){} + reg_expression(const charT* p, size_type len, flag_type f) + : basic_regex(p, len, f){} + reg_expression(const reg_expression& that) + : basic_regex(that) {} + ~reg_expression(){} + reg_expression& BOOST_REGEX_CALL operator=(const reg_expression& that) + { + return this->assign(that); + } + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) + template + explicit reg_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + : basic_regex(p, f) + { + } + + template + reg_expression(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal) + : basic_regex(arg_first, arg_last, f) + { + } + + template + reg_expression& BOOST_REGEX_CALL operator=(const std::basic_string& p) + { + this->assign(p); + return *this; + } +#else + explicit reg_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + : basic_regex(p, f) + { + } + + reg_expression& BOOST_REGEX_CALL operator=(const std::basic_string& p) + { + this->assign(p); + return *this; + } +#endif + +}; + +#ifdef BOOST_MSVC +#pragma warning (pop) +#endif + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/basic_regex_creator.hpp b/third-party/boost_regex/include/boost/regex/v4/basic_regex_creator.hpp new file mode 100644 index 0000000000..b9f02ecea0 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/basic_regex_creator.hpp @@ -0,0 +1,1598 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_creator.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_creator which fills in + * the data members of a regex_data object. + */ + +#ifndef BOOST_REGEX_V4_BASIC_REGEX_CREATOR_HPP +#define BOOST_REGEX_V4_BASIC_REGEX_CREATOR_HPP + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ + +namespace BOOST_REGEX_DETAIL_NS{ + +template +struct digraph : public std::pair +{ + digraph() : std::pair(charT(0), charT(0)){} + digraph(charT c1) : std::pair(c1, charT(0)){} + digraph(charT c1, charT c2) : std::pair(c1, c2) + {} + digraph(const digraph& d) : std::pair(d.first, d.second){} +#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + digraph& operator=(const digraph&) = default; +#endif + template + digraph(const Seq& s) : std::pair() + { + BOOST_REGEX_ASSERT(s.size() <= 2); + BOOST_REGEX_ASSERT(s.size()); + this->first = s[0]; + this->second = (s.size() > 1) ? s[1] : 0; + } +}; + +template +class basic_char_set +{ +public: + typedef digraph digraph_type; + typedef typename traits::string_type string_type; + typedef typename traits::char_class_type m_type; + + basic_char_set() + { + m_negate = false; + m_has_digraphs = false; + m_classes = 0; + m_negated_classes = 0; + m_empty = true; + } + + void add_single(const digraph_type& s) + { + m_singles.insert(s); + if(s.second) + m_has_digraphs = true; + m_empty = false; + } + void add_range(const digraph_type& first, const digraph_type& end) + { + m_ranges.push_back(first); + m_ranges.push_back(end); + if(first.second) + { + m_has_digraphs = true; + add_single(first); + } + if(end.second) + { + m_has_digraphs = true; + add_single(end); + } + m_empty = false; + } + void add_class(m_type m) + { + m_classes |= m; + m_empty = false; + } + void add_negated_class(m_type m) + { + m_negated_classes |= m; + m_empty = false; + } + void add_equivalent(const digraph_type& s) + { + m_equivalents.insert(s); + if(s.second) + { + m_has_digraphs = true; + add_single(s); + } + m_empty = false; + } + void negate() + { + m_negate = true; + //m_empty = false; + } + + // + // accessor functions: + // + bool has_digraphs()const + { + return m_has_digraphs; + } + bool is_negated()const + { + return m_negate; + } + typedef typename std::vector::const_iterator list_iterator; + typedef typename std::set::const_iterator set_iterator; + set_iterator singles_begin()const + { + return m_singles.begin(); + } + set_iterator singles_end()const + { + return m_singles.end(); + } + list_iterator ranges_begin()const + { + return m_ranges.begin(); + } + list_iterator ranges_end()const + { + return m_ranges.end(); + } + set_iterator equivalents_begin()const + { + return m_equivalents.begin(); + } + set_iterator equivalents_end()const + { + return m_equivalents.end(); + } + m_type classes()const + { + return m_classes; + } + m_type negated_classes()const + { + return m_negated_classes; + } + bool empty()const + { + return m_empty; + } +private: + std::set m_singles; // a list of single characters to match + std::vector m_ranges; // a list of end points of our ranges + bool m_negate; // true if the set is to be negated + bool m_has_digraphs; // true if we have digraphs present + m_type m_classes; // character classes to match + m_type m_negated_classes; // negated character classes to match + bool m_empty; // whether we've added anything yet + std::set m_equivalents; // a list of equivalence classes +}; + +template +class basic_regex_creator +{ +public: + basic_regex_creator(regex_data* data); + std::ptrdiff_t getoffset(void* addr) + { + return getoffset(addr, m_pdata->m_data.data()); + } + std::ptrdiff_t getoffset(const void* addr, const void* base) + { + return static_cast(addr) - static_cast(base); + } + re_syntax_base* getaddress(std::ptrdiff_t off) + { + return getaddress(off, m_pdata->m_data.data()); + } + re_syntax_base* getaddress(std::ptrdiff_t off, void* base) + { + return static_cast(static_cast(static_cast(base) + off)); + } + void init(unsigned l_flags) + { + m_pdata->m_flags = l_flags; + m_icase = l_flags & regex_constants::icase; + } + regbase::flag_type flags() + { + return m_pdata->m_flags; + } + void flags(regbase::flag_type f) + { + m_pdata->m_flags = f; + if(m_icase != static_cast(f & regbase::icase)) + { + m_icase = static_cast(f & regbase::icase); + } + } + re_syntax_base* append_state(syntax_element_type t, std::size_t s = sizeof(re_syntax_base)); + re_syntax_base* insert_state(std::ptrdiff_t pos, syntax_element_type t, std::size_t s = sizeof(re_syntax_base)); + re_literal* append_literal(charT c); + re_syntax_base* append_set(const basic_char_set& char_set); + re_syntax_base* append_set(const basic_char_set& char_set, mpl::false_*); + re_syntax_base* append_set(const basic_char_set& char_set, mpl::true_*); + void finalize(const charT* p1, const charT* p2); +protected: + regex_data* m_pdata; // pointer to the basic_regex_data struct we are filling in + const ::boost::regex_traits_wrapper& + m_traits; // convenience reference to traits class + re_syntax_base* m_last_state; // the last state we added + bool m_icase; // true for case insensitive matches + unsigned m_repeater_id; // the state_id of the next repeater + bool m_has_backrefs; // true if there are actually any backrefs + indexed_bit_flag m_backrefs; // bitmask of permitted backrefs + boost::uintmax_t m_bad_repeats; // bitmask of repeats we can't deduce a startmap for; + bool m_has_recursions; // set when we have recursive expressions to fixup + std::vector m_recursion_checks; // notes which recursions we've followed while analysing this expression + typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character + typename traits::char_class_type m_mask_space; // mask used to determine if a character is a word character + typename traits::char_class_type m_lower_mask; // mask used to determine if a character is a lowercase character + typename traits::char_class_type m_upper_mask; // mask used to determine if a character is an uppercase character + typename traits::char_class_type m_alpha_mask; // mask used to determine if a character is an alphabetic character +private: + basic_regex_creator& operator=(const basic_regex_creator&); + basic_regex_creator(const basic_regex_creator&); + + void fixup_pointers(re_syntax_base* state); + void fixup_recursions(re_syntax_base* state); + void create_startmaps(re_syntax_base* state); + int calculate_backstep(re_syntax_base* state); + void create_startmap(re_syntax_base* state, unsigned char* l_map, unsigned int* pnull, unsigned char mask); + unsigned get_restart_type(re_syntax_base* state); + void set_all_masks(unsigned char* bits, unsigned char); + bool is_bad_repeat(re_syntax_base* pt); + void set_bad_repeat(re_syntax_base* pt); + syntax_element_type get_repeat_type(re_syntax_base* state); + void probe_leading_repeat(re_syntax_base* state); +}; + +template +basic_regex_creator::basic_regex_creator(regex_data* data) + : m_pdata(data), m_traits(*(data->m_ptraits)), m_last_state(0), m_icase(false), m_repeater_id(0), + m_has_backrefs(false), m_bad_repeats(0), m_has_recursions(false), m_word_mask(0), m_mask_space(0), m_lower_mask(0), m_upper_mask(0), m_alpha_mask(0) +{ + m_pdata->m_data.clear(); + m_pdata->m_status = ::boost::regex_constants::error_ok; + static const charT w = 'w'; + static const charT s = 's'; + static const charT l[5] = { 'l', 'o', 'w', 'e', 'r', }; + static const charT u[5] = { 'u', 'p', 'p', 'e', 'r', }; + static const charT a[5] = { 'a', 'l', 'p', 'h', 'a', }; + m_word_mask = m_traits.lookup_classname(&w, &w +1); + m_mask_space = m_traits.lookup_classname(&s, &s +1); + m_lower_mask = m_traits.lookup_classname(l, l + 5); + m_upper_mask = m_traits.lookup_classname(u, u + 5); + m_alpha_mask = m_traits.lookup_classname(a, a + 5); + m_pdata->m_word_mask = m_word_mask; + BOOST_REGEX_ASSERT(m_word_mask != 0); + BOOST_REGEX_ASSERT(m_mask_space != 0); + BOOST_REGEX_ASSERT(m_lower_mask != 0); + BOOST_REGEX_ASSERT(m_upper_mask != 0); + BOOST_REGEX_ASSERT(m_alpha_mask != 0); +} + +template +re_syntax_base* basic_regex_creator::append_state(syntax_element_type t, std::size_t s) +{ + // if the state is a backref then make a note of it: + if(t == syntax_element_backref) + this->m_has_backrefs = true; + // append a new state, start by aligning our last one: + m_pdata->m_data.align(); + // set the offset to the next state in our last one: + if(m_last_state) + m_last_state->next.i = m_pdata->m_data.size() - getoffset(m_last_state); + // now actually extend our data: + m_last_state = static_cast(m_pdata->m_data.extend(s)); + // fill in boilerplate options in the new state: + m_last_state->next.i = 0; + m_last_state->type = t; + return m_last_state; +} + +template +re_syntax_base* basic_regex_creator::insert_state(std::ptrdiff_t pos, syntax_element_type t, std::size_t s) +{ + // append a new state, start by aligning our last one: + m_pdata->m_data.align(); + // set the offset to the next state in our last one: + if(m_last_state) + m_last_state->next.i = m_pdata->m_data.size() - getoffset(m_last_state); + // remember the last state position: + std::ptrdiff_t off = getoffset(m_last_state) + s; + // now actually insert our data: + re_syntax_base* new_state = static_cast(m_pdata->m_data.insert(pos, s)); + // fill in boilerplate options in the new state: + new_state->next.i = s; + new_state->type = t; + m_last_state = getaddress(off); + return new_state; +} + +template +re_literal* basic_regex_creator::append_literal(charT c) +{ + re_literal* result; + // start by seeing if we have an existing re_literal we can extend: + if((0 == m_last_state) || (m_last_state->type != syntax_element_literal)) + { + // no existing re_literal, create a new one: + result = static_cast(append_state(syntax_element_literal, sizeof(re_literal) + sizeof(charT))); + result->length = 1; + *static_cast(static_cast(result+1)) = m_traits.translate(c, m_icase); + } + else + { + // we have an existing re_literal, extend it: + std::ptrdiff_t off = getoffset(m_last_state); + m_pdata->m_data.extend(sizeof(charT)); + m_last_state = result = static_cast(getaddress(off)); + charT* characters = static_cast(static_cast(result+1)); + characters[result->length] = m_traits.translate(c, m_icase); + result->length += 1; + } + return result; +} + +template +inline re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set) +{ + typedef mpl::bool_< (sizeof(charT) == 1) > truth_type; + return char_set.has_digraphs() + ? append_set(char_set, static_cast(0)) + : append_set(char_set, static_cast(0)); +} + +template +re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set, mpl::false_*) +{ + typedef typename traits::string_type string_type; + typedef typename basic_char_set::list_iterator item_iterator; + typedef typename basic_char_set::set_iterator set_iterator; + typedef typename traits::char_class_type m_type; + + re_set_long* result = static_cast*>(append_state(syntax_element_long_set, sizeof(re_set_long))); + // + // fill in the basics: + // + result->csingles = static_cast(::boost::BOOST_REGEX_DETAIL_NS::distance(char_set.singles_begin(), char_set.singles_end())); + result->cranges = static_cast(::boost::BOOST_REGEX_DETAIL_NS::distance(char_set.ranges_begin(), char_set.ranges_end())) / 2; + result->cequivalents = static_cast(::boost::BOOST_REGEX_DETAIL_NS::distance(char_set.equivalents_begin(), char_set.equivalents_end())); + result->cclasses = char_set.classes(); + result->cnclasses = char_set.negated_classes(); + if(flags() & regbase::icase) + { + // adjust classes as needed: + if(((result->cclasses & m_lower_mask) == m_lower_mask) || ((result->cclasses & m_upper_mask) == m_upper_mask)) + result->cclasses |= m_alpha_mask; + if(((result->cnclasses & m_lower_mask) == m_lower_mask) || ((result->cnclasses & m_upper_mask) == m_upper_mask)) + result->cnclasses |= m_alpha_mask; + } + + result->isnot = char_set.is_negated(); + result->singleton = !char_set.has_digraphs(); + // + // remember where the state is for later: + // + std::ptrdiff_t offset = getoffset(result); + // + // now extend with all the singles: + // + item_iterator first, last; + set_iterator sfirst, slast; + sfirst = char_set.singles_begin(); + slast = char_set.singles_end(); + while(sfirst != slast) + { + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (sfirst->first == static_cast(0) ? 1 : sfirst->second ? 3 : 2))); + p[0] = m_traits.translate(sfirst->first, m_icase); + if(sfirst->first == static_cast(0)) + { + p[0] = 0; + } + else if(sfirst->second) + { + p[1] = m_traits.translate(sfirst->second, m_icase); + p[2] = 0; + } + else + p[1] = 0; + ++sfirst; + } + // + // now extend with all the ranges: + // + first = char_set.ranges_begin(); + last = char_set.ranges_end(); + while(first != last) + { + // first grab the endpoints of the range: + digraph c1 = *first; + c1.first = this->m_traits.translate(c1.first, this->m_icase); + c1.second = this->m_traits.translate(c1.second, this->m_icase); + ++first; + digraph c2 = *first; + c2.first = this->m_traits.translate(c2.first, this->m_icase); + c2.second = this->m_traits.translate(c2.second, this->m_icase); + ++first; + string_type s1, s2; + // different actions now depending upon whether collation is turned on: + if(flags() & regex_constants::collate) + { + // we need to transform our range into sort keys: + charT a1[3] = { c1.first, c1.second, charT(0), }; + charT a2[3] = { c2.first, c2.second, charT(0), }; + s1 = this->m_traits.transform(a1, (a1[1] ? a1+2 : a1+1)); + s2 = this->m_traits.transform(a2, (a2[1] ? a2+2 : a2+1)); + if(s1.empty()) + s1 = string_type(1, charT(0)); + if(s2.empty()) + s2 = string_type(1, charT(0)); + } + else + { + if(c1.second) + { + s1.insert(s1.end(), c1.first); + s1.insert(s1.end(), c1.second); + } + else + s1 = string_type(1, c1.first); + if(c2.second) + { + s2.insert(s2.end(), c2.first); + s2.insert(s2.end(), c2.second); + } + else + s2.insert(s2.end(), c2.first); + } + if(s1 > s2) + { + // Oops error: + return 0; + } + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (s1.size() + s2.size() + 2) ) ); + BOOST_REGEX_DETAIL_NS::copy(s1.begin(), s1.end(), p); + p[s1.size()] = charT(0); + p += s1.size() + 1; + BOOST_REGEX_DETAIL_NS::copy(s2.begin(), s2.end(), p); + p[s2.size()] = charT(0); + } + // + // now process the equivalence classes: + // + sfirst = char_set.equivalents_begin(); + slast = char_set.equivalents_end(); + while(sfirst != slast) + { + string_type s; + if(sfirst->second) + { + charT cs[3] = { sfirst->first, sfirst->second, charT(0), }; + s = m_traits.transform_primary(cs, cs+2); + } + else + s = m_traits.transform_primary(&sfirst->first, &sfirst->first+1); + if(s.empty()) + return 0; // invalid or unsupported equivalence class + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (s.size()+1) ) ); + BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), p); + p[s.size()] = charT(0); + ++sfirst; + } + // + // finally reset the address of our last state: + // + m_last_state = result = static_cast*>(getaddress(offset)); + return result; +} + +template +inline bool char_less(T t1, T t2) +{ + return t1 < t2; +} +inline bool char_less(char t1, char t2) +{ + return static_cast(t1) < static_cast(t2); +} +inline bool char_less(signed char t1, signed char t2) +{ + return static_cast(t1) < static_cast(t2); +} + +template +re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set, mpl::true_*) +{ + typedef typename traits::string_type string_type; + typedef typename basic_char_set::list_iterator item_iterator; + typedef typename basic_char_set::set_iterator set_iterator; + + re_set* result = static_cast(append_state(syntax_element_set, sizeof(re_set))); + bool negate = char_set.is_negated(); + std::memset(result->_map, 0, sizeof(result->_map)); + // + // handle singles first: + // + item_iterator first, last; + set_iterator sfirst, slast; + sfirst = char_set.singles_begin(); + slast = char_set.singles_end(); + while(sfirst != slast) + { + for(unsigned int i = 0; i < (1 << CHAR_BIT); ++i) + { + if(this->m_traits.translate(static_cast(i), this->m_icase) + == this->m_traits.translate(sfirst->first, this->m_icase)) + result->_map[i] = true; + } + ++sfirst; + } + // + // OK now handle ranges: + // + first = char_set.ranges_begin(); + last = char_set.ranges_end(); + while(first != last) + { + // first grab the endpoints of the range: + charT c1 = this->m_traits.translate(first->first, this->m_icase); + ++first; + charT c2 = this->m_traits.translate(first->first, this->m_icase); + ++first; + // different actions now depending upon whether collation is turned on: + if(flags() & regex_constants::collate) + { + // we need to transform our range into sort keys: + charT c3[2] = { c1, charT(0), }; + string_type s1 = this->m_traits.transform(c3, c3+1); + c3[0] = c2; + string_type s2 = this->m_traits.transform(c3, c3+1); + if(s1 > s2) + { + // Oops error: + return 0; + } + BOOST_REGEX_ASSERT(c3[1] == charT(0)); + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + c3[0] = static_cast(i); + string_type s3 = this->m_traits.transform(c3, c3 +1); + if((s1 <= s3) && (s3 <= s2)) + result->_map[i] = true; + } + } + else + { + if(char_less(c2, c1)) + { + // Oops error: + return 0; + } + // everything in range matches: + std::memset(result->_map + static_cast(c1), true, static_cast(1u) + static_cast(static_cast(c2) - static_cast(c1))); + } + } + // + // and now the classes: + // + typedef typename traits::char_class_type m_type; + m_type m = char_set.classes(); + if(flags() & regbase::icase) + { + // adjust m as needed: + if(((m & m_lower_mask) == m_lower_mask) || ((m & m_upper_mask) == m_upper_mask)) + m |= m_alpha_mask; + } + if(m != 0) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + if(this->m_traits.isctype(static_cast(i), m)) + result->_map[i] = true; + } + } + // + // and now the negated classes: + // + m = char_set.negated_classes(); + if(flags() & regbase::icase) + { + // adjust m as needed: + if(((m & m_lower_mask) == m_lower_mask) || ((m & m_upper_mask) == m_upper_mask)) + m |= m_alpha_mask; + } + if(m != 0) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + if(0 == this->m_traits.isctype(static_cast(i), m)) + result->_map[i] = true; + } + } + // + // now process the equivalence classes: + // + sfirst = char_set.equivalents_begin(); + slast = char_set.equivalents_end(); + while(sfirst != slast) + { + string_type s; + BOOST_REGEX_ASSERT(static_cast(0) == sfirst->second); + s = m_traits.transform_primary(&sfirst->first, &sfirst->first+1); + if(s.empty()) + return 0; // invalid or unsupported equivalence class + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + charT c[2] = { (static_cast(i)), charT(0), }; + string_type s2 = this->m_traits.transform_primary(c, c+1); + if(s == s2) + result->_map[i] = true; + } + ++sfirst; + } + if(negate) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + result->_map[i] = !(result->_map[i]); + } + } + return result; +} + +template +void basic_regex_creator::finalize(const charT* p1, const charT* p2) +{ + if(this->m_pdata->m_status) + return; + // we've added all the states we need, now finish things off. + // start by adding a terminating state: + append_state(syntax_element_match); + // extend storage to store original expression: + std::ptrdiff_t len = p2 - p1; + m_pdata->m_expression_len = len; + charT* ps = static_cast(m_pdata->m_data.extend(sizeof(charT) * (1 + (p2 - p1)))); + m_pdata->m_expression = ps; + BOOST_REGEX_DETAIL_NS::copy(p1, p2, ps); + ps[p2 - p1] = 0; + // fill in our other data... + // successful parsing implies a zero status: + m_pdata->m_status = 0; + // get the first state of the machine: + m_pdata->m_first_state = static_cast(m_pdata->m_data.data()); + // fixup pointers in the machine: + fixup_pointers(m_pdata->m_first_state); + if(m_has_recursions) + { + m_pdata->m_has_recursions = true; + fixup_recursions(m_pdata->m_first_state); + if(this->m_pdata->m_status) + return; + } + else + m_pdata->m_has_recursions = false; + // create nested startmaps: + create_startmaps(m_pdata->m_first_state); + // create main startmap: + std::memset(m_pdata->m_startmap, 0, sizeof(m_pdata->m_startmap)); + m_pdata->m_can_be_null = 0; + + m_bad_repeats = 0; + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + create_startmap(m_pdata->m_first_state, m_pdata->m_startmap, &(m_pdata->m_can_be_null), mask_all); + // get the restart type: + m_pdata->m_restart_type = get_restart_type(m_pdata->m_first_state); + // optimise a leading repeat if there is one: + probe_leading_repeat(m_pdata->m_first_state); +} + +template +void basic_regex_creator::fixup_pointers(re_syntax_base* state) +{ + while(state) + { + switch(state->type) + { + case syntax_element_recurse: + m_has_recursions = true; + if(state->next.i) + state->next.p = getaddress(state->next.i, state); + else + state->next.p = 0; + break; + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + // set the state_id of this repeat: + static_cast(state)->state_id = m_repeater_id++; + BOOST_FALLTHROUGH; + case syntax_element_alt: + std::memset(static_cast(state)->_map, 0, sizeof(static_cast(state)->_map)); + static_cast(state)->can_be_null = 0; + BOOST_FALLTHROUGH; + case syntax_element_jump: + static_cast(state)->alt.p = getaddress(static_cast(state)->alt.i, state); + BOOST_FALLTHROUGH; + default: + if(state->next.i) + state->next.p = getaddress(state->next.i, state); + else + state->next.p = 0; + } + state = state->next.p; + } +} + +template +void basic_regex_creator::fixup_recursions(re_syntax_base* state) +{ + re_syntax_base* base = state; + while(state) + { + switch(state->type) + { + case syntax_element_assert_backref: + { + // just check that the index is valid: + int idx = static_cast(state)->index; + if(idx < 0) + { + idx = -idx-1; + if(idx >= hash_value_mask) + { + idx = m_pdata->get_id(idx); + if(idx <= 0) + { + // check of sub-expression that doesn't exist: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered a forward reference to a marked sub-expression that does not exist."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + } + } + } + break; + case syntax_element_recurse: + { + bool ok = false; + re_syntax_base* p = base; + std::ptrdiff_t idx = static_cast(state)->alt.i; + if(idx >= hash_value_mask) + { + // + // There may be more than one capture group with this hash, just do what Perl + // does and recurse to the leftmost: + // + idx = m_pdata->get_id(static_cast(idx)); + } + if(idx < 0) + { + ok = false; + } + else + { + while(p) + { + if((p->type == syntax_element_startmark) && (static_cast(p)->index == idx)) + { + // + // We've found the target of the recursion, set the jump target: + // + static_cast(state)->alt.p = p; + ok = true; + // + // Now scan the target for nested repeats: + // + p = p->next.p; + int next_rep_id = 0; + while(p) + { + switch(p->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + next_rep_id = static_cast(p)->state_id; + break; + case syntax_element_endmark: + if(static_cast(p)->index == idx) + next_rep_id = -1; + break; + default: + break; + } + if(next_rep_id) + break; + p = p->next.p; + } + if(next_rep_id > 0) + { + static_cast(state)->state_id = next_rep_id - 1; + } + + break; + } + p = p->next.p; + } + } + if(!ok) + { + // recursion to sub-expression that doesn't exist: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered a forward reference to a recursive sub-expression that does not exist."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + } + break; + default: + break; + } + state = state->next.p; + } +} + +template +void basic_regex_creator::create_startmaps(re_syntax_base* state) +{ + // non-recursive implementation: + // create the last map in the machine first, so that earlier maps + // can make use of the result... + // + // This was originally a recursive implementation, but that caused stack + // overflows with complex expressions on small stacks (think COM+). + + // start by saving the case setting: + bool l_icase = m_icase; + std::vector > v; + + while(state) + { + switch(state->type) + { + case syntax_element_toggle_case: + // we need to track case changes here: + m_icase = static_cast(state)->icase; + state = state->next.p; + continue; + case syntax_element_alt: + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + // just push the state onto our stack for now: + v.push_back(std::pair(m_icase, state)); + state = state->next.p; + break; + case syntax_element_backstep: + // we need to calculate how big the backstep is: + static_cast(state)->index + = this->calculate_backstep(state->next.p); + if(static_cast(state)->index < 0) + { + // Oops error: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Invalid lookbehind assertion encountered in the regular expression."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + BOOST_FALLTHROUGH; + default: + state = state->next.p; + } + } + + // now work through our list, building all the maps as we go: + while(!v.empty()) + { + // Initialize m_recursion_checks if we need it: + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + + const std::pair& p = v.back(); + m_icase = p.first; + state = p.second; + v.pop_back(); + + // Build maps: + m_bad_repeats = 0; + create_startmap(state->next.p, static_cast(state)->_map, &static_cast(state)->can_be_null, mask_take); + m_bad_repeats = 0; + + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + create_startmap(static_cast(state)->alt.p, static_cast(state)->_map, &static_cast(state)->can_be_null, mask_skip); + // adjust the type of the state to allow for faster matching: + state->type = this->get_repeat_type(state); + } + // restore case sensitivity: + m_icase = l_icase; +} + +template +int basic_regex_creator::calculate_backstep(re_syntax_base* state) +{ + typedef typename traits::char_class_type m_type; + int result = 0; + while(state) + { + switch(state->type) + { + case syntax_element_startmark: + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + { + state = static_cast(state->next.p)->alt.p->next.p; + continue; + } + else if(static_cast(state)->index == -3) + { + state = state->next.p->next.p; + continue; + } + break; + case syntax_element_endmark: + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + return result; + break; + case syntax_element_literal: + result += static_cast(state)->length; + break; + case syntax_element_wild: + case syntax_element_set: + result += 1; + break; + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_backref: + case syntax_element_rep: + case syntax_element_combining: + case syntax_element_long_set_rep: + case syntax_element_backstep: + { + re_repeat* rep = static_cast(state); + // adjust the type of the state to allow for faster matching: + state->type = this->get_repeat_type(state); + if((state->type == syntax_element_dot_rep) + || (state->type == syntax_element_char_rep) + || (state->type == syntax_element_short_set_rep)) + { + if(rep->max != rep->min) + return -1; + result += static_cast(rep->min); + state = rep->alt.p; + continue; + } + else if(state->type == syntax_element_long_set_rep) + { + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_long_set); + if(static_cast*>(rep->next.p)->singleton == 0) + return -1; + if(rep->max != rep->min) + return -1; + result += static_cast(rep->min); + state = rep->alt.p; + continue; + } + } + return -1; + case syntax_element_long_set: + if(static_cast*>(state)->singleton == 0) + return -1; + result += 1; + break; + case syntax_element_jump: + state = static_cast(state)->alt.p; + continue; + case syntax_element_alt: + { + int r1 = calculate_backstep(state->next.p); + int r2 = calculate_backstep(static_cast(state)->alt.p); + if((r1 < 0) || (r1 != r2)) + return -1; + return result + r1; + } + default: + break; + } + state = state->next.p; + } + return -1; +} + +struct recursion_saver +{ + std::vector saved_state; + std::vector* state; + recursion_saver(std::vector* p) : saved_state(*p), state(p) {} + ~recursion_saver() + { + state->swap(saved_state); + } +}; + +template +void basic_regex_creator::create_startmap(re_syntax_base* state, unsigned char* l_map, unsigned int* pnull, unsigned char mask) +{ + recursion_saver saved_recursions(&m_recursion_checks); + int not_last_jump = 1; + re_syntax_base* recursion_start = 0; + int recursion_sub = 0; + re_syntax_base* recursion_restart = 0; + + // track case sensitivity: + bool l_icase = m_icase; + + while(state) + { + switch(state->type) + { + case syntax_element_toggle_case: + l_icase = static_cast(state)->icase; + state = state->next.p; + break; + case syntax_element_literal: + { + // don't set anything in *pnull, set each element in l_map + // that could match the first character in the literal: + if(l_map) + { + l_map[0] |= mask_init; + charT first_char = *static_cast(static_cast(static_cast(state) + 1)); + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(m_traits.translate(static_cast(i), l_icase) == first_char) + l_map[i] |= mask; + } + } + return; + } + case syntax_element_end_line: + { + // next character must be a line separator (if there is one): + if(l_map) + { + l_map[0] |= mask_init; + l_map[static_cast('\n')] |= mask; + l_map[static_cast('\r')] |= mask; + l_map[static_cast('\f')] |= mask; + l_map[0x85] |= mask; + } + // now figure out if we can match a NULL string at this point: + if(pnull) + create_startmap(state->next.p, 0, pnull, mask); + return; + } + case syntax_element_recurse: + { + BOOST_REGEX_ASSERT(static_cast(state)->alt.p->type == syntax_element_startmark); + recursion_sub = static_cast(static_cast(state)->alt.p)->index; + if(m_recursion_checks[recursion_sub] & 1u) + { + // Infinite recursion!! + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered an infinite recursion."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + else if(recursion_start == 0) + { + recursion_start = state; + recursion_restart = state->next.p; + state = static_cast(state)->alt.p; + m_recursion_checks[recursion_sub] |= 1u; + break; + } + m_recursion_checks[recursion_sub] |= 1u; + // can't handle nested recursion here... + BOOST_FALLTHROUGH; + } + case syntax_element_backref: + // can be null, and any character can match: + if(pnull) + *pnull |= mask; + BOOST_FALLTHROUGH; + case syntax_element_wild: + { + // can't be null, any character can match: + set_all_masks(l_map, mask); + return; + } + case syntax_element_accept: + case syntax_element_match: + { + // must be null, any character can match: + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + case syntax_element_word_start: + { + // recurse, then AND with all the word characters: + create_startmap(state->next.p, l_map, pnull, mask); + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(!m_traits.isctype(static_cast(i), m_word_mask)) + l_map[i] &= static_cast(~mask); + } + } + return; + } + case syntax_element_word_end: + { + // recurse, then AND with all the word characters: + create_startmap(state->next.p, l_map, pnull, mask); + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(m_traits.isctype(static_cast(i), m_word_mask)) + l_map[i] &= static_cast(~mask); + } + } + return; + } + case syntax_element_buffer_end: + { + // we *must be null* : + if(pnull) + *pnull |= mask; + return; + } + case syntax_element_long_set: + if(l_map) + { + typedef typename traits::char_class_type m_type; + if(static_cast*>(state)->singleton) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + charT c = static_cast(i); + if(&c != re_is_set_member(&c, &c + 1, static_cast*>(state), *m_pdata, l_icase)) + l_map[i] |= mask; + } + } + else + set_all_masks(l_map, mask); + } + return; + case syntax_element_set: + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(static_cast(state)->_map[ + static_cast(m_traits.translate(static_cast(i), l_icase))]) + l_map[i] |= mask; + } + } + return; + case syntax_element_jump: + // take the jump: + state = static_cast(state)->alt.p; + not_last_jump = -1; + break; + case syntax_element_alt: + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + re_alt* rep = static_cast(state); + if(rep->_map[0] & mask_init) + { + if(l_map) + { + // copy previous results: + l_map[0] |= mask_init; + for(unsigned int i = 0; i <= UCHAR_MAX; ++i) + { + if(rep->_map[i] & mask_any) + l_map[i] |= mask; + } + } + if(pnull) + { + if(rep->can_be_null & mask_any) + *pnull |= mask; + } + } + else + { + // we haven't created a startmap for this alternative yet + // so take the union of the two options: + if(is_bad_repeat(state)) + { + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + set_bad_repeat(state); + create_startmap(state->next.p, l_map, pnull, mask); + if((state->type == syntax_element_alt) + || (static_cast(state)->min == 0) + || (not_last_jump == 0)) + create_startmap(rep->alt.p, l_map, pnull, mask); + } + } + return; + case syntax_element_soft_buffer_end: + // match newline or null: + if(l_map) + { + l_map[0] |= mask_init; + l_map[static_cast('\n')] |= mask; + l_map[static_cast('\r')] |= mask; + } + if(pnull) + *pnull |= mask; + return; + case syntax_element_endmark: + // need to handle independent subs as a special case: + if(static_cast(state)->index < 0) + { + // can be null, any character can match: + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + else if(recursion_start && (recursion_sub != 0) && (recursion_sub == static_cast(state)->index)) + { + // recursion termination: + recursion_start = 0; + state = recursion_restart; + break; + } + + // + // Normally we just go to the next state... but if this sub-expression is + // the target of a recursion, then we might be ending a recursion, in which + // case we should check whatever follows that recursion, as well as whatever + // follows this state: + // + if(m_pdata->m_has_recursions && static_cast(state)->index) + { + bool ok = false; + re_syntax_base* p = m_pdata->m_first_state; + while(p) + { + if(p->type == syntax_element_recurse) + { + re_brace* p2 = static_cast(static_cast(p)->alt.p); + if((p2->type == syntax_element_startmark) && (p2->index == static_cast(state)->index)) + { + ok = true; + break; + } + } + p = p->next.p; + } + if(ok && ((m_recursion_checks[static_cast(state)->index] & 2u) == 0)) + { + m_recursion_checks[static_cast(state)->index] |= 2u; + create_startmap(p->next.p, l_map, pnull, mask); + } + } + state = state->next.p; + break; + + case syntax_element_commit: + set_all_masks(l_map, mask); + // Continue scanning so we can figure out whether we can be null: + state = state->next.p; + break; + case syntax_element_startmark: + // need to handle independent subs as a special case: + if(static_cast(state)->index == -3) + { + state = state->next.p->next.p; + break; + } + BOOST_FALLTHROUGH; + default: + state = state->next.p; + } + ++not_last_jump; + } +} + +template +unsigned basic_regex_creator::get_restart_type(re_syntax_base* state) +{ + // + // find out how the machine starts, so we can optimise the search: + // + while(state) + { + switch(state->type) + { + case syntax_element_startmark: + case syntax_element_endmark: + state = state->next.p; + continue; + case syntax_element_start_line: + return regbase::restart_line; + case syntax_element_word_start: + return regbase::restart_word; + case syntax_element_buffer_start: + return regbase::restart_buf; + case syntax_element_restart_continue: + return regbase::restart_continue; + default: + state = 0; + continue; + } + } + return regbase::restart_any; +} + +template +void basic_regex_creator::set_all_masks(unsigned char* bits, unsigned char mask) +{ + // + // set mask in all of bits elements, + // if bits[0] has mask_init not set then we can + // optimise this to a call to memset: + // + if(bits) + { + if(bits[0] == 0) + (std::memset)(bits, mask, 1u << CHAR_BIT); + else + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + bits[i] |= mask; + } + bits[0] |= mask_init; + } +} + +template +bool basic_regex_creator::is_bad_repeat(re_syntax_base* pt) +{ + switch(pt->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + unsigned state_id = static_cast(pt)->state_id; + if(state_id >= sizeof(m_bad_repeats) * CHAR_BIT) + return true; // run out of bits, assume we can't traverse this one. + static const boost::uintmax_t one = 1uL; + return m_bad_repeats & (one << state_id); + } + default: + return false; + } +} + +template +void basic_regex_creator::set_bad_repeat(re_syntax_base* pt) +{ + switch(pt->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + unsigned state_id = static_cast(pt)->state_id; + static const boost::uintmax_t one = 1uL; + if(state_id <= sizeof(m_bad_repeats) * CHAR_BIT) + m_bad_repeats |= (one << state_id); + } + break; + default: + break; + } +} + +template +syntax_element_type basic_regex_creator::get_repeat_type(re_syntax_base* state) +{ + typedef typename traits::char_class_type m_type; + if(state->type == syntax_element_rep) + { + // check to see if we are repeating a single state: + if(state->next.p->next.p->next.p == static_cast(state)->alt.p) + { + switch(state->next.p->type) + { + case BOOST_REGEX_DETAIL_NS::syntax_element_wild: + return BOOST_REGEX_DETAIL_NS::syntax_element_dot_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_literal: + return BOOST_REGEX_DETAIL_NS::syntax_element_char_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_set: + return BOOST_REGEX_DETAIL_NS::syntax_element_short_set_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_long_set: + if(static_cast*>(state->next.p)->singleton) + return BOOST_REGEX_DETAIL_NS::syntax_element_long_set_rep; + break; + default: + break; + } + } + } + return state->type; +} + +template +void basic_regex_creator::probe_leading_repeat(re_syntax_base* state) +{ + // enumerate our states, and see if we have a leading repeat + // for which failed search restarts can be optimized; + do + { + switch(state->type) + { + case syntax_element_startmark: + if(static_cast(state)->index >= 0) + { + state = state->next.p; + continue; + } +#ifdef BOOST_MSVC +# pragma warning(push) +#pragma warning(disable:6011) +#endif + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + { + // skip past the zero width assertion: + state = static_cast(state->next.p)->alt.p->next.p; + continue; + } +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + if(static_cast(state)->index == -3) + { + // Have to skip the leading jump state: + state = state->next.p->next.p; + continue; + } + return; + case syntax_element_endmark: + case syntax_element_start_line: + case syntax_element_end_line: + case syntax_element_word_boundary: + case syntax_element_within_word: + case syntax_element_word_start: + case syntax_element_word_end: + case syntax_element_buffer_start: + case syntax_element_buffer_end: + case syntax_element_restart_continue: + state = state->next.p; + break; + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + if(this->m_has_backrefs == 0) + static_cast(state)->leading = true; + BOOST_FALLTHROUGH; + default: + return; + } + }while(state); +} + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/basic_regex_parser.hpp b/third-party/boost_regex/include/boost/regex/v4/basic_regex_parser.hpp new file mode 100644 index 0000000000..1b7121f057 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/basic_regex_parser.hpp @@ -0,0 +1,3174 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_parser.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_parser. + */ + +#ifndef BOOST_REGEX_V4_BASIC_REGEX_PARSER_HPP +#define BOOST_REGEX_V4_BASIC_REGEX_PARSER_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#if BOOST_MSVC >= 1800 +#pragma warning(disable: 26812) +#endif +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +inline boost::intmax_t umax(mpl::false_ const&) +{ + // Get out clause here, just in case numeric_limits is unspecialized: + return std::numeric_limits::is_specialized ? (std::numeric_limits::max)() : INT_MAX; +} +inline boost::intmax_t umax(mpl::true_ const&) +{ + return (std::numeric_limits::max)(); +} + +inline boost::intmax_t umax() +{ + return umax(mpl::bool_::digits >= std::numeric_limits::digits>()); +} + +template +class basic_regex_parser : public basic_regex_creator +{ +public: + basic_regex_parser(regex_data* data); + void parse(const charT* p1, const charT* p2, unsigned flags); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position, const std::string& message) + { + fail(error_code, position, message, position); + } + + bool parse_all(); + bool parse_basic(); + bool parse_extended(); + bool parse_literal(); + bool parse_open_paren(); + bool parse_basic_escape(); + bool parse_extended_escape(); + bool parse_match_any(); + bool parse_repeat(std::size_t low = 0, std::size_t high = (std::numeric_limits::max)()); + bool parse_repeat_range(bool isbasic); + bool parse_alt(); + bool parse_set(); + bool parse_backref(); + void parse_set_literal(basic_char_set& char_set); + bool parse_inner_set(basic_char_set& char_set); + bool parse_QE(); + bool parse_perl_extension(); + bool parse_perl_verb(); + bool match_verb(const char*); + bool add_emacs_code(bool negate); + bool unwind_alts(std::ptrdiff_t last_paren_start); + digraph get_next_set_literal(basic_char_set& char_set); + charT unescape_character(); + regex_constants::syntax_option_type parse_options(); + +private: + typedef bool (basic_regex_parser::*parser_proc_type)(); + typedef typename traits::string_type string_type; + typedef typename traits::char_class_type char_class_type; + parser_proc_type m_parser_proc; // the main parser to use + const charT* m_base; // the start of the string being parsed + const charT* m_end; // the end of the string being parsed + const charT* m_position; // our current parser position + unsigned m_mark_count; // how many sub-expressions we have + int m_mark_reset; // used to indicate that we're inside a (?|...) block. + unsigned m_max_mark; // largest mark count seen inside a (?|...) block. + std::ptrdiff_t m_paren_start; // where the last seen ')' began (where repeats are inserted). + std::ptrdiff_t m_alt_insert_point; // where to insert the next alternative + bool m_has_case_change; // true if somewhere in the current block the case has changed + unsigned m_recursion_count; // How many times we've called parse_all. +#if defined(BOOST_MSVC) && defined(_M_IX86) + // This is an ugly warning suppression workaround (for warnings *inside* std::vector + // that can not otherwise be suppressed)... + BOOST_STATIC_ASSERT(sizeof(long) >= sizeof(void*)); + std::vector m_alt_jumps; // list of alternative in the current scope. +#else + std::vector m_alt_jumps; // list of alternative in the current scope. +#endif + + basic_regex_parser& operator=(const basic_regex_parser&); + basic_regex_parser(const basic_regex_parser&); +}; + +template +basic_regex_parser::basic_regex_parser(regex_data* data) + : basic_regex_creator(data), m_parser_proc(), m_base(0), m_end(0), m_position(0), + m_mark_count(0), m_mark_reset(-1), m_max_mark(0), m_paren_start(0), m_alt_insert_point(0), m_has_case_change(false), m_recursion_count(0) +{ +} + +template +void basic_regex_parser::parse(const charT* p1, const charT* p2, unsigned l_flags) +{ + // pass l_flags on to base class: + this->init(l_flags); + // set up pointers: + m_position = m_base = p1; + m_end = p2; + // empty strings are errors: + if((p1 == p2) && + ( + ((l_flags & regbase::main_option_type) != regbase::perl_syntax_group) + || (l_flags & regbase::no_empty_expressions) + ) + ) + { + fail(regex_constants::error_empty, 0); + return; + } + // select which parser to use: + switch(l_flags & regbase::main_option_type) + { + case regbase::perl_syntax_group: + { + m_parser_proc = &basic_regex_parser::parse_extended; + // + // Add a leading paren with index zero to give recursions a target: + // + re_brace* br = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + br->index = 0; + br->icase = this->flags() & regbase::icase; + break; + } + case regbase::basic_syntax_group: + m_parser_proc = &basic_regex_parser::parse_basic; + break; + case regbase::literal: + m_parser_proc = &basic_regex_parser::parse_literal; + break; + default: + // Oops, someone has managed to set more than one of the main option flags, + // so this must be an error: + fail(regex_constants::error_unknown, 0, "An invalid combination of regular expression syntax flags was used."); + return; + } + + // parse all our characters: + bool result = parse_all(); + // + // Unwind our alternatives: + // + unwind_alts(-1); + // reset l_flags as a global scope (?imsx) may have altered them: + this->flags(l_flags); + // if we haven't gobbled up all the characters then we must + // have had an unexpected ')' : + if(!result) + { + fail(regex_constants::error_paren, ::boost::BOOST_REGEX_DETAIL_NS::distance(m_base, m_position), "Found a closing ) with no corresponding opening parenthesis."); + return; + } + // if an error has been set then give up now: + if(this->m_pdata->m_status) + return; + // fill in our sub-expression count: + this->m_pdata->m_mark_count = 1u + (std::size_t)m_mark_count; + this->finalize(p1, p2); +} + +template +void basic_regex_parser::fail(regex_constants::error_type error_code, std::ptrdiff_t position) +{ + // get the error message: + std::string message = this->m_pdata->m_ptraits->error_string(error_code); + fail(error_code, position, message); +} + +template +void basic_regex_parser::fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos) +{ + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = error_code; + m_position = m_end; // don't bother parsing anything else + +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + // + // Augment error message with the regular expression text: + // + if(start_pos == position) + start_pos = (std::max)(static_cast(0), position - static_cast(10)); + std::ptrdiff_t end_pos = (std::min)(position + static_cast(10), static_cast(m_end - m_base)); + if(error_code != regex_constants::error_empty) + { + if((start_pos != 0) || (end_pos != (m_end - m_base))) + message += " The error occurred while parsing the regular expression fragment: '"; + else + message += " The error occurred while parsing the regular expression: '"; + if(start_pos != end_pos) + { + message += std::string(m_base + start_pos, m_base + position); + message += ">>>HERE>>>"; + message += std::string(m_base + position, m_base + end_pos); + } + message += "'."; + } +#endif + +#ifndef BOOST_NO_EXCEPTIONS + if(0 == (this->flags() & regex_constants::no_except)) + { + boost::regex_error e(message, error_code, position); + e.raise(); + } +#else + (void)position; // suppress warnings. +#endif +} + +template +bool basic_regex_parser::parse_all() +{ + if (++m_recursion_count > 400) + { + // exceeded internal limits + fail(boost::regex_constants::error_complexity, m_position - m_base, "Exceeded nested brace limit."); + } + bool result = true; + while(result && (m_position != m_end)) + { + result = (this->*m_parser_proc)(); + } + --m_recursion_count; + return result; +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4702) +#endif +template +bool basic_regex_parser::parse_basic() +{ + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_escape: + return parse_basic_escape(); + case regex_constants::syntax_dot: + return parse_match_any(); + case regex_constants::syntax_caret: + ++m_position; + this->append_state(syntax_element_start_line); + break; + case regex_constants::syntax_dollar: + ++m_position; + this->append_state(syntax_element_end_line); + break; + case regex_constants::syntax_star: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(); + } + case regex_constants::syntax_plus: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line) || !(this->flags() & regbase::emacs_ex)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(1); + } + case regex_constants::syntax_question: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line) || !(this->flags() & regbase::emacs_ex)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(0, 1); + } + case regex_constants::syntax_open_set: + return parse_set(); + case regex_constants::syntax_newline: + if(this->flags() & regbase::newline_alt) + return parse_alt(); + else + return parse_literal(); + default: + return parse_literal(); + } + return true; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC >= 1800 +#pragma warning(disable:26812) +#endif +#endif +template +bool basic_regex_parser::parse_extended() +{ + bool result = true; + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_open_mark: + return parse_open_paren(); + case regex_constants::syntax_close_mark: + return false; + case regex_constants::syntax_escape: + return parse_extended_escape(); + case regex_constants::syntax_dot: + return parse_match_any(); + case regex_constants::syntax_caret: + ++m_position; + this->append_state( + (this->flags() & regex_constants::no_mod_m ? syntax_element_buffer_start : syntax_element_start_line)); + break; + case regex_constants::syntax_dollar: + ++m_position; + this->append_state( + (this->flags() & regex_constants::no_mod_m ? syntax_element_buffer_end : syntax_element_end_line)); + break; + case regex_constants::syntax_star: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"*\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(); + case regex_constants::syntax_question: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"?\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(0,1); + case regex_constants::syntax_plus: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"+\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(1); + case regex_constants::syntax_open_brace: + ++m_position; + return parse_repeat_range(false); + case regex_constants::syntax_close_brace: + if((this->flags() & regbase::no_perl_ex) == regbase::no_perl_ex) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {."); + return false; + } + result = parse_literal(); + break; + case regex_constants::syntax_or: + return parse_alt(); + case regex_constants::syntax_open_set: + return parse_set(); + case regex_constants::syntax_newline: + if(this->flags() & regbase::newline_alt) + return parse_alt(); + else + return parse_literal(); + case regex_constants::syntax_hash: + // + // If we have a mod_x flag set, then skip until + // we get to a newline character: + // + if((this->flags() + & (regbase::no_perl_ex|regbase::mod_x)) + == regbase::mod_x) + { + while((m_position != m_end) && !is_separator(*m_position++)){} + return true; + } + BOOST_FALLTHROUGH; + default: + result = parse_literal(); + break; + } + return result; +} +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +bool basic_regex_parser::parse_literal() +{ + // append this as a literal provided it's not a space character + // or the perl option regbase::mod_x is not set: + if( + ((this->flags() + & (regbase::main_option_type|regbase::mod_x|regbase::no_perl_ex)) + != regbase::mod_x) + || !this->m_traits.isctype(*m_position, this->m_mask_space)) + this->append_literal(*m_position); + ++m_position; + return true; +} + +template +bool basic_regex_parser::parse_open_paren() +{ + // + // skip the '(' and error check: + // + if(++m_position == m_end) + { + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + // + // begin by checking for a perl-style (?...) extension: + // + if( + ((this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) == 0) + || ((this->flags() & (regbase::main_option_type | regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex)) + ) + { + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_question) + return parse_perl_extension(); + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_star) + return parse_perl_verb(); + } + // + // update our mark count, and append the required state: + // + unsigned markid = 0; + if(0 == (this->flags() & regbase::nosubs)) + { + markid = ++m_mark_count; +#ifndef BOOST_NO_STD_DISTANCE + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair(std::distance(m_base, m_position) - 1, 0)); +#else + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair((m_position - m_base) - 1, 0)); +#endif + } + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + std::ptrdiff_t last_paren_start = this->getoffset(pb); + // back up insertion point for alternations, and set new point: + std::ptrdiff_t last_alt_point = m_alt_insert_point; + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + // + // back up the current flags in case we have a nested (?imsx) group: + // + regex_constants::syntax_option_type opts = this->flags(); + bool old_case_change = m_has_case_change; + m_has_case_change = false; // no changes to this scope as yet... + // + // Back up branch reset data in case we have a nested (?|...) + // + int mark_reset = m_mark_reset; + m_mark_reset = -1; + // + // now recursively add more states, this will terminate when we get to a + // matching ')' : + // + parse_all(); + // + // Unwind pushed alternatives: + // + if(0 == unwind_alts(last_paren_start)) + return false; + // + // restore flags: + // + if(m_has_case_change) + { + // the case has changed in one or more of the alternatives + // within the scoped (...) block: we have to add a state + // to reset the case sensitivity: + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = opts & regbase::icase; + } + this->flags(opts); + m_has_case_change = old_case_change; + // + // restore branch reset: + // + m_mark_reset = mark_reset; + // + // we either have a ')' or we have run out of characters prematurely: + // + if(m_position == m_end) + { + this->fail(regex_constants::error_paren, ::boost::BOOST_REGEX_DETAIL_NS::distance(m_base, m_end)); + return false; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + return false; +#ifndef BOOST_NO_STD_DISTANCE + if(markid && (this->flags() & regbase::save_subexpression_location)) + this->m_pdata->m_subs.at(markid - 1).second = std::distance(m_base, m_position); +#else + if(markid && (this->flags() & regbase::save_subexpression_location)) + this->m_pdata->m_subs.at(markid - 1).second = (m_position - m_base); +#endif + ++m_position; + // + // append closing parenthesis state: + // + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + this->m_paren_start = last_paren_start; + // + // restore the alternate insertion point: + // + this->m_alt_insert_point = last_alt_point; + // + // allow backrefs to this mark: + // + if(markid > 0) + this->m_backrefs.set(markid); + + return true; +} + +template +bool basic_regex_parser::parse_basic_escape() +{ + if(++m_position == m_end) + { + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + bool result = true; + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::syntax_open_mark: + return parse_open_paren(); + case regex_constants::syntax_close_mark: + return false; + case regex_constants::syntax_plus: + if(this->flags() & regex_constants::bk_plus_qm) + { + ++m_position; + return parse_repeat(1); + } + else + return parse_literal(); + case regex_constants::syntax_question: + if(this->flags() & regex_constants::bk_plus_qm) + { + ++m_position; + return parse_repeat(0, 1); + } + else + return parse_literal(); + case regex_constants::syntax_open_brace: + if(this->flags() & regbase::no_intervals) + return parse_literal(); + ++m_position; + return parse_repeat_range(true); + case regex_constants::syntax_close_brace: + if(this->flags() & regbase::no_intervals) + return parse_literal(); + fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {."); + return false; + case regex_constants::syntax_or: + if(this->flags() & regbase::bk_vbar) + return parse_alt(); + else + result = parse_literal(); + break; + case regex_constants::syntax_digit: + return parse_backref(); + case regex_constants::escape_type_start_buffer: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_buffer_start); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_end_buffer: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_buffer_end); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_word_assert: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_boundary); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_not_word_assert: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_within_word); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_left_word: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_start); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_right_word: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_end); + } + else + result = parse_literal(); + break; + default: + if(this->flags() & regbase::emacs_ex) + { + bool negate = true; + switch(*m_position) + { + case 'w': + negate = false; + BOOST_FALLTHROUGH; + case 'W': + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(this->m_word_mask); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; + } + case 's': + negate = false; + BOOST_FALLTHROUGH; + case 'S': + return add_emacs_code(negate); + case 'c': + case 'C': + // not supported yet: + fail(regex_constants::error_escape, m_position - m_base, "The \\c and \\C escape sequences are not supported by POSIX basic regular expressions: try the Perl syntax instead."); + return false; + default: + break; + } + } + result = parse_literal(); + break; + } + return result; +} + +template +bool basic_regex_parser::parse_extended_escape() +{ + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Incomplete escape sequence found."); + return false; + } + bool negate = false; // in case this is a character class escape: \w \d etc + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::escape_type_not_class: + negate = true; + BOOST_FALLTHROUGH; + case regex_constants::escape_type_class: + { +escape_type_class_jump: + typedef typename traits::char_class_type m_type; + m_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(m); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; + } + // + // not a class, just a regular unknown escape: + // + this->append_literal(unescape_character()); + break; + } + case regex_constants::syntax_digit: + return parse_backref(); + case regex_constants::escape_type_left_word: + ++m_position; + this->append_state(syntax_element_word_start); + break; + case regex_constants::escape_type_right_word: + ++m_position; + this->append_state(syntax_element_word_end); + break; + case regex_constants::escape_type_start_buffer: + ++m_position; + this->append_state(syntax_element_buffer_start); + break; + case regex_constants::escape_type_end_buffer: + ++m_position; + this->append_state(syntax_element_buffer_end); + break; + case regex_constants::escape_type_word_assert: + ++m_position; + this->append_state(syntax_element_word_boundary); + break; + case regex_constants::escape_type_not_word_assert: + ++m_position; + this->append_state(syntax_element_within_word); + break; + case regex_constants::escape_type_Z: + ++m_position; + this->append_state(syntax_element_soft_buffer_end); + break; + case regex_constants::escape_type_Q: + return parse_QE(); + case regex_constants::escape_type_C: + return parse_match_any(); + case regex_constants::escape_type_X: + ++m_position; + this->append_state(syntax_element_combining); + break; + case regex_constants::escape_type_G: + ++m_position; + this->append_state(syntax_element_restart_continue); + break; + case regex_constants::escape_type_not_property: + negate = true; + BOOST_FALLTHROUGH; + case regex_constants::escape_type_property: + { + ++m_position; + char_class_type m; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Incomplete property escape found."); + return false; + } + // maybe have \p{ddd} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + const charT* base = m_position; + // skip forward until we find enclosing brace: + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Closing } missing from property escape sequence."); + return false; + } + m = this->m_traits.lookup_classname(++base, m_position++); + } + else + { + m = this->m_traits.lookup_classname(m_position, m_position+1); + ++m_position; + } + if(m != 0) + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(m); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + return true; + } + fail(regex_constants::error_ctype, m_position - m_base, "Escape sequence was neither a valid property nor a valid character class name."); + return false; + } + case regex_constants::escape_type_reset_start_mark: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->index = -5; + pb->icase = this->flags() & regbase::icase; + this->m_pdata->m_data.align(); + ++m_position; + return true; + } + goto escape_type_class_jump; + case regex_constants::escape_type_line_ending: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + const charT* e = get_escape_R_string(); + const charT* old_position = m_position; + const charT* old_end = m_end; + const charT* old_base = m_base; + m_position = e; + m_base = e; + m_end = e + traits::length(e); + bool r = parse_all(); + m_position = ++old_position; + m_end = old_end; + m_base = old_base; + return r; + } + goto escape_type_class_jump; + case regex_constants::escape_type_extended_backref: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + bool have_brace = false; + bool negative = false; + static const char incomplete_message[] = "Incomplete \\g escape found."; + if(++m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + // maybe have \g{ddd} + regex_constants::syntax_type syn = this->m_traits.syntax_type(*m_position); + regex_constants::syntax_type syn_end = 0; + if((syn == regex_constants::syntax_open_brace) + || (syn == regex_constants::escape_type_left_word) + || (syn == regex_constants::escape_type_end_buffer)) + { + if(++m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + have_brace = true; + switch(syn) + { + case regex_constants::syntax_open_brace: + syn_end = regex_constants::syntax_close_brace; + break; + case regex_constants::escape_type_left_word: + syn_end = regex_constants::escape_type_right_word; + break; + default: + syn_end = regex_constants::escape_type_end_buffer; + break; + } + } + negative = (*m_position == static_cast('-')); + if((negative) && (++m_position == m_end)) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + const charT* pc = m_position; + boost::intmax_t i = this->m_traits.toi(pc, m_end, 10); + if((i < 0) && syn_end) + { + // Check for a named capture, get the leftmost one if there is more than one: + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != syn_end)) + { + ++m_position; + } + i = hash_value_from_capture_name(base, m_position); + pc = m_position; + } + if(negative) + i = 1 + (static_cast(m_mark_count) - i); + if(((i < hash_value_mask) && (i > 0) && (this->m_backrefs.test(i))) || ((i >= hash_value_mask) && (this->m_pdata->get_id(i) > 0) && (this->m_backrefs.test(this->m_pdata->get_id(i))))) + { + m_position = pc; + re_brace* pb = static_cast(this->append_state(syntax_element_backref, sizeof(re_brace))); + pb->index = i; + pb->icase = this->flags() & regbase::icase; + } + else + { + fail(regex_constants::error_backref, m_position - m_base); + return false; + } + m_position = pc; + if(have_brace) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != syn_end)) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + ++m_position; + } + return true; + } + goto escape_type_class_jump; + case regex_constants::escape_type_control_v: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + goto escape_type_class_jump; + BOOST_FALLTHROUGH; + default: + this->append_literal(unescape_character()); + break; + } + return true; +} + +template +bool basic_regex_parser::parse_match_any() +{ + // + // we have a '.' that can match any character: + // + ++m_position; + static_cast( + this->append_state(syntax_element_wild, sizeof(re_dot)) + )->mask = static_cast(this->flags() & regbase::no_mod_s + ? BOOST_REGEX_DETAIL_NS::force_not_newline + : this->flags() & regbase::mod_s ? + BOOST_REGEX_DETAIL_NS::force_newline : BOOST_REGEX_DETAIL_NS::dont_care); + return true; +} + +template +bool basic_regex_parser::parse_repeat(std::size_t low, std::size_t high) +{ + bool greedy = true; + bool possessive = false; + std::size_t insert_point; + // + // when we get to here we may have a non-greedy ? mark still to come: + // + if((m_position != m_end) + && ( + (0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + || ((regbase::basic_syntax_group|regbase::emacs_ex) == (this->flags() & (regbase::main_option_type | regbase::emacs_ex))) + ) + ) + { + // OK we have a perl or emacs regex, check for a '?': + if ((this->flags() & (regbase::main_option_type | regbase::mod_x | regbase::no_perl_ex)) == regbase::mod_x) + { + // whitespace skip: + while ((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + } + if((m_position != m_end) && (this->m_traits.syntax_type(*m_position) == regex_constants::syntax_question)) + { + greedy = false; + ++m_position; + } + // for perl regexes only check for possessive ++ repeats. + if((m_position != m_end) + && (0 == (this->flags() & regbase::main_option_type)) + && (this->m_traits.syntax_type(*m_position) == regex_constants::syntax_plus)) + { + possessive = true; + ++m_position; + } + } + if(0 == this->m_last_state) + { + fail(regex_constants::error_badrepeat, ::boost::BOOST_REGEX_DETAIL_NS::distance(m_base, m_position), "Nothing to repeat."); + return false; + } + if(this->m_last_state->type == syntax_element_endmark) + { + // insert a repeat before the '(' matching the last ')': + insert_point = this->m_paren_start; + } + else if((this->m_last_state->type == syntax_element_literal) && (static_cast(this->m_last_state)->length > 1)) + { + // the last state was a literal with more than one character, split it in two: + re_literal* lit = static_cast(this->m_last_state); + charT c = (static_cast(static_cast(lit+1)))[lit->length - 1]; + lit->length -= 1; + // now append new state: + lit = static_cast(this->append_state(syntax_element_literal, sizeof(re_literal) + sizeof(charT))); + lit->length = 1; + (static_cast(static_cast(lit+1)))[0] = c; + insert_point = this->getoffset(this->m_last_state); + } + else + { + // repeat the last state whatever it was, need to add some error checking here: + switch(this->m_last_state->type) + { + case syntax_element_start_line: + case syntax_element_end_line: + case syntax_element_word_boundary: + case syntax_element_within_word: + case syntax_element_word_start: + case syntax_element_word_end: + case syntax_element_buffer_start: + case syntax_element_buffer_end: + case syntax_element_alt: + case syntax_element_soft_buffer_end: + case syntax_element_restart_continue: + case syntax_element_jump: + case syntax_element_startmark: + case syntax_element_backstep: + case syntax_element_toggle_case: + // can't legally repeat any of the above: + fail(regex_constants::error_badrepeat, m_position - m_base); + return false; + default: + // do nothing... + break; + } + insert_point = this->getoffset(this->m_last_state); + } + // + // OK we now know what to repeat, so insert the repeat around it: + // + re_repeat* rep = static_cast(this->insert_state(insert_point, syntax_element_rep, re_repeater_size)); + rep->min = low; + rep->max = high; + rep->greedy = greedy; + rep->leading = false; + // store our repeater position for later: + std::ptrdiff_t rep_off = this->getoffset(rep); + // and append a back jump to the repeat: + re_jump* jmp = static_cast(this->append_state(syntax_element_jump, sizeof(re_jump))); + jmp->alt.i = rep_off - this->getoffset(jmp); + this->m_pdata->m_data.align(); + // now fill in the alt jump for the repeat: + rep = static_cast(this->getaddress(rep_off)); + rep->alt.i = this->m_pdata->m_data.size() - rep_off; + // + // If the repeat is possessive then bracket the repeat with a (?>...) + // independent sub-expression construct: + // + if(possessive) + { + if(m_position != m_end) + { + // + // Check for illegal following quantifier, we have to do this here, because + // the extra states we insert below circumvents our usual error checking :-( + // + bool contin = false; + do + { + if ((this->flags() & (regbase::main_option_type | regbase::mod_x | regbase::no_perl_ex)) == regbase::mod_x) + { + // whitespace skip: + while ((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + } + if (m_position != m_end) + { + switch (this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_star: + case regex_constants::syntax_plus: + case regex_constants::syntax_question: + case regex_constants::syntax_open_brace: + fail(regex_constants::error_badrepeat, m_position - m_base); + return false; + case regex_constants::syntax_open_mark: + // Do we have a comment? If so we need to skip it here... + if ((m_position + 2 < m_end) && this->m_traits.syntax_type(*(m_position + 1)) == regex_constants::syntax_question + && this->m_traits.syntax_type(*(m_position + 2)) == regex_constants::syntax_hash) + { + while ((m_position != m_end) + && (this->m_traits.syntax_type(*m_position++) != regex_constants::syntax_close_mark)) { + } + contin = true; + } + else + contin = false; + break; + default: + contin = false; + } + } + else + contin = false; + } while (contin); + } + re_brace* pb = static_cast(this->insert_state(insert_point, syntax_element_startmark, sizeof(re_brace))); + pb->index = -3; + pb->icase = this->flags() & regbase::icase; + jmp = static_cast(this->insert_state(insert_point + sizeof(re_brace), syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + jmp->alt.i = this->m_pdata->m_data.size() - this->getoffset(jmp); + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = -3; + pb->icase = this->flags() & regbase::icase; + } + return true; +} + +template +bool basic_regex_parser::parse_repeat_range(bool isbasic) +{ + static const char incomplete_message[] = "Missing } in quantified repetition."; + // + // parse a repeat-range: + // + std::size_t min, max; + boost::intmax_t v; + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // get min: + v = this->m_traits.toi(m_position, m_end, 10); + // skip whitespace: + if((v < 0) || (v > umax())) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + min = static_cast(v); + // see if we have a comma: + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_comma) + { + // move on and error check: + ++m_position; + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // get the value if any: + v = this->m_traits.toi(m_position, m_end, 10); + max = ((v >= 0) && (v < umax())) ? (std::size_t)v : (std::numeric_limits::max)(); + } + else + { + // no comma, max = min: + max = min; + } + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + // OK now check trailing }: + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + if(isbasic) + { + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_escape) + { + ++m_position; + if(this->m_position == this->m_end) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + } + else + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_brace) + ++m_position; + else + { + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // + // finally go and add the repeat, unless error: + // + if(min > max) + { + // Backtrack to error location: + m_position -= 2; + while(this->m_traits.isctype(*m_position, this->m_word_mask)) --m_position; + ++m_position; + fail(regex_constants::error_badbrace, m_position - m_base); + return false; + } + return parse_repeat(min, max); +} + +template +bool basic_regex_parser::parse_alt() +{ + // + // error check: if there have been no previous states, + // or if the last state was a '(' then error: + // + if( + ((this->m_last_state == 0) || (this->m_last_state->type == syntax_element_startmark)) + && + !( + ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) + && + ((this->flags() & regbase::no_empty_expressions) == 0) + ) + ) + { + fail(regex_constants::error_empty, this->m_position - this->m_base, "A regular expression cannot start with the alternation operator |."); + return false; + } + // + // Reset mark count if required: + // + if(m_max_mark < m_mark_count) + m_max_mark = m_mark_count; + if(m_mark_reset >= 0) + m_mark_count = m_mark_reset; + + ++m_position; + // + // we need to append a trailing jump: + // + re_syntax_base* pj = this->append_state(BOOST_REGEX_DETAIL_NS::syntax_element_jump, sizeof(re_jump)); + std::ptrdiff_t jump_offset = this->getoffset(pj); + // + // now insert the alternative: + // + re_alt* palt = static_cast(this->insert_state(this->m_alt_insert_point, syntax_element_alt, re_alt_size)); + jump_offset += re_alt_size; + this->m_pdata->m_data.align(); + palt->alt.i = this->m_pdata->m_data.size() - this->getoffset(palt); + // + // update m_alt_insert_point so that the next alternate gets + // inserted at the start of the second of the two we've just created: + // + this->m_alt_insert_point = this->m_pdata->m_data.size(); + // + // the start of this alternative must have a case changes state + // if the current block has messed around with case changes: + // + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = this->m_icase; + } + // + // push the alternative onto our stack, a recursive + // implementation here is easier to understand (and faster + // as it happens), but causes all kinds of stack overflow problems + // on programs with small stacks (COM+). + // + m_alt_jumps.push_back(jump_offset); + return true; +} + +template +bool basic_regex_parser::parse_set() +{ + static const char incomplete_message[] = "Character set declaration starting with [ terminated prematurely - either no ] was found or the set had no content."; + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + basic_char_set char_set; + + const charT* base = m_position; // where the '[' was + const charT* item_base = m_position; // where the '[' or '^' was + + while(m_position != m_end) + { + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_caret: + if(m_position == base) + { + char_set.negate(); + ++m_position; + item_base = m_position; + } + else + parse_set_literal(char_set); + break; + case regex_constants::syntax_close_set: + if(m_position == item_base) + { + parse_set_literal(char_set); + break; + } + else + { + ++m_position; + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + } + return true; + case regex_constants::syntax_open_set: + if(parse_inner_set(char_set)) + break; + return true; + case regex_constants::syntax_escape: + { + // + // look ahead and see if this is a character class shortcut + // \d \w \s etc... + // + ++m_position; + if(this->m_traits.escape_syntax_type(*m_position) + == regex_constants::escape_type_class) + { + char_class_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + char_set.add_class(m); + ++m_position; + break; + } + } + else if(this->m_traits.escape_syntax_type(*m_position) + == regex_constants::escape_type_not_class) + { + // negated character class: + char_class_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + char_set.add_negated_class(m); + ++m_position; + break; + } + } + // not a character class, just a regular escape: + --m_position; + parse_set_literal(char_set); + break; + } + default: + parse_set_literal(char_set); + break; + } + } + return m_position != m_end; +} + +template +bool basic_regex_parser::parse_inner_set(basic_char_set& char_set) +{ + static const char incomplete_message[] = "Character class declaration starting with [ terminated prematurely - either no ] was found or the set had no content."; + // + // we have either a character class [:name:] + // a collating element [.name.] + // or an equivalence class [=name=] + // + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_dot: + // + // a collating element is treated as a literal: + // + --m_position; + parse_set_literal(char_set); + return true; + case regex_constants::syntax_colon: + { + // check that character classes are actually enabled: + if((this->flags() & (regbase::main_option_type | regbase::no_char_classes)) + == (regbase::basic_syntax_group | regbase::no_char_classes)) + { + --m_position; + parse_set_literal(char_set); + return true; + } + // skip the ':' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching ':]' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_colon)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + // + // check for negated class: + // + bool negated = false; + if(this->m_traits.syntax_type(*name_first) == regex_constants::syntax_caret) + { + ++name_first; + negated = true; + } + typedef typename traits::char_class_type m_type; + m_type m = this->m_traits.lookup_classname(name_first, name_last); + if(m == 0) + { + if(char_set.empty() && (name_last - name_first == 1)) + { + // maybe a special case: + ++m_position; + if( (m_position != m_end) + && (this->m_traits.syntax_type(*m_position) + == regex_constants::syntax_close_set)) + { + if(this->m_traits.escape_syntax_type(*name_first) + == regex_constants::escape_type_left_word) + { + ++m_position; + this->append_state(syntax_element_word_start); + return false; + } + if(this->m_traits.escape_syntax_type(*name_first) + == regex_constants::escape_type_right_word) + { + ++m_position; + this->append_state(syntax_element_word_end); + return false; + } + } + } + fail(regex_constants::error_ctype, name_first - m_base); + return false; + } + if(!negated) + char_set.add_class(m); + else + char_set.add_negated_class(m); + ++m_position; + break; + } + case regex_constants::syntax_equal: + { + // skip the '=' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching '=]' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + string_type m = this->m_traits.lookup_collatename(name_first, name_last); + if(m.empty() || (m.size() > 2)) + { + fail(regex_constants::error_collate, name_first - m_base); + return false; + } + digraph d; + d.first = m[0]; + if(m.size() > 1) + d.second = m[1]; + else + d.second = 0; + char_set.add_equivalent(d); + ++m_position; + break; + } + default: + --m_position; + parse_set_literal(char_set); + break; + } + return true; +} + +template +void basic_regex_parser::parse_set_literal(basic_char_set& char_set) +{ + digraph start_range(get_next_set_literal(char_set)); + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_dash) + { + // we have a range: + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set) + { + digraph end_range = get_next_set_literal(char_set); + char_set.add_range(start_range, end_range); + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_dash) + { + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_set) + { + // trailing - : + --m_position; + return; + } + fail(regex_constants::error_range, m_position - m_base); + return; + } + return; + } + --m_position; + } + char_set.add_single(start_range); +} + +template +digraph basic_regex_parser::get_next_set_literal(basic_char_set& char_set) +{ + digraph result; + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_dash: + if(!char_set.empty()) + { + // see if we are at the end of the set: + if((++m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_range, m_position - m_base); + return result; + } + --m_position; + } + result.first = *m_position++; + return result; + case regex_constants::syntax_escape: + // check to see if escapes are supported first: + if(this->flags() & regex_constants::no_escape_in_lists) + { + result = *m_position++; + break; + } + ++m_position; + result = unescape_character(); + break; + case regex_constants::syntax_open_set: + { + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, m_position - m_base); + return result; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_dot) + { + --m_position; + result.first = *m_position; + ++m_position; + return result; + } + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, m_position - m_base); + return result; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching ':]' + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_dot)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + ++m_position; + string_type s = this->m_traits.lookup_collatename(name_first, name_last); + if(s.empty() || (s.size() > 2)) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + result.first = s[0]; + if(s.size() > 1) + result.second = s[1]; + else + result.second = 0; + return result; + } + default: + result = *m_position++; + } + return result; +} + +// +// does a value fit in the specified charT type? +// +template +bool valid_value(charT, boost::intmax_t v, const mpl::true_&) +{ + return (v >> (sizeof(charT) * CHAR_BIT)) == 0; +} +template +bool valid_value(charT, boost::intmax_t, const mpl::false_&) +{ + return true; // v will alsways fit in a charT +} +template +bool valid_value(charT c, boost::intmax_t v) +{ + return valid_value(c, v, mpl::bool_<(sizeof(charT) < sizeof(boost::intmax_t))>()); +} + +template +charT basic_regex_parser::unescape_character() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + charT result(0); + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Escape sequence terminated prematurely."); + return false; + } + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::escape_type_control_a: + result = charT('\a'); + break; + case regex_constants::escape_type_e: + result = charT(27); + break; + case regex_constants::escape_type_control_f: + result = charT('\f'); + break; + case regex_constants::escape_type_control_n: + result = charT('\n'); + break; + case regex_constants::escape_type_control_r: + result = charT('\r'); + break; + case regex_constants::escape_type_control_t: + result = charT('\t'); + break; + case regex_constants::escape_type_control_v: + result = charT('\v'); + break; + case regex_constants::escape_type_word_assert: + result = charT('\b'); + break; + case regex_constants::escape_type_ascii_control: + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "ASCII escape sequence terminated prematurely."); + return result; + } + result = static_cast(*m_position % 32); + break; + case regex_constants::escape_type_hex: + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Hexadecimal escape sequence terminated prematurely."); + return result; + } + // maybe have \x{ddd} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Missing } in hexadecimal escape sequence."); + return result; + } + boost::intmax_t i = this->m_traits.toi(m_position, m_end, 16); + if((m_position == m_end) + || (i < 0) + || ((std::numeric_limits::is_specialized) && (i > (boost::intmax_t)(std::numeric_limits::max)())) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_badbrace, m_position - m_base, "Hexadecimal escape sequence was invalid."); + return result; + } + ++m_position; + result = charT(i); + } + else + { + std::ptrdiff_t len = (std::min)(static_cast(2), static_cast(m_end - m_position)); + boost::intmax_t i = this->m_traits.toi(m_position, m_position + len, 16); + if((i < 0) + || !valid_value(charT(0), i)) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Escape sequence did not encode a valid character."); + return result; + } + result = charT(i); + } + return result; + case regex_constants::syntax_digit: + { + // an octal escape sequence, the first character must be a zero + // followed by up to 3 octal digits: + std::ptrdiff_t len = (std::min)(::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end), static_cast(4)); + const charT* bp = m_position; + boost::intmax_t val = this->m_traits.toi(bp, bp + 1, 8); + if(val != 0) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + // Oops not an octal escape after all: + fail(regex_constants::error_escape, m_position - m_base, "Invalid octal escape sequence."); + return result; + } + val = this->m_traits.toi(m_position, m_position + len, 8); + if((val < 0) || (val > (boost::intmax_t)(std::numeric_limits::max)())) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Octal escape sequence is invalid."); + return result; + } + return static_cast(val); + } + case regex_constants::escape_type_named_char: + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + // maybe have \N{name} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + const charT* base = m_position; + // skip forward until we find enclosing brace: + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + string_type s = this->m_traits.lookup_collatename(++base, m_position++); + if(s.empty()) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_collate, m_position - m_base); + return false; + } + if(s.size() == 1) + { + return s[0]; + } + } + // fall through is a failure: + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + default: + result = *m_position; + break; + } + ++m_position; + return result; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool basic_regex_parser::parse_backref() +{ + BOOST_REGEX_ASSERT(m_position != m_end); + const charT* pc = m_position; + boost::intmax_t i = this->m_traits.toi(pc, pc + 1, 10); + if((i == 0) || (((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) && (this->flags() & regbase::no_bk_refs))) + { + // not a backref at all but an octal escape sequence: + charT c = unescape_character(); + this->append_literal(c); + } + else if((i > 0) && (this->m_backrefs.test(i))) + { + m_position = pc; + re_brace* pb = static_cast(this->append_state(syntax_element_backref, sizeof(re_brace))); + pb->index = i; + pb->icase = this->flags() & regbase::icase; + } + else + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_backref, m_position - m_base); + return false; + } + return true; +} + +template +bool basic_regex_parser::parse_QE() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + // + // parse a \Q...\E sequence: + // + ++m_position; // skip the Q + const charT* start = m_position; + const charT* end; + do + { + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape)) + ++m_position; + if(m_position == m_end) + { + // a \Q...\E sequence may terminate with the end of the expression: + end = m_position; + break; + } + if(++m_position == m_end) // skip the escape + { + fail(regex_constants::error_escape, m_position - m_base, "Unterminated \\Q...\\E sequence."); + return false; + } + // check to see if it's a \E: + if(this->m_traits.escape_syntax_type(*m_position) == regex_constants::escape_type_E) + { + ++m_position; + end = m_position - 2; + break; + } + // otherwise go round again: + }while(true); + // + // now add all the character between the two escapes as literals: + // + while(start != end) + { + this->append_literal(*start); + ++start; + } + return true; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool basic_regex_parser::parse_perl_extension() +{ + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + // + // treat comments as a special case, as these + // are the only ones that don't start with a leading + // startmark state: + // + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_hash) + { + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position++) != regex_constants::syntax_close_mark)) + {} + return true; + } + // + // backup some state, and prepare the way: + // + int markid = 0; + std::ptrdiff_t jump_offset = 0; + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->icase = this->flags() & regbase::icase; + std::ptrdiff_t last_paren_start = this->getoffset(pb); + // back up insertion point for alternations, and set new point: + std::ptrdiff_t last_alt_point = m_alt_insert_point; + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + std::ptrdiff_t expected_alt_point = m_alt_insert_point; + bool restore_flags = true; + regex_constants::syntax_option_type old_flags = this->flags(); + bool old_case_change = m_has_case_change; + m_has_case_change = false; + charT name_delim; + int mark_reset = m_mark_reset; + int max_mark = m_max_mark; + m_mark_reset = -1; + m_max_mark = m_mark_count; + boost::intmax_t v; + // + // select the actual extension used: + // + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_or: + m_mark_reset = m_mark_count; + BOOST_FALLTHROUGH; + case regex_constants::syntax_colon: + // + // a non-capturing mark: + // + pb->index = markid = 0; + ++m_position; + break; + case regex_constants::syntax_digit: + { + // + // a recursive subexpression: + // + v = this->m_traits.toi(m_position, m_end, 10); + if((v < 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "The recursive sub-expression refers to an invalid marking group, or is unterminated."); + return false; + } +insert_recursion: + pb->index = markid = 0; + re_recurse* pr = static_cast(this->append_state(syntax_element_recurse, sizeof(re_recurse))); + pr->alt.i = v; + pr->state_id = 0; + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = this->flags() & regbase::icase; + break; + } + case regex_constants::syntax_plus: + // + // A forward-relative recursive subexpression: + // + ++m_position; + v = this->m_traits.toi(m_position, m_end, 10); + if((v <= 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + if ((std::numeric_limits::max)() - m_mark_count < v) + { + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + v += m_mark_count; + goto insert_recursion; + case regex_constants::syntax_dash: + // + // Possibly a backward-relative recursive subexpression: + // + ++m_position; + v = this->m_traits.toi(m_position, m_end, 10); + if(v <= 0) + { + --m_position; + // Oops not a relative recursion at all, but a (?-imsx) group: + goto option_group_jump; + } + v = static_cast(m_mark_count) + 1 - v; + if(v <= 0) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + goto insert_recursion; + case regex_constants::syntax_equal: + pb->index = markid = -1; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::syntax_not: + pb->index = markid = -2; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::escape_type_left_word: + { + // a lookbehind assertion: + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + regex_constants::syntax_type t = this->m_traits.syntax_type(*m_position); + if(t == regex_constants::syntax_not) + pb->index = markid = -2; + else if(t == regex_constants::syntax_equal) + pb->index = markid = -1; + else + { + // Probably a named capture which also starts (?< : + name_delim = '>'; + --m_position; + goto named_capture_jump; + } + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->append_state(syntax_element_backstep, sizeof(re_brace)); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + } + case regex_constants::escape_type_right_word: + // + // an independent sub-expression: + // + pb->index = markid = -3; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::syntax_open_mark: + { + // a conditional expression: + pb->index = markid = -4; + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = this->m_traits.toi(m_position, m_end, 10); + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('R')) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('&')) + { + const charT* base = ++m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = -static_cast(hash_value_from_capture_name(base, m_position)); + } + else + { + v = -this->m_traits.toi(m_position, m_end, 10); + } + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = v < 0 ? (v - 1) : 0; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if((*m_position == charT('\'')) || (*m_position == charT('<'))) + { + const charT* base = ++m_position; + while((m_position != m_end) && (*m_position != charT('>')) && (*m_position != charT('\''))) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = v; + if(((*m_position != charT('>')) && (*m_position != charT('\''))) || (++m_position == m_end)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Unterminated named capture."); + return false; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if(*m_position == charT('D')) + { + const char* def = "DEFINE"; + while(*def && (m_position != m_end) && (*m_position == charT(*def))) + ++m_position, ++def; + if((m_position == m_end) || *def) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = 9999; // special magic value! + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if(v > 0) + { + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = v; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else + { + // verify that we have a lookahead or lookbehind assert: + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_question) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::escape_type_left_word) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + m_position -= 3; + } + else + { + if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + m_position -= 2; + } + } + break; + } + case regex_constants::syntax_close_mark: + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + case regex_constants::escape_type_end_buffer: + { + name_delim = *m_position; +named_capture_jump: + markid = 0; + if(0 == (this->flags() & regbase::nosubs)) + { + markid = ++m_mark_count; + #ifndef BOOST_NO_STD_DISTANCE + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair(std::distance(m_base, m_position) - 2, 0)); + #else + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair((m_position - m_base) - 2, 0)); + #endif + } + pb->index = markid; + const charT* base = ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + while((m_position != m_end) && (*m_position != name_delim)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + this->m_pdata->set_name(base, m_position, markid); + ++m_position; + break; + } + default: + if(*m_position == charT('R')) + { + ++m_position; + v = 0; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + goto insert_recursion; + } + if(*m_position == charT('&')) + { + ++m_position; + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + goto insert_recursion; + } + if(*m_position == charT('P')) + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('>')) + { + ++m_position; + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + goto insert_recursion; + } + } + // + // lets assume that we have a (?imsx) group and try and parse it: + // +option_group_jump: + regex_constants::syntax_option_type opts = parse_options(); + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + // make a note of whether we have a case change: + m_has_case_change = ((opts & regbase::icase) != (this->flags() & regbase::icase)); + pb->index = markid = 0; + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark) + { + // update flags and carry on as normal: + this->flags(opts); + restore_flags = false; + old_case_change |= m_has_case_change; // defer end of scope by one ')' + } + else if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_colon) + { + // update flags and carry on until the matching ')' is found: + this->flags(opts); + ++m_position; + } + else + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + + // finally append a case change state if we need it: + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = opts & regbase::icase; + } + + } + // + // now recursively add more states, this will terminate when we get to a + // matching ')' : + // + parse_all(); + // + // Unwind alternatives: + // + if(0 == unwind_alts(last_paren_start)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid alternation operators within (?...) block."); + return false; + } + // + // we either have a ')' or we have run out of characters prematurely: + // + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + this->fail(regex_constants::error_paren, ::boost::BOOST_REGEX_DETAIL_NS::distance(m_base, m_end)); + return false; + } + BOOST_REGEX_ASSERT(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark); + ++m_position; + // + // restore the flags: + // + if(restore_flags) + { + // append a case change state if we need it: + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = old_flags & regbase::icase; + } + this->flags(old_flags); + } + // + // set up the jump pointer if we have one: + // + if(jump_offset) + { + this->m_pdata->m_data.align(); + re_jump* jmp = static_cast(this->getaddress(jump_offset)); + jmp->alt.i = this->m_pdata->m_data.size() - this->getoffset(jmp); + if((this->m_last_state == jmp) && (markid != -2)) + { + // Oops... we didn't have anything inside the assertion. + // Note we don't get here for negated forward lookahead as (?!) + // does have some uses. + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid or empty zero width assertion."); + return false; + } + } + // + // verify that if this is conditional expression, that we do have + // an alternative, if not add one: + // + if(markid == -4) + { + re_syntax_base* b = this->getaddress(expected_alt_point); + // Make sure we have exactly one alternative following this state: + if(b->type != syntax_element_alt) + { + re_alt* alt = static_cast(this->insert_state(expected_alt_point, syntax_element_alt, sizeof(re_alt))); + alt->alt.i = this->m_pdata->m_data.size() - this->getoffset(alt); + } + else if(((std::ptrdiff_t)this->m_pdata->m_data.size() > (static_cast(b)->alt.i + this->getoffset(b))) && (static_cast(b)->alt.i > 0) && this->getaddress(static_cast(b)->alt.i, b)->type == syntax_element_alt) + { + // Can't have seen more than one alternative: + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_bad_pattern, m_position - m_base, "More than one alternation operator | was encountered inside a conditional expression."); + return false; + } + else + { + // We must *not* have seen an alternative inside a (DEFINE) block: + b = this->getaddress(b->next.i, b); + if((b->type == syntax_element_assert_backref) && (static_cast(b)->index == 9999)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_bad_pattern, m_position - m_base, "Alternation operators are not allowed inside a DEFINE block."); + return false; + } + } + // check for invalid repetition of next state: + b = this->getaddress(expected_alt_point); + b = this->getaddress(static_cast(b)->next.i, b); + if((b->type != syntax_element_assert_backref) + && (b->type != syntax_element_startmark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_badrepeat, m_position - m_base, "A repetition operator cannot be applied to a zero-width assertion."); + return false; + } + } + // + // append closing parenthesis state: + // + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + this->m_paren_start = last_paren_start; + // + // restore the alternate insertion point: + // + this->m_alt_insert_point = last_alt_point; + // + // and the case change data: + // + m_has_case_change = old_case_change; + // + // And the mark_reset data: + // + if(m_max_mark > m_mark_count) + { + m_mark_count = m_max_mark; + } + m_mark_reset = mark_reset; + m_max_mark = max_mark; + + + if(markid > 0) + { +#ifndef BOOST_NO_STD_DISTANCE + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.at((std::size_t)markid - 1).second = std::distance(m_base, m_position) - 1; +#else + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.at(markid - 1).second = (m_position - m_base) - 1; +#endif + // + // allow backrefs to this mark: + // + this->m_backrefs.set(markid); + } + return true; +} + +template +bool basic_regex_parser::match_verb(const char* verb) +{ + while(*verb) + { + if(static_cast(*verb) != *m_position) + { + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++verb; + } + return true; +} + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC >= 1800 +#pragma warning(disable:26812) +#endif +#endif +template +bool basic_regex_parser::parse_perl_verb() +{ + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + switch(*m_position) + { + case 'F': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if((this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark) || match_verb("AIL")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_fail); + return true; + } + break; + case 'A': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("CCEPT")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_accept); + return true; + } + break; + case 'C': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("OMMIT")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_commit; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'P': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("RUNE")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_prune; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'S': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("KIP")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_skip; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'T': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("HEN")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_then); + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + } + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; +} +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template +bool basic_regex_parser::add_emacs_code(bool negate) +{ + // + // parses an emacs style \sx or \Sx construct. + // + if(++m_position == m_end) + { + // Rewind to start of sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + basic_char_set char_set; + if(negate) + char_set.negate(); + + static const charT s_punct[5] = { 'p', 'u', 'n', 'c', 't', }; + + switch(*m_position) + { + case 's': + case ' ': + char_set.add_class(this->m_mask_space); + break; + case 'w': + char_set.add_class(this->m_word_mask); + break; + case '_': + char_set.add_single(digraph(charT('$'))); + char_set.add_single(digraph(charT('&'))); + char_set.add_single(digraph(charT('*'))); + char_set.add_single(digraph(charT('+'))); + char_set.add_single(digraph(charT('-'))); + char_set.add_single(digraph(charT('_'))); + char_set.add_single(digraph(charT('<'))); + char_set.add_single(digraph(charT('>'))); + break; + case '.': + char_set.add_class(this->m_traits.lookup_classname(s_punct, s_punct+5)); + break; + case '(': + char_set.add_single(digraph(charT('('))); + char_set.add_single(digraph(charT('['))); + char_set.add_single(digraph(charT('{'))); + break; + case ')': + char_set.add_single(digraph(charT(')'))); + char_set.add_single(digraph(charT(']'))); + char_set.add_single(digraph(charT('}'))); + break; + case '"': + char_set.add_single(digraph(charT('"'))); + char_set.add_single(digraph(charT('\''))); + char_set.add_single(digraph(charT('`'))); + break; + case '\'': + char_set.add_single(digraph(charT('\''))); + char_set.add_single(digraph(charT(','))); + char_set.add_single(digraph(charT('#'))); + break; + case '<': + char_set.add_single(digraph(charT(';'))); + break; + case '>': + char_set.add_single(digraph(charT('\n'))); + char_set.add_single(digraph(charT('\f'))); + break; + default: + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; +} + +template +regex_constants::syntax_option_type basic_regex_parser::parse_options() +{ + // we have a (?imsx-imsx) group, convert it into a set of flags: + regex_constants::syntax_option_type f = this->flags(); + bool breakout = false; + do + { + switch(*m_position) + { + case 's': + f |= regex_constants::mod_s; + f &= ~regex_constants::no_mod_s; + break; + case 'm': + f &= ~regex_constants::no_mod_m; + break; + case 'i': + f |= regex_constants::icase; + break; + case 'x': + f |= regex_constants::mod_x; + break; + default: + breakout = true; + continue; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + } + while(!breakout); + + breakout = false; + + if(*m_position == static_cast('-')) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + do + { + switch(*m_position) + { + case 's': + f &= ~regex_constants::mod_s; + f |= regex_constants::no_mod_s; + break; + case 'm': + f |= regex_constants::no_mod_m; + break; + case 'i': + f &= ~regex_constants::icase; + break; + case 'x': + f &= ~regex_constants::mod_x; + break; + default: + breakout = true; + continue; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + } + while(!breakout); + } + return f; +} + +template +bool basic_regex_parser::unwind_alts(std::ptrdiff_t last_paren_start) +{ + // + // If we didn't actually add any states after the last + // alternative then that's an error: + // + if((this->m_alt_insert_point == static_cast(this->m_pdata->m_data.size())) + && (!m_alt_jumps.empty()) && (m_alt_jumps.back() > last_paren_start) + && + !( + ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) + && + ((this->flags() & regbase::no_empty_expressions) == 0) + ) + ) + { + fail(regex_constants::error_empty, this->m_position - this->m_base, "Can't terminate a sub-expression with an alternation operator |."); + return false; + } + // + // Fix up our alternatives: + // + while((!m_alt_jumps.empty()) && (m_alt_jumps.back() > last_paren_start)) + { + // + // fix up the jump to point to the end of the states + // that we've just added: + // + std::ptrdiff_t jump_offset = m_alt_jumps.back(); + m_alt_jumps.pop_back(); + this->m_pdata->m_data.align(); + re_jump* jmp = static_cast(this->getaddress(jump_offset)); + if (jmp->type != syntax_element_jump) + { + // Something really bad happened, this used to be an assert, + // but we'll make it an error just in case we should ever get here. + fail(regex_constants::error_unknown, this->m_position - this->m_base, "Internal logic failed while compiling the expression, probably you added a repeat to something non-repeatable!"); + return false; + } + jmp->alt.i = this->m_pdata->m_data.size() - jump_offset; + } + return true; +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/c_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/c_regex_traits.hpp new file mode 100644 index 0000000000..f966c4d4b4 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/c_regex_traits.hpp @@ -0,0 +1,511 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE c_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class that wraps the global C locale. + */ + +#ifndef BOOST_C_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_C_REGEX_TRAITS_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif +#ifndef BOOST_REGEX_WORKAROUND_HPP +#include +#endif + +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ + using ::strlen; using ::tolower; +} +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103 4244) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ + + namespace BOOST_REGEX_DETAIL_NS { + + enum + { + char_class_space = 1 << 0, + char_class_print = 1 << 1, + char_class_cntrl = 1 << 2, + char_class_upper = 1 << 3, + char_class_lower = 1 << 4, + char_class_alpha = 1 << 5, + char_class_digit = 1 << 6, + char_class_punct = 1 << 7, + char_class_xdigit = 1 << 8, + char_class_alnum = char_class_alpha | char_class_digit, + char_class_graph = char_class_alnum | char_class_punct, + char_class_blank = 1 << 9, + char_class_word = 1 << 10, + char_class_unicode = 1 << 11, + char_class_horizontal = 1 << 12, + char_class_vertical = 1 << 13 + }; + + } + +template +struct c_regex_traits; + +template<> +struct c_regex_traits +{ + c_regex_traits(){} + typedef char char_type; + typedef std::size_t size_type; + typedef std::string string_type; + struct locale_type{}; + typedef boost::uint32_t char_class_type; + + static size_type length(const char_type* p) + { + return (std::strlen)(p); + } + + char translate(char c) const + { + return c; + } + char translate_nocase(char c) const + { + return static_cast((std::tolower)(static_cast(c))); + } + + static string_type BOOST_REGEX_CALL transform(const char* p1, const char* p2); + static string_type BOOST_REGEX_CALL transform_primary(const char* p1, const char* p2); + + static char_class_type BOOST_REGEX_CALL lookup_classname(const char* p1, const char* p2); + static string_type BOOST_REGEX_CALL lookup_collatename(const char* p1, const char* p2); + + static bool BOOST_REGEX_CALL isctype(char, char_class_type); + static int BOOST_REGEX_CALL value(char, int); + + locale_type imbue(locale_type l) + { return l; } + locale_type getloc()const + { return locale_type(); } + +private: + // this type is not copyable: + c_regex_traits(const c_regex_traits&); + c_regex_traits& operator=(const c_regex_traits&); +}; + +#ifndef BOOST_NO_WREGEX +template<> +struct c_regex_traits +{ + c_regex_traits(){} + typedef wchar_t char_type; + typedef std::size_t size_type; + typedef std::wstring string_type; + struct locale_type{}; + typedef boost::uint32_t char_class_type; + + static size_type length(const char_type* p) + { + return (std::wcslen)(p); + } + + wchar_t translate(wchar_t c) const + { + return c; + } + wchar_t translate_nocase(wchar_t c) const + { + return (std::towlower)(c); + } + + static string_type BOOST_REGEX_CALL transform(const wchar_t* p1, const wchar_t* p2); + static string_type BOOST_REGEX_CALL transform_primary(const wchar_t* p1, const wchar_t* p2); + + static char_class_type BOOST_REGEX_CALL lookup_classname(const wchar_t* p1, const wchar_t* p2); + static string_type BOOST_REGEX_CALL lookup_collatename(const wchar_t* p1, const wchar_t* p2); + + static bool BOOST_REGEX_CALL isctype(wchar_t, char_class_type); + static int BOOST_REGEX_CALL value(wchar_t, int); + + locale_type imbue(locale_type l) + { return l; } + locale_type getloc()const + { return locale_type(); } + +private: + // this type is not copyable: + c_regex_traits(const c_regex_traits&); + c_regex_traits& operator=(const c_regex_traits&); +}; + +#endif // BOOST_NO_WREGEX + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform(const char* p1, const char* p2) +{ + std::string result(10, ' '); + std::size_t s = result.size(); + std::size_t r; + std::string src(p1, p2); + while (s < (r = std::strxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if (r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, ' '); + s = result.size(); + } + result.erase(r); + return result; +} + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform_primary(const char* p1, const char* p2) +{ + static char s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::string result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch (s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for (std::string::size_type i = 0; i < result.size(); ++i) + result[i] = static_cast((std::tolower)(static_cast(result[i]))); + result = transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = transform(p1, p2); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = transform(p1, p2); + if ((!result.empty()) && (result[0] == s_delim)) + break; + std::size_t i; + for (i = 0; i < result.size(); ++i) + { + if (result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if (result.empty()) + result = std::string(1, char(0)); + return result; +} + +inline c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::lookup_classname(const char* p1, const char* p2) +{ + using namespace BOOST_REGEX_DETAIL_NS; + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx < 0) + { + std::string s(p1, p2); + for (std::string::size_type i = 0; i < s.size(); ++i) + s[i] = static_cast((std::tolower)(static_cast(s[i]))); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_REGEX_ASSERT(std::size_t(idx) + 1u < sizeof(masks) / sizeof(masks[0])); + return masks[idx + 1]; +} + +inline bool BOOST_REGEX_CALL c_regex_traits::isctype(char c, char_class_type mask) +{ + using namespace BOOST_REGEX_DETAIL_NS; + return + ((mask & char_class_space) && (std::isspace)(static_cast(c))) + || ((mask & char_class_print) && (std::isprint)(static_cast(c))) + || ((mask & char_class_cntrl) && (std::iscntrl)(static_cast(c))) + || ((mask & char_class_upper) && (std::isupper)(static_cast(c))) + || ((mask & char_class_lower) && (std::islower)(static_cast(c))) + || ((mask & char_class_alpha) && (std::isalpha)(static_cast(c))) + || ((mask & char_class_digit) && (std::isdigit)(static_cast(c))) + || ((mask & char_class_punct) && (std::ispunct)(static_cast(c))) + || ((mask & char_class_xdigit) && (std::isxdigit)(static_cast(c))) + || ((mask & char_class_blank) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + || ((mask & char_class_horizontal) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != '\v')); +} + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::lookup_collatename(const char* p1, const char* p2) +{ + std::string s(p1, p2); + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); + if (s.empty() && (p2 - p1 == 1)) + s.append(1, *p1); + return s; +} + +inline int BOOST_REGEX_CALL c_regex_traits::value(char c, int radix) +{ + char b[2] = { c, '\0', }; + char* ep; + int result = std::strtol(b, &ep, radix); + if (ep == b) + return -1; + return result; +} + +#ifndef BOOST_NO_WREGEX + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform(const wchar_t* p1, const wchar_t* p2) +{ + std::size_t r; + std::size_t s = 10; + std::wstring src(p1, p2); + std::wstring result(s, L' '); + while (s < (r = std::wcsxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if (r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, L' '); + s = result.size(); + } + result.erase(r); + return result; +} + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::transform_primary(const wchar_t* p1, const wchar_t* p2) +{ + static wchar_t s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::wstring result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch (s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for (std::wstring::size_type i = 0; i < result.size(); ++i) + result[i] = (std::towlower)(result[i]); + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + if ((!result.empty()) && (result[0] == s_delim)) + break; + std::size_t i; + for (i = 0; i < result.size(); ++i) + { + if (result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if (result.empty()) + result = std::wstring(1, char(0)); + return result; +} + +inline c_regex_traits::char_class_type BOOST_REGEX_CALL c_regex_traits::lookup_classname(const wchar_t* p1, const wchar_t* p2) +{ + using namespace BOOST_REGEX_DETAIL_NS; + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx < 0) + { + std::wstring s(p1, p2); + for (std::wstring::size_type i = 0; i < s.size(); ++i) + s[i] = (std::towlower)(s[i]); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_REGEX_ASSERT(idx + 1 < static_cast(sizeof(masks) / sizeof(masks[0]))); + return masks[idx + 1]; +} + +inline bool BOOST_REGEX_CALL c_regex_traits::isctype(wchar_t c, char_class_type mask) +{ + using namespace BOOST_REGEX_DETAIL_NS; + return + ((mask & char_class_space) && (std::iswspace)(c)) + || ((mask & char_class_print) && (std::iswprint)(c)) + || ((mask & char_class_cntrl) && (std::iswcntrl)(c)) + || ((mask & char_class_upper) && (std::iswupper)(c)) + || ((mask & char_class_lower) && (std::iswlower)(c)) + || ((mask & char_class_alpha) && (std::iswalpha)(c)) + || ((mask & char_class_digit) && (std::iswdigit)(c)) + || ((mask & char_class_punct) && (std::iswpunct)(c)) + || ((mask & char_class_xdigit) && (std::iswxdigit)(c)) + || ((mask & char_class_blank) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_unicode) && (c & ~static_cast(0xff))) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == L'\v'))) + || ((mask & char_class_horizontal) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != L'\v')); +} + +inline c_regex_traits::string_type BOOST_REGEX_CALL c_regex_traits::lookup_collatename(const wchar_t* p1, const wchar_t* p2) +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4244) +#endif + std::string name(p1, p2); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + name = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(name); + if (!name.empty()) + return string_type(name.begin(), name.end()); + if (p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +inline int BOOST_REGEX_CALL c_regex_traits::value(wchar_t c, int radix) +{ +#ifdef BOOST_BORLANDC + // workaround for broken wcstol: + if ((std::iswxdigit)(c) == 0) + return -1; +#endif + wchar_t b[2] = { c, '\0', }; + wchar_t* ep; + int result = std::wcstol(b, &ep, radix); + if (ep == b) + return -1; + return result; +} + +#endif + +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/char_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/char_regex_traits.hpp new file mode 100644 index 0000000000..e8a501ca00 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/char_regex_traits.hpp @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE char_regex_traits.cpp + * VERSION see + * DESCRIPTION: Declares deprecated traits classes char_regex_traits<>. + */ + + +#ifndef BOOST_REGEX_V4_CHAR_REGEX_TRAITS_HPP +#define BOOST_REGEX_V4_CHAR_REGEX_TRAITS_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ + +namespace deprecated{ +// +// class char_regex_traits_i +// provides case insensitive traits classes (deprecated): +template +class char_regex_traits_i : public regex_traits {}; + +template<> +class char_regex_traits_i : public regex_traits +{ +public: + typedef char char_type; + typedef unsigned char uchar_type; + typedef unsigned int size_type; + typedef regex_traits base_type; + +}; + +#ifndef BOOST_NO_WREGEX +template<> +class char_regex_traits_i : public regex_traits +{ +public: + typedef wchar_t char_type; + typedef unsigned short uchar_type; + typedef unsigned int size_type; + typedef regex_traits base_type; + +}; +#endif +} // namespace deprecated +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // include + diff --git a/third-party/boost_regex/include/boost/regex/v4/cpp_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/cpp_regex_traits.hpp new file mode 100644 index 0000000000..98b251511d --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/cpp_regex_traits.hpp @@ -0,0 +1,1237 @@ +/* + * + * Copyright (c) 2004 John Maddock + * Copyright 2011 Garmin Ltd. or its subsidiaries + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE cpp_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class cpp_regex_traits. + */ + +#ifndef BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED + +#include +#include +#include + +#ifndef BOOST_NO_STD_LOCALE + +#ifndef BOOST_RE_PAT_EXCEPT_HPP +#include +#endif +#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED +#include +#endif +#ifdef BOOST_HAS_THREADS +#include +#endif +#ifndef BOOST_REGEX_PRIMARY_TRANSFORM +#include +#endif +#ifndef BOOST_REGEX_OBJECT_CACHE_HPP +#include +#endif + +#include +#include +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4786 4251) +#endif + +namespace boost{ + +// +// forward declaration is needed by some compilers: +// +template +class cpp_regex_traits; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// class parser_buf: +// acts as a stream buffer which wraps around a pair of pointers: +// +template > +class parser_buf : public ::std::basic_streambuf +{ + typedef ::std::basic_streambuf base_type; + typedef typename base_type::int_type int_type; + typedef typename base_type::char_type char_type; + typedef typename base_type::pos_type pos_type; + typedef ::std::streamsize streamsize; + typedef typename base_type::off_type off_type; +public: + parser_buf() : base_type() { setbuf(0, 0); } + const charT* getnext() { return this->gptr(); } +protected: + std::basic_streambuf* setbuf(char_type* s, streamsize n) BOOST_OVERRIDE; + typename parser_buf::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which) BOOST_OVERRIDE; + typename parser_buf::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) BOOST_OVERRIDE; +private: + parser_buf& operator=(const parser_buf&); + parser_buf(const parser_buf&); +}; + +template +std::basic_streambuf* +parser_buf::setbuf(char_type* s, streamsize n) +{ + this->setg(s, s, s + n); + return this; +} + +template +typename parser_buf::pos_type +parser_buf::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) +{ + typedef typename boost::int_t::least cast_type; + + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + std::ptrdiff_t size = this->egptr() - this->eback(); + std::ptrdiff_t pos = this->gptr() - this->eback(); + charT* g = this->eback(); + switch(static_cast(way)) + { + case ::std::ios_base::beg: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + off, g + size); + break; + case ::std::ios_base::end: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + size - off, g + size); + break; + case ::std::ios_base::cur: + { + std::ptrdiff_t newpos = static_cast(pos + off); + if((newpos < 0) || (newpos > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + newpos, g + size); + break; + } + default: ; + } +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + return static_cast(this->gptr() - this->eback()); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +typename parser_buf::pos_type +parser_buf::seekpos(pos_type sp, ::std::ios_base::openmode which) +{ + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + off_type size = static_cast(this->egptr() - this->eback()); + charT* g = this->eback(); + if(off_type(sp) <= size) + { + this->setg(g, g + off_type(sp), g + size); + } + return pos_type(off_type(-1)); +} + +// +// class cpp_regex_traits_base: +// acts as a container for locale and the facets we are using. +// +template +struct cpp_regex_traits_base +{ + cpp_regex_traits_base(const std::locale& l) + { (void)imbue(l); } + std::locale imbue(const std::locale& l); + + std::locale m_locale; + std::ctype const* m_pctype; +#ifndef BOOST_NO_STD_MESSAGES + std::messages const* m_pmessages; +#endif + std::collate const* m_pcollate; + + bool operator<(const cpp_regex_traits_base& b)const + { + if(m_pctype == b.m_pctype) + { +#ifndef BOOST_NO_STD_MESSAGES + if(m_pmessages == b.m_pmessages) + { + return m_pcollate < b.m_pcollate; + } + return m_pmessages < b.m_pmessages; +#else + return m_pcollate < b.m_pcollate; +#endif + } + return m_pctype < b.m_pctype; + } + bool operator==(const cpp_regex_traits_base& b)const + { + return (m_pctype == b.m_pctype) +#ifndef BOOST_NO_STD_MESSAGES + && (m_pmessages == b.m_pmessages) +#endif + && (m_pcollate == b.m_pcollate); + } +}; + +template +std::locale cpp_regex_traits_base::imbue(const std::locale& l) +{ + std::locale result(m_locale); + m_locale = l; + m_pctype = &BOOST_USE_FACET(std::ctype, l); +#ifndef BOOST_NO_STD_MESSAGES + m_pmessages = BOOST_HAS_FACET(std::messages, l) ? &BOOST_USE_FACET(std::messages, l) : 0; +#endif + m_pcollate = &BOOST_USE_FACET(std::collate, l); + return result; +} + +// +// class cpp_regex_traits_char_layer: +// implements methods that require specialization for narrow characters: +// +template +class cpp_regex_traits_char_layer : public cpp_regex_traits_base +{ + typedef std::basic_string string_type; + typedef std::map map_type; + typedef typename map_type::const_iterator map_iterator_type; +public: + cpp_regex_traits_char_layer(const std::locale& l) + : cpp_regex_traits_base(l) + { + init(); + } + cpp_regex_traits_char_layer(const cpp_regex_traits_base& b) + : cpp_regex_traits_base(b) + { + init(); + } + void init(); + + regex_constants::syntax_type syntax_type(charT c)const + { + map_iterator_type i = m_char_map.find(c); + return ((i == m_char_map.end()) ? 0 : i->second); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + map_iterator_type i = m_char_map.find(c); + if(i == m_char_map.end()) + { + if(this->m_pctype->is(std::ctype_base::lower, c)) return regex_constants::escape_type_class; + if(this->m_pctype->is(std::ctype_base::upper, c)) return regex_constants::escape_type_not_class; + return 0; + } + return i->second; + } + +private: + string_type get_default_message(regex_constants::syntax_type); + // TODO: use a hash table when available! + map_type m_char_map; +}; + +template +void cpp_regex_traits_char_layer::init() +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: +#ifndef BOOST_NO_STD_MESSAGES +#ifndef __IBMCPP__ + typename std::messages::catalog cat = static_cast::catalog>(-1); +#else + typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if((!cat_name.empty()) && (this->m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if((int)cat >= 0) + { +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = this->m_pmessages->get(cat, 0, i, get_default_message(i)); + for(typename string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[mss[j]] = i; + } + } + this->m_pmessages->close(cat); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + if(this->m_pmessages) + this->m_pmessages->close(cat); + throw; + } +#endif + } + else + { +#endif + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while(ptr && *ptr) + { + m_char_map[this->m_pctype->widen(*ptr)] = i; + ++ptr; + } + } +#ifndef BOOST_NO_STD_MESSAGES + } +#endif +} + +template +typename cpp_regex_traits_char_layer::string_type + cpp_regex_traits_char_layer::get_default_message(regex_constants::syntax_type i) +{ + const char* ptr = get_default_syntax(i); + string_type result; + while(ptr && *ptr) + { + result.append(1, this->m_pctype->widen(*ptr)); + ++ptr; + } + return result; +} + +// +// specialized version for narrow characters: +// +template <> +class cpp_regex_traits_char_layer : public cpp_regex_traits_base +{ + typedef std::string string_type; +public: + cpp_regex_traits_char_layer(const std::locale& l) + : cpp_regex_traits_base(l) + { + init(); + } + cpp_regex_traits_char_layer(const cpp_regex_traits_base& l) + : cpp_regex_traits_base(l) + { + init(); + } + + regex_constants::syntax_type syntax_type(char c)const + { + return m_char_map[static_cast(c)]; + } + regex_constants::escape_syntax_type escape_syntax_type(char c) const + { + return m_char_map[static_cast(c)]; + } + +private: + regex_constants::syntax_type m_char_map[1u << CHAR_BIT]; + void init(); +}; + +#ifdef BOOST_REGEX_BUGGY_CTYPE_FACET +enum +{ + char_class_space=1<<0, + char_class_print=1<<1, + char_class_cntrl=1<<2, + char_class_upper=1<<3, + char_class_lower=1<<4, + char_class_alpha=1<<5, + char_class_digit=1<<6, + char_class_punct=1<<7, + char_class_xdigit=1<<8, + char_class_alnum=char_class_alpha|char_class_digit, + char_class_graph=char_class_alnum|char_class_punct, + char_class_blank=1<<9, + char_class_word=1<<10, + char_class_unicode=1<<11, + char_class_horizontal_space=1<<12, + char_class_vertical_space=1<<13 +}; + +#endif + +// +// class cpp_regex_traits_implementation: +// provides pimpl implementation for cpp_regex_traits. +// +template +class cpp_regex_traits_implementation : public cpp_regex_traits_char_layer +{ +public: + typedef typename cpp_regex_traits::char_class_type char_class_type; + typedef typename std::ctype::mask native_mask_type; + typedef typename boost::make_unsigned::type unsigned_native_mask_type; +#ifndef BOOST_REGEX_BUGGY_CTYPE_FACET + BOOST_STATIC_CONSTANT(char_class_type, mask_blank = 1u << 24); + BOOST_STATIC_CONSTANT(char_class_type, mask_word = 1u << 25); + BOOST_STATIC_CONSTANT(char_class_type, mask_unicode = 1u << 26); + BOOST_STATIC_CONSTANT(char_class_type, mask_horizontal = 1u << 27); + BOOST_STATIC_CONSTANT(char_class_type, mask_vertical = 1u << 28); +#endif + + typedef std::basic_string string_type; + typedef charT char_type; + //cpp_regex_traits_implementation(); + cpp_regex_traits_implementation(const std::locale& l) + : cpp_regex_traits_char_layer(l) + { + init(); + } + cpp_regex_traits_implementation(const cpp_regex_traits_base& l) + : cpp_regex_traits_char_layer(l) + { + init(); + } + std::string error_string(regex_constants::error_type n) const + { + if(!m_error_strings.empty()) + { + std::map::const_iterator p = m_error_strings.find(n); + return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second; + } + return get_default_error_string(n); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + char_class_type result = lookup_classname_imp(p1, p2); + if(result == 0) + { + string_type temp(p1, p2); + this->m_pctype->tolower(&*temp.begin(), &*temp.begin() + temp.size()); + result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size()); + } + return result; + } + string_type lookup_collatename(const charT* p1, const charT* p2) const; + string_type transform_primary(const charT* p1, const charT* p2) const; + string_type transform(const charT* p1, const charT* p2) const; +private: + std::map m_error_strings; // error messages indexed by numberic ID + std::map m_custom_class_names; // character class names + std::map m_custom_collate_names; // collating element names + unsigned m_collate_type; // the form of the collation string + charT m_collate_delim; // the collation group delimiter + // + // helpers: + // + char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const; + void init(); +#ifdef BOOST_REGEX_BUGGY_CTYPE_FACET +public: + bool isctype(charT c, char_class_type m)const; +#endif +}; + +#ifndef BOOST_REGEX_BUGGY_CTYPE_FACET +#if !defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) + +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_blank; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_word; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_unicode; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_vertical; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_horizontal; + +#endif +#endif + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::transform_primary(const charT* p1, const charT* p2) const +{ + // + // PRECONDITIONS: + // + // A bug in gcc 3.2 (and maybe other versions as well) treats + // p1 as a null terminated string, for efficiency reasons + // we work around this elsewhere, but just assert here that + // we adhere to gcc's (buggy) preconditions... + // + BOOST_REGEX_ASSERT(*p2 == 0); + string_type result; +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::collate::transform, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(*p1 == 0) + { + return string_type(1, charT(0)); + } +#endif + // + // swallowing all exceptions here is a bad idea + // however at least one std lib will always throw + // std::bad_alloc for certain arguments... + // +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(m_collate_type) + { + case sort_C: + case sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + this->m_pctype->tolower(&*result.begin(), &*result.begin() + result.size()); + result = this->m_pcollate->transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case sort_fixed: + { + // get a regular sort key, and then truncate it: + result.assign(this->m_pcollate->transform(p1, p2)); + result.erase(this->m_collate_delim); + break; + } + case sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result.assign(this->m_pcollate->transform(p1, p2)); + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == m_collate_delim) + break; + } + result.erase(i); + break; + } +#ifndef BOOST_NO_EXCEPTIONS + }catch(...){} +#endif + while((!result.empty()) && (charT(0) == *result.rbegin())) + result.erase(result.size() - 1); + if(result.empty()) + { + // character is ignorable at the primary level: + result = string_type(1, charT(0)); + } + return result; +} + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::transform(const charT* p1, const charT* p2) const +{ + // + // PRECONDITIONS: + // + // A bug in gcc 3.2 (and maybe other versions as well) treats + // p1 as a null terminated string, for efficiency reasons + // we work around this elsewhere, but just assert here that + // we adhere to gcc's (buggy) preconditions... + // + BOOST_REGEX_ASSERT(*p2 == 0); + // + // swallowing all exceptions here is a bad idea + // however at least one std lib will always throw + // std::bad_alloc for certain arguments... + // + string_type result, result2; +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::collate::transform, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(*p1 == 0) + { + return result; + } +#endif +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + result = this->m_pcollate->transform(p1, p2); + // + // Borland's STLPort version returns a NULL-terminated + // string that has garbage at the end - each call to + // std::collate::transform returns a different string! + // So as a workaround, we'll truncate the string at the first NULL + // which _seems_ to work.... +#if BOOST_WORKAROUND(BOOST_BORLANDC, < 0x580) + result.erase(result.find(charT(0))); +#else + // + // some implementations (Dinkumware) append unnecessary trailing \0's: + while((!result.empty()) && (charT(0) == *result.rbegin())) + result.erase(result.size() - 1); +#endif + // + // We may have NULL's used as separators between sections of the collate string, + // an example would be Boost.Locale. We have no way to detect this case via + // #defines since this can be used with any compiler/platform combination. + // Unfortunately our state machine (which was devised when all implementations + // used underlying C language API's) can't cope with that case. One workaround + // is to replace each character with 2, fortunately this code isn't used that + // much as this is now slower than before :-( + // + typedef typename make_unsigned::type uchar_type; + result2.reserve(result.size() * 2 + 2); + for(unsigned i = 0; i < result.size(); ++i) + { + if(static_cast(result[i]) == (std::numeric_limits::max)()) + { + result2.append(1, charT((std::numeric_limits::max)())).append(1, charT('b')); + } + else + { + result2.append(1, static_cast(1 + static_cast(result[i]))).append(1, charT('b') - 1); + } + } + BOOST_REGEX_ASSERT(std::find(result2.begin(), result2.end(), charT(0)) == result2.end()); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + } +#endif + return result2; +} + + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::lookup_collatename(const charT* p1, const charT* p2) const +{ + typedef typename std::map::const_iterator iter_type; + if(!m_custom_collate_names.empty()) + { + iter_type pos = m_custom_collate_names.find(string_type(p1, p2)); + if(pos != m_custom_collate_names.end()) + return pos->second; + } +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x0551) + std::string name(p1, p2); +#else + std::string name; + const charT* p0 = p1; + while(p0 != p2) + name.append(1, char(*p0++)); +#endif + name = lookup_default_collate_name(name); +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x0551) + if(!name.empty()) + return string_type(name.begin(), name.end()); +#else + if(!name.empty()) + { + string_type result; + typedef std::string::const_iterator iter; + iter b = name.begin(); + iter e = name.end(); + while(b != e) + result.append(1, charT(*b++)); + return result; + } +#endif + if(p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +template +void cpp_regex_traits_implementation::init() +{ +#ifndef BOOST_NO_STD_MESSAGES +#ifndef __IBMCPP__ + typename std::messages::catalog cat = static_cast::catalog>(-1); +#else + typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if((!cat_name.empty()) && (this->m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if((int)cat >= 0) + { + // + // Error messages: + // + for(boost::regex_constants::error_type i = static_cast(0); + i <= boost::regex_constants::error_unknown; + i = static_cast(i + 1)) + { + const char* p = get_default_error_string(i); + string_type default_message; + while(*p) + { + default_message.append(1, this->m_pctype->widen(*p)); + ++p; + } + string_type s = this->m_pmessages->get(cat, 0, i+200, default_message); + std::string result; + for(std::string::size_type j = 0; j < s.size(); ++j) + { + result.append(1, this->m_pctype->narrow(s[j], 0)); + } + m_error_strings[i] = result; + } + // + // Custom class names: + // +#ifndef BOOST_REGEX_BUGGY_CTYPE_FACET + static const char_class_type masks[16] = + { + static_cast(std::ctype::alnum), + static_cast(std::ctype::alpha), + static_cast(std::ctype::cntrl), + static_cast(std::ctype::digit), + static_cast(std::ctype::graph), + cpp_regex_traits_implementation::mask_horizontal, + static_cast(std::ctype::lower), + static_cast(std::ctype::print), + static_cast(std::ctype::punct), + static_cast(std::ctype::space), + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_vertical, + static_cast(std::ctype::xdigit), + cpp_regex_traits_implementation::mask_blank, + cpp_regex_traits_implementation::mask_word, + cpp_regex_traits_implementation::mask_unicode, + }; +#else + static const char_class_type masks[16] = + { + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alnum, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alpha, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_cntrl, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_digit, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_graph, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_horizontal_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_lower, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_print, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_punct, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_upper, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_vertical_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_xdigit, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_blank, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_word, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_unicode, + }; +#endif + static const string_type null_string; + for(unsigned int j = 0; j <= 13; ++j) + { + string_type s(this->m_pmessages->get(cat, 0, j+300, null_string)); + if(!s.empty()) + this->m_custom_class_names[s] = masks[j]; + } + } +#endif + // + // get the collation format used by m_pcollate: + // + m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim); +} + +template +typename cpp_regex_traits_implementation::char_class_type + cpp_regex_traits_implementation::lookup_classname_imp(const charT* p1, const charT* p2) const +{ +#ifndef BOOST_REGEX_BUGGY_CTYPE_FACET + static const char_class_type masks[22] = + { + 0, + static_cast(std::ctype::alnum), + static_cast(std::ctype::alpha), + cpp_regex_traits_implementation::mask_blank, + static_cast(std::ctype::cntrl), + static_cast(std::ctype::digit), + static_cast(std::ctype::digit), + static_cast(std::ctype::graph), + cpp_regex_traits_implementation::mask_horizontal, + static_cast(std::ctype::lower), + static_cast(std::ctype::lower), + static_cast(std::ctype::print), + static_cast(std::ctype::punct), + static_cast(std::ctype::space), + static_cast(std::ctype::space), + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_unicode, + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_vertical, + static_cast(std::ctype::alnum) | cpp_regex_traits_implementation::mask_word, + static_cast(std::ctype::alnum) | cpp_regex_traits_implementation::mask_word, + static_cast(std::ctype::xdigit), + }; +#else + static const char_class_type masks[22] = + { + 0, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alnum, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alpha, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_blank, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_cntrl, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_digit, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_digit, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_graph, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_horizontal_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_lower, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_lower, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_print, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_punct, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_upper, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_unicode, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_upper, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_vertical_space, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alnum | ::boost::BOOST_REGEX_DETAIL_NS::char_class_word, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_alnum | ::boost::BOOST_REGEX_DETAIL_NS::char_class_word, + ::boost::BOOST_REGEX_DETAIL_NS::char_class_xdigit, + }; +#endif + if(!m_custom_class_names.empty()) + { + typedef typename std::map, char_class_type>::const_iterator map_iter; + map_iter pos = m_custom_class_names.find(string_type(p1, p2)); + if(pos != m_custom_class_names.end()) + return pos->second; + } + std::size_t state_id = 1 + BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + BOOST_REGEX_ASSERT(state_id < sizeof(masks) / sizeof(masks[0])); + return masks[state_id]; +} + +#ifdef BOOST_REGEX_BUGGY_CTYPE_FACET +template +bool cpp_regex_traits_implementation::isctype(const charT c, char_class_type mask) const +{ + return + ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_space) && (this->m_pctype->is(std::ctype::space, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_print) && (this->m_pctype->is(std::ctype::print, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_cntrl) && (this->m_pctype->is(std::ctype::cntrl, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_upper) && (this->m_pctype->is(std::ctype::upper, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_lower) && (this->m_pctype->is(std::ctype::lower, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_alpha) && (this->m_pctype->is(std::ctype::alpha, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_digit) && (this->m_pctype->is(std::ctype::digit, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_punct) && (this->m_pctype->is(std::ctype::punct, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_xdigit) && (this->m_pctype->is(std::ctype::xdigit, c))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_blank) && (this->m_pctype->is(std::ctype::space, c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_word) && (c == '_')) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_unicode) && ::boost::BOOST_REGEX_DETAIL_NS::is_extended(c)) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_vertical_space) && (is_separator(c) || (c == '\v'))) + || ((mask & ::boost::BOOST_REGEX_DETAIL_NS::char_class_horizontal_space) && this->m_pctype->is(std::ctype::space, c) && !(is_separator(c) || (c == '\v'))); +} +#endif + + +template +inline boost::shared_ptr > create_cpp_regex_traits(const std::locale& l) +{ + cpp_regex_traits_base key(l); + return ::boost::object_cache, cpp_regex_traits_implementation >::get(key, 5); +} + +} // BOOST_REGEX_DETAIL_NS + +template +class cpp_regex_traits +{ +private: + typedef std::ctype ctype_type; +public: + typedef charT char_type; + typedef std::size_t size_type; + typedef std::basic_string string_type; + typedef std::locale locale_type; + typedef boost::uint_least32_t char_class_type; + + struct boost_extensions_tag{}; + + cpp_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::create_cpp_regex_traits(std::locale())) + { } + static size_type length(const char_type* p) + { + return std::char_traits::length(p); + } + regex_constants::syntax_type syntax_type(charT c)const + { + return m_pimpl->syntax_type(c); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + return m_pimpl->escape_syntax_type(c); + } + charT translate(charT c) const + { + return c; + } + charT translate_nocase(charT c) const + { + return m_pimpl->m_pctype->tolower(c); + } + charT translate(charT c, bool icase) const + { + return icase ? m_pimpl->m_pctype->tolower(c) : c; + } + charT tolower(charT c) const + { + return m_pimpl->m_pctype->tolower(c); + } + charT toupper(charT c) const + { + return m_pimpl->m_pctype->toupper(c); + } + string_type transform(const charT* p1, const charT* p2) const + { + return m_pimpl->transform(p1, p2); + } + string_type transform_primary(const charT* p1, const charT* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_classname(p1, p2); + } + string_type lookup_collatename(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_collatename(p1, p2); + } + bool isctype(charT c, char_class_type f) const + { +#ifndef BOOST_REGEX_BUGGY_CTYPE_FACET + typedef typename std::ctype::mask ctype_mask; + + static const ctype_mask mask_base = + static_cast( + std::ctype::alnum + | std::ctype::alpha + | std::ctype::cntrl + | std::ctype::digit + | std::ctype::graph + | std::ctype::lower + | std::ctype::print + | std::ctype::punct + | std::ctype::space + | std::ctype::upper + | std::ctype::xdigit); + + if((f & mask_base) + && (m_pimpl->m_pctype->is( + static_cast(f & mask_base), c))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_word) && (c == '_')) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_blank) + && m_pimpl->m_pctype->is(std::ctype::space, c) + && !BOOST_REGEX_DETAIL_NS::is_separator(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_vertical) + && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_horizontal) + && this->isctype(c, std::ctype::space) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_vertical)) + return true; +#ifdef __CYGWIN__ + // + // Cygwin has a buggy ctype facet, see https://www.cygwin.com/ml/cygwin/2012-08/msg00178.html: + // + else if((f & std::ctype::xdigit) == std::ctype::xdigit) + { + if((c >= 'a') && (c <= 'f')) + return true; + if((c >= 'A') && (c <= 'F')) + return true; + } +#endif + return false; +#else + return m_pimpl->isctype(c, f); +#endif + } + boost::intmax_t toi(const charT*& p1, const charT* p2, int radix)const; + int value(charT c, int radix)const + { + const charT* pc = &c; + return (int)toi(pc, pc + 1, radix); + } + locale_type imbue(locale_type l) + { + std::locale result(getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::create_cpp_regex_traits(l); + return result; + } + locale_type getloc()const + { + return m_pimpl->m_locale; + } + std::string error_string(regex_constants::error_type n) const + { + return m_pimpl->error_string(n); + } + + // + // extension: + // set the name of the message catalog in use (defaults to "boost_regex"). + // + static std::string catalog_name(const std::string& name); + static std::string get_catalog_name(); + +private: + boost::shared_ptr > m_pimpl; + // + // catalog name handler: + // + static std::string& get_catalog_name_inst(); + +#ifdef BOOST_HAS_THREADS + static static_mutex& get_mutex_inst(); +#endif +}; + + +template +boost::intmax_t cpp_regex_traits::toi(const charT*& first, const charT* last, int radix)const +{ + BOOST_REGEX_DETAIL_NS::parser_buf sbuf; // buffer for parsing numbers. + std::basic_istream is(&sbuf); // stream for parsing numbers. + + // we do NOT want to parse any thousands separators inside the stream: + last = std::find(first, last, BOOST_USE_FACET(std::numpunct, is.getloc()).thousands_sep()); + + sbuf.pubsetbuf(const_cast(static_cast(first)), static_cast(last-first)); + is.clear(); + if(std::abs(radix) == 16) is >> std::hex; + else if(std::abs(radix) == 8) is >> std::oct; + else is >> std::dec; + boost::intmax_t val; + if(is >> val) + { + first = first + ((last - first) - sbuf.in_avail()); + return val; + } + else + return -1; +} + +template +std::string cpp_regex_traits::catalog_name(const std::string& name) +{ +#ifdef BOOST_HAS_THREADS + static_mutex::scoped_lock lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + get_catalog_name_inst() = name; + return result; +} + +template +std::string& cpp_regex_traits::get_catalog_name_inst() +{ + static std::string s_name; + return s_name; +} + +template +std::string cpp_regex_traits::get_catalog_name() +{ +#ifdef BOOST_HAS_THREADS + static_mutex::scoped_lock lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + return result; +} + +#ifdef BOOST_HAS_THREADS +template +static_mutex& cpp_regex_traits::get_mutex_inst() +{ + static static_mutex s_mutex = BOOST_STATIC_MUTEX_INIT; + return s_mutex; +} +#endif + +namespace BOOST_REGEX_DETAIL_NS { + + inline void cpp_regex_traits_char_layer::init() + { + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); +#ifndef BOOST_NO_STD_MESSAGES +#ifndef __IBMCPP__ + std::messages::catalog cat = static_cast::catalog>(-1); +#else + std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if ((!cat_name.empty()) && (m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if ((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if ((int)cat >= 0) + { +#ifndef BOOST_NO_EXCEPTIONS + try { +#endif + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = this->m_pmessages->get(cat, 0, i, get_default_syntax(i)); + for (string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + this->m_pmessages->close(cat); +#ifndef BOOST_NO_EXCEPTIONS + } + catch (...) + { + this->m_pmessages->close(cat); + throw; + } +#endif + } + else + { +#endif + for (regex_constants::syntax_type j = 1; j < regex_constants::syntax_max; ++j) + { + const char* ptr = get_default_syntax(j); + while (ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = j; + ++ptr; + } + } +#ifndef BOOST_NO_STD_MESSAGES + } +#endif + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if (m_char_map[i] == 0) + { + if (this->m_pctype->is(std::ctype_base::lower, i)) + m_char_map[i] = regex_constants::escape_type_class; + else if (this->m_pctype->is(std::ctype_base::upper, i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + } while (0xFF != i++); + } + +} // namespace detail + + +} // boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/cregex.hpp b/third-party/boost_regex/include/boost/regex/v4/cregex.hpp new file mode 100644 index 0000000000..dec49c9b9f --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/cregex.hpp @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE cregex.cpp + * VERSION see + * DESCRIPTION: Declares POSIX API functions + * + boost::RegEx high level wrapper. + */ + +#ifndef BOOST_RE_CREGEX_HPP_INCLUDED +#define BOOST_RE_CREGEX_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif +#include +#include + +#ifdef __cplusplus +#include +#else +#include +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +/* include these defs only for POSIX compatablity */ +#ifdef __cplusplus +namespace boost{ +extern "C" { +#endif + +#if defined(__cplusplus) && !defined(BOOST_NO_STDC_NAMESPACE) +typedef std::ptrdiff_t regoff_t; +typedef std::size_t regsize_t; +#else +typedef ptrdiff_t regoff_t; +typedef size_t regsize_t; +#endif + +typedef struct +{ + unsigned int re_magic; +#ifdef __cplusplus + std::size_t re_nsub; /* number of parenthesized subexpressions */ +#else + size_t re_nsub; +#endif + const char* re_endp; /* end pointer for REG_PEND */ + void* guts; /* none of your business :-) */ + match_flag_type eflags; /* none of your business :-) */ +} regex_tA; + +#ifndef BOOST_NO_WREGEX +typedef struct +{ + unsigned int re_magic; +#ifdef __cplusplus + std::size_t re_nsub; /* number of parenthesized subexpressions */ +#else + size_t re_nsub; +#endif + const wchar_t* re_endp; /* end pointer for REG_PEND */ + void* guts; /* none of your business :-) */ + match_flag_type eflags; /* none of your business :-) */ +} regex_tW; +#endif + +typedef struct +{ + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + +/* regcomp() flags */ +typedef enum{ + REG_BASIC = 0000, + REG_EXTENDED = 0001, + REG_ICASE = 0002, + REG_NOSUB = 0004, + REG_NEWLINE = 0010, + REG_NOSPEC = 0020, + REG_PEND = 0040, + REG_DUMP = 0200, + REG_NOCOLLATE = 0400, + REG_ESCAPE_IN_LISTS = 01000, + REG_NEWLINE_ALT = 02000, + REG_PERLEX = 04000, + + REG_PERL = REG_EXTENDED | REG_NOCOLLATE | REG_ESCAPE_IN_LISTS | REG_PERLEX, + REG_AWK = REG_EXTENDED | REG_ESCAPE_IN_LISTS, + REG_GREP = REG_BASIC | REG_NEWLINE_ALT, + REG_EGREP = REG_EXTENDED | REG_NEWLINE_ALT, + + REG_ASSERT = 15, + REG_INVARG = 16, + REG_ATOI = 255, /* convert name to number (!) */ + REG_ITOA = 0400 /* convert number to name (!) */ +} reg_comp_flags; + +/* regexec() flags */ +typedef enum{ + REG_NOTBOL = 00001, + REG_NOTEOL = 00002, + REG_STARTEND = 00004 +} reg_exec_flags; + +/* + * POSIX error codes: + */ +typedef unsigned reg_error_t; +typedef reg_error_t reg_errcode_t; /* backwards compatibility */ + +static const reg_error_t REG_NOERROR = 0; /* Success. */ +static const reg_error_t REG_NOMATCH = 1; /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ +static const reg_error_t REG_BADPAT = 2; /* Invalid pattern. */ +static const reg_error_t REG_ECOLLATE = 3; /* Undefined collating element. */ +static const reg_error_t REG_ECTYPE = 4; /* Invalid character class name. */ +static const reg_error_t REG_EESCAPE = 5; /* Trailing backslash. */ +static const reg_error_t REG_ESUBREG = 6; /* Invalid back reference. */ +static const reg_error_t REG_EBRACK = 7; /* Unmatched left bracket. */ +static const reg_error_t REG_EPAREN = 8; /* Parenthesis imbalance. */ +static const reg_error_t REG_EBRACE = 9; /* Unmatched \{. */ +static const reg_error_t REG_BADBR = 10; /* Invalid contents of \{\}. */ +static const reg_error_t REG_ERANGE = 11; /* Invalid range end. */ +static const reg_error_t REG_ESPACE = 12; /* Ran out of memory. */ +static const reg_error_t REG_BADRPT = 13; /* No preceding re for repetition op. */ +static const reg_error_t REG_EEND = 14; /* unexpected end of expression */ +static const reg_error_t REG_ESIZE = 15; /* expression too big */ +static const reg_error_t REG_ERPAREN = 8; /* = REG_EPAREN : unmatched right parenthesis */ +static const reg_error_t REG_EMPTY = 17; /* empty expression */ +static const reg_error_t REG_E_MEMORY = 15; /* = REG_ESIZE : out of memory */ +static const reg_error_t REG_ECOMPLEXITY = 18; /* complexity too high */ +static const reg_error_t REG_ESTACK = 19; /* out of stack space */ +static const reg_error_t REG_E_PERL = 20; /* Perl (?...) error */ +static const reg_error_t REG_E_UNKNOWN = 21; /* unknown error */ +static const reg_error_t REG_ENOSYS = 21; /* = REG_E_UNKNOWN : Reserved. */ + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompA(regex_tA*, const char*, int); +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int, const regex_tA*, char*, regsize_t); +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecA(const regex_tA*, const char*, regsize_t, regmatch_t*, int); +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeA(regex_tA*); + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompW(regex_tW*, const wchar_t*, int); +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int, const regex_tW*, wchar_t*, regsize_t); +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecW(const regex_tW*, const wchar_t*, regsize_t, regmatch_t*, int); +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeW(regex_tW*); +#endif + +#ifdef UNICODE +#define regcomp regcompW +#define regerror regerrorW +#define regexec regexecW +#define regfree regfreeW +#define regex_t regex_tW +#else +#define regcomp regcompA +#define regerror regerrorA +#define regexec regexecA +#define regfree regfreeA +#define regex_t regex_tA +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef __cplusplus +} /* extern "C" */ +} /* namespace */ +#endif + +#endif /* include guard */ + + + + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/error_type.hpp b/third-party/boost_regex/include/boost/regex/v4/error_type.hpp new file mode 100644 index 0000000000..afcc71e3d8 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/error_type.hpp @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2003-2005 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE error_type.hpp + * VERSION see + * DESCRIPTION: Declares regular expression error type enumerator. + */ + +#ifndef BOOST_REGEX_ERROR_TYPE_HPP +#define BOOST_REGEX_ERROR_TYPE_HPP + +#ifdef __cplusplus +namespace boost{ +#endif + +#ifdef __cplusplus +namespace regex_constants{ + +enum error_type{ + + error_ok = 0, /* not used */ + error_no_match = 1, /* not used */ + error_bad_pattern = 2, + error_collate = 3, + error_ctype = 4, + error_escape = 5, + error_backref = 6, + error_brack = 7, + error_paren = 8, + error_brace = 9, + error_badbrace = 10, + error_range = 11, + error_space = 12, + error_badrepeat = 13, + error_end = 14, /* not used */ + error_size = 15, + error_right_paren = 16, /* not used */ + error_empty = 17, + error_complexity = 18, + error_stack = 19, + error_perl_extension = 20, + error_unknown = 21 +}; + +} +} +#endif /* __cplusplus */ + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/icu.hpp b/third-party/boost_regex/include/boost/regex/v4/icu.hpp new file mode 100644 index 0000000000..7e70f57e5a --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/icu.hpp @@ -0,0 +1,1516 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE icu.hpp + * VERSION see + * DESCRIPTION: Unicode regular expressions on top of the ICU Library. + */ + +#ifndef BOOST_REGEX_ICU_V4_HPP +#define BOOST_REGEX_ICU_V4_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_MSVC +#pragma warning (push) +#pragma warning (disable: 4251) +#endif + +namespace boost { + + namespace BOOST_REGEX_DETAIL_NS { + + // + // Implementation details: + // + class icu_regex_traits_implementation + { + typedef UChar32 char_type; + typedef std::size_t size_type; + typedef std::vector string_type; + typedef U_NAMESPACE_QUALIFIER Locale locale_type; + typedef boost::uint_least32_t char_class_type; + public: + icu_regex_traits_implementation(const U_NAMESPACE_QUALIFIER Locale& l) + : m_locale(l) + { + UErrorCode success = U_ZERO_ERROR; + m_collator.reset(U_NAMESPACE_QUALIFIER Collator::createInstance(l, success)); + if (U_SUCCESS(success) == 0) + init_error(); + m_collator->setStrength(U_NAMESPACE_QUALIFIER Collator::IDENTICAL); + success = U_ZERO_ERROR; + m_primary_collator.reset(U_NAMESPACE_QUALIFIER Collator::createInstance(l, success)); + if (U_SUCCESS(success) == 0) + init_error(); + m_primary_collator->setStrength(U_NAMESPACE_QUALIFIER Collator::PRIMARY); + } + U_NAMESPACE_QUALIFIER Locale getloc()const + { + return m_locale; + } + string_type do_transform(const char_type* p1, const char_type* p2, const U_NAMESPACE_QUALIFIER Collator* pcoll) const + { + // TODO make thread safe!!!! : + typedef u32_to_u16_iterator itt; + itt i(p1), j(p2); +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + std::vector< ::UChar> t(i, j); +#else + std::vector< ::UChar> t; + while (i != j) + t.push_back(*i++); +#endif + ::uint8_t result[100]; + ::int32_t len; + if (!t.empty()) + len = pcoll->getSortKey(&*t.begin(), static_cast< ::int32_t>(t.size()), result, sizeof(result)); + else + len = pcoll->getSortKey(static_cast(0), static_cast< ::int32_t>(0), result, sizeof(result)); + if (std::size_t(len) > sizeof(result)) + { + scoped_array< ::uint8_t> presult(new ::uint8_t[len + 1]); + if (!t.empty()) + len = pcoll->getSortKey(&*t.begin(), static_cast< ::int32_t>(t.size()), presult.get(), len + 1); + else + len = pcoll->getSortKey(static_cast(0), static_cast< ::int32_t>(0), presult.get(), len + 1); + if ((0 == presult[len - 1]) && (len > 1)) + --len; +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + return string_type(presult.get(), presult.get() + len); +#else + string_type sresult; + ::uint8_t const* ia = presult.get(); + ::uint8_t const* ib = presult.get() + len; + while (ia != ib) + sresult.push_back(*ia++); + return sresult; +#endif + } + if ((0 == result[len - 1]) && (len > 1)) + --len; +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + return string_type(result, result + len); +#else + string_type sresult; + ::uint8_t const* ia = result; + ::uint8_t const* ib = result + len; + while (ia != ib) + sresult.push_back(*ia++); + return sresult; +#endif + } + string_type transform(const char_type* p1, const char_type* p2) const + { + return do_transform(p1, p2, m_collator.get()); + } + string_type transform_primary(const char_type* p1, const char_type* p2) const + { + return do_transform(p1, p2, m_primary_collator.get()); + } + private: + void init_error() + { + std::runtime_error e("Could not initialize ICU resources"); + boost::throw_exception(e); + } + U_NAMESPACE_QUALIFIER Locale m_locale; // The ICU locale that we're using + boost::scoped_ptr< U_NAMESPACE_QUALIFIER Collator> m_collator; // The full collation object + boost::scoped_ptr< U_NAMESPACE_QUALIFIER Collator> m_primary_collator; // The primary collation object + }; + + inline boost::shared_ptr get_icu_regex_traits_implementation(const U_NAMESPACE_QUALIFIER Locale& loc) + { + return boost::shared_ptr(new icu_regex_traits_implementation(loc)); + } + + } + + class icu_regex_traits + { + public: + typedef UChar32 char_type; + typedef std::size_t size_type; + typedef std::vector string_type; + typedef U_NAMESPACE_QUALIFIER Locale locale_type; +#ifdef BOOST_NO_INT64_T + typedef std::bitset<64> char_class_type; +#else + typedef boost::uint64_t char_class_type; +#endif + + struct boost_extensions_tag {}; + + icu_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::get_icu_regex_traits_implementation(U_NAMESPACE_QUALIFIER Locale())) + { + } + static size_type length(const char_type* p) + { + size_type result = 0; + while (*p) + { + ++p; + ++result; + } + return result; + } + ::boost::regex_constants::syntax_type syntax_type(char_type c)const + { + return ((c < 0x7f) && (c > 0)) ? BOOST_REGEX_DETAIL_NS::get_default_syntax_type(static_cast(c)) : regex_constants::syntax_char; + } + ::boost::regex_constants::escape_syntax_type escape_syntax_type(char_type c) const + { + return ((c < 0x7f) && (c > 0)) ? BOOST_REGEX_DETAIL_NS::get_default_escape_syntax_type(static_cast(c)) : regex_constants::syntax_char; + } + char_type translate(char_type c) const + { + return c; + } + char_type translate_nocase(char_type c) const + { + return ::u_foldCase(c, U_FOLD_CASE_DEFAULT); + } + char_type translate(char_type c, bool icase) const + { + return icase ? translate_nocase(c) : translate(c); + } + char_type tolower(char_type c) const + { + return ::u_tolower(c); + } + char_type toupper(char_type c) const + { + return ::u_toupper(c); + } + string_type transform(const char_type* p1, const char_type* p2) const + { + return m_pimpl->transform(p1, p2); + } + string_type transform_primary(const char_type* p1, const char_type* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const char_type* p1, const char_type* p2) const + { + static const char_class_type mask_blank = char_class_type(1) << offset_blank; + static const char_class_type mask_space = char_class_type(1) << offset_space; + static const char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + static const char_class_type mask_underscore = char_class_type(1) << offset_underscore; + static const char_class_type mask_unicode = char_class_type(1) << offset_unicode; + static const char_class_type mask_any = char_class_type(1) << offset_any; + static const char_class_type mask_ascii = char_class_type(1) << offset_ascii; + static const char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + static const char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + static const char_class_type masks[] = + { + 0, + U_GC_L_MASK | U_GC_ND_MASK, + U_GC_L_MASK, + mask_blank, + U_GC_CC_MASK | U_GC_CF_MASK | U_GC_ZL_MASK | U_GC_ZP_MASK, + U_GC_ND_MASK, + U_GC_ND_MASK, + (0x3FFFFFFFu) & ~(U_GC_CC_MASK | U_GC_CF_MASK | U_GC_CS_MASK | U_GC_CN_MASK | U_GC_Z_MASK), + mask_horizontal, + U_GC_LL_MASK, + U_GC_LL_MASK, + ~(U_GC_C_MASK), + U_GC_P_MASK, + char_class_type(U_GC_Z_MASK) | mask_space, + char_class_type(U_GC_Z_MASK) | mask_space, + U_GC_LU_MASK, + mask_unicode, + U_GC_LU_MASK, + mask_vertical, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_ND_MASK) | mask_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx >= 0) + return masks[idx + 1]; + char_class_type result = lookup_icu_mask(p1, p2); + if (result != 0) + return result; + + if (idx < 0) + { + string_type s(p1, p2); + string_type::size_type i = 0; + while (i < s.size()) + { + s[i] = static_cast((::u_tolower)(s[i])); + if (::u_isspace(s[i]) || (s[i] == '-') || (s[i] == '_')) + s.erase(s.begin() + i, s.begin() + i + 1); + else + { + s[i] = static_cast((::u_tolower)(s[i])); + ++i; + } + } + if (!s.empty()) + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + if (idx >= 0) + return masks[idx + 1]; + if (!s.empty()) + result = lookup_icu_mask(&*s.begin(), &*s.begin() + s.size()); + if (result != 0) + return result; + } + BOOST_ASSERT(std::size_t(idx + 1) < sizeof(masks) / sizeof(masks[0])); + return masks[idx + 1]; + } + string_type lookup_collatename(const char_type* p1, const char_type* p2) const + { + string_type result; +#ifdef BOOST_NO_CXX98_BINDERS + if (std::find_if(p1, p2, std::bind(std::greater< ::UChar32>(), std::placeholders::_1, 0x7f)) == p2) +#else + if (std::find_if(p1, p2, std::bind2nd(std::greater< ::UChar32>(), 0x7f)) == p2) +#endif + { +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + std::string s(p1, p2); +#else + std::string s; + const char_type* p3 = p1; + while (p3 != p2) + s.append(1, *p3++); +#endif + // Try Unicode name: + UErrorCode err = U_ZERO_ERROR; + UChar32 c = ::u_charFromName(U_UNICODE_CHAR_NAME, s.c_str(), &err); + if (U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // Try Unicode-extended name: + err = U_ZERO_ERROR; + c = ::u_charFromName(U_EXTENDED_CHAR_NAME, s.c_str(), &err); + if (U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // try POSIX name: + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + result.assign(s.begin(), s.end()); +#else + result.clear(); + std::string::const_iterator si, sj; + si = s.begin(); + sj = s.end(); + while (si != sj) + result.push_back(*si++); +#endif + } + if (result.empty() && (p2 - p1 == 1)) + result.push_back(*p1); + return result; + } + bool isctype(char_type c, char_class_type f) const + { + static const char_class_type mask_blank = char_class_type(1) << offset_blank; + static const char_class_type mask_space = char_class_type(1) << offset_space; + static const char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + static const char_class_type mask_underscore = char_class_type(1) << offset_underscore; + static const char_class_type mask_unicode = char_class_type(1) << offset_unicode; + static const char_class_type mask_any = char_class_type(1) << offset_any; + static const char_class_type mask_ascii = char_class_type(1) << offset_ascii; + static const char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + static const char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + // check for standard catagories first: + char_class_type m = char_class_type(static_cast(1) << u_charType(c)); + if ((m & f) != 0) + return true; + // now check for special cases: + if (((f & mask_blank) != 0) && u_isblank(c)) + return true; + if (((f & mask_space) != 0) && u_isspace(c)) + return true; + if (((f & mask_xdigit) != 0) && (u_digit(c, 16) >= 0)) + return true; + if (((f & mask_unicode) != 0) && (c >= 0x100)) + return true; + if (((f & mask_underscore) != 0) && (c == '_')) + return true; + if (((f & mask_any) != 0) && (c <= 0x10FFFF)) + return true; + if (((f & mask_ascii) != 0) && (c <= 0x7F)) + return true; + if (((f & mask_vertical) != 0) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == static_cast('\v')) || (m == U_GC_ZL_MASK) || (m == U_GC_ZP_MASK))) + return true; + if (((f & mask_horizontal) != 0) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && u_isspace(c) && (c != static_cast('\v'))) + return true; + return false; + } + boost::intmax_t toi(const char_type*& p1, const char_type* p2, int radix)const + { + return BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + int value(char_type c, int radix)const + { + return u_digit(c, static_cast< ::int8_t>(radix)); + } + locale_type imbue(locale_type l) + { + locale_type result(m_pimpl->getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::get_icu_regex_traits_implementation(l); + return result; + } + locale_type getloc()const + { + return locale_type(); + } + std::string error_string(::boost::regex_constants::error_type n) const + { + return BOOST_REGEX_DETAIL_NS::get_default_error_string(n); + } + private: + icu_regex_traits(const icu_regex_traits&); + icu_regex_traits& operator=(const icu_regex_traits&); + + // + // define the bitmasks offsets we need for additional character properties: + // + enum { + offset_blank = U_CHAR_CATEGORY_COUNT, + offset_space = U_CHAR_CATEGORY_COUNT + 1, + offset_xdigit = U_CHAR_CATEGORY_COUNT + 2, + offset_underscore = U_CHAR_CATEGORY_COUNT + 3, + offset_unicode = U_CHAR_CATEGORY_COUNT + 4, + offset_any = U_CHAR_CATEGORY_COUNT + 5, + offset_ascii = U_CHAR_CATEGORY_COUNT + 6, + offset_horizontal = U_CHAR_CATEGORY_COUNT + 7, + offset_vertical = U_CHAR_CATEGORY_COUNT + 8 + }; + + static char_class_type lookup_icu_mask(const ::UChar32* p1, const ::UChar32* p2) + { + static const char_class_type mask_blank = char_class_type(1) << offset_blank; + static const char_class_type mask_space = char_class_type(1) << offset_space; + static const char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + static const char_class_type mask_underscore = char_class_type(1) << offset_underscore; + static const char_class_type mask_unicode = char_class_type(1) << offset_unicode; + static const char_class_type mask_any = char_class_type(1) << offset_any; + static const char_class_type mask_ascii = char_class_type(1) << offset_ascii; + static const char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + static const char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + static const ::UChar32 prop_name_table[] = { + /* any */ 'a', 'n', 'y', + /* ascii */ 'a', 's', 'c', 'i', 'i', + /* assigned */ 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* c* */ 'c', '*', + /* cc */ 'c', 'c', + /* cf */ 'c', 'f', + /* closepunctuation */ 'c', 'l', 'o', 's', 'e', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* cn */ 'c', 'n', + /* co */ 'c', 'o', + /* connectorpunctuation */ 'c', 'o', 'n', 'n', 'e', 'c', 't', 'o', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* control */ 'c', 'o', 'n', 't', 'r', 'o', 'l', + /* cs */ 'c', 's', + /* currencysymbol */ 'c', 'u', 'r', 'r', 'e', 'n', 'c', 'y', 's', 'y', 'm', 'b', 'o', 'l', + /* dashpunctuation */ 'd', 'a', 's', 'h', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* decimaldigitnumber */ 'd', 'e', 'c', 'i', 'm', 'a', 'l', 'd', 'i', 'g', 'i', 't', 'n', 'u', 'm', 'b', 'e', 'r', + /* enclosingmark */ 'e', 'n', 'c', 'l', 'o', 's', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* finalpunctuation */ 'f', 'i', 'n', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* format */ 'f', 'o', 'r', 'm', 'a', 't', + /* initialpunctuation */ 'i', 'n', 'i', 't', 'i', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* l* */ 'l', '*', + /* letter */ 'l', 'e', 't', 't', 'e', 'r', + /* letternumber */ 'l', 'e', 't', 't', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* lineseparator */ 'l', 'i', 'n', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* ll */ 'l', 'l', + /* lm */ 'l', 'm', + /* lo */ 'l', 'o', + /* lowercaseletter */ 'l', 'o', 'w', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* lt */ 'l', 't', + /* lu */ 'l', 'u', + /* m* */ 'm', '*', + /* mark */ 'm', 'a', 'r', 'k', + /* mathsymbol */ 'm', 'a', 't', 'h', 's', 'y', 'm', 'b', 'o', 'l', + /* mc */ 'm', 'c', + /* me */ 'm', 'e', + /* mn */ 'm', 'n', + /* modifierletter */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* modifiersymbol */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* n* */ 'n', '*', + /* nd */ 'n', 'd', + /* nl */ 'n', 'l', + /* no */ 'n', 'o', + /* nonspacingmark */ 'n', 'o', 'n', 's', 'p', 'a', 'c', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* notassigned */ 'n', 'o', 't', 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* number */ 'n', 'u', 'm', 'b', 'e', 'r', + /* openpunctuation */ 'o', 'p', 'e', 'n', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* other */ 'o', 't', 'h', 'e', 'r', + /* otherletter */ 'o', 't', 'h', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* othernumber */ 'o', 't', 'h', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* otherpunctuation */ 'o', 't', 'h', 'e', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* othersymbol */ 'o', 't', 'h', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* p* */ 'p', '*', + /* paragraphseparator */ 'p', 'a', 'r', 'a', 'g', 'r', 'a', 'p', 'h', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* pc */ 'p', 'c', + /* pd */ 'p', 'd', + /* pe */ 'p', 'e', + /* pf */ 'p', 'f', + /* pi */ 'p', 'i', + /* po */ 'p', 'o', + /* privateuse */ 'p', 'r', 'i', 'v', 'a', 't', 'e', 'u', 's', 'e', + /* ps */ 'p', 's', + /* punctuation */ 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* s* */ 's', '*', + /* sc */ 's', 'c', + /* separator */ 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* sk */ 's', 'k', + /* sm */ 's', 'm', + /* so */ 's', 'o', + /* spaceseparator */ 's', 'p', 'a', 'c', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* spacingcombiningmark */ 's', 'p', 'a', 'c', 'i', 'n', 'g', 'c', 'o', 'm', 'b', 'i', 'n', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* surrogate */ 's', 'u', 'r', 'r', 'o', 'g', 'a', 't', 'e', + /* symbol */ 's', 'y', 'm', 'b', 'o', 'l', + /* titlecase */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', + /* titlecaseletter */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* uppercaseletter */ 'u', 'p', 'p', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* z* */ 'z', '*', + /* zl */ 'z', 'l', + /* zp */ 'z', 'p', + /* zs */ 'z', 's', + }; + + static const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> range_data[] = { + { prop_name_table + 0, prop_name_table + 3, }, // any + { prop_name_table + 3, prop_name_table + 8, }, // ascii + { prop_name_table + 8, prop_name_table + 16, }, // assigned + { prop_name_table + 16, prop_name_table + 18, }, // c* + { prop_name_table + 18, prop_name_table + 20, }, // cc + { prop_name_table + 20, prop_name_table + 22, }, // cf + { prop_name_table + 22, prop_name_table + 38, }, // closepunctuation + { prop_name_table + 38, prop_name_table + 40, }, // cn + { prop_name_table + 40, prop_name_table + 42, }, // co + { prop_name_table + 42, prop_name_table + 62, }, // connectorpunctuation + { prop_name_table + 62, prop_name_table + 69, }, // control + { prop_name_table + 69, prop_name_table + 71, }, // cs + { prop_name_table + 71, prop_name_table + 85, }, // currencysymbol + { prop_name_table + 85, prop_name_table + 100, }, // dashpunctuation + { prop_name_table + 100, prop_name_table + 118, }, // decimaldigitnumber + { prop_name_table + 118, prop_name_table + 131, }, // enclosingmark + { prop_name_table + 131, prop_name_table + 147, }, // finalpunctuation + { prop_name_table + 147, prop_name_table + 153, }, // format + { prop_name_table + 153, prop_name_table + 171, }, // initialpunctuation + { prop_name_table + 171, prop_name_table + 173, }, // l* + { prop_name_table + 173, prop_name_table + 179, }, // letter + { prop_name_table + 179, prop_name_table + 191, }, // letternumber + { prop_name_table + 191, prop_name_table + 204, }, // lineseparator + { prop_name_table + 204, prop_name_table + 206, }, // ll + { prop_name_table + 206, prop_name_table + 208, }, // lm + { prop_name_table + 208, prop_name_table + 210, }, // lo + { prop_name_table + 210, prop_name_table + 225, }, // lowercaseletter + { prop_name_table + 225, prop_name_table + 227, }, // lt + { prop_name_table + 227, prop_name_table + 229, }, // lu + { prop_name_table + 229, prop_name_table + 231, }, // m* + { prop_name_table + 231, prop_name_table + 235, }, // mark + { prop_name_table + 235, prop_name_table + 245, }, // mathsymbol + { prop_name_table + 245, prop_name_table + 247, }, // mc + { prop_name_table + 247, prop_name_table + 249, }, // me + { prop_name_table + 249, prop_name_table + 251, }, // mn + { prop_name_table + 251, prop_name_table + 265, }, // modifierletter + { prop_name_table + 265, prop_name_table + 279, }, // modifiersymbol + { prop_name_table + 279, prop_name_table + 281, }, // n* + { prop_name_table + 281, prop_name_table + 283, }, // nd + { prop_name_table + 283, prop_name_table + 285, }, // nl + { prop_name_table + 285, prop_name_table + 287, }, // no + { prop_name_table + 287, prop_name_table + 301, }, // nonspacingmark + { prop_name_table + 301, prop_name_table + 312, }, // notassigned + { prop_name_table + 312, prop_name_table + 318, }, // number + { prop_name_table + 318, prop_name_table + 333, }, // openpunctuation + { prop_name_table + 333, prop_name_table + 338, }, // other + { prop_name_table + 338, prop_name_table + 349, }, // otherletter + { prop_name_table + 349, prop_name_table + 360, }, // othernumber + { prop_name_table + 360, prop_name_table + 376, }, // otherpunctuation + { prop_name_table + 376, prop_name_table + 387, }, // othersymbol + { prop_name_table + 387, prop_name_table + 389, }, // p* + { prop_name_table + 389, prop_name_table + 407, }, // paragraphseparator + { prop_name_table + 407, prop_name_table + 409, }, // pc + { prop_name_table + 409, prop_name_table + 411, }, // pd + { prop_name_table + 411, prop_name_table + 413, }, // pe + { prop_name_table + 413, prop_name_table + 415, }, // pf + { prop_name_table + 415, prop_name_table + 417, }, // pi + { prop_name_table + 417, prop_name_table + 419, }, // po + { prop_name_table + 419, prop_name_table + 429, }, // privateuse + { prop_name_table + 429, prop_name_table + 431, }, // ps + { prop_name_table + 431, prop_name_table + 442, }, // punctuation + { prop_name_table + 442, prop_name_table + 444, }, // s* + { prop_name_table + 444, prop_name_table + 446, }, // sc + { prop_name_table + 446, prop_name_table + 455, }, // separator + { prop_name_table + 455, prop_name_table + 457, }, // sk + { prop_name_table + 457, prop_name_table + 459, }, // sm + { prop_name_table + 459, prop_name_table + 461, }, // so + { prop_name_table + 461, prop_name_table + 475, }, // spaceseparator + { prop_name_table + 475, prop_name_table + 495, }, // spacingcombiningmark + { prop_name_table + 495, prop_name_table + 504, }, // surrogate + { prop_name_table + 504, prop_name_table + 510, }, // symbol + { prop_name_table + 510, prop_name_table + 519, }, // titlecase + { prop_name_table + 519, prop_name_table + 534, }, // titlecaseletter + { prop_name_table + 534, prop_name_table + 549, }, // uppercaseletter + { prop_name_table + 549, prop_name_table + 551, }, // z* + { prop_name_table + 551, prop_name_table + 553, }, // zl + { prop_name_table + 553, prop_name_table + 555, }, // zp + { prop_name_table + 555, prop_name_table + 557, }, // zs + }; + + static const icu_regex_traits::char_class_type icu_class_map[] = { + mask_any, // any + mask_ascii, // ascii + (0x3FFFFFFFu) & ~(U_GC_CN_MASK), // assigned + U_GC_C_MASK, // c* + U_GC_CC_MASK, // cc + U_GC_CF_MASK, // cf + U_GC_PE_MASK, // closepunctuation + U_GC_CN_MASK, // cn + U_GC_CO_MASK, // co + U_GC_PC_MASK, // connectorpunctuation + U_GC_CC_MASK, // control + U_GC_CS_MASK, // cs + U_GC_SC_MASK, // currencysymbol + U_GC_PD_MASK, // dashpunctuation + U_GC_ND_MASK, // decimaldigitnumber + U_GC_ME_MASK, // enclosingmark + U_GC_PF_MASK, // finalpunctuation + U_GC_CF_MASK, // format + U_GC_PI_MASK, // initialpunctuation + U_GC_L_MASK, // l* + U_GC_L_MASK, // letter + U_GC_NL_MASK, // letternumber + U_GC_ZL_MASK, // lineseparator + U_GC_LL_MASK, // ll + U_GC_LM_MASK, // lm + U_GC_LO_MASK, // lo + U_GC_LL_MASK, // lowercaseletter + U_GC_LT_MASK, // lt + U_GC_LU_MASK, // lu + U_GC_M_MASK, // m* + U_GC_M_MASK, // mark + U_GC_SM_MASK, // mathsymbol + U_GC_MC_MASK, // mc + U_GC_ME_MASK, // me + U_GC_MN_MASK, // mn + U_GC_LM_MASK, // modifierletter + U_GC_SK_MASK, // modifiersymbol + U_GC_N_MASK, // n* + U_GC_ND_MASK, // nd + U_GC_NL_MASK, // nl + U_GC_NO_MASK, // no + U_GC_MN_MASK, // nonspacingmark + U_GC_CN_MASK, // notassigned + U_GC_N_MASK, // number + U_GC_PS_MASK, // openpunctuation + U_GC_C_MASK, // other + U_GC_LO_MASK, // otherletter + U_GC_NO_MASK, // othernumber + U_GC_PO_MASK, // otherpunctuation + U_GC_SO_MASK, // othersymbol + U_GC_P_MASK, // p* + U_GC_ZP_MASK, // paragraphseparator + U_GC_PC_MASK, // pc + U_GC_PD_MASK, // pd + U_GC_PE_MASK, // pe + U_GC_PF_MASK, // pf + U_GC_PI_MASK, // pi + U_GC_PO_MASK, // po + U_GC_CO_MASK, // privateuse + U_GC_PS_MASK, // ps + U_GC_P_MASK, // punctuation + U_GC_S_MASK, // s* + U_GC_SC_MASK, // sc + U_GC_Z_MASK, // separator + U_GC_SK_MASK, // sk + U_GC_SM_MASK, // sm + U_GC_SO_MASK, // so + U_GC_ZS_MASK, // spaceseparator + U_GC_MC_MASK, // spacingcombiningmark + U_GC_CS_MASK, // surrogate + U_GC_S_MASK, // symbol + U_GC_LT_MASK, // titlecase + U_GC_LT_MASK, // titlecaseletter + U_GC_LU_MASK, // uppercaseletter + U_GC_Z_MASK, // z* + U_GC_ZL_MASK, // zl + U_GC_ZP_MASK, // zp + U_GC_ZS_MASK, // zs + }; + + + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_begin = range_data; + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_end = range_data + (sizeof(range_data) / sizeof(range_data[0])); + + BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> t = { p1, p2, }; + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* p = std::lower_bound(ranges_begin, ranges_end, t); + if ((p != ranges_end) && (t == *p)) + return icu_class_map[p - ranges_begin]; + return 0; + } + + boost::shared_ptr< ::boost::BOOST_REGEX_DETAIL_NS::icu_regex_traits_implementation> m_pimpl; + }; + +} // namespace boost + +namespace boost { + + // types: + typedef basic_regex< ::UChar32, icu_regex_traits> u32regex; + typedef match_results u32match; + typedef match_results u16match; + + // + // Construction of 32-bit regex types from UTF-8 and UTF-16 primitives: + // + namespace BOOST_REGEX_DETAIL_NS { + +#if !defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(__IBMCPP__) + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<1>*) + { + typedef boost::u8_to_u32_iterator conv_type; + return u32regex(conv_type(i, i, j), conv_type(j, i, j), opt); + } + + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<2>*) + { + typedef boost::u16_to_u32_iterator conv_type; + return u32regex(conv_type(i, i, j), conv_type(j, i, j), opt); + } + + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<4>*) + { + return u32regex(i, j, opt); + } +#else + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<1>*) + { + typedef boost::u8_to_u32_iterator conv_type; + typedef std::vector vector_type; + vector_type v; + conv_type a(i, i, j), b(j, i, j); + while (a != b) + { + v.push_back(*a); + ++a; + } + if (v.size()) + return u32regex(&*v.begin(), v.size(), opt); + return u32regex(static_cast(0), static_cast(0), opt); + } + + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<2>*) + { + typedef boost::u16_to_u32_iterator conv_type; + typedef std::vector vector_type; + vector_type v; + conv_type a(i, i, j), b(j, i, j); + while (a != b) + { + v.push_back(*a); + ++a; + } + if (v.size()) + return u32regex(&*v.begin(), v.size(), opt); + return u32regex(static_cast(0), static_cast(0), opt); + } + + template + inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const boost::mpl::int_<4>*) + { + typedef std::vector vector_type; + vector_type v; + while (i != j) + { + v.push_back((UChar32)(*i)); + ++i; + } + if (v.size()) + return u32regex(&*v.begin(), v.size(), opt); + return u32regex(static_cast(0), static_cast(0), opt); + } +#endif + } + + // BOOST_REGEX_UCHAR_IS_WCHAR_T + // + // Source inspection of unicode/umachine.h in ICU version 59 indicates that: + // + // On version 59, UChar is always char16_t in C++ mode (and uint16_t in C mode) + // + // On earlier versions, the logic is + // + // #if U_SIZEOF_WCHAR_T==2 + // typedef wchar_t OldUChar; + // #elif defined(__CHAR16_TYPE__) + // typedef __CHAR16_TYPE__ OldUChar; + // #else + // typedef uint16_t OldUChar; + // #endif + // + // That is, UChar is wchar_t only on versions below 59, when U_SIZEOF_WCHAR_T==2 + // + // Hence, + +#define BOOST_REGEX_UCHAR_IS_WCHAR_T (U_ICU_VERSION_MAJOR_NUM < 59 && U_SIZEOF_WCHAR_T == 2) + +#if BOOST_REGEX_UCHAR_IS_WCHAR_T + BOOST_STATIC_ASSERT((boost::is_same::value)); +#else + BOOST_STATIC_ASSERT(!(boost::is_same::value)); +#endif + + // + // Construction from an iterator pair: + // + template + inline u32regex make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(i, j, opt, static_cast const*>(0)); + } + // + // construction from UTF-8 nul-terminated strings: + // + inline u32regex make_u32regex(const char* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::strlen(p), opt, static_cast const*>(0)); + } + inline u32regex make_u32regex(const unsigned char* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::strlen(reinterpret_cast(p)), opt, static_cast const*>(0)); + } + // + // construction from UTF-16 nul-terminated strings: + // +#ifndef BOOST_NO_WREGEX + inline u32regex make_u32regex(const wchar_t* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::wcslen(p), opt, static_cast const*>(0)); + } +#endif +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T + inline u32regex make_u32regex(const UChar* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + u_strlen(p), opt, static_cast const*>(0)); + } +#endif + // + // construction from basic_string class-template: + // + template + inline u32regex make_u32regex(const std::basic_string& s, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(s.begin(), s.end(), opt, static_cast const*>(0)); + } + // + // Construction from ICU string type: + // + inline u32regex make_u32regex(const U_NAMESPACE_QUALIFIER UnicodeString& s, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) + { + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(s.getBuffer(), s.getBuffer() + s.length(), opt, static_cast const*>(0)); + } + + // + // regex_match overloads that widen the character type as appropriate: + // + namespace BOOST_REGEX_DETAIL_NS { + template + void copy_results(MR1& out, MR2 const& in, NSubs named_subs) + { + // copy results from an adapted MR2 match_results: + out.set_size(in.size(), in.prefix().first.base(), in.suffix().second.base()); + out.set_base(in.base().base()); + out.set_named_subs(named_subs); + for (int i = 0; i < (int)in.size(); ++i) + { + if (in[i].matched || !i) + { + out.set_first(in[i].first.base(), i); + out.set_second(in[i].second.base(), i, in[i].matched); + } + } +#ifdef BOOST_REGEX_MATCH_EXTRA + // Copy full capture info as well: + for (int i = 0; i < (int)in.size(); ++i) + { + if (in[i].captures().size()) + { + out[i].get_captures().assign(in[i].captures().size(), typename MR1::value_type()); + for (int j = 0; j < (int)out[i].captures().size(); ++j) + { + out[i].get_captures()[j].first = in[i].captures()[j].first.base(); + out[i].get_captures()[j].second = in[i].captures()[j].second.base(); + out[i].get_captures()[j].matched = in[i].captures()[j].matched; + } + } + } +#endif + } + + template + inline bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + boost::mpl::int_<4> const*) + { + return ::boost::regex_match(first, last, m, e, flags); + } + template + bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + boost::mpl::int_<2> const*) + { + typedef u16_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_match(conv_type(first, first, last), conv_type(last, first, last), what, e, flags); + // copy results across to m: + if (result) copy_results(m, what, e.get_named_subs()); + return result; + } + template + bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + boost::mpl::int_<1> const*) + { + typedef u8_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_match(conv_type(first, first, last), conv_type(last, first, last), what, e, flags); + // copy results across to m: + if (result) copy_results(m, what, e.get_named_subs()); + return result; + } + } // namespace BOOST_REGEX_DETAIL_NS + + template + inline bool u32regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(first, last, m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const UChar* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + u_strlen(p), m, e, flags, static_cast const*>(0)); + } +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) + inline bool u32regex_match(const wchar_t* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::wcslen(p), m, e, flags, static_cast const*>(0)); + } +#endif + inline bool u32regex_match(const char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::strlen(p), m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const unsigned char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::strlen((const char*)p), m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const std::string& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); + } +#ifndef BOOST_NO_STD_WSTRING + inline bool u32regex_match(const std::wstring& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); + } +#endif + inline bool u32regex_match(const U_NAMESPACE_QUALIFIER UnicodeString& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, static_cast const*>(0)); + } + // + // regex_match overloads that do not return what matched: + // + template + inline bool u32regex_match(BidiIterator first, BidiIterator last, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(first, last, m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const UChar* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + u_strlen(p), m, e, flags, static_cast const*>(0)); + } +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) + inline bool u32regex_match(const wchar_t* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::wcslen(p), m, e, flags, static_cast const*>(0)); + } +#endif + inline bool u32regex_match(const char* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::strlen(p), m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const unsigned char* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p + std::strlen((const char*)p), m, e, flags, static_cast const*>(0)); + } + inline bool u32regex_match(const std::string& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); + } +#ifndef BOOST_NO_STD_WSTRING + inline bool u32regex_match(const std::wstring& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); + } +#endif + inline bool u32regex_match(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, static_cast const*>(0)); + } + + // + // regex_search overloads that widen the character type as appropriate: + // + namespace BOOST_REGEX_DETAIL_NS { + template + inline bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + boost::mpl::int_<4> const*) + { + return ::boost::regex_search(first, last, m, e, flags, base); + } + template + bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + boost::mpl::int_<2> const*) + { + typedef u16_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_search(conv_type(first, first, last), conv_type(last, first, last), what, e, flags, conv_type(base)); + // copy results across to m: + if (result) copy_results(m, what, e.get_named_subs()); + return result; + } + template + bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + boost::mpl::int_<1> const*) + { + typedef u8_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_search(conv_type(first, first, last), conv_type(last, first, last), what, e, flags, conv_type(base)); + // copy results across to m: + if (result) copy_results(m, what, e.get_named_subs()); + return result; + } + } + + template + inline bool u32regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, first, static_cast const*>(0)); + } + template + inline bool u32regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, base, static_cast const*>(0)); + } + inline bool u32regex_search(const UChar* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + u_strlen(p), m, e, flags, p, static_cast const*>(0)); + } +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) + inline bool u32regex_search(const wchar_t* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::wcslen(p), m, e, flags, p, static_cast const*>(0)); + } +#endif + inline bool u32regex_search(const char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::strlen(p), m, e, flags, p, static_cast const*>(0)); + } + inline bool u32regex_search(const unsigned char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::strlen((const char*)p), m, e, flags, p, static_cast const*>(0)); + } + inline bool u32regex_search(const std::string& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); + } +#ifndef BOOST_NO_STD_WSTRING + inline bool u32regex_search(const std::wstring& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); + } +#endif + inline bool u32regex_search(const U_NAMESPACE_QUALIFIER UnicodeString& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, s.getBuffer(), static_cast const*>(0)); + } + template + inline bool u32regex_search(BidiIterator first, BidiIterator last, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, first, static_cast const*>(0)); + } + inline bool u32regex_search(const UChar* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + u_strlen(p), m, e, flags, p, static_cast const*>(0)); + } +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) + inline bool u32regex_search(const wchar_t* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::wcslen(p), m, e, flags, p, static_cast const*>(0)); + } +#endif + inline bool u32regex_search(const char* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::strlen(p), m, e, flags, p, static_cast const*>(0)); + } + inline bool u32regex_search(const unsigned char* p, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p + std::strlen((const char*)p), m, e, flags, p, static_cast const*>(0)); + } + inline bool u32regex_search(const std::string& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); + } +#ifndef BOOST_NO_STD_WSTRING + inline bool u32regex_search(const std::wstring& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); + } +#endif + inline bool u32regex_search(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + match_flag_type flags = match_default) + { + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, s.getBuffer(), static_cast const*>(0)); + } + + // + // overloads for regex_replace with utf-8 and utf-16 data types: + // + namespace BOOST_REGEX_DETAIL_NS { + template + inline std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator > + make_utf32_seq(I i, I j, mpl::int_<1> const*) + { + return std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator >(boost::u8_to_u32_iterator(i, i, j), boost::u8_to_u32_iterator(j, i, j)); + } + template + inline std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator > + make_utf32_seq(I i, I j, mpl::int_<2> const*) + { + return std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator >(boost::u16_to_u32_iterator(i, i, j), boost::u16_to_u32_iterator(j, i, j)); + } + template + inline std::pair< I, I > + make_utf32_seq(I i, I j, mpl::int_<4> const*) + { + return std::pair< I, I >(i, j); + } + template + inline std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator > + make_utf32_seq(const charT* p, mpl::int_<1> const*) + { + std::size_t len = std::strlen((const char*)p); + return std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator >(boost::u8_to_u32_iterator(p, p, p + len), boost::u8_to_u32_iterator(p + len, p, p + len)); + } + template + inline std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator > + make_utf32_seq(const charT* p, mpl::int_<2> const*) + { + std::size_t len = u_strlen((const UChar*)p); + return std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator >(boost::u16_to_u32_iterator(p, p, p + len), boost::u16_to_u32_iterator(p + len, p, p + len)); + } + template + inline std::pair< const charT*, const charT* > + make_utf32_seq(const charT* p, mpl::int_<4> const*) + { + return std::pair< const charT*, const charT* >(p, p + icu_regex_traits::length((UChar32 const*)p)); + } + template + inline OutputIterator make_utf32_out(OutputIterator o, mpl::int_<4> const*) + { + return o; + } + template + inline utf16_output_iterator make_utf32_out(OutputIterator o, mpl::int_<2> const*) + { + return o; + } + template + inline utf8_output_iterator make_utf32_out(OutputIterator o, mpl::int_<1> const*) + { + return o; + } + + template + OutputIterator do_regex_replace(OutputIterator out, + std::pair const& in, + const u32regex& e, + const std::pair& fmt, + match_flag_type flags + ) + { + // unfortunately we have to copy the format string in order to pass in onward: + std::vector f; +#ifndef BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS + f.assign(fmt.first, fmt.second); +#else + f.clear(); + I2 pos = fmt.first; + while (pos != fmt.second) + f.push_back(*pos++); +#endif + + regex_iterator i(in.first, in.second, e, flags); + regex_iterator j; + if (i == j) + { + if (!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(in.first, in.second, out); + } + else + { + I1 last_m = in.first; + while (i != j) + { + if (!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(i->prefix().first, i->prefix().second, out); + if (!f.empty()) + out = ::boost::BOOST_REGEX_DETAIL_NS::regex_format_imp(out, *i, &*f.begin(), &*f.begin() + f.size(), flags, e.get_traits()); + else + out = ::boost::BOOST_REGEX_DETAIL_NS::regex_format_imp(out, *i, static_cast(0), static_cast(0), flags, e.get_traits()); + last_m = (*i)[0].second; + if (flags & regex_constants::format_first_only) + break; + ++i; + } + if (!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(last_m, in.second, out); + } + return out; + } + template + inline const BaseIterator& extract_output_base(const BaseIterator& b) + { + return b; + } + template + inline BaseIterator extract_output_base(const utf8_output_iterator& b) + { + return b.base(); + } + template + inline BaseIterator extract_output_base(const utf16_output_iterator& b) + { + return b.base(); + } + } // BOOST_REGEX_DETAIL_NS + + template + inline OutputIterator u32regex_replace(OutputIterator out, + BidirectionalIterator first, + BidirectionalIterator last, + const u32regex& e, + const charT* fmt, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt, static_cast const*>(0)), + flags) + ); + } + + template + inline OutputIterator u32regex_replace(OutputIterator out, + Iterator first, + Iterator last, + const u32regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.begin(), fmt.end(), static_cast const*>(0)), + flags) + ); + } + + template + inline OutputIterator u32regex_replace(OutputIterator out, + Iterator first, + Iterator last, + const u32regex& e, + const U_NAMESPACE_QUALIFIER UnicodeString& fmt, + match_flag_type flags = match_default) + { + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.getBuffer(), fmt.getBuffer() + fmt.length(), static_cast const*>(0)), + flags) + ); + } + + template + std::basic_string u32regex_replace(const std::basic_string& s, + const u32regex& e, + const charT* fmt, + match_flag_type flags = match_default) + { + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + u32regex_replace(i, s.begin(), s.end(), e, fmt, flags); + return result; + } + + template + std::basic_string u32regex_replace(const std::basic_string& s, + const u32regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) + { + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + u32regex_replace(i, s.begin(), s.end(), e, fmt.c_str(), flags); + return result; + } + + namespace BOOST_REGEX_DETAIL_NS { + + class unicode_string_out_iterator + { + U_NAMESPACE_QUALIFIER UnicodeString* out; + public: + unicode_string_out_iterator(U_NAMESPACE_QUALIFIER UnicodeString& s) : out(&s) {} + unicode_string_out_iterator& operator++() { return *this; } + unicode_string_out_iterator& operator++(int) { return *this; } + unicode_string_out_iterator& operator*() { return *this; } + unicode_string_out_iterator& operator=(UChar v) + { + *out += v; + return *this; + } + typedef std::ptrdiff_t difference_type; + typedef UChar value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::output_iterator_tag iterator_category; + }; + + } + + inline U_NAMESPACE_QUALIFIER UnicodeString u32regex_replace(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + const UChar* fmt, + match_flag_type flags = match_default) + { + U_NAMESPACE_QUALIFIER UnicodeString result; + BOOST_REGEX_DETAIL_NS::unicode_string_out_iterator i(result); + u32regex_replace(i, s.getBuffer(), s.getBuffer() + s.length(), e, fmt, flags); + return result; + } + + inline U_NAMESPACE_QUALIFIER UnicodeString u32regex_replace(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + const U_NAMESPACE_QUALIFIER UnicodeString& fmt, + match_flag_type flags = match_default) + { + U_NAMESPACE_QUALIFIER UnicodeString result; + BOOST_REGEX_DETAIL_NS::unicode_string_out_iterator i(result); + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(i, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(s.getBuffer(), s.getBuffer() + s.length(), static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.getBuffer(), fmt.getBuffer() + fmt.length(), static_cast const*>(0)), + flags); + return result; + } + +} // namespace boost. + +#ifdef BOOST_MSVC +#pragma warning (pop) +#endif + +#include +#include + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/indexed_bit_flag.hpp b/third-party/boost_regex/include/boost/regex/v4/indexed_bit_flag.hpp new file mode 100644 index 0000000000..c9d32c59a1 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/indexed_bit_flag.hpp @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2020 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_parser.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_parser. + */ + +#include +#include + +#ifndef BOOST_REGEX_V4_INDEXED_BIT_FLAG_HPP +#define BOOST_REGEX_V4_INDEXED_BIT_FLAG_HPP + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +class indexed_bit_flag +{ + boost::uint64_t low_mask; + std::set mask_set; +public: + indexed_bit_flag() : low_mask(0) {} + void set(std::size_t i) + { + if (i < std::numeric_limits::digits - 1) + low_mask |= static_cast(1u) << i; + else + mask_set.insert(i); + } + bool test(std::size_t i) + { + if (i < std::numeric_limits::digits - 1) + return low_mask & static_cast(1u) << i ? true : false; + else + return mask_set.find(i) != mask_set.end(); + } +}; + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/iterator_category.hpp b/third-party/boost_regex/include/boost/regex/v4/iterator_category.hpp new file mode 100644 index 0000000000..9e40142378 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/iterator_category.hpp @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_match.hpp + * VERSION see + * DESCRIPTION: Iterator traits for selecting an iterator type as + * an integral constant expression. + */ + + +#ifndef BOOST_REGEX_ITERATOR_CATEGORY_HPP +#define BOOST_REGEX_ITERATOR_CATEGORY_HPP + +#include +#include +#include + +namespace boost{ +namespace detail{ + +template +struct is_random_imp +{ +#ifndef BOOST_NO_STD_ITERATOR_TRAITS +private: + typedef typename std::iterator_traits::iterator_category cat; +public: + BOOST_STATIC_CONSTANT(bool, value = (::boost::is_convertible::value)); +#else + BOOST_STATIC_CONSTANT(bool, value = false); +#endif +}; + +template +struct is_random_pointer_imp +{ + BOOST_STATIC_CONSTANT(bool, value = true); +}; + +template +struct is_random_imp_selector +{ + template + struct rebind + { + typedef is_random_imp type; + }; +}; + +template <> +struct is_random_imp_selector +{ + template + struct rebind + { + typedef is_random_pointer_imp type; + }; +}; + +} + +template +struct is_random_access_iterator +{ +private: + typedef detail::is_random_imp_selector< ::boost::is_pointer::value> selector; + typedef typename selector::template rebind bound_type; + typedef typename bound_type::type answer; +public: + BOOST_STATIC_CONSTANT(bool, value = answer::value); +}; + +#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +template +const bool is_random_access_iterator::value; +#endif + +} + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/iterator_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/iterator_traits.hpp new file mode 100644 index 0000000000..ae45ecb80c --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/iterator_traits.hpp @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE iterator_traits.cpp + * VERSION see + * DESCRIPTION: Declares iterator traits workarounds. + */ + +#ifndef BOOST_REGEX_V4_ITERATOR_TRAITS_HPP +#define BOOST_REGEX_V4_ITERATOR_TRAITS_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#if defined(BOOST_NO_STD_ITERATOR_TRAITS) + +template +struct regex_iterator_traits +{ + typedef typename T::iterator_category iterator_category; + typedef typename T::value_type value_type; +#if !defined(BOOST_NO_STD_ITERATOR) + typedef typename T::difference_type difference_type; + typedef typename T::pointer pointer; + typedef typename T::reference reference; +#else + typedef std::ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; +#endif +}; + +template +struct pointer_iterator_traits +{ + typedef std::ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + typedef std::random_access_iterator_tag iterator_category; +}; +template +struct const_pointer_iterator_traits +{ + typedef std::ptrdiff_t difference_type; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + typedef std::random_access_iterator_tag iterator_category; +}; + +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +// +// the follwoing are needed for ICU support: +// +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; + +#ifdef BOOST_REGEX_HAS_OTHER_WCHAR_T +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +#endif + +#if defined(__SGI_STL_PORT) && defined(__STL_DEBUG) +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +#ifndef BOOST_NO_STD_WSTRING +template<> +struct regex_iterator_traits : pointer_iterator_traits{}; +template<> +struct regex_iterator_traits : const_pointer_iterator_traits{}; +#endif // BOOST_NO_WSTRING +#endif // stport + +#else + +template +struct regex_iterator_traits : public std::iterator_traits {}; + +#endif + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/match_flags.hpp b/third-party/boost_regex/include/boost/regex/v4/match_flags.hpp new file mode 100644 index 0000000000..5dc7265508 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/match_flags.hpp @@ -0,0 +1,161 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE match_flags.hpp + * VERSION see + * DESCRIPTION: Declares match_flags type. + */ + +#ifndef BOOST_REGEX_V4_MATCH_FLAGS +#define BOOST_REGEX_V4_MATCH_FLAGS + +#ifdef __cplusplus +# include +#endif + +#ifdef __cplusplus +namespace boost{ + namespace regex_constants{ +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#if BOOST_MSVC >= 1800 +#pragma warning(disable : 26812) +#endif +#endif + +typedef enum _match_flags +{ + match_default = 0, + match_not_bol = 1, /* first is not start of line */ + match_not_eol = match_not_bol << 1, /* last is not end of line */ + match_not_bob = match_not_eol << 1, /* first is not start of buffer */ + match_not_eob = match_not_bob << 1, /* last is not end of buffer */ + match_not_bow = match_not_eob << 1, /* first is not start of word */ + match_not_eow = match_not_bow << 1, /* last is not end of word */ + match_not_dot_newline = match_not_eow << 1, /* \n is not matched by '.' */ + match_not_dot_null = match_not_dot_newline << 1, /* '\0' is not matched by '.' */ + match_prev_avail = match_not_dot_null << 1, /* *--first is a valid expression */ + match_init = match_prev_avail << 1, /* internal use */ + match_any = match_init << 1, /* don't care what we match */ + match_not_null = match_any << 1, /* string can't be null */ + match_continuous = match_not_null << 1, /* each grep match must continue from */ + /* uninterrupted from the previous one */ + match_partial = match_continuous << 1, /* find partial matches */ + + match_stop = match_partial << 1, /* stop after first match (grep) V3 only */ + match_not_initial_null = match_stop, /* don't match initial null, V4 only */ + match_all = match_stop << 1, /* must find the whole of input even if match_any is set */ + match_perl = match_all << 1, /* Use perl matching rules */ + match_posix = match_perl << 1, /* Use POSIX matching rules */ + match_nosubs = match_posix << 1, /* don't trap marked subs */ + match_extra = match_nosubs << 1, /* include full capture information for repeated captures */ + match_single_line = match_extra << 1, /* treat text as single line and ignore any \n's when matching ^ and $. */ + match_unused1 = match_single_line << 1, /* unused */ + match_unused2 = match_unused1 << 1, /* unused */ + match_unused3 = match_unused2 << 1, /* unused */ + match_max = match_unused3, + + format_perl = 0, /* perl style replacement */ + format_default = 0, /* ditto. */ + format_sed = match_max << 1, /* sed style replacement. */ + format_all = format_sed << 1, /* enable all extensions to syntax. */ + format_no_copy = format_all << 1, /* don't copy non-matching segments. */ + format_first_only = format_no_copy << 1, /* Only replace first occurrence. */ + format_is_if = format_first_only << 1, /* internal use only. */ + format_literal = format_is_if << 1, /* treat string as a literal */ + + match_not_any = match_not_bol | match_not_eol | match_not_bob + | match_not_eob | match_not_bow | match_not_eow | match_not_dot_newline + | match_not_dot_null | match_prev_avail | match_init | match_not_null + | match_continuous | match_partial | match_stop | match_not_initial_null + | match_stop | match_all | match_perl | match_posix | match_nosubs + | match_extra | match_single_line | match_unused1 | match_unused2 + | match_unused3 | match_max | format_perl | format_default | format_sed + | format_all | format_no_copy | format_first_only | format_is_if + | format_literal + + +} match_flags; + +#if defined(BOOST_BORLANDC) || (defined(_MSC_VER) && (_MSC_VER <= 1310)) +typedef unsigned long match_flag_type; +#else +typedef match_flags match_flag_type; + + +#ifdef __cplusplus +inline match_flags operator&(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) & static_cast(m2)); } +inline match_flags operator|(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) | static_cast(m2)); } +inline match_flags operator^(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) ^ static_cast(m2)); } +inline match_flags operator~(match_flags m1) +{ return static_cast(~static_cast(m1)); } +inline match_flags& operator&=(match_flags& m1, match_flags m2) +{ m1 = m1&m2; return m1; } +inline match_flags& operator|=(match_flags& m1, match_flags m2) +{ m1 = m1|m2; return m1; } +inline match_flags& operator^=(match_flags& m1, match_flags m2) +{ m1 = m1^m2; return m1; } +#endif +#endif + +#ifdef __cplusplus +} /* namespace regex_constants */ +/* + * import names into boost for backwards compatibility: + */ +using regex_constants::match_flag_type; +using regex_constants::match_default; +using regex_constants::match_not_bol; +using regex_constants::match_not_eol; +using regex_constants::match_not_bob; +using regex_constants::match_not_eob; +using regex_constants::match_not_bow; +using regex_constants::match_not_eow; +using regex_constants::match_not_dot_newline; +using regex_constants::match_not_dot_null; +using regex_constants::match_prev_avail; +/* using regex_constants::match_init; */ +using regex_constants::match_any; +using regex_constants::match_not_null; +using regex_constants::match_continuous; +using regex_constants::match_partial; +/*using regex_constants::match_stop; */ +using regex_constants::match_all; +using regex_constants::match_perl; +using regex_constants::match_posix; +using regex_constants::match_nosubs; +using regex_constants::match_extra; +using regex_constants::match_single_line; +/*using regex_constants::match_max; */ +using regex_constants::format_all; +using regex_constants::format_sed; +using regex_constants::format_perl; +using regex_constants::format_default; +using regex_constants::format_no_copy; +using regex_constants::format_first_only; +/*using regex_constants::format_is_if;*/ + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + +} /* namespace boost */ +#endif /* __cplusplus */ +#endif /* include guard */ + diff --git a/third-party/boost_regex/include/boost/regex/v4/match_results.hpp b/third-party/boost_regex/include/boost/regex/v4/match_results.hpp new file mode 100644 index 0000000000..c580e4fcba --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/match_results.hpp @@ -0,0 +1,716 @@ +/* + * + * Copyright (c) 1998-2009 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE match_results.cpp + * VERSION see + * DESCRIPTION: Declares template class match_results. + */ + +#ifndef BOOST_REGEX_V4_MATCH_RESULTS_HPP +#define BOOST_REGEX_V4_MATCH_RESULTS_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4251) +#if BOOST_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +# if BOOST_MSVC < 1600 +# pragma warning(disable : 4660) +# endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +class named_subexpressions; + +} + +template +class match_results +{ +private: +#ifndef BOOST_NO_STD_ALLOCATOR + typedef std::vector, Allocator> vector_type; +#else + typedef std::vector > vector_type; +#endif +public: + typedef sub_match value_type; +#ifndef BOOST_NO_CXX11_ALLOCATOR + typedef typename std::allocator_traits::value_type const & const_reference; +#elif !defined(BOOST_NO_STD_ALLOCATOR) && !(defined(BOOST_MSVC) && defined(_STLPORT_VERSION)) + typedef typename Allocator::const_reference const_reference; +#else + typedef const value_type& const_reference; +#endif + typedef const_reference reference; + typedef typename vector_type::const_iterator const_iterator; + typedef const_iterator iterator; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits< + BidiIterator>::difference_type difference_type; +#ifdef BOOST_NO_CXX11_ALLOCATOR + typedef typename Allocator::size_type size_type; +#else + typedef typename std::allocator_traits::size_type size_type; +#endif + typedef Allocator allocator_type; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits< + BidiIterator>::value_type char_type; + typedef std::basic_string string_type; + typedef BOOST_REGEX_DETAIL_NS::named_subexpressions named_sub_type; + + // construct/copy/destroy: + explicit match_results(const Allocator& a = Allocator()) +#ifndef BOOST_NO_STD_ALLOCATOR + : m_subs(a), m_base(), m_null(), m_last_closed_paren(0), m_is_singular(true) {} +#else + : m_subs(), m_base(), m_null(), m_last_closed_paren(0), m_is_singular(true) { (void)a; } +#endif + // + // IMPORTANT: in the code below, the crazy looking checks around m_is_singular are + // all required because it is illegal to copy a singular iterator. + // See https://svn.boost.org/trac/boost/ticket/3632. + // + match_results(const match_results& m) + : m_subs(m.m_subs), m_base(), m_null(), m_named_subs(m.m_named_subs), m_last_closed_paren(m.m_last_closed_paren), m_is_singular(m.m_is_singular) + { + if(!m_is_singular) + { + m_base = m.m_base; + m_null = m.m_null; + } + } + match_results& operator=(const match_results& m) + { + m_subs = m.m_subs; + m_named_subs = m.m_named_subs; + m_last_closed_paren = m.m_last_closed_paren; + m_is_singular = m.m_is_singular; + if(!m_is_singular) + { + m_base = m.m_base; + m_null = m.m_null; + } + return *this; + } + ~match_results(){} + + // size: + size_type size() const + { return empty() ? 0 : m_subs.size() - 2; } + size_type max_size() const + { return m_subs.max_size(); } + bool empty() const + { return m_subs.size() < 2; } + // element access: + difference_type length(int sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + if((sub < (int)m_subs.size()) && (sub > 0)) + return m_subs[sub].length(); + return 0; + } + difference_type length(const char_type* sub) const + { + if(m_is_singular) + raise_logic_error(); + const char_type* sub_end = sub; + while(*sub_end) ++sub_end; + return length(named_subexpression_index(sub, sub_end)); + } + template + difference_type length(const charT* sub) const + { + if(m_is_singular) + raise_logic_error(); + const charT* sub_end = sub; + while(*sub_end) ++sub_end; + return length(named_subexpression_index(sub, sub_end)); + } + template + difference_type length(const std::basic_string& sub) const + { + return length(sub.c_str()); + } + difference_type position(size_type sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + if(sub < m_subs.size()) + { + const sub_match& s = m_subs[sub]; + if(s.matched || (sub == 2)) + { + return ::boost::BOOST_REGEX_DETAIL_NS::distance((BidiIterator)(m_base), (BidiIterator)(s.first)); + } + } + return ~static_cast(0); + } + difference_type position(const char_type* sub) const + { + const char_type* sub_end = sub; + while(*sub_end) ++sub_end; + return position(named_subexpression_index(sub, sub_end)); + } + template + difference_type position(const charT* sub) const + { + const charT* sub_end = sub; + while(*sub_end) ++sub_end; + return position(named_subexpression_index(sub, sub_end)); + } + template + difference_type position(const std::basic_string& sub) const + { + return position(sub.c_str()); + } + string_type str(int sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + string_type result; + if(sub < (int)m_subs.size() && (sub > 0)) + { + const sub_match& s = m_subs[sub]; + if(s.matched) + { + result = s.str(); + } + } + return result; + } + string_type str(const char_type* sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const std::basic_string& sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const charT* sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const std::basic_string& sub) const + { + return (*this)[sub].str(); + } + const_reference operator[](int sub) const + { + if(m_is_singular && m_subs.empty()) + raise_logic_error(); + sub += 2; + if(sub < (int)m_subs.size() && (sub >= 0)) + { + return m_subs[sub]; + } + return m_null; + } + // + // Named sub-expressions: + // + const_reference named_subexpression(const char_type* i, const char_type* j) const + { + // + // Scan for the leftmost *matched* subexpression with the specified named: + // + if(m_is_singular) + raise_logic_error(); + BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type r = m_named_subs->equal_range(i, j); + while((r.first != r.second) && ((*this)[r.first->index].matched == false)) + ++r.first; + return r.first != r.second ? (*this)[r.first->index] : m_null; + } + template + const_reference named_subexpression(const charT* i, const charT* j) const + { + BOOST_STATIC_ASSERT(sizeof(charT) <= sizeof(char_type)); + if(i == j) + return m_null; + std::vector s; + while(i != j) + s.insert(s.end(), *i++); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + int named_subexpression_index(const char_type* i, const char_type* j) const + { + // + // Scan for the leftmost *matched* subexpression with the specified named. + // If none found then return the leftmost expression with that name, + // otherwise an invalid index: + // + if(m_is_singular) + raise_logic_error(); + BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type s, r; + s = r = m_named_subs->equal_range(i, j); + while((r.first != r.second) && ((*this)[r.first->index].matched == false)) + ++r.first; + if(r.first == r.second) + r = s; + return r.first != r.second ? r.first->index : -20; + } + template + int named_subexpression_index(const charT* i, const charT* j) const + { + BOOST_STATIC_ASSERT(sizeof(charT) <= sizeof(char_type)); + if(i == j) + return -20; + std::vector s; + while(i != j) + s.insert(s.end(), *i++); + return named_subexpression_index(&*s.begin(), &*s.begin() + s.size()); + } + template + const_reference operator[](const std::basic_string& s) const + { + return named_subexpression(s.c_str(), s.c_str() + s.size()); + } + const_reference operator[](const char_type* p) const + { + const char_type* e = p; + while(*e) ++e; + return named_subexpression(p, e); + } + + template + const_reference operator[](const charT* p) const + { + BOOST_STATIC_ASSERT(sizeof(charT) <= sizeof(char_type)); + if(*p == 0) + return m_null; + std::vector s; + while(*p) + s.insert(s.end(), *p++); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + template + const_reference operator[](const std::basic_string& ns) const + { + BOOST_STATIC_ASSERT(sizeof(charT) <= sizeof(char_type)); + if(ns.empty()) + return m_null; + std::vector s; + for(unsigned i = 0; i < ns.size(); ++i) + s.insert(s.end(), ns[i]); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + + const_reference prefix() const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[-1]; + } + + const_reference suffix() const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[-2]; + } + const_iterator begin() const + { + return (m_subs.size() > 2) ? (m_subs.begin() + 2) : m_subs.end(); + } + const_iterator end() const + { + return m_subs.end(); + } + // format: + template + OutputIterator format(OutputIterator out, + Functor fmt, + match_flag_type flags = format_default) const + { + if(m_is_singular) + raise_logic_error(); + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, OutputIterator>::type F; + F func(fmt); + return func(*this, out, flags); + } + template + string_type format(Functor fmt, match_flag_type flags = format_default) const + { + if(m_is_singular) + raise_logic_error(); + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, BOOST_REGEX_DETAIL_NS::string_out_iterator > >::type F; + F func(fmt); + + func(*this, i, flags); + return result; + } + // format with locale: + template + OutputIterator format(OutputIterator out, + Functor fmt, + match_flag_type flags, + const RegexT& re) const + { + if(m_is_singular) + raise_logic_error(); + typedef ::boost::regex_traits_wrapper traits_type; + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, OutputIterator, traits_type>::type F; + F func(fmt); + return func(*this, out, flags, re.get_traits()); + } + template + string_type format(Functor fmt, + match_flag_type flags, + const RegexT& re) const + { + if(m_is_singular) + raise_logic_error(); + typedef ::boost::regex_traits_wrapper traits_type; + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, BOOST_REGEX_DETAIL_NS::string_out_iterator >, traits_type >::type F; + F func(fmt); + + func(*this, i, flags, re.get_traits()); + return result; + } + + const_reference get_last_closed_paren()const + { + if(m_is_singular) + raise_logic_error(); + return m_last_closed_paren == 0 ? m_null : (*this)[m_last_closed_paren]; + } + + allocator_type get_allocator() const + { +#ifndef BOOST_NO_STD_ALLOCATOR + return m_subs.get_allocator(); +#else + return allocator_type(); +#endif + } + void swap(match_results& that) + { + std::swap(m_subs, that.m_subs); + std::swap(m_named_subs, that.m_named_subs); + std::swap(m_last_closed_paren, that.m_last_closed_paren); + if(m_is_singular) + { + if(!that.m_is_singular) + { + m_base = that.m_base; + m_null = that.m_null; + } + } + else if(that.m_is_singular) + { + that.m_base = m_base; + that.m_null = m_null; + } + else + { + std::swap(m_base, that.m_base); + std::swap(m_null, that.m_null); + } + std::swap(m_is_singular, that.m_is_singular); + } + bool operator==(const match_results& that)const + { + if(m_is_singular) + { + return that.m_is_singular; + } + else if(that.m_is_singular) + { + return false; + } + return (m_subs == that.m_subs) && (m_base == that.m_base) && (m_last_closed_paren == that.m_last_closed_paren); + } + bool operator!=(const match_results& that)const + { return !(*this == that); } + +#ifdef BOOST_REGEX_MATCH_EXTRA + typedef typename sub_match::capture_sequence_type capture_sequence_type; + + const capture_sequence_type& captures(int i)const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[i].captures(); + } +#endif + + // + // private access functions: + void BOOST_REGEX_CALL set_second(BidiIterator i) + { + BOOST_REGEX_ASSERT(m_subs.size() > 2); + m_subs[2].second = i; + m_subs[2].matched = true; + m_subs[0].first = i; + m_subs[0].matched = (m_subs[0].first != m_subs[0].second); + m_null.first = i; + m_null.second = i; + m_null.matched = false; + m_is_singular = false; + } + + void BOOST_REGEX_CALL set_second(BidiIterator i, size_type pos, bool m = true, bool escape_k = false) + { + if(pos) + m_last_closed_paren = static_cast(pos); + pos += 2; + BOOST_REGEX_ASSERT(m_subs.size() > pos); + m_subs[pos].second = i; + m_subs[pos].matched = m; + if((pos == 2) && !escape_k) + { + m_subs[0].first = i; + m_subs[0].matched = (m_subs[0].first != m_subs[0].second); + m_null.first = i; + m_null.second = i; + m_null.matched = false; + m_is_singular = false; + } + } + void BOOST_REGEX_CALL set_size(size_type n, BidiIterator i, BidiIterator j) + { + value_type v(j); + size_type len = m_subs.size(); + if(len > n + 2) + { + m_subs.erase(m_subs.begin()+n+2, m_subs.end()); + std::fill(m_subs.begin(), m_subs.end(), v); + } + else + { + std::fill(m_subs.begin(), m_subs.end(), v); + if(n+2 != len) + m_subs.insert(m_subs.end(), n+2-len, v); + } + m_subs[1].first = i; + m_last_closed_paren = 0; + } + void BOOST_REGEX_CALL set_base(BidiIterator pos) + { + m_base = pos; + } + BidiIterator base()const + { + return m_base; + } + void BOOST_REGEX_CALL set_first(BidiIterator i) + { + BOOST_REGEX_ASSERT(m_subs.size() > 2); + // set up prefix: + m_subs[1].second = i; + m_subs[1].matched = (m_subs[1].first != i); + // set up $0: + m_subs[2].first = i; + // zero out everything else: + for(size_type n = 3; n < m_subs.size(); ++n) + { + m_subs[n].first = m_subs[n].second = m_subs[0].second; + m_subs[n].matched = false; + } + } + void BOOST_REGEX_CALL set_first(BidiIterator i, size_type pos, bool escape_k = false) + { + BOOST_REGEX_ASSERT(pos+2 < m_subs.size()); + if(pos || escape_k) + { + m_subs[pos+2].first = i; + if(escape_k) + { + m_subs[1].second = i; + m_subs[1].matched = (m_subs[1].first != m_subs[1].second); + } + } + else + set_first(i); + } + void BOOST_REGEX_CALL maybe_assign(const match_results& m); + + void BOOST_REGEX_CALL set_named_subs(boost::shared_ptr subs) + { + m_named_subs = subs; + } + +private: + // + // Error handler called when an uninitialized match_results is accessed: + // + static void raise_logic_error() + { + std::logic_error e("Attempt to access an uninitialized boost::match_results<> class."); + boost::throw_exception(e); + } + + + vector_type m_subs; // subexpressions + BidiIterator m_base; // where the search started from + sub_match m_null; // a null match + boost::shared_ptr m_named_subs; // Shared copy of named subs in the regex object + int m_last_closed_paren; // Last ) to be seen - used for formatting + bool m_is_singular; // True if our stored iterators are singular +}; + +template +void BOOST_REGEX_CALL match_results::maybe_assign(const match_results& m) +{ + if(m_is_singular) + { + *this = m; + return; + } + const_iterator p1, p2; + p1 = begin(); + p2 = m.begin(); + // + // Distances are measured from the start of *this* match, unless this isn't + // a valid match in which case we use the start of the whole sequence. Note that + // no subsequent match-candidate can ever be to the left of the first match found. + // This ensures that when we are using bidirectional iterators, that distances + // measured are as short as possible, and therefore as efficient as possible + // to compute. Finally note that we don't use the "matched" data member to test + // whether a sub-expression is a valid match, because partial matches set this + // to false for sub-expression 0. + // + BidiIterator l_end = this->suffix().second; + BidiIterator l_base = (p1->first == l_end) ? this->prefix().first : (*this)[0].first; + difference_type len1 = 0; + difference_type len2 = 0; + difference_type base1 = 0; + difference_type base2 = 0; + std::size_t i; + for(i = 0; i < size(); ++i, ++p1, ++p2) + { + // + // Leftmost takes priority over longest; handle special cases + // where distances need not be computed first (an optimisation + // for bidirectional iterators: ensure that we don't accidently + // compute the length of the whole sequence, as this can be really + // expensive). + // + if(p1->first == l_end) + { + if(p2->first != l_end) + { + // p2 must be better than p1, and no need to calculate + // actual distances: + base1 = 1; + base2 = 0; + break; + } + else + { + // *p1 and *p2 are either unmatched or match end-of sequence, + // either way no need to calculate distances: + if((p1->matched == false) && (p2->matched == true)) + break; + if((p1->matched == true) && (p2->matched == false)) + return; + continue; + } + } + else if(p2->first == l_end) + { + // p1 better than p2, and no need to calculate distances: + return; + } + base1 = ::boost::BOOST_REGEX_DETAIL_NS::distance(l_base, p1->first); + base2 = ::boost::BOOST_REGEX_DETAIL_NS::distance(l_base, p2->first); + BOOST_REGEX_ASSERT(base1 >= 0); + BOOST_REGEX_ASSERT(base2 >= 0); + if(base1 < base2) return; + if(base2 < base1) break; + + len1 = ::boost::BOOST_REGEX_DETAIL_NS::distance((BidiIterator)p1->first, (BidiIterator)p1->second); + len2 = ::boost::BOOST_REGEX_DETAIL_NS::distance((BidiIterator)p2->first, (BidiIterator)p2->second); + BOOST_REGEX_ASSERT(len1 >= 0); + BOOST_REGEX_ASSERT(len2 >= 0); + if((len1 != len2) || ((p1->matched == false) && (p2->matched == true))) + break; + if((p1->matched == true) && (p2->matched == false)) + return; + } + if(i == size()) + return; + if(base2 < base1) + *this = m; + else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) ) + *this = m; +} + +template +void swap(match_results& a, match_results& b) +{ + a.swap(b); +} + +#ifndef BOOST_NO_STD_LOCALE +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const match_results& s) +{ + return (os << s.str()); +} +#else +template +std::ostream& operator << (std::ostream& os, + const match_results& s) +{ + return (os << s.str()); +} +#endif + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v4/mem_block_cache.hpp b/third-party/boost_regex/include/boost/regex/v4/mem_block_cache.hpp new file mode 100644 index 0000000000..1996a512af --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/mem_block_cache.hpp @@ -0,0 +1,183 @@ + /* + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE mem_block_cache.hpp + * VERSION see + * DESCRIPTION: memory block cache used by the non-recursive matcher. + */ + +#ifndef BOOST_REGEX_V4_MEM_BLOCK_CACHE_HPP +#define BOOST_REGEX_V4_MEM_BLOCK_CACHE_HPP + +#include +#ifdef BOOST_HAS_THREADS +#include +#endif + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#ifndef BOOST_NO_CXX11_HDR_ATOMIC + #include + #if ATOMIC_POINTER_LOCK_FREE == 2 + #define BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE + #define BOOST_REGEX_ATOMIC_POINTER std::atomic + #endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE /* lock free implementation */ +struct mem_block_cache +{ + std::atomic cache[BOOST_REGEX_MAX_CACHE_BLOCKS]; + + ~mem_block_cache() + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + if (cache[i].load()) ::operator delete(cache[i].load()); + } + } + void* get() + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + void* p = cache[i].load(); + if (p != NULL) { + if (cache[i].compare_exchange_strong(p, NULL)) return p; + } + } + return ::operator new(BOOST_REGEX_BLOCKSIZE); + } + void put(void* ptr) + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + void* p = cache[i].load(); + if (p == NULL) { + if (cache[i].compare_exchange_strong(p, ptr)) return; + } + } + ::operator delete(ptr); + } + + static mem_block_cache& instance() + { + static mem_block_cache block_cache = { { {nullptr} } }; + return block_cache; + } +}; + + +#else /* lock-based implementation */ + + +struct mem_block_node +{ + mem_block_node* next; +}; + +struct mem_block_cache +{ + // this member has to be statically initialsed: + mem_block_node* next; + unsigned cached_blocks; +#ifdef BOOST_HAS_THREADS + boost::static_mutex mut; +#endif + + ~mem_block_cache() + { + while(next) + { + mem_block_node* old = next; + next = next->next; + ::operator delete(old); + } + } + void* get() + { +#ifdef BOOST_HAS_THREADS + boost::static_mutex::scoped_lock g(mut); +#endif + if(next) + { + mem_block_node* result = next; + next = next->next; + --cached_blocks; + return result; + } + return ::operator new(BOOST_REGEX_BLOCKSIZE); + } + void put(void* p) + { +#ifdef BOOST_HAS_THREADS + boost::static_mutex::scoped_lock g(mut); +#endif + if(cached_blocks >= BOOST_REGEX_MAX_CACHE_BLOCKS) + { + ::operator delete(p); + } + else + { + mem_block_node* old = static_cast(p); + old->next = next; + next = old; + ++cached_blocks; + } + } + static mem_block_cache& instance() + { +#ifdef BOOST_HAS_THREADS + static mem_block_cache block_cache = { 0, 0, BOOST_STATIC_MUTEX_INIT, }; +#else + static mem_block_cache block_cache = { 0, 0, }; +#endif + return block_cache; + } +}; +#endif + +#if BOOST_REGEX_MAX_CACHE_BLOCKS == 0 + +inline void* BOOST_REGEX_CALL get_mem_block() +{ + return ::operator new(BOOST_REGEX_BLOCKSIZE); +} + +inline void BOOST_REGEX_CALL put_mem_block(void* p) +{ + ::operator delete(p); +} + +#else + +inline void* BOOST_REGEX_CALL get_mem_block() +{ + return mem_block_cache::instance().get(); +} + +inline void BOOST_REGEX_CALL put_mem_block(void* p) +{ + mem_block_cache::instance().put(p); +} + +#endif +} +} // namespace boost + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/object_cache.hpp b/third-party/boost_regex/include/boost/regex/v4/object_cache.hpp new file mode 100644 index 0000000000..98ba4c19d3 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/object_cache.hpp @@ -0,0 +1,171 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE object_cache.hpp + * VERSION see + * DESCRIPTION: Implements a generic object cache. + */ + +#ifndef BOOST_REGEX_OBJECT_CACHE_HPP +#define BOOST_REGEX_OBJECT_CACHE_HPP + +#include +#include +#include +#include +#include +#include +#ifdef BOOST_HAS_THREADS +#include +#endif + +namespace boost{ + +template +class object_cache +{ +public: + typedef std::pair< ::boost::shared_ptr, Key const*> value_type; + typedef std::list list_type; + typedef typename list_type::iterator list_iterator; + typedef std::map map_type; + typedef typename map_type::iterator map_iterator; + typedef typename list_type::size_type size_type; + static boost::shared_ptr get(const Key& k, size_type l_max_cache_size); + +private: + static boost::shared_ptr do_get(const Key& k, size_type l_max_cache_size); + + struct data + { + list_type cont; + map_type index; + }; + + // Needed by compilers not implementing the resolution to DR45. For reference, + // see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45. + friend struct data; +}; + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4702) +#endif +template +boost::shared_ptr object_cache::get(const Key& k, size_type l_max_cache_size) +{ +#ifdef BOOST_HAS_THREADS + static boost::static_mutex mut = BOOST_STATIC_MUTEX_INIT; + boost::static_mutex::scoped_lock l(mut); + if (l) + { + return do_get(k, l_max_cache_size); + } + // + // what do we do if the lock fails? + // for now just throw, but we should never really get here... + // + ::boost::throw_exception(std::runtime_error("Error in thread safety code: could not acquire a lock")); +#if defined(BOOST_NO_UNREACHABLE_RETURN_DETECTION) || defined(BOOST_NO_EXCEPTIONS) + return boost::shared_ptr(); +#endif +#else + return do_get(k, l_max_cache_size); +#endif +} +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +boost::shared_ptr object_cache::do_get(const Key& k, size_type l_max_cache_size) +{ + typedef typename object_cache::data object_data; + typedef typename map_type::size_type map_size_type; + static object_data s_data; + + // + // see if the object is already in the cache: + // + map_iterator mpos = s_data.index.find(k); + if(mpos != s_data.index.end()) + { + // + // Eureka! + // We have a cached item, bump it up the list and return it: + // + if(--(s_data.cont.end()) != mpos->second) + { + // splice out the item we want to move: + list_type temp; + temp.splice(temp.end(), s_data.cont, mpos->second); + // and now place it at the end of the list: + s_data.cont.splice(s_data.cont.end(), temp, temp.begin()); + BOOST_REGEX_ASSERT(*(s_data.cont.back().second) == k); + // update index with new position: + mpos->second = --(s_data.cont.end()); + BOOST_REGEX_ASSERT(&(mpos->first) == mpos->second->second); + BOOST_REGEX_ASSERT(&(mpos->first) == s_data.cont.back().second); + } + return s_data.cont.back().first; + } + // + // if we get here then the item is not in the cache, + // so create it: + // + boost::shared_ptr result(new Object(k)); + // + // Add it to the list, and index it: + // + s_data.cont.push_back(value_type(result, static_cast(0))); + s_data.index.insert(std::make_pair(k, --(s_data.cont.end()))); + s_data.cont.back().second = &(s_data.index.find(k)->first); + map_size_type s = s_data.index.size(); + BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get()); + BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second); + BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k); + if(s > l_max_cache_size) + { + // + // We have too many items in the list, so we need to start + // popping them off the back of the list, but only if they're + // being held uniquely by us: + // + list_iterator pos = s_data.cont.begin(); + list_iterator last = s_data.cont.end(); + while((pos != last) && (s > l_max_cache_size)) + { + if(pos->first.unique()) + { + list_iterator condemmed(pos); + ++pos; + // now remove the items from our containers, + // then order has to be as follows: + BOOST_REGEX_ASSERT(s_data.index.find(*(condemmed->second)) != s_data.index.end()); + s_data.index.erase(*(condemmed->second)); + s_data.cont.erase(condemmed); + --s; + } + else + ++pos; + } + BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get()); + BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second); + BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k); + } + return result; +} + +} + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/pattern_except.hpp b/third-party/boost_regex/include/boost/regex/v4/pattern_except.hpp new file mode 100644 index 0000000000..7aba564bbf --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/pattern_except.hpp @@ -0,0 +1,128 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE pattern_except.hpp + * VERSION see + * DESCRIPTION: Declares pattern-matching exception classes. + */ + +#ifndef BOOST_RE_V4_PAT_EXCEPT_HPP +#define BOOST_RE_V4_PAT_EXCEPT_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#include +#include +#include +#include + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable : 4275) +#if BOOST_MSVC >= 1800 +#pragma warning(disable : 26812) +#endif +#endif +class regex_error : public std::runtime_error +{ +public: + explicit regex_error(const std::string& s, regex_constants::error_type err = regex_constants::error_unknown, std::ptrdiff_t pos = 0) + : std::runtime_error(s) + , m_error_code(err) + , m_position(pos) + { + } + explicit regex_error(regex_constants::error_type err) + : std::runtime_error(::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(err)) + , m_error_code(err) + , m_position(0) + { + } + ~regex_error() BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE {} + regex_constants::error_type code()const + { return m_error_code; } + std::ptrdiff_t position()const + { return m_position; } + void raise()const + { +#ifndef BOOST_NO_EXCEPTIONS +#ifndef BOOST_REGEX_STANDALONE + ::boost::throw_exception(*this); +#else + throw* this; +#endif +#endif + } +private: + regex_constants::error_type m_error_code; + std::ptrdiff_t m_position; +}; + +typedef regex_error bad_pattern; +typedef regex_error bad_expression; + +namespace BOOST_REGEX_DETAIL_NS{ + +template +inline void raise_runtime_error(const E& ex) +{ +#ifndef BOOST_REGEX_STANDALONE + ::boost::throw_exception(ex); +#else + throw ex; +#endif +} + +template +void raise_error(const traits& t, regex_constants::error_type code) +{ + (void)t; // warning suppression + regex_error e(t.error_string(code), code, 0); + ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(e); +} + +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/perl_matcher.hpp b/third-party/boost_regex/include/boost/regex/v4/perl_matcher.hpp new file mode 100644 index 0000000000..4bd7d11463 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/perl_matcher.hpp @@ -0,0 +1,645 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef BOOST_REGEX_MATCHER_HPP +#define BOOST_REGEX_MATCHER_HPP + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +#pragma warning(disable : 4251) +#if BOOST_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +# if BOOST_MSVC < 1600 +# pragma warning(disable : 4660) +# endif +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +// +// error checking API: +// +inline void BOOST_REGEX_CALL verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf) +{ + // + // can't mix match_extra with POSIX matching rules: + // + if ((mf & match_extra) && (mf & match_posix)) + { + std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules"); + throw_exception(msg); + } +} +// +// function can_start: +// +template +inline bool can_start(charT c, const unsigned char* map, unsigned char mask) +{ + return ((c < static_cast(0)) ? true : ((c >= static_cast(1 << CHAR_BIT)) ? true : map[c] & mask)); +} +inline bool can_start(char c, const unsigned char* map, unsigned char mask) +{ + return map[(unsigned char)c] & mask; +} +inline bool can_start(signed char c, const unsigned char* map, unsigned char mask) +{ + return map[(unsigned char)c] & mask; +} +inline bool can_start(unsigned char c, const unsigned char* map, unsigned char mask) +{ + return map[c] & mask; +} +inline bool can_start(unsigned short c, const unsigned char* map, unsigned char mask) +{ + return ((c >= (1 << CHAR_BIT)) ? true : map[c] & mask); +} +#if !defined(__hpux) && !defined(__WINSCW__)// WCHAR_MIN not usable in pp-directives. +#if defined(WCHAR_MIN) && (WCHAR_MIN == 0) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +inline bool can_start(wchar_t c, const unsigned char* map, unsigned char mask) +{ + return ((c >= static_cast(1u << CHAR_BIT)) ? true : map[c] & mask); +} +#endif +#endif +#if !defined(BOOST_NO_INTRINSIC_WCHAR_T) +inline bool can_start(unsigned int c, const unsigned char* map, unsigned char mask) +{ + return (((c >= static_cast(1u << CHAR_BIT)) ? true : map[c] & mask)); +} +#endif + + +// +// Unfortunately Rogue Waves standard library appears to have a bug +// in std::basic_string::compare that results in erroneous answers +// in some cases (tested with Borland C++ 5.1, Rogue Wave lib version +// 0x020101) the test case was: +// {39135,0} < {0xff,0} +// which succeeds when it should not. +// +#ifndef _RWSTD_VER +template +inline int string_compare(const std::basic_string& s, const C* p) +{ + if(0 == *p) + { + if(s.empty() || ((s.size() == 1) && (s[0] == 0))) + return 0; + } + return s.compare(p); +} +#else +template +inline int string_compare(const std::basic_string& s, const C* p) +{ + if(0 == *p) + { + if(s.empty() || ((s.size() == 1) && (s[0] == 0))) + return 0; + } + return s.compare(p); +} +inline int string_compare(const std::string& s, const char* p) +{ return std::strcmp(s.c_str(), p); } +# ifndef BOOST_NO_WREGEX +inline int string_compare(const std::wstring& s, const wchar_t* p) +{ return std::wcscmp(s.c_str(), p); } +#endif +#endif +template +inline int string_compare(const Seq& s, const C* p) +{ + std::size_t i = 0; + while((i < s.size()) && (p[i] == s[i])) + { + ++i; + } + return (i == s.size()) ? -(int)p[i] : (int)s[i] - (int)p[i]; +} +# define STR_COMP(s,p) string_compare(s,p) + +template +inline const charT* re_skip_past_null(const charT* p) +{ + while (*p != static_cast(0)) ++p; + return ++p; +} + +template +iterator BOOST_REGEX_CALL re_is_set_member(iterator next, + iterator last, + const re_set_long* set_, + const regex_data& e, bool icase) +{ + const charT* p = reinterpret_cast(set_+1); + iterator ptr; + unsigned int i; + //bool icase = e.m_flags & regex_constants::icase; + + if(next == last) return next; + + typedef typename traits_type::string_type traits_string_type; + const ::boost::regex_traits_wrapper& traits_inst = *(e.m_ptraits); + + // dwa 9/13/00 suppress incorrect MSVC warning - it claims this is never + // referenced + (void)traits_inst; + + // try and match a single character, could be a multi-character + // collating element... + for(i = 0; i < set_->csingles; ++i) + { + ptr = next; + if(*p == static_cast(0)) + { + // treat null string as special case: + if(traits_inst.translate(*ptr, icase)) + { + ++p; + continue; + } + return set_->isnot ? next : (ptr == next) ? ++next : ptr; + } + else + { + while(*p && (ptr != last)) + { + if(traits_inst.translate(*ptr, icase) != *p) + break; + ++p; + ++ptr; + } + + if(*p == static_cast(0)) // if null we've matched + return set_->isnot ? next : (ptr == next) ? ++next : ptr; + + p = re_skip_past_null(p); // skip null + } + } + + charT col = traits_inst.translate(*next, icase); + + + if(set_->cranges || set_->cequivalents) + { + traits_string_type s1; + // + // try and match a range, NB only a single character can match + if(set_->cranges) + { + if((e.m_flags & regex_constants::collate) == 0) + s1.assign(1, col); + else + { + charT a[2] = { col, charT(0), }; + s1 = traits_inst.transform(a, a + 1); + } + for(i = 0; i < set_->cranges; ++i) + { + if(STR_COMP(s1, p) >= 0) + { + do{ ++p; }while(*p); + ++p; + if(STR_COMP(s1, p) <= 0) + return set_->isnot ? next : ++next; + } + else + { + // skip first string + do{ ++p; }while(*p); + ++p; + } + // skip second string + do{ ++p; }while(*p); + ++p; + } + } + // + // try and match an equivalence class, NB only a single character can match + if(set_->cequivalents) + { + charT a[2] = { col, charT(0), }; + s1 = traits_inst.transform_primary(a, a +1); + for(i = 0; i < set_->cequivalents; ++i) + { + if(STR_COMP(s1, p) == 0) + return set_->isnot ? next : ++next; + // skip string + do{ ++p; }while(*p); + ++p; + } + } + } + if(traits_inst.isctype(col, set_->cclasses) == true) + return set_->isnot ? next : ++next; + if((set_->cnclasses != 0) && (traits_inst.isctype(col, set_->cnclasses) == false)) + return set_->isnot ? next : ++next; + return set_->isnot ? ++next : next; +} + +template +class repeater_count +{ + repeater_count** stack; + repeater_count* next; + int state_id; + std::size_t count; // the number of iterations so far + BidiIterator start_pos; // where the last repeat started + + repeater_count* unwind_until(int n, repeater_count* p, int current_recursion_id) + { + while(p && (p->state_id != n)) + { + if(-2 - current_recursion_id == p->state_id) + return 0; + p = p->next; + if(p && (p->state_id < 0)) + { + p = unwind_until(p->state_id, p, current_recursion_id); + if(!p) + return p; + p = p->next; + } + } + return p; + } +public: + repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {} + + repeater_count(int i, repeater_count** s, BidiIterator start, int current_recursion_id) + : start_pos(start) + { + state_id = i; + stack = s; + next = *stack; + *stack = this; + if((state_id > next->state_id) && (next->state_id >= 0)) + count = 0; + else + { + repeater_count* p = next; + p = unwind_until(state_id, p, current_recursion_id); + if(p) + { + count = p->count; + start_pos = p->start_pos; + } + else + count = 0; + } + } + ~repeater_count() + { + if(next) + *stack = next; + } + std::size_t get_count() { return count; } + int get_id() { return state_id; } + std::size_t operator++() { return ++count; } + bool check_null_repeat(const BidiIterator& pos, std::size_t max) + { + // this is called when we are about to start a new repeat, + // if the last one was NULL move our count to max, + // otherwise save the current position. + bool result = (count == 0) ? false : (pos == start_pos); + if(result) + count = max; + else + start_pos = pos; + return result; + } +}; + +struct saved_state; + +enum saved_state_type +{ + saved_type_end = 0, + saved_type_paren = 1, + saved_type_recurse = 2, + saved_type_assertion = 3, + saved_state_alt = 4, + saved_state_repeater_count = 5, + saved_state_extra_block = 6, + saved_state_greedy_single_repeat = 7, + saved_state_rep_slow_dot = 8, + saved_state_rep_fast_dot = 9, + saved_state_rep_char = 10, + saved_state_rep_short_set = 11, + saved_state_rep_long_set = 12, + saved_state_non_greedy_long_repeat = 13, + saved_state_count = 14 +}; + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC >= 1800 +#pragma warning(disable:26495) +#endif +#endif +template +struct recursion_info +{ + typedef typename Results::value_type value_type; + typedef typename value_type::iterator iterator; + int idx; + const re_syntax_base* preturn_address; + Results results; + repeater_count* repeater_stack; + iterator location_of_start; +}; +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template +class perl_matcher +{ +public: + typedef typename traits::char_type char_type; + typedef perl_matcher self_type; + typedef bool (self_type::*matcher_proc_type)(); + typedef std::size_t traits_size_type; + typedef typename is_byte::width_type width_type; + typedef typename regex_iterator_traits::difference_type difference_type; + typedef match_results results_type; + + perl_matcher(BidiIterator first, BidiIterator end, + match_results& what, + const basic_regex& e, + match_flag_type f, + BidiIterator l_base) + : m_result(what), base(first), last(end), + position(first), backstop(l_base), re(e), traits_inst(e.get_traits()), + m_independent(false), next_count(&rep_obj), rep_obj(&next_count) +#ifdef BOOST_REGEX_NON_RECURSIVE + , m_recursions(0) +#endif + { + construct_init(e, f); + } + + bool match(); + bool find(); + + void setf(match_flag_type f) + { m_match_flags |= f; } + void unsetf(match_flag_type f) + { m_match_flags &= ~f; } + +private: + void construct_init(const basic_regex& e, match_flag_type f); + + bool find_imp(); + bool match_imp(); +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD + typedef bool (perl_matcher::*protected_proc_type)(); + bool protected_call(protected_proc_type); +#endif + void estimate_max_state_count(std::random_access_iterator_tag*); + void estimate_max_state_count(void*); + bool match_prefix(); + bool match_all_states(); + + // match procs, stored in s_match_vtable: + bool match_startmark(); + bool match_endmark(); + bool match_literal(); + bool match_start_line(); + bool match_end_line(); + bool match_wild(); + bool match_match(); + bool match_word_boundary(); + bool match_within_word(); + bool match_word_start(); + bool match_word_end(); + bool match_buffer_start(); + bool match_buffer_end(); + bool match_backref(); + bool match_long_set(); + bool match_set(); + bool match_jump(); + bool match_alt(); + bool match_rep(); + bool match_combining(); + bool match_soft_buffer_end(); + bool match_restart_continue(); + bool match_long_set_repeat(); + bool match_set_repeat(); + bool match_char_repeat(); + bool match_dot_repeat_fast(); + bool match_dot_repeat_slow(); + bool match_dot_repeat_dispatch() + { + return ::boost::is_random_access_iterator::value ? match_dot_repeat_fast() : match_dot_repeat_slow(); + } + bool match_backstep(); + bool match_assert_backref(); + bool match_toggle_case(); +#ifdef BOOST_REGEX_RECURSIVE + bool backtrack_till_match(std::size_t count); +#endif + bool match_recursion(); + bool match_fail(); + bool match_accept(); + bool match_commit(); + bool match_then(); + bool skip_until_paren(int index, bool match = true); + + // find procs stored in s_find_vtable: + bool find_restart_any(); + bool find_restart_word(); + bool find_restart_line(); + bool find_restart_buf(); + bool find_restart_lit(); + +private: + // final result structure to be filled in: + match_results& m_result; + // temporary result for POSIX matches: + scoped_ptr > m_temp_match; + // pointer to actual result structure to fill in: + match_results* m_presult; + // start of sequence being searched: + BidiIterator base; + // end of sequence being searched: + BidiIterator last; + // current character being examined: + BidiIterator position; + // where to restart next search after failed match attempt: + BidiIterator restart; + // where the current search started from, acts as base for $` during grep: + BidiIterator search_base; + // how far we can go back when matching lookbehind: + BidiIterator backstop; + // the expression being examined: + const basic_regex& re; + // the expression's traits class: + const ::boost::regex_traits_wrapper& traits_inst; + // the next state in the machine being matched: + const re_syntax_base* pstate; + // matching flags in use: + match_flag_type m_match_flags; + // how many states we have examined so far: + std::ptrdiff_t state_count; + // max number of states to examine before giving up: + std::ptrdiff_t max_state_count; + // whether we should ignore case or not: + bool icase; + // set to true when (position == last), indicates that we may have a partial match: + bool m_has_partial_match; + // set to true whenever we get a match: + bool m_has_found_match; + // set to true whenever we're inside an independent sub-expression: + bool m_independent; + // the current repeat being examined: + repeater_count* next_count; + // the first repeat being examined (top of linked list): + repeater_count rep_obj; + // the mask to pass when matching word boundaries: + typename traits::char_class_type m_word_mask; + // the bitmask to use when determining whether a match_any matches a newline or not: + unsigned char match_any_mask; + // recursion information: + std::vector > recursion_stack; +#ifdef BOOST_REGEX_RECURSIVE + // Set to false by a (*COMMIT): + bool m_can_backtrack; + bool m_have_accept; + bool m_have_then; +#endif +#ifdef BOOST_REGEX_NON_RECURSIVE + // + // additional members for non-recursive version: + // + typedef bool (self_type::*unwind_proc_type)(bool); + + void extend_stack(); + bool unwind(bool); + bool unwind_end(bool); + bool unwind_paren(bool); + bool unwind_recursion_stopper(bool); + bool unwind_assertion(bool); + bool unwind_alt(bool); + bool unwind_repeater_counter(bool); + bool unwind_extra_block(bool); + bool unwind_greedy_single_repeat(bool); + bool unwind_slow_dot_repeat(bool); + bool unwind_fast_dot_repeat(bool); + bool unwind_char_repeat(bool); + bool unwind_short_set_repeat(bool); + bool unwind_long_set_repeat(bool); + bool unwind_non_greedy_repeat(bool); + bool unwind_recursion(bool); + bool unwind_recursion_pop(bool); + bool unwind_commit(bool); + bool unwind_then(bool); + bool unwind_case(bool); + void destroy_single_repeat(); + void push_matched_paren(int index, const sub_match& sub); + void push_recursion_stopper(); + void push_assertion(const re_syntax_base* ps, bool positive); + void push_alt(const re_syntax_base* ps); + void push_repeater_count(int i, repeater_count** s); + void push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id); + void push_non_greedy_repeat(const re_syntax_base* ps); + void push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2); + void push_recursion_pop(); + void push_case_change(bool); + + // pointer to base of stack: + saved_state* m_stack_base; + // pointer to current stack position: + saved_state* m_backup_state; + // how many memory blocks have we used up?: + unsigned used_block_count; + // determines what value to return when unwinding from recursion, + // allows for mixed recursive/non-recursive algorithm: + bool m_recursive_result; + // We have unwound to a lookahead/lookbehind, used by COMMIT/PRUNE/SKIP: + bool m_unwound_lookahead; + // We have unwound to an alternative, used by THEN: + bool m_unwound_alt; + // We are unwinding a commit - used by independent subs to determine whether to stop there or carry on unwinding: + //bool m_unwind_commit; + // Recursion limit: + unsigned m_recursions; +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC >= 1800 +#pragma warning(disable:26495) +#endif +#endif + // these operations aren't allowed, so are declared private, + // bodies are provided to keep explicit-instantiation requests happy: + perl_matcher& operator=(const perl_matcher&) + { + return *this; + } + perl_matcher(const perl_matcher& that) + : m_result(that.m_result), re(that.re), traits_inst(that.traits_inst), rep_obj(0) {} +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +}; + +} // namespace BOOST_REGEX_DETAIL_NS + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +// +// include the implementation of perl_matcher: +// +#ifdef BOOST_REGEX_RECURSIVE +#include +#else +#include +#endif +// this one has to be last: +#include + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/perl_matcher_common.hpp b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_common.hpp new file mode 100644 index 0000000000..7cf0574beb --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_common.hpp @@ -0,0 +1,1030 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE perl_matcher_common.cpp + * VERSION see + * DESCRIPTION: Definitions of perl_matcher member functions that are + * common to both the recursive and non-recursive versions. + */ + +#ifndef BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP +#define BOOST_REGEX_V4_PERL_MATCHER_COMMON_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#if BOOST_MSVC >= 1800 +#pragma warning(disable: 26812) +#endif +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_BORLANDC +# pragma option push -w-8008 -w-8066 +#endif +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_MSVC +# pragma warning(push) +#pragma warning(disable:26812) +#endif + template +void perl_matcher::construct_init(const basic_regex& e, match_flag_type f) +{ + typedef typename regex_iterator_traits::iterator_category category; + typedef typename basic_regex::flag_type expression_flag_type; + + if(e.empty()) + { + // precondition failure: e is not a valid regex. + std::invalid_argument ex("Invalid regular expression object"); + boost::throw_exception(ex); + } + pstate = 0; + m_match_flags = f; + estimate_max_state_count(static_cast(0)); + expression_flag_type re_f = re.flags(); + icase = re_f & regex_constants::icase; + if(!(m_match_flags & (match_perl|match_posix))) + { + if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0) + m_match_flags |= match_perl; + else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex)) + m_match_flags |= match_perl; + else if((re_f & (regbase::main_option_type|regbase::literal)) == (regbase::literal)) + m_match_flags |= match_perl; + else + m_match_flags |= match_posix; + } + if(m_match_flags & match_posix) + { + m_temp_match.reset(new match_results()); + m_presult = m_temp_match.get(); + } + else + m_presult = &m_result; +#ifdef BOOST_REGEX_NON_RECURSIVE + m_stack_base = 0; + m_backup_state = 0; +#elif defined(BOOST_REGEX_RECURSIVE) + m_can_backtrack = true; + m_have_accept = false; +#endif + // find the value to use for matching word boundaries: + m_word_mask = re.get_data().m_word_mask; + // find bitmask to use for matching '.': + match_any_mask = static_cast((f & match_not_dot_newline) ? BOOST_REGEX_DETAIL_NS::test_not_newline : BOOST_REGEX_DETAIL_NS::test_newline); + // Disable match_any if requested in the state machine: + if(e.get_data().m_disable_match_any) + m_match_flags &= regex_constants::match_not_any; +} +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template +void perl_matcher::estimate_max_state_count(std::random_access_iterator_tag*) +{ + // + // How many states should we allow our machine to visit before giving up? + // This is a heuristic: it takes the greater of O(N^2) and O(NS^2) + // where N is the length of the string, and S is the number of states + // in the machine. It's tempting to up this to O(N^2S) or even O(N^2S^2) + // but these take unreasonably amounts of time to bale out in pathological + // cases. + // + // Calculate NS^2 first: + // + static const std::ptrdiff_t k = 100000; + std::ptrdiff_t dist = boost::BOOST_REGEX_DETAIL_NS::distance(base, last); + if(dist == 0) + dist = 1; + std::ptrdiff_t states = re.size(); + if(states == 0) + states = 1; + if ((std::numeric_limits::max)() / states < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= states; + if((std::numeric_limits::max)() / dist < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= dist; + if((std::numeric_limits::max)() - k < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states += k; + + max_state_count = states; + + // + // Now calculate N^2: + // + states = dist; + if((std::numeric_limits::max)() / dist < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= dist; + if((std::numeric_limits::max)() - k < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states += k; + // + // N^2 can be a very large number indeed, to prevent things getting out + // of control, cap the max states: + // + if(states > BOOST_REGEX_MAX_STATE_COUNT) + states = BOOST_REGEX_MAX_STATE_COUNT; + // + // If (the possibly capped) N^2 is larger than our first estimate, + // use this instead: + // + if(states > max_state_count) + max_state_count = states; +} + +template +inline void perl_matcher::estimate_max_state_count(void*) +{ + // we don't know how long the sequence is: + max_state_count = BOOST_REGEX_MAX_STATE_COUNT; +} + +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD +template +inline bool perl_matcher::protected_call( + protected_proc_type proc) +{ + ::boost::BOOST_REGEX_DETAIL_NS::concrete_protected_call + > + obj(this, proc); + return obj.execute(); + +} +#endif + +template +inline bool perl_matcher::match() +{ +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD + return protected_call(&perl_matcher::match_imp); +#else + return match_imp(); +#endif +} + +template +bool perl_matcher::match_imp() +{ + // initialise our stack if we are non-recursive: +#ifdef BOOST_REGEX_NON_RECURSIVE + save_state_init init(&m_stack_base, &m_backup_state); + used_block_count = BOOST_REGEX_MAX_BLOCKS; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif +#endif + + // reset our state machine: + position = base; + search_base = base; + state_count = 0; + m_match_flags |= regex_constants::match_all; + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), search_base, last); + m_presult->set_base(base); + m_presult->set_named_subs(this->re.get_named_subs()); + if(m_match_flags & match_posix) + m_result = *m_presult; + verify_options(re.flags(), m_match_flags); + if(0 == match_prefix()) + return false; + return (m_result[0].second == last) && (m_result[0].first == base); + +#if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif +} + +template +inline bool perl_matcher::find() +{ +#ifdef BOOST_REGEX_HAS_MS_STACK_GUARD + return protected_call(&perl_matcher::find_imp); +#else + return find_imp(); +#endif +} + +template +bool perl_matcher::find_imp() +{ + static matcher_proc_type const s_find_vtable[7] = + { + &perl_matcher::find_restart_any, + &perl_matcher::find_restart_word, + &perl_matcher::find_restart_line, + &perl_matcher::find_restart_buf, + &perl_matcher::match_prefix, + &perl_matcher::find_restart_lit, + &perl_matcher::find_restart_lit, + }; + + // initialise our stack if we are non-recursive: +#ifdef BOOST_REGEX_NON_RECURSIVE + save_state_init init(&m_stack_base, &m_backup_state); + used_block_count = BOOST_REGEX_MAX_BLOCKS; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif +#endif + + state_count = 0; + if((m_match_flags & regex_constants::match_init) == 0) + { + // reset our state machine: + search_base = position = base; + pstate = re.get_first_state(); + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), base, last); + m_presult->set_base(base); + m_presult->set_named_subs(this->re.get_named_subs()); + m_match_flags |= regex_constants::match_init; + } + else + { + // start again: + search_base = position = m_result[0].second; + // If last match was null and match_not_null was not set then increment + // our start position, otherwise we go into an infinite loop: + if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0)) + { + if(position == last) + return false; + else + ++position; + } + // reset $` start: + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), search_base, last); + //if((base != search_base) && (base == backstop)) + // m_match_flags |= match_prev_avail; + } + if(m_match_flags & match_posix) + { + m_result.set_size(static_cast(1u + re.mark_count()), base, last); + m_result.set_base(base); + } + + verify_options(re.flags(), m_match_flags); + // find out what kind of expression we have: + unsigned type = (m_match_flags & match_continuous) ? + static_cast(regbase::restart_continue) + : static_cast(re.get_restart_type()); + + // call the appropriate search routine: + matcher_proc_type proc = s_find_vtable[type]; + return (this->*proc)(); + +#if defined(BOOST_REGEX_NON_RECURSIVE) && !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif +} + +template +bool perl_matcher::match_prefix() +{ + m_has_partial_match = false; + m_has_found_match = false; + pstate = re.get_first_state(); + m_presult->set_first(position); + restart = position; + match_all_states(); + if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial)) + { + m_has_found_match = true; + m_presult->set_second(last, 0, false); + position = last; + if((m_match_flags & match_posix) == match_posix) + { + m_result.maybe_assign(*m_presult); + } + } +#ifdef BOOST_REGEX_MATCH_EXTRA + if(m_has_found_match && (match_extra & m_match_flags)) + { + // + // we have a match, reverse the capture information: + // + for(unsigned i = 0; i < m_presult->size(); ++i) + { + typename sub_match::capture_sequence_type & seq = ((*m_presult)[i]).get_captures(); + std::reverse(seq.begin(), seq.end()); + } + } +#endif + if(!m_has_found_match) + position = restart; // reset search postion +#ifdef BOOST_REGEX_RECURSIVE + m_can_backtrack = true; // reset for further searches +#endif + return m_has_found_match; +} + +template +bool perl_matcher::match_literal() +{ + unsigned int len = static_cast(pstate)->length; + const char_type* what = reinterpret_cast(static_cast(pstate) + 1); + // + // compare string with what we stored in + // our records: + for(unsigned int i = 0; i < len; ++i, ++position) + { + if((position == last) || (traits_inst.translate(*position, icase) != what[i])) + return false; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_start_line() +{ + if(position == backstop) + { + if((m_match_flags & match_prev_avail) == 0) + { + if((m_match_flags & match_not_bol) == 0) + { + pstate = pstate->next.p; + return true; + } + return false; + } + } + else if(m_match_flags & match_single_line) + return false; + + // check the previous value character: + BidiIterator t(position); + --t; + if(position != last) + { + if(is_separator(*t) && !((*t == static_cast('\r')) && (*position == static_cast('\n'))) ) + { + pstate = pstate->next.p; + return true; + } + } + else if(is_separator(*t)) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_end_line() +{ + if(position != last) + { + if(m_match_flags & match_single_line) + return false; + // we're not yet at the end so *first is always valid: + if(is_separator(*position)) + { + if((position != backstop) || (m_match_flags & match_prev_avail)) + { + // check that we're not in the middle of \r\n sequence + BidiIterator t(position); + --t; + if((*t == static_cast('\r')) && (*position == static_cast('\n'))) + { + return false; + } + } + pstate = pstate->next.p; + return true; + } + } + else if((m_match_flags & match_not_eol) == 0) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_wild() +{ + if(position == last) + return false; + if(is_separator(*position) && ((match_any_mask & static_cast(pstate)->mask) == 0)) + return false; + if((*position == char_type(0)) && (m_match_flags & match_not_dot_null)) + return false; + pstate = pstate->next.p; + ++position; + return true; +} + +template +bool perl_matcher::match_word_boundary() +{ + bool b; // indcates whether next character is a word character + if(position != last) + { + // prev and this character must be opposites: + b = traits_inst.isctype(*position, m_word_mask); + } + else + { + if (m_match_flags & match_not_eow) + return false; + b = false; + } + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + { + if(m_match_flags & match_not_bow) + return false; + else + b ^= false; + } + else + { + --position; + b ^= traits_inst.isctype(*position, m_word_mask); + ++position; + } + if(b) + { + pstate = pstate->next.p; + return true; + } + return false; // no match if we get to here... +} + +template +bool perl_matcher::match_within_word() +{ + if(position == last) + return false; + // both prev and this character must be m_word_mask: + bool prev = traits_inst.isctype(*position, m_word_mask); + { + bool b; + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + return false; + else + { + --position; + b = traits_inst.isctype(*position, m_word_mask); + ++position; + } + if(b == prev) + { + pstate = pstate->next.p; + return true; + } + } + return false; +} + +template +bool perl_matcher::match_word_start() +{ + if(position == last) + return false; // can't be starting a word if we're already at the end of input + if(!traits_inst.isctype(*position, m_word_mask)) + return false; // next character isn't a word character + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + { + if(m_match_flags & match_not_bow) + return false; // no previous input + } + else + { + // otherwise inside buffer: + BidiIterator t(position); + --t; + if(traits_inst.isctype(*t, m_word_mask)) + return false; // previous character not non-word + } + // OK we have a match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_word_end() +{ + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + return false; // start of buffer can't be end of word + BidiIterator t(position); + --t; + if(traits_inst.isctype(*t, m_word_mask) == false) + return false; // previous character wasn't a word character + + if(position == last) + { + if(m_match_flags & match_not_eow) + return false; // end of buffer but not end of word + } + else + { + // otherwise inside buffer: + if(traits_inst.isctype(*position, m_word_mask)) + return false; // next character is a word character + } + pstate = pstate->next.p; + return true; // if we fall through to here then we've succeeded +} + +template +bool perl_matcher::match_buffer_start() +{ + if((position != backstop) || (m_match_flags & match_not_bob)) + return false; + // OK match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_buffer_end() +{ + if((position != last) || (m_match_flags & match_not_eob)) + return false; + // OK match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_backref() +{ + // + // Compare with what we previously matched. + // Note that this succeeds if the backref did not partisipate + // in the match, this is in line with ECMAScript, but not Perl + // or PCRE. + // + int index = static_cast(pstate)->index; + if(index >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(index); + BOOST_REGEX_ASSERT(r.first != r.second); + do + { + index = r.first->index; + ++r.first; + }while((r.first != r.second) && ((*m_presult)[index].matched != true)); + } + + if((m_match_flags & match_perl) && !(*m_presult)[index].matched) + return false; + + BidiIterator i = (*m_presult)[index].first; + BidiIterator j = (*m_presult)[index].second; + while(i != j) + { + if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase))) + return false; + ++i; + ++position; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_long_set() +{ + typedef typename traits::char_class_type char_class_type; + // let the traits class do the work: + if(position == last) + return false; + BidiIterator t = re_is_set_member(position, last, static_cast*>(pstate), re.get_data(), icase); + if(t != position) + { + pstate = pstate->next.p; + position = t; + return true; + } + return false; +} + +template +bool perl_matcher::match_set() +{ + if(position == last) + return false; + if(static_cast(pstate)->_map[static_cast(traits_inst.translate(*position, icase))]) + { + pstate = pstate->next.p; + ++position; + return true; + } + return false; +} + +template +bool perl_matcher::match_jump() +{ + pstate = static_cast(pstate)->alt.p; + return true; +} + +template +bool perl_matcher::match_combining() +{ + if(position == last) + return false; + if(is_combining(traits_inst.translate(*position, icase))) + return false; + ++position; + while((position != last) && is_combining(traits_inst.translate(*position, icase))) + ++position; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_soft_buffer_end() +{ + if(m_match_flags & match_not_eob) + return false; + BidiIterator p(position); + while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p; + if(p != last) + return false; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_restart_continue() +{ + if(position == search_base) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_backstep() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + if( ::boost::is_random_access_iterator::value) + { + std::ptrdiff_t maxlen = ::boost::BOOST_REGEX_DETAIL_NS::distance(backstop, position); + if(maxlen < static_cast(pstate)->index) + return false; + std::advance(position, -static_cast(pstate)->index); + } + else + { + int c = static_cast(pstate)->index; + while(c--) + { + if(position == backstop) + return false; + --position; + } + } + pstate = pstate->next.p; + return true; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +inline bool perl_matcher::match_assert_backref() +{ + // return true if marked sub-expression N has been matched: + int index = static_cast(pstate)->index; + bool result = false; + if(index == 9999) + { + // Magic value for a (DEFINE) block: + return false; + } + else if(index > 0) + { + // Have we matched subexpression "index"? + // Check if index is a hash value: + if(index >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(index); + while(r.first != r.second) + { + if((*m_presult)[r.first->index].matched) + { + result = true; + break; + } + ++r.first; + } + } + else + { + result = (*m_presult)[index].matched; + } + pstate = pstate->next.p; + } + else + { + // Have we recursed into subexpression "index"? + // If index == 0 then check for any recursion at all, otherwise for recursion to -index-1. + int idx = -(index+1); + if(idx >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(idx); + int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx; + while(r.first != r.second) + { + result |= (stack_index == r.first->index); + if(result)break; + ++r.first; + } + } + else + { + result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0)); + } + pstate = pstate->next.p; + } + return result; +} + +template +bool perl_matcher::match_fail() +{ + // Just force a backtrack: + return false; +} + +template +bool perl_matcher::match_accept() +{ + if(!recursion_stack.empty()) + { + return skip_until_paren(recursion_stack.back().idx); + } + else + { + return skip_until_paren(INT_MAX); + } +} + +template +bool perl_matcher::find_restart_any() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + const unsigned char* _map = re.get_map(); + while(true) + { + // skip everything we can't match: + while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) ) + ++position; + if(position == last) + { + // run out of characters, try a null match if possible: + if(re.can_be_null()) + return match_prefix(); + break; + } + // now try and obtain a match: + if(match_prefix()) + return true; + if(position == last) + return false; + ++position; + } + return false; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::find_restart_word() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + // do search optimised for word starts: + const unsigned char* _map = re.get_map(); + if((m_match_flags & match_prev_avail) || (position != base)) + --position; + else if(match_prefix()) + return true; + do + { + while((position != last) && traits_inst.isctype(*position, m_word_mask)) + ++position; + while((position != last) && !traits_inst.isctype(*position, m_word_mask)) + ++position; + if(position == last) + break; + + if(can_start(*position, _map, (unsigned char)mask_any) ) + { + if(match_prefix()) + return true; + } + if(position == last) + break; + } while(true); + return false; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::find_restart_line() +{ + // do search optimised for line starts: + const unsigned char* _map = re.get_map(); + if(match_prefix()) + return true; + while(position != last) + { + while((position != last) && !is_separator(*position)) + ++position; + if(position == last) + return false; + ++position; + if(position == last) + { + if(re.can_be_null() && match_prefix()) + return true; + return false; + } + + if( can_start(*position, _map, (unsigned char)mask_any) ) + { + if(match_prefix()) + return true; + } + if(position == last) + return false; + //++position; + } + return false; +} + +template +bool perl_matcher::find_restart_buf() +{ + if((position == base) && ((m_match_flags & match_not_bob) == 0)) + return match_prefix(); + return false; +} + +template +bool perl_matcher::find_restart_lit() +{ +#if 0 + if(position == last) + return false; // can't possibly match if we're at the end already + + unsigned type = (m_match_flags & match_continuous) ? + static_cast(regbase::restart_continue) + : static_cast(re.get_restart_type()); + + const kmp_info* info = access::get_kmp(re); + int len = info->len; + const char_type* x = info->pstr; + int j = 0; + while (position != last) + { + while((j > -1) && (x[j] != traits_inst.translate(*position, icase))) + j = info->kmp_next[j]; + ++position; + ++j; + if(j >= len) + { + if(type == regbase::restart_fixed_lit) + { + std::advance(position, -j); + restart = position; + std::advance(restart, len); + m_result.set_first(position); + m_result.set_second(restart); + position = restart; + return true; + } + else + { + restart = position; + std::advance(position, -j); + if(match_prefix()) + return true; + else + { + for(int k = 0; (restart != position) && (k < j); ++k, --restart) + {} // dwa 10/20/2000 - warning suppression for MWCW + if(restart != last) + ++restart; + position = restart; + j = 0; //we could do better than this... + } + } + } + } + if((m_match_flags & match_partial) && (position == last) && j) + { + // we need to check for a partial match: + restart = position; + std::advance(position, -j); + return match_prefix(); + } +#endif + return false; +} + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_BORLANDC +# pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/perl_matcher_non_recursive.hpp b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_non_recursive.hpp new file mode 100644 index 0000000000..670efbab07 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_non_recursive.hpp @@ -0,0 +1,1947 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE perl_matcher_common.cpp + * VERSION see + * DESCRIPTION: Definitions of perl_matcher member functions that are + * specific to the non-recursive implementation. + */ + +#ifndef BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP +#define BOOST_REGEX_V4_PERL_MATCHER_NON_RECURSIVE_HPP + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4706) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +template +inline void inplace_destroy(T* p) +{ + (void)p; // warning suppression + p->~T(); +} + +struct saved_state +{ + union{ + unsigned int state_id; + // this padding ensures correct alignment on 64-bit platforms: + std::size_t padding1; + std::ptrdiff_t padding2; + void* padding3; + }; + saved_state(unsigned i) : state_id(i) {} +}; + +template +struct saved_matched_paren : public saved_state +{ + int index; + sub_match sub; + saved_matched_paren(int i, const sub_match& s) : saved_state(1), index(i), sub(s){} +}; + +template +struct saved_position : public saved_state +{ + const re_syntax_base* pstate; + BidiIterator position; + saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){} +}; + +template +struct saved_assertion : public saved_position +{ + bool positive; + saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos) + : saved_position(ps, pos, saved_type_assertion), positive(p){} +}; + +template +struct saved_repeater : public saved_state +{ + repeater_count count; + saved_repeater(int i, repeater_count** s, BidiIterator start, int current_recursion_id) + : saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){} +}; + +struct saved_extra_block : public saved_state +{ + saved_state *base, *end; + saved_extra_block(saved_state* b, saved_state* e) + : saved_state(saved_state_extra_block), base(b), end(e) {} +}; + +struct save_state_init +{ + saved_state** stack; + save_state_init(saved_state** base, saved_state** end) + : stack(base) + { + *base = static_cast(get_mem_block()); + *end = reinterpret_cast(reinterpret_cast(*base)+BOOST_REGEX_BLOCKSIZE); + --(*end); + (void) new (*end)saved_state(0); + BOOST_REGEX_ASSERT(*end > *base); + } + ~save_state_init() + { + put_mem_block(*stack); + *stack = 0; + } +}; + +template +struct saved_single_repeat : public saved_state +{ + std::size_t count; + const re_repeat* rep; + BidiIterator last_position; + saved_single_repeat(std::size_t c, const re_repeat* r, BidiIterator lp, int arg_id) + : saved_state(arg_id), count(c), rep(r), last_position(lp){} +}; + +template +struct saved_recursion : public saved_state +{ + saved_recursion(int idx, const re_syntax_base* p, Results* pr, Results* pr2) + : saved_state(14), recursion_id(idx), preturn_address(p), internal_results(*pr), prior_results(*pr2) {} + int recursion_id; + const re_syntax_base* preturn_address; + Results internal_results, prior_results; +}; + +struct saved_change_case : public saved_state +{ + bool icase; + saved_change_case(bool c) : saved_state(18), icase(c) {} +}; + +struct incrementer +{ + incrementer(unsigned* pu) : m_pu(pu) { ++*m_pu; } + ~incrementer() { --*m_pu; } + bool operator > (unsigned i) { return *m_pu > i; } +private: + unsigned* m_pu; +}; + +template +bool perl_matcher::match_all_states() +{ + static matcher_proc_type const s_match_vtable[34] = + { + (&perl_matcher::match_startmark), + &perl_matcher::match_endmark, + &perl_matcher::match_literal, + &perl_matcher::match_start_line, + &perl_matcher::match_end_line, + &perl_matcher::match_wild, + &perl_matcher::match_match, + &perl_matcher::match_word_boundary, + &perl_matcher::match_within_word, + &perl_matcher::match_word_start, + &perl_matcher::match_word_end, + &perl_matcher::match_buffer_start, + &perl_matcher::match_buffer_end, + &perl_matcher::match_backref, + &perl_matcher::match_long_set, + &perl_matcher::match_set, + &perl_matcher::match_jump, + &perl_matcher::match_alt, + &perl_matcher::match_rep, + &perl_matcher::match_combining, + &perl_matcher::match_soft_buffer_end, + &perl_matcher::match_restart_continue, + // Although this next line *should* be evaluated at compile time, in practice + // some compilers (VC++) emit run-time initialisation which breaks thread + // safety, so use a dispatch function instead: + //(::boost::is_random_access_iterator::value ? &perl_matcher::match_dot_repeat_fast : &perl_matcher::match_dot_repeat_slow), + &perl_matcher::match_dot_repeat_dispatch, + &perl_matcher::match_char_repeat, + &perl_matcher::match_set_repeat, + &perl_matcher::match_long_set_repeat, + &perl_matcher::match_backstep, + &perl_matcher::match_assert_backref, + &perl_matcher::match_toggle_case, + &perl_matcher::match_recursion, + &perl_matcher::match_fail, + &perl_matcher::match_accept, + &perl_matcher::match_commit, + &perl_matcher::match_then, + }; + incrementer inc(&m_recursions); + if(inc > 80) + raise_error(traits_inst, regex_constants::error_complexity); + push_recursion_stopper(); + do{ + while(pstate) + { + matcher_proc_type proc = s_match_vtable[pstate->type]; + ++state_count; + if(!(this->*proc)()) + { + if(state_count > max_state_count) + raise_error(traits_inst, regex_constants::error_complexity); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + bool successful_unwind = unwind(false); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(!successful_unwind) + return m_recursive_result; + } + } + }while(unwind(true)); + return m_recursive_result; +} + +template +void perl_matcher::extend_stack() +{ + if(used_block_count) + { + --used_block_count; + saved_state* stack_base; + saved_state* backup_state; + stack_base = static_cast(get_mem_block()); + backup_state = reinterpret_cast(reinterpret_cast(stack_base)+BOOST_REGEX_BLOCKSIZE); + saved_extra_block* block = static_cast(backup_state); + --block; + (void) new (block) saved_extra_block(m_stack_base, m_backup_state); + m_stack_base = stack_base; + m_backup_state = block; + } + else + raise_error(traits_inst, regex_constants::error_stack); +} + +template +inline void perl_matcher::push_matched_paren(int index, const sub_match& sub) +{ + //BOOST_REGEX_ASSERT(index); + saved_matched_paren* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_matched_paren(index, sub); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_case_change(bool c) +{ + //BOOST_REGEX_ASSERT(index); + saved_change_case* pmp = static_cast(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast(m_backup_state); + --pmp; + } + (void) new (pmp)saved_change_case(c); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_recursion_stopper() +{ + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(saved_type_recurse); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_assertion(const re_syntax_base* ps, bool positive) +{ + saved_assertion* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_assertion(positive, ps, position); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_alt(const re_syntax_base* ps) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_position(ps, position, saved_state_alt); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_non_greedy_repeat(const re_syntax_base* ps) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_position(ps, position, saved_state_non_greedy_long_repeat); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_repeater_count(int i, repeater_count** s) +{ + saved_repeater* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_repeater(i, s, position, this->recursion_stack.empty() ? (INT_MIN + 3) : this->recursion_stack.back().idx); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_single_repeat(c, r, last_position, state_id); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2) +{ + saved_recursion* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_recursion(idx, p, presults, presults2); + m_backup_state = pmp; +} + +template +bool perl_matcher::match_toggle_case() +{ + // change our case sensitivity: + push_case_change(this->icase); + this->icase = static_cast(pstate)->icase; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_startmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + switch(index) + { + case 0: + pstate = pstate->next.p; + break; + case -1: + case -2: + { + // forward lookahead assert: + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + push_assertion(next_pstate, index == -1); + break; + } + case -3: + { + // independent sub-expression, currently this is always recursive: + bool old_independent = m_independent; + m_independent = true; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + bool r = false; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + r = match_all_states(); + if(!r && !m_independent) + { + // Must be unwinding from a COMMIT/SKIP/PRUNE and the independent + // sub failed, need to unwind everything else: + while(unwind(false)); + return false; + } +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)) {} + throw; + } +#endif + pstate = next_pstate; + m_independent = old_independent; +#ifdef BOOST_REGEX_MATCH_EXTRA + if(r && (m_match_flags & match_extra)) + { + // + // our captures have been stored in *m_presult + // we need to unpack them, and insert them + // back in the right order when we unwind the stack: + // + match_results temp_match(*m_presult); + unsigned i; + for(i = 0; i < temp_match.size(); ++i) + (*m_presult)[i].get_captures().clear(); + // match everything else: +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + r = match_all_states(); +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)) {} + throw; + } +#endif + // now place the stored captures back: + for(i = 0; i < temp_match.size(); ++i) + { + typedef typename sub_match::capture_sequence_type seq; + seq& s1 = (*m_presult)[i].get_captures(); + const seq& s2 = temp_match[i].captures(); + s1.insert( + s1.end(), + s2.begin(), + s2.end()); + } + } +#endif + return r; + } + case -4: + { + // conditional expression: + const re_alt* alt = static_cast(pstate->next.p); + BOOST_REGEX_ASSERT(alt->type == syntax_element_alt); + pstate = alt->next.p; + if(pstate->type == syntax_element_assert_backref) + { + if(!match_assert_backref()) + pstate = alt->alt.p; + break; + } + else + { + // zero width assertion, have to match this recursively: + BOOST_REGEX_ASSERT(pstate->type == syntax_element_startmark); + bool negated = static_cast(pstate)->index == -2; + BidiIterator saved_position = position; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + bool r = match_all_states(); + position = saved_position; + if(negated) + r = !r; + if(r) + pstate = next_pstate; + else + pstate = alt->alt.p; +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif + break; + } + } + case -5: + { + push_matched_paren(0, (*m_presult)[0]); + m_presult->set_first(position, 0, true); + pstate = pstate->next.p; + break; + } + default: + { + BOOST_REGEX_ASSERT(index > 0); + if((m_match_flags & match_nosubs) == 0) + { + push_matched_paren(index, (*m_presult)[index]); + m_presult->set_first(position, index); + } + pstate = pstate->next.p; + break; + } + } + return true; +} + +template +bool perl_matcher::match_alt() +{ + bool take_first, take_second; + const re_alt* jmp = static_cast(pstate); + + // find out which of these two alternatives we need to take: + if(position == last) + { + take_first = jmp->can_be_null & mask_take; + take_second = jmp->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, jmp->_map, (unsigned char)mask_take); + take_second = can_start(*position, jmp->_map, (unsigned char)mask_skip); + } + + if(take_first) + { + // we can take the first alternative, + // see if we need to push next alternative: + if(take_second) + { + push_alt(jmp->alt.p); + } + pstate = pstate->next.p; + return true; + } + if(take_second) + { + pstate = jmp->alt.p; + return true; + } + return false; // neither option is possible +} + +template +bool perl_matcher::match_rep() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127 4244) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + + // find out which of these two alternatives we need to take: + bool take_first, take_second; + if(position == last) + { + take_first = rep->can_be_null & mask_take; + take_second = rep->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, rep->_map, (unsigned char)mask_take); + take_second = can_start(*position, rep->_map, (unsigned char)mask_skip); + } + + if((m_backup_state->state_id != saved_state_repeater_count) + || (static_cast*>(m_backup_state)->count.get_id() != rep->state_id) + || (next_count->get_id() != rep->state_id)) + { + // we're moving to a different repeat from the last + // one, so set up a counter object: + push_repeater_count(rep->state_id, &next_count); + } + // + // If we've had at least one repeat already, and the last one + // matched the NULL string then set the repeat count to + // maximum: + // + next_count->check_null_repeat(position, rep->max); + + if(next_count->get_count() < rep->min) + { + // we must take the repeat: + if(take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + return false; + } + + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // try and take the repeat if we can: + if((next_count->get_count() < rep->max) && take_first) + { + if(take_second) + { + // store position in case we fail: + push_alt(rep->alt.p); + } + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + else if(take_second) + { + pstate = rep->alt.p; + return true; + } + return false; // can't take anything, fail... + } + else // non-greedy + { + // try and skip the repeat if we can: + if(take_second) + { + if((next_count->get_count() < rep->max) && take_first) + { + // store position in case we fail: + push_non_greedy_repeat(rep->next.p); + } + pstate = rep->alt.p; + return true; + } + if((next_count->get_count() < rep->max) && take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + } + return false; +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_dot_repeat_slow() +{ + std::size_t count = 0; + const re_repeat* rep = static_cast(pstate); + re_syntax_base* psingle = rep->next.p; + // match compulsory repeats first: + while(count < rep->min) + { + pstate = psingle; + if(!match_wild()) + return false; + ++count; + } + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // repeat for as long as we can: + while(count < rep->max) + { + pstate = psingle; + if(!match_wild()) + break; + ++count; + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_slow_dot); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +} + +template +bool perl_matcher::match_dot_repeat_fast() +{ + if(m_match_flags & match_not_dot_null) + return match_dot_repeat_slow(); + if((static_cast(pstate->next.p)->mask & match_any_mask) == 0) + return match_dot_repeat_slow(); + + const re_repeat* rep = static_cast(pstate); + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t count = static_cast((std::min)(static_cast(::boost::BOOST_REGEX_DETAIL_NS::distance(position, last)), greedy ? rep->max : rep->min)); + if(rep->min > count) + { + position = last; + return false; // not enough text left to match + } + std::advance(position, count); + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_fast_dot); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +} + +template +bool perl_matcher::match_char_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + BOOST_REGEX_ASSERT(1 == static_cast(rep->next.p)->length); + const char_type what = *reinterpret_cast(static_cast(rep->next.p) + 1); + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : ::boost::BOOST_REGEX_DETAIL_NS::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && (traits_inst.translate(*position, icase) == what)) + { + ++position; + } + count = (unsigned)::boost::BOOST_REGEX_DETAIL_NS::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what)) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_char); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_set_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + const unsigned char* map = static_cast(rep->next.p)->_map; + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : ::boost::BOOST_REGEX_DETAIL_NS::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + } + count = (unsigned)::boost::BOOST_REGEX_DETAIL_NS::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_short_set); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_long_set_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + typedef typename traits::char_class_type m_type; + const re_repeat* rep = static_cast(pstate); + const re_set_long* set = static_cast*>(pstate->next.p); + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : ::boost::BOOST_REGEX_DETAIL_NS::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + } + count = (unsigned)::boost::BOOST_REGEX_DETAIL_NS::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_long_set); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_recursion() +{ + BOOST_REGEX_ASSERT(pstate->type == syntax_element_recurse); + // + // See if we've seen this recursion before at this location, if we have then + // we need to prevent infinite recursion: + // + for(typename std::vector >::reverse_iterator i = recursion_stack.rbegin(); i != recursion_stack.rend(); ++i) + { + if(i->idx == static_cast(static_cast(pstate)->alt.p)->index) + { + if(i->location_of_start == position) + return false; + break; + } + } + // + // Backup call stack: + // + push_recursion_pop(); + // + // Set new call stack: + // + if(recursion_stack.capacity() == 0) + { + recursion_stack.reserve(50); + } + recursion_stack.push_back(recursion_info()); + recursion_stack.back().preturn_address = pstate->next.p; + recursion_stack.back().results = *m_presult; + pstate = static_cast(pstate)->alt.p; + recursion_stack.back().idx = static_cast(pstate)->index; + recursion_stack.back().location_of_start = position; + //if(static_cast(pstate)->state_id > 0) + { + push_repeater_count(-(2 + static_cast(pstate)->index), &next_count); + } + + return true; +} + +template +bool perl_matcher::match_endmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + if(index > 0) + { + if((m_match_flags & match_nosubs) == 0) + { + m_presult->set_second(position, index); + } + if(!recursion_stack.empty()) + { + if(index == recursion_stack.back().idx) + { + pstate = recursion_stack.back().preturn_address; + *m_presult = recursion_stack.back().results; + push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results); + recursion_stack.pop_back(); + push_repeater_count(-(2 + index), &next_count); + } + } + } + else if((index < 0) && (index != -4)) + { + // matched forward lookahead: + pstate = 0; + return true; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_match() +{ + if(!recursion_stack.empty()) + { + BOOST_REGEX_ASSERT(0 == recursion_stack.back().idx); + pstate = recursion_stack.back().preturn_address; + push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results); + *m_presult = recursion_stack.back().results; + recursion_stack.pop_back(); + return true; + } + if((m_match_flags & match_not_null) && (position == (*m_presult)[0].first)) + return false; + if((m_match_flags & match_all) && (position != last)) + return false; + if((m_match_flags & regex_constants::match_not_initial_null) && (position == search_base)) + return false; + m_presult->set_second(position); + pstate = 0; + m_has_found_match = true; + if((m_match_flags & match_posix) == match_posix) + { + m_result.maybe_assign(*m_presult); + if((m_match_flags & match_any) == 0) + return false; + } +#ifdef BOOST_REGEX_MATCH_EXTRA + if(match_extra & m_match_flags) + { + for(unsigned i = 0; i < m_presult->size(); ++i) + if((*m_presult)[i].matched) + ((*m_presult)[i]).get_captures().push_back((*m_presult)[i]); + } +#endif + return true; +} + +template +bool perl_matcher::match_commit() +{ + // Ideally we would just junk all the states that are on the stack, + // however we might not unwind correctly in that case, so for now, + // just mark that we don't backtrack into whatever is left (or rather + // we'll unwind it unconditionally without pausing to try other matches). + + switch(static_cast(pstate)->action) + { + case commit_commit: + restart = last; + break; + case commit_skip: + if(base != position) + { + restart = position; + // Have to decrement restart since it will get incremented again later: + --restart; + } + break; + case commit_prune: + break; + } + + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(16); + m_backup_state = pmp; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_then() +{ + // Just leave a mark that we need to skip to next alternative: + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(17); + m_backup_state = pmp; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::skip_until_paren(int index, bool have_match) +{ + while(pstate) + { + if(pstate->type == syntax_element_endmark) + { + if(static_cast(pstate)->index == index) + { + if(have_match) + return this->match_endmark(); + pstate = pstate->next.p; + return true; + } + else + { + // Unenclosed closing ), occurs when (*ACCEPT) is inside some other + // parenthesis which may or may not have other side effects associated with it. + const re_syntax_base* sp = pstate; + match_endmark(); + if(!pstate) + { + unwind(true); + // unwind may leave pstate NULL if we've unwound a forward lookahead, in which + // case just move to the next state and keep looking... + if (!pstate) + pstate = sp->next.p; + } + } + continue; + } + else if(pstate->type == syntax_element_match) + return true; + else if(pstate->type == syntax_element_startmark) + { + int idx = static_cast(pstate)->index; + pstate = pstate->next.p; + skip_until_paren(idx, false); + continue; + } + pstate = pstate->next.p; + } + return true; +} + +/**************************************************************************** + +Unwind and associated procedures follow, these perform what normal stack +unwinding does in the recursive implementation. + +****************************************************************************/ + +template +bool perl_matcher::unwind(bool have_match) +{ + static unwind_proc_type const s_unwind_table[19] = + { + &perl_matcher::unwind_end, + &perl_matcher::unwind_paren, + &perl_matcher::unwind_recursion_stopper, + &perl_matcher::unwind_assertion, + &perl_matcher::unwind_alt, + &perl_matcher::unwind_repeater_counter, + &perl_matcher::unwind_extra_block, + &perl_matcher::unwind_greedy_single_repeat, + &perl_matcher::unwind_slow_dot_repeat, + &perl_matcher::unwind_fast_dot_repeat, + &perl_matcher::unwind_char_repeat, + &perl_matcher::unwind_short_set_repeat, + &perl_matcher::unwind_long_set_repeat, + &perl_matcher::unwind_non_greedy_repeat, + &perl_matcher::unwind_recursion, + &perl_matcher::unwind_recursion_pop, + &perl_matcher::unwind_commit, + &perl_matcher::unwind_then, + &perl_matcher::unwind_case, + }; + + m_recursive_result = have_match; + m_unwound_lookahead = false; + m_unwound_alt = false; + unwind_proc_type unwinder; + bool cont; + // + // keep unwinding our stack until we have something to do: + // + do + { + unwinder = s_unwind_table[m_backup_state->state_id]; + cont = (this->*unwinder)(m_recursive_result); + }while(cont); + // + // return true if we have more states to try: + // + return pstate ? true : false; +} + +template +bool perl_matcher::unwind_end(bool) +{ + pstate = 0; // nothing left to search + return false; // end of stack nothing more to search +} + +template +bool perl_matcher::unwind_case(bool) +{ + saved_change_case* pmp = static_cast(m_backup_state); + icase = pmp->icase; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +bool perl_matcher::unwind_paren(bool have_match) +{ + saved_matched_paren* pmp = static_cast*>(m_backup_state); + // restore previous values if no match was found: + if(!have_match) + { + m_presult->set_first(pmp->sub.first, pmp->index, pmp->index == 0); + m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched, pmp->index == 0); + } +#ifdef BOOST_REGEX_MATCH_EXTRA + // + // we have a match, push the capture information onto the stack: + // + else if(pmp->sub.matched && (match_extra & m_match_flags)) + ((*m_presult)[pmp->index]).get_captures().push_back(pmp->sub); +#endif + // unwind stack: + m_backup_state = pmp+1; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp); + return true; // keep looking +} + +template +bool perl_matcher::unwind_recursion_stopper(bool) +{ + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + pstate = 0; // nothing left to search + return false; // end of stack nothing more to search +} + +template +bool perl_matcher::unwind_assertion(bool r) +{ + saved_assertion* pmp = static_cast*>(m_backup_state); + pstate = pmp->pstate; + position = pmp->position; + bool result = (r == pmp->positive); + m_recursive_result = pmp->positive ? r : !r; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + m_unwound_lookahead = true; + return !result; // return false if the assertion was matched to stop search. +} + +template +bool perl_matcher::unwind_alt(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + pstate = pmp->pstate; + position = pmp->position; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + m_unwound_alt = !r; + return r; +} + +template +bool perl_matcher::unwind_repeater_counter(bool) +{ + ++used_block_count; + saved_repeater* pmp = static_cast*>(m_backup_state); + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; // keep looking +} + +template +bool perl_matcher::unwind_extra_block(bool) +{ + saved_extra_block* pmp = static_cast(m_backup_state); + void* condemmed = m_stack_base; + m_stack_base = pmp->base; + m_backup_state = pmp->end; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp); + put_mem_block(condemmed); + return true; // keep looking +} + +template +inline void perl_matcher::destroy_single_repeat() +{ + saved_single_repeat* p = static_cast*>(m_backup_state); + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(p++); + m_backup_state = p; +} + +template +bool perl_matcher::unwind_greedy_single_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + + count -= rep->min; + + if((m_match_flags & match_partial) && (position == last)) + m_has_partial_match = true; + + BOOST_REGEX_ASSERT(count); + position = pmp->last_position; + + // backtrack till we can skip out: + do + { + --position; + --count; + ++state_count; + }while(count && !can_start(*position, rep->_map, mask_skip)); + + // if we've hit base, destroy this state: + if(count == 0) + { + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count + rep->min; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_slow_dot_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + BOOST_REGEX_ASSERT(rep->type == syntax_element_dot_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_wild); + + BOOST_REGEX_ASSERT(count < rep->max); + pstate = rep->next.p; + position = pmp->last_position; + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(!match_wild()) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_fast_dot_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + + BOOST_REGEX_ASSERT(count < rep->max); + position = pmp->last_position; + if(position != last) + { + + // wind forward until we can skip out of the repeat: + do + { + ++position; + ++count; + ++state_count; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_char_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const char_type what = *reinterpret_cast(static_cast(pstate) + 1); + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_char_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_literal); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(traits_inst.translate(*position, icase) != what) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++ position; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_short_set_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const unsigned char* map = static_cast(rep->next.p)->_map; + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_short_set_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_set); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(!map[static_cast(traits_inst.translate(*position, icase))]) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++ position; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_long_set_repeat(bool r) +{ + typedef typename traits::char_class_type m_type; + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const re_set_long* set = static_cast*>(pstate); + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_long_set_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_long_set); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(position == re_is_set_member(position, last, set, re.get_data(), icase)) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++position; + ++count; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_non_greedy_repeat(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + position = pmp->position; + pstate = pmp->pstate; + ++(*next_count); + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return r; +} + +template +bool perl_matcher::unwind_recursion(bool r) +{ + // We are backtracking back inside a recursion, need to push the info + // back onto the recursion stack, and do so unconditionally, otherwise + // we can get mismatched pushes and pops... + saved_recursion* pmp = static_cast*>(m_backup_state); + if (!r) + { + recursion_stack.push_back(recursion_info()); + recursion_stack.back().idx = pmp->recursion_id; + recursion_stack.back().preturn_address = pmp->preturn_address; + recursion_stack.back().results = pmp->prior_results; + recursion_stack.back().location_of_start = position; + *m_presult = pmp->internal_results; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +bool perl_matcher::unwind_recursion_pop(bool r) +{ + // Backtracking out of a recursion, we must pop state off the recursion + // stack unconditionally to ensure matched pushes and pops: + saved_state* pmp = static_cast(m_backup_state); + if (!r && !recursion_stack.empty()) + { + *m_presult = recursion_stack.back().results; + position = recursion_stack.back().location_of_start; + recursion_stack.pop_back(); + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +void perl_matcher::push_recursion_pop() +{ + saved_state* pmp = static_cast(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast(m_backup_state); + --pmp; + } + (void) new (pmp)saved_state(15); + m_backup_state = pmp; +} + +template +bool perl_matcher::unwind_commit(bool b) +{ + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + while(unwind(b) && !m_unwound_lookahead){} + if(m_unwound_lookahead && pstate) + { + // + // If we stop because we just unwound an assertion, put the + // commit state back on the stack again: + // + m_unwound_lookahead = false; + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(16); + m_backup_state = pmp; + } + // This prevents us from stopping when we exit from an independent sub-expression: + m_independent = false; + return false; +} + +template +bool perl_matcher::unwind_then(bool b) +{ + // Unwind everything till we hit an alternative: + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + bool result = false; + while((result = unwind(b)) && !m_unwound_alt){} + // We're now pointing at the next alternative, need one more backtrack + // since *all* the other alternatives must fail once we've reached a THEN clause: + if(result && m_unwound_alt) + unwind(b); + return false; +} + +/* +template +bool perl_matcher::unwind_parenthesis_pop(bool r) +{ + saved_state* pmp = static_cast(m_backup_state); + if(!r) + { + --parenthesis_stack_position; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +void perl_matcher::push_parenthesis_pop() +{ + saved_state* pmp = static_cast(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast(m_backup_state); + --pmp; + } + (void) new (pmp)saved_state(16); + m_backup_state = pmp; +} + +template +bool perl_matcher::unwind_parenthesis_push(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + parenthesis_stack[parenthesis_stack_position++] = pmp->position; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +inline void perl_matcher::push_parenthesis_push(BidiIterator p) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_position(0, p, 17); + m_backup_state = pmp; +} +*/ +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/perl_matcher_recursive.hpp b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_recursive.hpp new file mode 100644 index 0000000000..7d262fe2f2 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/perl_matcher_recursive.hpp @@ -0,0 +1,1131 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE perl_matcher_common.cpp + * VERSION see + * DESCRIPTION: Definitions of perl_matcher member functions that are + * specific to the recursive implementation. + */ + +#ifndef BOOST_REGEX_V4_PERL_MATCHER_RECURSIVE_HPP +#define BOOST_REGEX_V4_PERL_MATCHER_RECURSIVE_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4800) +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +template +class backup_subex +{ + int index; + sub_match sub; +public: + template + backup_subex(const match_results& w, int i) + : index(i), sub(w[i], false) {} + template + void restore(match_results& w) + { + w.set_first(sub.first, index, index == 0); + w.set_second(sub.second, index, sub.matched, index == 0); + } + const sub_match& get() { return sub; } +}; + +template +bool perl_matcher::match_all_states() +{ + static matcher_proc_type const s_match_vtable[34] = + { + (&perl_matcher::match_startmark), + &perl_matcher::match_endmark, + &perl_matcher::match_literal, + &perl_matcher::match_start_line, + &perl_matcher::match_end_line, + &perl_matcher::match_wild, + &perl_matcher::match_match, + &perl_matcher::match_word_boundary, + &perl_matcher::match_within_word, + &perl_matcher::match_word_start, + &perl_matcher::match_word_end, + &perl_matcher::match_buffer_start, + &perl_matcher::match_buffer_end, + &perl_matcher::match_backref, + &perl_matcher::match_long_set, + &perl_matcher::match_set, + &perl_matcher::match_jump, + &perl_matcher::match_alt, + &perl_matcher::match_rep, + &perl_matcher::match_combining, + &perl_matcher::match_soft_buffer_end, + &perl_matcher::match_restart_continue, + // Although this next line *should* be evaluated at compile time, in practice + // some compilers (VC++) emit run-time initialisation which breaks thread + // safety, so use a dispatch function instead: + //(::boost::is_random_access_iterator::value ? &perl_matcher::match_dot_repeat_fast : &perl_matcher::match_dot_repeat_slow), + &perl_matcher::match_dot_repeat_dispatch, + &perl_matcher::match_char_repeat, + &perl_matcher::match_set_repeat, + &perl_matcher::match_long_set_repeat, + &perl_matcher::match_backstep, + &perl_matcher::match_assert_backref, + &perl_matcher::match_toggle_case, + &perl_matcher::match_recursion, + &perl_matcher::match_fail, + &perl_matcher::match_accept, + &perl_matcher::match_commit, + &perl_matcher::match_then, + }; + + if(state_count > max_state_count) + raise_error(traits_inst, regex_constants::error_complexity); + while(pstate) + { + matcher_proc_type proc = s_match_vtable[pstate->type]; + ++state_count; + if(!(this->*proc)()) + { + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + return 0; + } + } + return true; +} + +template +bool perl_matcher::match_startmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + bool r = true; + switch(index) + { + case 0: + pstate = pstate->next.p; + break; + case -1: + case -2: + { + // forward lookahead assert: + BidiIterator old_position(position); + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + r = match_all_states(); + pstate = next_pstate; + position = old_position; + if((r && (index != -1)) || (!r && (index != -2))) + r = false; + else + r = true; + if(r && m_have_accept) + r = skip_until_paren(INT_MAX); + break; + } + case -3: + { + // independent sub-expression: + bool old_independent = m_independent; + m_independent = true; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + bool can_backtrack = m_can_backtrack; + r = match_all_states(); + if(r) + m_can_backtrack = can_backtrack; + pstate = next_pstate; + m_independent = old_independent; +#ifdef BOOST_REGEX_MATCH_EXTRA + if(r && (m_match_flags & match_extra)) + { + // + // our captures have been stored in *m_presult + // we need to unpack them, and insert them + // back in the right order when we unwind the stack: + // + unsigned i; + match_results tm(*m_presult); + for(i = 0; i < tm.size(); ++i) + (*m_presult)[i].get_captures().clear(); + // match everything else: + r = match_all_states(); + // now place the stored captures back: + for(i = 0; i < tm.size(); ++i) + { + typedef typename sub_match::capture_sequence_type seq; + seq& s1 = (*m_presult)[i].get_captures(); + const seq& s2 = tm[i].captures(); + s1.insert( + s1.end(), + s2.begin(), + s2.end()); + } + } +#endif + if(r && m_have_accept) + r = skip_until_paren(INT_MAX); + break; + } + case -4: + { + // conditional expression: + const re_alt* alt = static_cast(pstate->next.p); + BOOST_REGEX_ASSERT(alt->type == syntax_element_alt); + pstate = alt->next.p; + if(pstate->type == syntax_element_assert_backref) + { + if(!match_assert_backref()) + pstate = alt->alt.p; + break; + } + else + { + // zero width assertion, have to match this recursively: + BOOST_REGEX_ASSERT(pstate->type == syntax_element_startmark); + bool negated = static_cast(pstate)->index == -2; + BidiIterator saved_position = position; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + bool res = match_all_states(); + position = saved_position; + if(negated) + res = !res; + if(res) + pstate = next_pstate; + else + pstate = alt->alt.p; + break; + } + } + case -5: + { + // Reset start of $0, since we have a \K escape + backup_subex sub(*m_presult, 0); + m_presult->set_first(position, 0, true); + pstate = pstate->next.p; + r = match_all_states(); + if(r == false) + sub.restore(*m_presult); + break; + } + default: + { + BOOST_REGEX_ASSERT(index > 0); + if((m_match_flags & match_nosubs) == 0) + { + backup_subex sub(*m_presult, index); + m_presult->set_first(position, index); + pstate = pstate->next.p; + r = match_all_states(); + if(r == false) + sub.restore(*m_presult); +#ifdef BOOST_REGEX_MATCH_EXTRA + // + // we have a match, push the capture information onto the stack: + // + else if(sub.get().matched && (match_extra & m_match_flags)) + ((*m_presult)[index]).get_captures().push_back(sub.get()); +#endif + } + else + { + pstate = pstate->next.p; + } + break; + } + } + return r; +} + +template +bool perl_matcher::match_alt() +{ + bool take_first, take_second; + const re_alt* jmp = static_cast(pstate); + + // find out which of these two alternatives we need to take: + if(position == last) + { + take_first = jmp->can_be_null & mask_take; + take_second = jmp->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, jmp->_map, (unsigned char)mask_take); + take_second = can_start(*position, jmp->_map, (unsigned char)mask_skip); + } + + if(take_first) + { + // we can take the first alternative, + // see if we need to push next alternative: + if(take_second) + { + BidiIterator oldposition(position); + const re_syntax_base* old_pstate = jmp->alt.p; + pstate = pstate->next.p; + bool oldcase = icase; + m_have_then = false; + if(!match_all_states()) + { + pstate = old_pstate; + position = oldposition; + icase = oldcase; + if(m_have_then) + { + m_can_backtrack = true; + m_have_then = false; + return false; + } + } + m_have_then = false; + return m_can_backtrack; + } + pstate = pstate->next.p; + return true; + } + if(take_second) + { + pstate = jmp->alt.p; + return true; + } + return false; // neither option is possible +} + +template +bool perl_matcher::match_rep() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127 4244) +#endif + const re_repeat* rep = static_cast(pstate); + // + // Always copy the repeat count, so that the state is restored + // when we exit this scope: + // + repeater_count r(rep->state_id, &next_count, position, this->recursion_stack.size() ? this->recursion_stack.back().idx : INT_MIN + 3); + // + // If we've had at least one repeat already, and the last one + // matched the NULL string then set the repeat count to + // maximum: + // + next_count->check_null_repeat(position, rep->max); + + // find out which of these two alternatives we need to take: + bool take_first, take_second; + if(position == last) + { + take_first = rep->can_be_null & mask_take; + take_second = rep->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, rep->_map, (unsigned char)mask_take); + take_second = can_start(*position, rep->_map, (unsigned char)mask_skip); + } + + if(next_count->get_count() < rep->min) + { + // we must take the repeat: + if(take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return match_all_states(); + } + return false; + } + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // try and take the repeat if we can: + if((next_count->get_count() < rep->max) && take_first) + { + // store position in case we fail: + BidiIterator pos = position; + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + if(match_all_states()) + return true; + if(!m_can_backtrack) + return false; + // failed repeat, reset posistion and fall through for alternative: + position = pos; + } + if(take_second) + { + pstate = rep->alt.p; + return true; + } + return false; // can't take anything, fail... + } + else // non-greedy + { + // try and skip the repeat if we can: + if(take_second) + { + // store position in case we fail: + BidiIterator pos = position; + pstate = rep->alt.p; + if(match_all_states()) + return true; + if(!m_can_backtrack) + return false; + // failed alternative, reset posistion and fall through for repeat: + position = pos; + } + if((next_count->get_count() < rep->max) && take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return match_all_states(); + } + } + return false; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_dot_repeat_slow() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + std::size_t count = 0; + const re_repeat* rep = static_cast(pstate); + re_syntax_base* psingle = rep->next.p; + // match compulsary repeats first: + while(count < rep->min) + { + pstate = psingle; + if(!match_wild()) + return false; + ++count; + } + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // normal repeat: + while(count < rep->max) + { + pstate = psingle; + if(!match_wild()) + break; + ++count; + } + if((rep->leading) && (count < rep->max)) + restart = position; + pstate = rep; + return backtrack_till_match(count - rep->min); + } + else + { + // non-greedy, keep trying till we get a match: + BidiIterator save_pos; + do + { + if((rep->leading) && (rep->max == UINT_MAX)) + restart = position; + pstate = rep->alt.p; + save_pos = position; + ++state_count; + if(match_all_states()) + return true; + if((count >= rep->max) || !m_can_backtrack) + return false; + ++count; + pstate = psingle; + position = save_pos; + if(!match_wild()) + return false; + }while(true); + } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_dot_repeat_fast() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + if(m_match_flags & match_not_dot_null) + return match_dot_repeat_slow(); + if((static_cast(pstate->next.p)->mask & match_any_mask) == 0) + return match_dot_repeat_slow(); + // + // start by working out how much we can skip: + // + const re_repeat* rep = static_cast(pstate); +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4267) +#endif + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t count = (std::min)(static_cast(::boost::BOOST_REGEX_DETAIL_NS::distance(position, last)), greedy ? rep->max : rep->min); + if(rep->min > count) + { + position = last; + return false; // not enough text left to match + } + std::advance(position, count); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + if((rep->leading) && (count < rep->max) && greedy) + restart = position; + if(greedy) + return backtrack_till_match(count - rep->min); + + // non-greedy, keep trying till we get a match: + BidiIterator save_pos; + do + { + while((position != last) && (count < rep->max) && !can_start(*position, rep->_map, mask_skip)) + { + ++position; + ++count; + } + if((rep->leading) && (rep->max == UINT_MAX)) + restart = position; + pstate = rep->alt.p; + save_pos = position; + ++state_count; + if(match_all_states()) + return true; + if((count >= rep->max) || !m_can_backtrack) + return false; + if(save_pos == last) + return false; + position = ++save_pos; + ++count; + }while(true); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_char_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#pragma warning(disable:4267) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + BOOST_REGEX_ASSERT(1 == static_cast(rep->next.p)->length); + const char_type what = *reinterpret_cast(static_cast(rep->next.p) + 1); + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t count, desired; + if(::boost::is_random_access_iterator::value) + { + desired = + (std::min)( + (std::size_t)(greedy ? rep->max : rep->min), + (std::size_t)::boost::BOOST_REGEX_DETAIL_NS::distance(position, last)); + count = desired; + ++desired; + if(icase) + { + while(--desired && (traits_inst.translate_nocase(*position) == what)) + { + ++position; + } + } + else + { + while(--desired && (traits_inst.translate(*position) == what)) + { + ++position; + } + } + count = count - desired; + } + else + { + count = 0; + desired = greedy ? rep->max : rep->min; + while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what)) + { + ++position; + ++count; + } + } + if((rep->leading) && (count < rep->max) && greedy) + restart = position; + if(count < rep->min) + return false; + + if(greedy) + return backtrack_till_match(count - rep->min); + + // non-greedy, keep trying till we get a match: + BidiIterator save_pos; + do + { + while((position != last) && (count < rep->max) && !can_start(*position, rep->_map, mask_skip)) + { + if((traits_inst.translate(*position, icase) == what)) + { + ++position; + ++count; + } + else + return false; // counldn't repeat even though it was the only option + } + if((rep->leading) && (rep->max == UINT_MAX)) + restart = position; + pstate = rep->alt.p; + save_pos = position; + ++state_count; + if(match_all_states()) + return true; + if((count >= rep->max) || !m_can_backtrack) + return false; + position = save_pos; + if(position == last) + return false; + if(traits_inst.translate(*position, icase) == what) + { + ++position; + ++count; + } + else + { + return false; + } + }while(true); +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_set_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + const unsigned char* map = static_cast(rep->next.p)->_map; + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : ::boost::BOOST_REGEX_DETAIL_NS::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + } + count = (unsigned)::boost::BOOST_REGEX_DETAIL_NS::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + ++count; + } + } + if((rep->leading) && (count < rep->max) && greedy) + restart = position; + if(count < rep->min) + return false; + + if(greedy) + return backtrack_till_match(count - rep->min); + + // non-greedy, keep trying till we get a match: + BidiIterator save_pos; + do + { + while((position != last) && (count < rep->max) && !can_start(*position, rep->_map, mask_skip)) + { + if(map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + ++count; + } + else + return false; // counldn't repeat even though it was the only option + } + if((rep->leading) && (rep->max == UINT_MAX)) + restart = position; + pstate = rep->alt.p; + save_pos = position; + ++state_count; + if(match_all_states()) + return true; + if((count >= rep->max) || !m_can_backtrack) + return false; + position = save_pos; + if(position == last) + return false; + if(map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + ++count; + } + else + { + return false; + } + }while(true); +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_long_set_repeat() +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + typedef typename traits::char_class_type char_class_type; + const re_repeat* rep = static_cast(pstate); + const re_set_long* set = static_cast*>(pstate->next.p); + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : ::boost::BOOST_REGEX_DETAIL_NS::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + } + count = (unsigned)::boost::BOOST_REGEX_DETAIL_NS::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + ++count; + } + } + if((rep->leading) && (count < rep->max) && greedy) + restart = position; + if(count < rep->min) + return false; + + if(greedy) + return backtrack_till_match(count - rep->min); + + // non-greedy, keep trying till we get a match: + BidiIterator save_pos; + do + { + while((position != last) && (count < rep->max) && !can_start(*position, rep->_map, mask_skip)) + { + if(position != re_is_set_member(position, last, set, re.get_data(), icase)) + { + ++position; + ++count; + } + else + return false; // counldn't repeat even though it was the only option + } + if((rep->leading) && (rep->max == UINT_MAX)) + restart = position; + pstate = rep->alt.p; + save_pos = position; + ++state_count; + if(match_all_states()) + return true; + if((count >= rep->max) || !m_can_backtrack) + return false; + position = save_pos; + if(position == last) + return false; + if(position != re_is_set_member(position, last, set, re.get_data(), icase)) + { + ++position; + ++count; + } + else + { + return false; + } + }while(true); +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::backtrack_till_match(std::size_t count) +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + if(!m_can_backtrack) + return false; + if((m_match_flags & match_partial) && (position == last)) + m_has_partial_match = true; + + const re_repeat* rep = static_cast(pstate); + BidiIterator backtrack = position; + if(position == last) + { + if(rep->can_be_null & mask_skip) + { + pstate = rep->alt.p; + if(match_all_states()) + return true; + } + if(count) + { + position = --backtrack; + --count; + } + else + return false; + } + do + { + while(count && !can_start(*position, rep->_map, mask_skip)) + { + --position; + --count; + ++state_count; + } + pstate = rep->alt.p; + backtrack = position; + if(match_all_states()) + return true; + if(count == 0) + return false; + position = --backtrack; + ++state_count; + --count; + }while(true); +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_recursion() +{ + BOOST_REGEX_ASSERT(pstate->type == syntax_element_recurse); + // + // Set new call stack: + // + if(recursion_stack.capacity() == 0) + { + recursion_stack.reserve(50); + } + // + // See if we've seen this recursion before at this location, if we have then + // we need to prevent infinite recursion: + // + for(typename std::vector >::reverse_iterator i = recursion_stack.rbegin(); i != recursion_stack.rend(); ++i) + { + if(i->idx == static_cast(static_cast(pstate)->alt.p)->index) + { + if(i->location_of_start == position) + return false; + break; + } + } + // + // Now get on with it: + // + recursion_stack.push_back(recursion_info()); + recursion_stack.back().preturn_address = pstate->next.p; + recursion_stack.back().results = *m_presult; + recursion_stack.back().repeater_stack = next_count; + recursion_stack.back().location_of_start = position; + pstate = static_cast(pstate)->alt.p; + recursion_stack.back().idx = static_cast(pstate)->index; + + repeater_count* saved = next_count; + repeater_count r(&next_count); // resets all repeat counts since we're recursing and starting fresh on those + next_count = &r; + bool can_backtrack = m_can_backtrack; + bool result = match_all_states(); + m_can_backtrack = can_backtrack; + next_count = saved; + + if(!result) + { + next_count = recursion_stack.back().repeater_stack; + *m_presult = recursion_stack.back().results; + recursion_stack.pop_back(); + return false; + } + return true; +} + +template +bool perl_matcher::match_endmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + if(index > 0) + { + if((m_match_flags & match_nosubs) == 0) + { + m_presult->set_second(position, index); + } + if(!recursion_stack.empty()) + { + if(index == recursion_stack.back().idx) + { + recursion_info saved = recursion_stack.back(); + recursion_stack.pop_back(); + pstate = saved.preturn_address; + repeater_count* saved_count = next_count; + next_count = saved.repeater_stack; + *m_presult = saved.results; + if(!match_all_states()) + { + recursion_stack.push_back(saved); + next_count = saved_count; + return false; + } + } + } + } + else if((index < 0) && (index != -4)) + { + // matched forward lookahead: + pstate = 0; + return true; + } + pstate = pstate ? pstate->next.p : 0; + return true; +} + +template +bool perl_matcher::match_match() +{ + if(!recursion_stack.empty()) + { + BOOST_REGEX_ASSERT(0 == recursion_stack.back().idx); + const re_syntax_base* saved_state = pstate = recursion_stack.back().preturn_address; + *m_presult = recursion_stack.back().results; + recursion_stack.pop_back(); + if(!match_all_states()) + { + recursion_stack.push_back(recursion_info()); + recursion_stack.back().preturn_address = saved_state; + recursion_stack.back().results = *m_presult; + recursion_stack.back().location_of_start = position; + return false; + } + return true; + } + if((m_match_flags & match_not_null) && (position == (*m_presult)[0].first)) + return false; + if((m_match_flags & match_all) && (position != last)) + return false; + if((m_match_flags & regex_constants::match_not_initial_null) && (position == search_base)) + return false; + m_presult->set_second(position); + pstate = 0; + m_has_found_match = true; + if((m_match_flags & match_posix) == match_posix) + { + m_result.maybe_assign(*m_presult); + if((m_match_flags & match_any) == 0) + return false; + } +#ifdef BOOST_REGEX_MATCH_EXTRA + if(match_extra & m_match_flags) + { + for(unsigned i = 0; i < m_presult->size(); ++i) + if((*m_presult)[i].matched) + ((*m_presult)[i]).get_captures().push_back((*m_presult)[i]); + } +#endif + return true; +} + +template +bool perl_matcher::match_commit() +{ + m_can_backtrack = false; + int action = static_cast(pstate)->action; + switch(action) + { + case commit_commit: + restart = last; + break; + case commit_skip: + restart = position; + break; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_then() +{ + pstate = pstate->next.p; + if(match_all_states()) + return true; + m_can_backtrack = false; + m_have_then = true; + return false; +} + +template +bool perl_matcher::match_toggle_case() +{ + // change our case sensitivity: + bool oldcase = this->icase; + this->icase = static_cast(pstate)->icase; + pstate = pstate->next.p; + bool result = match_all_states(); + this->icase = oldcase; + return result; +} + + + +template +bool perl_matcher::skip_until_paren(int index, bool have_match) +{ + while(pstate) + { + if(pstate->type == syntax_element_endmark) + { + if(static_cast(pstate)->index == index) + { + if(have_match) + return this->match_endmark(); + pstate = pstate->next.p; + return true; + } + else + { + // Unenclosed closing ), occurs when (*ACCEPT) is inside some other + // parenthesis which may or may not have other side effects associated with it. + bool r = match_endmark(); + m_have_accept = true; + if(!pstate) + return r; + } + continue; + } + else if(pstate->type == syntax_element_match) + return true; + else if(pstate->type == syntax_element_startmark) + { + int idx = static_cast(pstate)->index; + pstate = pstate->next.p; + skip_until_paren(idx, false); + continue; + } + pstate = pstate->next.p; + } + return true; +} + + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/primary_transform.hpp b/third-party/boost_regex/include/boost/regex/v4/primary_transform.hpp new file mode 100644 index 0000000000..47d172aa80 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/primary_transform.hpp @@ -0,0 +1,146 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: primary_transform.hpp + * VERSION: see + * DESCRIPTION: Heuristically determines the sort string format in use + * by the current locale. + */ + +#ifndef BOOST_REGEX_PRIMARY_TRANSFORM +#define BOOST_REGEX_PRIMARY_TRANSFORM + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ + namespace BOOST_REGEX_DETAIL_NS{ + + +enum{ + sort_C, + sort_fixed, + sort_delim, + sort_unknown +}; + +template +unsigned count_chars(const S& s, charT c) +{ + // + // Count how many occurrences of character c occur + // in string s: if c is a delimeter between collation + // fields, then this should be the same value for all + // sort keys: + // + unsigned int count = 0; + for(unsigned pos = 0; pos < s.size(); ++pos) + { + if(s[pos] == c) ++count; + } + return count; +} + + +template +unsigned find_sort_syntax(const traits* pt, charT* delim) +{ + // + // compare 'a' with 'A' to see how similar they are, + // should really use a-accute but we can't portably do that, + // + typedef typename traits::string_type string_type; + typedef typename traits::char_type char_type; + + // Suppress incorrect warning for MSVC + (void)pt; + + char_type a[2] = {'a', '\0', }; + string_type sa(pt->transform(a, a+1)); + if(sa == a) + { + *delim = 0; + return sort_C; + } + char_type A[2] = { 'A', '\0', }; + string_type sA(pt->transform(A, A+1)); + char_type c[2] = { ';', '\0', }; + string_type sc(pt->transform(c, c+1)); + + int pos = 0; + while((pos <= static_cast(sa.size())) && (pos <= static_cast(sA.size())) && (sa[pos] == sA[pos])) ++pos; + --pos; + if(pos < 0) + { + *delim = 0; + return sort_unknown; + } + // + // at this point sa[pos] is either the end of a fixed width field + // or the character that acts as a delimiter: + // + charT maybe_delim = sa[pos]; + if((pos != 0) && (count_chars(sa, maybe_delim) == count_chars(sA, maybe_delim)) && (count_chars(sa, maybe_delim) == count_chars(sc, maybe_delim))) + { + *delim = maybe_delim; + return sort_delim; + } + // + // OK doen't look like a delimiter, try for fixed width field: + // + if((sa.size() == sA.size()) && (sa.size() == sc.size())) + { + // note assumes that the fixed width field is less than + // (numeric_limits::max)(), should be true for all types + // I can't imagine 127 character fields... + *delim = static_cast(++pos); + return sort_fixed; + } + // + // don't know what it is: + // + *delim = 0; + return sort_unknown; +} + + + } // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/protected_call.hpp b/third-party/boost_regex/include/boost/regex/v4/protected_call.hpp new file mode 100644 index 0000000000..451b2e34bd --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/protected_call.hpp @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_creator.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_creator which fills in + * the data members of a regex_data object. + */ + +#ifndef BOOST_REGEX_V4_PROTECTED_CALL_HPP +#define BOOST_REGEX_V4_PROTECTED_CALL_HPP + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +class BOOST_REGEX_DECL abstract_protected_call +{ +public: + bool BOOST_REGEX_CALL execute()const; + // this stops gcc-4 from complaining: + virtual ~abstract_protected_call(){} +private: + virtual bool call()const = 0; +}; + +template +class concrete_protected_call + : public abstract_protected_call +{ +public: + typedef bool (T::*proc_type)(); + concrete_protected_call(T* o, proc_type p) + : obj(o), proc(p) {} +private: + bool call()const BOOST_OVERRIDE; + T* obj; + proc_type proc; +}; + +template +bool concrete_protected_call::call()const +{ + return (obj->*proc)(); +} + +} +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/regbase.hpp b/third-party/boost_regex/include/boost/regex/v4/regbase.hpp new file mode 100644 index 0000000000..2b737d5aba --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regbase.hpp @@ -0,0 +1,180 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regbase.cpp + * VERSION see + * DESCRIPTION: Declares class regbase. + */ + +#ifndef BOOST_REGEX_V4_REGBASE_HPP +#define BOOST_REGEX_V4_REGBASE_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +// +// class regbase +// handles error codes and flags +// +class BOOST_REGEX_DECL regbase +{ +public: + enum flag_type_ + { + // + // Divide the flags up into logical groups: + // bits 0-7 indicate main synatx type. + // bits 8-15 indicate syntax subtype. + // bits 16-31 indicate options that are common to all + // regex syntaxes. + // In all cases the default is 0. + // + // Main synatx group: + // + perl_syntax_group = 0, // default + basic_syntax_group = 1, // POSIX basic + literal = 2, // all characters are literals + main_option_type = literal | basic_syntax_group | perl_syntax_group, // everything! + // + // options specific to perl group: + // + no_bk_refs = 1 << 8, // \d not allowed + no_perl_ex = 1 << 9, // disable perl extensions + no_mod_m = 1 << 10, // disable Perl m modifier + mod_x = 1 << 11, // Perl x modifier + mod_s = 1 << 12, // force s modifier on (overrides match_not_dot_newline) + no_mod_s = 1 << 13, // force s modifier off (overrides match_not_dot_newline) + + // + // options specific to basic group: + // + no_char_classes = 1 << 8, // [[:CLASS:]] not allowed + no_intervals = 1 << 9, // {x,y} not allowed + bk_plus_qm = 1 << 10, // uses \+ and \? + bk_vbar = 1 << 11, // use \| for alternatives + emacs_ex = 1 << 12, // enables emacs extensions + + // + // options common to all groups: + // + no_escape_in_lists = 1 << 16, // '\' not special inside [...] + newline_alt = 1 << 17, // \n is the same as | + no_except = 1 << 18, // no exception on error + failbit = 1 << 19, // error flag + icase = 1 << 20, // characters are matched regardless of case + nocollate = 0, // don't use locale specific collation (deprecated) + collate = 1 << 21, // use locale specific collation + nosubs = 1 << 22, // don't mark sub-expressions + save_subexpression_location = 1 << 23, // save subexpression locations + no_empty_expressions = 1 << 24, // no empty expressions allowed + optimize = 0, // not really supported + + + + basic = basic_syntax_group | collate | no_escape_in_lists, + extended = no_bk_refs | collate | no_perl_ex | no_escape_in_lists, + normal = 0, + emacs = basic_syntax_group | collate | emacs_ex | bk_vbar, + awk = no_bk_refs | collate | no_perl_ex, + grep = basic | newline_alt, + egrep = extended | newline_alt, + sed = basic, + perl = normal, + ECMAScript = normal, + JavaScript = normal, + JScript = normal + }; + typedef unsigned int flag_type; + + enum restart_info + { + restart_any = 0, + restart_word = 1, + restart_line = 2, + restart_buf = 3, + restart_continue = 4, + restart_lit = 5, + restart_fixed_lit = 6, + restart_count = 7 + }; +}; + +// +// provide std lib proposal compatible constants: +// +namespace regex_constants{ + + enum flag_type_ + { + + no_except = ::boost::regbase::no_except, + failbit = ::boost::regbase::failbit, + literal = ::boost::regbase::literal, + icase = ::boost::regbase::icase, + nocollate = ::boost::regbase::nocollate, + collate = ::boost::regbase::collate, + nosubs = ::boost::regbase::nosubs, + optimize = ::boost::regbase::optimize, + bk_plus_qm = ::boost::regbase::bk_plus_qm, + bk_vbar = ::boost::regbase::bk_vbar, + no_intervals = ::boost::regbase::no_intervals, + no_char_classes = ::boost::regbase::no_char_classes, + no_escape_in_lists = ::boost::regbase::no_escape_in_lists, + no_mod_m = ::boost::regbase::no_mod_m, + mod_x = ::boost::regbase::mod_x, + mod_s = ::boost::regbase::mod_s, + no_mod_s = ::boost::regbase::no_mod_s, + save_subexpression_location = ::boost::regbase::save_subexpression_location, + no_empty_expressions = ::boost::regbase::no_empty_expressions, + + basic = ::boost::regbase::basic, + extended = ::boost::regbase::extended, + normal = ::boost::regbase::normal, + emacs = ::boost::regbase::emacs, + awk = ::boost::regbase::awk, + grep = ::boost::regbase::grep, + egrep = ::boost::regbase::egrep, + sed = basic, + perl = normal, + ECMAScript = normal, + JavaScript = normal, + JScript = normal + }; + typedef ::boost::regbase::flag_type syntax_option_type; + +} // namespace regex_constants + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex.hpp b/third-party/boost_regex/include/boost/regex/v4/regex.hpp new file mode 100644 index 0000000000..e8ce7e5e05 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex.hpp @@ -0,0 +1,166 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex.cpp + * VERSION see + * DESCRIPTION: Declares boost::basic_regex<> and associated + * functions and classes. This header is the main + * entry point for the template regex code. + */ + +#ifndef BOOST_RE_REGEX_HPP_INCLUDED +#define BOOST_RE_REGEX_HPP_INCLUDED + +#ifdef __cplusplus + +// what follows is all C++ don't include in C builds!! + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif +#ifndef BOOST_REGEX_WORKAROUND_HPP +#include +#endif + +#ifndef BOOST_REGEX_FWD_HPP +#include +#endif +#ifndef BOOST_REGEX_TRAITS_HPP +#include +#endif +#ifndef BOOST_REGEX_RAW_BUFFER_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_MATCH_FLAGS +#include +#endif +#ifndef BOOST_REGEX_RAW_BUFFER_HPP +#include +#endif +#ifndef BOOST_RE_PAT_EXCEPT_HPP +#include +#endif + +#ifndef BOOST_REGEX_V4_CHAR_REGEX_TRAITS_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_STATES_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_REGBASE_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_ITERATOR_TRAITS_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_BASIC_REGEX_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_BASIC_REGEX_CREATOR_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_BASIC_REGEX_PARSER_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_SUB_MATCH_HPP +#include +#endif +#ifndef BOOST_REGEX_FORMAT_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_MATCH_RESULTS_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_PROTECTED_CALL_HPP +#include +#endif +#ifndef BOOST_REGEX_MATCHER_HPP +#include +#endif + + +namespace boost{ +#ifdef BOOST_REGEX_NO_FWD +typedef basic_regex > regex; +#ifndef BOOST_NO_WREGEX +typedef basic_regex > wregex; +#endif +#endif + +typedef match_results cmatch; +typedef match_results smatch; +#ifndef BOOST_NO_WREGEX +typedef match_results wcmatch; +typedef match_results wsmatch; +#endif + +} // namespace boost +#ifndef BOOST_REGEX_MATCH_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_REGEX_SEARCH_HPP +#include +#endif +#ifndef BOOST_REGEX_ITERATOR_HPP +#include +#endif +#ifndef BOOST_REGEX_TOKEN_ITERATOR_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_REGEX_GREP_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_REGEX_REPLACE_HPP +#include +#endif +#ifndef BOOST_REGEX_V4_REGEX_MERGE_HPP +#include +#endif +#ifndef BOOST_REGEX_SPLIT_HPP +#include +#endif + +#endif // __cplusplus + +#endif // include + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_format.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_format.hpp new file mode 100644 index 0000000000..9401fa30de --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_format.hpp @@ -0,0 +1,1158 @@ +/* + * + * Copyright (c) 1998-2009 John Maddock + * Copyright 2008 Eric Niebler. + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_FORMAT_HPP +#define BOOST_REGEX_FORMAT_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef BOOST_NO_SFINAE +#include +#endif +#include + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// +// Forward declaration: +// + template >::allocator_type > +class match_results; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// struct trivial_format_traits: +// defines minimum localisation support for formatting +// in the case that the actual regex traits is unavailable. +// +template +struct trivial_format_traits +{ + typedef charT char_type; + + static std::ptrdiff_t length(const charT* p) + { + return global_length(p); + } + static charT tolower(charT c) + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c); + } + static charT toupper(charT c) + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c); + } + static int value(const charT c, int radix) + { + int result = global_value(c); + return result >= radix ? -1 : result; + } + int toi(const charT*& p1, const charT* p2, int radix)const + { + return (int)global_toi(p1, p2, radix, *this); + } +}; + +#ifdef BOOST_MSVC +# pragma warning(push) +#pragma warning(disable:26812) +#endif +template +class basic_regex_formatter +{ +public: + typedef typename traits::char_type char_type; + basic_regex_formatter(OutputIterator o, const Results& r, const traits& t) + : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {} + OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f); + OutputIterator format(ForwardIter p1, match_flag_type f) + { + return format(p1, p1 + m_traits.length(p1), f); + } +private: + typedef typename Results::value_type sub_match_type; + enum output_state + { + output_copy, + output_next_lower, + output_next_upper, + output_lower, + output_upper, + output_none + }; + + void put(char_type c); + void put(const sub_match_type& sub); + void format_all(); + void format_perl(); + void format_escape(); + void format_conditional(); + void format_until_scope_end(); + bool handle_perl_verb(bool have_brace); + + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::false_&) + { + std::vector v(i, j); + return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size()) + : this->m_results.named_subexpression(static_cast(0), static_cast(0)); + } + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const mpl::true_&) + { + return this->m_results.named_subexpression(i, j); + } + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j) + { + typedef typename boost::is_convertible::type tag_type; + return get_named_sub(i, j, tag_type()); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::false_&) + { + std::vector v(i, j); + return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size()) + : this->m_results.named_subexpression_index(static_cast(0), static_cast(0)); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j, const mpl::true_&) + { + return this->m_results.named_subexpression_index(i, j); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j) + { + typedef typename boost::is_convertible::type tag_type; + return get_named_sub_index(i, j, tag_type()); + } +#ifdef BOOST_MSVC + // msvc-8.0 issues a spurious warning on the call to std::advance here: +#pragma warning(push) +#pragma warning(disable:4244) +#endif + inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::false_&) + { + if(i != j) + { + std::vector v(i, j); + const char_type* start = &v[0]; + const char_type* pos = start; + int r = (int)m_traits.toi(pos, &v[0] + v.size(), base); + std::advance(i, pos - start); + return r; + } + return -1; + } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + inline int toi(ForwardIter& i, ForwardIter j, int base, const boost::mpl::true_&) + { + return m_traits.toi(i, j, base); + } + inline int toi(ForwardIter& i, ForwardIter j, int base) + { +#if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210)) + // Workaround for Intel support issue #656654. + // See also https://svn.boost.org/trac/boost/ticket/6359 + return toi(i, j, base, mpl::false_()); +#else + typedef typename boost::is_convertible::type tag_type; + return toi(i, j, base, tag_type()); +#endif + } + + const traits& m_traits; // the traits class for localised formatting operations + const Results& m_results; // the match_results being used. + OutputIterator m_out; // where to send output. + ForwardIter m_position; // format string, current position + ForwardIter m_end; // format string end + match_flag_type m_flags; // format flags to use + output_state m_state; // what to do with the next character + output_state m_restore_state; // what state to restore to. + bool m_have_conditional; // we are parsing a conditional +private: + basic_regex_formatter(const basic_regex_formatter&); + basic_regex_formatter& operator=(const basic_regex_formatter&); +}; +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +template +OutputIterator basic_regex_formatter::format(ForwardIter p1, ForwardIter p2, match_flag_type f) +{ + m_position = p1; + m_end = p2; + m_flags = f; + format_all(); + return m_out; +} + +template +void basic_regex_formatter::format_all() +{ + // over and over: + while(m_position != m_end) + { + switch(*m_position) + { + case '&': + if(m_flags & ::boost::regex_constants::format_sed) + { + ++m_position; + put(m_results[0]); + break; + } + put(*m_position++); + break; + case '\\': + format_escape(); + break; + case '(': + if(m_flags & boost::regex_constants::format_all) + { + ++m_position; + bool have_conditional = m_have_conditional; + m_have_conditional = false; + format_until_scope_end(); + m_have_conditional = have_conditional; + if(m_position == m_end) + return; + BOOST_REGEX_ASSERT(*m_position == static_cast(')')); + ++m_position; // skip the closing ')' + break; + } + put(*m_position); + ++m_position; + break; + case ')': + if(m_flags & boost::regex_constants::format_all) + { + return; + } + put(*m_position); + ++m_position; + break; + case ':': + if((m_flags & boost::regex_constants::format_all) && m_have_conditional) + { + return; + } + put(*m_position); + ++m_position; + break; + case '?': + if(m_flags & boost::regex_constants::format_all) + { + ++m_position; + format_conditional(); + break; + } + put(*m_position); + ++m_position; + break; + case '$': + if((m_flags & format_sed) == 0) + { + format_perl(); + break; + } + // not a special character: + BOOST_FALLTHROUGH; + default: + put(*m_position); + ++m_position; + break; + } + } +} + +template +void basic_regex_formatter::format_perl() +{ + // + // On entry *m_position points to a '$' character + // output the information that goes with it: + // + BOOST_REGEX_ASSERT(*m_position == '$'); + // + // see if this is a trailing '$': + // + if(++m_position == m_end) + { + --m_position; + put(*m_position); + ++m_position; + return; + } + // + // OK find out what kind it is: + // + bool have_brace = false; + ForwardIter save_position = m_position; + switch(*m_position) + { + case '&': + ++m_position; + put(this->m_results[0]); + break; + case '`': + ++m_position; + put(this->m_results.prefix()); + break; + case '\'': + ++m_position; + put(this->m_results.suffix()); + break; + case '$': + put(*m_position++); + break; + case '+': + if((++m_position != m_end) && (*m_position == '{')) + { + ForwardIter base = ++m_position; + while((m_position != m_end) && (*m_position != '}')) ++m_position; + if(m_position != m_end) + { + // Named sub-expression: + put(get_named_sub(base, m_position)); + ++m_position; + break; + } + else + { + m_position = --base; + } + } + put((this->m_results)[this->m_results.size() > 1 ? static_cast(this->m_results.size() - 1) : 1]); + break; + case '{': + have_brace = true; + ++m_position; + BOOST_FALLTHROUGH; + default: + // see if we have a number: + { + std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end); + //len = (std::min)(static_cast(2), len); + int v = this->toi(m_position, m_position + len, 10); + if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}')))) + { + // Look for a Perl-5.10 verb: + if(!handle_perl_verb(have_brace)) + { + // leave the $ as is, and carry on: + m_position = --save_position; + put(*m_position); + ++m_position; + } + break; + } + // otherwise output sub v: + put(this->m_results[v]); + if(have_brace) + ++m_position; + } + } +} + +template +bool basic_regex_formatter::handle_perl_verb(bool have_brace) +{ + // + // We may have a capitalised string containing a Perl action: + // + static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' }; + static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' }; + static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' }; + static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' }; + static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' }; + static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' }; + + if(m_position == m_end) + return false; + if(have_brace && (*m_position == '^')) + ++m_position; + + std::ptrdiff_t max_len = m_end - m_position; + + if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH)) + { + m_position += 5; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 5; + return false; + } + } + put(this->m_results[0]); + return true; + } + if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH)) + { + m_position += 8; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 8; + return false; + } + } + put(this->m_results.prefix()); + return true; + } + if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH)) + { + m_position += 9; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 9; + return false; + } + } + put(this->m_results.suffix()); + return true; + } + if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH)) + { + m_position += 16; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 16; + return false; + } + } + put((this->m_results)[this->m_results.size() > 1 ? static_cast(this->m_results.size() - 1) : 1]); + return true; + } + if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT)) + { + m_position += 20; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 20; + return false; + } + } + put(this->m_results.get_last_closed_paren()); + return true; + } + if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT)) + { + m_position += 2; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 2; + return false; + } + } + put(this->m_results.get_last_closed_paren()); + return true; + } + return false; +} + +template +void basic_regex_formatter::format_escape() +{ + // skip the escape and check for trailing escape: + if(++m_position == m_end) + { + put(static_cast('\\')); + return; + } + // now switch on the escape type: + switch(*m_position) + { + case 'a': + put(static_cast('\a')); + ++m_position; + break; + case 'f': + put(static_cast('\f')); + ++m_position; + break; + case 'n': + put(static_cast('\n')); + ++m_position; + break; + case 'r': + put(static_cast('\r')); + ++m_position; + break; + case 't': + put(static_cast('\t')); + ++m_position; + break; + case 'v': + put(static_cast('\v')); + ++m_position; + break; + case 'x': + if(++m_position == m_end) + { + put(static_cast('x')); + return; + } + // maybe have \x{ddd} + if(*m_position == static_cast('{')) + { + ++m_position; + int val = this->toi(m_position, m_end, 16); + if(val < 0) + { + // invalid value treat everything as literals: + put(static_cast('x')); + put(static_cast('{')); + return; + } + if((m_position == m_end) || (*m_position != static_cast('}'))) + { + --m_position; + while(*m_position != static_cast('\\')) + --m_position; + ++m_position; + put(*m_position++); + return; + } + ++m_position; + put(static_cast(val)); + return; + } + else + { + std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end); + len = (std::min)(static_cast(2), len); + int val = this->toi(m_position, m_position + len, 16); + if(val < 0) + { + --m_position; + put(*m_position++); + return; + } + put(static_cast(val)); + } + break; + case 'c': + if(++m_position == m_end) + { + --m_position; + put(*m_position++); + return; + } + put(static_cast(*m_position++ % 32)); + break; + case 'e': + put(static_cast(27)); + ++m_position; + break; + default: + // see if we have a perl specific escape: + if((m_flags & boost::regex_constants::format_sed) == 0) + { + bool breakout = false; + switch(*m_position) + { + case 'l': + ++m_position; + m_restore_state = m_state; + m_state = output_next_lower; + breakout = true; + break; + case 'L': + ++m_position; + m_state = output_lower; + breakout = true; + break; + case 'u': + ++m_position; + m_restore_state = m_state; + m_state = output_next_upper; + breakout = true; + break; + case 'U': + ++m_position; + m_state = output_upper; + breakout = true; + break; + case 'E': + ++m_position; + m_state = output_copy; + breakout = true; + break; + } + if(breakout) + break; + } + // see if we have a \n sed style backreference: + std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end); + len = (std::min)(static_cast(1), len); + int v = this->toi(m_position, m_position+len, 10); + if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed))) + { + put(m_results[v]); + break; + } + else if(v == 0) + { + // octal ecape sequence: + --m_position; + len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end); + len = (std::min)(static_cast(4), len); + v = this->toi(m_position, m_position + len, 8); + BOOST_REGEX_ASSERT(v >= 0); + put(static_cast(v)); + break; + } + // Otherwise output the character "as is": + put(*m_position++); + break; + } +} + +template +void basic_regex_formatter::format_conditional() +{ + if(m_position == m_end) + { + // oops trailing '?': + put(static_cast('?')); + return; + } + int v; + if(*m_position == '{') + { + ForwardIter base = m_position; + ++m_position; + v = this->toi(m_position, m_end, 10); + if(v < 0) + { + // Try a named subexpression: + while((m_position != m_end) && (*m_position != '}')) + ++m_position; + v = this->get_named_sub_index(base + 1, m_position); + } + if((v < 0) || (*m_position != '}')) + { + m_position = base; + // oops trailing '?': + put(static_cast('?')); + return; + } + // Skip trailing '}': + ++m_position; + } + else + { + std::ptrdiff_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance(m_position, m_end); + len = (std::min)(static_cast(2), len); + v = this->toi(m_position, m_position + len, 10); + } + if(v < 0) + { + // oops not a number: + put(static_cast('?')); + return; + } + + // output varies depending upon whether sub-expression v matched or not: + if(m_results[v].matched) + { + m_have_conditional = true; + format_all(); + m_have_conditional = false; + if((m_position != m_end) && (*m_position == static_cast(':'))) + { + // skip the ':': + ++m_position; + // save output state, then turn it off: + output_state saved_state = m_state; + m_state = output_none; + // format the rest of this scope: + format_until_scope_end(); + // restore output state: + m_state = saved_state; + } + } + else + { + // save output state, then turn it off: + output_state saved_state = m_state; + m_state = output_none; + // format until ':' or ')': + m_have_conditional = true; + format_all(); + m_have_conditional = false; + // restore state: + m_state = saved_state; + if((m_position != m_end) && (*m_position == static_cast(':'))) + { + // skip the ':': + ++m_position; + // format the rest of this scope: + format_until_scope_end(); + } + } +} + +template +void basic_regex_formatter::format_until_scope_end() +{ + do + { + format_all(); + if((m_position == m_end) || (*m_position == static_cast(')'))) + return; + put(*m_position++); + }while(m_position != m_end); +} + +template +void basic_regex_formatter::put(char_type c) +{ + // write a single character to output + // according to which case translation mode we are in: + switch(this->m_state) + { + case output_none: + return; + case output_next_lower: + c = m_traits.tolower(c); + this->m_state = m_restore_state; + break; + case output_next_upper: + c = m_traits.toupper(c); + this->m_state = m_restore_state; + break; + case output_lower: + c = m_traits.tolower(c); + break; + case output_upper: + c = m_traits.toupper(c); + break; + default: + break; + } + *m_out = c; + ++m_out; +} + +template +void basic_regex_formatter::put(const sub_match_type& sub) +{ + typedef typename sub_match_type::iterator iterator_type; + iterator_type i = sub.first; + while(i != sub.second) + { + put(*i); + ++i; + } +} + +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; + } + + typedef std::ptrdiff_t difference_type; + typedef typename S::value_type value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::output_iterator_tag iterator_category; +}; + +template +OutputIterator regex_format_imp(OutputIterator out, + const match_results& m, + ForwardIter p1, ForwardIter p2, + match_flag_type flags, + const traits& t + ) +{ + if(flags & regex_constants::format_literal) + { + return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out); + } + + BOOST_REGEX_DETAIL_NS::basic_regex_formatter< + OutputIterator, + match_results, + traits, ForwardIter> f(out, m, t); + return f.format(p1, p2, flags); +} + +#ifndef BOOST_NO_SFINAE + +BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator) + +struct any_type +{ + template + any_type(const T&); + template + any_type(const T&, const U&); + template + any_type(const T&, const U&, const V&); +}; +typedef char no_type; +typedef char (&unary_type)[2]; +typedef char (&binary_type)[3]; +typedef char (&ternary_type)[4]; + +no_type check_is_formatter(unary_type, binary_type, ternary_type); +template +unary_type check_is_formatter(T const &, binary_type, ternary_type); +template +binary_type check_is_formatter(unary_type, T const &, ternary_type); +template +binary_type check_is_formatter(T const &, U const &, ternary_type); +template +ternary_type check_is_formatter(unary_type, binary_type, T const &); +template +ternary_type check_is_formatter(T const &, binary_type, U const &); +template +ternary_type check_is_formatter(unary_type, T const &, U const &); +template +ternary_type check_is_formatter(T const &, U const &, V const &); + +struct unary_binary_ternary +{ + typedef unary_type (*unary_fun)(any_type); + typedef binary_type (*binary_fun)(any_type, any_type); + typedef ternary_type (*ternary_fun)(any_type, any_type, any_type); + operator unary_fun(); + operator binary_fun(); + operator ternary_fun(); +}; + +template::value> +struct formatter_wrapper + : Formatter + , unary_binary_ternary +{ + formatter_wrapper(){} +}; + +template +struct formatter_wrapper + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template +struct formatter_wrapper + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template +struct format_traits_imp +{ +private: + // + // F must be a pointer, a function, or a class with a function call operator: + // + BOOST_STATIC_ASSERT((::boost::is_pointer::value || ::boost::is_function::value || ::boost::is_class::value)); + static formatter_wrapper::type> f; + static M m; + static O out; + static boost::regex_constants::match_flag_type flags; +public: + BOOST_STATIC_CONSTANT(int, value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags)))); +}; + +template +struct format_traits +{ +public: + // + // Type is mpl::int_ where N is one of: + // + // 0 : F is a pointer to a presumably null-terminated string. + // 1 : F is a character-container such as a std::string. + // 2 : F is a Unary Functor. + // 3 : F is a Binary Functor. + // 4 : F is a Ternary Functor. + // + typedef typename boost::mpl::if_< + boost::mpl::and_, boost::mpl::not_::type> > >, + boost::mpl::int_<0>, + typename boost::mpl::if_< + has_const_iterator, + boost::mpl::int_<1>, + boost::mpl::int_::value> + >::type + >::type type; + // + // This static assertion will fail if the functor passed does not accept + // the same type of arguments passed. + // + BOOST_STATIC_ASSERT( boost::is_class::value && !has_const_iterator::value ? (type::value > 1) : true); +}; + +#else // BOOST_NO_SFINAE + +template +struct format_traits +{ +public: + // + // Type is mpl::int_ where N is one of: + // + // 0 : F is a pointer to a presumably null-terminated string. + // 1 : F is a character-container such as a std::string. + // + // Other options such as F being a Functor are not supported without + // SFINAE support. + // + typedef typename boost::mpl::if_< + boost::is_pointer, + boost::mpl::int_<0>, + boost::mpl::int_<1> + >::type type; +}; + +#endif // BOOST_NO_SFINAE + +template +struct format_functor3 +{ + format_functor3(Base b) : func(b) {} + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f) + { + return boost::unwrap_ref(func)(m, i, f); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor3(const format_functor3&); + format_functor3& operator=(const format_functor3&); +}; + +template +struct format_functor2 +{ + format_functor2(Base b) : func(b) {} + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/) + { + return boost::unwrap_ref(func)(m, i); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor2(const format_functor2&); + format_functor2& operator=(const format_functor2&); +}; + +template +struct format_functor1 +{ + format_functor1(Base b) : func(b) {} + + template + OutputIter do_format_string(const S& s, OutputIter i) + { + return BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), i); + } + template + inline OutputIter do_format_string(const S* s, OutputIter i) + { + while(s && *s) + { + *i = *s; + ++i; + ++s; + } + return i; + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/) + { + return do_format_string(boost::unwrap_ref(func)(m), i); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor1(const format_functor1&); + format_functor1& operator=(const format_functor1&); +}; + +template +struct format_functor_c_string +{ + format_functor_c_string(const charT* ps) : func(ps) {} + + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits()) + { + //typedef typename Match::char_type char_type; + const charT* end = func; + while(*end) ++end; + return regex_format_imp(i, m, func, end, f, t); + } +private: + const charT* func; + format_functor_c_string(const format_functor_c_string&); + format_functor_c_string& operator=(const format_functor_c_string&); +}; + +template +struct format_functor_container +{ + format_functor_container(const Container& c) : func(c) {} + + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits()) + { + //typedef typename Match::char_type char_type; + return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t); + } +private: + const Container& func; + format_functor_container(const format_functor_container&); + format_functor_container& operator=(const format_functor_container&); +}; + +template > +struct compute_functor_type +{ + typedef typename format_traits::type tag; + typedef typename boost::remove_cv< typename boost::remove_pointer::type>::type maybe_char_type; + + typedef typename mpl::if_< + ::boost::is_same >, format_functor_c_string, + typename mpl::if_< + ::boost::is_same >, format_functor_container, + typename mpl::if_< + ::boost::is_same >, format_functor1, + typename mpl::if_< + ::boost::is_same >, format_functor2, + format_functor3 + >::type + >::type + >::type + >::type type; +}; + +} // namespace BOOST_REGEX_DETAIL_NS + +template +inline OutputIterator regex_format(OutputIterator out, + const match_results& m, + Functor fmt, + match_flag_type flags = format_all + ) +{ + return m.format(out, fmt, flags); +} + +template +inline std::basic_string::char_type> regex_format(const match_results& m, + Functor fmt, + match_flag_type flags = format_all) +{ + return m.format(fmt, flags); +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_FORMAT_HPP + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_fwd.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_fwd.hpp new file mode 100644 index 0000000000..3076b069ac --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_fwd.hpp @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_fwd.cpp + * VERSION see + * DESCRIPTION: Forward declares boost::basic_regex<> and + * associated typedefs. + */ + +#ifndef BOOST_REGEX_FWD_HPP_INCLUDED +#define BOOST_REGEX_FWD_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +// +// define BOOST_REGEX_NO_FWD if this +// header doesn't work! +// +#ifdef BOOST_REGEX_NO_FWD +# ifndef BOOST_RE_REGEX_HPP +# include +# endif +#else + +namespace boost{ + +template +class cpp_regex_traits; +template +struct c_regex_traits; +template +class w32_regex_traits; + +#ifdef BOOST_REGEX_USE_WIN32_LOCALE +template > +struct regex_traits; +#elif defined(BOOST_REGEX_USE_CPP_LOCALE) +template > +struct regex_traits; +#else +template > +struct regex_traits; +#endif + +template > +class basic_regex; + +typedef basic_regex > regex; +#ifndef BOOST_NO_WREGEX +typedef basic_regex > wregex; +#endif + +} // namespace boost + +#endif // BOOST_REGEX_NO_FWD + +#endif + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_grep.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_grep.hpp new file mode 100644 index 0000000000..c5cb054e58 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_grep.hpp @@ -0,0 +1,155 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_grep.hpp + * VERSION see + * DESCRIPTION: Provides regex_grep implementation. + */ + +#ifndef BOOST_REGEX_V4_REGEX_GREP_HPP +#define BOOST_REGEX_V4_REGEX_GREP_HPP + + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// +// regex_grep: +// find all non-overlapping matches within the sequence first last: +// +template +inline unsigned int regex_grep(Predicate foo, + BidiIterator first, + BidiIterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + if(e.flags() & regex_constants::failbit) + return false; + + typedef typename match_results::allocator_type match_allocator_type; + + match_results m; + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, first); + unsigned int count = 0; + while(matcher.find()) + { + ++count; + if(0 == foo(m)) + return count; // caller doesn't want to go on + if(m[0].second == last) + return count; // we've reached the end, don't try and find an extra null match. + if(m.length() == 0) + { + if(m[0].second == last) + return count; + // we found a NULL-match, now try to find + // a non-NULL one at the same position: + match_results m2(m); + matcher.setf(match_not_null | match_continuous); + if(matcher.find()) + { + ++count; + if(0 == foo(m)) + return count; + } + else + { + // reset match back to where it was: + m = m2; + } + matcher.unsetf((match_not_null | match_continuous) & ~flags); + } + } + return count; +} + +// +// regex_grep convenience interfaces: +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +// +// this isn't really a partial specialisation, but template function +// overloading - if the compiler doesn't support partial specialisation +// then it really won't support this either: +template +inline unsigned int regex_grep(Predicate foo, const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, str, str + traits::length(str), e, flags); +} + +template +inline unsigned int regex_grep(Predicate foo, const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, s.begin(), s.end(), e, flags); +} +#else // partial specialisation +inline unsigned int regex_grep(bool (*foo)(const cmatch&), const char* str, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, str, str + regex::traits_type::length(str), e, flags); +} +#ifndef BOOST_NO_WREGEX +inline unsigned int regex_grep(bool (*foo)(const wcmatch&), const wchar_t* str, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, str, str + wregex::traits_type::length(str), e, flags); +} +#endif +inline unsigned int regex_grep(bool (*foo)(const match_results&), const std::string& s, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, s.begin(), s.end(), e, flags); +} +#if !defined(BOOST_NO_WREGEX) +inline unsigned int regex_grep(bool (*foo)(const match_results::const_iterator>&), + const std::basic_string& s, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, s.begin(), s.end(), e, flags); +} +#endif +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_GREP_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_iterator.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_iterator.hpp new file mode 100644 index 0000000000..bbdeed5880 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_iterator.hpp @@ -0,0 +1,195 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_iterator.hpp + * VERSION see + * DESCRIPTION: Provides regex_iterator implementation. + */ + +#ifndef BOOST_REGEX_V4_REGEX_ITERATOR_HPP +#define BOOST_REGEX_V4_REGEX_ITERATOR_HPP + +#include + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +class regex_iterator_implementation +{ + typedef basic_regex regex_type; + + match_results what; // current match + BidirectionalIterator base; // start of sequence + BidirectionalIterator end; // end of sequence + const regex_type re; // the expression + match_flag_type flags; // flags for matching + +public: + regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f) + : base(), end(last), re(*p), flags(f){} + regex_iterator_implementation(const regex_iterator_implementation& other) + :what(other.what), base(other.base), end(other.end), re(other.re), flags(other.flags){} + bool init(BidirectionalIterator first) + { + base = first; + return regex_search(first, end, what, re, flags); + } + bool compare(const regex_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second); + } + const match_results& get() + { return what; } + bool next() + { + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail; + BidirectionalIterator next_start = what[0].second; + match_flag_type f(flags); + if(!what.length() || (f & regex_constants::match_posix)) + f |= regex_constants::match_not_initial_null; + //if(base != next_start) + // f |= regex_constants::match_not_bob; + bool result = regex_search(next_start, end, what, re, f, base); + if(result) + what.set_base(base); + return result; + } +private: + regex_iterator_implementation& operator=(const regex_iterator_implementation&); +}; + +template ::value_type, + class traits = regex_traits > +class regex_iterator +{ +private: + typedef regex_iterator_implementation impl; + typedef shared_ptr pimpl; +public: + typedef basic_regex regex_type; + typedef match_results value_type; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + regex_iterator(){} + regex_iterator(BidirectionalIterator a, BidirectionalIterator b, + const regex_type& re, + match_flag_type m = match_default) + : pdata(new impl(&re, b, m)) + { + if(!pdata->init(a)) + { + pdata.reset(); + } + } + regex_iterator(const regex_iterator& that) + : pdata(that.pdata) {} + regex_iterator& operator=(const regex_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const regex_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const regex_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + regex_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + regex_iterator operator++(int) + { + regex_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && !pdata.unique()) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef regex_iterator cregex_iterator; +typedef regex_iterator sregex_iterator; +#ifndef BOOST_NO_WREGEX +typedef regex_iterator wcregex_iterator; +typedef regex_iterator wsregex_iterator; +#endif + +// make_regex_iterator: +template +inline regex_iterator make_regex_iterator(const charT* p, const basic_regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_iterator(p, p+traits::length(p), e, m); +} +template +inline regex_iterator::const_iterator, charT, traits> make_regex_iterator(const std::basic_string& p, const basic_regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, m); +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_match.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_match.hpp new file mode 100644 index 0000000000..a50daa2aa5 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_match.hpp @@ -0,0 +1,382 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_match.hpp + * VERSION see + * DESCRIPTION: Regular expression matching algorithms. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + + +#ifndef BOOST_REGEX_MATCH_HPP +#define BOOST_REGEX_MATCH_HPP + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// +// proc regex_match +// returns true if the specified regular expression matches +// the whole of the input. Fills in what matched in m. +// +template +bool regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, first); + return matcher.match(); +} +template +bool regex_match(iterator first, iterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(first, last, m, e, flags | regex_constants::match_any); +} +// +// query_match convenience interfaces: +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +// +// this isn't really a partial specialisation, but template function +// overloading - if the compiler doesn't support partial specialisation +// then it really won't support this either: +template +inline bool regex_match(const charT* str, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + traits::length(str), m, e, flags); +} + +template +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator, Allocator>& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +template +inline bool regex_match(const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + traits::length(str), m, e, flags | regex_constants::match_any); +} + +template +inline bool regex_match(const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + typedef typename std::basic_string::const_iterator iterator; + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#else // partial ordering +inline bool regex_match(const char* str, + cmatch& m, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + regex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const char* str, + const regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + regex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#ifndef BOOST_NO_STD_LOCALE +inline bool regex_match(const char* str, + cmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + regex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const char* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + regex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_match(const char* str, + cmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + regex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const char* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + regex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +inline bool regex_match(const char* str, + cmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + regex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const char* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + regex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#endif +#ifndef BOOST_NO_WREGEX +inline bool regex_match(const wchar_t* str, + wcmatch& m, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const wchar_t* str, + const wregex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#ifndef BOOST_NO_STD_LOCALE +inline bool regex_match(const wchar_t* str, + wcmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const wchar_t* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_match(const wchar_t* str, + wcmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const wchar_t* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +inline bool regex_match(const wchar_t* str, + wcmatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags); +} +inline bool regex_match(const wchar_t* str, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + wregex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#endif +#endif +inline bool regex_match(const std::string& s, + smatch& m, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::string& s, + const regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#ifndef BOOST_NO_STD_LOCALE +inline bool regex_match(const std::string& s, + smatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_match(const std::string& s, + smatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +inline bool regex_match(const std::string& s, + smatch& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#endif +#if !defined(BOOST_NO_WREGEX) +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator>& m, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::basic_string& s, + const wregex& e, + match_flag_type flags = match_default) +{ + match_results::const_iterator> m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#ifndef BOOST_NO_STD_LOCALE +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator>& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::basic_string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results::const_iterator> m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator>& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::basic_string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results::const_iterator> m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator>& m, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +inline bool regex_match(const std::basic_string& s, + const basic_regex >& e, + match_flag_type flags = match_default) +{ + match_results::const_iterator> m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#endif +#endif + +#endif + + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_MATCH_HPP + + + + + + + + + + + + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_merge.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_merge.hpp new file mode 100644 index 0000000000..404ca77501 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_merge.hpp @@ -0,0 +1,93 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_V4_REGEX_MERGE_HPP +#define BOOST_REGEX_V4_REGEX_MERGE_HPP + + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +inline OutputIterator regex_merge(OutputIterator out, + Iterator first, + Iterator last, + const basic_regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + return regex_replace(out, first, last, e, fmt, flags); +} + +template +inline OutputIterator regex_merge(OutputIterator out, + Iterator first, + Iterator last, + const basic_regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + return regex_merge(out, first, last, e, fmt.c_str(), flags); +} + +template +inline std::basic_string regex_merge(const std::basic_string& s, + const basic_regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + return regex_replace(s, e, fmt, flags); +} + +template +inline std::basic_string regex_merge(const std::basic_string& s, + const basic_regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + return regex_replace(s, e, fmt, flags); +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_MERGE_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_raw_buffer.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_raw_buffer.hpp new file mode 100644 index 0000000000..ac27e1a29e --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_raw_buffer.hpp @@ -0,0 +1,241 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_raw_buffer.hpp + * VERSION see + * DESCRIPTION: Raw character buffer for regex code. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_RAW_BUFFER_HPP +#define BOOST_REGEX_RAW_BUFFER_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#include +#include + +namespace boost{ + namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +struct empty_padding{}; + +union padding +{ + void* p; + unsigned int i; +}; + +template +struct padding3 +{ + enum{ + padding_size = 8, + padding_mask = 7 + }; +}; + +template<> +struct padding3<2> +{ + enum{ + padding_size = 2, + padding_mask = 1 + }; +}; + +template<> +struct padding3<4> +{ + enum{ + padding_size = 4, + padding_mask = 3 + }; +}; + +template<> +struct padding3<8> +{ + enum{ + padding_size = 8, + padding_mask = 7 + }; +}; + +template<> +struct padding3<16> +{ + enum{ + padding_size = 16, + padding_mask = 15 + }; +}; + +enum{ + padding_size = padding3::padding_size, + padding_mask = padding3::padding_mask +}; + +// +// class raw_storage +// basically this is a simplified vector +// this is used by basic_regex for expression storage +// + +class raw_storage +{ +public: + typedef std::size_t size_type; + typedef unsigned char* pointer; +private: + pointer last, start, end; +public: + + raw_storage(); + raw_storage(size_type n); + + ~raw_storage() + { + ::operator delete(start); + } + + void BOOST_REGEX_CALL resize(size_type n) + { + size_type newsize = start ? last - start : 1024; + while (newsize < n) + newsize *= 2; + size_type datasize = end - start; + // extend newsize to WORD/DWORD boundary: + newsize = (newsize + padding_mask) & ~(padding_mask); + + // allocate and copy data: + pointer ptr = static_cast(::operator new(newsize)); + BOOST_REGEX_NOEH_ASSERT(ptr) + if (start) + std::memcpy(ptr, start, datasize); + + // get rid of old buffer: + ::operator delete(start); + + // and set up pointers: + start = ptr; + end = ptr + datasize; + last = ptr + newsize; + } + + void* BOOST_REGEX_CALL extend(size_type n) + { + if(size_type(last - end) < n) + resize(n + (end - start)); + pointer result = end; + end += n; + return result; + } + + void* BOOST_REGEX_CALL insert(size_type pos, size_type n) + { + BOOST_REGEX_ASSERT(pos <= size_type(end - start)); + if (size_type(last - end) < n) + resize(n + (end - start)); + void* result = start + pos; + std::memmove(start + pos + n, start + pos, (end - start) - pos); + end += n; + return result; + } + + size_type BOOST_REGEX_CALL size() + { + return size_type(end - start); + } + + size_type BOOST_REGEX_CALL capacity() + { + return size_type(last - start); + } + + void* BOOST_REGEX_CALL data()const + { + return start; + } + + size_type BOOST_REGEX_CALL index(void* ptr) + { + return size_type(static_cast(ptr) - static_cast(data())); + } + + void BOOST_REGEX_CALL clear() + { + end = start; + } + + void BOOST_REGEX_CALL align() + { + // move end up to a boundary: + end = start + (((end - start) + padding_mask) & ~padding_mask); + } + void swap(raw_storage& that) + { + std::swap(start, that.start); + std::swap(end, that.end); + std::swap(last, that.last); + } +}; + +inline raw_storage::raw_storage() +{ + last = start = end = 0; +} + +inline raw_storage::raw_storage(size_type n) +{ + start = end = static_cast(::operator new(n)); + BOOST_REGEX_NOEH_ASSERT(start) + last = start + n; +} + + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#endif + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_replace.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_replace.hpp new file mode 100644 index 0000000000..415c58b634 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_replace.hpp @@ -0,0 +1,99 @@ +/* + * + * Copyright (c) 1998-2009 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_V4_REGEX_REPLACE_HPP +#define BOOST_REGEX_V4_REGEX_REPLACE_HPP + + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +OutputIterator regex_replace(OutputIterator out, + BidirectionalIterator first, + BidirectionalIterator last, + const basic_regex& e, + Formatter fmt, + match_flag_type flags = match_default) +{ + regex_iterator i(first, last, e, flags); + regex_iterator j; + if(i == j) + { + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(first, last, out); + } + else + { + BidirectionalIterator last_m(first); + while(i != j) + { + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(i->prefix().first, i->prefix().second, out); + out = i->format(out, fmt, flags, e); + last_m = (*i)[0].second; + if(flags & regex_constants::format_first_only) + break; + ++i; + } + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(last_m, last, out); + } + return out; +} + +template +std::basic_string regex_replace(const std::basic_string& s, + const basic_regex& e, + Formatter fmt, + match_flag_type flags = match_default) +{ + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + regex_replace(i, s.begin(), s.end(), e, fmt, flags); + return result; +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_REPLACE_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_search.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_search.hpp new file mode 100644 index 0000000000..0725d3ec3f --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_search.hpp @@ -0,0 +1,217 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_search.hpp + * VERSION see + * DESCRIPTION: Provides regex_search implementation. + */ + +#ifndef BOOST_REGEX_V4_REGEX_SEARCH_HPP +#define BOOST_REGEX_V4_REGEX_SEARCH_HPP + + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +template +bool regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(first, last, m, e, flags, first); +} + +template +bool regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags, + BidiIterator base) +{ + if(e.flags() & regex_constants::failbit) + return false; + + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, base); + return matcher.find(); +} + +// +// regex_search convenience interfaces: +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +// +// this isn't really a partial specialisation, but template function +// overloading - if the compiler doesn't support partial specialisation +// then it really won't support this either: +template +inline bool regex_search(const charT* str, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + traits::length(str), m, e, flags); +} + +template +inline bool regex_search(const std::basic_string& s, + match_results::const_iterator, Allocator>& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), m, e, flags); +} +#else // partial overloads: +inline bool regex_search(const char* str, + cmatch& m, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + regex::traits_type::length(str), m, e, flags); +} +inline bool regex_search(const char* first, const char* last, + const regex& e, + match_flag_type flags = match_default) +{ + cmatch m; + return regex_search(first, last, m, e, flags | regex_constants::match_any); +} + +#ifndef BOOST_NO_WREGEX +inline bool regex_search(const wchar_t* str, + wcmatch& m, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + wregex::traits_type::length(str), m, e, flags); +} +inline bool regex_search(const wchar_t* first, const wchar_t* last, + const wregex& e, + match_flag_type flags = match_default) +{ + wcmatch m; + return regex_search(first, last, m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_search(const std::string& s, + smatch& m, + const regex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), m, e, flags); +} +#if !defined(BOOST_NO_WREGEX) +inline bool regex_search(const std::basic_string& s, + wsmatch& m, + const wregex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), m, e, flags); +} +#endif + +#endif + +template +bool regex_search(BidiIterator first, BidiIterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + if(e.flags() & regex_constants::failbit) + return false; + + match_results m; + typedef typename match_results::allocator_type match_alloc_type; + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags | regex_constants::match_any, first); + return matcher.find(); +} + +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +template +inline bool regex_search(const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + traits::length(str), e, flags); +} + +template +inline bool regex_search(const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), e, flags); +} +#else // non-template function overloads +inline bool regex_search(const char* str, + const regex& e, + match_flag_type flags = match_default) +{ + cmatch m; + return regex_search(str, str + regex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#ifndef BOOST_NO_WREGEX +inline bool regex_search(const wchar_t* str, + const wregex& e, + match_flag_type flags = match_default) +{ + wcmatch m; + return regex_search(str, str + wregex::traits_type::length(str), m, e, flags | regex_constants::match_any); +} +#endif +inline bool regex_search(const std::string& s, + const regex& e, + match_flag_type flags = match_default) +{ + smatch m; + return regex_search(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} +#if !defined(BOOST_NO_WREGEX) +inline bool regex_search(const std::basic_string& s, + const wregex& e, + match_flag_type flags = match_default) +{ + wsmatch m; + return regex_search(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} + +#endif // BOOST_NO_WREGEX + +#endif // partial overload + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_SEARCH_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_split.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_split.hpp new file mode 100644 index 0000000000..afa5659831 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_split.hpp @@ -0,0 +1,174 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_split.hpp + * VERSION see + * DESCRIPTION: Implements regex_split and associated functions. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_SPLIT_HPP +#define BOOST_REGEX_SPLIT_HPP + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +# pragma warning(push) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +template +const basic_regex& get_default_expression(charT) +{ + static const charT expression_text[4] = { '\\', 's', '+', '\00', }; + static const basic_regex e(expression_text); + return e; +} + +template +class split_pred +{ + typedef std::basic_string string_type; + typedef typename string_type::const_iterator iterator_type; + iterator_type* p_last; + OutputIterator* p_out; + std::size_t* p_max; + std::size_t initial_max; +public: + split_pred(iterator_type* a, OutputIterator* b, std::size_t* c) + : p_last(a), p_out(b), p_max(c), initial_max(*c) {} + + bool operator()(const match_results& what); +}; + +template +bool split_pred::operator() + (const match_results& what) +{ + *p_last = what[0].second; + if(what.size() > 1) + { + // output sub-expressions only: + for(unsigned i = 1; i < what.size(); ++i) + { + *(*p_out) = what.str(i); + ++(*p_out); + if(0 == --*p_max) return false; + } + return *p_max != 0; + } + else + { + // output $` only if it's not-null or not at the start of the input: + const sub_match& sub = what[-1]; + if((sub.first != sub.second) || (*p_max != initial_max)) + { + *(*p_out) = sub.str(); + ++(*p_out); + return --*p_max; + } + } + // + // initial null, do nothing: + return true; +} + +} // namespace BOOST_REGEX_DETAIL_NS + +template +std::size_t regex_split(OutputIterator out, + std::basic_string& s, + const basic_regex& e, + match_flag_type flags, + std::size_t max_split) +{ + typedef typename std::basic_string::const_iterator ci_t; + //typedef typename match_results::allocator_type match_allocator; + ci_t last = s.begin(); + std::size_t init_size = max_split; + BOOST_REGEX_DETAIL_NS::split_pred pred(&last, &out, &max_split); + ci_t i, j; + i = s.begin(); + j = s.end(); + regex_grep(pred, i, j, e, flags); + // + // if there is still input left, do a final push as long as max_split + // is not exhausted, and we're not splitting sub-expressions rather + // than whitespace: + if(max_split && (last != s.end()) && (e.mark_count() == 0)) + { + *out = std::basic_string((ci_t)last, (ci_t)s.end()); + ++out; + last = s.end(); + --max_split; + } + // + // delete from the string everything that has been processed so far: + s.erase(0, last - s.begin()); + // + // return the number of new records pushed: + return init_size - max_split; +} + +template +inline std::size_t regex_split(OutputIterator out, + std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_split(out, s, e, flags, UINT_MAX); +} + +template +inline std::size_t regex_split(OutputIterator out, + std::basic_string& s) +{ + return regex_split(out, s, BOOST_REGEX_DETAIL_NS::get_default_expression(charT(0)), match_default, UINT_MAX); +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_token_iterator.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_token_iterator.hpp new file mode 100644 index 0000000000..fc54b3c97f --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_token_iterator.hpp @@ -0,0 +1,327 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_token_iterator.hpp + * VERSION see + * DESCRIPTION: Provides regex_token_iterator implementation. + */ + +#ifndef BOOST_REGEX_V4_REGEX_TOKEN_ITERATOR_HPP +#define BOOST_REGEX_V4_REGEX_TOKEN_ITERATOR_HPP + +#include +#include +#if (BOOST_WORKAROUND(BOOST_BORLANDC, >= 0x560) && BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) +// +// Borland C++ Builder 6, and Visual C++ 6, +// can't cope with the array template constructor +// so we have a template member that will accept any type as +// argument, and then assert that is really is an array: +// +#include +#include +#endif + +namespace boost{ + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#pragma warning(push) +#pragma warning(disable:4700) +#endif + +template +class regex_token_iterator_implementation +{ + typedef basic_regex regex_type; + typedef sub_match value_type; + + match_results what; // current match + BidirectionalIterator base; // start of search area + BidirectionalIterator end; // end of search area + const regex_type re; // the expression + match_flag_type flags; // match flags + value_type result; // the current string result + int N; // the current sub-expression being enumerated + std::vector subs; // the sub-expressions to enumerate + +public: + regex_token_iterator_implementation(const regex_token_iterator_implementation& other) + : what(other.what), base(other.base), end(other.end), re(other.re), flags(other.flags), result(other.result), N(other.N), subs(other.subs) {} + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, int sub, match_flag_type f) + : end(last), re(*p), flags(f), N(0){ subs.push_back(sub); } + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const std::vector& v, match_flag_type f) + : end(last), re(*p), flags(f), N(0), subs(v){} +#if !BOOST_WORKAROUND(__HP_aCC, < 60700) +#if (BOOST_WORKAROUND(BOOST_BORLANDC, >= 0x560) && BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) \ + || BOOST_WORKAROUND(__HP_aCC, < 60700) + template + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const T& submatches, match_flag_type f) + : end(last), re(*p), flags(f), N(0) + { + // assert that T really is an array: + BOOST_STATIC_ASSERT(::boost::is_array::value); + const std::size_t array_size = sizeof(T) / sizeof(submatches[0]); + for(std::size_t i = 0; i < array_size; ++i) + { + subs.push_back(submatches[i]); + } + } +#else + template + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const int (&submatches)[CN], match_flag_type f) + : end(last), re(*p), flags(f), N(0) + { + for(std::size_t i = 0; i < CN; ++i) + { + subs.push_back(submatches[i]); + } + } +#endif +#endif + bool init(BidirectionalIterator first) + { + N = 0; + base = first; + if(regex_search(first, end, what, re, flags, base) == true) + { + N = 0; + result = ((subs[N] == -1) ? what.prefix() : what[(int)subs[N]]); + return true; + } + else if((subs[N] == -1) && (first != end)) + { + result.first = first; + result.second = end; + result.matched = (first != end); + N = -1; + return true; + } + return false; + } + bool compare(const regex_token_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) + && (end == that.end) + && (flags == that.flags) + && (N == that.N) + && (what[0].first == that.what[0].first) + && (what[0].second == that.what[0].second); + } + const value_type& get() + { return result; } + bool next() + { + if(N == -1) + return false; + if(N+1 < (int)subs.size()) + { + ++N; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + //if(what.prefix().first != what[0].second) + // flags |= /*match_prev_avail |*/ regex_constants::match_not_bob; + BidirectionalIterator last_end(what[0].second); + if(regex_search(last_end, end, what, re, ((what[0].first == what[0].second) ? flags | regex_constants::match_not_initial_null : flags), base)) + { + N =0; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + else if((last_end != end) && (subs[0] == -1)) + { + N =-1; + result.first = last_end; + result.second = end; + result.matched = (last_end != end); + return true; + } + return false; + } +private: + regex_token_iterator_implementation& operator=(const regex_token_iterator_implementation&); +}; + +template ::value_type, + class traits = regex_traits > +class regex_token_iterator +{ +private: + typedef regex_token_iterator_implementation impl; + typedef shared_ptr pimpl; +public: + typedef basic_regex regex_type; + typedef sub_match value_type; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + regex_token_iterator(){} + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + int submatch = 0, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatch, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const std::vector& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#if !BOOST_WORKAROUND(__HP_aCC, < 60700) +#if (BOOST_WORKAROUND(BOOST_BORLANDC, >= 0x560) && BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) \ + || BOOST_WORKAROUND(__HP_aCC, < 60700) + template + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const T& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#else + template + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const int (&submatches)[N], match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#endif +#endif + regex_token_iterator(const regex_token_iterator& that) + : pdata(that.pdata) {} + regex_token_iterator& operator=(const regex_token_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const regex_token_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const regex_token_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + regex_token_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + regex_token_iterator operator++(int) + { + regex_token_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && !pdata.unique()) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef regex_token_iterator cregex_token_iterator; +typedef regex_token_iterator sregex_token_iterator; +#ifndef BOOST_NO_WREGEX +typedef regex_token_iterator wcregex_token_iterator; +typedef regex_token_iterator wsregex_token_iterator; +#endif + +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_TOKEN_ITERATOR_HPP + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_traits.hpp new file mode 100644 index 0000000000..ffa2bb6871 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_traits.hpp @@ -0,0 +1,189 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits classes. + */ + +#ifndef BOOST_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_REGEX_TRAITS_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif +#ifndef BOOST_REGEX_WORKAROUND_HPP +#include +#endif +#ifndef BOOST_REGEX_SYNTAX_TYPE_HPP +#include +#endif +#ifndef BOOST_REGEX_ERROR_TYPE_HPP +#include +#endif +#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED +#include +#endif +#ifndef BOOST_NO_STD_LOCALE +# ifndef BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED +# include +# endif +#endif +#if !BOOST_WORKAROUND(BOOST_BORLANDC, < 0x560) +# ifndef BOOST_C_REGEX_TRAITS_HPP_INCLUDED +# include +# endif +#endif +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +# ifndef BOOST_W32_REGEX_TRAITS_HPP_INCLUDED +# include +# endif +#endif +#ifndef BOOST_REGEX_FWD_HPP_INCLUDED +#include +#endif + +#include "boost/mpl/has_xxx.hpp" +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ + +template +struct regex_traits : public implementationT +{ + regex_traits() : implementationT() {} +}; + +// +// class regex_traits_wrapper. +// this is what our implementation will actually store; +// it provides default implementations of the "optional" +// interfaces that we support, in addition to the +// required "standard" ones: +// +namespace BOOST_REGEX_DETAIL_NS{ +#if !BOOST_WORKAROUND(__HP_aCC, < 60000) +BOOST_MPL_HAS_XXX_TRAIT_DEF(boost_extensions_tag) +#else +template +struct has_boost_extensions_tag +{ + BOOST_STATIC_CONSTANT(bool, value = false); +}; +#endif + +template +struct default_wrapper : public BaseT +{ + typedef typename BaseT::char_type char_type; + std::string error_string(::boost::regex_constants::error_type e)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(e); + } + ::boost::regex_constants::syntax_type syntax_type(char_type c)const + { + return ((c & 0x7f) == c) ? get_default_syntax_type(static_cast(c)) : ::boost::regex_constants::syntax_char; + } + ::boost::regex_constants::escape_syntax_type escape_syntax_type(char_type c)const + { + return ((c & 0x7f) == c) ? get_default_escape_syntax_type(static_cast(c)) : ::boost::regex_constants::escape_type_identity; + } + boost::intmax_t toi(const char_type*& p1, const char_type* p2, int radix)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + char_type translate(char_type c, bool icase)const + { + return (icase ? this->translate_nocase(c) : this->translate(c)); + } + char_type translate(char_type c)const + { + return BaseT::translate(c); + } + char_type tolower(char_type c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c); + } + char_type toupper(char_type c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c); + } +}; + +template +struct compute_wrapper_base +{ + typedef BaseT type; +}; +#if !BOOST_WORKAROUND(__HP_aCC, < 60000) +template +struct compute_wrapper_base +{ + typedef default_wrapper type; +}; +#else +template <> +struct compute_wrapper_base, false> +{ + typedef default_wrapper > type; +}; +#ifndef BOOST_NO_WREGEX +template <> +struct compute_wrapper_base, false> +{ + typedef default_wrapper > type; +}; +#endif +#endif + +} // namespace BOOST_REGEX_DETAIL_NS + +template +struct regex_traits_wrapper + : public ::boost::BOOST_REGEX_DETAIL_NS::compute_wrapper_base< + BaseT, + ::boost::BOOST_REGEX_DETAIL_NS::has_boost_extensions_tag::value + >::type +{ + regex_traits_wrapper(){} +private: + regex_traits_wrapper(const regex_traits_wrapper&); + regex_traits_wrapper& operator=(const regex_traits_wrapper&); +}; + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // include + diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_traits_defaults.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_traits_defaults.hpp new file mode 100644 index 0000000000..1dbb0bf9c5 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_traits_defaults.hpp @@ -0,0 +1,997 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits_defaults.hpp + * VERSION see + * DESCRIPTION: Declares API's for access to regex_traits default properties. + */ + +#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED +#define BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include +#include + +#include +#include +#include + +#ifndef BOOST_REGEX_SYNTAX_TYPE_HPP +#include +#endif +#ifndef BOOST_REGEX_ERROR_TYPE_HPP +#include +#endif +#include +#include +#include + +#ifdef BOOST_NO_STDC_NAMESPACE +namespace std{ + using ::strlen; +} +#endif + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + + +// +// helpers to suppress warnings: +// +template +inline bool is_extended(charT c) +{ + typedef typename make_unsigned::type unsigned_type; + return (sizeof(charT) > 1) && (static_cast(c) >= 256u); +} +inline bool is_extended(char) +{ return false; } + +inline const char* BOOST_REGEX_CALL get_default_syntax(regex_constants::syntax_type n) +{ + // if the user hasn't supplied a message catalog, then this supplies + // default "messages" for us to load in the range 1-100. + const char* messages[] = { + "", + "(", + ")", + "$", + "^", + ".", + "*", + "+", + "?", + "[", + "]", + "|", + "\\", + "#", + "-", + "{", + "}", + "0123456789", + "b", + "B", + "<", + ">", + "", + "", + "A`", + "z'", + "\n", + ",", + "a", + "f", + "n", + "r", + "t", + "v", + "x", + "c", + ":", + "=", + "e", + "", + "", + "", + "", + "", + "", + "", + "", + "E", + "Q", + "X", + "C", + "Z", + "G", + "!", + "p", + "P", + "N", + "gk", + "K", + "R", + }; + + return ((n >= (sizeof(messages) / sizeof(messages[1]))) ? "" : messages[n]); +} + +inline const char* BOOST_REGEX_CALL get_default_error_string(regex_constants::error_type n) +{ + static const char* const s_default_error_messages[] = { + "Success", /* REG_NOERROR 0 error_ok */ + "No match", /* REG_NOMATCH 1 error_no_match */ + "Invalid regular expression.", /* REG_BADPAT 2 error_bad_pattern */ + "Invalid collation character.", /* REG_ECOLLATE 3 error_collate */ + "Invalid character class name, collating name, or character range.", /* REG_ECTYPE 4 error_ctype */ + "Invalid or unterminated escape sequence.", /* REG_EESCAPE 5 error_escape */ + "Invalid back reference: specified capturing group does not exist.", /* REG_ESUBREG 6 error_backref */ + "Unmatched [ or [^ in character class declaration.", /* REG_EBRACK 7 error_brack */ + "Unmatched marking parenthesis ( or \\(.", /* REG_EPAREN 8 error_paren */ + "Unmatched quantified repeat operator { or \\{.", /* REG_EBRACE 9 error_brace */ + "Invalid content of repeat range.", /* REG_BADBR 10 error_badbrace */ + "Invalid range end in character class", /* REG_ERANGE 11 error_range */ + "Out of memory.", /* REG_ESPACE 12 error_space NOT USED */ + "Invalid preceding regular expression prior to repetition operator.", /* REG_BADRPT 13 error_badrepeat */ + "Premature end of regular expression", /* REG_EEND 14 error_end NOT USED */ + "Regular expression is too large.", /* REG_ESIZE 15 error_size NOT USED */ + "Unmatched ) or \\)", /* REG_ERPAREN 16 error_right_paren NOT USED */ + "Empty regular expression.", /* REG_EMPTY 17 error_empty */ + "The complexity of matching the regular expression exceeded predefined bounds. " + "Try refactoring the regular expression to make each choice made by the state machine unambiguous. " + "This exception is thrown to prevent \"eternal\" matches that take an " + "indefinite period time to locate.", /* REG_ECOMPLEXITY 18 error_complexity */ + "Ran out of stack space trying to match the regular expression.", /* REG_ESTACK 19 error_stack */ + "Invalid or unterminated Perl (?...) sequence.", /* REG_E_PERL 20 error_perl */ + "Unknown error.", /* REG_E_UNKNOWN 21 error_unknown */ + }; + + return (n > ::boost::regex_constants::error_unknown) ? s_default_error_messages[::boost::regex_constants::error_unknown] : s_default_error_messages[n]; +} + +inline regex_constants::syntax_type BOOST_REGEX_CALL get_default_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::syntax_type char_syntax[] = { + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_newline, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /* */ // 32 + regex_constants::syntax_not, /*!*/ + regex_constants::syntax_char, /*"*/ + regex_constants::syntax_hash, /*#*/ + regex_constants::syntax_dollar, /*$*/ + regex_constants::syntax_char, /*%*/ + regex_constants::syntax_char, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::syntax_star, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::syntax_comma, /*,*/ + regex_constants::syntax_dash, /*-*/ + regex_constants::syntax_dot, /*.*/ + regex_constants::syntax_char, /*/*/ + regex_constants::syntax_digit, /*0*/ + regex_constants::syntax_digit, /*1*/ + regex_constants::syntax_digit, /*2*/ + regex_constants::syntax_digit, /*3*/ + regex_constants::syntax_digit, /*4*/ + regex_constants::syntax_digit, /*5*/ + regex_constants::syntax_digit, /*6*/ + regex_constants::syntax_digit, /*7*/ + regex_constants::syntax_digit, /*8*/ + regex_constants::syntax_digit, /*9*/ + regex_constants::syntax_colon, /*:*/ + regex_constants::syntax_char, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::syntax_equal, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::syntax_char, /*@*/ + regex_constants::syntax_char, /*A*/ + regex_constants::syntax_char, /*B*/ + regex_constants::syntax_char, /*C*/ + regex_constants::syntax_char, /*D*/ + regex_constants::syntax_char, /*E*/ + regex_constants::syntax_char, /*F*/ + regex_constants::syntax_char, /*G*/ + regex_constants::syntax_char, /*H*/ + regex_constants::syntax_char, /*I*/ + regex_constants::syntax_char, /*J*/ + regex_constants::syntax_char, /*K*/ + regex_constants::syntax_char, /*L*/ + regex_constants::syntax_char, /*M*/ + regex_constants::syntax_char, /*N*/ + regex_constants::syntax_char, /*O*/ + regex_constants::syntax_char, /*P*/ + regex_constants::syntax_char, /*Q*/ + regex_constants::syntax_char, /*R*/ + regex_constants::syntax_char, /*S*/ + regex_constants::syntax_char, /*T*/ + regex_constants::syntax_char, /*U*/ + regex_constants::syntax_char, /*V*/ + regex_constants::syntax_char, /*W*/ + regex_constants::syntax_char, /*X*/ + regex_constants::syntax_char, /*Y*/ + regex_constants::syntax_char, /*Z*/ + regex_constants::syntax_open_set, /*[*/ + regex_constants::syntax_escape, /*\*/ + regex_constants::syntax_close_set, /*]*/ + regex_constants::syntax_caret, /*^*/ + regex_constants::syntax_char, /*_*/ + regex_constants::syntax_char, /*`*/ + regex_constants::syntax_char, /*a*/ + regex_constants::syntax_char, /*b*/ + regex_constants::syntax_char, /*c*/ + regex_constants::syntax_char, /*d*/ + regex_constants::syntax_char, /*e*/ + regex_constants::syntax_char, /*f*/ + regex_constants::syntax_char, /*g*/ + regex_constants::syntax_char, /*h*/ + regex_constants::syntax_char, /*i*/ + regex_constants::syntax_char, /*j*/ + regex_constants::syntax_char, /*k*/ + regex_constants::syntax_char, /*l*/ + regex_constants::syntax_char, /*m*/ + regex_constants::syntax_char, /*n*/ + regex_constants::syntax_char, /*o*/ + regex_constants::syntax_char, /*p*/ + regex_constants::syntax_char, /*q*/ + regex_constants::syntax_char, /*r*/ + regex_constants::syntax_char, /*s*/ + regex_constants::syntax_char, /*t*/ + regex_constants::syntax_char, /*u*/ + regex_constants::syntax_char, /*v*/ + regex_constants::syntax_char, /*w*/ + regex_constants::syntax_char, /*x*/ + regex_constants::syntax_char, /*y*/ + regex_constants::syntax_char, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::syntax_char, /*~*/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + +inline regex_constants::escape_syntax_type BOOST_REGEX_CALL get_default_escape_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::escape_syntax_type char_syntax[] = { + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /* */ // 32 + regex_constants::escape_type_identity, /*!*/ + regex_constants::escape_type_identity, /*"*/ + regex_constants::escape_type_identity, /*#*/ + regex_constants::escape_type_identity, /*$*/ + regex_constants::escape_type_identity, /*%*/ + regex_constants::escape_type_identity, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::escape_type_identity, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::escape_type_identity, /*,*/ + regex_constants::escape_type_identity, /*-*/ + regex_constants::escape_type_identity, /*.*/ + regex_constants::escape_type_identity, /*/*/ + regex_constants::escape_type_decimal, /*0*/ + regex_constants::escape_type_backref, /*1*/ + regex_constants::escape_type_backref, /*2*/ + regex_constants::escape_type_backref, /*3*/ + regex_constants::escape_type_backref, /*4*/ + regex_constants::escape_type_backref, /*5*/ + regex_constants::escape_type_backref, /*6*/ + regex_constants::escape_type_backref, /*7*/ + regex_constants::escape_type_backref, /*8*/ + regex_constants::escape_type_backref, /*9*/ + regex_constants::escape_type_identity, /*:*/ + regex_constants::escape_type_identity, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::escape_type_identity, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::escape_type_identity, /*@*/ + regex_constants::escape_type_start_buffer, /*A*/ + regex_constants::escape_type_not_word_assert, /*B*/ + regex_constants::escape_type_C, /*C*/ + regex_constants::escape_type_not_class, /*D*/ + regex_constants::escape_type_E, /*E*/ + regex_constants::escape_type_not_class, /*F*/ + regex_constants::escape_type_G, /*G*/ + regex_constants::escape_type_not_class, /*H*/ + regex_constants::escape_type_not_class, /*I*/ + regex_constants::escape_type_not_class, /*J*/ + regex_constants::escape_type_reset_start_mark, /*K*/ + regex_constants::escape_type_not_class, /*L*/ + regex_constants::escape_type_not_class, /*M*/ + regex_constants::escape_type_named_char, /*N*/ + regex_constants::escape_type_not_class, /*O*/ + regex_constants::escape_type_not_property, /*P*/ + regex_constants::escape_type_Q, /*Q*/ + regex_constants::escape_type_line_ending, /*R*/ + regex_constants::escape_type_not_class, /*S*/ + regex_constants::escape_type_not_class, /*T*/ + regex_constants::escape_type_not_class, /*U*/ + regex_constants::escape_type_not_class, /*V*/ + regex_constants::escape_type_not_class, /*W*/ + regex_constants::escape_type_X, /*X*/ + regex_constants::escape_type_not_class, /*Y*/ + regex_constants::escape_type_Z, /*Z*/ + regex_constants::escape_type_identity, /*[*/ + regex_constants::escape_type_identity, /*\*/ + regex_constants::escape_type_identity, /*]*/ + regex_constants::escape_type_identity, /*^*/ + regex_constants::escape_type_identity, /*_*/ + regex_constants::escape_type_start_buffer, /*`*/ + regex_constants::escape_type_control_a, /*a*/ + regex_constants::escape_type_word_assert, /*b*/ + regex_constants::escape_type_ascii_control, /*c*/ + regex_constants::escape_type_class, /*d*/ + regex_constants::escape_type_e, /*e*/ + regex_constants::escape_type_control_f, /*f*/ + regex_constants::escape_type_extended_backref, /*g*/ + regex_constants::escape_type_class, /*h*/ + regex_constants::escape_type_class, /*i*/ + regex_constants::escape_type_class, /*j*/ + regex_constants::escape_type_extended_backref, /*k*/ + regex_constants::escape_type_class, /*l*/ + regex_constants::escape_type_class, /*m*/ + regex_constants::escape_type_control_n, /*n*/ + regex_constants::escape_type_class, /*o*/ + regex_constants::escape_type_property, /*p*/ + regex_constants::escape_type_class, /*q*/ + regex_constants::escape_type_control_r, /*r*/ + regex_constants::escape_type_class, /*s*/ + regex_constants::escape_type_control_t, /*t*/ + regex_constants::escape_type_class, /*u*/ + regex_constants::escape_type_control_v, /*v*/ + regex_constants::escape_type_class, /*w*/ + regex_constants::escape_type_hex, /*x*/ + regex_constants::escape_type_class, /*y*/ + regex_constants::escape_type_end_buffer, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::escape_type_identity, /*~*/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + +// is charT c a combining character? +inline bool BOOST_REGEX_CALL is_combining_implementation(boost::uint_least16_t c) +{ + const boost::uint_least16_t combining_ranges[] = { 0x0300, 0x0361, + 0x0483, 0x0486, + 0x0903, 0x0903, + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09CC, + 0x09D7, 0x09D7, + 0x0A3E, 0x0A40, + 0x0A83, 0x0A83, + 0x0ABE, 0x0AC0, + 0x0AC9, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B3E, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B4C, + 0x0B57, 0x0B57, + 0x0B83, 0x0B83, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D4C, + 0x0D57, 0x0D57, + 0x0F7F, 0x0F7F, + 0x20D0, 0x20E1, + 0x3099, 0x309A, + 0xFE20, 0xFE23, + 0xffff, 0xffff, }; + + const boost::uint_least16_t* p = combining_ranges + 1; + while (*p < c) p += 2; + --p; + if ((c >= *p) && (c <= *(p + 1))) + return true; + return false; +} + +template +inline bool is_combining(charT c) +{ + return (c <= static_cast(0)) ? false : ((c >= static_cast((std::numeric_limits::max)())) ? false : is_combining_implementation(static_cast(c))); +} +template <> +inline bool is_combining(char) +{ + return false; +} +template <> +inline bool is_combining(signed char) +{ + return false; +} +template <> +inline bool is_combining(unsigned char) +{ + return false; +} +#if !defined(__hpux) && !defined(__WINSCW__) // can't use WCHAR_MAX/MIN in pp-directives +#ifdef _MSC_VER +template<> +inline bool is_combining(wchar_t c) +{ + return is_combining_implementation(static_cast(c)); +} +#elif !defined(__DECCXX) && !defined(__osf__) && !defined(__OSF__) && defined(WCHAR_MIN) && (WCHAR_MIN == 0) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if defined(WCHAR_MAX) && (WCHAR_MAX <= USHRT_MAX) +template<> +inline bool is_combining(wchar_t c) +{ + return is_combining_implementation(static_cast(c)); +} +#else +template<> +inline bool is_combining(wchar_t c) +{ + return (c >= (std::numeric_limits::max)()) ? false : is_combining_implementation(static_cast(c)); +} +#endif +#endif +#endif + +// +// is a charT c a line separator? +// +template +inline bool is_separator(charT c) +{ + return BOOST_REGEX_MAKE_BOOL( + (c == static_cast('\n')) + || (c == static_cast('\r')) + || (c == static_cast('\f')) + || (static_cast(c) == 0x2028u) + || (static_cast(c) == 0x2029u) + || (static_cast(c) == 0x85u)); +} +template <> +inline bool is_separator(char c) +{ + return BOOST_REGEX_MAKE_BOOL((c == '\n') || (c == '\r') || (c == '\f')); +} + +// +// get a default collating element: +// +inline std::string BOOST_REGEX_CALL lookup_default_collate_name(const std::string& name) +{ + // + // these are the POSIX collating names: + // + static const char* def_coll_names[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "alert", "backspace", "tab", "newline", + "vertical-tab", "form-feed", "carriage-return", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", + "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "IS4", "IS3", "IS2", "IS1", "space", "exclamation-mark", + "quotation-mark", "number-sign", "dollar-sign", "percent-sign", "ampersand", "apostrophe", + "left-parenthesis", "right-parenthesis", "asterisk", "plus-sign", "comma", "hyphen", + "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + "colon", "semicolon", "less-than-sign", "equals-sign", "greater-than-sign", + "question-mark", "commercial-at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", + "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "left-square-bracket", "backslash", + "right-square-bracket", "circumflex", "underscore", "grave-accent", "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "left-curly-bracket", + "vertical-line", "right-curly-bracket", "tilde", "DEL", "", + }; + + // these multi-character collating elements + // should keep most Western-European locales + // happy - we should really localise these a + // little more - but this will have to do for + // now: + + static const char* def_multi_coll[] = { + "ae", + "Ae", + "AE", + "ch", + "Ch", + "CH", + "ll", + "Ll", + "LL", + "ss", + "Ss", + "SS", + "nj", + "Nj", + "NJ", + "dz", + "Dz", + "DZ", + "lj", + "Lj", + "LJ", + "", + }; + + unsigned int i = 0; + while (*def_coll_names[i]) + { + if (def_coll_names[i] == name) + { + return std::string(1, char(i)); + } + ++i; + } + i = 0; + while (*def_multi_coll[i]) + { + if (def_multi_coll[i] == name) + { + return def_multi_coll[i]; + } + ++i; + } + return std::string(); +} + +// +// get the state_id of a character classification, the individual +// traits classes then transform that state_id into a bitmask: +// +template +struct character_pointer_range +{ + const charT* p1; + const charT* p2; + + bool operator < (const character_pointer_range& r)const + { + return std::lexicographical_compare(p1, p2, r.p1, r.p2); + } + bool operator == (const character_pointer_range& r)const + { + // Not only do we check that the ranges are of equal size before + // calling std::equal, but there is no other algorithm available: + // not even a non-standard MS one. So forward to unchecked_equal + // in the MS case. + return ((p2 - p1) == (r.p2 - r.p1)) && BOOST_REGEX_DETAIL_NS::equal(p1, p2, r.p1); + } +}; +template +int get_default_class_id(const charT* p1, const charT* p2) +{ + static const charT data[73] = { + 'a', 'l', 'n', 'u', 'm', + 'a', 'l', 'p', 'h', 'a', + 'b', 'l', 'a', 'n', 'k', + 'c', 'n', 't', 'r', 'l', + 'd', 'i', 'g', 'i', 't', + 'g', 'r', 'a', 'p', 'h', + 'l', 'o', 'w', 'e', 'r', + 'p', 'r', 'i', 'n', 't', + 'p', 'u', 'n', 'c', 't', + 's', 'p', 'a', 'c', 'e', + 'u', 'n', 'i', 'c', 'o', 'd', 'e', + 'u', 'p', 'p', 'e', 'r', + 'v', + 'w', 'o', 'r', 'd', + 'x', 'd', 'i', 'g', 'i', 't', + }; + + static const character_pointer_range ranges[21] = + { + {data+0, data+5,}, // alnum + {data+5, data+10,}, // alpha + {data+10, data+15,}, // blank + {data+15, data+20,}, // cntrl + {data+20, data+21,}, // d + {data+20, data+25,}, // digit + {data+25, data+30,}, // graph + {data+29, data+30,}, // h + {data+30, data+31,}, // l + {data+30, data+35,}, // lower + {data+35, data+40,}, // print + {data+40, data+45,}, // punct + {data+45, data+46,}, // s + {data+45, data+50,}, // space + {data+57, data+58,}, // u + {data+50, data+57,}, // unicode + {data+57, data+62,}, // upper + {data+62, data+63,}, // v + {data+63, data+64,}, // w + {data+63, data+67,}, // word + {data+67, data+73,}, // xdigit + }; + const character_pointer_range* ranges_begin = ranges; + const character_pointer_range* ranges_end = ranges + (sizeof(ranges)/sizeof(ranges[0])); + + character_pointer_range t = { p1, p2, }; + const character_pointer_range* p = std::lower_bound(ranges_begin, ranges_end, t); + if((p != ranges_end) && (t == *p)) + return static_cast(p - ranges); + return -1; +} + +// +// helper functions: +// +template +std::ptrdiff_t global_length(const charT* p) +{ + std::ptrdiff_t n = 0; + while(*p) + { + ++p; + ++n; + } + return n; +} +template<> +inline std::ptrdiff_t global_length(const char* p) +{ + return (std::strlen)(p); +} +#ifndef BOOST_NO_WREGEX +template<> +inline std::ptrdiff_t global_length(const wchar_t* p) +{ + return (std::ptrdiff_t)(std::wcslen)(p); +} +#endif +template +inline charT BOOST_REGEX_CALL global_lower(charT c) +{ + return c; +} +template +inline charT BOOST_REGEX_CALL global_upper(charT c) +{ + return c; +} + +inline char BOOST_REGEX_CALL do_global_lower(char c) +{ + return static_cast((std::tolower)((unsigned char)c)); +} + +inline char BOOST_REGEX_CALL do_global_upper(char c) +{ + return static_cast((std::toupper)((unsigned char)c)); +} +#ifndef BOOST_NO_WREGEX +inline wchar_t BOOST_REGEX_CALL do_global_lower(wchar_t c) +{ + return (std::towlower)(c); +} + +inline wchar_t BOOST_REGEX_CALL do_global_upper(wchar_t c) +{ + return (std::towupper)(c); +} +#endif +// +// This sucks: declare template specialisations of global_lower/global_upper +// that just forward to the non-template implementation functions. We do +// this because there is one compiler (Compaq Tru64 C++) that doesn't seem +// to differentiate between templates and non-template overloads.... +// what's more, the primary template, plus all overloads have to be +// defined in the same translation unit (if one is inline they all must be) +// otherwise the "local template instantiation" compiler option can pick +// the wrong instantiation when linking: +// +template<> inline char BOOST_REGEX_CALL global_lower(char c) { return do_global_lower(c); } +template<> inline char BOOST_REGEX_CALL global_upper(char c) { return do_global_upper(c); } +#ifndef BOOST_NO_WREGEX +template<> inline wchar_t BOOST_REGEX_CALL global_lower(wchar_t c) { return do_global_lower(c); } +template<> inline wchar_t BOOST_REGEX_CALL global_upper(wchar_t c) { return do_global_upper(c); } +#endif + +template +int global_value(charT c) +{ + static const charT zero = '0'; + static const charT nine = '9'; + static const charT a = 'a'; + static const charT f = 'f'; + static const charT A = 'A'; + static const charT F = 'F'; + + if(c > f) return -1; + if(c >= a) return 10 + (c - a); + if(c > F) return -1; + if(c >= A) return 10 + (c - A); + if(c > nine) return -1; + if(c >= zero) return c - zero; + return -1; +} +template +boost::intmax_t global_toi(const charT*& p1, const charT* p2, int radix, const traits& t) +{ + (void)t; // warning suppression + boost::intmax_t limit = (std::numeric_limits::max)() / radix; + boost::intmax_t next_value = t.value(*p1, radix); + if((p1 == p2) || (next_value < 0) || (next_value >= radix)) + return -1; + boost::intmax_t result = 0; + while(p1 != p2) + { + next_value = t.value(*p1, radix); + if((next_value < 0) || (next_value >= radix)) + break; + result *= radix; + result += next_value; + ++p1; + if (result > limit) + return -1; + } + return result; +} + +template +inline typename boost::enable_if_c<(sizeof(charT) > 1), const charT*>::type get_escape_R_string() +{ +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4309 4245) +#endif + static const charT e1[] = { '(', '?', '-', 'x', ':', '(', '?', '>', '\x0D', '\x0A', '?', + '|', '[', '\x0A', '\x0B', '\x0C', static_cast(0x85), static_cast(0x2028), + static_cast(0x2029), ']', ')', ')', '\0' }; + static const charT e2[] = { '(', '?', '-', 'x', ':', '(', '?', '>', '\x0D', '\x0A', '?', + '|', '[', '\x0A', '\x0B', '\x0C', static_cast(0x85), ']', ')', ')', '\0' }; + + charT c = static_cast(0x2029u); + bool b = (static_cast(c) == 0x2029u); + + return (b ? e1 : e2); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +} + +template +inline typename boost::disable_if_c<(sizeof(charT) > 1), const charT*>::type get_escape_R_string() +{ +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4309) +#endif + static const charT e2[] = { '(', '?', '-', 'x', ':', '(', '?', '>', '\x0D', '\x0A', '?', + '|', '[', '\x0A', '\x0B', '\x0C', '\x85', ']', ')', ')', '\0' }; + return e2; +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +} + +} // BOOST_REGEX_DETAIL_NS +} // boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/regex_workaround.hpp b/third-party/boost_regex/include/boost/regex/v4/regex_workaround.hpp new file mode 100644 index 0000000000..324136e07b --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/regex_workaround.hpp @@ -0,0 +1,237 @@ +/* + * + * Copyright (c) 1998-2005 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_workarounds.cpp + * VERSION see + * DESCRIPTION: Declares Misc workarounds. + */ + +#ifndef BOOST_REGEX_WORKAROUND_HPP +#define BOOST_REGEX_WORKAROUND_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef BOOST_NO_STD_LOCALE +# include +#endif + +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::sprintf; using ::strcpy; using ::strcat; using ::strlen; +} +#endif + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ +#ifdef BOOST_NO_STD_DISTANCE +template +std::ptrdiff_t distance(const T& x, const T& y) +{ return y - x; } +#else +using std::distance; +#endif +}} + + +#ifdef BOOST_REGEX_NO_BOOL +# define BOOST_REGEX_MAKE_BOOL(x) static_cast((x) ? true : false) +#else +# define BOOST_REGEX_MAKE_BOOL(x) static_cast(x) +#endif + +/***************************************************************************** + * + * Fix broken namespace support: + * + ****************************************************************************/ + +#if defined(BOOST_NO_STDC_NAMESPACE) && defined(__cplusplus) + +namespace std{ + using ::ptrdiff_t; + using ::size_t; + using ::abs; + using ::memset; + using ::memcpy; +} + +#endif + +/***************************************************************************** + * + * helper functions pointer_construct/pointer_destroy: + * + ****************************************************************************/ + +#ifdef __cplusplus +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_MSVC +#pragma warning (push) +#pragma warning (disable : 4100) +#endif + +template +inline void pointer_destroy(T* p) +{ p->~T(); (void)p; } + +#ifdef BOOST_MSVC +#pragma warning (pop) +#endif + +template +inline void pointer_construct(T* p, const T& t) +{ new (p) T(t); } + +}} // namespaces +#endif + +/***************************************************************************** + * + * helper function copy: + * + ****************************************************************************/ + +#ifdef __cplusplus +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ +#if BOOST_WORKAROUND(BOOST_MSVC,>=1400) && BOOST_WORKAROUND(BOOST_MSVC, <1600) && defined(_CPPLIB_VER) && defined(BOOST_DINKUMWARE_STDLIB) && !(defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) + // + // MSVC 8 will either emit warnings or else refuse to compile + // code that makes perfectly legitimate use of std::copy, when + // the OutputIterator type is a user-defined class (apparently all user + // defined iterators are "unsafe"). This code works around that: + // + template + inline OutputIterator copy( + InputIterator first, + InputIterator last, + OutputIterator dest + ) + { + return stdext::unchecked_copy(first, last, dest); + } + template + inline bool equal( + InputIterator1 first, + InputIterator1 last, + InputIterator2 with + ) + { + return stdext::unchecked_equal(first, last, with); + } +#elif BOOST_WORKAROUND(BOOST_MSVC, > 1500) + // + // MSVC 10 will either emit warnings or else refuse to compile + // code that makes perfectly legitimate use of std::copy, when + // the OutputIterator type is a user-defined class (apparently all user + // defined iterators are "unsafe"). What's more Microsoft have removed their + // non-standard "unchecked" versions, even though their still in the MS + // documentation!! Work around this as best we can: + // + template + inline OutputIterator copy( + InputIterator first, + InputIterator last, + OutputIterator dest + ) + { + while(first != last) + *dest++ = *first++; + return dest; + } + template + inline bool equal( + InputIterator1 first, + InputIterator1 last, + InputIterator2 with + ) + { + while(first != last) + if(*first++ != *with++) return false; + return true; + } +#else + using std::copy; + using std::equal; +#endif +#if BOOST_WORKAROUND(BOOST_MSVC,>=1400) && defined(__STDC_WANT_SECURE_LIB__) && __STDC_WANT_SECURE_LIB__ + + // use safe versions of strcpy etc: + using ::strcpy_s; + using ::strcat_s; +#else + inline std::size_t strcpy_s( + char *strDestination, + std::size_t sizeInBytes, + const char *strSource + ) + { + std::size_t lenSourceWithNull = std::strlen(strSource) + 1; + if (lenSourceWithNull > sizeInBytes) + return 1; + std::memcpy(strDestination, strSource, lenSourceWithNull); + return 0; + } + inline std::size_t strcat_s( + char *strDestination, + std::size_t sizeInBytes, + const char *strSource + ) + { + std::size_t lenSourceWithNull = std::strlen(strSource) + 1; + std::size_t lenDestination = std::strlen(strDestination); + if (lenSourceWithNull + lenDestination > sizeInBytes) + return 1; + std::memcpy(strDestination + lenDestination, strSource, lenSourceWithNull); + return 0; + } + +#endif + + inline void overflow_error_if_not_zero(std::size_t i) + { + if(i) + { + std::overflow_error e("String buffer too small"); + boost::throw_exception(e); + } + } + +}} // namespaces + +#endif // __cplusplus + +#endif // include guard + diff --git a/third-party/boost_regex/include/boost/regex/v4/states.hpp b/third-party/boost_regex/include/boost/regex/v4/states.hpp new file mode 100644 index 0000000000..86eb02b102 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/states.hpp @@ -0,0 +1,321 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE states.cpp + * VERSION see + * DESCRIPTION: Declares internal state machine structures. + */ + +#ifndef BOOST_REGEX_V4_STATES_HPP +#define BOOST_REGEX_V4_STATES_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +/*** mask_type ******************************************************* +Whenever we have a choice of two alternatives, we use an array of bytes +to indicate which of the two alternatives it is possible to take for any +given input character. If mask_take is set, then we can take the next +state, and if mask_skip is set then we can take the alternative. +***********************************************************************/ +enum mask_type +{ + mask_take = 1, + mask_skip = 2, + mask_init = 4, + mask_any = mask_skip | mask_take, + mask_all = mask_any +}; + +/*** helpers ********************************************************** +These helpers let us use function overload resolution to detect whether +we have narrow or wide character strings: +***********************************************************************/ +struct _narrow_type{}; +struct _wide_type{}; +template struct is_byte; +template<> struct is_byte { typedef _narrow_type width_type; }; +template<> struct is_byte{ typedef _narrow_type width_type; }; +template<> struct is_byte { typedef _narrow_type width_type; }; +template struct is_byte { typedef _wide_type width_type; }; + +/*** enum syntax_element_type ****************************************** +Every record in the state machine falls into one of the following types: +***********************************************************************/ +enum syntax_element_type +{ + // start of a marked sub-expression, or perl-style (?...) extension + syntax_element_startmark = 0, + // end of a marked sub-expression, or perl-style (?...) extension + syntax_element_endmark = syntax_element_startmark + 1, + // any sequence of literal characters + syntax_element_literal = syntax_element_endmark + 1, + // start of line assertion: ^ + syntax_element_start_line = syntax_element_literal + 1, + // end of line assertion $ + syntax_element_end_line = syntax_element_start_line + 1, + // match any character: . + syntax_element_wild = syntax_element_end_line + 1, + // end of expression: we have a match when we get here + syntax_element_match = syntax_element_wild + 1, + // perl style word boundary: \b + syntax_element_word_boundary = syntax_element_match + 1, + // perl style within word boundary: \B + syntax_element_within_word = syntax_element_word_boundary + 1, + // start of word assertion: \< + syntax_element_word_start = syntax_element_within_word + 1, + // end of word assertion: \> + syntax_element_word_end = syntax_element_word_start + 1, + // start of buffer assertion: \` + syntax_element_buffer_start = syntax_element_word_end + 1, + // end of buffer assertion: \' + syntax_element_buffer_end = syntax_element_buffer_start + 1, + // backreference to previously matched sub-expression + syntax_element_backref = syntax_element_buffer_end + 1, + // either a wide character set [..] or one with multicharacter collating elements: + syntax_element_long_set = syntax_element_backref + 1, + // narrow character set: [...] + syntax_element_set = syntax_element_long_set + 1, + // jump to a new state in the machine: + syntax_element_jump = syntax_element_set + 1, + // choose between two production states: + syntax_element_alt = syntax_element_jump + 1, + // a repeat + syntax_element_rep = syntax_element_alt + 1, + // match a combining character sequence + syntax_element_combining = syntax_element_rep + 1, + // perl style soft buffer end: \z + syntax_element_soft_buffer_end = syntax_element_combining + 1, + // perl style continuation: \G + syntax_element_restart_continue = syntax_element_soft_buffer_end + 1, + // single character repeats: + syntax_element_dot_rep = syntax_element_restart_continue + 1, + syntax_element_char_rep = syntax_element_dot_rep + 1, + syntax_element_short_set_rep = syntax_element_char_rep + 1, + syntax_element_long_set_rep = syntax_element_short_set_rep + 1, + // a backstep for lookbehind repeats: + syntax_element_backstep = syntax_element_long_set_rep + 1, + // an assertion that a mark was matched: + syntax_element_assert_backref = syntax_element_backstep + 1, + syntax_element_toggle_case = syntax_element_assert_backref + 1, + // a recursive expression: + syntax_element_recurse = syntax_element_toggle_case + 1, + // Verbs: + syntax_element_fail = syntax_element_recurse + 1, + syntax_element_accept = syntax_element_fail + 1, + syntax_element_commit = syntax_element_accept + 1, + syntax_element_then = syntax_element_commit + 1 +}; + +#ifdef BOOST_REGEX_DEBUG +// dwa 09/26/00 - This is needed to suppress warnings about an ambiguous conversion +std::ostream& operator<<(std::ostream&, syntax_element_type); +#endif + +struct re_syntax_base; + +/*** union offset_type ************************************************ +Points to another state in the machine. During machine construction +we use integral offsets, but these are converted to pointers before +execution of the machine. +***********************************************************************/ +union offset_type +{ + re_syntax_base* p; + std::ptrdiff_t i; +}; + +/*** struct re_syntax_base ******************************************** +Base class for all states in the machine. +***********************************************************************/ +struct re_syntax_base +{ + syntax_element_type type; // what kind of state this is + offset_type next; // next state in the machine +}; + +/*** struct re_brace ************************************************** +A marked parenthesis. +***********************************************************************/ +struct re_brace : public re_syntax_base +{ + // The index to match, can be zero (don't mark the sub-expression) + // or negative (for perl style (?...) extensions): + int index; + bool icase; +}; + +/*** struct re_dot ************************************************** +Match anything. +***********************************************************************/ +enum +{ + dont_care = 1, + force_not_newline = 0, + force_newline = 2, + + test_not_newline = 2, + test_newline = 3 +}; +struct re_dot : public re_syntax_base +{ + unsigned char mask; +}; + +/*** struct re_literal ************************************************ +A string of literals, following this structure will be an +array of characters: charT[length] +***********************************************************************/ +struct re_literal : public re_syntax_base +{ + unsigned int length; +}; + +/*** struct re_case ************************************************ +Indicates whether we are moving to a case insensive block or not +***********************************************************************/ +struct re_case : public re_syntax_base +{ + bool icase; +}; + +/*** struct re_set_long *********************************************** +A wide character set of characters, following this structure will be +an array of type charT: +First csingles null-terminated strings +Then 2 * cranges NULL terminated strings +Then cequivalents NULL terminated strings +***********************************************************************/ +template +struct re_set_long : public re_syntax_base +{ + unsigned int csingles, cranges, cequivalents; + mask_type cclasses; + mask_type cnclasses; + bool isnot; + bool singleton; +}; + +/*** struct re_set **************************************************** +A set of narrow-characters, matches any of _map which is none-zero +***********************************************************************/ +struct re_set : public re_syntax_base +{ + unsigned char _map[1 << CHAR_BIT]; +}; + +/*** struct re_jump *************************************************** +Jump to a new location in the machine (not next). +***********************************************************************/ +struct re_jump : public re_syntax_base +{ + offset_type alt; // location to jump to +}; + +/*** struct re_alt *************************************************** +Jump to a new location in the machine (possibly next). +***********************************************************************/ +struct re_alt : public re_jump +{ + unsigned char _map[1 << CHAR_BIT]; // which characters can take the jump + unsigned int can_be_null; // true if we match a NULL string +}; + +/*** struct re_repeat ************************************************* +Repeat a section of the machine +***********************************************************************/ +struct re_repeat : public re_alt +{ + std::size_t min, max; // min and max allowable repeats + int state_id; // Unique identifier for this repeat + bool leading; // True if this repeat is at the start of the machine (lets us optimize some searches) + bool greedy; // True if this is a greedy repeat +}; + +/*** struct re_recurse ************************************************ +Recurse to a particular subexpression. +**********************************************************************/ +struct re_recurse : public re_jump +{ + int state_id; // identifier of first nested repeat within the recursion. +}; + +/*** struct re_commit ************************************************* +Used for the PRUNE, SKIP and COMMIT verbs which basically differ only in what happens +if no match is found and we start searching forward. +**********************************************************************/ +enum commit_type +{ + commit_prune, + commit_skip, + commit_commit +}; +struct re_commit : public re_syntax_base +{ + commit_type action; +}; + +/*** enum re_jump_size_type ******************************************* +Provides compiled size of re_jump structure (allowing for trailing alignment). +We provide this so we know how manybytes to insert when constructing the machine +(The value of padding_mask is defined in regex_raw_buffer.hpp). +***********************************************************************/ +enum re_jump_size_type +{ + re_jump_size = (sizeof(re_jump) + padding_mask) & ~(padding_mask), + re_repeater_size = (sizeof(re_repeat) + padding_mask) & ~(padding_mask), + re_alt_size = (sizeof(re_alt) + padding_mask) & ~(padding_mask) +}; + +/*** proc re_is_set_member ********************************************* +Forward declaration: we'll need this one later... +***********************************************************************/ + +template +struct regex_data; + +template +iterator BOOST_REGEX_CALL re_is_set_member(iterator next, + iterator last, + const re_set_long* set_, + const regex_data& e, bool icase); + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v4/sub_match.hpp b/third-party/boost_regex/include/boost/regex/v4/sub_match.hpp new file mode 100644 index 0000000000..30a580d523 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/sub_match.hpp @@ -0,0 +1,516 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE sub_match.cpp + * VERSION see + * DESCRIPTION: Declares template class sub_match. + */ + +#ifndef BOOST_REGEX_V4_SUB_MATCH_HPP +#define BOOST_REGEX_V4_SUB_MATCH_HPP + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +namespace boost{ + +template +struct sub_match : public std::pair +{ + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type value_type; +#if defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::ptrdiff_t difference_type; +#else + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::difference_type difference_type; +#endif + typedef BidiIterator iterator_type; + typedef BidiIterator iterator; + typedef BidiIterator const_iterator; + + bool matched; + + sub_match() : std::pair(), matched(false) {} + sub_match(BidiIterator i) : std::pair(i, i), matched(false) {} +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x0551)\ + && !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) + template + operator std::basic_string ()const + { + return matched ? std::basic_string(this->first, this->second) : std::basic_string(); + } +#else + operator std::basic_string ()const + { + return str(); + } +#endif + difference_type BOOST_REGEX_CALL length()const + { + difference_type n = matched ? ::boost::BOOST_REGEX_DETAIL_NS::distance((BidiIterator)this->first, (BidiIterator)this->second) : 0; + return n; + } + std::basic_string str()const + { + std::basic_string result; + if(matched) + { + std::size_t len = ::boost::BOOST_REGEX_DETAIL_NS::distance((BidiIterator)this->first, (BidiIterator)this->second); + result.reserve(len); + BidiIterator i = this->first; + while(i != this->second) + { + result.append(1, *i); + ++i; + } + } + return result; + } + int compare(const sub_match& s)const + { + if(matched != s.matched) + return static_cast(matched) - static_cast(s.matched); + return str().compare(s.str()); + } + int compare(const std::basic_string& s)const + { + return str().compare(s); + } + int compare(const value_type* p)const + { + return str().compare(p); + } + + bool operator==(const sub_match& that)const + { return compare(that) == 0; } + bool BOOST_REGEX_CALL operator !=(const sub_match& that)const + { return compare(that) != 0; } + bool operator<(const sub_match& that)const + { return compare(that) < 0; } + bool operator>(const sub_match& that)const + { return compare(that) > 0; } + bool operator<=(const sub_match& that)const + { return compare(that) <= 0; } + bool operator>=(const sub_match& that)const + { return compare(that) >= 0; } + +#ifdef BOOST_REGEX_MATCH_EXTRA + typedef std::vector > capture_sequence_type; + + const capture_sequence_type& captures()const + { + if(!m_captures) + m_captures.reset(new capture_sequence_type()); + return *m_captures; + } + // + // Private implementation API: DO NOT USE! + // + capture_sequence_type& get_captures()const + { + if(!m_captures) + m_captures.reset(new capture_sequence_type()); + return *m_captures; + } + +private: + mutable boost::scoped_ptr m_captures; +public: + +#endif + sub_match(const sub_match& that, bool +#ifdef BOOST_REGEX_MATCH_EXTRA + deep_copy +#endif + = true + ) + : std::pair(that), + matched(that.matched) + { +#ifdef BOOST_REGEX_MATCH_EXTRA + if(that.m_captures) + if(deep_copy) + m_captures.reset(new capture_sequence_type(*(that.m_captures))); +#endif + } + sub_match& operator=(const sub_match& that) + { + this->first = that.first; + this->second = that.second; + matched = that.matched; +#ifdef BOOST_REGEX_MATCH_EXTRA + if(that.m_captures) + get_captures() = *(that.m_captures); +#endif + return *this; + } + // + // Make this type a range, for both Boost.Range, and C++11: + // + BidiIterator begin()const { return this->first; } + BidiIterator end()const { return this->second; } + + +#ifdef BOOST_OLD_REGEX_H + // + // the following are deprecated, do not use!! + // + operator int()const; + operator unsigned int()const; + operator short()const + { + return (short)(int)(*this); + } + operator unsigned short()const + { + return (unsigned short)(unsigned int)(*this); + } +#endif +}; + +typedef sub_match csub_match; +typedef sub_match ssub_match; +#ifndef BOOST_NO_WREGEX +typedef sub_match wcsub_match; +typedef sub_match wssub_match; +#endif + +// comparison to std::basic_string<> part 1: +template +inline bool operator == (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) == 0; } +template +inline bool operator != (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) != 0; } +template +inline bool operator < (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) < 0; } +template +inline bool operator <= (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) <= 0; } +template +inline bool operator >= (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) >= 0; } +template +inline bool operator > (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) > 0; } +// comparison to std::basic_string<> part 2: +template +inline bool operator == (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) != 0; } +template +inline bool operator < (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) < 0; } +template +inline bool operator > (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) > 0; } +template +inline bool operator <= (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) <= 0; } +template +inline bool operator >= (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) >= 0; } +// comparison to const charT* part 1: +template +inline bool operator == (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) != 0; } +template +inline bool operator > (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) > 0; } +template +inline bool operator < (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) < 0; } +template +inline bool operator >= (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) >= 0; } +template +inline bool operator <= (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s) +{ return m.str().compare(s) <= 0; } +// comparison to const charT* part 2: +template +inline bool operator == (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) != 0; } +template +inline bool operator < (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) > 0; } +template +inline bool operator > (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) < 0; } +template +inline bool operator <= (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) >= 0; } +template +inline bool operator >= (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) <= 0; } + +// comparison to const charT& part 1: +template +inline bool operator == (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) == 0; } +template +inline bool operator != (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) != 0; } +template +inline bool operator > (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) > 0; } +template +inline bool operator < (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) < 0; } +template +inline bool operator >= (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) >= 0; } +template +inline bool operator <= (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) <= 0; } +// comparison to const charT* part 2: +template +inline bool operator == (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) == 0; } +template +inline bool operator != (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) != 0; } +template +inline bool operator < (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) > 0; } +template +inline bool operator > (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) < 0; } +template +inline bool operator <= (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) >= 0; } +template +inline bool operator >= (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) <= 0; } + +// addition operators: +template +inline std::basic_string::value_type, traits, Allocator> +operator + (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ + std::basic_string::value_type, traits, Allocator> result; + result.reserve(s.size() + m.length() + 1); + return result.append(s).append(m.first, m.second); +} +template +inline std::basic_string::value_type, traits, Allocator> +operator + (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ + std::basic_string::value_type, traits, Allocator> result; + result.reserve(s.size() + m.length() + 1); + return result.append(m.first, m.second).append(s); +} +#if !(defined(__GNUC__) && defined(BOOST_NO_STD_LOCALE)) +template +inline std::basic_string::value_type> +operator + (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ + std::basic_string::value_type> result; + result.reserve(std::char_traits::value_type>::length(s) + m.length() + 1); + return result.append(s).append(m.first, m.second); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const * s) +{ + std::basic_string::value_type> result; + result.reserve(std::char_traits::value_type>::length(s) + m.length() + 1); + return result.append(m.first, m.second).append(s); +} +#else +// worwaround versions: +template +inline std::basic_string::value_type> +operator + (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const* s, + const sub_match& m) +{ + return s + m.str(); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const * s) +{ + return m.str() + s; +} +#endif +template +inline std::basic_string::value_type> +operator + (typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s, + const sub_match& m) +{ + std::basic_string::value_type> result; + result.reserve(m.length() + 2); + return result.append(1, s).append(m.first, m.second); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m, + typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::value_type const& s) +{ + std::basic_string::value_type> result; + result.reserve(m.length() + 2); + return result.append(m.first, m.second).append(1, s); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m1, + const sub_match& m2) +{ + std::basic_string::value_type> result; + result.reserve(m1.length() + m2.length() + 1); + return result.append(m1.first, m1.second).append(m2.first, m2.second); +} +#ifndef BOOST_NO_STD_LOCALE +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const sub_match& s) +{ + return (os << s.str()); +} +#else +template +std::ostream& operator << (std::ostream& os, + const sub_match& s) +{ + return (os << s.str()); +} +#endif + +#ifdef BOOST_OLD_REGEX_H +namespace BOOST_REGEX_DETAIL_NS{ +template +int do_toi(BidiIterator i, BidiIterator j, char c, int radix) +{ + std::string s(i, j); + char* p; + int result = std::strtol(s.c_str(), &p, radix); + if(*p)raise_regex_exception("Bad sub-expression"); + return result; +} + +// +// helper: +template +int do_toi(I& i, I j, charT c) +{ + int result = 0; + while((i != j) && (isdigit(*i))) + { + result = result*10 + (*i - '0'); + ++i; + } + return result; +} +} + + +template +sub_match::operator int()const +{ + BidiIterator i = first; + BidiIterator j = second; + if(i == j)raise_regex_exception("Bad sub-expression"); + int neg = 1; + if((i != j) && (*i == '-')) + { + neg = -1; + ++i; + } + neg *= BOOST_REGEX_DETAIL_NS::do_toi(i, j, *i); + if(i != j)raise_regex_exception("Bad sub-expression"); + return neg; +} +template +sub_match::operator unsigned int()const +{ + BidiIterator i = first; + BidiIterator j = second; + if(i == j) + raise_regex_exception("Bad sub-expression"); + return BOOST_REGEX_DETAIL_NS::do_toi(i, j, *first); +} +#endif + +} // namespace boost + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v4/syntax_type.hpp b/third-party/boost_regex/include/boost/regex/v4/syntax_type.hpp new file mode 100644 index 0000000000..3efdf0b0f9 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/syntax_type.hpp @@ -0,0 +1,105 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE syntax_type.hpp + * VERSION see + * DESCRIPTION: Declares regular expression synatx type enumerator. + */ + +#ifndef BOOST_REGEX_SYNTAX_TYPE_HPP +#define BOOST_REGEX_SYNTAX_TYPE_HPP + +namespace boost{ +namespace regex_constants{ + +typedef unsigned char syntax_type; + +// +// values chosen are binary compatible with previous version: +// +static const syntax_type syntax_char = 0; +static const syntax_type syntax_open_mark = 1; +static const syntax_type syntax_close_mark = 2; +static const syntax_type syntax_dollar = 3; +static const syntax_type syntax_caret = 4; +static const syntax_type syntax_dot = 5; +static const syntax_type syntax_star = 6; +static const syntax_type syntax_plus = 7; +static const syntax_type syntax_question = 8; +static const syntax_type syntax_open_set = 9; +static const syntax_type syntax_close_set = 10; +static const syntax_type syntax_or = 11; +static const syntax_type syntax_escape = 12; +static const syntax_type syntax_dash = 14; +static const syntax_type syntax_open_brace = 15; +static const syntax_type syntax_close_brace = 16; +static const syntax_type syntax_digit = 17; +static const syntax_type syntax_comma = 27; +static const syntax_type syntax_equal = 37; +static const syntax_type syntax_colon = 36; +static const syntax_type syntax_not = 53; + +// extensions: + +static const syntax_type syntax_hash = 13; +static const syntax_type syntax_newline = 26; + +// escapes: + +typedef syntax_type escape_syntax_type; + +static const escape_syntax_type escape_type_word_assert = 18; +static const escape_syntax_type escape_type_not_word_assert = 19; +static const escape_syntax_type escape_type_control_f = 29; +static const escape_syntax_type escape_type_control_n = 30; +static const escape_syntax_type escape_type_control_r = 31; +static const escape_syntax_type escape_type_control_t = 32; +static const escape_syntax_type escape_type_control_v = 33; +static const escape_syntax_type escape_type_ascii_control = 35; +static const escape_syntax_type escape_type_hex = 34; +static const escape_syntax_type escape_type_unicode = 0; // not used +static const escape_syntax_type escape_type_identity = 0; // not used +static const escape_syntax_type escape_type_backref = syntax_digit; +static const escape_syntax_type escape_type_decimal = syntax_digit; // not used +static const escape_syntax_type escape_type_class = 22; +static const escape_syntax_type escape_type_not_class = 23; + +// extensions: + +static const escape_syntax_type escape_type_left_word = 20; +static const escape_syntax_type escape_type_right_word = 21; +static const escape_syntax_type escape_type_start_buffer = 24; // for \` +static const escape_syntax_type escape_type_end_buffer = 25; // for \' +static const escape_syntax_type escape_type_control_a = 28; // for \a +static const escape_syntax_type escape_type_e = 38; // for \e +static const escape_syntax_type escape_type_E = 47; // for \Q\E +static const escape_syntax_type escape_type_Q = 48; // for \Q\E +static const escape_syntax_type escape_type_X = 49; // for \X +static const escape_syntax_type escape_type_C = 50; // for \C +static const escape_syntax_type escape_type_Z = 51; // for \Z +static const escape_syntax_type escape_type_G = 52; // for \G + +static const escape_syntax_type escape_type_property = 54; // for \p +static const escape_syntax_type escape_type_not_property = 55; // for \P +static const escape_syntax_type escape_type_named_char = 56; // for \N +static const escape_syntax_type escape_type_extended_backref = 57; // for \g +static const escape_syntax_type escape_type_reset_start_mark = 58; // for \K +static const escape_syntax_type escape_type_line_ending = 59; // for \R + +static const escape_syntax_type syntax_max = 60; + +} +} + + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v4/u32regex_iterator.hpp b/third-party/boost_regex/include/boost/regex/v4/u32regex_iterator.hpp new file mode 100644 index 0000000000..f8763a8d6a --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/u32regex_iterator.hpp @@ -0,0 +1,185 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE u32regex_iterator.hpp + * VERSION see + * DESCRIPTION: Provides u32regex_iterator implementation. + */ + +#ifndef BOOST_REGEX_V4_U32REGEX_ITERATOR_HPP +#define BOOST_REGEX_V4_U32REGEX_ITERATOR_HPP + +namespace boost{ + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +template +class u32regex_iterator_implementation +{ + typedef u32regex regex_type; + + match_results what; // current match + BidirectionalIterator base; // start of sequence + BidirectionalIterator end; // end of sequence + const regex_type re; // the expression + match_flag_type flags; // flags for matching + +public: + u32regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f) + : base(), end(last), re(*p), flags(f){} + bool init(BidirectionalIterator first) + { + base = first; + return u32regex_search(first, end, what, re, flags, base); + } + bool compare(const u32regex_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second); + } + const match_results& get() + { return what; } + bool next() + { + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail; + BidirectionalIterator next_start = what[0].second; + match_flag_type f(flags); + if(!what.length()) + f |= regex_constants::match_not_initial_null; + //if(base != next_start) + // f |= regex_constants::match_not_bob; + bool result = u32regex_search(next_start, end, what, re, f, base); + if(result) + what.set_base(base); + return result; + } +private: + u32regex_iterator_implementation& operator=(const u32regex_iterator_implementation&); +}; + +template +class u32regex_iterator +{ +private: + typedef u32regex_iterator_implementation impl; + typedef shared_ptr pimpl; +public: + typedef u32regex regex_type; + typedef match_results value_type; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + u32regex_iterator(){} + u32regex_iterator(BidirectionalIterator a, BidirectionalIterator b, + const regex_type& re, + match_flag_type m = match_default) + : pdata(new impl(&re, b, m)) + { + if(!pdata->init(a)) + { + pdata.reset(); + } + } + u32regex_iterator(const u32regex_iterator& that) + : pdata(that.pdata) {} + u32regex_iterator& operator=(const u32regex_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const u32regex_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const u32regex_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + u32regex_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + u32regex_iterator operator++(int) + { + u32regex_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && !pdata.unique()) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef u32regex_iterator utf8regex_iterator; +typedef u32regex_iterator utf16regex_iterator; +typedef u32regex_iterator utf32regex_iterator; + +inline u32regex_iterator make_u32regex_iterator(const char* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+std::strlen(p), e, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_iterator make_u32regex_iterator(const wchar_t* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+std::wcslen(p), e, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +inline u32regex_iterator make_u32regex_iterator(const UChar* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+u_strlen(p), e, m); +} +#endif +template +inline u32regex_iterator::const_iterator> make_u32regex_iterator(const std::basic_string& p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_iterator(p.begin(), p.end(), e, m); +} +inline u32regex_iterator make_u32regex_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, m); +} + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v4/u32regex_token_iterator.hpp b/third-party/boost_regex/include/boost/regex/v4/u32regex_token_iterator.hpp new file mode 100644 index 0000000000..2e04810dff --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/u32regex_token_iterator.hpp @@ -0,0 +1,360 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE u32regex_token_iterator.hpp + * VERSION see + * DESCRIPTION: Provides u32regex_token_iterator implementation. + */ + +#ifndef BOOST_REGEX_V4_U32REGEX_TOKEN_ITERATOR_HPP +#define BOOST_REGEX_V4_U32REGEX_TOKEN_ITERATOR_HPP + +#if (BOOST_WORKAROUND(BOOST_BORLANDC, >= 0x560) && BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) +// +// Borland C++ Builder 6, and Visual C++ 6, +// can't cope with the array template constructor +// so we have a template member that will accept any type as +// argument, and then assert that is really is an array: +// +#include +#include +#endif + +namespace boost{ + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4700) +#endif + +template +class u32regex_token_iterator_implementation +{ + typedef u32regex regex_type; + typedef sub_match value_type; + + match_results what; // current match + BidirectionalIterator end; // end of search area + BidirectionalIterator base; // start of search area + const regex_type re; // the expression + match_flag_type flags; // match flags + value_type result; // the current string result + int N; // the current sub-expression being enumerated + std::vector subs; // the sub-expressions to enumerate + +public: + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, int sub, match_flag_type f) + : end(last), re(*p), flags(f){ subs.push_back(sub); } + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const std::vector& v, match_flag_type f) + : end(last), re(*p), flags(f), subs(v){} +#if (BOOST_WORKAROUND(__BORLANDC__, >= 0x560) && BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) \ + || BOOST_WORKAROUND(__HP_aCC, < 60700) + template + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const T& submatches, match_flag_type f) + : end(last), re(*p), flags(f) + { + // assert that T really is an array: + BOOST_STATIC_ASSERT(::boost::is_array::value); + const std::size_t array_size = sizeof(T) / sizeof(submatches[0]); + for(std::size_t i = 0; i < array_size; ++i) + { + subs.push_back(submatches[i]); + } + } +#else + template + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const int (&submatches)[CN], match_flag_type f) + : end(last), re(*p), flags(f) + { + for(std::size_t i = 0; i < CN; ++i) + { + subs.push_back(submatches[i]); + } + } +#endif + + bool init(BidirectionalIterator first) + { + base = first; + N = 0; + if(u32regex_search(first, end, what, re, flags, base) == true) + { + N = 0; + result = ((subs[N] == -1) ? what.prefix() : what[(int)subs[N]]); + return true; + } + else if((subs[N] == -1) && (first != end)) + { + result.first = first; + result.second = end; + result.matched = (first != end); + N = -1; + return true; + } + return false; + } + bool compare(const u32regex_token_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) + && (end == that.end) + && (flags == that.flags) + && (N == that.N) + && (what[0].first == that.what[0].first) + && (what[0].second == that.what[0].second); + } + const value_type& get() + { return result; } + bool next() + { + if(N == -1) + return false; + if(N+1 < (int)subs.size()) + { + ++N; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail | regex_constants::match_not_bob; + BidirectionalIterator last_end(what[0].second); + if(u32regex_search(last_end, end, what, re, ((what[0].first == what[0].second) ? flags | regex_constants::match_not_initial_null : flags), base)) + { + N =0; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + else if((last_end != end) && (subs[0] == -1)) + { + N =-1; + result.first = last_end; + result.second = end; + result.matched = (last_end != end); + return true; + } + return false; + } +private: + u32regex_token_iterator_implementation& operator=(const u32regex_token_iterator_implementation&); +}; + +template +class u32regex_token_iterator +{ +private: + typedef u32regex_token_iterator_implementation impl; + typedef shared_ptr pimpl; +public: + typedef u32regex regex_type; + typedef sub_match value_type; + typedef typename BOOST_REGEX_DETAIL_NS::regex_iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + u32regex_token_iterator(){} + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + int submatch = 0, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatch, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const std::vector& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#if (BOOST_WORKAROUND(__BORLANDC__, >= 0x560) && BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x570)))\ + || BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) \ + || BOOST_WORKAROUND(__HP_aCC, < 60700) + template + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const T& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#else + template + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const int (&submatches)[N], match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } +#endif + u32regex_token_iterator(const u32regex_token_iterator& that) + : pdata(that.pdata) {} + u32regex_token_iterator& operator=(const u32regex_token_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const u32regex_token_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const u32regex_token_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + u32regex_token_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + u32regex_token_iterator operator++(int) + { + u32regex_token_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && !pdata.unique()) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef u32regex_token_iterator utf8regex_token_iterator; +typedef u32regex_token_iterator utf16regex_token_iterator; +typedef u32regex_token_iterator utf32regex_token_iterator; + +// construction from an integral sub_match state_id: +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +// construction from a reference to an array: +template +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +template +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +template +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +template +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +// construction from a vector of sub_match state_id's: +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(U_WCHAR_IS_UTF16) && (U_SIZEOF_WCHAR_T != 2) +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V4_REGEX_TOKEN_ITERATOR_HPP + + + + diff --git a/third-party/boost_regex/include/boost/regex/v4/unicode_iterator.hpp b/third-party/boost_regex/include/boost/regex/v4/unicode_iterator.hpp new file mode 100644 index 0000000000..985aa72b20 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/unicode_iterator.hpp @@ -0,0 +1,871 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE unicode_iterator.hpp + * VERSION see + * DESCRIPTION: Iterator adapters for converting between different Unicode encodings. + */ + +/**************************************************************************** + +Contents: +~~~~~~~~~ + +1) Read Only, Input Adapters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +template +class u32_to_u8_iterator; + +Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-8. + +template +class u8_to_u32_iterator; + +Adapts sequence of UTF-8 code points to "look like" a sequence of UTF-32. + +template +class u32_to_u16_iterator; + +Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-16. + +template +class u16_to_u32_iterator; + +Adapts sequence of UTF-16 code points to "look like" a sequence of UTF-32. + +2) Single pass output iterator adapters: + +template +class utf8_output_iterator; + +Accepts UTF-32 code points and forwards them on as UTF-8 code points. + +template +class utf16_output_iterator; + +Accepts UTF-32 code points and forwards them on as UTF-16 code points. + +****************************************************************************/ + +#ifndef BOOST_REGEX_V4_UNICODE_ITERATOR_HPP +#define BOOST_REGEX_V4_UNICODE_ITERATOR_HPP +#include +#include +#include +#include +#include +#ifndef BOOST_NO_STD_LOCALE +#include +#include +#endif +#include // CHAR_BIT + +#ifdef BOOST_REGEX_CXX03 + +#else +#endif + +namespace boost{ + +namespace detail{ + +static const ::boost::uint16_t high_surrogate_base = 0xD7C0u; +static const ::boost::uint16_t low_surrogate_base = 0xDC00u; +static const ::boost::uint32_t ten_bit_mask = 0x3FFu; + +inline bool is_high_surrogate(::boost::uint16_t v) +{ + return (v & 0xFFFFFC00u) == 0xd800u; +} +inline bool is_low_surrogate(::boost::uint16_t v) +{ + return (v & 0xFFFFFC00u) == 0xdc00u; +} +template +inline bool is_surrogate(T v) +{ + return (v & 0xFFFFF800u) == 0xd800; +} + +inline unsigned utf8_byte_count(boost::uint8_t c) +{ + // if the most significant bit with a zero in it is in position + // 8-N then there are N bytes in this UTF-8 sequence: + boost::uint8_t mask = 0x80u; + unsigned result = 0; + while(c & mask) + { + ++result; + mask >>= 1; + } + return (result == 0) ? 1 : ((result > 4) ? 4 : result); +} + +inline unsigned utf8_trailing_byte_count(boost::uint8_t c) +{ + return utf8_byte_count(c) - 1; +} + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4100) +#endif +#ifndef BOOST_NO_EXCEPTIONS +BOOST_NORETURN +#endif +inline void invalid_utf32_code_point(::boost::uint32_t val) +{ +#ifndef BOOST_NO_STD_LOCALE + std::stringstream ss; + ss << "Invalid UTF-32 code point U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-16 sequence"; + std::out_of_range e(ss.str()); +#else + std::out_of_range e("Invalid UTF-32 code point encountered while trying to encode UTF-16 sequence"); +#endif + boost::throw_exception(e); +} +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + +} // namespace detail + +template +class u32_to_u16_iterator +{ +#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef typename std::iterator_traits::value_type base_value_type; + + BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32); + BOOST_STATIC_ASSERT(sizeof(U16Type)*CHAR_BIT == 16); +#endif + +public: + typedef std::ptrdiff_t difference_type; + typedef U16Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_current == 2) + extract_current(); + return m_values[m_current]; + } + bool operator==(const u32_to_u16_iterator& that)const + { + if(m_position == that.m_position) + { + // Both m_currents must be equal, or both even + // this is the same as saying their sum must be even: + return (m_current + that.m_current) & 1u ? false : true; + } + return false; + } + bool operator!=(const u32_to_u16_iterator& that)const + { + return !(*this == that); + } + u32_to_u16_iterator& operator++() + { + // if we have a pending read then read now, so that we know whether + // to skip a position, or move to a low-surrogate: + if(m_current == 2) + { + // pending read: + extract_current(); + } + // move to the next surrogate position: + ++m_current; + // if we've reached the end skip a position: + if(m_values[m_current] == 0) + { + m_current = 2; + ++m_position; + } + return *this; + } + u32_to_u16_iterator operator++(int) + { + u32_to_u16_iterator r(*this); + ++(*this); + return r; + } + u32_to_u16_iterator& operator--() + { + if(m_current != 1) + { + // decrementing an iterator always leads to a valid position: + --m_position; + extract_current(); + m_current = m_values[1] ? 1 : 0; + } + else + { + m_current = 0; + } + return *this; + } + u32_to_u16_iterator operator--(int) + { + u32_to_u16_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u32_to_u16_iterator() : m_position(), m_current(0) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + } + u32_to_u16_iterator(BaseIterator b) : m_position(b), m_current(2) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + } +private: + + void extract_current()const + { + // begin by checking for a code point out of range: + ::boost::uint32_t v = *m_position; + if(v >= 0x10000u) + { + if(v > 0x10FFFFu) + detail::invalid_utf32_code_point(*m_position); + // split into two surrogates: + m_values[0] = static_cast(v >> 10) + detail::high_surrogate_base; + m_values[1] = static_cast(v & detail::ten_bit_mask) + detail::low_surrogate_base; + m_current = 0; + BOOST_REGEX_ASSERT(detail::is_high_surrogate(m_values[0])); + BOOST_REGEX_ASSERT(detail::is_low_surrogate(m_values[1])); + } + else + { + // 16-bit code point: + m_values[0] = static_cast(*m_position); + m_values[1] = 0; + m_current = 0; + // value must not be a surrogate: + if(detail::is_surrogate(m_values[0])) + detail::invalid_utf32_code_point(*m_position); + } + } + BaseIterator m_position; + mutable U16Type m_values[3]; + mutable unsigned m_current; +}; + +template +class u16_to_u32_iterator +{ + // special values for pending iterator reads: + BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu); + +#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef typename std::iterator_traits::value_type base_value_type; + + BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 16); + BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32); +#endif + +public: + typedef std::ptrdiff_t difference_type; + typedef U32Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_value == pending_read) + extract_current(); + return m_value; + } + bool operator==(const u16_to_u32_iterator& that)const + { + return m_position == that.m_position; + } + bool operator!=(const u16_to_u32_iterator& that)const + { + return !(*this == that); + } + u16_to_u32_iterator& operator++() + { + // skip high surrogate first if there is one: + if(detail::is_high_surrogate(*m_position)) ++m_position; + ++m_position; + m_value = pending_read; + return *this; + } + u16_to_u32_iterator operator++(int) + { + u16_to_u32_iterator r(*this); + ++(*this); + return r; + } + u16_to_u32_iterator& operator--() + { + --m_position; + // if we have a low surrogate then go back one more: + if(detail::is_low_surrogate(*m_position)) + --m_position; + m_value = pending_read; + return *this; + } + u16_to_u32_iterator operator--(int) + { + u16_to_u32_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u16_to_u32_iterator() : m_position() + { + m_value = pending_read; + } + u16_to_u32_iterator(BaseIterator b) : m_position(b) + { + m_value = pending_read; + } + // + // Range checked version: + // + u16_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b) + { + m_value = pending_read; + // + // The range must not start with a low surrogate, or end in a high surrogate, + // otherwise we run the risk of running outside the underlying input range. + // Likewise b must not be located at a low surrogate. + // + boost::uint16_t val; + if(start != end) + { + if((b != start) && (b != end)) + { + val = *b; + if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u)) + invalid_code_point(val); + } + val = *start; + if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u)) + invalid_code_point(val); + val = *--end; + if(detail::is_high_surrogate(val)) + invalid_code_point(val); + } + } +private: + static void invalid_code_point(::boost::uint16_t val) + { +#ifndef BOOST_NO_STD_LOCALE + std::stringstream ss; + ss << "Misplaced UTF-16 surrogate U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-32 sequence"; + std::out_of_range e(ss.str()); +#else + std::out_of_range e("Misplaced UTF-16 surrogate encountered while trying to encode UTF-32 sequence"); +#endif + boost::throw_exception(e); + } + void extract_current()const + { + m_value = static_cast(static_cast< ::boost::uint16_t>(*m_position)); + // if the last value is a high surrogate then adjust m_position and m_value as needed: + if(detail::is_high_surrogate(*m_position)) + { + // precondition; next value must have be a low-surrogate: + BaseIterator next(m_position); + ::boost::uint16_t t = *++next; + if((t & 0xFC00u) != 0xDC00u) + invalid_code_point(t); + m_value = (m_value - detail::high_surrogate_base) << 10; + m_value |= (static_cast(static_cast< ::boost::uint16_t>(t)) & detail::ten_bit_mask); + } + // postcondition; result must not be a surrogate: + if(detail::is_surrogate(m_value)) + invalid_code_point(static_cast< ::boost::uint16_t>(m_value)); + } + BaseIterator m_position; + mutable U32Type m_value; +}; + +template +class u32_to_u8_iterator +{ +#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef typename std::iterator_traits::value_type base_value_type; + + BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 32); + BOOST_STATIC_ASSERT(sizeof(U8Type)*CHAR_BIT == 8); +#endif + +public: + typedef std::ptrdiff_t difference_type; + typedef U8Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_current == 4) + extract_current(); + return m_values[m_current]; + } + bool operator==(const u32_to_u8_iterator& that)const + { + if(m_position == that.m_position) + { + // either the m_current's must be equal, or one must be 0 and + // the other 4: which means neither must have bits 1 or 2 set: + return (m_current == that.m_current) + || (((m_current | that.m_current) & 3) == 0); + } + return false; + } + bool operator!=(const u32_to_u8_iterator& that)const + { + return !(*this == that); + } + u32_to_u8_iterator& operator++() + { + // if we have a pending read then read now, so that we know whether + // to skip a position, or move to a low-surrogate: + if(m_current == 4) + { + // pending read: + extract_current(); + } + // move to the next surrogate position: + ++m_current; + // if we've reached the end skip a position: + if(m_values[m_current] == 0) + { + m_current = 4; + ++m_position; + } + return *this; + } + u32_to_u8_iterator operator++(int) + { + u32_to_u8_iterator r(*this); + ++(*this); + return r; + } + u32_to_u8_iterator& operator--() + { + if((m_current & 3) == 0) + { + --m_position; + extract_current(); + m_current = 3; + while(m_current && (m_values[m_current] == 0)) + --m_current; + } + else + --m_current; + return *this; + } + u32_to_u8_iterator operator--(int) + { + u32_to_u8_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u32_to_u8_iterator() : m_position(), m_current(0) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + m_values[3] = 0; + m_values[4] = 0; + } + u32_to_u8_iterator(BaseIterator b) : m_position(b), m_current(4) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + m_values[3] = 0; + m_values[4] = 0; + } +private: + + void extract_current()const + { + boost::uint32_t c = *m_position; + if(c > 0x10FFFFu) + detail::invalid_utf32_code_point(c); + if(c < 0x80u) + { + m_values[0] = static_cast(c); + m_values[1] = static_cast(0u); + m_values[2] = static_cast(0u); + m_values[3] = static_cast(0u); + } + else if(c < 0x800u) + { + m_values[0] = static_cast(0xC0u + (c >> 6)); + m_values[1] = static_cast(0x80u + (c & 0x3Fu)); + m_values[2] = static_cast(0u); + m_values[3] = static_cast(0u); + } + else if(c < 0x10000u) + { + m_values[0] = static_cast(0xE0u + (c >> 12)); + m_values[1] = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + m_values[2] = static_cast(0x80u + (c & 0x3Fu)); + m_values[3] = static_cast(0u); + } + else + { + m_values[0] = static_cast(0xF0u + (c >> 18)); + m_values[1] = static_cast(0x80u + ((c >> 12) & 0x3Fu)); + m_values[2] = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + m_values[3] = static_cast(0x80u + (c & 0x3Fu)); + } + m_current= 0; + } + BaseIterator m_position; + mutable U8Type m_values[5]; + mutable unsigned m_current; +}; + +template +class u8_to_u32_iterator +{ + // special values for pending iterator reads: + BOOST_STATIC_CONSTANT(U32Type, pending_read = 0xffffffffu); + +#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef typename std::iterator_traits::value_type base_value_type; + + BOOST_STATIC_ASSERT(sizeof(base_value_type)*CHAR_BIT == 8); + BOOST_STATIC_ASSERT(sizeof(U32Type)*CHAR_BIT == 32); +#endif + +public: + typedef std::ptrdiff_t difference_type; + typedef U32Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_value == pending_read) + extract_current(); + return m_value; + } + bool operator==(const u8_to_u32_iterator& that)const + { + return m_position == that.m_position; + } + bool operator!=(const u8_to_u32_iterator& that)const + { + return !(*this == that); + } + u8_to_u32_iterator& operator++() + { + // We must not start with a continuation character: + if((static_cast(*m_position) & 0xC0) == 0x80) + invalid_sequence(); + // skip high surrogate first if there is one: + unsigned c = detail::utf8_byte_count(*m_position); + if(m_value == pending_read) + { + // Since we haven't read in a value, we need to validate the code points: + for(unsigned i = 0; i < c; ++i) + { + ++m_position; + // We must have a continuation byte: + if((i != c - 1) && ((static_cast(*m_position) & 0xC0) != 0x80)) + invalid_sequence(); + } + } + else + { + std::advance(m_position, c); + } + m_value = pending_read; + return *this; + } + u8_to_u32_iterator operator++(int) + { + u8_to_u32_iterator r(*this); + ++(*this); + return r; + } + u8_to_u32_iterator& operator--() + { + // Keep backtracking until we don't have a trailing character: + unsigned count = 0; + while((*--m_position & 0xC0u) == 0x80u) ++count; + // now check that the sequence was valid: + if(count != detail::utf8_trailing_byte_count(*m_position)) + invalid_sequence(); + m_value = pending_read; + return *this; + } + u8_to_u32_iterator operator--(int) + { + u8_to_u32_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u8_to_u32_iterator() : m_position() + { + m_value = pending_read; + } + u8_to_u32_iterator(BaseIterator b) : m_position(b) + { + m_value = pending_read; + } + // + // Checked constructor: + // + u8_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b) + { + m_value = pending_read; + // + // We must not start with a continuation character, or end with a + // truncated UTF-8 sequence otherwise we run the risk of going past + // the start/end of the underlying sequence: + // + if(start != end) + { + unsigned char v = *start; + if((v & 0xC0u) == 0x80u) + invalid_sequence(); + if((b != start) && (b != end) && ((*b & 0xC0u) == 0x80u)) + invalid_sequence(); + BaseIterator pos = end; + do + { + v = *--pos; + } + while((start != pos) && ((v & 0xC0u) == 0x80u)); + std::ptrdiff_t extra = detail::utf8_byte_count(v); + if(std::distance(pos, end) < extra) + invalid_sequence(); + } + } +private: + static void invalid_sequence() + { + std::out_of_range e("Invalid UTF-8 sequence encountered while trying to encode UTF-32 character"); + boost::throw_exception(e); + } + void extract_current()const + { + m_value = static_cast(static_cast< ::boost::uint8_t>(*m_position)); + // we must not have a continuation character: + if((m_value & 0xC0u) == 0x80u) + invalid_sequence(); + // see how many extra bytes we have: + unsigned extra = detail::utf8_trailing_byte_count(*m_position); + // extract the extra bits, 6 from each extra byte: + BaseIterator next(m_position); + for(unsigned c = 0; c < extra; ++c) + { + ++next; + m_value <<= 6; + // We must have a continuation byte: + if((static_cast(*next) & 0xC0) != 0x80) + invalid_sequence(); + m_value += static_cast(*next) & 0x3Fu; + } + // we now need to remove a few of the leftmost bits, but how many depends + // upon how many extra bytes we've extracted: + static const boost::uint32_t masks[4] = + { + 0x7Fu, + 0x7FFu, + 0xFFFFu, + 0x1FFFFFu, + }; + m_value &= masks[extra]; + // check the result is in range: + if(m_value > static_cast(0x10FFFFu)) + invalid_sequence(); + // The result must not be a surrogate: + if((m_value >= static_cast(0xD800)) && (m_value <= static_cast(0xDFFF))) + invalid_sequence(); + // We should not have had an invalidly encoded UTF8 sequence: + if((extra > 0) && (m_value <= static_cast(masks[extra - 1]))) + invalid_sequence(); + } + BaseIterator m_position; + mutable U32Type m_value; +}; + +template +class utf16_output_iterator +{ +public: + typedef void difference_type; + typedef void value_type; + typedef boost::uint32_t* pointer; + typedef boost::uint32_t& reference; + typedef std::output_iterator_tag iterator_category; + + utf16_output_iterator(const BaseIterator& b) + : m_position(b){} + utf16_output_iterator(const utf16_output_iterator& that) + : m_position(that.m_position){} + utf16_output_iterator& operator=(const utf16_output_iterator& that) + { + m_position = that.m_position; + return *this; + } + const utf16_output_iterator& operator*()const + { + return *this; + } + void operator=(boost::uint32_t val)const + { + push(val); + } + utf16_output_iterator& operator++() + { + return *this; + } + utf16_output_iterator& operator++(int) + { + return *this; + } + BaseIterator base()const + { + return m_position; + } +private: + void push(boost::uint32_t v)const + { + if(v >= 0x10000u) + { + // begin by checking for a code point out of range: + if(v > 0x10FFFFu) + detail::invalid_utf32_code_point(v); + // split into two surrogates: + *m_position++ = static_cast(v >> 10) + detail::high_surrogate_base; + *m_position++ = static_cast(v & detail::ten_bit_mask) + detail::low_surrogate_base; + } + else + { + // 16-bit code point: + // value must not be a surrogate: + if(detail::is_surrogate(v)) + detail::invalid_utf32_code_point(v); + *m_position++ = static_cast(v); + } + } + mutable BaseIterator m_position; +}; + +template +class utf8_output_iterator +{ +public: + typedef void difference_type; + typedef void value_type; + typedef boost::uint32_t* pointer; + typedef boost::uint32_t& reference; + typedef std::output_iterator_tag iterator_category; + + utf8_output_iterator(const BaseIterator& b) + : m_position(b){} + utf8_output_iterator(const utf8_output_iterator& that) + : m_position(that.m_position){} + utf8_output_iterator& operator=(const utf8_output_iterator& that) + { + m_position = that.m_position; + return *this; + } + const utf8_output_iterator& operator*()const + { + return *this; + } + void operator=(boost::uint32_t val)const + { + push(val); + } + utf8_output_iterator& operator++() + { + return *this; + } + utf8_output_iterator& operator++(int) + { + return *this; + } + BaseIterator base()const + { + return m_position; + } +private: + void push(boost::uint32_t c)const + { + if(c > 0x10FFFFu) + detail::invalid_utf32_code_point(c); + if(c < 0x80u) + { + *m_position++ = static_cast(c); + } + else if(c < 0x800u) + { + *m_position++ = static_cast(0xC0u + (c >> 6)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + else if(c < 0x10000u) + { + *m_position++ = static_cast(0xE0u + (c >> 12)); + *m_position++ = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + else + { + *m_position++ = static_cast(0xF0u + (c >> 18)); + *m_position++ = static_cast(0x80u + ((c >> 12) & 0x3Fu)); + *m_position++ = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + } + mutable BaseIterator m_position; +}; + +} // namespace boost + +#endif // BOOST_REGEX_UNICODE_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v4/w32_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v4/w32_regex_traits.hpp new file mode 100644 index 0000000000..e1ac5d5f55 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v4/w32_regex_traits.hpp @@ -0,0 +1,1229 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE w32_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class w32_regex_traits. + */ + +#ifndef BOOST_W32_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_W32_REGEX_TRAITS_HPP_INCLUDED + +#ifndef BOOST_REGEX_NO_WIN32_LOCALE + +#ifndef BOOST_RE_PAT_EXCEPT_HPP +#include +#endif +#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED +#include +#endif +#ifdef BOOST_HAS_THREADS +#include +#endif +#ifndef BOOST_REGEX_PRIMARY_TRANSFORM +#include +#endif +#ifndef BOOST_REGEX_OBJECT_CACHE_HPP +#include +#endif + +#define VC_EXTRALEAN +#define WIN32_LEAN_AND_MEAN +#include + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE) +#pragma comment(lib, "user32.lib") +#endif + + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4786) +#if BOOST_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ + +// +// forward declaration is needed by some compilers: +// +template +class w32_regex_traits; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// start by typedeffing the types we'll need: +// +typedef ::boost::uint32_t lcid_type; // placeholder for LCID. +typedef ::boost::shared_ptr cat_type; // placeholder for dll HANDLE. + +// +// then add wrappers around the actual Win32 API's (ie implementation hiding): +// +lcid_type BOOST_REGEX_CALL w32_get_default_locale(); +bool BOOST_REGEX_CALL w32_is_lower(char, lcid_type); +#ifndef BOOST_NO_WREGEX +bool BOOST_REGEX_CALL w32_is_lower(wchar_t, lcid_type); +#endif +bool BOOST_REGEX_CALL w32_is_upper(char, lcid_type); +#ifndef BOOST_NO_WREGEX +bool BOOST_REGEX_CALL w32_is_upper(wchar_t, lcid_type); +#endif +cat_type BOOST_REGEX_CALL w32_cat_open(const std::string& name); +std::string BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::string& def); +#ifndef BOOST_NO_WREGEX +std::wstring BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::wstring& def); +#endif +std::string BOOST_REGEX_CALL w32_transform(lcid_type state_id, const char* p1, const char* p2); +#ifndef BOOST_NO_WREGEX +std::wstring BOOST_REGEX_CALL w32_transform(lcid_type state_id, const wchar_t* p1, const wchar_t* p2); +#endif +char BOOST_REGEX_CALL w32_tolower(char c, lcid_type); +#ifndef BOOST_NO_WREGEX +wchar_t BOOST_REGEX_CALL w32_tolower(wchar_t c, lcid_type); +#endif +char BOOST_REGEX_CALL w32_toupper(char c, lcid_type); +#ifndef BOOST_NO_WREGEX +wchar_t BOOST_REGEX_CALL w32_toupper(wchar_t c, lcid_type); +#endif +bool BOOST_REGEX_CALL w32_is(lcid_type, boost::uint32_t mask, char c); +#ifndef BOOST_NO_WREGEX +bool BOOST_REGEX_CALL w32_is(lcid_type, boost::uint32_t mask, wchar_t c); +#endif +// +// class w32_regex_traits_base: +// acts as a container for locale and the facets we are using. +// +template +struct w32_regex_traits_base +{ + w32_regex_traits_base(lcid_type l) + { imbue(l); } + lcid_type imbue(lcid_type l); + + lcid_type m_locale; +}; + +template +inline lcid_type w32_regex_traits_base::imbue(lcid_type l) +{ + lcid_type result(m_locale); + m_locale = l; + return result; +} + +// +// class w32_regex_traits_char_layer: +// implements methods that require specialisation for narrow characters: +// +template +class w32_regex_traits_char_layer : public w32_regex_traits_base +{ + typedef std::basic_string string_type; + typedef std::map map_type; + typedef typename map_type::const_iterator map_iterator_type; +public: + w32_regex_traits_char_layer(const lcid_type l); + + regex_constants::syntax_type syntax_type(charT c)const + { + map_iterator_type i = m_char_map.find(c); + return ((i == m_char_map.end()) ? 0 : i->second); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + map_iterator_type i = m_char_map.find(c); + if(i == m_char_map.end()) + { + if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_lower(c, this->m_locale)) return regex_constants::escape_type_class; + if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_upper(c, this->m_locale)) return regex_constants::escape_type_not_class; + return 0; + } + return i->second; + } + charT tolower(charT c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_tolower(c, this->m_locale); + } + bool isctype(boost::uint32_t mask, charT c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, mask, c); + } + +private: + string_type get_default_message(regex_constants::syntax_type); + // TODO: use a hash table when available! + map_type m_char_map; +}; + +template +w32_regex_traits_char_layer::w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) + : w32_regex_traits_base(l) +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if(cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if(!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if(cat) + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_message(i)); + for(typename string_type::size_type j = 0; j < mss.size(); ++j) + { + this->m_char_map[mss[j]] = i; + } + } + } + else + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while(ptr && *ptr) + { + this->m_char_map[static_cast(*ptr)] = i; + ++ptr; + } + } + } +} + +template +typename w32_regex_traits_char_layer::string_type + w32_regex_traits_char_layer::get_default_message(regex_constants::syntax_type i) +{ + const char* ptr = get_default_syntax(i); + string_type result; + while(ptr && *ptr) + { + result.append(1, static_cast(*ptr)); + ++ptr; + } + return result; +} + +// +// specialised version for narrow characters: +// +template <> +class w32_regex_traits_char_layer : public w32_regex_traits_base +{ + typedef std::string string_type; +public: + w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) + : w32_regex_traits_base(l) + { + init(); + } + + regex_constants::syntax_type syntax_type(char c)const + { + return m_char_map[static_cast(c)]; + } + regex_constants::escape_syntax_type escape_syntax_type(char c) const + { + return m_char_map[static_cast(c)]; + } + char tolower(char c)const + { + return m_lower_map[static_cast(c)]; + } + bool isctype(boost::uint32_t mask, char c)const + { + return m_type_map[static_cast(c)] & mask; + } + +private: + regex_constants::syntax_type m_char_map[1u << CHAR_BIT]; + char m_lower_map[1u << CHAR_BIT]; + boost::uint16_t m_type_map[1u << CHAR_BIT]; + template + void init(); +}; + +// +// class w32_regex_traits_implementation: +// provides pimpl implementation for w32_regex_traits. +// +template +class w32_regex_traits_implementation : public w32_regex_traits_char_layer +{ +public: + typedef typename w32_regex_traits::char_class_type char_class_type; + BOOST_STATIC_CONSTANT(char_class_type, mask_word = 0x0400); // must be C1_DEFINED << 1 + BOOST_STATIC_CONSTANT(char_class_type, mask_unicode = 0x0800); // must be C1_DEFINED << 2 + BOOST_STATIC_CONSTANT(char_class_type, mask_horizontal = 0x1000); // must be C1_DEFINED << 3 + BOOST_STATIC_CONSTANT(char_class_type, mask_vertical = 0x2000); // must be C1_DEFINED << 4 + BOOST_STATIC_CONSTANT(char_class_type, mask_base = 0x3ff); // all the masks used by the CT_CTYPE1 group + + typedef std::basic_string string_type; + typedef charT char_type; + w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l); + std::string error_string(regex_constants::error_type n) const + { + if(!m_error_strings.empty()) + { + std::map::const_iterator p = m_error_strings.find(n); + return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second; + } + return get_default_error_string(n); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + char_class_type result = lookup_classname_imp(p1, p2); + if(result == 0) + { + typedef typename string_type::size_type size_type; + string_type temp(p1, p2); + for(size_type i = 0; i < temp.size(); ++i) + temp[i] = this->tolower(temp[i]); + result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size()); + } + return result; + } + string_type lookup_collatename(const charT* p1, const charT* p2) const; + string_type transform_primary(const charT* p1, const charT* p2) const; + string_type transform(const charT* p1, const charT* p2) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_locale, p1, p2); + } +private: + std::map m_error_strings; // error messages indexed by numberic ID + std::map m_custom_class_names; // character class names + std::map m_custom_collate_names; // collating element names + unsigned m_collate_type; // the form of the collation string + charT m_collate_delim; // the collation group delimiter + // + // helpers: + // + char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const; +}; + +template +typename w32_regex_traits_implementation::string_type + w32_regex_traits_implementation::transform_primary(const charT* p1, const charT* p2) const +{ + string_type result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(m_collate_type) + { + case sort_C: + case sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + typedef typename string_type::size_type size_type; + for(size_type i = 0; i < result.size(); ++i) + result[i] = this->tolower(result[i]); + result = this->transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case sort_fixed: + { + // get a regular sort key, and then truncate it: + result.assign(this->transform(p1, p2)); + result.erase(this->m_collate_delim); + break; + } + case sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result.assign(this->transform(p1, p2)); + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == m_collate_delim) + break; + } + result.erase(i); + break; + } + if(result.empty()) + result = string_type(1, charT(0)); + return result; +} + +template +typename w32_regex_traits_implementation::string_type + w32_regex_traits_implementation::lookup_collatename(const charT* p1, const charT* p2) const +{ + typedef typename std::map::const_iterator iter_type; + if(m_custom_collate_names.size()) + { + iter_type pos = m_custom_collate_names.find(string_type(p1, p2)); + if(pos != m_custom_collate_names.end()) + return pos->second; + } +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x0551) + std::string name(p1, p2); +#else + std::string name; + const charT* p0 = p1; + while(p0 != p2) + name.append(1, char(*p0++)); +#endif + name = lookup_default_collate_name(name); +#if !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)\ + && !BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x0551) + if(name.size()) + return string_type(name.begin(), name.end()); +#else + if(name.size()) + { + string_type result; + typedef std::string::const_iterator iter; + iter b = name.begin(); + iter e = name.end(); + while(b != e) + result.append(1, charT(*b++)); + return result; + } +#endif + if(p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +template +w32_regex_traits_implementation::w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) +: w32_regex_traits_char_layer(l) +{ + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if(cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if(!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if(cat) + { + // + // Error messages: + // + for(boost::regex_constants::error_type i = static_cast(0); + i <= boost::regex_constants::error_unknown; + i = static_cast(i + 1)) + { + const char* p = get_default_error_string(i); + string_type default_message; + while(*p) + { + default_message.append(1, static_cast(*p)); + ++p; + } + string_type s = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i+200, default_message); + std::string result; + for(std::string::size_type j = 0; j < s.size(); ++j) + { + result.append(1, static_cast(s[j])); + } + m_error_strings[i] = result; + } + // + // Custom class names: + // + static const char_class_type masks[14] = + { + 0x0104u, // C1_ALPHA | C1_DIGIT + 0x0100u, // C1_ALPHA + 0x0020u, // C1_CNTRL + 0x0004u, // C1_DIGIT + (~(0x0020u|0x0008u) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE + 0x0002u, // C1_LOWER + (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL + 0x0010u, // C1_PUNCT + 0x0008u, // C1_SPACE + 0x0001u, // C1_UPPER + 0x0080u, // C1_XDIGIT + 0x0040u, // C1_BLANK + w32_regex_traits_implementation::mask_word, + w32_regex_traits_implementation::mask_unicode, + }; + static const string_type null_string; + for(unsigned int j = 0; j <= 13; ++j) + { + string_type s(::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, j+300, null_string)); + if(s.size()) + this->m_custom_class_names[s] = masks[j]; + } + } + // + // get the collation format used by m_pcollate: + // + m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim); +} + +template +typename w32_regex_traits_implementation::char_class_type + w32_regex_traits_implementation::lookup_classname_imp(const charT* p1, const charT* p2) const +{ + static const char_class_type masks[22] = + { + 0, + 0x0104u, // C1_ALPHA | C1_DIGIT + 0x0100u, // C1_ALPHA + 0x0040u, // C1_BLANK + 0x0020u, // C1_CNTRL + 0x0004u, // C1_DIGIT + 0x0004u, // C1_DIGIT + (~(0x0020u|0x0008u|0x0040) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE or C1_BLANK + w32_regex_traits_implementation::mask_horizontal, + 0x0002u, // C1_LOWER + 0x0002u, // C1_LOWER + (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL + 0x0010u, // C1_PUNCT + 0x0008u, // C1_SPACE + 0x0008u, // C1_SPACE + 0x0001u, // C1_UPPER + w32_regex_traits_implementation::mask_unicode, + 0x0001u, // C1_UPPER + w32_regex_traits_implementation::mask_vertical, + 0x0104u | w32_regex_traits_implementation::mask_word, + 0x0104u | w32_regex_traits_implementation::mask_word, + 0x0080u, // C1_XDIGIT + }; + if(m_custom_class_names.size()) + { + typedef typename std::map, char_class_type>::const_iterator map_iter; + map_iter pos = m_custom_class_names.find(string_type(p1, p2)); + if(pos != m_custom_class_names.end()) + return pos->second; + } + std::size_t state_id = 1u + (std::size_t)BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if(state_id < sizeof(masks) / sizeof(masks[0])) + return masks[state_id]; + return masks[0]; +} + + +template +boost::shared_ptr > create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) +{ + // TODO: create a cache for previously constructed objects. + return boost::object_cache< ::boost::BOOST_REGEX_DETAIL_NS::lcid_type, w32_regex_traits_implementation >::get(l, 5); +} + +} // BOOST_REGEX_DETAIL_NS + +template +class w32_regex_traits +{ +public: + typedef charT char_type; + typedef std::size_t size_type; + typedef std::basic_string string_type; + typedef ::boost::BOOST_REGEX_DETAIL_NS::lcid_type locale_type; + typedef boost::uint_least32_t char_class_type; + + struct boost_extensions_tag{}; + + w32_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::w32_get_default_locale())) + { } + static size_type length(const char_type* p) + { + return std::char_traits::length(p); + } + regex_constants::syntax_type syntax_type(charT c)const + { + return m_pimpl->syntax_type(c); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + return m_pimpl->escape_syntax_type(c); + } + charT translate(charT c) const + { + return c; + } + charT translate_nocase(charT c) const + { + return this->m_pimpl->tolower(c); + } + charT translate(charT c, bool icase) const + { + return icase ? this->m_pimpl->tolower(c) : c; + } + charT tolower(charT c) const + { + return this->m_pimpl->tolower(c); + } + charT toupper(charT c) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_toupper(c, this->m_pimpl->m_locale); + } + string_type transform(const charT* p1, const charT* p2) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_pimpl->m_locale, p1, p2); + } + string_type transform_primary(const charT* p1, const charT* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_classname(p1, p2); + } + string_type lookup_collatename(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_collatename(p1, p2); + } + bool isctype(charT c, char_class_type f) const + { + if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_base) + && (this->m_pimpl->isctype(f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_base, c))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_vertical) + && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_horizontal) + && this->isctype(c, 0x0008u) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_vertical)) + return true; + return false; + } + boost::intmax_t toi(const charT*& p1, const charT* p2, int radix)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + int value(charT c, int radix)const + { + int result = (int)::boost::BOOST_REGEX_DETAIL_NS::global_value(c); + return result < radix ? result : -1; + } + locale_type imbue(locale_type l) + { + ::boost::BOOST_REGEX_DETAIL_NS::lcid_type result(getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::create_w32_regex_traits(l); + return result; + } + locale_type getloc()const + { + return m_pimpl->m_locale; + } + std::string error_string(regex_constants::error_type n) const + { + return m_pimpl->error_string(n); + } + + // + // extension: + // set the name of the message catalog in use (defaults to "boost_regex"). + // + static std::string catalog_name(const std::string& name); + static std::string get_catalog_name(); + +private: + boost::shared_ptr > m_pimpl; + // + // catalog name handler: + // + static std::string& get_catalog_name_inst(); + +#ifdef BOOST_HAS_THREADS + static static_mutex& get_mutex_inst(); +#endif +}; + +template +std::string w32_regex_traits::catalog_name(const std::string& name) +{ +#ifdef BOOST_HAS_THREADS + static_mutex::scoped_lock lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + get_catalog_name_inst() = name; + return result; +} + +template +std::string& w32_regex_traits::get_catalog_name_inst() +{ + static std::string s_name; + return s_name; +} + +template +std::string w32_regex_traits::get_catalog_name() +{ +#ifdef BOOST_HAS_THREADS + static_mutex::scoped_lock lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + return result; +} + +#ifdef BOOST_HAS_THREADS +template +static_mutex& w32_regex_traits::get_mutex_inst() +{ + static static_mutex s_mutex = BOOST_STATIC_MUTEX_INIT; + return s_mutex; +} +#endif + +namespace BOOST_REGEX_DETAIL_NS { + +#ifdef BOOST_NO_ANSI_APIS + inline UINT get_code_page_for_locale_id(lcid_type idx) + { + WCHAR code_page_string[7]; + if (::GetLocaleInfoW(idx, LOCALE_IDEFAULTANSICODEPAGE, code_page_string, 7) == 0) + return 0; + + return static_cast(_wtol(code_page_string)); +} +#endif + + template + inline void w32_regex_traits_char_layer::init() + { + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if (cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if (!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if (cat) + { + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_syntax(i)); + for (string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + } + else + { + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while (ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = i; + ++ptr; + } + } + } + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if (m_char_map[i] == 0) + { + if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0002u, (char)i)) + m_char_map[i] = regex_constants::escape_type_class; + else if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0001u, (char)i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + } while (0xFF != i++); + + // + // fill in lower case map: + // + char char_map[1 << CHAR_BIT]; + for (int ii = 0; ii < (1 << CHAR_BIT); ++ii) + char_map[ii] = static_cast(ii); +#ifndef BOOST_NO_ANSI_APIS + int r = ::LCMapStringA(this->m_locale, LCMAP_LOWERCASE, char_map, 1 << CHAR_BIT, this->m_lower_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(r != 0); +#else + UINT code_page = get_code_page_for_locale_id(this->m_locale); + BOOST_REGEX_ASSERT(code_page != 0); + + WCHAR wide_char_map[1 << CHAR_BIT]; + int conv_r = ::MultiByteToWideChar(code_page, 0, char_map, 1 << CHAR_BIT, wide_char_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(conv_r != 0); + + WCHAR wide_lower_map[1 << CHAR_BIT]; + int r = ::LCMapStringW(this->m_locale, LCMAP_LOWERCASE, wide_char_map, 1 << CHAR_BIT, wide_lower_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(r != 0); + + conv_r = ::WideCharToMultiByte(code_page, 0, wide_lower_map, r, this->m_lower_map, 1 << CHAR_BIT, NULL, NULL); + BOOST_REGEX_ASSERT(conv_r != 0); +#endif + if (r < (1 << CHAR_BIT)) + { + // if we have multibyte characters then not all may have been given + // a lower case mapping: + for (int jj = r; jj < (1 << CHAR_BIT); ++jj) + this->m_lower_map[jj] = static_cast(jj); + } + +#ifndef BOOST_NO_ANSI_APIS + r = ::GetStringTypeExA(this->m_locale, CT_CTYPE1, char_map, 1 << CHAR_BIT, this->m_type_map); +#else + r = ::GetStringTypeExW(this->m_locale, CT_CTYPE1, wide_char_map, 1 << CHAR_BIT, this->m_type_map); +#endif + BOOST_REGEX_ASSERT(0 != r); + } + + inline lcid_type BOOST_REGEX_CALL w32_get_default_locale() + { + return ::GetUserDefaultLCID(); + } + + inline bool BOOST_REGEX_CALL w32_is_lower(char c, lcid_type idx) + { +#ifndef BOOST_NO_ANSI_APIS + WORD mask; + if (::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + WORD mask; + if (::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; +#endif + } + + inline bool BOOST_REGEX_CALL w32_is_lower(wchar_t c, lcid_type idx) + { + WORD mask; + if (::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_LOWER)) + return true; + return false; + } + + inline bool BOOST_REGEX_CALL w32_is_upper(char c, lcid_type idx) + { +#ifndef BOOST_NO_ANSI_APIS + WORD mask; + if (::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + WORD mask; + if (::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; +#endif + } + + inline bool BOOST_REGEX_CALL w32_is_upper(wchar_t c, lcid_type idx) + { + WORD mask; + if (::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & C1_UPPER)) + return true; + return false; + } + + inline void free_module(void* mod) + { + ::FreeLibrary(static_cast(mod)); + } + + inline cat_type BOOST_REGEX_CALL w32_cat_open(const std::string& name) + { +#ifndef BOOST_NO_ANSI_APIS + cat_type result(::LoadLibraryA(name.c_str()), &free_module); + return result; +#else + LPWSTR wide_name = (LPWSTR)_alloca((name.size() + 1) * sizeof(WCHAR)); + if (::MultiByteToWideChar(CP_ACP, 0, name.c_str(), name.size(), wide_name, name.size() + 1) == 0) + return cat_type(); + + cat_type result(::LoadLibraryW(wide_name), &free_module); + return result; +#endif + } + + inline std::string BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type, int i, const std::string& def) + { +#ifndef BOOST_NO_ANSI_APIS + char buf[256]; + if (0 == ::LoadStringA( + static_cast(cat.get()), + i, + buf, + 256 + )) + { + return def; + } +#else + WCHAR wbuf[256]; + int r = ::LoadStringW( + static_cast(cat.get()), + i, + wbuf, + 256 + ); + if (r == 0) + return def; + + + int buf_size = 1 + ::WideCharToMultiByte(CP_ACP, 0, wbuf, r, NULL, 0, NULL, NULL); + LPSTR buf = (LPSTR)_alloca(buf_size); + if (::WideCharToMultiByte(CP_ACP, 0, wbuf, r, buf, buf_size, NULL, NULL) == 0) + return def; // failed conversion. +#endif + return std::string(buf); + } + +#ifndef BOOST_NO_WREGEX + inline std::wstring BOOST_REGEX_CALL w32_cat_get(const cat_type& cat, lcid_type, int i, const std::wstring& def) + { + wchar_t buf[256]; + if (0 == ::LoadStringW( + static_cast(cat.get()), + i, + buf, + 256 + )) + { + return def; + } + return std::wstring(buf); + } +#endif + inline std::string BOOST_REGEX_CALL w32_transform(lcid_type idx, const char* p1, const char* p2) + { +#ifndef BOOST_NO_ANSI_APIS + int bytes = ::LCMapStringA( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringA( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + &*result.begin(), // destination buffer + bytes // size of destination buffer + ); +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return std::string(p1, p2); + + int src_len = static_cast(p2 - p1); + LPWSTR wide_p1 = (LPWSTR)_alloca((src_len + 1) * 2); + if (::MultiByteToWideChar(code_page, 0, p1, src_len, wide_p1, src_len + 1) == 0) + return std::string(p1, p2); + + int bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + (LPWSTR) & *result.begin(), // destination buffer + bytes // size of destination buffer + ); +#endif + if (bytes > static_cast(result.size())) + return std::string(p1, p2); + while (result.size() && result[result.size() - 1] == '\0') + { + result.erase(result.size() - 1); + } + return result; + } + +#ifndef BOOST_NO_WREGEX + inline std::wstring BOOST_REGEX_CALL w32_transform(lcid_type idx, const wchar_t* p1, const wchar_t* p2) + { + int bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::wstring(p1, p2); + std::string result(++bytes, '\0'); + bytes = ::LCMapStringW( + idx, // locale identifier + LCMAP_SORTKEY, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + reinterpret_cast(&*result.begin()), // destination buffer *of bytes* + bytes // size of destination buffer + ); + if (bytes > static_cast(result.size())) + return std::wstring(p1, p2); + while (result.size() && result[result.size() - 1] == L'\0') + { + result.erase(result.size() - 1); + } + std::wstring r2; + for (std::string::size_type i = 0; i < result.size(); ++i) + r2.append(1, static_cast(static_cast(result[i]))); + return r2; + } +#endif + inline char BOOST_REGEX_CALL w32_tolower(char c, lcid_type idx) + { + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = ::LCMapStringA( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return c; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + WCHAR wide_result; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + + if (::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte lower case equivalent available +#endif + return result[0]; + } + +#ifndef BOOST_NO_WREGEX + inline wchar_t BOOST_REGEX_CALL w32_tolower(wchar_t c, lcid_type idx) + { + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_LOWERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + return result[0]; + } +#endif + inline char BOOST_REGEX_CALL w32_toupper(char c, lcid_type idx) + { + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = ::LCMapStringA( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return c; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + WCHAR wide_result; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + + if (::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte upper case equivalent available. +#endif + return result[0]; + } + +#ifndef BOOST_NO_WREGEX + inline wchar_t BOOST_REGEX_CALL w32_toupper(wchar_t c, lcid_type idx) + { + wchar_t result[2]; + int b = ::LCMapStringW( + idx, // locale identifier + LCMAP_UPPERCASE, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + return result[0]; + } +#endif + inline bool BOOST_REGEX_CALL w32_is(lcid_type idx, boost::uint32_t m, char c) + { + WORD mask; +#ifndef BOOST_NO_ANSI_APIS + if (::GetStringTypeExA(idx, CT_CTYPE1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#else + UINT code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + WCHAR wide_c; + if (::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + if (::GetStringTypeExW(idx, CT_CTYPE1, &wide_c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#endif + if ((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + return false; + } + +#ifndef BOOST_NO_WREGEX + inline bool BOOST_REGEX_CALL w32_is(lcid_type idx, boost::uint32_t m, wchar_t c) + { + WORD mask; + if (::GetStringTypeExW(idx, CT_CTYPE1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; + if ((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + if ((m & w32_regex_traits_implementation::mask_unicode) && (c > 0xff)) + return true; + return false; + } +#endif + +} // BOOST_REGEX_DETAIL_NS + + +} // boost + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable: 4103) +#endif +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif // BOOST_REGEX_NO_WIN32_LOCALE + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/basic_regex.hpp b/third-party/boost_regex/include/boost/regex/v5/basic_regex.hpp new file mode 100644 index 0000000000..5c73775f06 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/basic_regex.hpp @@ -0,0 +1,734 @@ +/* + * + * Copyright (c) 1998-2004 John Maddock + * Copyright 2011 Garmin Ltd. or its subsidiaries + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/ for most recent version. + * FILE basic_regex.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex. + */ + +#ifndef BOOST_REGEX_V5_BASIC_REGEX_HPP +#define BOOST_REGEX_V5_BASIC_REGEX_HPP + +#include + +namespace boost{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable : 4251) +#if BOOST_REGEX_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +#if BOOST_REGEX_MSVC < 1600 +#pragma warning(disable : 4660) +#endif +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// forward declaration, we will need this one later: +// +template +class basic_regex_parser; + +template +void bubble_down_one(I first, I last) +{ + if(first != last) + { + I next = last - 1; + while((next != first) && (*next < *(next-1))) + { + (next-1)->swap(*next); + --next; + } + } +} + +static const int hash_value_mask = 1 << (std::numeric_limits::digits - 1); + +template +inline int hash_value_from_capture_name(Iterator i, Iterator j) +{ + std::size_t r = 0; + while (i != j) + { + r ^= *i + 0x9e3779b9 + (r << 6) + (r >> 2); + ++i; + } + r %= ((std::numeric_limits::max)()); + return static_cast(r) | hash_value_mask; +} + +class named_subexpressions +{ +public: + struct name + { + template + name(const charT* i, const charT* j, int idx) + : index(idx) + { + hash = hash_value_from_capture_name(i, j); + } + name(int h, int idx) + : index(idx), hash(h) + { + } + int index; + int hash; + bool operator < (const name& other)const + { + return hash < other.hash; + } + bool operator == (const name& other)const + { + return hash == other.hash; + } + void swap(name& other) + { + std::swap(index, other.index); + std::swap(hash, other.hash); + } + }; + + typedef std::vector::const_iterator const_iterator; + typedef std::pair range_type; + + named_subexpressions(){} + + template + void set_name(const charT* i, const charT* j, int index) + { + m_sub_names.push_back(name(i, j, index)); + bubble_down_one(m_sub_names.begin(), m_sub_names.end()); + } + template + int get_id(const charT* i, const charT* j)const + { + name t(i, j, 0); + typename std::vector::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t); + if((pos != m_sub_names.end()) && (*pos == t)) + { + return pos->index; + } + return -1; + } + template + range_type equal_range(const charT* i, const charT* j)const + { + name t(i, j, 0); + return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t); + } + int get_id(int h)const + { + name t(h, 0); + std::vector::const_iterator pos = std::lower_bound(m_sub_names.begin(), m_sub_names.end(), t); + if((pos != m_sub_names.end()) && (*pos == t)) + { + return pos->index; + } + return -1; + } + range_type equal_range(int h)const + { + name t(h, 0); + return std::equal_range(m_sub_names.begin(), m_sub_names.end(), t); + } +private: + std::vector m_sub_names; +}; + +// +// class regex_data: +// represents the data we wish to expose to the matching algorithms. +// +template +struct regex_data : public named_subexpressions +{ + typedef regex_constants::syntax_option_type flag_type; + typedef std::size_t size_type; + + regex_data(const ::std::shared_ptr< + ::boost::regex_traits_wrapper >& t) + : m_ptraits(t), m_flags(0), m_status(0), m_expression(0), m_expression_len(0), + m_mark_count(0), m_first_state(0), m_restart_type(0), + m_startmap{ 0 }, + m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {} + regex_data() + : m_ptraits(new ::boost::regex_traits_wrapper()), m_flags(0), m_status(0), m_expression(0), m_expression_len(0), + m_mark_count(0), m_first_state(0), m_restart_type(0), + m_startmap{ 0 }, + m_can_be_null(0), m_word_mask(0), m_has_recursions(false), m_disable_match_any(false) {} + + ::std::shared_ptr< + ::boost::regex_traits_wrapper + > m_ptraits; // traits class instance + flag_type m_flags; // flags with which we were compiled + int m_status; // error code (0 implies OK). + const charT* m_expression; // the original expression + std::ptrdiff_t m_expression_len; // the length of the original expression + size_type m_mark_count; // the number of marked sub-expressions + BOOST_REGEX_DETAIL_NS::re_syntax_base* m_first_state; // the first state of the machine + unsigned m_restart_type; // search optimisation type + unsigned char m_startmap[1 << CHAR_BIT]; // which characters can start a match + unsigned int m_can_be_null; // whether we can match a null string + BOOST_REGEX_DETAIL_NS::raw_storage m_data; // the buffer in which our states are constructed + typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character + std::vector< + std::pair< + std::size_t, std::size_t> > m_subs; // Position of sub-expressions within the *string*. + bool m_has_recursions; // whether we have recursive expressions; + bool m_disable_match_any; // when set we need to disable the match_any flag as it causes different/buggy behaviour. +}; +// +// class basic_regex_implementation +// pimpl implementation class for basic_regex. +// +template +class basic_regex_implementation + : public regex_data +{ +public: + typedef regex_constants::syntax_option_type flag_type; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef typename traits::locale_type locale_type; + typedef const charT* const_iterator; + + basic_regex_implementation(){} + basic_regex_implementation(const ::std::shared_ptr< + ::boost::regex_traits_wrapper >& t) + : regex_data(t) {} + void assign(const charT* arg_first, + const charT* arg_last, + flag_type f) + { + regex_data* pdat = this; + basic_regex_parser parser(pdat); + parser.parse(arg_first, arg_last, f); + } + + locale_type imbue(locale_type l) + { + return this->m_ptraits->imbue(l); + } + locale_type getloc()const + { + return this->m_ptraits->getloc(); + } + std::basic_string str()const + { + std::basic_string result; + if(this->m_status == 0) + result = std::basic_string(this->m_expression, this->m_expression_len); + return result; + } + const_iterator expression()const + { + return this->m_expression; + } + std::pair subexpression(std::size_t n)const + { + const std::pair& pi = this->m_subs.at(n); + std::pair p(expression() + pi.first, expression() + pi.second); + return p; + } + // + // begin, end: + const_iterator begin()const + { + return (this->m_status ? 0 : this->m_expression); + } + const_iterator end()const + { + return (this->m_status ? 0 : this->m_expression + this->m_expression_len); + } + flag_type flags()const + { + return this->m_flags; + } + size_type size()const + { + return this->m_expression_len; + } + int status()const + { + return this->m_status; + } + size_type mark_count()const + { + return this->m_mark_count - 1; + } + const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const + { + return this->m_first_state; + } + unsigned get_restart_type()const + { + return this->m_restart_type; + } + const unsigned char* get_map()const + { + return this->m_startmap; + } + const ::boost::regex_traits_wrapper& get_traits()const + { + return *(this->m_ptraits); + } + bool can_be_null()const + { + return this->m_can_be_null; + } + const regex_data& get_data()const + { + basic_regex_implementation const* p = this; + return *static_cast*>(p); + } +}; + +} // namespace BOOST_REGEX_DETAIL_NS +// +// class basic_regex: +// represents the compiled +// regular expression: +// + +#ifdef BOOST_REGEX_NO_FWD +template > +#else +template +#endif +class basic_regex : public regbase +{ +public: + // typedefs: + typedef std::size_t traits_size_type; + typedef typename traits::string_type traits_string_type; + typedef charT char_type; + typedef traits traits_type; + + typedef charT value_type; + typedef charT& reference; + typedef const charT& const_reference; + typedef const charT* const_iterator; + typedef const_iterator iterator; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef regex_constants::syntax_option_type flag_type; + // locale_type + // placeholder for actual locale type used by the + // traits class to localise *this. + typedef typename traits::locale_type locale_type; + +public: + explicit basic_regex(){} + explicit basic_regex(const charT* p, flag_type f = regex_constants::normal) + { + assign(p, f); + } + basic_regex(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + { + assign(p1, p2, f); + } + basic_regex(const charT* p, size_type len, flag_type f) + { + assign(p, len, f); + } + basic_regex(const basic_regex& that) + : m_pimpl(that.m_pimpl) {} + ~basic_regex(){} + basic_regex& operator=(const basic_regex& that) + { + return assign(that); + } + basic_regex& operator=(const charT* ptr) + { + return assign(ptr); + } + + // + // assign: + basic_regex& assign(const basic_regex& that) + { + m_pimpl = that.m_pimpl; + return *this; + } + basic_regex& assign(const charT* p, flag_type f = regex_constants::normal) + { + return assign(p, p + traits::length(p), f); + } + basic_regex& assign(const charT* p, size_type len, flag_type f) + { + return assign(p, p + len, f); + } +private: + basic_regex& do_assign(const charT* p1, + const charT* p2, + flag_type f); +public: + basic_regex& assign(const charT* p1, + const charT* p2, + flag_type f = regex_constants::normal) + { + return do_assign(p1, p2, f); + } + + template + unsigned int set_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + { + return set_expression(p.data(), p.data() + p.size(), f); + } + + template + explicit basic_regex(const std::basic_string& p, flag_type f = regex_constants::normal) + { + assign(p, f); + } + + template + basic_regex(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal) + { + typedef typename traits::string_type seq_type; + seq_type a(arg_first, arg_last); + if(!a.empty()) + assign(static_cast(&*a.begin()), static_cast(&*a.begin() + a.size()), f); + else + assign(static_cast(0), static_cast(0), f); + } + + template + basic_regex& operator=(const std::basic_string& p) + { + return assign(p.data(), p.data() + p.size(), regex_constants::normal); + } + + template + basic_regex& assign( + const std::basic_string& s, + flag_type f = regex_constants::normal) + { + return assign(s.data(), s.data() + s.size(), f); + } + + template + basic_regex& assign(InputIterator arg_first, + InputIterator arg_last, + flag_type f = regex_constants::normal) + { + typedef typename traits::string_type seq_type; + seq_type a(arg_first, arg_last); + if(a.size()) + { + const charT* p1 = &*a.begin(); + const charT* p2 = &*a.begin() + a.size(); + return assign(p1, p2, f); + } + return assign(static_cast(0), static_cast(0), f); + } + + // + // locale: + locale_type imbue(locale_type l); + locale_type getloc()const + { + return m_pimpl.get() ? m_pimpl->getloc() : locale_type(); + } + // + // getflags: + // retained for backwards compatibility only, "flags" + // is now the preferred name: + flag_type getflags()const + { + return flags(); + } + flag_type flags()const + { + return m_pimpl.get() ? m_pimpl->flags() : 0; + } + // + // str: + std::basic_string str()const + { + return m_pimpl.get() ? m_pimpl->str() : std::basic_string(); + } + // + // begin, end, subexpression: + std::pair subexpression(std::size_t n)const + { +#ifdef BOOST_REGEX_STANDALONE + if (!m_pimpl.get()) + throw std::logic_error("Can't access subexpressions in an invalid regex."); +#else + if(!m_pimpl.get()) + boost::throw_exception(std::logic_error("Can't access subexpressions in an invalid regex.")); +#endif + return m_pimpl->subexpression(n); + } + const_iterator begin()const + { + return (m_pimpl.get() ? m_pimpl->begin() : 0); + } + const_iterator end()const + { + return (m_pimpl.get() ? m_pimpl->end() : 0); + } + // + // swap: + void swap(basic_regex& that)throw() + { + m_pimpl.swap(that.m_pimpl); + } + // + // size: + size_type size()const + { + return (m_pimpl.get() ? m_pimpl->size() : 0); + } + // + // max_size: + size_type max_size()const + { + return UINT_MAX; + } + // + // empty: + bool empty()const + { + return (m_pimpl.get() ? 0 != m_pimpl->status() : true); + } + + size_type mark_count()const + { + return (m_pimpl.get() ? m_pimpl->mark_count() : 0); + } + + int status()const + { + return (m_pimpl.get() ? m_pimpl->status() : regex_constants::error_empty); + } + + int compare(const basic_regex& that) const + { + if(m_pimpl.get() == that.m_pimpl.get()) + return 0; + if(!m_pimpl.get()) + return -1; + if(!that.m_pimpl.get()) + return 1; + if(status() != that.status()) + return status() - that.status(); + if(flags() != that.flags()) + return flags() - that.flags(); + return str().compare(that.str()); + } + bool operator==(const basic_regex& e)const + { + return compare(e) == 0; + } + bool operator != (const basic_regex& e)const + { + return compare(e) != 0; + } + bool operator<(const basic_regex& e)const + { + return compare(e) < 0; + } + bool operator>(const basic_regex& e)const + { + return compare(e) > 0; + } + bool operator<=(const basic_regex& e)const + { + return compare(e) <= 0; + } + bool operator>=(const basic_regex& e)const + { + return compare(e) >= 0; + } + + // + // The following are deprecated as public interfaces + // but are available for compatibility with earlier versions. + const charT* expression()const + { + return (m_pimpl.get() && !m_pimpl->status() ? m_pimpl->expression() : 0); + } + unsigned int set_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + { + assign(p1, p2, f | regex_constants::no_except); + return status(); + } + unsigned int set_expression(const charT* p, flag_type f = regex_constants::normal) + { + assign(p, f | regex_constants::no_except); + return status(); + } + unsigned int error_code()const + { + return status(); + } + // + // private access methods: + // + const BOOST_REGEX_DETAIL_NS::re_syntax_base* get_first_state()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_first_state(); + } + unsigned get_restart_type()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_restart_type(); + } + const unsigned char* get_map()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_map(); + } + const ::boost::regex_traits_wrapper& get_traits()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_traits(); + } + bool can_be_null()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->can_be_null(); + } + const BOOST_REGEX_DETAIL_NS::regex_data& get_data()const + { + BOOST_REGEX_ASSERT(0 != m_pimpl.get()); + return m_pimpl->get_data(); + } + std::shared_ptr get_named_subs()const + { + return m_pimpl; + } + +private: + std::shared_ptr > m_pimpl; +}; + +// +// out of line members; +// these are the only members that mutate the basic_regex object, +// and are designed to provide the strong exception guarantee +// (in the event of a throw, the state of the object remains unchanged). +// +template +basic_regex& basic_regex::do_assign(const charT* p1, + const charT* p2, + flag_type f) +{ + std::shared_ptr > temp; + if(!m_pimpl.get()) + { + temp = std::shared_ptr >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation()); + } + else + { + temp = std::shared_ptr >(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation(m_pimpl->m_ptraits)); + } + temp->assign(p1, p2, f); + temp.swap(m_pimpl); + return *this; +} + +template +typename basic_regex::locale_type basic_regex::imbue(locale_type l) +{ + std::shared_ptr > temp(new BOOST_REGEX_DETAIL_NS::basic_regex_implementation()); + locale_type result = temp->imbue(l); + temp.swap(m_pimpl); + return result; +} + +// +// non-members: +// +template +void swap(basic_regex& e1, basic_regex& e2) +{ + e1.swap(e2); +} + +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const basic_regex& e) +{ + return (os << e.str()); +} + +// +// class reg_expression: +// this is provided for backwards compatibility only, +// it is deprecated, no not use! +// +#ifdef BOOST_REGEX_NO_FWD +template > +#else +template +#endif +class reg_expression : public basic_regex +{ +public: + typedef typename basic_regex::flag_type flag_type; + typedef typename basic_regex::size_type size_type; + explicit reg_expression(){} + explicit reg_expression(const charT* p, flag_type f = regex_constants::normal) + : basic_regex(p, f){} + reg_expression(const charT* p1, const charT* p2, flag_type f = regex_constants::normal) + : basic_regex(p1, p2, f){} + reg_expression(const charT* p, size_type len, flag_type f) + : basic_regex(p, len, f){} + reg_expression(const reg_expression& that) + : basic_regex(that) {} + ~reg_expression(){} + reg_expression& operator=(const reg_expression& that) + { + return this->assign(that); + } + + template + explicit reg_expression(const std::basic_string& p, flag_type f = regex_constants::normal) + : basic_regex(p, f) + { + } + + template + reg_expression(InputIterator arg_first, InputIterator arg_last, flag_type f = regex_constants::normal) + : basic_regex(arg_first, arg_last, f) + { + } + + template + reg_expression& operator=(const std::basic_string& p) + { + this->assign(p); + return *this; + } + +}; + +#ifdef BOOST_REGEX_MSVC +#pragma warning (pop) +#endif + +} // namespace boost + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/basic_regex_creator.hpp b/third-party/boost_regex/include/boost/regex/v5/basic_regex_creator.hpp new file mode 100644 index 0000000000..bb76c7c1f2 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/basic_regex_creator.hpp @@ -0,0 +1,1576 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_creator.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_creator which fills in + * the data members of a regex_data object. + */ + +#ifndef BOOST_REGEX_V5_BASIC_REGEX_CREATOR_HPP +#define BOOST_REGEX_V5_BASIC_REGEX_CREATOR_HPP + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable:4459) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +#include + +namespace boost{ + +namespace BOOST_REGEX_DETAIL_NS{ + +template +struct digraph : public std::pair +{ + digraph() : std::pair(charT(0), charT(0)){} + digraph(charT c1) : std::pair(c1, charT(0)){} + digraph(charT c1, charT c2) : std::pair(c1, c2) + {} + digraph(const digraph& d) : std::pair(d.first, d.second){} + digraph& operator=(const digraph&) = default; + template + digraph(const Seq& s) : std::pair() + { + BOOST_REGEX_ASSERT(s.size() <= 2); + BOOST_REGEX_ASSERT(s.size()); + this->first = s[0]; + this->second = (s.size() > 1) ? s[1] : 0; + } +}; + +template +class basic_char_set +{ +public: + typedef digraph digraph_type; + typedef typename traits::string_type string_type; + typedef typename traits::char_class_type m_type; + + basic_char_set() + { + m_negate = false; + m_has_digraphs = false; + m_classes = 0; + m_negated_classes = 0; + m_empty = true; + } + + void add_single(const digraph_type& s) + { + m_singles.insert(s); + if(s.second) + m_has_digraphs = true; + m_empty = false; + } + void add_range(const digraph_type& first, const digraph_type& end) + { + m_ranges.push_back(first); + m_ranges.push_back(end); + if(first.second) + { + m_has_digraphs = true; + add_single(first); + } + if(end.second) + { + m_has_digraphs = true; + add_single(end); + } + m_empty = false; + } + void add_class(m_type m) + { + m_classes |= m; + m_empty = false; + } + void add_negated_class(m_type m) + { + m_negated_classes |= m; + m_empty = false; + } + void add_equivalent(const digraph_type& s) + { + m_equivalents.insert(s); + if(s.second) + { + m_has_digraphs = true; + add_single(s); + } + m_empty = false; + } + void negate() + { + m_negate = true; + //m_empty = false; + } + + // + // accessor functions: + // + bool has_digraphs()const + { + return m_has_digraphs; + } + bool is_negated()const + { + return m_negate; + } + typedef typename std::vector::const_iterator list_iterator; + typedef typename std::set::const_iterator set_iterator; + set_iterator singles_begin()const + { + return m_singles.begin(); + } + set_iterator singles_end()const + { + return m_singles.end(); + } + list_iterator ranges_begin()const + { + return m_ranges.begin(); + } + list_iterator ranges_end()const + { + return m_ranges.end(); + } + set_iterator equivalents_begin()const + { + return m_equivalents.begin(); + } + set_iterator equivalents_end()const + { + return m_equivalents.end(); + } + m_type classes()const + { + return m_classes; + } + m_type negated_classes()const + { + return m_negated_classes; + } + bool empty()const + { + return m_empty; + } +private: + std::set m_singles; // a list of single characters to match + std::vector m_ranges; // a list of end points of our ranges + bool m_negate; // true if the set is to be negated + bool m_has_digraphs; // true if we have digraphs present + m_type m_classes; // character classes to match + m_type m_negated_classes; // negated character classes to match + bool m_empty; // whether we've added anything yet + std::set m_equivalents; // a list of equivalence classes +}; + +template +class basic_regex_creator +{ +public: + basic_regex_creator(regex_data* data); + std::ptrdiff_t getoffset(void* addr) + { + return getoffset(addr, m_pdata->m_data.data()); + } + std::ptrdiff_t getoffset(const void* addr, const void* base) + { + return static_cast(addr) - static_cast(base); + } + re_syntax_base* getaddress(std::ptrdiff_t off) + { + return getaddress(off, m_pdata->m_data.data()); + } + re_syntax_base* getaddress(std::ptrdiff_t off, void* base) + { + return static_cast(static_cast(static_cast(base) + off)); + } + void init(unsigned l_flags) + { + m_pdata->m_flags = l_flags; + m_icase = l_flags & regex_constants::icase; + } + regbase::flag_type flags() + { + return m_pdata->m_flags; + } + void flags(regbase::flag_type f) + { + m_pdata->m_flags = f; + if(m_icase != static_cast(f & regbase::icase)) + { + m_icase = static_cast(f & regbase::icase); + } + } + re_syntax_base* append_state(syntax_element_type t, std::size_t s = sizeof(re_syntax_base)); + re_syntax_base* insert_state(std::ptrdiff_t pos, syntax_element_type t, std::size_t s = sizeof(re_syntax_base)); + re_literal* append_literal(charT c); + re_syntax_base* append_set(const basic_char_set& char_set); + re_syntax_base* append_set(const basic_char_set& char_set, std::integral_constant*); + re_syntax_base* append_set(const basic_char_set& char_set, std::integral_constant*); + void finalize(const charT* p1, const charT* p2); +protected: + regex_data* m_pdata; // pointer to the basic_regex_data struct we are filling in + const ::boost::regex_traits_wrapper& + m_traits; // convenience reference to traits class + re_syntax_base* m_last_state; // the last state we added + bool m_icase; // true for case insensitive matches + unsigned m_repeater_id; // the state_id of the next repeater + bool m_has_backrefs; // true if there are actually any backrefs + std::uintmax_t m_bad_repeats; // bitmask of repeats we can't deduce a startmap for; + bool m_has_recursions; // set when we have recursive expressions to fixup + std::vector m_recursion_checks; // notes which recursions we've followed while analysing this expression + typename traits::char_class_type m_word_mask; // mask used to determine if a character is a word character + typename traits::char_class_type m_mask_space; // mask used to determine if a character is a word character + typename traits::char_class_type m_lower_mask; // mask used to determine if a character is a lowercase character + typename traits::char_class_type m_upper_mask; // mask used to determine if a character is an uppercase character + typename traits::char_class_type m_alpha_mask; // mask used to determine if a character is an alphabetic character +private: + basic_regex_creator& operator=(const basic_regex_creator&); + basic_regex_creator(const basic_regex_creator&); + + void fixup_pointers(re_syntax_base* state); + void fixup_recursions(re_syntax_base* state); + void create_startmaps(re_syntax_base* state); + int calculate_backstep(re_syntax_base* state); + void create_startmap(re_syntax_base* state, unsigned char* l_map, unsigned int* pnull, unsigned char mask); + unsigned get_restart_type(re_syntax_base* state); + void set_all_masks(unsigned char* bits, unsigned char); + bool is_bad_repeat(re_syntax_base* pt); + void set_bad_repeat(re_syntax_base* pt); + syntax_element_type get_repeat_type(re_syntax_base* state); + void probe_leading_repeat(re_syntax_base* state); +}; + +template +basic_regex_creator::basic_regex_creator(regex_data* data) + : m_pdata(data), m_traits(*(data->m_ptraits)), m_last_state(0), m_icase(false), m_repeater_id(0), + m_has_backrefs(false), m_bad_repeats(0), m_has_recursions(false), m_word_mask(0), m_mask_space(0), m_lower_mask(0), m_upper_mask(0), m_alpha_mask(0) +{ + m_pdata->m_data.clear(); + m_pdata->m_status = ::boost::regex_constants::error_ok; + static const charT w = 'w'; + static const charT s = 's'; + static const charT l[5] = { 'l', 'o', 'w', 'e', 'r', }; + static const charT u[5] = { 'u', 'p', 'p', 'e', 'r', }; + static const charT a[5] = { 'a', 'l', 'p', 'h', 'a', }; + m_word_mask = m_traits.lookup_classname(&w, &w +1); + m_mask_space = m_traits.lookup_classname(&s, &s +1); + m_lower_mask = m_traits.lookup_classname(l, l + 5); + m_upper_mask = m_traits.lookup_classname(u, u + 5); + m_alpha_mask = m_traits.lookup_classname(a, a + 5); + m_pdata->m_word_mask = m_word_mask; + BOOST_REGEX_ASSERT(m_word_mask != 0); + BOOST_REGEX_ASSERT(m_mask_space != 0); + BOOST_REGEX_ASSERT(m_lower_mask != 0); + BOOST_REGEX_ASSERT(m_upper_mask != 0); + BOOST_REGEX_ASSERT(m_alpha_mask != 0); +} + +template +re_syntax_base* basic_regex_creator::append_state(syntax_element_type t, std::size_t s) +{ + // if the state is a backref then make a note of it: + if(t == syntax_element_backref) + this->m_has_backrefs = true; + // append a new state, start by aligning our last one: + m_pdata->m_data.align(); + // set the offset to the next state in our last one: + if(m_last_state) + m_last_state->next.i = m_pdata->m_data.size() - getoffset(m_last_state); + // now actually extend our data: + m_last_state = static_cast(m_pdata->m_data.extend(s)); + // fill in boilerplate options in the new state: + m_last_state->next.i = 0; + m_last_state->type = t; + return m_last_state; +} + +template +re_syntax_base* basic_regex_creator::insert_state(std::ptrdiff_t pos, syntax_element_type t, std::size_t s) +{ + // append a new state, start by aligning our last one: + m_pdata->m_data.align(); + // set the offset to the next state in our last one: + if(m_last_state) + m_last_state->next.i = m_pdata->m_data.size() - getoffset(m_last_state); + // remember the last state position: + std::ptrdiff_t off = getoffset(m_last_state) + s; + // now actually insert our data: + re_syntax_base* new_state = static_cast(m_pdata->m_data.insert(pos, s)); + // fill in boilerplate options in the new state: + new_state->next.i = s; + new_state->type = t; + m_last_state = getaddress(off); + return new_state; +} + +template +re_literal* basic_regex_creator::append_literal(charT c) +{ + re_literal* result; + // start by seeing if we have an existing re_literal we can extend: + if((0 == m_last_state) || (m_last_state->type != syntax_element_literal)) + { + // no existing re_literal, create a new one: + result = static_cast(append_state(syntax_element_literal, sizeof(re_literal) + sizeof(charT))); + result->length = 1; + *static_cast(static_cast(result+1)) = m_traits.translate(c, m_icase); + } + else + { + // we have an existing re_literal, extend it: + std::ptrdiff_t off = getoffset(m_last_state); + m_pdata->m_data.extend(sizeof(charT)); + m_last_state = result = static_cast(getaddress(off)); + charT* characters = static_cast(static_cast(result+1)); + characters[result->length] = m_traits.translate(c, m_icase); + result->length += 1; + } + return result; +} + +template +inline re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set) +{ + typedef std::integral_constant truth_type; + return char_set.has_digraphs() + ? append_set(char_set, static_cast*>(0)) + : append_set(char_set, static_cast(0)); +} + +template +re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set, std::integral_constant*) +{ + typedef typename traits::string_type string_type; + typedef typename basic_char_set::list_iterator item_iterator; + typedef typename basic_char_set::set_iterator set_iterator; + typedef typename traits::char_class_type m_type; + + re_set_long* result = static_cast*>(append_state(syntax_element_long_set, sizeof(re_set_long))); + // + // fill in the basics: + // + result->csingles = static_cast(std::distance(char_set.singles_begin(), char_set.singles_end())); + result->cranges = static_cast(std::distance(char_set.ranges_begin(), char_set.ranges_end())) / 2; + result->cequivalents = static_cast(std::distance(char_set.equivalents_begin(), char_set.equivalents_end())); + result->cclasses = char_set.classes(); + result->cnclasses = char_set.negated_classes(); + if(flags() & regbase::icase) + { + // adjust classes as needed: + if(((result->cclasses & m_lower_mask) == m_lower_mask) || ((result->cclasses & m_upper_mask) == m_upper_mask)) + result->cclasses |= m_alpha_mask; + if(((result->cnclasses & m_lower_mask) == m_lower_mask) || ((result->cnclasses & m_upper_mask) == m_upper_mask)) + result->cnclasses |= m_alpha_mask; + } + + result->isnot = char_set.is_negated(); + result->singleton = !char_set.has_digraphs(); + // + // remember where the state is for later: + // + std::ptrdiff_t offset = getoffset(result); + // + // now extend with all the singles: + // + item_iterator first, last; + set_iterator sfirst, slast; + sfirst = char_set.singles_begin(); + slast = char_set.singles_end(); + while(sfirst != slast) + { + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (sfirst->first == static_cast(0) ? 1 : sfirst->second ? 3 : 2))); + p[0] = m_traits.translate(sfirst->first, m_icase); + if(sfirst->first == static_cast(0)) + { + p[0] = 0; + } + else if(sfirst->second) + { + p[1] = m_traits.translate(sfirst->second, m_icase); + p[2] = 0; + } + else + p[1] = 0; + ++sfirst; + } + // + // now extend with all the ranges: + // + first = char_set.ranges_begin(); + last = char_set.ranges_end(); + while(first != last) + { + // first grab the endpoints of the range: + digraph c1 = *first; + c1.first = this->m_traits.translate(c1.first, this->m_icase); + c1.second = this->m_traits.translate(c1.second, this->m_icase); + ++first; + digraph c2 = *first; + c2.first = this->m_traits.translate(c2.first, this->m_icase); + c2.second = this->m_traits.translate(c2.second, this->m_icase); + ++first; + string_type s1, s2; + // different actions now depending upon whether collation is turned on: + if(flags() & regex_constants::collate) + { + // we need to transform our range into sort keys: + charT a1[3] = { c1.first, c1.second, charT(0), }; + charT a2[3] = { c2.first, c2.second, charT(0), }; + s1 = this->m_traits.transform(a1, (a1[1] ? a1+2 : a1+1)); + s2 = this->m_traits.transform(a2, (a2[1] ? a2+2 : a2+1)); + if(s1.empty()) + s1 = string_type(1, charT(0)); + if(s2.empty()) + s2 = string_type(1, charT(0)); + } + else + { + if(c1.second) + { + s1.insert(s1.end(), c1.first); + s1.insert(s1.end(), c1.second); + } + else + s1 = string_type(1, c1.first); + if(c2.second) + { + s2.insert(s2.end(), c2.first); + s2.insert(s2.end(), c2.second); + } + else + s2.insert(s2.end(), c2.first); + } + if(s1 > s2) + { + // Oops error: + return 0; + } + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (s1.size() + s2.size() + 2) ) ); + BOOST_REGEX_DETAIL_NS::copy(s1.begin(), s1.end(), p); + p[s1.size()] = charT(0); + p += s1.size() + 1; + BOOST_REGEX_DETAIL_NS::copy(s2.begin(), s2.end(), p); + p[s2.size()] = charT(0); + } + // + // now process the equivalence classes: + // + sfirst = char_set.equivalents_begin(); + slast = char_set.equivalents_end(); + while(sfirst != slast) + { + string_type s; + if(sfirst->second) + { + charT cs[3] = { sfirst->first, sfirst->second, charT(0), }; + s = m_traits.transform_primary(cs, cs+2); + } + else + s = m_traits.transform_primary(&sfirst->first, &sfirst->first+1); + if(s.empty()) + return 0; // invalid or unsupported equivalence class + charT* p = static_cast(this->m_pdata->m_data.extend(sizeof(charT) * (s.size()+1) ) ); + BOOST_REGEX_DETAIL_NS::copy(s.begin(), s.end(), p); + p[s.size()] = charT(0); + ++sfirst; + } + // + // finally reset the address of our last state: + // + m_last_state = result = static_cast*>(getaddress(offset)); + return result; +} + +template +inline bool char_less(T t1, T t2) +{ + return t1 < t2; +} +inline bool char_less(char t1, char t2) +{ + return static_cast(t1) < static_cast(t2); +} +inline bool char_less(signed char t1, signed char t2) +{ + return static_cast(t1) < static_cast(t2); +} + +template +re_syntax_base* basic_regex_creator::append_set( + const basic_char_set& char_set, std::integral_constant*) +{ + typedef typename traits::string_type string_type; + typedef typename basic_char_set::list_iterator item_iterator; + typedef typename basic_char_set::set_iterator set_iterator; + + re_set* result = static_cast(append_state(syntax_element_set, sizeof(re_set))); + bool negate = char_set.is_negated(); + std::memset(result->_map, 0, sizeof(result->_map)); + // + // handle singles first: + // + item_iterator first, last; + set_iterator sfirst, slast; + sfirst = char_set.singles_begin(); + slast = char_set.singles_end(); + while(sfirst != slast) + { + for(unsigned int i = 0; i < (1 << CHAR_BIT); ++i) + { + if(this->m_traits.translate(static_cast(i), this->m_icase) + == this->m_traits.translate(sfirst->first, this->m_icase)) + result->_map[i] = true; + } + ++sfirst; + } + // + // OK now handle ranges: + // + first = char_set.ranges_begin(); + last = char_set.ranges_end(); + while(first != last) + { + // first grab the endpoints of the range: + charT c1 = this->m_traits.translate(first->first, this->m_icase); + ++first; + charT c2 = this->m_traits.translate(first->first, this->m_icase); + ++first; + // different actions now depending upon whether collation is turned on: + if(flags() & regex_constants::collate) + { + // we need to transform our range into sort keys: + charT c3[2] = { c1, charT(0), }; + string_type s1 = this->m_traits.transform(c3, c3+1); + c3[0] = c2; + string_type s2 = this->m_traits.transform(c3, c3+1); + if(s1 > s2) + { + // Oops error: + return 0; + } + BOOST_REGEX_ASSERT(c3[1] == charT(0)); + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + c3[0] = static_cast(i); + string_type s3 = this->m_traits.transform(c3, c3 +1); + if((s1 <= s3) && (s3 <= s2)) + result->_map[i] = true; + } + } + else + { + if(char_less(c2, c1)) + { + // Oops error: + return 0; + } + // everything in range matches: + std::memset(result->_map + static_cast(c1), true, static_cast(1u) + static_cast(static_cast(c2) - static_cast(c1))); + } + } + // + // and now the classes: + // + typedef typename traits::char_class_type m_type; + m_type m = char_set.classes(); + if(flags() & regbase::icase) + { + // adjust m as needed: + if(((m & m_lower_mask) == m_lower_mask) || ((m & m_upper_mask) == m_upper_mask)) + m |= m_alpha_mask; + } + if(m != 0) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + if(this->m_traits.isctype(static_cast(i), m)) + result->_map[i] = true; + } + } + // + // and now the negated classes: + // + m = char_set.negated_classes(); + if(flags() & regbase::icase) + { + // adjust m as needed: + if(((m & m_lower_mask) == m_lower_mask) || ((m & m_upper_mask) == m_upper_mask)) + m |= m_alpha_mask; + } + if(m != 0) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + if(0 == this->m_traits.isctype(static_cast(i), m)) + result->_map[i] = true; + } + } + // + // now process the equivalence classes: + // + sfirst = char_set.equivalents_begin(); + slast = char_set.equivalents_end(); + while(sfirst != slast) + { + string_type s; + BOOST_REGEX_ASSERT(static_cast(0) == sfirst->second); + s = m_traits.transform_primary(&sfirst->first, &sfirst->first+1); + if(s.empty()) + return 0; // invalid or unsupported equivalence class + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + charT c[2] = { (static_cast(i)), charT(0), }; + string_type s2 = this->m_traits.transform_primary(c, c+1); + if(s == s2) + result->_map[i] = true; + } + ++sfirst; + } + if(negate) + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + { + result->_map[i] = !(result->_map[i]); + } + } + return result; +} + +template +void basic_regex_creator::finalize(const charT* p1, const charT* p2) +{ + if(this->m_pdata->m_status) + return; + // we've added all the states we need, now finish things off. + // start by adding a terminating state: + append_state(syntax_element_match); + // extend storage to store original expression: + std::ptrdiff_t len = p2 - p1; + m_pdata->m_expression_len = len; + charT* ps = static_cast(m_pdata->m_data.extend(sizeof(charT) * (1 + (p2 - p1)))); + m_pdata->m_expression = ps; + BOOST_REGEX_DETAIL_NS::copy(p1, p2, ps); + ps[p2 - p1] = 0; + // fill in our other data... + // successful parsing implies a zero status: + m_pdata->m_status = 0; + // get the first state of the machine: + m_pdata->m_first_state = static_cast(m_pdata->m_data.data()); + // fixup pointers in the machine: + fixup_pointers(m_pdata->m_first_state); + if(m_has_recursions) + { + m_pdata->m_has_recursions = true; + fixup_recursions(m_pdata->m_first_state); + if(this->m_pdata->m_status) + return; + } + else + m_pdata->m_has_recursions = false; + // create nested startmaps: + create_startmaps(m_pdata->m_first_state); + // create main startmap: + std::memset(m_pdata->m_startmap, 0, sizeof(m_pdata->m_startmap)); + m_pdata->m_can_be_null = 0; + + m_bad_repeats = 0; + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + create_startmap(m_pdata->m_first_state, m_pdata->m_startmap, &(m_pdata->m_can_be_null), mask_all); + // get the restart type: + m_pdata->m_restart_type = get_restart_type(m_pdata->m_first_state); + // optimise a leading repeat if there is one: + probe_leading_repeat(m_pdata->m_first_state); +} + +template +void basic_regex_creator::fixup_pointers(re_syntax_base* state) +{ + while(state) + { + switch(state->type) + { + case syntax_element_recurse: + m_has_recursions = true; + if(state->next.i) + state->next.p = getaddress(state->next.i, state); + else + state->next.p = 0; + break; + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + // set the state_id of this repeat: + static_cast(state)->state_id = m_repeater_id++; + BOOST_REGEX_FALLTHROUGH; + case syntax_element_alt: + std::memset(static_cast(state)->_map, 0, sizeof(static_cast(state)->_map)); + static_cast(state)->can_be_null = 0; + BOOST_REGEX_FALLTHROUGH; + case syntax_element_jump: + static_cast(state)->alt.p = getaddress(static_cast(state)->alt.i, state); + BOOST_REGEX_FALLTHROUGH; + default: + if(state->next.i) + state->next.p = getaddress(state->next.i, state); + else + state->next.p = 0; + } + state = state->next.p; + } +} + +template +void basic_regex_creator::fixup_recursions(re_syntax_base* state) +{ + re_syntax_base* base = state; + while(state) + { + switch(state->type) + { + case syntax_element_assert_backref: + { + // just check that the index is valid: + int idx = static_cast(state)->index; + if(idx < 0) + { + idx = -idx-1; + if(idx >= hash_value_mask) + { + idx = m_pdata->get_id(idx); + if(idx <= 0) + { + // check of sub-expression that doesn't exist: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered a forward reference to a marked sub-expression that does not exist."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + } + } + } + break; + case syntax_element_recurse: + { + bool ok = false; + re_syntax_base* p = base; + std::ptrdiff_t idx = static_cast(state)->alt.i; + if(idx >= hash_value_mask) + { + // + // There may be more than one capture group with this hash, just do what Perl + // does and recurse to the leftmost: + // + idx = m_pdata->get_id(static_cast(idx)); + } + if(idx < 0) + { + ok = false; + } + else + { + while(p) + { + if((p->type == syntax_element_startmark) && (static_cast(p)->index == idx)) + { + // + // We've found the target of the recursion, set the jump target: + // + static_cast(state)->alt.p = p; + ok = true; + // + // Now scan the target for nested repeats: + // + p = p->next.p; + int next_rep_id = 0; + while(p) + { + switch(p->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + next_rep_id = static_cast(p)->state_id; + break; + case syntax_element_endmark: + if(static_cast(p)->index == idx) + next_rep_id = -1; + break; + default: + break; + } + if(next_rep_id) + break; + p = p->next.p; + } + if(next_rep_id > 0) + { + static_cast(state)->state_id = next_rep_id - 1; + } + + break; + } + p = p->next.p; + } + } + if(!ok) + { + // recursion to sub-expression that doesn't exist: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered a forward reference to a recursive sub-expression that does not exist."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + } + break; + default: + break; + } + state = state->next.p; + } +} + +template +void basic_regex_creator::create_startmaps(re_syntax_base* state) +{ + // non-recursive implementation: + // create the last map in the machine first, so that earlier maps + // can make use of the result... + // + // This was originally a recursive implementation, but that caused stack + // overflows with complex expressions on small stacks (think COM+). + + // start by saving the case setting: + bool l_icase = m_icase; + std::vector > v; + + while(state) + { + switch(state->type) + { + case syntax_element_toggle_case: + // we need to track case changes here: + m_icase = static_cast(state)->icase; + state = state->next.p; + continue; + case syntax_element_alt: + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + // just push the state onto our stack for now: + v.push_back(std::pair(m_icase, state)); + state = state->next.p; + break; + case syntax_element_backstep: + // we need to calculate how big the backstep is: + static_cast(state)->index + = this->calculate_backstep(state->next.p); + if(static_cast(state)->index < 0) + { + // Oops error: + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Invalid lookbehind assertion encountered in the regular expression."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + BOOST_REGEX_FALLTHROUGH; + default: + state = state->next.p; + } + } + + // now work through our list, building all the maps as we go: + while(!v.empty()) + { + // Initialize m_recursion_checks if we need it: + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + + const std::pair& p = v.back(); + m_icase = p.first; + state = p.second; + v.pop_back(); + + // Build maps: + m_bad_repeats = 0; + create_startmap(state->next.p, static_cast(state)->_map, &static_cast(state)->can_be_null, mask_take); + m_bad_repeats = 0; + + if(m_has_recursions) + m_recursion_checks.assign(1 + m_pdata->m_mark_count, 0u); + create_startmap(static_cast(state)->alt.p, static_cast(state)->_map, &static_cast(state)->can_be_null, mask_skip); + // adjust the type of the state to allow for faster matching: + state->type = this->get_repeat_type(state); + } + // restore case sensitivity: + m_icase = l_icase; +} + +template +int basic_regex_creator::calculate_backstep(re_syntax_base* state) +{ + typedef typename traits::char_class_type m_type; + int result = 0; + while(state) + { + switch(state->type) + { + case syntax_element_startmark: + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + { + state = static_cast(state->next.p)->alt.p->next.p; + continue; + } + else if(static_cast(state)->index == -3) + { + state = state->next.p->next.p; + continue; + } + break; + case syntax_element_endmark: + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + return result; + break; + case syntax_element_literal: + result += static_cast(state)->length; + break; + case syntax_element_wild: + case syntax_element_set: + result += 1; + break; + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_backref: + case syntax_element_rep: + case syntax_element_combining: + case syntax_element_long_set_rep: + case syntax_element_backstep: + { + re_repeat* rep = static_cast(state); + // adjust the type of the state to allow for faster matching: + state->type = this->get_repeat_type(state); + if((state->type == syntax_element_dot_rep) + || (state->type == syntax_element_char_rep) + || (state->type == syntax_element_short_set_rep)) + { + if(rep->max != rep->min) + return -1; + if (static_cast((std::numeric_limits::max)() - result) < rep->min) + return -1; // protection against overflow, we can't calculate a backstep in this case and the expression is probably ill-formed. + result += static_cast(rep->min); + state = rep->alt.p; + continue; + } + else if(state->type == syntax_element_long_set_rep) + { + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_long_set); + if(static_cast*>(rep->next.p)->singleton == 0) + return -1; + if(rep->max != rep->min) + return -1; + result += static_cast(rep->min); + state = rep->alt.p; + continue; + } + } + return -1; + case syntax_element_long_set: + if(static_cast*>(state)->singleton == 0) + return -1; + result += 1; + break; + case syntax_element_jump: + state = static_cast(state)->alt.p; + continue; + case syntax_element_alt: + { + int r1 = calculate_backstep(state->next.p); + int r2 = calculate_backstep(static_cast(state)->alt.p); + if((r1 < 0) || (r1 != r2)) + return -1; + return result + r1; + } + default: + break; + } + state = state->next.p; + } + return -1; +} + +struct recursion_saver +{ + std::vector saved_state; + std::vector* state; + recursion_saver(std::vector* p) : saved_state(*p), state(p) {} + ~recursion_saver() + { + state->swap(saved_state); + } +}; + +template +void basic_regex_creator::create_startmap(re_syntax_base* state, unsigned char* l_map, unsigned int* pnull, unsigned char mask) +{ + recursion_saver saved_recursions(&m_recursion_checks); + int not_last_jump = 1; + re_syntax_base* recursion_start = 0; + int recursion_sub = 0; + re_syntax_base* recursion_restart = 0; + + // track case sensitivity: + bool l_icase = m_icase; + + while(state) + { + switch(state->type) + { + case syntax_element_toggle_case: + l_icase = static_cast(state)->icase; + state = state->next.p; + break; + case syntax_element_literal: + { + // don't set anything in *pnull, set each element in l_map + // that could match the first character in the literal: + if(l_map) + { + l_map[0] |= mask_init; + charT first_char = *static_cast(static_cast(static_cast(state) + 1)); + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(m_traits.translate(static_cast(i), l_icase) == first_char) + l_map[i] |= mask; + } + } + return; + } + case syntax_element_end_line: + { + // next character must be a line separator (if there is one): + if(l_map) + { + l_map[0] |= mask_init; + l_map[static_cast('\n')] |= mask; + l_map[static_cast('\r')] |= mask; + l_map[static_cast('\f')] |= mask; + l_map[0x85] |= mask; + } + // now figure out if we can match a NULL string at this point: + if(pnull) + create_startmap(state->next.p, 0, pnull, mask); + return; + } + case syntax_element_recurse: + { + BOOST_REGEX_ASSERT(static_cast(state)->alt.p->type == syntax_element_startmark); + recursion_sub = static_cast(static_cast(state)->alt.p)->index; + if(m_recursion_checks[recursion_sub] & 1u) + { + // Infinite recursion!! + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = boost::regex_constants::error_bad_pattern; + // + // clear the expression, we should be empty: + // + this->m_pdata->m_expression = 0; + this->m_pdata->m_expression_len = 0; + // + // and throw if required: + // + if(0 == (this->flags() & regex_constants::no_except)) + { + std::string message = "Encountered an infinite recursion."; + boost::regex_error e(message, boost::regex_constants::error_bad_pattern, 0); + e.raise(); + } + } + else if(recursion_start == 0) + { + recursion_start = state; + recursion_restart = state->next.p; + state = static_cast(state)->alt.p; + m_recursion_checks[recursion_sub] |= 1u; + break; + } + m_recursion_checks[recursion_sub] |= 1u; + // can't handle nested recursion here... + BOOST_REGEX_FALLTHROUGH; + } + case syntax_element_backref: + // can be null, and any character can match: + if(pnull) + *pnull |= mask; + BOOST_REGEX_FALLTHROUGH; + case syntax_element_wild: + { + // can't be null, any character can match: + set_all_masks(l_map, mask); + return; + } + case syntax_element_accept: + case syntax_element_match: + { + // must be null, any character can match: + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + case syntax_element_word_start: + { + // recurse, then AND with all the word characters: + create_startmap(state->next.p, l_map, pnull, mask); + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(!m_traits.isctype(static_cast(i), m_word_mask)) + l_map[i] &= static_cast(~mask); + } + } + return; + } + case syntax_element_word_end: + { + // recurse, then AND with all the word characters: + create_startmap(state->next.p, l_map, pnull, mask); + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(m_traits.isctype(static_cast(i), m_word_mask)) + l_map[i] &= static_cast(~mask); + } + } + return; + } + case syntax_element_buffer_end: + { + // we *must be null* : + if(pnull) + *pnull |= mask; + return; + } + case syntax_element_long_set: + if(l_map) + { + typedef typename traits::char_class_type m_type; + if(static_cast*>(state)->singleton) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + charT c = static_cast(i); + if(&c != re_is_set_member(&c, &c + 1, static_cast*>(state), *m_pdata, l_icase)) + l_map[i] |= mask; + } + } + else + set_all_masks(l_map, mask); + } + return; + case syntax_element_set: + if(l_map) + { + l_map[0] |= mask_init; + for(unsigned int i = 0; i < (1u << CHAR_BIT); ++i) + { + if(static_cast(state)->_map[ + static_cast(m_traits.translate(static_cast(i), l_icase))]) + l_map[i] |= mask; + } + } + return; + case syntax_element_jump: + // take the jump: + state = static_cast(state)->alt.p; + not_last_jump = -1; + break; + case syntax_element_alt: + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + re_alt* rep = static_cast(state); + if(rep->_map[0] & mask_init) + { + if(l_map) + { + // copy previous results: + l_map[0] |= mask_init; + for(unsigned int i = 0; i <= UCHAR_MAX; ++i) + { + if(rep->_map[i] & mask_any) + l_map[i] |= mask; + } + } + if(pnull) + { + if(rep->can_be_null & mask_any) + *pnull |= mask; + } + } + else + { + // we haven't created a startmap for this alternative yet + // so take the union of the two options: + if(is_bad_repeat(state)) + { + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + set_bad_repeat(state); + create_startmap(state->next.p, l_map, pnull, mask); + if((state->type == syntax_element_alt) + || (static_cast(state)->min == 0) + || (not_last_jump == 0)) + create_startmap(rep->alt.p, l_map, pnull, mask); + } + } + return; + case syntax_element_soft_buffer_end: + // match newline or null: + if(l_map) + { + l_map[0] |= mask_init; + l_map[static_cast('\n')] |= mask; + l_map[static_cast('\r')] |= mask; + } + if(pnull) + *pnull |= mask; + return; + case syntax_element_endmark: + // need to handle independent subs as a special case: + if(static_cast(state)->index < 0) + { + // can be null, any character can match: + set_all_masks(l_map, mask); + if(pnull) + *pnull |= mask; + return; + } + else if(recursion_start && (recursion_sub != 0) && (recursion_sub == static_cast(state)->index)) + { + // recursion termination: + recursion_start = 0; + state = recursion_restart; + break; + } + + // + // Normally we just go to the next state... but if this sub-expression is + // the target of a recursion, then we might be ending a recursion, in which + // case we should check whatever follows that recursion, as well as whatever + // follows this state: + // + if(m_pdata->m_has_recursions && static_cast(state)->index) + { + bool ok = false; + re_syntax_base* p = m_pdata->m_first_state; + while(p) + { + if(p->type == syntax_element_recurse) + { + re_brace* p2 = static_cast(static_cast(p)->alt.p); + if((p2->type == syntax_element_startmark) && (p2->index == static_cast(state)->index)) + { + ok = true; + break; + } + } + p = p->next.p; + } + if(ok && ((m_recursion_checks[static_cast(state)->index] & 2u) == 0)) + { + m_recursion_checks[static_cast(state)->index] |= 2u; + create_startmap(p->next.p, l_map, pnull, mask); + } + } + state = state->next.p; + break; + + case syntax_element_commit: + set_all_masks(l_map, mask); + // Continue scanning so we can figure out whether we can be null: + state = state->next.p; + break; + case syntax_element_startmark: + // need to handle independent subs as a special case: + if(static_cast(state)->index == -3) + { + state = state->next.p->next.p; + break; + } + BOOST_REGEX_FALLTHROUGH; + default: + state = state->next.p; + } + ++not_last_jump; + } +} + +template +unsigned basic_regex_creator::get_restart_type(re_syntax_base* state) +{ + // + // find out how the machine starts, so we can optimise the search: + // + while(state) + { + switch(state->type) + { + case syntax_element_startmark: + case syntax_element_endmark: + state = state->next.p; + continue; + case syntax_element_start_line: + return regbase::restart_line; + case syntax_element_word_start: + return regbase::restart_word; + case syntax_element_buffer_start: + return regbase::restart_buf; + case syntax_element_restart_continue: + return regbase::restart_continue; + default: + state = 0; + continue; + } + } + return regbase::restart_any; +} + +template +void basic_regex_creator::set_all_masks(unsigned char* bits, unsigned char mask) +{ + // + // set mask in all of bits elements, + // if bits[0] has mask_init not set then we can + // optimise this to a call to memset: + // + if(bits) + { + if(bits[0] == 0) + (std::memset)(bits, mask, 1u << CHAR_BIT); + else + { + for(unsigned i = 0; i < (1u << CHAR_BIT); ++i) + bits[i] |= mask; + } + bits[0] |= mask_init; + } +} + +template +bool basic_regex_creator::is_bad_repeat(re_syntax_base* pt) +{ + switch(pt->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + unsigned state_id = static_cast(pt)->state_id; + if(state_id >= sizeof(m_bad_repeats) * CHAR_BIT) + return true; // run out of bits, assume we can't traverse this one. + static const std::uintmax_t one = 1uL; + return m_bad_repeats & (one << state_id); + } + default: + return false; + } +} + +template +void basic_regex_creator::set_bad_repeat(re_syntax_base* pt) +{ + switch(pt->type) + { + case syntax_element_rep: + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + { + unsigned state_id = static_cast(pt)->state_id; + static const std::uintmax_t one = 1uL; + if(state_id <= sizeof(m_bad_repeats) * CHAR_BIT) + m_bad_repeats |= (one << state_id); + } + break; + default: + break; + } +} + +template +syntax_element_type basic_regex_creator::get_repeat_type(re_syntax_base* state) +{ + typedef typename traits::char_class_type m_type; + if(state->type == syntax_element_rep) + { + // check to see if we are repeating a single state: + if(state->next.p->next.p->next.p == static_cast(state)->alt.p) + { + switch(state->next.p->type) + { + case BOOST_REGEX_DETAIL_NS::syntax_element_wild: + return BOOST_REGEX_DETAIL_NS::syntax_element_dot_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_literal: + return BOOST_REGEX_DETAIL_NS::syntax_element_char_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_set: + return BOOST_REGEX_DETAIL_NS::syntax_element_short_set_rep; + case BOOST_REGEX_DETAIL_NS::syntax_element_long_set: + if(static_cast*>(state->next.p)->singleton) + return BOOST_REGEX_DETAIL_NS::syntax_element_long_set_rep; + break; + default: + break; + } + } + } + return state->type; +} + +template +void basic_regex_creator::probe_leading_repeat(re_syntax_base* state) +{ + // enumerate our states, and see if we have a leading repeat + // for which failed search restarts can be optimized; + do + { + switch(state->type) + { + case syntax_element_startmark: + if(static_cast(state)->index >= 0) + { + state = state->next.p; + continue; + } +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable:6011) +#endif + if((static_cast(state)->index == -1) + || (static_cast(state)->index == -2)) + { + // skip past the zero width assertion: + state = static_cast(state->next.p)->alt.p->next.p; + continue; + } +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + if(static_cast(state)->index == -3) + { + // Have to skip the leading jump state: + state = state->next.p->next.p; + continue; + } + return; + case syntax_element_endmark: + case syntax_element_start_line: + case syntax_element_end_line: + case syntax_element_word_boundary: + case syntax_element_within_word: + case syntax_element_word_start: + case syntax_element_word_end: + case syntax_element_buffer_start: + case syntax_element_buffer_end: + case syntax_element_restart_continue: + state = state->next.p; + break; + case syntax_element_dot_rep: + case syntax_element_char_rep: + case syntax_element_short_set_rep: + case syntax_element_long_set_rep: + if(this->m_has_backrefs == 0) + static_cast(state)->leading = true; + BOOST_REGEX_FALLTHROUGH; + default: + return; + } + }while(state); +} + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/basic_regex_parser.hpp b/third-party/boost_regex/include/boost/regex/v5/basic_regex_parser.hpp new file mode 100644 index 0000000000..34d775ef84 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/basic_regex_parser.hpp @@ -0,0 +1,3130 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE basic_regex_parser.cpp + * VERSION see + * DESCRIPTION: Declares template class basic_regex_parser. + */ + +#ifndef BOOST_REGEX_V5_BASIC_REGEX_PARSER_HPP +#define BOOST_REGEX_V5_BASIC_REGEX_PARSER_HPP + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4244 4459) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +inline std::intmax_t umax(std::integral_constant const&) +{ + // Get out clause here, just in case numeric_limits is unspecialized: + return std::numeric_limits::is_specialized ? (std::numeric_limits::max)() : INT_MAX; +} +inline std::intmax_t umax(std::integral_constant const&) +{ + return (std::numeric_limits::max)(); +} + +inline std::intmax_t umax() +{ + return umax(std::integral_constant::digits >= std::numeric_limits::digits>()); +} + +template +class basic_regex_parser : public basic_regex_creator +{ +public: + basic_regex_parser(regex_data* data); + void parse(const charT* p1, const charT* p2, unsigned flags); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos); + void fail(regex_constants::error_type error_code, std::ptrdiff_t position, const std::string& message) + { + fail(error_code, position, message, position); + } + + bool parse_all(); + bool parse_basic(); + bool parse_extended(); + bool parse_literal(); + bool parse_open_paren(); + bool parse_basic_escape(); + bool parse_extended_escape(); + bool parse_match_any(); + bool parse_repeat(std::size_t low = 0, std::size_t high = (std::numeric_limits::max)()); + bool parse_repeat_range(bool isbasic); + bool parse_alt(); + bool parse_set(); + bool parse_backref(); + void parse_set_literal(basic_char_set& char_set); + bool parse_inner_set(basic_char_set& char_set); + bool parse_QE(); + bool parse_perl_extension(); + bool parse_perl_verb(); + bool match_verb(const char*); + bool add_emacs_code(bool negate); + bool unwind_alts(std::ptrdiff_t last_paren_start); + digraph get_next_set_literal(basic_char_set& char_set); + charT unescape_character(); + regex_constants::syntax_option_type parse_options(); + +private: + typedef bool (basic_regex_parser::*parser_proc_type)(); + typedef typename traits::string_type string_type; + typedef typename traits::char_class_type char_class_type; + parser_proc_type m_parser_proc; // the main parser to use + const charT* m_base; // the start of the string being parsed + const charT* m_end; // the end of the string being parsed + const charT* m_position; // our current parser position + unsigned m_mark_count; // how many sub-expressions we have + int m_mark_reset; // used to indicate that we're inside a (?|...) block. + unsigned m_max_mark; // largest mark count seen inside a (?|...) block. + std::ptrdiff_t m_paren_start; // where the last seen ')' began (where repeats are inserted). + std::ptrdiff_t m_alt_insert_point; // where to insert the next alternative + bool m_has_case_change; // true if somewhere in the current block the case has changed + unsigned m_recursion_count; // How many times we've called parse_all. + unsigned m_max_backref; // Largest index of any backref. +#if defined(BOOST_REGEX_MSVC) && defined(_M_IX86) + // This is an ugly warning suppression workaround (for warnings *inside* std::vector + // that can not otherwise be suppressed)... + static_assert(sizeof(long) >= sizeof(void*), "Long isn't long enough!"); + std::vector m_alt_jumps; // list of alternative in the current scope. +#else + std::vector m_alt_jumps; // list of alternative in the current scope. +#endif + + basic_regex_parser& operator=(const basic_regex_parser&); + basic_regex_parser(const basic_regex_parser&); +}; + +template +basic_regex_parser::basic_regex_parser(regex_data* data) + : basic_regex_creator(data), m_parser_proc(), m_base(0), m_end(0), m_position(0), + m_mark_count(0), m_mark_reset(-1), m_max_mark(0), m_paren_start(0), m_alt_insert_point(0), m_has_case_change(false), m_recursion_count(0), m_max_backref(0) +{ +} + +template +void basic_regex_parser::parse(const charT* p1, const charT* p2, unsigned l_flags) +{ + // pass l_flags on to base class: + this->init(l_flags); + // set up pointers: + m_position = m_base = p1; + m_end = p2; + // empty strings are errors: + if((p1 == p2) && + ( + ((l_flags & regbase::main_option_type) != regbase::perl_syntax_group) + || (l_flags & regbase::no_empty_expressions) + ) + ) + { + fail(regex_constants::error_empty, 0); + return; + } + // select which parser to use: + switch(l_flags & regbase::main_option_type) + { + case regbase::perl_syntax_group: + { + m_parser_proc = &basic_regex_parser::parse_extended; + // + // Add a leading paren with index zero to give recursions a target: + // + re_brace* br = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + br->index = 0; + br->icase = this->flags() & regbase::icase; + break; + } + case regbase::basic_syntax_group: + m_parser_proc = &basic_regex_parser::parse_basic; + break; + case regbase::literal: + m_parser_proc = &basic_regex_parser::parse_literal; + break; + default: + // Oops, someone has managed to set more than one of the main option flags, + // so this must be an error: + fail(regex_constants::error_unknown, 0, "An invalid combination of regular expression syntax flags was used."); + return; + } + + // parse all our characters: + bool result = parse_all(); + // + // Unwind our alternatives: + // + unwind_alts(-1); + // reset l_flags as a global scope (?imsx) may have altered them: + this->flags(l_flags); + // if we haven't gobbled up all the characters then we must + // have had an unexpected ')' : + if(!result) + { + fail(regex_constants::error_paren, std::distance(m_base, m_position), "Found a closing ) with no corresponding opening parenthesis."); + return; + } + // if an error has been set then give up now: + if(this->m_pdata->m_status) + return; + // fill in our sub-expression count: + this->m_pdata->m_mark_count = 1u + (std::size_t)m_mark_count; + // + // Check we don't have backreferences to sub-expressions which don't exist: + // + if (m_max_backref > m_mark_count) + { + fail(regex_constants::error_backref, std::distance(m_base, m_position), "Found a backreference to a non-existant sub-expression."); + } + this->finalize(p1, p2); +} + +template +void basic_regex_parser::fail(regex_constants::error_type error_code, std::ptrdiff_t position) +{ + // get the error message: + std::string message = this->m_pdata->m_ptraits->error_string(error_code); + fail(error_code, position, message); +} + +template +void basic_regex_parser::fail(regex_constants::error_type error_code, std::ptrdiff_t position, std::string message, std::ptrdiff_t start_pos) +{ + if(0 == this->m_pdata->m_status) // update the error code if not already set + this->m_pdata->m_status = error_code; + m_position = m_end; // don't bother parsing anything else + + // + // Augment error message with the regular expression text: + // + if(start_pos == position) + start_pos = (std::max)(static_cast(0), position - static_cast(10)); + std::ptrdiff_t end_pos = (std::min)(position + static_cast(10), static_cast(m_end - m_base)); + if(error_code != regex_constants::error_empty) + { + if((start_pos != 0) || (end_pos != (m_end - m_base))) + message += " The error occurred while parsing the regular expression fragment: '"; + else + message += " The error occurred while parsing the regular expression: '"; + if(start_pos != end_pos) + { + message += std::string(m_base + start_pos, m_base + position); + message += ">>>HERE>>>"; + message += std::string(m_base + position, m_base + end_pos); + } + message += "'."; + } + +#ifndef BOOST_NO_EXCEPTIONS + if(0 == (this->flags() & regex_constants::no_except)) + { + boost::regex_error e(message, error_code, position); + e.raise(); + } +#else + (void)position; // suppress warnings. +#endif +} + +template +bool basic_regex_parser::parse_all() +{ + if (++m_recursion_count > 400) + { + // exceeded internal limits + fail(boost::regex_constants::error_complexity, m_position - m_base, "Exceeded nested brace limit."); + } + bool result = true; + while(result && (m_position != m_end)) + { + result = (this->*m_parser_proc)(); + } + --m_recursion_count; + return result; +} + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4702) +#endif +template +bool basic_regex_parser::parse_basic() +{ + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_escape: + return parse_basic_escape(); + case regex_constants::syntax_dot: + return parse_match_any(); + case regex_constants::syntax_caret: + ++m_position; + this->append_state(syntax_element_start_line); + break; + case regex_constants::syntax_dollar: + ++m_position; + this->append_state(syntax_element_end_line); + break; + case regex_constants::syntax_star: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(); + } + case regex_constants::syntax_plus: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line) || !(this->flags() & regbase::emacs_ex)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(1); + } + case regex_constants::syntax_question: + if(!(this->m_last_state) || (this->m_last_state->type == syntax_element_start_line) || !(this->flags() & regbase::emacs_ex)) + return parse_literal(); + else + { + ++m_position; + return parse_repeat(0, 1); + } + case regex_constants::syntax_open_set: + return parse_set(); + case regex_constants::syntax_newline: + if(this->flags() & regbase::newline_alt) + return parse_alt(); + else + return parse_literal(); + default: + return parse_literal(); + } + return true; +} + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable:26812) +#endif +#endif +template +bool basic_regex_parser::parse_extended() +{ + bool result = true; + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_open_mark: + return parse_open_paren(); + case regex_constants::syntax_close_mark: + return false; + case regex_constants::syntax_escape: + return parse_extended_escape(); + case regex_constants::syntax_dot: + return parse_match_any(); + case regex_constants::syntax_caret: + ++m_position; + this->append_state( + (this->flags() & regex_constants::no_mod_m ? syntax_element_buffer_start : syntax_element_start_line)); + break; + case regex_constants::syntax_dollar: + ++m_position; + this->append_state( + (this->flags() & regex_constants::no_mod_m ? syntax_element_buffer_end : syntax_element_end_line)); + break; + case regex_constants::syntax_star: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"*\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(); + case regex_constants::syntax_question: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"?\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(0,1); + case regex_constants::syntax_plus: + if(m_position == this->m_base) + { + fail(regex_constants::error_badrepeat, 0, "The repeat operator \"+\" cannot start a regular expression."); + return false; + } + ++m_position; + return parse_repeat(1); + case regex_constants::syntax_open_brace: + ++m_position; + return parse_repeat_range(false); + case regex_constants::syntax_close_brace: + if((this->flags() & regbase::no_perl_ex) == regbase::no_perl_ex) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {."); + return false; + } + result = parse_literal(); + break; + case regex_constants::syntax_or: + return parse_alt(); + case regex_constants::syntax_open_set: + return parse_set(); + case regex_constants::syntax_newline: + if(this->flags() & regbase::newline_alt) + return parse_alt(); + else + return parse_literal(); + case regex_constants::syntax_hash: + // + // If we have a mod_x flag set, then skip until + // we get to a newline character: + // + if((this->flags() + & (regbase::no_perl_ex|regbase::mod_x)) + == regbase::mod_x) + { + while((m_position != m_end) && !is_separator(*m_position++)){} + return true; + } + BOOST_REGEX_FALLTHROUGH; + default: + result = parse_literal(); + break; + } + return result; +} +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + +template +bool basic_regex_parser::parse_literal() +{ + // append this as a literal provided it's not a space character + // or the perl option regbase::mod_x is not set: + if( + ((this->flags() + & (regbase::main_option_type|regbase::mod_x|regbase::no_perl_ex)) + != regbase::mod_x) + || !this->m_traits.isctype(*m_position, this->m_mask_space)) + this->append_literal(*m_position); + ++m_position; + return true; +} + +template +bool basic_regex_parser::parse_open_paren() +{ + // + // skip the '(' and error check: + // + if(++m_position == m_end) + { + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + // + // begin by checking for a perl-style (?...) extension: + // + if( + ((this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) == 0) + || ((this->flags() & (regbase::main_option_type | regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex)) + ) + { + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_question) + return parse_perl_extension(); + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_star) + return parse_perl_verb(); + } + // + // update our mark count, and append the required state: + // + unsigned markid = 0; + if(0 == (this->flags() & regbase::nosubs)) + { + markid = ++m_mark_count; + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair(std::distance(m_base, m_position) - 1, 0)); + } + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + std::ptrdiff_t last_paren_start = this->getoffset(pb); + // back up insertion point for alternations, and set new point: + std::ptrdiff_t last_alt_point = m_alt_insert_point; + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + // + // back up the current flags in case we have a nested (?imsx) group: + // + regex_constants::syntax_option_type opts = this->flags(); + bool old_case_change = m_has_case_change; + m_has_case_change = false; // no changes to this scope as yet... + // + // Back up branch reset data in case we have a nested (?|...) + // + int mark_reset = m_mark_reset; + m_mark_reset = -1; + // + // now recursively add more states, this will terminate when we get to a + // matching ')' : + // + parse_all(); + // + // Unwind pushed alternatives: + // + if(0 == unwind_alts(last_paren_start)) + return false; + // + // restore flags: + // + if(m_has_case_change) + { + // the case has changed in one or more of the alternatives + // within the scoped (...) block: we have to add a state + // to reset the case sensitivity: + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = opts & regbase::icase; + } + this->flags(opts); + m_has_case_change = old_case_change; + // + // restore branch reset: + // + m_mark_reset = mark_reset; + // + // we either have a ')' or we have run out of characters prematurely: + // + if(m_position == m_end) + { + this->fail(regex_constants::error_paren, std::distance(m_base, m_end)); + return false; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + return false; + if(markid && (this->flags() & regbase::save_subexpression_location)) + this->m_pdata->m_subs.at(markid - 1).second = std::distance(m_base, m_position); + ++m_position; + // + // append closing parenthesis state: + // + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + this->m_paren_start = last_paren_start; + // + // restore the alternate insertion point: + // + this->m_alt_insert_point = last_alt_point; + + return true; +} + +template +bool basic_regex_parser::parse_basic_escape() +{ + if(++m_position == m_end) + { + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + bool result = true; + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::syntax_open_mark: + return parse_open_paren(); + case regex_constants::syntax_close_mark: + return false; + case regex_constants::syntax_plus: + if(this->flags() & regex_constants::bk_plus_qm) + { + ++m_position; + return parse_repeat(1); + } + else + return parse_literal(); + case regex_constants::syntax_question: + if(this->flags() & regex_constants::bk_plus_qm) + { + ++m_position; + return parse_repeat(0, 1); + } + else + return parse_literal(); + case regex_constants::syntax_open_brace: + if(this->flags() & regbase::no_intervals) + return parse_literal(); + ++m_position; + return parse_repeat_range(true); + case regex_constants::syntax_close_brace: + if(this->flags() & regbase::no_intervals) + return parse_literal(); + fail(regex_constants::error_brace, this->m_position - this->m_base, "Found a closing repetition operator } with no corresponding {."); + return false; + case regex_constants::syntax_or: + if(this->flags() & regbase::bk_vbar) + return parse_alt(); + else + result = parse_literal(); + break; + case regex_constants::syntax_digit: + return parse_backref(); + case regex_constants::escape_type_start_buffer: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_buffer_start); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_end_buffer: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_buffer_end); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_word_assert: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_boundary); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_not_word_assert: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_within_word); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_left_word: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_start); + } + else + result = parse_literal(); + break; + case regex_constants::escape_type_right_word: + if(this->flags() & regbase::emacs_ex) + { + ++m_position; + this->append_state(syntax_element_word_end); + } + else + result = parse_literal(); + break; + default: + if(this->flags() & regbase::emacs_ex) + { + bool negate = true; + switch(*m_position) + { + case 'w': + negate = false; + BOOST_REGEX_FALLTHROUGH; + case 'W': + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(this->m_word_mask); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; + } + case 's': + negate = false; + BOOST_REGEX_FALLTHROUGH; + case 'S': + return add_emacs_code(negate); + case 'c': + case 'C': + // not supported yet: + fail(regex_constants::error_escape, m_position - m_base, "The \\c and \\C escape sequences are not supported by POSIX basic regular expressions: try the Perl syntax instead."); + return false; + default: + break; + } + } + result = parse_literal(); + break; + } + return result; +} + +template +bool basic_regex_parser::parse_extended_escape() +{ + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Incomplete escape sequence found."); + return false; + } + bool negate = false; // in case this is a character class escape: \w \d etc + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::escape_type_not_class: + negate = true; + BOOST_REGEX_FALLTHROUGH; + case regex_constants::escape_type_class: + { +escape_type_class_jump: + typedef typename traits::char_class_type m_type; + m_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(m); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; + } + // + // not a class, just a regular unknown escape: + // + this->append_literal(unescape_character()); + break; + } + case regex_constants::syntax_digit: + return parse_backref(); + case regex_constants::escape_type_left_word: + ++m_position; + this->append_state(syntax_element_word_start); + break; + case regex_constants::escape_type_right_word: + ++m_position; + this->append_state(syntax_element_word_end); + break; + case regex_constants::escape_type_start_buffer: + ++m_position; + this->append_state(syntax_element_buffer_start); + break; + case regex_constants::escape_type_end_buffer: + ++m_position; + this->append_state(syntax_element_buffer_end); + break; + case regex_constants::escape_type_word_assert: + ++m_position; + this->append_state(syntax_element_word_boundary); + break; + case regex_constants::escape_type_not_word_assert: + ++m_position; + this->append_state(syntax_element_within_word); + break; + case regex_constants::escape_type_Z: + ++m_position; + this->append_state(syntax_element_soft_buffer_end); + break; + case regex_constants::escape_type_Q: + return parse_QE(); + case regex_constants::escape_type_C: + return parse_match_any(); + case regex_constants::escape_type_X: + ++m_position; + this->append_state(syntax_element_combining); + break; + case regex_constants::escape_type_G: + ++m_position; + this->append_state(syntax_element_restart_continue); + break; + case regex_constants::escape_type_not_property: + negate = true; + BOOST_REGEX_FALLTHROUGH; + case regex_constants::escape_type_property: + { + ++m_position; + char_class_type m; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Incomplete property escape found."); + return false; + } + // maybe have \p{ddd} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + const charT* base = m_position; + // skip forward until we find enclosing brace: + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Closing } missing from property escape sequence."); + return false; + } + m = this->m_traits.lookup_classname(++base, m_position++); + } + else + { + m = this->m_traits.lookup_classname(m_position, m_position+1); + ++m_position; + } + if(m != 0) + { + basic_char_set char_set; + if(negate) + char_set.negate(); + char_set.add_class(m); + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + return true; + } + fail(regex_constants::error_ctype, m_position - m_base, "Escape sequence was neither a valid property nor a valid character class name."); + return false; + } + case regex_constants::escape_type_reset_start_mark: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->index = -5; + pb->icase = this->flags() & regbase::icase; + this->m_pdata->m_data.align(); + ++m_position; + return true; + } + goto escape_type_class_jump; + case regex_constants::escape_type_line_ending: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + const charT* e = get_escape_R_string(); + const charT* old_position = m_position; + const charT* old_end = m_end; + const charT* old_base = m_base; + m_position = e; + m_base = e; + m_end = e + traits::length(e); + bool r = parse_all(); + m_position = ++old_position; + m_end = old_end; + m_base = old_base; + return r; + } + goto escape_type_class_jump; + case regex_constants::escape_type_extended_backref: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + { + bool have_brace = false; + bool negative = false; + static const char incomplete_message[] = "Incomplete \\g escape found."; + if(++m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + // maybe have \g{ddd} + regex_constants::syntax_type syn = this->m_traits.syntax_type(*m_position); + regex_constants::syntax_type syn_end = 0; + if((syn == regex_constants::syntax_open_brace) + || (syn == regex_constants::escape_type_left_word) + || (syn == regex_constants::escape_type_end_buffer)) + { + if(++m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + have_brace = true; + switch(syn) + { + case regex_constants::syntax_open_brace: + syn_end = regex_constants::syntax_close_brace; + break; + case regex_constants::escape_type_left_word: + syn_end = regex_constants::escape_type_right_word; + break; + default: + syn_end = regex_constants::escape_type_end_buffer; + break; + } + } + negative = (*m_position == static_cast('-')); + if((negative) && (++m_position == m_end)) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + const charT* pc = m_position; + std::intmax_t i = this->m_traits.toi(pc, m_end, 10); + if((i < 0) && syn_end) + { + // Check for a named capture, get the leftmost one if there is more than one: + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != syn_end)) + { + ++m_position; + } + i = hash_value_from_capture_name(base, m_position); + pc = m_position; + } + if(negative) + i = 1 + (static_cast(m_mark_count) - i); + if(((i < hash_value_mask) && (i > 0)) || ((i >= hash_value_mask) && (this->m_pdata->get_id((int)i) > 0))) + { + m_position = pc; + re_brace* pb = static_cast(this->append_state(syntax_element_backref, sizeof(re_brace))); + pb->index = (int)i; + pb->icase = this->flags() & regbase::icase; + if ((i > m_max_backref) && (i < hash_value_mask)) + m_max_backref = i; + } + else + { + fail(regex_constants::error_backref, m_position - m_base); + return false; + } + m_position = pc; + if(have_brace) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != syn_end)) + { + fail(regex_constants::error_escape, m_position - m_base, incomplete_message); + return false; + } + ++m_position; + } + return true; + } + goto escape_type_class_jump; + case regex_constants::escape_type_control_v: + if(0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + goto escape_type_class_jump; + BOOST_REGEX_FALLTHROUGH; + default: + this->append_literal(unescape_character()); + break; + } + return true; +} + +template +bool basic_regex_parser::parse_match_any() +{ + // + // we have a '.' that can match any character: + // + ++m_position; + static_cast( + this->append_state(syntax_element_wild, sizeof(re_dot)) + )->mask = static_cast(this->flags() & regbase::no_mod_s + ? BOOST_REGEX_DETAIL_NS::force_not_newline + : this->flags() & regbase::mod_s ? + BOOST_REGEX_DETAIL_NS::force_newline : BOOST_REGEX_DETAIL_NS::dont_care); + return true; +} + +template +bool basic_regex_parser::parse_repeat(std::size_t low, std::size_t high) +{ + bool greedy = true; + bool possessive = false; + std::size_t insert_point; + // + // when we get to here we may have a non-greedy ? mark still to come: + // + if((m_position != m_end) + && ( + (0 == (this->flags() & (regbase::main_option_type | regbase::no_perl_ex))) + || ((regbase::basic_syntax_group|regbase::emacs_ex) == (this->flags() & (regbase::main_option_type | regbase::emacs_ex))) + ) + ) + { + // OK we have a perl or emacs regex, check for a '?': + if ((this->flags() & (regbase::main_option_type | regbase::mod_x | regbase::no_perl_ex)) == regbase::mod_x) + { + // whitespace skip: + while ((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + } + if((m_position != m_end) && (this->m_traits.syntax_type(*m_position) == regex_constants::syntax_question)) + { + greedy = false; + ++m_position; + } + // for perl regexes only check for possessive ++ repeats. + if((m_position != m_end) + && (0 == (this->flags() & regbase::main_option_type)) + && (this->m_traits.syntax_type(*m_position) == regex_constants::syntax_plus)) + { + possessive = true; + ++m_position; + } + } + if(0 == this->m_last_state) + { + fail(regex_constants::error_badrepeat, std::distance(m_base, m_position), "Nothing to repeat."); + return false; + } + if(this->m_last_state->type == syntax_element_endmark) + { + // insert a repeat before the '(' matching the last ')': + insert_point = this->m_paren_start; + } + else if((this->m_last_state->type == syntax_element_literal) && (static_cast(this->m_last_state)->length > 1)) + { + // the last state was a literal with more than one character, split it in two: + re_literal* lit = static_cast(this->m_last_state); + charT c = (static_cast(static_cast(lit+1)))[lit->length - 1]; + lit->length -= 1; + // now append new state: + lit = static_cast(this->append_state(syntax_element_literal, sizeof(re_literal) + sizeof(charT))); + lit->length = 1; + (static_cast(static_cast(lit+1)))[0] = c; + insert_point = this->getoffset(this->m_last_state); + } + else + { + // repeat the last state whatever it was, need to add some error checking here: + switch(this->m_last_state->type) + { + case syntax_element_start_line: + case syntax_element_end_line: + case syntax_element_word_boundary: + case syntax_element_within_word: + case syntax_element_word_start: + case syntax_element_word_end: + case syntax_element_buffer_start: + case syntax_element_buffer_end: + case syntax_element_alt: + case syntax_element_soft_buffer_end: + case syntax_element_restart_continue: + case syntax_element_jump: + case syntax_element_startmark: + case syntax_element_backstep: + case syntax_element_toggle_case: + // can't legally repeat any of the above: + fail(regex_constants::error_badrepeat, m_position - m_base); + return false; + default: + // do nothing... + break; + } + insert_point = this->getoffset(this->m_last_state); + } + // + // OK we now know what to repeat, so insert the repeat around it: + // + re_repeat* rep = static_cast(this->insert_state(insert_point, syntax_element_rep, re_repeater_size)); + rep->min = low; + rep->max = high; + rep->greedy = greedy; + rep->leading = false; + // store our repeater position for later: + std::ptrdiff_t rep_off = this->getoffset(rep); + // and append a back jump to the repeat: + re_jump* jmp = static_cast(this->append_state(syntax_element_jump, sizeof(re_jump))); + jmp->alt.i = rep_off - this->getoffset(jmp); + this->m_pdata->m_data.align(); + // now fill in the alt jump for the repeat: + rep = static_cast(this->getaddress(rep_off)); + rep->alt.i = this->m_pdata->m_data.size() - rep_off; + // + // If the repeat is possessive then bracket the repeat with a (?>...) + // independent sub-expression construct: + // + if(possessive) + { + if(m_position != m_end) + { + // + // Check for illegal following quantifier, we have to do this here, because + // the extra states we insert below circumvents our usual error checking :-( + // + bool contin = false; + do + { + if ((this->flags() & (regbase::main_option_type | regbase::mod_x | regbase::no_perl_ex)) == regbase::mod_x) + { + // whitespace skip: + while ((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + } + if (m_position != m_end) + { + switch (this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_star: + case regex_constants::syntax_plus: + case regex_constants::syntax_question: + case regex_constants::syntax_open_brace: + fail(regex_constants::error_badrepeat, m_position - m_base); + return false; + case regex_constants::syntax_open_mark: + // Do we have a comment? If so we need to skip it here... + if ((m_position + 2 < m_end) && this->m_traits.syntax_type(*(m_position + 1)) == regex_constants::syntax_question + && this->m_traits.syntax_type(*(m_position + 2)) == regex_constants::syntax_hash) + { + while ((m_position != m_end) + && (this->m_traits.syntax_type(*m_position++) != regex_constants::syntax_close_mark)) { + } + contin = true; + } + else + contin = false; + break; + default: + contin = false; + } + } + else + contin = false; + } while (contin); + } + re_brace* pb = static_cast(this->insert_state(insert_point, syntax_element_startmark, sizeof(re_brace))); + pb->index = -3; + pb->icase = this->flags() & regbase::icase; + jmp = static_cast(this->insert_state(insert_point + sizeof(re_brace), syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + jmp->alt.i = this->m_pdata->m_data.size() - this->getoffset(jmp); + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = -3; + pb->icase = this->flags() & regbase::icase; + } + return true; +} + +template +bool basic_regex_parser::parse_repeat_range(bool isbasic) +{ + static const char incomplete_message[] = "Missing } in quantified repetition."; + // + // parse a repeat-range: + // + std::size_t min, max; + std::intmax_t v; + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // get min: + v = this->m_traits.toi(m_position, m_end, 10); + // skip whitespace: + if((v < 0) || (v > umax())) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + min = static_cast(v); + // see if we have a comma: + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_comma) + { + // move on and error check: + ++m_position; + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // get the value if any: + v = this->m_traits.toi(m_position, m_end, 10); + max = ((v >= 0) && (v < umax())) ? (std::size_t)v : (std::numeric_limits::max)(); + } + else + { + // no comma, max = min: + max = min; + } + // skip whitespace: + while((m_position != m_end) && this->m_traits.isctype(*m_position, this->m_mask_space)) + ++m_position; + // OK now check trailing }: + if(this->m_position == this->m_end) + { + if(this->flags() & (regbase::main_option_type | regbase::no_perl_ex)) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + if(isbasic) + { + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_escape) + { + ++m_position; + if(this->m_position == this->m_end) + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + } + else + { + fail(regex_constants::error_brace, this->m_position - this->m_base, incomplete_message); + return false; + } + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_brace) + ++m_position; + else + { + // Treat the opening '{' as a literal character, rewind to start of error: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_brace) --m_position; + return parse_literal(); + } + // + // finally go and add the repeat, unless error: + // + if(min > max) + { + // Backtrack to error location: + m_position -= 2; + while(this->m_traits.isctype(*m_position, this->m_word_mask)) --m_position; + ++m_position; + fail(regex_constants::error_badbrace, m_position - m_base); + return false; + } + return parse_repeat(min, max); +} + +template +bool basic_regex_parser::parse_alt() +{ + // + // error check: if there have been no previous states, + // or if the last state was a '(' then error: + // + if( + ((this->m_last_state == 0) || (this->m_last_state->type == syntax_element_startmark)) + && + !( + ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) + && + ((this->flags() & regbase::no_empty_expressions) == 0) + ) + ) + { + fail(regex_constants::error_empty, this->m_position - this->m_base, "A regular expression cannot start with the alternation operator |."); + return false; + } + // + // Reset mark count if required: + // + if(m_max_mark < m_mark_count) + m_max_mark = m_mark_count; + if(m_mark_reset >= 0) + m_mark_count = m_mark_reset; + + ++m_position; + // + // we need to append a trailing jump: + // + re_syntax_base* pj = this->append_state(BOOST_REGEX_DETAIL_NS::syntax_element_jump, sizeof(re_jump)); + std::ptrdiff_t jump_offset = this->getoffset(pj); + // + // now insert the alternative: + // + re_alt* palt = static_cast(this->insert_state(this->m_alt_insert_point, syntax_element_alt, re_alt_size)); + jump_offset += re_alt_size; + this->m_pdata->m_data.align(); + palt->alt.i = this->m_pdata->m_data.size() - this->getoffset(palt); + // + // update m_alt_insert_point so that the next alternate gets + // inserted at the start of the second of the two we've just created: + // + this->m_alt_insert_point = this->m_pdata->m_data.size(); + // + // the start of this alternative must have a case changes state + // if the current block has messed around with case changes: + // + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = this->m_icase; + } + // + // push the alternative onto our stack, a recursive + // implementation here is easier to understand (and faster + // as it happens), but causes all kinds of stack overflow problems + // on programs with small stacks (COM+). + // + m_alt_jumps.push_back(jump_offset); + return true; +} + +template +bool basic_regex_parser::parse_set() +{ + static const char incomplete_message[] = "Character set declaration starting with [ terminated prematurely - either no ] was found or the set had no content."; + ++m_position; + if(m_position == m_end) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + basic_char_set char_set; + + const charT* base = m_position; // where the '[' was + const charT* item_base = m_position; // where the '[' or '^' was + + while(m_position != m_end) + { + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_caret: + if(m_position == base) + { + char_set.negate(); + ++m_position; + item_base = m_position; + } + else + parse_set_literal(char_set); + break; + case regex_constants::syntax_close_set: + if(m_position == item_base) + { + parse_set_literal(char_set); + break; + } + else + { + ++m_position; + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + } + return true; + case regex_constants::syntax_open_set: + if(parse_inner_set(char_set)) + break; + return true; + case regex_constants::syntax_escape: + { + // + // look ahead and see if this is a character class shortcut + // \d \w \s etc... + // + ++m_position; + if(this->m_traits.escape_syntax_type(*m_position) + == regex_constants::escape_type_class) + { + char_class_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + char_set.add_class(m); + ++m_position; + break; + } + } + else if(this->m_traits.escape_syntax_type(*m_position) + == regex_constants::escape_type_not_class) + { + // negated character class: + char_class_type m = this->m_traits.lookup_classname(m_position, m_position+1); + if(m != 0) + { + char_set.add_negated_class(m); + ++m_position; + break; + } + } + // not a character class, just a regular escape: + --m_position; + parse_set_literal(char_set); + break; + } + default: + parse_set_literal(char_set); + break; + } + } + return m_position != m_end; +} + +template +bool basic_regex_parser::parse_inner_set(basic_char_set& char_set) +{ + static const char incomplete_message[] = "Character class declaration starting with [ terminated prematurely - either no ] was found or the set had no content."; + // + // we have either a character class [:name:] + // a collating element [.name.] + // or an equivalence class [=name=] + // + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_dot: + // + // a collating element is treated as a literal: + // + --m_position; + parse_set_literal(char_set); + return true; + case regex_constants::syntax_colon: + { + // check that character classes are actually enabled: + if((this->flags() & (regbase::main_option_type | regbase::no_char_classes)) + == (regbase::basic_syntax_group | regbase::no_char_classes)) + { + --m_position; + parse_set_literal(char_set); + return true; + } + // skip the ':' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching ':]' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_colon)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + // + // check for negated class: + // + bool negated = false; + if(this->m_traits.syntax_type(*name_first) == regex_constants::syntax_caret) + { + ++name_first; + negated = true; + } + typedef typename traits::char_class_type m_type; + m_type m = this->m_traits.lookup_classname(name_first, name_last); + if(m == 0) + { + if(char_set.empty() && (name_last - name_first == 1)) + { + // maybe a special case: + ++m_position; + if( (m_position != m_end) + && (this->m_traits.syntax_type(*m_position) + == regex_constants::syntax_close_set)) + { + if(this->m_traits.escape_syntax_type(*name_first) + == regex_constants::escape_type_left_word) + { + ++m_position; + this->append_state(syntax_element_word_start); + return false; + } + if(this->m_traits.escape_syntax_type(*name_first) + == regex_constants::escape_type_right_word) + { + ++m_position; + this->append_state(syntax_element_word_end); + return false; + } + } + } + fail(regex_constants::error_ctype, name_first - m_base); + return false; + } + if(!negated) + char_set.add_class(m); + else + char_set.add_negated_class(m); + ++m_position; + break; + } + case regex_constants::syntax_equal: + { + // skip the '=' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching '=]' + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_brack, m_position - m_base, incomplete_message); + return false; + } + string_type m = this->m_traits.lookup_collatename(name_first, name_last); + if(m.empty() || (m.size() > 2)) + { + fail(regex_constants::error_collate, name_first - m_base); + return false; + } + digraph d; + d.first = m[0]; + if(m.size() > 1) + d.second = m[1]; + else + d.second = 0; + char_set.add_equivalent(d); + ++m_position; + break; + } + default: + --m_position; + parse_set_literal(char_set); + break; + } + return true; +} + +template +void basic_regex_parser::parse_set_literal(basic_char_set& char_set) +{ + digraph start_range(get_next_set_literal(char_set)); + if(m_end == m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_dash) + { + // we have a range: + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set) + { + digraph end_range = get_next_set_literal(char_set); + char_set.add_range(start_range, end_range); + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_dash) + { + if(m_end == ++m_position) + { + fail(regex_constants::error_brack, m_position - m_base); + return; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_set) + { + // trailing - : + --m_position; + return; + } + fail(regex_constants::error_range, m_position - m_base); + return; + } + return; + } + --m_position; + } + char_set.add_single(start_range); +} + +template +digraph basic_regex_parser::get_next_set_literal(basic_char_set& char_set) +{ + digraph result; + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_dash: + if(!char_set.empty()) + { + // see if we are at the end of the set: + if((++m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_range, m_position - m_base); + return result; + } + --m_position; + } + result.first = *m_position++; + return result; + case regex_constants::syntax_escape: + // check to see if escapes are supported first: + if(this->flags() & regex_constants::no_escape_in_lists) + { + result = *m_position++; + break; + } + ++m_position; + result = unescape_character(); + break; + case regex_constants::syntax_open_set: + { + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, m_position - m_base); + return result; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_dot) + { + --m_position; + result.first = *m_position; + ++m_position; + return result; + } + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, m_position - m_base); + return result; + } + const charT* name_first = m_position; + // skip at least one character, then find the matching ':]' + if(m_end == ++m_position) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_dot)) + ++m_position; + const charT* name_last = m_position; + if(m_end == m_position) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + if((m_end == ++m_position) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_set)) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + ++m_position; + string_type s = this->m_traits.lookup_collatename(name_first, name_last); + if(s.empty() || (s.size() > 2)) + { + fail(regex_constants::error_collate, name_first - m_base); + return result; + } + result.first = s[0]; + if(s.size() > 1) + result.second = s[1]; + else + result.second = 0; + return result; + } + default: + result = *m_position++; + } + return result; +} + +// +// does a value fit in the specified charT type? +// +template +bool valid_value(charT, std::intmax_t v, const std::integral_constant&) +{ + return (v >> (sizeof(charT) * CHAR_BIT)) == 0; +} +template +bool valid_value(charT, std::intmax_t, const std::integral_constant&) +{ + return true; // v will alsways fit in a charT +} +template +bool valid_value(charT c, std::intmax_t v) +{ + return valid_value(c, v, std::integral_constant()); +} + +template +charT basic_regex_parser::unescape_character() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + charT result(0); + if(m_position == m_end) + { + fail(regex_constants::error_escape, m_position - m_base, "Escape sequence terminated prematurely."); + return false; + } + switch(this->m_traits.escape_syntax_type(*m_position)) + { + case regex_constants::escape_type_control_a: + result = charT('\a'); + break; + case regex_constants::escape_type_e: + result = charT(27); + break; + case regex_constants::escape_type_control_f: + result = charT('\f'); + break; + case regex_constants::escape_type_control_n: + result = charT('\n'); + break; + case regex_constants::escape_type_control_r: + result = charT('\r'); + break; + case regex_constants::escape_type_control_t: + result = charT('\t'); + break; + case regex_constants::escape_type_control_v: + result = charT('\v'); + break; + case regex_constants::escape_type_word_assert: + result = charT('\b'); + break; + case regex_constants::escape_type_ascii_control: + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "ASCII escape sequence terminated prematurely."); + return result; + } + result = static_cast(*m_position % 32); + break; + case regex_constants::escape_type_hex: + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Hexadecimal escape sequence terminated prematurely."); + return result; + } + // maybe have \x{ddd} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Missing } in hexadecimal escape sequence."); + return result; + } + std::intmax_t i = this->m_traits.toi(m_position, m_end, 16); + if((m_position == m_end) + || (i < 0) + || ((std::numeric_limits::is_specialized) && (i > (std::intmax_t)(std::numeric_limits::max)())) + || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_badbrace, m_position - m_base, "Hexadecimal escape sequence was invalid."); + return result; + } + ++m_position; + result = charT(i); + } + else + { + std::ptrdiff_t len = (std::min)(static_cast(2), static_cast(m_end - m_position)); + std::intmax_t i = this->m_traits.toi(m_position, m_position + len, 16); + if((i < 0) + || !valid_value(charT(0), i)) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Escape sequence did not encode a valid character."); + return result; + } + result = charT(i); + } + return result; + case regex_constants::syntax_digit: + { + // an octal escape sequence, the first character must be a zero + // followed by up to 3 octal digits: + std::ptrdiff_t len = (std::min)(std::distance(m_position, m_end), static_cast(4)); + const charT* bp = m_position; + std::intmax_t val = this->m_traits.toi(bp, bp + 1, 8); + if(val != 0) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + // Oops not an octal escape after all: + fail(regex_constants::error_escape, m_position - m_base, "Invalid octal escape sequence."); + return result; + } + val = this->m_traits.toi(m_position, m_position + len, 8); + if((val < 0) || (val > (std::intmax_t)(std::numeric_limits::max)())) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base, "Octal escape sequence is invalid."); + return result; + } + return static_cast(val); + } + case regex_constants::escape_type_named_char: + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + // maybe have \N{name} + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_open_brace) + { + const charT* base = m_position; + // skip forward until we find enclosing brace: + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_brace)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + string_type s = this->m_traits.lookup_collatename(++base, m_position++); + if(s.empty()) + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_collate, m_position - m_base); + return false; + } + if(s.size() == 1) + { + return s[0]; + } + } + // fall through is a failure: + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + default: + result = *m_position; + break; + } + ++m_position; + return result; +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool basic_regex_parser::parse_backref() +{ + BOOST_REGEX_ASSERT(m_position != m_end); + const charT* pc = m_position; + std::intmax_t i = this->m_traits.toi(pc, pc + 1, 10); + if((i == 0) || (((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) && (this->flags() & regbase::no_bk_refs))) + { + // not a backref at all but an octal escape sequence: + charT c = unescape_character(); + this->append_literal(c); + } + else if((i > 0)) + { + m_position = pc; + re_brace* pb = static_cast(this->append_state(syntax_element_backref, sizeof(re_brace))); + pb->index = (int)i; + pb->icase = this->flags() & regbase::icase; + if(i > m_max_backref) + m_max_backref = i; + } + else + { + // Rewind to start of escape: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_backref, m_position - m_base); + return false; + } + return true; +} + +template +bool basic_regex_parser::parse_QE() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + // + // parse a \Q...\E sequence: + // + ++m_position; // skip the Q + const charT* start = m_position; + const charT* end; + do + { + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape)) + ++m_position; + if(m_position == m_end) + { + // a \Q...\E sequence may terminate with the end of the expression: + end = m_position; + break; + } + if(++m_position == m_end) // skip the escape + { + fail(regex_constants::error_escape, m_position - m_base, "Unterminated \\Q...\\E sequence."); + return false; + } + // check to see if it's a \E: + if(this->m_traits.escape_syntax_type(*m_position) == regex_constants::escape_type_E) + { + ++m_position; + end = m_position - 2; + break; + } + // otherwise go round again: + }while(true); + // + // now add all the character between the two escapes as literals: + // + while(start != end) + { + this->append_literal(*start); + ++start; + } + return true; +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool basic_regex_parser::parse_perl_extension() +{ + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + // + // treat comments as a special case, as these + // are the only ones that don't start with a leading + // startmark state: + // + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_hash) + { + while((m_position != m_end) + && (this->m_traits.syntax_type(*m_position++) != regex_constants::syntax_close_mark)) + {} + return true; + } + // + // backup some state, and prepare the way: + // + int markid = 0; + std::ptrdiff_t jump_offset = 0; + re_brace* pb = static_cast(this->append_state(syntax_element_startmark, sizeof(re_brace))); + pb->icase = this->flags() & regbase::icase; + std::ptrdiff_t last_paren_start = this->getoffset(pb); + // back up insertion point for alternations, and set new point: + std::ptrdiff_t last_alt_point = m_alt_insert_point; + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + std::ptrdiff_t expected_alt_point = m_alt_insert_point; + bool restore_flags = true; + regex_constants::syntax_option_type old_flags = this->flags(); + bool old_case_change = m_has_case_change; + m_has_case_change = false; + charT name_delim; + int mark_reset = m_mark_reset; + int max_mark = m_max_mark; + m_mark_reset = -1; + m_max_mark = m_mark_count; + std::intmax_t v; + // + // select the actual extension used: + // + switch(this->m_traits.syntax_type(*m_position)) + { + case regex_constants::syntax_or: + m_mark_reset = m_mark_count; + BOOST_REGEX_FALLTHROUGH; + case regex_constants::syntax_colon: + // + // a non-capturing mark: + // + pb->index = markid = 0; + ++m_position; + break; + case regex_constants::syntax_digit: + { + // + // a recursive subexpression: + // + v = this->m_traits.toi(m_position, m_end, 10); + if((v < 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "The recursive sub-expression refers to an invalid marking group, or is unterminated."); + return false; + } +insert_recursion: + pb->index = markid = 0; + re_recurse* pr = static_cast(this->append_state(syntax_element_recurse, sizeof(re_recurse))); + pr->alt.i = (std::ptrdiff_t)v; + pr->state_id = 0; + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = this->flags() & regbase::icase; + break; + } + case regex_constants::syntax_plus: + // + // A forward-relative recursive subexpression: + // + ++m_position; + v = this->m_traits.toi(m_position, m_end, 10); + if((v <= 0) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + if ((std::numeric_limits::max)() - m_mark_count < v) + { + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + v += m_mark_count; + goto insert_recursion; + case regex_constants::syntax_dash: + // + // Possibly a backward-relative recursive subexpression: + // + ++m_position; + v = this->m_traits.toi(m_position, m_end, 10); + if(v <= 0) + { + --m_position; + // Oops not a relative recursion at all, but a (?-imsx) group: + goto option_group_jump; + } + v = static_cast(m_mark_count) + 1 - v; + if(v <= 0) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "An invalid or unterminated recursive sub-expression."); + return false; + } + goto insert_recursion; + case regex_constants::syntax_equal: + pb->index = markid = -1; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::syntax_not: + pb->index = markid = -2; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::escape_type_left_word: + { + // a lookbehind assertion: + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + regex_constants::syntax_type t = this->m_traits.syntax_type(*m_position); + if(t == regex_constants::syntax_not) + pb->index = markid = -2; + else if(t == regex_constants::syntax_equal) + pb->index = markid = -1; + else + { + // Probably a named capture which also starts (?< : + name_delim = '>'; + --m_position; + goto named_capture_jump; + } + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->append_state(syntax_element_backstep, sizeof(re_brace)); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + } + case regex_constants::escape_type_right_word: + // + // an independent sub-expression: + // + pb->index = markid = -3; + ++m_position; + jump_offset = this->getoffset(this->append_state(syntax_element_jump, sizeof(re_jump))); + this->m_pdata->m_data.align(); + m_alt_insert_point = this->m_pdata->m_data.size(); + break; + case regex_constants::syntax_open_mark: + { + // a conditional expression: + pb->index = markid = -4; + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = this->m_traits.toi(m_position, m_end, 10); + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('R')) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('&')) + { + const charT* base = ++m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = -static_cast(hash_value_from_capture_name(base, m_position)); + } + else + { + v = -this->m_traits.toi(m_position, m_end, 10); + } + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = v < 0 ? (int)(v - 1) : 0; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if((*m_position == charT('\'')) || (*m_position == charT('<'))) + { + const charT* base = ++m_position; + while((m_position != m_end) && (*m_position != charT('>')) && (*m_position != charT('\''))) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = (int)v; + if(((*m_position != charT('>')) && (*m_position != charT('\''))) || (++m_position == m_end)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Unterminated named capture."); + return false; + } + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if(*m_position == charT('D')) + { + const char* def = "DEFINE"; + while(*def && (m_position != m_end) && (*m_position == charT(*def))) + ++m_position, ++def; + if((m_position == m_end) || *def) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = 9999; // special magic value! + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else if(v > 0) + { + re_brace* br = static_cast(this->append_state(syntax_element_assert_backref, sizeof(re_brace))); + br->index = (int)v; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + } + else + { + // verify that we have a lookahead or lookbehind assert: + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_question) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(this->m_traits.syntax_type(*m_position) == regex_constants::escape_type_left_word) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + m_position -= 3; + } + else + { + if((this->m_traits.syntax_type(*m_position) != regex_constants::syntax_equal) + && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_not)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + m_position -= 2; + } + } + break; + } + case regex_constants::syntax_close_mark: + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + case regex_constants::escape_type_end_buffer: + { + name_delim = *m_position; +named_capture_jump: + markid = 0; + if(0 == (this->flags() & regbase::nosubs)) + { + markid = ++m_mark_count; + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.push_back(std::pair(std::distance(m_base, m_position) - 2, 0)); + } + pb->index = markid; + const charT* base = ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + while((m_position != m_end) && (*m_position != name_delim)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + this->m_pdata->set_name(base, m_position, markid); + ++m_position; + break; + } + default: + if(*m_position == charT('R')) + { + ++m_position; + v = 0; + if(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + goto insert_recursion; + } + if(*m_position == charT('&')) + { + ++m_position; + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + goto insert_recursion; + } + if(*m_position == charT('P')) + { + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(*m_position == charT('>')) + { + ++m_position; + const charT* base = m_position; + while((m_position != m_end) && (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + ++m_position; + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + v = static_cast(hash_value_from_capture_name(base, m_position)); + goto insert_recursion; + } + } + // + // lets assume that we have a (?imsx) group and try and parse it: + // +option_group_jump: + regex_constants::syntax_option_type opts = parse_options(); + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + // make a note of whether we have a case change: + m_has_case_change = ((opts & regbase::icase) != (this->flags() & regbase::icase)); + pb->index = markid = 0; + if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark) + { + // update flags and carry on as normal: + this->flags(opts); + restore_flags = false; + old_case_change |= m_has_case_change; // defer end of scope by one ')' + } + else if(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_colon) + { + // update flags and carry on until the matching ')' is found: + this->flags(opts); + ++m_position; + } + else + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + + // finally append a case change state if we need it: + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = opts & regbase::icase; + } + + } + // + // now recursively add more states, this will terminate when we get to a + // matching ')' : + // + parse_all(); + // + // Unwind alternatives: + // + if(0 == unwind_alts(last_paren_start)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid alternation operators within (?...) block."); + return false; + } + // + // we either have a ')' or we have run out of characters prematurely: + // + if(m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + this->fail(regex_constants::error_paren, std::distance(m_base, m_end)); + return false; + } + BOOST_REGEX_ASSERT(this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark); + ++m_position; + // + // restore the flags: + // + if(restore_flags) + { + // append a case change state if we need it: + if(m_has_case_change) + { + static_cast( + this->append_state(syntax_element_toggle_case, sizeof(re_case)) + )->icase = old_flags & regbase::icase; + } + this->flags(old_flags); + } + // + // set up the jump pointer if we have one: + // + if(jump_offset) + { + this->m_pdata->m_data.align(); + re_jump* jmp = static_cast(this->getaddress(jump_offset)); + jmp->alt.i = this->m_pdata->m_data.size() - this->getoffset(jmp); + if((this->m_last_state == jmp) && (markid != -2)) + { + // Oops... we didn't have anything inside the assertion. + // Note we don't get here for negated forward lookahead as (?!) + // does have some uses. + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base, "Invalid or empty zero width assertion."); + return false; + } + } + // + // verify that if this is conditional expression, that we do have + // an alternative, if not add one: + // + if(markid == -4) + { + re_syntax_base* b = this->getaddress(expected_alt_point); + // Make sure we have exactly one alternative following this state: + if(b->type != syntax_element_alt) + { + re_alt* alt = static_cast(this->insert_state(expected_alt_point, syntax_element_alt, sizeof(re_alt))); + alt->alt.i = this->m_pdata->m_data.size() - this->getoffset(alt); + } + else if(((std::ptrdiff_t)this->m_pdata->m_data.size() > (static_cast(b)->alt.i + this->getoffset(b))) && (static_cast(b)->alt.i > 0) && this->getaddress(static_cast(b)->alt.i, b)->type == syntax_element_alt) + { + // Can't have seen more than one alternative: + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_bad_pattern, m_position - m_base, "More than one alternation operator | was encountered inside a conditional expression."); + return false; + } + else + { + // We must *not* have seen an alternative inside a (DEFINE) block: + b = this->getaddress(b->next.i, b); + if((b->type == syntax_element_assert_backref) && (static_cast(b)->index == 9999)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_bad_pattern, m_position - m_base, "Alternation operators are not allowed inside a DEFINE block."); + return false; + } + } + // check for invalid repetition of next state: + b = this->getaddress(expected_alt_point); + b = this->getaddress(static_cast(b)->next.i, b); + if((b->type != syntax_element_assert_backref) + && (b->type != syntax_element_startmark)) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_badrepeat, m_position - m_base, "A repetition operator cannot be applied to a zero-width assertion."); + return false; + } + } + // + // append closing parenthesis state: + // + pb = static_cast(this->append_state(syntax_element_endmark, sizeof(re_brace))); + pb->index = markid; + pb->icase = this->flags() & regbase::icase; + this->m_paren_start = last_paren_start; + // + // restore the alternate insertion point: + // + this->m_alt_insert_point = last_alt_point; + // + // and the case change data: + // + m_has_case_change = old_case_change; + // + // And the mark_reset data: + // + if(m_max_mark > m_mark_count) + { + m_mark_count = m_max_mark; + } + m_mark_reset = mark_reset; + m_max_mark = max_mark; + + + if(markid > 0) + { + if(this->flags() & regbase::save_subexpression_location) + this->m_pdata->m_subs.at((std::size_t)markid - 1).second = std::distance(m_base, m_position) - 1; + } + return true; +} + +template +bool basic_regex_parser::match_verb(const char* verb) +{ + while(*verb) + { + if(static_cast(*verb) != *m_position) + { + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(++m_position == m_end) + { + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++verb; + } + return true; +} + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable:26812) +#endif +#endif +template +bool basic_regex_parser::parse_perl_verb() +{ + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + switch(*m_position) + { + case 'F': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if((this->m_traits.syntax_type(*m_position) == regex_constants::syntax_close_mark) || match_verb("AIL")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_fail); + return true; + } + break; + case 'A': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("CCEPT")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_accept); + return true; + } + break; + case 'C': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("OMMIT")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_commit; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'P': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("RUNE")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_prune; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'S': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("KIP")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + static_cast(this->append_state(syntax_element_commit, sizeof(re_commit)))->action = commit_skip; + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + case 'T': + if(++m_position == m_end) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + if(match_verb("HEN")) + { + if((m_position == m_end) || (this->m_traits.syntax_type(*m_position) != regex_constants::syntax_close_mark)) + { + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; + } + ++m_position; + this->append_state(syntax_element_then); + this->m_pdata->m_disable_match_any = true; + return true; + } + break; + } + // Rewind to start of (* sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_perl_extension, m_position - m_base); + return false; +} +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +template +bool basic_regex_parser::add_emacs_code(bool negate) +{ + // + // parses an emacs style \sx or \Sx construct. + // + if(++m_position == m_end) + { + // Rewind to start of sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_escape) --m_position; + fail(regex_constants::error_escape, m_position - m_base); + return false; + } + basic_char_set char_set; + if(negate) + char_set.negate(); + + static const charT s_punct[5] = { 'p', 'u', 'n', 'c', 't', }; + + switch(*m_position) + { + case 's': + case ' ': + char_set.add_class(this->m_mask_space); + break; + case 'w': + char_set.add_class(this->m_word_mask); + break; + case '_': + char_set.add_single(digraph(charT('$'))); + char_set.add_single(digraph(charT('&'))); + char_set.add_single(digraph(charT('*'))); + char_set.add_single(digraph(charT('+'))); + char_set.add_single(digraph(charT('-'))); + char_set.add_single(digraph(charT('_'))); + char_set.add_single(digraph(charT('<'))); + char_set.add_single(digraph(charT('>'))); + break; + case '.': + char_set.add_class(this->m_traits.lookup_classname(s_punct, s_punct+5)); + break; + case '(': + char_set.add_single(digraph(charT('('))); + char_set.add_single(digraph(charT('['))); + char_set.add_single(digraph(charT('{'))); + break; + case ')': + char_set.add_single(digraph(charT(')'))); + char_set.add_single(digraph(charT(']'))); + char_set.add_single(digraph(charT('}'))); + break; + case '"': + char_set.add_single(digraph(charT('"'))); + char_set.add_single(digraph(charT('\''))); + char_set.add_single(digraph(charT('`'))); + break; + case '\'': + char_set.add_single(digraph(charT('\''))); + char_set.add_single(digraph(charT(','))); + char_set.add_single(digraph(charT('#'))); + break; + case '<': + char_set.add_single(digraph(charT(';'))); + break; + case '>': + char_set.add_single(digraph(charT('\n'))); + char_set.add_single(digraph(charT('\f'))); + break; + default: + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + if(0 == this->append_set(char_set)) + { + fail(regex_constants::error_ctype, m_position - m_base); + return false; + } + ++m_position; + return true; +} + +template +regex_constants::syntax_option_type basic_regex_parser::parse_options() +{ + // we have a (?imsx-imsx) group, convert it into a set of flags: + regex_constants::syntax_option_type f = this->flags(); + bool breakout = false; + do + { + switch(*m_position) + { + case 's': + f |= regex_constants::mod_s; + f &= ~regex_constants::no_mod_s; + break; + case 'm': + f &= ~regex_constants::no_mod_m; + break; + case 'i': + f |= regex_constants::icase; + break; + case 'x': + f |= regex_constants::mod_x; + break; + default: + breakout = true; + continue; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + } + while(!breakout); + + breakout = false; + + if(*m_position == static_cast('-')) + { + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + do + { + switch(*m_position) + { + case 's': + f &= ~regex_constants::mod_s; + f |= regex_constants::no_mod_s; + break; + case 'm': + f |= regex_constants::no_mod_m; + break; + case 'i': + f &= ~regex_constants::icase; + break; + case 'x': + f &= ~regex_constants::mod_x; + break; + default: + breakout = true; + continue; + } + if(++m_position == m_end) + { + // Rewind to start of (? sequence: + --m_position; + while(this->m_traits.syntax_type(*m_position) != regex_constants::syntax_open_mark) --m_position; + fail(regex_constants::error_paren, m_position - m_base); + return false; + } + } + while(!breakout); + } + return f; +} + +template +bool basic_regex_parser::unwind_alts(std::ptrdiff_t last_paren_start) +{ + // + // If we didn't actually add any states after the last + // alternative then that's an error: + // + if((this->m_alt_insert_point == static_cast(this->m_pdata->m_data.size())) + && (!m_alt_jumps.empty()) && (m_alt_jumps.back() > last_paren_start) + && + !( + ((this->flags() & regbase::main_option_type) == regbase::perl_syntax_group) + && + ((this->flags() & regbase::no_empty_expressions) == 0) + ) + ) + { + fail(regex_constants::error_empty, this->m_position - this->m_base, "Can't terminate a sub-expression with an alternation operator |."); + return false; + } + // + // Fix up our alternatives: + // + while((!m_alt_jumps.empty()) && (m_alt_jumps.back() > last_paren_start)) + { + // + // fix up the jump to point to the end of the states + // that we've just added: + // + std::ptrdiff_t jump_offset = m_alt_jumps.back(); + m_alt_jumps.pop_back(); + this->m_pdata->m_data.align(); + re_jump* jmp = static_cast(this->getaddress(jump_offset)); + if (jmp->type != syntax_element_jump) + { + // Something really bad happened, this used to be an assert, + // but we'll make it an error just in case we should ever get here. + fail(regex_constants::error_unknown, this->m_position - this->m_base, "Internal logic failed while compiling the expression, probably you added a repeat to something non-repeatable!"); + return false; + } + jmp->alt.i = this->m_pdata->m_data.size() - jump_offset; + } + return true; +} + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/c_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/c_regex_traits.hpp new file mode 100644 index 0000000000..9de3463256 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/c_regex_traits.hpp @@ -0,0 +1,474 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE c_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class that wraps the global C locale. + */ + +#ifndef BOOST_C_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_C_REGEX_TRAITS_HPP_INCLUDED + +#include +#include +#include + +namespace boost{ + + namespace BOOST_REGEX_DETAIL_NS { + + enum + { + char_class_space = 1 << 0, + char_class_print = 1 << 1, + char_class_cntrl = 1 << 2, + char_class_upper = 1 << 3, + char_class_lower = 1 << 4, + char_class_alpha = 1 << 5, + char_class_digit = 1 << 6, + char_class_punct = 1 << 7, + char_class_xdigit = 1 << 8, + char_class_alnum = char_class_alpha | char_class_digit, + char_class_graph = char_class_alnum | char_class_punct, + char_class_blank = 1 << 9, + char_class_word = 1 << 10, + char_class_unicode = 1 << 11, + char_class_horizontal = 1 << 12, + char_class_vertical = 1 << 13 + }; + + } + +template +struct c_regex_traits; + +template<> +struct c_regex_traits +{ + c_regex_traits(){} + typedef char char_type; + typedef std::size_t size_type; + typedef std::string string_type; + struct locale_type{}; + typedef std::uint32_t char_class_type; + + static size_type length(const char_type* p) + { + return (std::strlen)(p); + } + + char translate(char c) const + { + return c; + } + char translate_nocase(char c) const + { + return static_cast((std::tolower)(static_cast(c))); + } + + static string_type transform(const char* p1, const char* p2); + static string_type transform_primary(const char* p1, const char* p2); + + static char_class_type lookup_classname(const char* p1, const char* p2); + static string_type lookup_collatename(const char* p1, const char* p2); + + static bool isctype(char, char_class_type); + static int value(char, int); + + locale_type imbue(locale_type l) + { return l; } + locale_type getloc()const + { return locale_type(); } + +private: + // this type is not copyable: + c_regex_traits(const c_regex_traits&); + c_regex_traits& operator=(const c_regex_traits&); +}; + +#ifndef BOOST_NO_WREGEX +template<> +struct c_regex_traits +{ + c_regex_traits(){} + typedef wchar_t char_type; + typedef std::size_t size_type; + typedef std::wstring string_type; + struct locale_type{}; + typedef std::uint32_t char_class_type; + + static size_type length(const char_type* p) + { + return (std::wcslen)(p); + } + + wchar_t translate(wchar_t c) const + { + return c; + } + wchar_t translate_nocase(wchar_t c) const + { + return (std::towlower)(c); + } + + static string_type transform(const wchar_t* p1, const wchar_t* p2); + static string_type transform_primary(const wchar_t* p1, const wchar_t* p2); + + static char_class_type lookup_classname(const wchar_t* p1, const wchar_t* p2); + static string_type lookup_collatename(const wchar_t* p1, const wchar_t* p2); + + static bool isctype(wchar_t, char_class_type); + static int value(wchar_t, int); + + locale_type imbue(locale_type l) + { return l; } + locale_type getloc()const + { return locale_type(); } + +private: + // this type is not copyable: + c_regex_traits(const c_regex_traits&); + c_regex_traits& operator=(const c_regex_traits&); +}; + +#endif // BOOST_NO_WREGEX + +inline c_regex_traits::string_type c_regex_traits::transform(const char* p1, const char* p2) +{ + std::string result(10, ' '); + std::size_t s = result.size(); + std::size_t r; + std::string src(p1, p2); + while (s < (r = std::strxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if (r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, ' '); + s = result.size(); + } + result.erase(r); + return result; +} + +inline c_regex_traits::string_type c_regex_traits::transform_primary(const char* p1, const char* p2) +{ + static char s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::string result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch (s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for (std::string::size_type i = 0; i < result.size(); ++i) + result[i] = static_cast((std::tolower)(static_cast(result[i]))); + result = transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = transform(p1, p2); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = transform(p1, p2); + if ((!result.empty()) && (result[0] == s_delim)) + break; + std::size_t i; + for (i = 0; i < result.size(); ++i) + { + if (result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if (result.empty()) + result = std::string(1, char(0)); + return result; +} + +inline c_regex_traits::char_class_type c_regex_traits::lookup_classname(const char* p1, const char* p2) +{ + using namespace BOOST_REGEX_DETAIL_NS; + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx < 0) + { + std::string s(p1, p2); + for (std::string::size_type i = 0; i < s.size(); ++i) + s[i] = static_cast((std::tolower)(static_cast(s[i]))); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_REGEX_ASSERT(std::size_t(idx) + 1u < sizeof(masks) / sizeof(masks[0])); + return masks[idx + 1]; +} + +inline bool c_regex_traits::isctype(char c, char_class_type mask) +{ + using namespace BOOST_REGEX_DETAIL_NS; + return + ((mask & char_class_space) && (std::isspace)(static_cast(c))) + || ((mask & char_class_print) && (std::isprint)(static_cast(c))) + || ((mask & char_class_cntrl) && (std::iscntrl)(static_cast(c))) + || ((mask & char_class_upper) && (std::isupper)(static_cast(c))) + || ((mask & char_class_lower) && (std::islower)(static_cast(c))) + || ((mask & char_class_alpha) && (std::isalpha)(static_cast(c))) + || ((mask & char_class_digit) && (std::isdigit)(static_cast(c))) + || ((mask & char_class_punct) && (std::ispunct)(static_cast(c))) + || ((mask & char_class_xdigit) && (std::isxdigit)(static_cast(c))) + || ((mask & char_class_blank) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + || ((mask & char_class_horizontal) && (std::isspace)(static_cast(c)) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != '\v')); +} + +inline c_regex_traits::string_type c_regex_traits::lookup_collatename(const char* p1, const char* p2) +{ + std::string s(p1, p2); + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); + if (s.empty() && (p2 - p1 == 1)) + s.append(1, *p1); + return s; +} + +inline int c_regex_traits::value(char c, int radix) +{ + char b[2] = { c, '\0', }; + char* ep; + int result = std::strtol(b, &ep, radix); + if (ep == b) + return -1; + return result; +} + +#ifndef BOOST_NO_WREGEX + +inline c_regex_traits::string_type c_regex_traits::transform(const wchar_t* p1, const wchar_t* p2) +{ + std::size_t r; + std::size_t s = 10; + std::wstring src(p1, p2); + std::wstring result(s, L' '); + while (s < (r = std::wcsxfrm(&*result.begin(), src.c_str(), s))) + { +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::strxfrm, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if (r == INT_MAX) + { + result.erase(); + result.insert(result.begin(), static_cast(0)); + return result; + } +#endif + result.append(r - s + 3, L' '); + s = result.size(); + } + result.erase(r); + return result; +} + +inline c_regex_traits::string_type c_regex_traits::transform_primary(const wchar_t* p1, const wchar_t* p2) +{ + static wchar_t s_delim; + static const int s_collate_type = ::boost::BOOST_REGEX_DETAIL_NS::find_sort_syntax(static_cast*>(0), &s_delim); + std::wstring result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch (s_collate_type) + { + case ::boost::BOOST_REGEX_DETAIL_NS::sort_C: + case ::boost::BOOST_REGEX_DETAIL_NS::sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + for (std::wstring::size_type i = 0; i < result.size(); ++i) + result[i] = (std::towlower)(result[i]); + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_fixed: + { + // get a regular sort key, and then truncate it: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + result.erase(s_delim); + break; + } + case ::boost::BOOST_REGEX_DETAIL_NS::sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result = c_regex_traits::transform(&*result.begin(), &*result.begin() + result.size()); + if ((!result.empty()) && (result[0] == s_delim)) + break; + std::size_t i; + for (i = 0; i < result.size(); ++i) + { + if (result[i] == s_delim) + break; + } + result.erase(i); + break; + } + if (result.empty()) + result = std::wstring(1, char(0)); + return result; +} + +inline c_regex_traits::char_class_type c_regex_traits::lookup_classname(const wchar_t* p1, const wchar_t* p2) +{ + using namespace BOOST_REGEX_DETAIL_NS; + static const char_class_type masks[] = + { + 0, + char_class_alnum, + char_class_alpha, + char_class_blank, + char_class_cntrl, + char_class_digit, + char_class_digit, + char_class_graph, + char_class_horizontal, + char_class_lower, + char_class_lower, + char_class_print, + char_class_punct, + char_class_space, + char_class_space, + char_class_upper, + char_class_unicode, + char_class_upper, + char_class_vertical, + char_class_alnum | char_class_word, + char_class_alnum | char_class_word, + char_class_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx < 0) + { + std::wstring s(p1, p2); + for (std::wstring::size_type i = 0; i < s.size(); ++i) + s[i] = (std::towlower)(s[i]); + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + } + BOOST_REGEX_ASSERT(idx + 1 < static_cast(sizeof(masks) / sizeof(masks[0]))); + return masks[idx + 1]; +} + +inline bool c_regex_traits::isctype(wchar_t c, char_class_type mask) +{ + using namespace BOOST_REGEX_DETAIL_NS; + return + ((mask & char_class_space) && (std::iswspace)(c)) + || ((mask & char_class_print) && (std::iswprint)(c)) + || ((mask & char_class_cntrl) && (std::iswcntrl)(c)) + || ((mask & char_class_upper) && (std::iswupper)(c)) + || ((mask & char_class_lower) && (std::iswlower)(c)) + || ((mask & char_class_alpha) && (std::iswalpha)(c)) + || ((mask & char_class_digit) && (std::iswdigit)(c)) + || ((mask & char_class_punct) && (std::iswpunct)(c)) + || ((mask & char_class_xdigit) && (std::iswxdigit)(c)) + || ((mask & char_class_blank) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c)) + || ((mask & char_class_word) && (c == '_')) + || ((mask & char_class_unicode) && (c & ~static_cast(0xff))) + || ((mask & char_class_vertical) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == L'\v'))) + || ((mask & char_class_horizontal) && (std::iswspace)(c) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && (c != L'\v')); +} + +inline c_regex_traits::string_type c_regex_traits::lookup_collatename(const wchar_t* p1, const wchar_t* p2) +{ + std::string name; + // Usual msvc warning suppression does not work here with std::string template constructor.... use a workaround instead: + for (const wchar_t* pos = p1; pos != p2; ++pos) + name.push_back((char)*pos); + name = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(name); + if (!name.empty()) + return string_type(name.begin(), name.end()); + if (p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +inline int c_regex_traits::value(wchar_t c, int radix) +{ +#ifdef BOOST_BORLANDC + // workaround for broken wcstol: + if ((std::iswxdigit)(c) == 0) + return -1; +#endif + wchar_t b[2] = { c, '\0', }; + wchar_t* ep; + int result = std::wcstol(b, &ep, radix); + if (ep == b) + return -1; + return result; +} + +#endif + +} + +#endif + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/char_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/char_regex_traits.hpp new file mode 100644 index 0000000000..aeed86f834 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/char_regex_traits.hpp @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE char_regex_traits.cpp + * VERSION see + * DESCRIPTION: Declares deprecated traits classes char_regex_traits<>. + */ + + +#ifndef BOOST_REGEX_V5_CHAR_REGEX_TRAITS_HPP +#define BOOST_REGEX_V5_CHAR_REGEX_TRAITS_HPP + +namespace boost{ + +namespace deprecated{ +// +// class char_regex_traits_i +// provides case insensitive traits classes (deprecated): +template +class char_regex_traits_i : public regex_traits {}; + +template<> +class char_regex_traits_i : public regex_traits +{ +public: + typedef char char_type; + typedef unsigned char uchar_type; + typedef unsigned int size_type; + typedef regex_traits base_type; + +}; + +#ifndef BOOST_NO_WREGEX +template<> +class char_regex_traits_i : public regex_traits +{ +public: + typedef wchar_t char_type; + typedef unsigned short uchar_type; + typedef unsigned int size_type; + typedef regex_traits base_type; + +}; +#endif +} // namespace deprecated +} // namespace boost + +#endif // include + diff --git a/third-party/boost_regex/include/boost/regex/v5/cpp_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/cpp_regex_traits.hpp new file mode 100644 index 0000000000..26b6f503d6 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/cpp_regex_traits.hpp @@ -0,0 +1,1040 @@ +/* + * + * Copyright (c) 2004 John Maddock + * Copyright 2011 Garmin Ltd. or its subsidiaries + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE cpp_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class cpp_regex_traits. + */ + +#ifndef BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_CPP_REGEX_TRAITS_HPP_INCLUDED + +#include +#include +#include +#include + +#include +#include + +#ifdef BOOST_HAS_THREADS +#include +#endif +#include +#include + +#include +#include +#include + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4786 4251) +#endif + +namespace boost{ + +// +// forward declaration is needed by some compilers: +// +template +class cpp_regex_traits; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// class parser_buf: +// acts as a stream buffer which wraps around a pair of pointers: +// +template > +class parser_buf : public ::std::basic_streambuf +{ + typedef ::std::basic_streambuf base_type; + typedef typename base_type::int_type int_type; + typedef typename base_type::char_type char_type; + typedef typename base_type::pos_type pos_type; + typedef ::std::streamsize streamsize; + typedef typename base_type::off_type off_type; +public: + parser_buf() : base_type() { setbuf(0, 0); } + const charT* getnext() { return this->gptr(); } +protected: + std::basic_streambuf* setbuf(char_type* s, streamsize n) override; + typename parser_buf::pos_type seekpos(pos_type sp, ::std::ios_base::openmode which) override; + typename parser_buf::pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) override; +private: + parser_buf& operator=(const parser_buf&); + parser_buf(const parser_buf&); +}; + +template +std::basic_streambuf* +parser_buf::setbuf(char_type* s, streamsize n) +{ + this->setg(s, s, s + n); + return this; +} + +template +typename parser_buf::pos_type +parser_buf::seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) +{ + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + std::ptrdiff_t size = this->egptr() - this->eback(); + std::ptrdiff_t pos = this->gptr() - this->eback(); + charT* g = this->eback(); + switch(static_cast(way)) + { + case ::std::ios_base::beg: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + off, g + size); + break; + case ::std::ios_base::end: + if((off < 0) || (off > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + size - off, g + size); + break; + case ::std::ios_base::cur: + { + std::ptrdiff_t newpos = static_cast(pos + off); + if((newpos < 0) || (newpos > size)) + return pos_type(off_type(-1)); + else + this->setg(g, g + newpos, g + size); + break; + } + default: ; + } +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4244) +#endif + return static_cast(this->gptr() - this->eback()); +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +typename parser_buf::pos_type +parser_buf::seekpos(pos_type sp, ::std::ios_base::openmode which) +{ + if(which & ::std::ios_base::out) + return pos_type(off_type(-1)); + off_type size = static_cast(this->egptr() - this->eback()); + charT* g = this->eback(); + if(off_type(sp) <= size) + { + this->setg(g, g + off_type(sp), g + size); + } + return pos_type(off_type(-1)); +} + +// +// class cpp_regex_traits_base: +// acts as a container for locale and the facets we are using. +// +template +struct cpp_regex_traits_base +{ + cpp_regex_traits_base(const std::locale& l) + { (void)imbue(l); } + std::locale imbue(const std::locale& l); + + std::locale m_locale; + std::ctype const* m_pctype; + std::messages const* m_pmessages; + std::collate const* m_pcollate; + + bool operator<(const cpp_regex_traits_base& b)const + { + if(m_pctype == b.m_pctype) + { + if(m_pmessages == b.m_pmessages) + { + return m_pcollate < b.m_pcollate; + } + return m_pmessages < b.m_pmessages; + } + return m_pctype < b.m_pctype; + } + bool operator==(const cpp_regex_traits_base& b)const + { + return (m_pctype == b.m_pctype) + && (m_pmessages == b.m_pmessages) + && (m_pcollate == b.m_pcollate); + } +}; + +template +std::locale cpp_regex_traits_base::imbue(const std::locale& l) +{ + std::locale result(m_locale); + m_locale = l; + m_pctype = &std::use_facet>(l); + m_pmessages = std::has_facet >(l) ? &std::use_facet >(l) : 0; + m_pcollate = &std::use_facet >(l); + return result; +} + +// +// class cpp_regex_traits_char_layer: +// implements methods that require specialization for narrow characters: +// +template +class cpp_regex_traits_char_layer : public cpp_regex_traits_base +{ + typedef std::basic_string string_type; + typedef std::map map_type; + typedef typename map_type::const_iterator map_iterator_type; +public: + cpp_regex_traits_char_layer(const std::locale& l) + : cpp_regex_traits_base(l) + { + init(); + } + cpp_regex_traits_char_layer(const cpp_regex_traits_base& b) + : cpp_regex_traits_base(b) + { + init(); + } + void init(); + + regex_constants::syntax_type syntax_type(charT c)const + { + map_iterator_type i = m_char_map.find(c); + return ((i == m_char_map.end()) ? 0 : i->second); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + map_iterator_type i = m_char_map.find(c); + if(i == m_char_map.end()) + { + if(this->m_pctype->is(std::ctype_base::lower, c)) return regex_constants::escape_type_class; + if(this->m_pctype->is(std::ctype_base::upper, c)) return regex_constants::escape_type_not_class; + return 0; + } + return i->second; + } + +private: + string_type get_default_message(regex_constants::syntax_type); + // TODO: use a hash table when available! + map_type m_char_map; +}; + +template +void cpp_regex_traits_char_layer::init() +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: +#ifndef __IBMCPP__ + typename std::messages::catalog cat = static_cast::catalog>(-1); +#else + typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if((!cat_name.empty()) && (this->m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if((int)cat >= 0) + { +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = this->m_pmessages->get(cat, 0, i, get_default_message(i)); + for(typename string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[mss[j]] = i; + } + } + this->m_pmessages->close(cat); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + if(this->m_pmessages) + this->m_pmessages->close(cat); + throw; + } +#endif + } + else + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while(ptr && *ptr) + { + m_char_map[this->m_pctype->widen(*ptr)] = i; + ++ptr; + } + } + } +} + +template +typename cpp_regex_traits_char_layer::string_type + cpp_regex_traits_char_layer::get_default_message(regex_constants::syntax_type i) +{ + const char* ptr = get_default_syntax(i); + string_type result; + while(ptr && *ptr) + { + result.append(1, this->m_pctype->widen(*ptr)); + ++ptr; + } + return result; +} + +// +// specialized version for narrow characters: +// +template <> +class cpp_regex_traits_char_layer : public cpp_regex_traits_base +{ + typedef std::string string_type; +public: + cpp_regex_traits_char_layer(const std::locale& l) + : cpp_regex_traits_base(l) + { + init(); + } + cpp_regex_traits_char_layer(const cpp_regex_traits_base& l) + : cpp_regex_traits_base(l) + { + init(); + } + + regex_constants::syntax_type syntax_type(char c)const + { + return m_char_map[static_cast(c)]; + } + regex_constants::escape_syntax_type escape_syntax_type(char c) const + { + return m_char_map[static_cast(c)]; + } + +private: + regex_constants::syntax_type m_char_map[1u << CHAR_BIT]; + void init(); +}; + +// +// class cpp_regex_traits_implementation: +// provides pimpl implementation for cpp_regex_traits. +// +template +class cpp_regex_traits_implementation : public cpp_regex_traits_char_layer +{ +public: + typedef typename cpp_regex_traits::char_class_type char_class_type; + typedef typename std::ctype::mask native_mask_type; + typedef typename std::make_unsigned::type unsigned_native_mask_type; + static const char_class_type mask_blank = 1u << 24; + static const char_class_type mask_word = 1u << 25; + static const char_class_type mask_unicode = 1u << 26; + static const char_class_type mask_horizontal = 1u << 27; + static const char_class_type mask_vertical = 1u << 28; + + typedef std::basic_string string_type; + typedef charT char_type; + //cpp_regex_traits_implementation(); + cpp_regex_traits_implementation(const std::locale& l) + : cpp_regex_traits_char_layer(l) + { + init(); + } + cpp_regex_traits_implementation(const cpp_regex_traits_base& l) + : cpp_regex_traits_char_layer(l) + { + init(); + } + std::string error_string(regex_constants::error_type n) const + { + if(!m_error_strings.empty()) + { + std::map::const_iterator p = m_error_strings.find(n); + return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second; + } + return get_default_error_string(n); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + char_class_type result = lookup_classname_imp(p1, p2); + if(result == 0) + { + string_type temp(p1, p2); + this->m_pctype->tolower(&*temp.begin(), &*temp.begin() + temp.size()); + result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size()); + } + return result; + } + string_type lookup_collatename(const charT* p1, const charT* p2) const; + string_type transform_primary(const charT* p1, const charT* p2) const; + string_type transform(const charT* p1, const charT* p2) const; +private: + std::map m_error_strings; // error messages indexed by numberic ID + std::map m_custom_class_names; // character class names + std::map m_custom_collate_names; // collating element names + unsigned m_collate_type; // the form of the collation string + charT m_collate_delim; // the collation group delimiter + // + // helpers: + // + char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const; + void init(); +}; + +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_blank; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_word; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_unicode; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_vertical; +template +typename cpp_regex_traits_implementation::char_class_type const cpp_regex_traits_implementation::mask_horizontal; + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::transform_primary(const charT* p1, const charT* p2) const +{ + // + // PRECONDITIONS: + // + // A bug in gcc 3.2 (and maybe other versions as well) treats + // p1 as a null terminated string, for efficiency reasons + // we work around this elsewhere, but just assert here that + // we adhere to gcc's (buggy) preconditions... + // + BOOST_REGEX_ASSERT(*p2 == 0); + string_type result; +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::collate::transform, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(*p1 == 0) + { + return string_type(1, charT(0)); + } +#endif + // + // swallowing all exceptions here is a bad idea + // however at least one std lib will always throw + // std::bad_alloc for certain arguments... + // +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(m_collate_type) + { + case sort_C: + case sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + this->m_pctype->tolower(&*result.begin(), &*result.begin() + result.size()); + result = this->m_pcollate->transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case sort_fixed: + { + // get a regular sort key, and then truncate it: + result.assign(this->m_pcollate->transform(p1, p2)); + result.erase(this->m_collate_delim); + break; + } + case sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result.assign(this->m_pcollate->transform(p1, p2)); + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == m_collate_delim) + break; + } + result.erase(i); + break; + } +#ifndef BOOST_NO_EXCEPTIONS + }catch(...){} +#endif + while((!result.empty()) && (charT(0) == *result.rbegin())) + result.erase(result.size() - 1); + if(result.empty()) + { + // character is ignorable at the primary level: + result = string_type(1, charT(0)); + } + return result; +} + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::transform(const charT* p1, const charT* p2) const +{ + // + // PRECONDITIONS: + // + // A bug in gcc 3.2 (and maybe other versions as well) treats + // p1 as a null terminated string, for efficiency reasons + // we work around this elsewhere, but just assert here that + // we adhere to gcc's (buggy) preconditions... + // + BOOST_REGEX_ASSERT(*p2 == 0); + // + // swallowing all exceptions here is a bad idea + // however at least one std lib will always throw + // std::bad_alloc for certain arguments... + // + string_type result, result2; +#if defined(_CPPLIB_VER) + // + // A bug in VC11 and 12 causes the program to hang if we pass a null-string + // to std::collate::transform, but only for certain locales :-( + // Probably effects Intel and Clang or any compiler using the VC std library (Dinkumware). + // + if(*p1 == 0) + { + return result; + } +#endif +#ifndef BOOST_NO_EXCEPTIONS + try{ +#endif + result = this->m_pcollate->transform(p1, p2); + // + // some implementations (Dinkumware) append unnecessary trailing \0's: + while((!result.empty()) && (charT(0) == *result.rbegin())) + result.erase(result.size() - 1); + // + // We may have NULL's used as separators between sections of the collate string, + // an example would be Boost.Locale. We have no way to detect this case via + // #defines since this can be used with any compiler/platform combination. + // Unfortunately our state machine (which was devised when all implementations + // used underlying C language API's) can't cope with that case. One workaround + // is to replace each character with 2, fortunately this code isn't used that + // much as this is now slower than before :-( + // + typedef typename std::make_unsigned::type uchar_type; + result2.reserve(result.size() * 2 + 2); + for(unsigned i = 0; i < result.size(); ++i) + { + if(static_cast(result[i]) == (std::numeric_limits::max)()) + { + result2.append(1, charT((std::numeric_limits::max)())).append(1, charT('b')); + } + else + { + result2.append(1, static_cast(1 + static_cast(result[i]))).append(1, charT('b') - 1); + } + } + BOOST_REGEX_ASSERT(std::find(result2.begin(), result2.end(), charT(0)) == result2.end()); +#ifndef BOOST_NO_EXCEPTIONS + } + catch(...) + { + } +#endif + return result2; +} + + +template +typename cpp_regex_traits_implementation::string_type + cpp_regex_traits_implementation::lookup_collatename(const charT* p1, const charT* p2) const +{ + typedef typename std::map::const_iterator iter_type; + if(!m_custom_collate_names.empty()) + { + iter_type pos = m_custom_collate_names.find(string_type(p1, p2)); + if(pos != m_custom_collate_names.end()) + return pos->second; + } + std::string name(p1, p2); + name = lookup_default_collate_name(name); + if(!name.empty()) + return string_type(name.begin(), name.end()); + if(p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +template +void cpp_regex_traits_implementation::init() +{ +#ifndef __IBMCPP__ + typename std::messages::catalog cat = static_cast::catalog>(-1); +#else + typename std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if((!cat_name.empty()) && (this->m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if((int)cat >= 0) + { + // + // Error messages: + // + for(boost::regex_constants::error_type i = static_cast(0); + i <= boost::regex_constants::error_unknown; + i = static_cast(i + 1)) + { + const char* p = get_default_error_string(i); + string_type default_message; + while(*p) + { + default_message.append(1, this->m_pctype->widen(*p)); + ++p; + } + string_type s = this->m_pmessages->get(cat, 0, i+200, default_message); + std::string result; + for(std::string::size_type j = 0; j < s.size(); ++j) + { + result.append(1, this->m_pctype->narrow(s[j], 0)); + } + m_error_strings[i] = result; + } + // + // Custom class names: + // + static const char_class_type masks[16] = + { + static_cast(std::ctype::alnum), + static_cast(std::ctype::alpha), + static_cast(std::ctype::cntrl), + static_cast(std::ctype::digit), + static_cast(std::ctype::graph), + cpp_regex_traits_implementation::mask_horizontal, + static_cast(std::ctype::lower), + static_cast(std::ctype::print), + static_cast(std::ctype::punct), + static_cast(std::ctype::space), + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_vertical, + static_cast(std::ctype::xdigit), + cpp_regex_traits_implementation::mask_blank, + cpp_regex_traits_implementation::mask_word, + cpp_regex_traits_implementation::mask_unicode, + }; + static const string_type null_string; + for(unsigned int j = 0; j <= 13; ++j) + { + string_type s(this->m_pmessages->get(cat, 0, j+300, null_string)); + if(!s.empty()) + this->m_custom_class_names[s] = masks[j]; + } + } + // + // get the collation format used by m_pcollate: + // + m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim); +} + +template +typename cpp_regex_traits_implementation::char_class_type + cpp_regex_traits_implementation::lookup_classname_imp(const charT* p1, const charT* p2) const +{ + static const char_class_type masks[22] = + { + 0, + static_cast(std::ctype::alnum), + static_cast(std::ctype::alpha), + cpp_regex_traits_implementation::mask_blank, + static_cast(std::ctype::cntrl), + static_cast(std::ctype::digit), + static_cast(std::ctype::digit), + static_cast(std::ctype::graph), + cpp_regex_traits_implementation::mask_horizontal, + static_cast(std::ctype::lower), + static_cast(std::ctype::lower), + static_cast(std::ctype::print), + static_cast(std::ctype::punct), + static_cast(std::ctype::space), + static_cast(std::ctype::space), + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_unicode, + static_cast(std::ctype::upper), + cpp_regex_traits_implementation::mask_vertical, + static_cast(std::ctype::alnum) | cpp_regex_traits_implementation::mask_word, + static_cast(std::ctype::alnum) | cpp_regex_traits_implementation::mask_word, + static_cast(std::ctype::xdigit), + }; + if(!m_custom_class_names.empty()) + { + typedef typename std::map, char_class_type>::const_iterator map_iter; + map_iter pos = m_custom_class_names.find(string_type(p1, p2)); + if(pos != m_custom_class_names.end()) + return pos->second; + } + std::size_t state_id = 1 + BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + BOOST_REGEX_ASSERT(state_id < sizeof(masks) / sizeof(masks[0])); + return masks[state_id]; +} + +template +inline std::shared_ptr > create_cpp_regex_traits(const std::locale& l) +{ + cpp_regex_traits_base key(l); + return ::boost::object_cache, cpp_regex_traits_implementation >::get(key, 5); +} + +} // BOOST_REGEX_DETAIL_NS + +template +class cpp_regex_traits +{ +private: + typedef std::ctype ctype_type; +public: + typedef charT char_type; + typedef std::size_t size_type; + typedef std::basic_string string_type; + typedef std::locale locale_type; + typedef std::uint_least32_t char_class_type; + + struct boost_extensions_tag{}; + + cpp_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::create_cpp_regex_traits(std::locale())) + { } + static size_type length(const char_type* p) + { + return std::char_traits::length(p); + } + regex_constants::syntax_type syntax_type(charT c)const + { + return m_pimpl->syntax_type(c); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + return m_pimpl->escape_syntax_type(c); + } + charT translate(charT c) const + { + return c; + } + charT translate_nocase(charT c) const + { + return m_pimpl->m_pctype->tolower(c); + } + charT translate(charT c, bool icase) const + { + return icase ? m_pimpl->m_pctype->tolower(c) : c; + } + charT tolower(charT c) const + { + return m_pimpl->m_pctype->tolower(c); + } + charT toupper(charT c) const + { + return m_pimpl->m_pctype->toupper(c); + } + string_type transform(const charT* p1, const charT* p2) const + { + return m_pimpl->transform(p1, p2); + } + string_type transform_primary(const charT* p1, const charT* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_classname(p1, p2); + } + string_type lookup_collatename(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_collatename(p1, p2); + } + bool isctype(charT c, char_class_type f) const + { + typedef typename std::ctype::mask ctype_mask; + + static const ctype_mask mask_base = + static_cast( + std::ctype::alnum + | std::ctype::alpha + | std::ctype::cntrl + | std::ctype::digit + | std::ctype::graph + | std::ctype::lower + | std::ctype::print + | std::ctype::punct + | std::ctype::space + | std::ctype::upper + | std::ctype::xdigit); + + if((f & mask_base) + && (m_pimpl->m_pctype->is( + static_cast(f & mask_base), c))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_word) && (c == '_')) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_blank) + && m_pimpl->m_pctype->is(std::ctype::space, c) + && !BOOST_REGEX_DETAIL_NS::is_separator(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_vertical) + && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_horizontal) + && this->isctype(c, std::ctype::space) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::cpp_regex_traits_implementation::mask_vertical)) + return true; +#ifdef __CYGWIN__ + // + // Cygwin has a buggy ctype facet, see https://www.cygwin.com/ml/cygwin/2012-08/msg00178.html: + // + else if((f & std::ctype::xdigit) == std::ctype::xdigit) + { + if((c >= 'a') && (c <= 'f')) + return true; + if((c >= 'A') && (c <= 'F')) + return true; + } +#endif + return false; + } + std::intmax_t toi(const charT*& p1, const charT* p2, int radix)const; + int value(charT c, int radix)const + { + const charT* pc = &c; + return (int)toi(pc, pc + 1, radix); + } + locale_type imbue(locale_type l) + { + std::locale result(getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::create_cpp_regex_traits(l); + return result; + } + locale_type getloc()const + { + return m_pimpl->m_locale; + } + std::string error_string(regex_constants::error_type n) const + { + return m_pimpl->error_string(n); + } + + // + // extension: + // set the name of the message catalog in use (defaults to "boost_regex"). + // + static std::string catalog_name(const std::string& name); + static std::string get_catalog_name(); + +private: + std::shared_ptr > m_pimpl; + // + // catalog name handler: + // + static std::string& get_catalog_name_inst(); + +#ifdef BOOST_HAS_THREADS + static std::mutex& get_mutex_inst(); +#endif +}; + + +template +std::intmax_t cpp_regex_traits::toi(const charT*& first, const charT* last, int radix)const +{ + BOOST_REGEX_DETAIL_NS::parser_buf sbuf; // buffer for parsing numbers. + std::basic_istream is(&sbuf); // stream for parsing numbers. + + // we do NOT want to parse any thousands separators inside the stream: + last = std::find(first, last, std::use_facet>(is.getloc()).thousands_sep()); + + sbuf.pubsetbuf(const_cast(static_cast(first)), static_cast(last-first)); + is.clear(); + if(std::abs(radix) == 16) is >> std::hex; + else if(std::abs(radix) == 8) is >> std::oct; + else is >> std::dec; + std::intmax_t val; + if(is >> val) + { + first = first + ((last - first) - sbuf.in_avail()); + return val; + } + else + return -1; +} + +template +std::string cpp_regex_traits::catalog_name(const std::string& name) +{ +#ifdef BOOST_HAS_THREADS + std::lock_guard lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + get_catalog_name_inst() = name; + return result; +} + +template +std::string& cpp_regex_traits::get_catalog_name_inst() +{ + static std::string s_name; + return s_name; +} + +template +std::string cpp_regex_traits::get_catalog_name() +{ +#ifdef BOOST_HAS_THREADS + std::lock_guard lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + return result; +} + +#ifdef BOOST_HAS_THREADS +template +std::mutex& cpp_regex_traits::get_mutex_inst() +{ + static std::mutex s_mutex; + return s_mutex; +} +#endif + +namespace BOOST_REGEX_DETAIL_NS { + + inline void cpp_regex_traits_char_layer::init() + { + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); +#ifndef __IBMCPP__ + std::messages::catalog cat = static_cast::catalog>(-1); +#else + std::messages::catalog cat = reinterpret_cast::catalog>(-1); +#endif + std::string cat_name(cpp_regex_traits::get_catalog_name()); + if ((!cat_name.empty()) && (m_pmessages != 0)) + { + cat = this->m_pmessages->open( + cat_name, + this->m_locale); + if ((int)cat < 0) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if ((int)cat >= 0) + { +#ifndef BOOST_NO_EXCEPTIONS + try { +#endif + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = this->m_pmessages->get(cat, 0, i, get_default_syntax(i)); + for (string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + this->m_pmessages->close(cat); +#ifndef BOOST_NO_EXCEPTIONS + } + catch (...) + { + this->m_pmessages->close(cat); + throw; + } +#endif + } + else + { + for (regex_constants::syntax_type j = 1; j < regex_constants::syntax_max; ++j) + { + const char* ptr = get_default_syntax(j); + while (ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = j; + ++ptr; + } + } + } + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if (m_char_map[i] == 0) + { + if (this->m_pctype->is(std::ctype_base::lower, i)) + m_char_map[i] = regex_constants::escape_type_class; + else if (this->m_pctype->is(std::ctype_base::upper, i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + } while (0xFF != i++); + } + +} // namespace detail + + +} // boost + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/cregex.hpp b/third-party/boost_regex/include/boost/regex/v5/cregex.hpp new file mode 100644 index 0000000000..a657105215 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/cregex.hpp @@ -0,0 +1,195 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE cregex.cpp + * VERSION see + * DESCRIPTION: Declares POSIX API functions + * + boost::RegEx high level wrapper. + */ + +#ifndef BOOST_RE_CREGEX_HPP_INCLUDED +#define BOOST_RE_CREGEX_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif +#include +#include + +#ifndef BOOST_REGEX_STANDALONE +#if !defined(BOOST_REGEX_NO_LIB) && !defined(BOOST_REGEX_SOURCE) && !defined(BOOST_ALL_NO_LIB) && defined(__cplusplus) +# define BOOST_LIB_NAME boost_regex +# if defined(BOOST_REGEX_DYN_LINK) || defined(BOOST_ALL_DYN_LINK) +# define BOOST_DYN_LINK +# endif +# ifdef BOOST_REGEX_DIAG +# define BOOST_LIB_DIAGNOSTIC +# endif +# include +#endif +#endif + +#ifdef __cplusplus +#include +#else +#include +#endif + +/* include these defs only for POSIX compatablity */ +#ifdef __cplusplus +namespace boost{ +extern "C" { +#endif + +#if defined(__cplusplus) +typedef std::ptrdiff_t regoff_t; +typedef std::size_t regsize_t; +#else +typedef ptrdiff_t regoff_t; +typedef size_t regsize_t; +#endif + +typedef struct +{ + unsigned int re_magic; +#ifdef __cplusplus + std::size_t re_nsub; /* number of parenthesized subexpressions */ +#else + size_t re_nsub; +#endif + const char* re_endp; /* end pointer for REG_PEND */ + void* guts; /* none of your business :-) */ + match_flag_type eflags; /* none of your business :-) */ +} regex_tA; + +#ifndef BOOST_NO_WREGEX +typedef struct +{ + unsigned int re_magic; +#ifdef __cplusplus + std::size_t re_nsub; /* number of parenthesized subexpressions */ +#else + size_t re_nsub; +#endif + const wchar_t* re_endp; /* end pointer for REG_PEND */ + void* guts; /* none of your business :-) */ + match_flag_type eflags; /* none of your business :-) */ +} regex_tW; +#endif + +typedef struct +{ + regoff_t rm_so; /* start of match */ + regoff_t rm_eo; /* end of match */ +} regmatch_t; + +/* regcomp() flags */ +typedef enum{ + REG_BASIC = 0000, + REG_EXTENDED = 0001, + REG_ICASE = 0002, + REG_NOSUB = 0004, + REG_NEWLINE = 0010, + REG_NOSPEC = 0020, + REG_PEND = 0040, + REG_DUMP = 0200, + REG_NOCOLLATE = 0400, + REG_ESCAPE_IN_LISTS = 01000, + REG_NEWLINE_ALT = 02000, + REG_PERLEX = 04000, + + REG_PERL = REG_EXTENDED | REG_NOCOLLATE | REG_ESCAPE_IN_LISTS | REG_PERLEX, + REG_AWK = REG_EXTENDED | REG_ESCAPE_IN_LISTS, + REG_GREP = REG_BASIC | REG_NEWLINE_ALT, + REG_EGREP = REG_EXTENDED | REG_NEWLINE_ALT, + + REG_ASSERT = 15, + REG_INVARG = 16, + REG_ATOI = 255, /* convert name to number (!) */ + REG_ITOA = 0400 /* convert number to name (!) */ +} reg_comp_flags; + +/* regexec() flags */ +typedef enum{ + REG_NOTBOL = 00001, + REG_NOTEOL = 00002, + REG_STARTEND = 00004 +} reg_exec_flags; + +/* + * POSIX error codes: + */ +typedef unsigned reg_error_t; +typedef reg_error_t reg_errcode_t; /* backwards compatibility */ + +static const reg_error_t REG_NOERROR = 0; /* Success. */ +static const reg_error_t REG_NOMATCH = 1; /* Didn't find a match (for regexec). */ + + /* POSIX regcomp return error codes. (In the order listed in the + standard.) */ +static const reg_error_t REG_BADPAT = 2; /* Invalid pattern. */ +static const reg_error_t REG_ECOLLATE = 3; /* Undefined collating element. */ +static const reg_error_t REG_ECTYPE = 4; /* Invalid character class name. */ +static const reg_error_t REG_EESCAPE = 5; /* Trailing backslash. */ +static const reg_error_t REG_ESUBREG = 6; /* Invalid back reference. */ +static const reg_error_t REG_EBRACK = 7; /* Unmatched left bracket. */ +static const reg_error_t REG_EPAREN = 8; /* Parenthesis imbalance. */ +static const reg_error_t REG_EBRACE = 9; /* Unmatched \{. */ +static const reg_error_t REG_BADBR = 10; /* Invalid contents of \{\}. */ +static const reg_error_t REG_ERANGE = 11; /* Invalid range end. */ +static const reg_error_t REG_ESPACE = 12; /* Ran out of memory. */ +static const reg_error_t REG_BADRPT = 13; /* No preceding re for repetition op. */ +static const reg_error_t REG_EEND = 14; /* unexpected end of expression */ +static const reg_error_t REG_ESIZE = 15; /* expression too big */ +static const reg_error_t REG_ERPAREN = 8; /* = REG_EPAREN : unmatched right parenthesis */ +static const reg_error_t REG_EMPTY = 17; /* empty expression */ +static const reg_error_t REG_E_MEMORY = 15; /* = REG_ESIZE : out of memory */ +static const reg_error_t REG_ECOMPLEXITY = 18; /* complexity too high */ +static const reg_error_t REG_ESTACK = 19; /* out of stack space */ +static const reg_error_t REG_E_PERL = 20; /* Perl (?...) error */ +static const reg_error_t REG_E_UNKNOWN = 21; /* unknown error */ +static const reg_error_t REG_ENOSYS = 21; /* = REG_E_UNKNOWN : Reserved. */ + +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompA(regex_tA*, const char*, int); +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorA(int, const regex_tA*, char*, regsize_t); +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecA(const regex_tA*, const char*, regsize_t, regmatch_t*, int); +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeA(regex_tA*); + +#ifndef BOOST_NO_WREGEX +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regcompW(regex_tW*, const wchar_t*, int); +BOOST_REGEX_DECL regsize_t BOOST_REGEX_CCALL regerrorW(int, const regex_tW*, wchar_t*, regsize_t); +BOOST_REGEX_DECL int BOOST_REGEX_CCALL regexecW(const regex_tW*, const wchar_t*, regsize_t, regmatch_t*, int); +BOOST_REGEX_DECL void BOOST_REGEX_CCALL regfreeW(regex_tW*); +#endif + +#ifdef UNICODE +#define regcomp regcompW +#define regerror regerrorW +#define regexec regexecW +#define regfree regfreeW +#define regex_t regex_tW +#else +#define regcomp regcompA +#define regerror regerrorA +#define regexec regexecA +#define regfree regfreeA +#define regex_t regex_tA +#endif + +#ifdef __cplusplus +} /* extern "C" */ +} /* namespace */ +#endif + +#endif /* include guard */ + diff --git a/third-party/boost_regex/include/boost/regex/v5/error_type.hpp b/third-party/boost_regex/include/boost/regex/v5/error_type.hpp new file mode 100644 index 0000000000..afcc71e3d8 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/error_type.hpp @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2003-2005 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE error_type.hpp + * VERSION see + * DESCRIPTION: Declares regular expression error type enumerator. + */ + +#ifndef BOOST_REGEX_ERROR_TYPE_HPP +#define BOOST_REGEX_ERROR_TYPE_HPP + +#ifdef __cplusplus +namespace boost{ +#endif + +#ifdef __cplusplus +namespace regex_constants{ + +enum error_type{ + + error_ok = 0, /* not used */ + error_no_match = 1, /* not used */ + error_bad_pattern = 2, + error_collate = 3, + error_ctype = 4, + error_escape = 5, + error_backref = 6, + error_brack = 7, + error_paren = 8, + error_brace = 9, + error_badbrace = 10, + error_range = 11, + error_space = 12, + error_badrepeat = 13, + error_end = 14, /* not used */ + error_size = 15, + error_right_paren = 16, /* not used */ + error_empty = 17, + error_complexity = 18, + error_stack = 19, + error_perl_extension = 20, + error_unknown = 21 +}; + +} +} +#endif /* __cplusplus */ + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/icu.hpp b/third-party/boost_regex/include/boost/regex/v5/icu.hpp new file mode 100644 index 0000000000..aefd97684a --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/icu.hpp @@ -0,0 +1,1402 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE icu.hpp + * VERSION see + * DESCRIPTION: Unicode regular expressions on top of the ICU Library. + */ + +#ifndef BOOST_REGEX_ICU_V5_HPP +#define BOOST_REGEX_ICU_V5_HPP + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_REGEX_MSVC +#pragma warning (push) +#pragma warning (disable: 4251) +#endif + +namespace boost{ + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// Implementation details: +// +class icu_regex_traits_implementation +{ + typedef UChar32 char_type; + typedef std::size_t size_type; + typedef std::vector string_type; + typedef U_NAMESPACE_QUALIFIER Locale locale_type; + typedef std::uint_least32_t char_class_type; +public: + icu_regex_traits_implementation(const U_NAMESPACE_QUALIFIER Locale& l) + : m_locale(l) + { + UErrorCode success = U_ZERO_ERROR; + m_collator.reset(U_NAMESPACE_QUALIFIER Collator::createInstance(l, success)); + if(U_SUCCESS(success) == 0) + init_error(); + m_collator->setStrength(U_NAMESPACE_QUALIFIER Collator::IDENTICAL); + success = U_ZERO_ERROR; + m_primary_collator.reset(U_NAMESPACE_QUALIFIER Collator::createInstance(l, success)); + if(U_SUCCESS(success) == 0) + init_error(); + m_primary_collator->setStrength(U_NAMESPACE_QUALIFIER Collator::PRIMARY); + } + U_NAMESPACE_QUALIFIER Locale getloc()const + { + return m_locale; + } + string_type do_transform(const char_type* p1, const char_type* p2, const U_NAMESPACE_QUALIFIER Collator* pcoll) const + { + // TODO make thread safe!!!! : + typedef u32_to_u16_iterator itt; + itt i(p1), j(p2); + std::vector< ::UChar> t(i, j); + std::uint8_t result[100]; + std::int32_t len; + if (!t.empty()) + len = pcoll->getSortKey(&*t.begin(), static_cast(t.size()), result, sizeof(result)); + else + len = pcoll->getSortKey(static_cast(0), static_cast(0), result, sizeof(result)); + if (std::size_t(len) > sizeof(result)) + { + std::unique_ptr< std::uint8_t[]> presult(new ::uint8_t[len + 1]); + if (!t.empty()) + len = pcoll->getSortKey(&*t.begin(), static_cast(t.size()), presult.get(), len + 1); + else + len = pcoll->getSortKey(static_cast(0), static_cast(0), presult.get(), len + 1); + if ((0 == presult[len - 1]) && (len > 1)) + --len; + return string_type(presult.get(), presult.get() + len); + } + if ((0 == result[len - 1]) && (len > 1)) + --len; + return string_type(result, result + len); + } + string_type transform(const char_type* p1, const char_type* p2) const + { + return do_transform(p1, p2, m_collator.get()); + } + string_type transform_primary(const char_type* p1, const char_type* p2) const + { + return do_transform(p1, p2, m_primary_collator.get()); + } +private: + void init_error() + { + std::runtime_error e("Could not initialize ICU resources"); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif + } + U_NAMESPACE_QUALIFIER Locale m_locale; // The ICU locale that we're using + std::unique_ptr< U_NAMESPACE_QUALIFIER Collator> m_collator; // The full collation object + std::unique_ptr< U_NAMESPACE_QUALIFIER Collator> m_primary_collator; // The primary collation object +}; +inline std::shared_ptr get_icu_regex_traits_implementation(const U_NAMESPACE_QUALIFIER Locale& loc) +{ + return std::shared_ptr(new icu_regex_traits_implementation(loc)); +} + +} + +class icu_regex_traits +{ +public: + typedef UChar32 char_type; + typedef std::size_t size_type; + typedef std::vector string_type; + typedef U_NAMESPACE_QUALIFIER Locale locale_type; + typedef std::uint64_t char_class_type; + + struct boost_extensions_tag{}; + + icu_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::get_icu_regex_traits_implementation(U_NAMESPACE_QUALIFIER Locale())) + { + } + static size_type length(const char_type* p) + { + size_type result = 0; + while (*p) + { + ++p; + ++result; + } + return result; + } + + ::boost::regex_constants::syntax_type syntax_type(char_type c)const + { + return ((c < 0x7f) && (c > 0)) ? BOOST_REGEX_DETAIL_NS::get_default_syntax_type(static_cast(c)) : regex_constants::syntax_char; + } + ::boost::regex_constants::escape_syntax_type escape_syntax_type(char_type c) const + { + return ((c < 0x7f) && (c > 0)) ? BOOST_REGEX_DETAIL_NS::get_default_escape_syntax_type(static_cast(c)) : regex_constants::syntax_char; + } + char_type translate(char_type c) const + { + return c; + } + char_type translate_nocase(char_type c) const + { + return ::u_foldCase(c, U_FOLD_CASE_DEFAULT); + } + char_type translate(char_type c, bool icase) const + { + return icase ? translate_nocase(c) : translate(c); + } + char_type tolower(char_type c) const + { + return ::u_tolower(c); + } + char_type toupper(char_type c) const + { + return ::u_toupper(c); + } + string_type transform(const char_type* p1, const char_type* p2) const + { + return m_pimpl->transform(p1, p2); + } + string_type transform_primary(const char_type* p1, const char_type* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const char_type* p1, const char_type* p2) const + { + constexpr char_class_type mask_blank = char_class_type(1) << offset_blank; + constexpr char_class_type mask_space = char_class_type(1) << offset_space; + constexpr char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + constexpr char_class_type mask_underscore = char_class_type(1) << offset_underscore; + constexpr char_class_type mask_unicode = char_class_type(1) << offset_unicode; + //constexpr char_class_type mask_any = char_class_type(1) << offset_any; + //constexpr char_class_type mask_ascii = char_class_type(1) << offset_ascii; + constexpr char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + constexpr char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + static const char_class_type masks[] = + { + 0, + U_GC_L_MASK | U_GC_ND_MASK, + U_GC_L_MASK, + mask_blank, + U_GC_CC_MASK | U_GC_CF_MASK | U_GC_ZL_MASK | U_GC_ZP_MASK, + U_GC_ND_MASK, + U_GC_ND_MASK, + (0x3FFFFFFFu) & ~(U_GC_CC_MASK | U_GC_CF_MASK | U_GC_CS_MASK | U_GC_CN_MASK | U_GC_Z_MASK), + mask_horizontal, + U_GC_LL_MASK, + U_GC_LL_MASK, + ~(U_GC_C_MASK), + U_GC_P_MASK, + char_class_type(U_GC_Z_MASK) | mask_space, + char_class_type(U_GC_Z_MASK) | mask_space, + U_GC_LU_MASK, + mask_unicode, + U_GC_LU_MASK, + mask_vertical, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_L_MASK | U_GC_ND_MASK | U_GC_MN_MASK) | mask_underscore, + char_class_type(U_GC_ND_MASK) | mask_xdigit, + }; + + int idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if (idx >= 0) + return masks[idx + 1]; + char_class_type result = lookup_icu_mask(p1, p2); + if (result != 0) + return result; + + if (idx < 0) + { + string_type s(p1, p2); + string_type::size_type i = 0; + while (i < s.size()) + { + s[i] = static_cast((::u_tolower)(s[i])); + if (::u_isspace(s[i]) || (s[i] == '-') || (s[i] == '_')) + s.erase(s.begin() + i, s.begin() + i + 1); + else + { + s[i] = static_cast((::u_tolower)(s[i])); + ++i; + } + } + if (!s.empty()) + idx = ::boost::BOOST_REGEX_DETAIL_NS::get_default_class_id(&*s.begin(), &*s.begin() + s.size()); + if (idx >= 0) + return masks[idx + 1]; + if (!s.empty()) + result = lookup_icu_mask(&*s.begin(), &*s.begin() + s.size()); + if (result != 0) + return result; + } + BOOST_REGEX_ASSERT(std::size_t(idx + 1) < sizeof(masks) / sizeof(masks[0])); + return masks[idx + 1]; + } + string_type lookup_collatename(const char_type* p1, const char_type* p2) const + { + string_type result; + if (std::find_if(p1, p2, std::bind(std::greater< ::UChar32>(), std::placeholders::_1, 0x7f)) == p2) + { + std::string s(p1, p2); + // Try Unicode name: + UErrorCode err = U_ZERO_ERROR; + UChar32 c = ::u_charFromName(U_UNICODE_CHAR_NAME, s.c_str(), &err); + if (U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // Try Unicode-extended name: + err = U_ZERO_ERROR; + c = ::u_charFromName(U_EXTENDED_CHAR_NAME, s.c_str(), &err); + if (U_SUCCESS(err)) + { + result.push_back(c); + return result; + } + // try POSIX name: + s = ::boost::BOOST_REGEX_DETAIL_NS::lookup_default_collate_name(s); + result.assign(s.begin(), s.end()); + } + if (result.empty() && (p2 - p1 == 1)) + result.push_back(*p1); + return result; + } + bool isctype(char_type c, char_class_type f) const + { + constexpr char_class_type mask_blank = char_class_type(1) << offset_blank; + constexpr char_class_type mask_space = char_class_type(1) << offset_space; + constexpr char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + constexpr char_class_type mask_underscore = char_class_type(1) << offset_underscore; + constexpr char_class_type mask_unicode = char_class_type(1) << offset_unicode; + constexpr char_class_type mask_any = char_class_type(1) << offset_any; + constexpr char_class_type mask_ascii = char_class_type(1) << offset_ascii; + constexpr char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + constexpr char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + // check for standard catagories first: + char_class_type m = char_class_type(static_cast(1) << u_charType(c)); + if ((m & f) != 0) + return true; + // now check for special cases: + if (((f & mask_blank) != 0) && u_isblank(c)) + return true; + if (((f & mask_space) != 0) && u_isspace(c)) + return true; + if (((f & mask_xdigit) != 0) && (u_digit(c, 16) >= 0)) + return true; + if (((f & mask_unicode) != 0) && (c >= 0x100)) + return true; + if (((f & mask_underscore) != 0) && (c == '_')) + return true; + if (((f & mask_any) != 0) && (c <= 0x10FFFF)) + return true; + if (((f & mask_ascii) != 0) && (c <= 0x7F)) + return true; + if (((f & mask_vertical) != 0) && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == static_cast('\v')) || (m == U_GC_ZL_MASK) || (m == U_GC_ZP_MASK))) + return true; + if (((f & mask_horizontal) != 0) && !::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) && u_isspace(c) && (c != static_cast('\v'))) + return true; + return false; + } + std::intmax_t toi(const char_type*& p1, const char_type* p2, int radix)const + { + return BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + int value(char_type c, int radix)const + { + return u_digit(c, static_cast< std::int8_t>(radix)); + } + locale_type imbue(locale_type l) + { + locale_type result(m_pimpl->getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::get_icu_regex_traits_implementation(l); + return result; + } + locale_type getloc()const + { + return locale_type(); + } + std::string error_string(::boost::regex_constants::error_type n) const + { + return BOOST_REGEX_DETAIL_NS::get_default_error_string(n); + } +private: + icu_regex_traits(const icu_regex_traits&); + icu_regex_traits& operator=(const icu_regex_traits&); + + // + // define the bitmasks offsets we need for additional character properties: + // + enum{ + offset_blank = U_CHAR_CATEGORY_COUNT, + offset_space = U_CHAR_CATEGORY_COUNT+1, + offset_xdigit = U_CHAR_CATEGORY_COUNT+2, + offset_underscore = U_CHAR_CATEGORY_COUNT+3, + offset_unicode = U_CHAR_CATEGORY_COUNT+4, + offset_any = U_CHAR_CATEGORY_COUNT+5, + offset_ascii = U_CHAR_CATEGORY_COUNT+6, + offset_horizontal = U_CHAR_CATEGORY_COUNT+7, + offset_vertical = U_CHAR_CATEGORY_COUNT+8 + }; + + static char_class_type lookup_icu_mask(const ::UChar32* p1, const ::UChar32* p2) + { + //constexpr char_class_type mask_blank = char_class_type(1) << offset_blank; + //constexpr char_class_type mask_space = char_class_type(1) << offset_space; + //constexpr char_class_type mask_xdigit = char_class_type(1) << offset_xdigit; + //constexpr char_class_type mask_underscore = char_class_type(1) << offset_underscore; + //constexpr char_class_type mask_unicode = char_class_type(1) << offset_unicode; + constexpr char_class_type mask_any = char_class_type(1) << offset_any; + constexpr char_class_type mask_ascii = char_class_type(1) << offset_ascii; + //constexpr char_class_type mask_horizontal = char_class_type(1) << offset_horizontal; + //constexpr char_class_type mask_vertical = char_class_type(1) << offset_vertical; + + static const ::UChar32 prop_name_table[] = { + /* any */ 'a', 'n', 'y', + /* ascii */ 'a', 's', 'c', 'i', 'i', + /* assigned */ 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* c* */ 'c', '*', + /* cc */ 'c', 'c', + /* cf */ 'c', 'f', + /* closepunctuation */ 'c', 'l', 'o', 's', 'e', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* cn */ 'c', 'n', + /* co */ 'c', 'o', + /* connectorpunctuation */ 'c', 'o', 'n', 'n', 'e', 'c', 't', 'o', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* control */ 'c', 'o', 'n', 't', 'r', 'o', 'l', + /* cs */ 'c', 's', + /* currencysymbol */ 'c', 'u', 'r', 'r', 'e', 'n', 'c', 'y', 's', 'y', 'm', 'b', 'o', 'l', + /* dashpunctuation */ 'd', 'a', 's', 'h', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* decimaldigitnumber */ 'd', 'e', 'c', 'i', 'm', 'a', 'l', 'd', 'i', 'g', 'i', 't', 'n', 'u', 'm', 'b', 'e', 'r', + /* enclosingmark */ 'e', 'n', 'c', 'l', 'o', 's', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* finalpunctuation */ 'f', 'i', 'n', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* format */ 'f', 'o', 'r', 'm', 'a', 't', + /* initialpunctuation */ 'i', 'n', 'i', 't', 'i', 'a', 'l', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* l* */ 'l', '*', + /* letter */ 'l', 'e', 't', 't', 'e', 'r', + /* letternumber */ 'l', 'e', 't', 't', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* lineseparator */ 'l', 'i', 'n', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* ll */ 'l', 'l', + /* lm */ 'l', 'm', + /* lo */ 'l', 'o', + /* lowercaseletter */ 'l', 'o', 'w', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* lt */ 'l', 't', + /* lu */ 'l', 'u', + /* m* */ 'm', '*', + /* mark */ 'm', 'a', 'r', 'k', + /* mathsymbol */ 'm', 'a', 't', 'h', 's', 'y', 'm', 'b', 'o', 'l', + /* mc */ 'm', 'c', + /* me */ 'm', 'e', + /* mn */ 'm', 'n', + /* modifierletter */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* modifiersymbol */ 'm', 'o', 'd', 'i', 'f', 'i', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* n* */ 'n', '*', + /* nd */ 'n', 'd', + /* nl */ 'n', 'l', + /* no */ 'n', 'o', + /* nonspacingmark */ 'n', 'o', 'n', 's', 'p', 'a', 'c', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* notassigned */ 'n', 'o', 't', 'a', 's', 's', 'i', 'g', 'n', 'e', 'd', + /* number */ 'n', 'u', 'm', 'b', 'e', 'r', + /* openpunctuation */ 'o', 'p', 'e', 'n', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* other */ 'o', 't', 'h', 'e', 'r', + /* otherletter */ 'o', 't', 'h', 'e', 'r', 'l', 'e', 't', 't', 'e', 'r', + /* othernumber */ 'o', 't', 'h', 'e', 'r', 'n', 'u', 'm', 'b', 'e', 'r', + /* otherpunctuation */ 'o', 't', 'h', 'e', 'r', 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* othersymbol */ 'o', 't', 'h', 'e', 'r', 's', 'y', 'm', 'b', 'o', 'l', + /* p* */ 'p', '*', + /* paragraphseparator */ 'p', 'a', 'r', 'a', 'g', 'r', 'a', 'p', 'h', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* pc */ 'p', 'c', + /* pd */ 'p', 'd', + /* pe */ 'p', 'e', + /* pf */ 'p', 'f', + /* pi */ 'p', 'i', + /* po */ 'p', 'o', + /* privateuse */ 'p', 'r', 'i', 'v', 'a', 't', 'e', 'u', 's', 'e', + /* ps */ 'p', 's', + /* punctuation */ 'p', 'u', 'n', 'c', 't', 'u', 'a', 't', 'i', 'o', 'n', + /* s* */ 's', '*', + /* sc */ 's', 'c', + /* separator */ 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* sk */ 's', 'k', + /* sm */ 's', 'm', + /* so */ 's', 'o', + /* spaceseparator */ 's', 'p', 'a', 'c', 'e', 's', 'e', 'p', 'a', 'r', 'a', 't', 'o', 'r', + /* spacingcombiningmark */ 's', 'p', 'a', 'c', 'i', 'n', 'g', 'c', 'o', 'm', 'b', 'i', 'n', 'i', 'n', 'g', 'm', 'a', 'r', 'k', + /* surrogate */ 's', 'u', 'r', 'r', 'o', 'g', 'a', 't', 'e', + /* symbol */ 's', 'y', 'm', 'b', 'o', 'l', + /* titlecase */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', + /* titlecaseletter */ 't', 'i', 't', 'l', 'e', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* uppercaseletter */ 'u', 'p', 'p', 'e', 'r', 'c', 'a', 's', 'e', 'l', 'e', 't', 't', 'e', 'r', + /* z* */ 'z', '*', + /* zl */ 'z', 'l', + /* zp */ 'z', 'p', + /* zs */ 'z', 's', + }; + + static const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> range_data[] = { + { prop_name_table + 0, prop_name_table + 3, }, // any + { prop_name_table + 3, prop_name_table + 8, }, // ascii + { prop_name_table + 8, prop_name_table + 16, }, // assigned + { prop_name_table + 16, prop_name_table + 18, }, // c* + { prop_name_table + 18, prop_name_table + 20, }, // cc + { prop_name_table + 20, prop_name_table + 22, }, // cf + { prop_name_table + 22, prop_name_table + 38, }, // closepunctuation + { prop_name_table + 38, prop_name_table + 40, }, // cn + { prop_name_table + 40, prop_name_table + 42, }, // co + { prop_name_table + 42, prop_name_table + 62, }, // connectorpunctuation + { prop_name_table + 62, prop_name_table + 69, }, // control + { prop_name_table + 69, prop_name_table + 71, }, // cs + { prop_name_table + 71, prop_name_table + 85, }, // currencysymbol + { prop_name_table + 85, prop_name_table + 100, }, // dashpunctuation + { prop_name_table + 100, prop_name_table + 118, }, // decimaldigitnumber + { prop_name_table + 118, prop_name_table + 131, }, // enclosingmark + { prop_name_table + 131, prop_name_table + 147, }, // finalpunctuation + { prop_name_table + 147, prop_name_table + 153, }, // format + { prop_name_table + 153, prop_name_table + 171, }, // initialpunctuation + { prop_name_table + 171, prop_name_table + 173, }, // l* + { prop_name_table + 173, prop_name_table + 179, }, // letter + { prop_name_table + 179, prop_name_table + 191, }, // letternumber + { prop_name_table + 191, prop_name_table + 204, }, // lineseparator + { prop_name_table + 204, prop_name_table + 206, }, // ll + { prop_name_table + 206, prop_name_table + 208, }, // lm + { prop_name_table + 208, prop_name_table + 210, }, // lo + { prop_name_table + 210, prop_name_table + 225, }, // lowercaseletter + { prop_name_table + 225, prop_name_table + 227, }, // lt + { prop_name_table + 227, prop_name_table + 229, }, // lu + { prop_name_table + 229, prop_name_table + 231, }, // m* + { prop_name_table + 231, prop_name_table + 235, }, // mark + { prop_name_table + 235, prop_name_table + 245, }, // mathsymbol + { prop_name_table + 245, prop_name_table + 247, }, // mc + { prop_name_table + 247, prop_name_table + 249, }, // me + { prop_name_table + 249, prop_name_table + 251, }, // mn + { prop_name_table + 251, prop_name_table + 265, }, // modifierletter + { prop_name_table + 265, prop_name_table + 279, }, // modifiersymbol + { prop_name_table + 279, prop_name_table + 281, }, // n* + { prop_name_table + 281, prop_name_table + 283, }, // nd + { prop_name_table + 283, prop_name_table + 285, }, // nl + { prop_name_table + 285, prop_name_table + 287, }, // no + { prop_name_table + 287, prop_name_table + 301, }, // nonspacingmark + { prop_name_table + 301, prop_name_table + 312, }, // notassigned + { prop_name_table + 312, prop_name_table + 318, }, // number + { prop_name_table + 318, prop_name_table + 333, }, // openpunctuation + { prop_name_table + 333, prop_name_table + 338, }, // other + { prop_name_table + 338, prop_name_table + 349, }, // otherletter + { prop_name_table + 349, prop_name_table + 360, }, // othernumber + { prop_name_table + 360, prop_name_table + 376, }, // otherpunctuation + { prop_name_table + 376, prop_name_table + 387, }, // othersymbol + { prop_name_table + 387, prop_name_table + 389, }, // p* + { prop_name_table + 389, prop_name_table + 407, }, // paragraphseparator + { prop_name_table + 407, prop_name_table + 409, }, // pc + { prop_name_table + 409, prop_name_table + 411, }, // pd + { prop_name_table + 411, prop_name_table + 413, }, // pe + { prop_name_table + 413, prop_name_table + 415, }, // pf + { prop_name_table + 415, prop_name_table + 417, }, // pi + { prop_name_table + 417, prop_name_table + 419, }, // po + { prop_name_table + 419, prop_name_table + 429, }, // privateuse + { prop_name_table + 429, prop_name_table + 431, }, // ps + { prop_name_table + 431, prop_name_table + 442, }, // punctuation + { prop_name_table + 442, prop_name_table + 444, }, // s* + { prop_name_table + 444, prop_name_table + 446, }, // sc + { prop_name_table + 446, prop_name_table + 455, }, // separator + { prop_name_table + 455, prop_name_table + 457, }, // sk + { prop_name_table + 457, prop_name_table + 459, }, // sm + { prop_name_table + 459, prop_name_table + 461, }, // so + { prop_name_table + 461, prop_name_table + 475, }, // spaceseparator + { prop_name_table + 475, prop_name_table + 495, }, // spacingcombiningmark + { prop_name_table + 495, prop_name_table + 504, }, // surrogate + { prop_name_table + 504, prop_name_table + 510, }, // symbol + { prop_name_table + 510, prop_name_table + 519, }, // titlecase + { prop_name_table + 519, prop_name_table + 534, }, // titlecaseletter + { prop_name_table + 534, prop_name_table + 549, }, // uppercaseletter + { prop_name_table + 549, prop_name_table + 551, }, // z* + { prop_name_table + 551, prop_name_table + 553, }, // zl + { prop_name_table + 553, prop_name_table + 555, }, // zp + { prop_name_table + 555, prop_name_table + 557, }, // zs + }; + + static const icu_regex_traits::char_class_type icu_class_map[] = { + mask_any, // any + mask_ascii, // ascii + (0x3FFFFFFFu) & ~(U_GC_CN_MASK), // assigned + U_GC_C_MASK, // c* + U_GC_CC_MASK, // cc + U_GC_CF_MASK, // cf + U_GC_PE_MASK, // closepunctuation + U_GC_CN_MASK, // cn + U_GC_CO_MASK, // co + U_GC_PC_MASK, // connectorpunctuation + U_GC_CC_MASK, // control + U_GC_CS_MASK, // cs + U_GC_SC_MASK, // currencysymbol + U_GC_PD_MASK, // dashpunctuation + U_GC_ND_MASK, // decimaldigitnumber + U_GC_ME_MASK, // enclosingmark + U_GC_PF_MASK, // finalpunctuation + U_GC_CF_MASK, // format + U_GC_PI_MASK, // initialpunctuation + U_GC_L_MASK, // l* + U_GC_L_MASK, // letter + U_GC_NL_MASK, // letternumber + U_GC_ZL_MASK, // lineseparator + U_GC_LL_MASK, // ll + U_GC_LM_MASK, // lm + U_GC_LO_MASK, // lo + U_GC_LL_MASK, // lowercaseletter + U_GC_LT_MASK, // lt + U_GC_LU_MASK, // lu + U_GC_M_MASK, // m* + U_GC_M_MASK, // mark + U_GC_SM_MASK, // mathsymbol + U_GC_MC_MASK, // mc + U_GC_ME_MASK, // me + U_GC_MN_MASK, // mn + U_GC_LM_MASK, // modifierletter + U_GC_SK_MASK, // modifiersymbol + U_GC_N_MASK, // n* + U_GC_ND_MASK, // nd + U_GC_NL_MASK, // nl + U_GC_NO_MASK, // no + U_GC_MN_MASK, // nonspacingmark + U_GC_CN_MASK, // notassigned + U_GC_N_MASK, // number + U_GC_PS_MASK, // openpunctuation + U_GC_C_MASK, // other + U_GC_LO_MASK, // otherletter + U_GC_NO_MASK, // othernumber + U_GC_PO_MASK, // otherpunctuation + U_GC_SO_MASK, // othersymbol + U_GC_P_MASK, // p* + U_GC_ZP_MASK, // paragraphseparator + U_GC_PC_MASK, // pc + U_GC_PD_MASK, // pd + U_GC_PE_MASK, // pe + U_GC_PF_MASK, // pf + U_GC_PI_MASK, // pi + U_GC_PO_MASK, // po + U_GC_CO_MASK, // privateuse + U_GC_PS_MASK, // ps + U_GC_P_MASK, // punctuation + U_GC_S_MASK, // s* + U_GC_SC_MASK, // sc + U_GC_Z_MASK, // separator + U_GC_SK_MASK, // sk + U_GC_SM_MASK, // sm + U_GC_SO_MASK, // so + U_GC_ZS_MASK, // spaceseparator + U_GC_MC_MASK, // spacingcombiningmark + U_GC_CS_MASK, // surrogate + U_GC_S_MASK, // symbol + U_GC_LT_MASK, // titlecase + U_GC_LT_MASK, // titlecaseletter + U_GC_LU_MASK, // uppercaseletter + U_GC_Z_MASK, // z* + U_GC_ZL_MASK, // zl + U_GC_ZP_MASK, // zp + U_GC_ZS_MASK, // zs + }; + + + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_begin = range_data; + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* ranges_end = range_data + (sizeof(range_data) / sizeof(range_data[0])); + + BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32> t = { p1, p2, }; + const BOOST_REGEX_DETAIL_NS::character_pointer_range< ::UChar32>* p = std::lower_bound(ranges_begin, ranges_end, t); + if ((p != ranges_end) && (t == *p)) + return icu_class_map[p - ranges_begin]; + return 0; + } + std::shared_ptr< ::boost::BOOST_REGEX_DETAIL_NS::icu_regex_traits_implementation> m_pimpl; +}; + +} // namespace boost + +namespace boost{ + +// types: +typedef basic_regex< ::UChar32, icu_regex_traits> u32regex; +typedef match_results u32match; +typedef match_results u16match; + +// +// Construction of 32-bit regex types from UTF-8 and UTF-16 primitives: +// +namespace BOOST_REGEX_DETAIL_NS{ + +template +inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const std::integral_constant*) +{ + typedef boost::u8_to_u32_iterator conv_type; + return u32regex(conv_type(i, i, j), conv_type(j, i, j), opt); +} + +template +inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const std::integral_constant*) +{ + typedef boost::u16_to_u32_iterator conv_type; + return u32regex(conv_type(i, i, j), conv_type(j, i, j), opt); +} + +template +inline u32regex do_make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt, + const std::integral_constant*) +{ + return u32regex(i, j, opt); +} +} + +// BOOST_REGEX_UCHAR_IS_WCHAR_T +// +// Source inspection of unicode/umachine.h in ICU version 59 indicates that: +// +// On version 59, UChar is always char16_t in C++ mode (and uint16_t in C mode) +// +// On earlier versions, the logic is +// +// #if U_SIZEOF_WCHAR_T==2 +// typedef wchar_t OldUChar; +// #elif defined(__CHAR16_TYPE__) +// typedef __CHAR16_TYPE__ OldUChar; +// #else +// typedef uint16_t OldUChar; +// #endif +// +// That is, UChar is wchar_t only on versions below 59, when U_SIZEOF_WCHAR_T==2 +// +// Hence, + +#define BOOST_REGEX_UCHAR_IS_WCHAR_T (U_ICU_VERSION_MAJOR_NUM < 59 && U_SIZEOF_WCHAR_T == 2) + +#if BOOST_REGEX_UCHAR_IS_WCHAR_T + static_assert((std::is_same::value), "Configuration logic has failed!"); +#else + static_assert(!(std::is_same::value), "Configuration logic has failed!"); +#endif + +// +// Construction from an iterator pair: +// +template +inline u32regex make_u32regex(InputIterator i, + InputIterator j, + boost::regex_constants::syntax_option_type opt) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(i, j, opt, static_cast const*>(0)); +} +// +// construction from UTF-8 nul-terminated strings: +// +inline u32regex make_u32regex(const char* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::strlen(p), opt, static_cast const*>(0)); +} +inline u32regex make_u32regex(const unsigned char* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::strlen(reinterpret_cast(p)), opt, static_cast const*>(0)); +} +// +// construction from UTF-16 nul-terminated strings: +// +#ifndef BOOST_NO_WREGEX +inline u32regex make_u32regex(const wchar_t* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + std::wcslen(p), opt, static_cast const*>(0)); +} +#endif +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T +inline u32regex make_u32regex(const UChar* p, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(p, p + u_strlen(p), opt, static_cast const*>(0)); +} +#endif +// +// construction from basic_string class-template: +// +template +inline u32regex make_u32regex(const std::basic_string& s, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(s.begin(), s.end(), opt, static_cast const*>(0)); +} +// +// Construction from ICU string type: +// +inline u32regex make_u32regex(const U_NAMESPACE_QUALIFIER UnicodeString& s, boost::regex_constants::syntax_option_type opt = boost::regex_constants::perl) +{ + return BOOST_REGEX_DETAIL_NS::do_make_u32regex(s.getBuffer(), s.getBuffer() + s.length(), opt, static_cast const*>(0)); +} + +// +// regex_match overloads that widen the character type as appropriate: +// +namespace BOOST_REGEX_DETAIL_NS{ +template +void copy_results(MR1& out, MR2 const& in, NSubs named_subs) +{ + // copy results from an adapted MR2 match_results: + out.set_size(in.size(), in.prefix().first.base(), in.suffix().second.base()); + out.set_base(in.base().base()); + out.set_named_subs(named_subs); + for(int i = 0; i < (int)in.size(); ++i) + { + if(in[i].matched || !i) + { + out.set_first(in[i].first.base(), i); + out.set_second(in[i].second.base(), i, in[i].matched); + } + } +#ifdef BOOST_REGEX_MATCH_EXTRA + // Copy full capture info as well: + for(int i = 0; i < (int)in.size(); ++i) + { + if(in[i].captures().size()) + { + out[i].get_captures().assign(in[i].captures().size(), typename MR1::value_type()); + for(int j = 0; j < (int)out[i].captures().size(); ++j) + { + out[i].get_captures()[j].first = in[i].captures()[j].first.base(); + out[i].get_captures()[j].second = in[i].captures()[j].second.base(); + out[i].get_captures()[j].matched = in[i].captures()[j].matched; + } + } + } +#endif +} + +template +inline bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + std::integral_constant const*) +{ + return ::boost::regex_match(first, last, m, e, flags); +} +template +bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + std::integral_constant const*) +{ + typedef u16_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_match(conv_type(first, first, last), conv_type(last, first, last), what, e, flags); + // copy results across to m: + if(result) copy_results(m, what, e.get_named_subs()); + return result; +} +template +bool do_regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + std::integral_constant const*) +{ + typedef u8_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_match(conv_type(first, first, last), conv_type(last, first, last), what, e, flags); + // copy results across to m: + if(result) copy_results(m, what, e.get_named_subs()); + return result; +} +} // namespace BOOST_REGEX_DETAIL_NS + +template +inline bool u32regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(first, last, m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const UChar* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+u_strlen(p), m, e, flags, static_cast const*>(0)); +} +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) +inline bool u32regex_match(const wchar_t* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::wcslen(p), m, e, flags, static_cast const*>(0)); +} +#endif +inline bool u32regex_match(const char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::strlen(p), m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const unsigned char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::strlen((const char*)p), m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const std::string& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); +} +#ifndef BOOST_NO_STD_WSTRING +inline bool u32regex_match(const std::wstring& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); +} +#endif +inline bool u32regex_match(const U_NAMESPACE_QUALIFIER UnicodeString& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, static_cast const*>(0)); +} +// +// regex_match overloads that do not return what matched: +// +template +inline bool u32regex_match(BidiIterator first, BidiIterator last, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(first, last, m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const UChar* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+u_strlen(p), m, e, flags, static_cast const*>(0)); +} +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) +inline bool u32regex_match(const wchar_t* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::wcslen(p), m, e, flags, static_cast const*>(0)); +} +#endif +inline bool u32regex_match(const char* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::strlen(p), m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const unsigned char* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(p, p+std::strlen((const char*)p), m, e, flags, static_cast const*>(0)); +} +inline bool u32regex_match(const std::string& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); +} +#ifndef BOOST_NO_STD_WSTRING +inline bool u32regex_match(const std::wstring& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.begin(), s.end(), m, e, flags, static_cast const*>(0)); +} +#endif +inline bool u32regex_match(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_match(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, static_cast const*>(0)); +} + +// +// regex_search overloads that widen the character type as appropriate: +// +namespace BOOST_REGEX_DETAIL_NS{ +template +inline bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + std::integral_constant const*) +{ + return ::boost::regex_search(first, last, m, e, flags, base); +} +template +bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + std::integral_constant const*) +{ + typedef u16_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_search(conv_type(first, first, last), conv_type(last, first, last), what, e, flags, conv_type(base)); + // copy results across to m: + if(result) copy_results(m, what, e.get_named_subs()); + return result; +} +template +bool do_regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base, + std::integral_constant const*) +{ + typedef u8_to_u32_iterator conv_type; + typedef match_results match_type; + //typedef typename match_type::allocator_type alloc_type; + match_type what; + bool result = ::boost::regex_search(conv_type(first, first, last), conv_type(last, first, last), what, e, flags, conv_type(base)); + // copy results across to m: + if(result) copy_results(m, what, e.get_named_subs()); + return result; +} +} + +template +inline bool u32regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, first, static_cast const*>(0)); +} +template +inline bool u32regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const u32regex& e, + match_flag_type flags, + BidiIterator base) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, base, static_cast const*>(0)); +} +inline bool u32regex_search(const UChar* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+u_strlen(p), m, e, flags, p, static_cast const*>(0)); +} +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) +inline bool u32regex_search(const wchar_t* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::wcslen(p), m, e, flags, p, static_cast const*>(0)); +} +#endif +inline bool u32regex_search(const char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::strlen(p), m, e, flags, p, static_cast const*>(0)); +} +inline bool u32regex_search(const unsigned char* p, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::strlen((const char*)p), m, e, flags, p, static_cast const*>(0)); +} +inline bool u32regex_search(const std::string& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); +} +#ifndef BOOST_NO_STD_WSTRING +inline bool u32regex_search(const std::wstring& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); +} +#endif +inline bool u32regex_search(const U_NAMESPACE_QUALIFIER UnicodeString& s, + match_results& m, + const u32regex& e, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, s.getBuffer(), static_cast const*>(0)); +} +template +inline bool u32regex_search(BidiIterator first, BidiIterator last, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(first, last, m, e, flags, first, static_cast const*>(0)); +} +inline bool u32regex_search(const UChar* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+u_strlen(p), m, e, flags, p, static_cast const*>(0)); +} +#if !BOOST_REGEX_UCHAR_IS_WCHAR_T && !defined(BOOST_NO_WREGEX) +inline bool u32regex_search(const wchar_t* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::wcslen(p), m, e, flags, p, static_cast const*>(0)); +} +#endif +inline bool u32regex_search(const char* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::strlen(p), m, e, flags, p, static_cast const*>(0)); +} +inline bool u32regex_search(const unsigned char* p, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(p, p+std::strlen((const char*)p), m, e, flags, p, static_cast const*>(0)); +} +inline bool u32regex_search(const std::string& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); +} +#ifndef BOOST_NO_STD_WSTRING +inline bool u32regex_search(const std::wstring& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.begin(), s.end(), m, e, flags, s.begin(), static_cast const*>(0)); +} +#endif +inline bool u32regex_search(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return BOOST_REGEX_DETAIL_NS::do_regex_search(s.getBuffer(), s.getBuffer() + s.length(), m, e, flags, s.getBuffer(), static_cast const*>(0)); +} + +// +// overloads for regex_replace with utf-8 and utf-16 data types: +// +namespace BOOST_REGEX_DETAIL_NS{ +template +inline std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator > + make_utf32_seq(I i, I j, std::integral_constant const*) +{ + return std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator >(boost::u8_to_u32_iterator(i, i, j), boost::u8_to_u32_iterator(j, i, j)); +} +template +inline std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator > + make_utf32_seq(I i, I j, std::integral_constant const*) +{ + return std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator >(boost::u16_to_u32_iterator(i, i, j), boost::u16_to_u32_iterator(j, i, j)); +} +template +inline std::pair< I, I > + make_utf32_seq(I i, I j, std::integral_constant const*) +{ + return std::pair< I, I >(i, j); +} +template +inline std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator > + make_utf32_seq(const charT* p, std::integral_constant const*) +{ + std::size_t len = std::strlen((const char*)p); + return std::pair< boost::u8_to_u32_iterator, boost::u8_to_u32_iterator >(boost::u8_to_u32_iterator(p, p, p+len), boost::u8_to_u32_iterator(p+len, p, p+len)); +} +template +inline std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator > + make_utf32_seq(const charT* p, std::integral_constant const*) +{ + std::size_t len = u_strlen((const UChar*)p); + return std::pair< boost::u16_to_u32_iterator, boost::u16_to_u32_iterator >(boost::u16_to_u32_iterator(p, p, p + len), boost::u16_to_u32_iterator(p+len, p, p + len)); +} +template +inline std::pair< const charT*, const charT* > + make_utf32_seq(const charT* p, std::integral_constant const*) +{ + return std::pair< const charT*, const charT* >(p, p+icu_regex_traits::length((UChar32 const*)p)); +} +template +inline OutputIterator make_utf32_out(OutputIterator o, std::integral_constant const*) +{ + return o; +} +template +inline utf16_output_iterator make_utf32_out(OutputIterator o, std::integral_constant const*) +{ + return o; +} +template +inline utf8_output_iterator make_utf32_out(OutputIterator o, std::integral_constant const*) +{ + return o; +} + +template +OutputIterator do_regex_replace(OutputIterator out, + std::pair const& in, + const u32regex& e, + const std::pair& fmt, + match_flag_type flags + ) +{ + // unfortunately we have to copy the format string in order to pass in onward: + std::vector f; + f.assign(fmt.first, fmt.second); + + regex_iterator i(in.first, in.second, e, flags); + regex_iterator j; + if(i == j) + { + if(!(flags & regex_constants::format_no_copy)) + out = std::copy(in.first, in.second, out); + } + else + { + I1 last_m = in.first; + while(i != j) + { + if(!(flags & regex_constants::format_no_copy)) + out = std::copy(i->prefix().first, i->prefix().second, out); + if(!f.empty()) + out = ::boost::BOOST_REGEX_DETAIL_NS::regex_format_imp(out, *i, &*f.begin(), &*f.begin() + f.size(), flags, e.get_traits()); + else + out = ::boost::BOOST_REGEX_DETAIL_NS::regex_format_imp(out, *i, static_cast(0), static_cast(0), flags, e.get_traits()); + last_m = (*i)[0].second; + if(flags & regex_constants::format_first_only) + break; + ++i; + } + if(!(flags & regex_constants::format_no_copy)) + out = std::copy(last_m, in.second, out); + } + return out; +} +template +inline const BaseIterator& extract_output_base(const BaseIterator& b) +{ + return b; +} +template +inline BaseIterator extract_output_base(const utf8_output_iterator& b) +{ + return b.base(); +} +template +inline BaseIterator extract_output_base(const utf16_output_iterator& b) +{ + return b.base(); +} +} // BOOST_REGEX_DETAIL_NS + +template +inline OutputIterator u32regex_replace(OutputIterator out, + BidirectionalIterator first, + BidirectionalIterator last, + const u32regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt, static_cast const*>(0)), + flags) + ); +} + +template +inline OutputIterator u32regex_replace(OutputIterator out, + Iterator first, + Iterator last, + const u32regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.begin(), fmt.end(), static_cast const*>(0)), + flags) + ); +} + +template +inline OutputIterator u32regex_replace(OutputIterator out, + Iterator first, + Iterator last, + const u32regex& e, + const U_NAMESPACE_QUALIFIER UnicodeString& fmt, + match_flag_type flags = match_default) +{ + return BOOST_REGEX_DETAIL_NS::extract_output_base + ( + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(out, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(first, last, static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.getBuffer(), fmt.getBuffer() + fmt.length(), static_cast const*>(0)), + flags) + ); +} + +template +std::basic_string u32regex_replace(const std::basic_string& s, + const u32regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + u32regex_replace(i, s.begin(), s.end(), e, fmt, flags); + return result; +} + +template +std::basic_string u32regex_replace(const std::basic_string& s, + const u32regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + u32regex_replace(i, s.begin(), s.end(), e, fmt.c_str(), flags); + return result; +} + +namespace BOOST_REGEX_DETAIL_NS{ + +class unicode_string_out_iterator +{ + U_NAMESPACE_QUALIFIER UnicodeString* out; +public: + unicode_string_out_iterator(U_NAMESPACE_QUALIFIER UnicodeString& s) : out(&s) {} + unicode_string_out_iterator& operator++() { return *this; } + unicode_string_out_iterator& operator++(int) { return *this; } + unicode_string_out_iterator& operator*() { return *this; } + unicode_string_out_iterator& operator=(UChar v) + { + *out += v; + return *this; + } + typedef std::ptrdiff_t difference_type; + typedef UChar value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::output_iterator_tag iterator_category; +}; + +} + +inline U_NAMESPACE_QUALIFIER UnicodeString u32regex_replace(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + const UChar* fmt, + match_flag_type flags = match_default) +{ + U_NAMESPACE_QUALIFIER UnicodeString result; + BOOST_REGEX_DETAIL_NS::unicode_string_out_iterator i(result); + u32regex_replace(i, s.getBuffer(), s.getBuffer()+s.length(), e, fmt, flags); + return result; +} + +inline U_NAMESPACE_QUALIFIER UnicodeString u32regex_replace(const U_NAMESPACE_QUALIFIER UnicodeString& s, + const u32regex& e, + const U_NAMESPACE_QUALIFIER UnicodeString& fmt, + match_flag_type flags = match_default) +{ + U_NAMESPACE_QUALIFIER UnicodeString result; + BOOST_REGEX_DETAIL_NS::unicode_string_out_iterator i(result); + BOOST_REGEX_DETAIL_NS::do_regex_replace( + BOOST_REGEX_DETAIL_NS::make_utf32_out(i, static_cast const*>(0)), + BOOST_REGEX_DETAIL_NS::make_utf32_seq(s.getBuffer(), s.getBuffer()+s.length(), static_cast const*>(0)), + e, + BOOST_REGEX_DETAIL_NS::make_utf32_seq(fmt.getBuffer(), fmt.getBuffer() + fmt.length(), static_cast const*>(0)), + flags); + return result; +} + +} // namespace boost. + +#ifdef BOOST_REGEX_MSVC +#pragma warning (pop) +#endif + +#include +#include + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/iterator_category.hpp b/third-party/boost_regex/include/boost/regex/v5/iterator_category.hpp new file mode 100644 index 0000000000..9bd745781c --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/iterator_category.hpp @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_match.hpp + * VERSION see + * DESCRIPTION: Iterator traits for selecting an iterator type as + * an integral constant expression. + */ + + +#ifndef BOOST_REGEX_ITERATOR_CATEGORY_HPP +#define BOOST_REGEX_ITERATOR_CATEGORY_HPP + +#include +#include + +namespace boost{ +namespace detail{ + +template +struct is_random_imp +{ +private: + typedef typename std::iterator_traits::iterator_category cat; +public: + static const bool value = (std::is_convertible::value); +}; + +template +struct is_random_pointer_imp +{ + static const bool value = true; +}; + +template +struct is_random_imp_selector +{ + template + struct rebind + { + typedef is_random_imp type; + }; +}; + +template <> +struct is_random_imp_selector +{ + template + struct rebind + { + typedef is_random_pointer_imp type; + }; +}; + +} + +template +struct is_random_access_iterator +{ +private: + typedef detail::is_random_imp_selector< std::is_pointer::value> selector; + typedef typename selector::template rebind bound_type; + typedef typename bound_type::type answer; +public: + static const bool value = answer::value; +}; + +template +const bool is_random_access_iterator::value; + +} + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/iterator_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/iterator_traits.hpp new file mode 100644 index 0000000000..293db6bf8c --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/iterator_traits.hpp @@ -0,0 +1,32 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE iterator_traits.cpp + * VERSION see + * DESCRIPTION: Declares iterator traits workarounds. + */ + +#ifndef BOOST_REGEX_V5_ITERATOR_TRAITS_HPP +#define BOOST_REGEX_V5_ITERATOR_TRAITS_HPP + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +template +struct regex_iterator_traits : public std::iterator_traits {}; + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/match_flags.hpp b/third-party/boost_regex/include/boost/regex/v5/match_flags.hpp new file mode 100644 index 0000000000..6ff236b041 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/match_flags.hpp @@ -0,0 +1,156 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE match_flags.hpp + * VERSION see + * DESCRIPTION: Declares match_flags type. + */ + +#ifndef BOOST_REGEX_V5_MATCH_FLAGS +#define BOOST_REGEX_V5_MATCH_FLAGS + +#ifdef __cplusplus +# include +#endif + +#ifdef __cplusplus +namespace boost{ + namespace regex_constants{ +#endif + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable : 26812) +#endif +#endif + +typedef enum _match_flags +{ + match_default = 0, + match_not_bol = 1, /* first is not start of line */ + match_not_eol = match_not_bol << 1, /* last is not end of line */ + match_not_bob = match_not_eol << 1, /* first is not start of buffer */ + match_not_eob = match_not_bob << 1, /* last is not end of buffer */ + match_not_bow = match_not_eob << 1, /* first is not start of word */ + match_not_eow = match_not_bow << 1, /* last is not end of word */ + match_not_dot_newline = match_not_eow << 1, /* \n is not matched by '.' */ + match_not_dot_null = match_not_dot_newline << 1, /* '\0' is not matched by '.' */ + match_prev_avail = match_not_dot_null << 1, /* *--first is a valid expression */ + match_init = match_prev_avail << 1, /* internal use */ + match_any = match_init << 1, /* don't care what we match */ + match_not_null = match_any << 1, /* string can't be null */ + match_continuous = match_not_null << 1, /* each grep match must continue from */ + /* uninterrupted from the previous one */ + match_partial = match_continuous << 1, /* find partial matches */ + + match_stop = match_partial << 1, /* stop after first match (grep) V3 only */ + match_not_initial_null = match_stop, /* don't match initial null, V4 only */ + match_all = match_stop << 1, /* must find the whole of input even if match_any is set */ + match_perl = match_all << 1, /* Use perl matching rules */ + match_posix = match_perl << 1, /* Use POSIX matching rules */ + match_nosubs = match_posix << 1, /* don't trap marked subs */ + match_extra = match_nosubs << 1, /* include full capture information for repeated captures */ + match_single_line = match_extra << 1, /* treat text as single line and ignore any \n's when matching ^ and $. */ + match_unused1 = match_single_line << 1, /* unused */ + match_unused2 = match_unused1 << 1, /* unused */ + match_unused3 = match_unused2 << 1, /* unused */ + match_max = match_unused3, + + format_perl = 0, /* perl style replacement */ + format_default = 0, /* ditto. */ + format_sed = match_max << 1, /* sed style replacement. */ + format_all = format_sed << 1, /* enable all extensions to syntax. */ + format_no_copy = format_all << 1, /* don't copy non-matching segments. */ + format_first_only = format_no_copy << 1, /* Only replace first occurrence. */ + format_is_if = format_first_only << 1, /* internal use only. */ + format_literal = format_is_if << 1, /* treat string as a literal */ + + match_not_any = match_not_bol | match_not_eol | match_not_bob + | match_not_eob | match_not_bow | match_not_eow | match_not_dot_newline + | match_not_dot_null | match_prev_avail | match_init | match_not_null + | match_continuous | match_partial | match_stop | match_not_initial_null + | match_stop | match_all | match_perl | match_posix | match_nosubs + | match_extra | match_single_line | match_unused1 | match_unused2 + | match_unused3 | match_max | format_perl | format_default | format_sed + | format_all | format_no_copy | format_first_only | format_is_if + | format_literal + + +} match_flags; + +typedef match_flags match_flag_type; + +#ifdef __cplusplus +inline match_flags operator&(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) & static_cast(m2)); } +inline match_flags operator|(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) | static_cast(m2)); } +inline match_flags operator^(match_flags m1, match_flags m2) +{ return static_cast(static_cast(m1) ^ static_cast(m2)); } +inline match_flags operator~(match_flags m1) +{ return static_cast(~static_cast(m1)); } +inline match_flags& operator&=(match_flags& m1, match_flags m2) +{ m1 = m1&m2; return m1; } +inline match_flags& operator|=(match_flags& m1, match_flags m2) +{ m1 = m1|m2; return m1; } +inline match_flags& operator^=(match_flags& m1, match_flags m2) +{ m1 = m1^m2; return m1; } +#endif + +#ifdef __cplusplus +} /* namespace regex_constants */ +/* + * import names into boost for backwards compatibility: + */ +using regex_constants::match_flag_type; +using regex_constants::match_default; +using regex_constants::match_not_bol; +using regex_constants::match_not_eol; +using regex_constants::match_not_bob; +using regex_constants::match_not_eob; +using regex_constants::match_not_bow; +using regex_constants::match_not_eow; +using regex_constants::match_not_dot_newline; +using regex_constants::match_not_dot_null; +using regex_constants::match_prev_avail; +/* using regex_constants::match_init; */ +using regex_constants::match_any; +using regex_constants::match_not_null; +using regex_constants::match_continuous; +using regex_constants::match_partial; +/*using regex_constants::match_stop; */ +using regex_constants::match_all; +using regex_constants::match_perl; +using regex_constants::match_posix; +using regex_constants::match_nosubs; +using regex_constants::match_extra; +using regex_constants::match_single_line; +/*using regex_constants::match_max; */ +using regex_constants::format_all; +using regex_constants::format_sed; +using regex_constants::format_perl; +using regex_constants::format_default; +using regex_constants::format_no_copy; +using regex_constants::format_first_only; +/*using regex_constants::format_is_if;*/ + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + + +} /* namespace boost */ +#endif /* __cplusplus */ +#endif /* include guard */ + diff --git a/third-party/boost_regex/include/boost/regex/v5/match_results.hpp b/third-party/boost_regex/include/boost/regex/v5/match_results.hpp new file mode 100644 index 0000000000..3f9cd0129f --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/match_results.hpp @@ -0,0 +1,667 @@ +/* + * + * Copyright (c) 1998-2009 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE match_results.cpp + * VERSION see + * DESCRIPTION: Declares template class match_results. + */ + +#ifndef BOOST_REGEX_V5_MATCH_RESULTS_HPP +#define BOOST_REGEX_V5_MATCH_RESULTS_HPP + +namespace boost{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable : 4251 4459) +#if BOOST_REGEX_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +# if BOOST_REGEX_MSVC < 1600 +# pragma warning(disable : 4660) +# endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +class named_subexpressions; + +} + +template +class match_results +{ +private: + typedef std::vector, Allocator> vector_type; +public: + typedef sub_match value_type; + typedef typename std::allocator_traits::value_type const & const_reference; + typedef const_reference reference; + typedef typename vector_type::const_iterator const_iterator; + typedef const_iterator iterator; + typedef typename std::iterator_traits< + BidiIterator>::difference_type difference_type; + typedef typename std::allocator_traits::size_type size_type; + typedef Allocator allocator_type; + typedef typename std::iterator_traits< + BidiIterator>::value_type char_type; + typedef std::basic_string string_type; + typedef BOOST_REGEX_DETAIL_NS::named_subexpressions named_sub_type; + + // construct/copy/destroy: + explicit match_results(const Allocator& a = Allocator()) + : m_subs(a), m_base(), m_null(), m_last_closed_paren(0), m_is_singular(true) {} + // + // IMPORTANT: in the code below, the crazy looking checks around m_is_singular are + // all required because it is illegal to copy a singular iterator. + // See https://svn.boost.org/trac/boost/ticket/3632. + // + match_results(const match_results& m) + : m_subs(m.m_subs), m_base(), m_null(), m_named_subs(m.m_named_subs), m_last_closed_paren(m.m_last_closed_paren), m_is_singular(m.m_is_singular) + { + if(!m_is_singular) + { + m_base = m.m_base; + m_null = m.m_null; + } + } + match_results& operator=(const match_results& m) + { + m_subs = m.m_subs; + m_named_subs = m.m_named_subs; + m_last_closed_paren = m.m_last_closed_paren; + m_is_singular = m.m_is_singular; + if(!m_is_singular) + { + m_base = m.m_base; + m_null = m.m_null; + } + return *this; + } + ~match_results(){} + + // size: + size_type size() const + { return empty() ? 0 : m_subs.size() - 2; } + size_type max_size() const + { return m_subs.max_size(); } + bool empty() const + { return m_subs.size() < 2; } + // element access: + difference_type length(int sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + if((sub < (int)m_subs.size()) && (sub > 0)) + return m_subs[sub].length(); + return 0; + } + difference_type length(const char_type* sub) const + { + if(m_is_singular) + raise_logic_error(); + const char_type* sub_end = sub; + while(*sub_end) ++sub_end; + return length(named_subexpression_index(sub, sub_end)); + } + template + difference_type length(const charT* sub) const + { + if(m_is_singular) + raise_logic_error(); + const charT* sub_end = sub; + while(*sub_end) ++sub_end; + return length(named_subexpression_index(sub, sub_end)); + } + template + difference_type length(const std::basic_string& sub) const + { + return length(sub.c_str()); + } + difference_type position(size_type sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + if(sub < m_subs.size()) + { + const sub_match& s = m_subs[sub]; + if(s.matched || (sub == 2)) + { + return std::distance((BidiIterator)(m_base), (BidiIterator)(s.first)); + } + } + return ~static_cast(0); + } + difference_type position(const char_type* sub) const + { + const char_type* sub_end = sub; + while(*sub_end) ++sub_end; + return position(named_subexpression_index(sub, sub_end)); + } + template + difference_type position(const charT* sub) const + { + const charT* sub_end = sub; + while(*sub_end) ++sub_end; + return position(named_subexpression_index(sub, sub_end)); + } + template + difference_type position(const std::basic_string& sub) const + { + return position(sub.c_str()); + } + string_type str(int sub = 0) const + { + if(m_is_singular) + raise_logic_error(); + sub += 2; + string_type result; + if(sub < (int)m_subs.size() && (sub > 0)) + { + const sub_match& s = m_subs[sub]; + if(s.matched) + { + result = s.str(); + } + } + return result; + } + string_type str(const char_type* sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const std::basic_string& sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const charT* sub) const + { + return (*this)[sub].str(); + } + template + string_type str(const std::basic_string& sub) const + { + return (*this)[sub].str(); + } + const_reference operator[](int sub) const + { + if(m_is_singular && m_subs.empty()) + raise_logic_error(); + sub += 2; + if(sub < (int)m_subs.size() && (sub >= 0)) + { + return m_subs[sub]; + } + return m_null; + } + // + // Named sub-expressions: + // + const_reference named_subexpression(const char_type* i, const char_type* j) const + { + // + // Scan for the leftmost *matched* subexpression with the specified named: + // + if(m_is_singular) + raise_logic_error(); + BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type r = m_named_subs->equal_range(i, j); + while((r.first != r.second) && ((*this)[r.first->index].matched == false)) + ++r.first; + return r.first != r.second ? (*this)[r.first->index] : m_null; + } + template + const_reference named_subexpression(const charT* i, const charT* j) const + { + static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic"); + if(i == j) + return m_null; + std::vector s; + while(i != j) + s.insert(s.end(), *i++); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + int named_subexpression_index(const char_type* i, const char_type* j) const + { + // + // Scan for the leftmost *matched* subexpression with the specified named. + // If none found then return the leftmost expression with that name, + // otherwise an invalid index: + // + if(m_is_singular) + raise_logic_error(); + BOOST_REGEX_DETAIL_NS::named_subexpressions::range_type s, r; + s = r = m_named_subs->equal_range(i, j); + while((r.first != r.second) && ((*this)[r.first->index].matched == false)) + ++r.first; + if(r.first == r.second) + r = s; + return r.first != r.second ? r.first->index : -20; + } + template + int named_subexpression_index(const charT* i, const charT* j) const + { + static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic"); + if(i == j) + return -20; + std::vector s; + while(i != j) + s.insert(s.end(), *i++); + return named_subexpression_index(&*s.begin(), &*s.begin() + s.size()); + } + template + const_reference operator[](const std::basic_string& s) const + { + return named_subexpression(s.c_str(), s.c_str() + s.size()); + } + const_reference operator[](const char_type* p) const + { + const char_type* e = p; + while(*e) ++e; + return named_subexpression(p, e); + } + + template + const_reference operator[](const charT* p) const + { + static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic"); + if(*p == 0) + return m_null; + std::vector s; + while(*p) + s.insert(s.end(), *p++); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + template + const_reference operator[](const std::basic_string& ns) const + { + static_assert(sizeof(charT) <= sizeof(char_type), "Failed internal logic"); + if(ns.empty()) + return m_null; + std::vector s; + for(unsigned i = 0; i < ns.size(); ++i) + s.insert(s.end(), ns[i]); + return named_subexpression(&*s.begin(), &*s.begin() + s.size()); + } + + const_reference prefix() const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[-1]; + } + + const_reference suffix() const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[-2]; + } + const_iterator begin() const + { + return (m_subs.size() > 2) ? (m_subs.begin() + 2) : m_subs.end(); + } + const_iterator end() const + { + return m_subs.end(); + } + // format: + template + OutputIterator format(OutputIterator out, + Functor fmt, + match_flag_type flags = format_default) const + { + if(m_is_singular) + raise_logic_error(); + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, OutputIterator>::type F; + F func(fmt); + return func(*this, out, flags); + } + template + string_type format(Functor fmt, match_flag_type flags = format_default) const + { + if(m_is_singular) + raise_logic_error(); + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, BOOST_REGEX_DETAIL_NS::string_out_iterator > >::type F; + F func(fmt); + + func(*this, i, flags); + return result; + } + // format with locale: + template + OutputIterator format(OutputIterator out, + Functor fmt, + match_flag_type flags, + const RegexT& re) const + { + if(m_is_singular) + raise_logic_error(); + typedef ::boost::regex_traits_wrapper traits_type; + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, OutputIterator, traits_type>::type F; + F func(fmt); + return func(*this, out, flags, re.get_traits()); + } + template + string_type format(Functor fmt, + match_flag_type flags, + const RegexT& re) const + { + if(m_is_singular) + raise_logic_error(); + typedef ::boost::regex_traits_wrapper traits_type; + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + + typedef typename BOOST_REGEX_DETAIL_NS::compute_functor_type, BOOST_REGEX_DETAIL_NS::string_out_iterator >, traits_type >::type F; + F func(fmt); + + func(*this, i, flags, re.get_traits()); + return result; + } + + const_reference get_last_closed_paren()const + { + if(m_is_singular) + raise_logic_error(); + return m_last_closed_paren == 0 ? m_null : (*this)[m_last_closed_paren]; + } + + allocator_type get_allocator() const + { + return m_subs.get_allocator(); + } + void swap(match_results& that) + { + std::swap(m_subs, that.m_subs); + std::swap(m_named_subs, that.m_named_subs); + std::swap(m_last_closed_paren, that.m_last_closed_paren); + if(m_is_singular) + { + if(!that.m_is_singular) + { + m_base = that.m_base; + m_null = that.m_null; + } + } + else if(that.m_is_singular) + { + that.m_base = m_base; + that.m_null = m_null; + } + else + { + std::swap(m_base, that.m_base); + std::swap(m_null, that.m_null); + } + std::swap(m_is_singular, that.m_is_singular); + } + bool operator==(const match_results& that)const + { + if(m_is_singular) + { + return that.m_is_singular; + } + else if(that.m_is_singular) + { + return false; + } + return (m_subs == that.m_subs) && (m_base == that.m_base) && (m_last_closed_paren == that.m_last_closed_paren); + } + bool operator!=(const match_results& that)const + { return !(*this == that); } + +#ifdef BOOST_REGEX_MATCH_EXTRA + typedef typename sub_match::capture_sequence_type capture_sequence_type; + + const capture_sequence_type& captures(int i)const + { + if(m_is_singular) + raise_logic_error(); + return (*this)[i].captures(); + } +#endif + + // + // private access functions: + void set_second(BidiIterator i) + { + BOOST_REGEX_ASSERT(m_subs.size() > 2); + m_subs[2].second = i; + m_subs[2].matched = true; + m_subs[0].first = i; + m_subs[0].matched = (m_subs[0].first != m_subs[0].second); + m_null.first = i; + m_null.second = i; + m_null.matched = false; + m_is_singular = false; + } + + void set_second(BidiIterator i, size_type pos, bool m = true, bool escape_k = false) + { + if(pos) + m_last_closed_paren = static_cast(pos); + pos += 2; + BOOST_REGEX_ASSERT(m_subs.size() > pos); + m_subs[pos].second = i; + m_subs[pos].matched = m; + if((pos == 2) && !escape_k) + { + m_subs[0].first = i; + m_subs[0].matched = (m_subs[0].first != m_subs[0].second); + m_null.first = i; + m_null.second = i; + m_null.matched = false; + m_is_singular = false; + } + } + void set_size(size_type n, BidiIterator i, BidiIterator j) + { + value_type v(j); + size_type len = m_subs.size(); + if(len > n + 2) + { + m_subs.erase(m_subs.begin()+n+2, m_subs.end()); + std::fill(m_subs.begin(), m_subs.end(), v); + } + else + { + std::fill(m_subs.begin(), m_subs.end(), v); + if(n+2 != len) + m_subs.insert(m_subs.end(), n+2-len, v); + } + m_subs[1].first = i; + m_last_closed_paren = 0; + } + void set_base(BidiIterator pos) + { + m_base = pos; + } + BidiIterator base()const + { + return m_base; + } + void set_first(BidiIterator i) + { + BOOST_REGEX_ASSERT(m_subs.size() > 2); + // set up prefix: + m_subs[1].second = i; + m_subs[1].matched = (m_subs[1].first != i); + // set up $0: + m_subs[2].first = i; + // zero out everything else: + for(size_type n = 3; n < m_subs.size(); ++n) + { + m_subs[n].first = m_subs[n].second = m_subs[0].second; + m_subs[n].matched = false; + } + } + void set_first(BidiIterator i, size_type pos, bool escape_k = false) + { + BOOST_REGEX_ASSERT(pos+2 < m_subs.size()); + if(pos || escape_k) + { + m_subs[pos+2].first = i; + if(escape_k) + { + m_subs[1].second = i; + m_subs[1].matched = (m_subs[1].first != m_subs[1].second); + } + } + else + set_first(i); + } + void maybe_assign(const match_results& m); + + void set_named_subs(std::shared_ptr subs) + { + m_named_subs = subs; + } + +private: + // + // Error handler called when an uninitialized match_results is accessed: + // + static void raise_logic_error() + { + std::logic_error e("Attempt to access an uninitialized boost::match_results<> class."); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif + } + + + vector_type m_subs; // subexpressions + BidiIterator m_base; // where the search started from + sub_match m_null; // a null match + std::shared_ptr m_named_subs; // Shared copy of named subs in the regex object + int m_last_closed_paren; // Last ) to be seen - used for formatting + bool m_is_singular; // True if our stored iterators are singular +}; + +template +void match_results::maybe_assign(const match_results& m) +{ + if(m_is_singular) + { + *this = m; + return; + } + const_iterator p1, p2; + p1 = begin(); + p2 = m.begin(); + // + // Distances are measured from the start of *this* match, unless this isn't + // a valid match in which case we use the start of the whole sequence. Note that + // no subsequent match-candidate can ever be to the left of the first match found. + // This ensures that when we are using bidirectional iterators, that distances + // measured are as short as possible, and therefore as efficient as possible + // to compute. Finally note that we don't use the "matched" data member to test + // whether a sub-expression is a valid match, because partial matches set this + // to false for sub-expression 0. + // + BidiIterator l_end = this->suffix().second; + BidiIterator l_base = (p1->first == l_end) ? this->prefix().first : (*this)[0].first; + difference_type len1 = 0; + difference_type len2 = 0; + difference_type base1 = 0; + difference_type base2 = 0; + std::size_t i; + for(i = 0; i < size(); ++i, ++p1, ++p2) + { + // + // Leftmost takes priority over longest; handle special cases + // where distances need not be computed first (an optimisation + // for bidirectional iterators: ensure that we don't accidently + // compute the length of the whole sequence, as this can be really + // expensive). + // + if(p1->first == l_end) + { + if(p2->first != l_end) + { + // p2 must be better than p1, and no need to calculate + // actual distances: + base1 = 1; + base2 = 0; + break; + } + else + { + // *p1 and *p2 are either unmatched or match end-of sequence, + // either way no need to calculate distances: + if((p1->matched == false) && (p2->matched == true)) + break; + if((p1->matched == true) && (p2->matched == false)) + return; + continue; + } + } + else if(p2->first == l_end) + { + // p1 better than p2, and no need to calculate distances: + return; + } + base1 = std::distance(l_base, p1->first); + base2 = std::distance(l_base, p2->first); + BOOST_REGEX_ASSERT(base1 >= 0); + BOOST_REGEX_ASSERT(base2 >= 0); + if(base1 < base2) return; + if(base2 < base1) break; + + len1 = std::distance((BidiIterator)p1->first, (BidiIterator)p1->second); + len2 = std::distance((BidiIterator)p2->first, (BidiIterator)p2->second); + BOOST_REGEX_ASSERT(len1 >= 0); + BOOST_REGEX_ASSERT(len2 >= 0); + if((len1 != len2) || ((p1->matched == false) && (p2->matched == true))) + break; + if((p1->matched == true) && (p2->matched == false)) + return; + } + if(i == size()) + return; + if(base2 < base1) + *this = m; + else if((len2 > len1) || ((p1->matched == false) && (p2->matched == true)) ) + *this = m; +} + +template +void swap(match_results& a, match_results& b) +{ + a.swap(b); +} + +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const match_results& s) +{ + return (os << s.str()); +} + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} // namespace boost + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v5/mem_block_cache.hpp b/third-party/boost_regex/include/boost/regex/v5/mem_block_cache.hpp new file mode 100644 index 0000000000..3e1216d06a --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/mem_block_cache.hpp @@ -0,0 +1,173 @@ + /* + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE mem_block_cache.hpp + * VERSION see + * DESCRIPTION: memory block cache used by the non-recursive matcher. + */ + +#ifndef BOOST_REGEX_V5_MEM_BLOCK_CACHE_HPP +#define BOOST_REGEX_V5_MEM_BLOCK_CACHE_HPP + +#include +#ifdef BOOST_HAS_THREADS +#include +#endif + +#ifndef BOOST_NO_CXX11_HDR_ATOMIC + #include + #if ATOMIC_POINTER_LOCK_FREE == 2 + #define BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE + #define BOOST_REGEX_ATOMIC_POINTER std::atomic + #endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#if BOOST_REGEX_MAX_CACHE_BLOCKS != 0 +#ifdef BOOST_REGEX_MEM_BLOCK_CACHE_LOCK_FREE /* lock free implementation */ +struct mem_block_cache +{ + std::atomic cache[BOOST_REGEX_MAX_CACHE_BLOCKS]; + + ~mem_block_cache() + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + if (cache[i].load()) ::operator delete(cache[i].load()); + } + } + void* get() + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + void* p = cache[i].load(); + if (p != NULL) { + if (cache[i].compare_exchange_strong(p, NULL)) return p; + } + } + return ::operator new(BOOST_REGEX_BLOCKSIZE); + } + void put(void* ptr) + { + for (size_t i = 0;i < BOOST_REGEX_MAX_CACHE_BLOCKS; ++i) { + void* p = cache[i].load(); + if (p == NULL) { + if (cache[i].compare_exchange_strong(p, ptr)) return; + } + } + ::operator delete(ptr); + } + + static mem_block_cache& instance() + { + static mem_block_cache block_cache = { { {nullptr} } }; + return block_cache; + } +}; + + +#else /* lock-based implementation */ + + +struct mem_block_node +{ + mem_block_node* next; +}; + +struct mem_block_cache +{ + // this member has to be statically initialsed: + mem_block_node* next { nullptr }; + unsigned cached_blocks { 0 }; +#ifdef BOOST_HAS_THREADS + std::mutex mut; +#endif + + ~mem_block_cache() + { + while(next) + { + mem_block_node* old = next; + next = next->next; + ::operator delete(old); + } + } + void* get() + { +#ifdef BOOST_HAS_THREADS + std::lock_guard g(mut); +#endif + if(next) + { + mem_block_node* result = next; + next = next->next; + --cached_blocks; + return result; + } + return ::operator new(BOOST_REGEX_BLOCKSIZE); + } + void put(void* p) + { +#ifdef BOOST_HAS_THREADS + std::lock_guard g(mut); +#endif + if(cached_blocks >= BOOST_REGEX_MAX_CACHE_BLOCKS) + { + ::operator delete(p); + } + else + { + mem_block_node* old = static_cast(p); + old->next = next; + next = old; + ++cached_blocks; + } + } + static mem_block_cache& instance() + { + static mem_block_cache block_cache; + return block_cache; + } +}; +#endif +#endif + +#if BOOST_REGEX_MAX_CACHE_BLOCKS == 0 + +inline void* get_mem_block() +{ + return ::operator new(BOOST_REGEX_BLOCKSIZE); +} + +inline void put_mem_block(void* p) +{ + ::operator delete(p); +} + +#else + +inline void* get_mem_block() +{ + return mem_block_cache::instance().get(); +} + +inline void put_mem_block(void* p) +{ + mem_block_cache::instance().put(p); +} + +#endif +} +} // namespace boost + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/object_cache.hpp b/third-party/boost_regex/include/boost/regex/v5/object_cache.hpp new file mode 100644 index 0000000000..6ebef9b34e --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/object_cache.hpp @@ -0,0 +1,160 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE object_cache.hpp + * VERSION see + * DESCRIPTION: Implements a generic object cache. + */ + +#ifndef BOOST_REGEX_OBJECT_CACHE_HPP +#define BOOST_REGEX_OBJECT_CACHE_HPP + +#include +#include +#include +#include +#include +#include +#ifdef BOOST_HAS_THREADS +#include +#endif + +namespace boost{ + +template +class object_cache +{ +public: + typedef std::pair< ::std::shared_ptr, Key const*> value_type; + typedef std::list list_type; + typedef typename list_type::iterator list_iterator; + typedef std::map map_type; + typedef typename map_type::iterator map_iterator; + typedef typename list_type::size_type size_type; + static std::shared_ptr get(const Key& k, size_type l_max_cache_size); + +private: + static std::shared_ptr do_get(const Key& k, size_type l_max_cache_size); + + struct data + { + list_type cont; + map_type index; + }; + + // Needed by compilers not implementing the resolution to DR45. For reference, + // see http://www.open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#45. + friend struct data; +}; + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable: 4702) +#endif +template +std::shared_ptr object_cache::get(const Key& k, size_type l_max_cache_size) +{ +#ifdef BOOST_HAS_THREADS + static std::mutex mut; + std::lock_guard l(mut); + return do_get(k, l_max_cache_size); +#else + return do_get(k, l_max_cache_size); +#endif +} +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + +template +std::shared_ptr object_cache::do_get(const Key& k, size_type l_max_cache_size) +{ + typedef typename object_cache::data object_data; + typedef typename map_type::size_type map_size_type; + static object_data s_data; + + // + // see if the object is already in the cache: + // + map_iterator mpos = s_data.index.find(k); + if(mpos != s_data.index.end()) + { + // + // Eureka! + // We have a cached item, bump it up the list and return it: + // + if(--(s_data.cont.end()) != mpos->second) + { + // splice out the item we want to move: + list_type temp; + temp.splice(temp.end(), s_data.cont, mpos->second); + // and now place it at the end of the list: + s_data.cont.splice(s_data.cont.end(), temp, temp.begin()); + BOOST_REGEX_ASSERT(*(s_data.cont.back().second) == k); + // update index with new position: + mpos->second = --(s_data.cont.end()); + BOOST_REGEX_ASSERT(&(mpos->first) == mpos->second->second); + BOOST_REGEX_ASSERT(&(mpos->first) == s_data.cont.back().second); + } + return s_data.cont.back().first; + } + // + // if we get here then the item is not in the cache, + // so create it: + // + std::shared_ptr result(new Object(k)); + // + // Add it to the list, and index it: + // + s_data.cont.push_back(value_type(result, static_cast(0))); + s_data.index.insert(std::make_pair(k, --(s_data.cont.end()))); + s_data.cont.back().second = &(s_data.index.find(k)->first); + map_size_type s = s_data.index.size(); + BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get()); + BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second); + BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k); + if(s > l_max_cache_size) + { + // + // We have too many items in the list, so we need to start + // popping them off the back of the list, but only if they're + // being held uniquely by us: + // + list_iterator pos = s_data.cont.begin(); + list_iterator last = s_data.cont.end(); + while((pos != last) && (s > l_max_cache_size)) + { + if(pos->first.use_count() == 1) + { + list_iterator condemmed(pos); + ++pos; + // now remove the items from our containers, + // then order has to be as follows: + BOOST_REGEX_ASSERT(s_data.index.find(*(condemmed->second)) != s_data.index.end()); + s_data.index.erase(*(condemmed->second)); + s_data.cont.erase(condemmed); + --s; + } + else + ++pos; + } + BOOST_REGEX_ASSERT(s_data.index[k]->first.get() == result.get()); + BOOST_REGEX_ASSERT(&(s_data.index.find(k)->first) == s_data.cont.back().second); + BOOST_REGEX_ASSERT(s_data.index.find(k)->first == k); + } + return result; +} + +} + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/pattern_except.hpp b/third-party/boost_regex/include/boost/regex/v5/pattern_except.hpp new file mode 100644 index 0000000000..3fbdca0a22 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/pattern_except.hpp @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE pattern_except.hpp + * VERSION see + * DESCRIPTION: Declares pattern-matching exception classes. + */ + +#ifndef BOOST_RE_V5_PAT_EXCEPT_HPP +#define BOOST_RE_V5_PAT_EXCEPT_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#include +#include +#include +#include + +namespace boost{ + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable : 4275) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable : 26812 4459) +#endif +#endif +class regex_error : public std::runtime_error +{ +public: + explicit regex_error(const std::string& s, regex_constants::error_type err = regex_constants::error_unknown, std::ptrdiff_t pos = 0) + : std::runtime_error(s) + , m_error_code(err) + , m_position(pos) + { + } + explicit regex_error(regex_constants::error_type err) + : std::runtime_error(::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(err)) + , m_error_code(err) + , m_position(0) + { + } + ~regex_error() noexcept override {} + regex_constants::error_type code()const + { return m_error_code; } + std::ptrdiff_t position()const + { return m_position; } + void raise()const + { +#ifndef BOOST_NO_EXCEPTIONS +#ifndef BOOST_REGEX_STANDALONE + ::boost::throw_exception(*this); +#else + throw* this; +#endif +#endif + } +private: + regex_constants::error_type m_error_code; + std::ptrdiff_t m_position; +}; + +typedef regex_error bad_pattern; +typedef regex_error bad_expression; + +namespace BOOST_REGEX_DETAIL_NS{ + +template +inline void raise_runtime_error(const E& ex) +{ +#ifndef BOOST_REGEX_STANDALONE + ::boost::throw_exception(ex); +#else + throw ex; +#endif +} + +template +void raise_error(const traits& t, regex_constants::error_type code) +{ + (void)t; // warning suppression + regex_error e(t.error_string(code), code, 0); + ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(e); +} + +} + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + +} // namespace boost + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/perl_matcher.hpp b/third-party/boost_regex/include/boost/regex/v5/perl_matcher.hpp new file mode 100644 index 0000000000..deeffa589b --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/perl_matcher.hpp @@ -0,0 +1,576 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifndef BOOST_REGEX_MATCHER_HPP +#define BOOST_REGEX_MATCHER_HPP + +#include + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable : 4251 4459) +#if BOOST_REGEX_MSVC < 1700 +# pragma warning(disable : 4231) +#endif +# if BOOST_REGEX_MSVC < 1600 +# pragma warning(disable : 4660) +# endif +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +// +// error checking API: +// +inline void verify_options(boost::regex_constants::syntax_option_type, match_flag_type mf) +{ + // + // can't mix match_extra with POSIX matching rules: + // + if ((mf & match_extra) && (mf & match_posix)) + { + std::logic_error msg("Usage Error: Can't mix regular expression captures with POSIX matching rules"); +#ifndef BOOST_REGEX_STANDALONE + throw_exception(msg); +#else + throw msg; +#endif + } +} +// +// function can_start: +// +template +inline bool can_start(charT c, const unsigned char* map, unsigned char mask) +{ + return ((c < static_cast(0)) ? true : ((c >= static_cast(1 << CHAR_BIT)) ? true : map[c] & mask)); +} +inline bool can_start(char c, const unsigned char* map, unsigned char mask) +{ + return map[(unsigned char)c] & mask; +} +inline bool can_start(signed char c, const unsigned char* map, unsigned char mask) +{ + return map[(unsigned char)c] & mask; +} +inline bool can_start(unsigned char c, const unsigned char* map, unsigned char mask) +{ + return map[c] & mask; +} +inline bool can_start(unsigned short c, const unsigned char* map, unsigned char mask) +{ + return ((c >= (1 << CHAR_BIT)) ? true : map[c] & mask); +} +#if defined(WCHAR_MIN) && (WCHAR_MIN == 0) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +inline bool can_start(wchar_t c, const unsigned char* map, unsigned char mask) +{ + return ((c >= static_cast(1u << CHAR_BIT)) ? true : map[c] & mask); +} +#endif +#if !defined(BOOST_NO_INTRINSIC_WCHAR_T) +inline bool can_start(unsigned int c, const unsigned char* map, unsigned char mask) +{ + return (((c >= static_cast(1u << CHAR_BIT)) ? true : map[c] & mask)); +} +#endif + +template +inline int string_compare(const std::basic_string& s, const C* p) +{ + if(0 == *p) + { + if(s.empty() || ((s.size() == 1) && (s[0] == 0))) + return 0; + } + return s.compare(p); +} +template +inline int string_compare(const Seq& s, const C* p) +{ + std::size_t i = 0; + while((i < s.size()) && (p[i] == s[i])) + { + ++i; + } + return (i == s.size()) ? -(int)p[i] : (int)s[i] - (int)p[i]; +} +# define STR_COMP(s,p) string_compare(s,p) + +template +inline const charT* re_skip_past_null(const charT* p) +{ + while (*p != static_cast(0)) ++p; + return ++p; +} + +template +iterator re_is_set_member(iterator next, + iterator last, + const re_set_long* set_, + const regex_data& e, bool icase) +{ + const charT* p = reinterpret_cast(set_+1); + iterator ptr; + unsigned int i; + //bool icase = e.m_flags & regex_constants::icase; + + if(next == last) return next; + + typedef typename traits_type::string_type traits_string_type; + const ::boost::regex_traits_wrapper& traits_inst = *(e.m_ptraits); + + // dwa 9/13/00 suppress incorrect MSVC warning - it claims this is never + // referenced + (void)traits_inst; + + // try and match a single character, could be a multi-character + // collating element... + for(i = 0; i < set_->csingles; ++i) + { + ptr = next; + if(*p == static_cast(0)) + { + // treat null string as special case: + if(traits_inst.translate(*ptr, icase)) + { + ++p; + continue; + } + return set_->isnot ? next : (ptr == next) ? ++next : ptr; + } + else + { + while(*p && (ptr != last)) + { + if(traits_inst.translate(*ptr, icase) != *p) + break; + ++p; + ++ptr; + } + + if(*p == static_cast(0)) // if null we've matched + return set_->isnot ? next : (ptr == next) ? ++next : ptr; + + p = re_skip_past_null(p); // skip null + } + } + + charT col = traits_inst.translate(*next, icase); + + + if(set_->cranges || set_->cequivalents) + { + traits_string_type s1; + // + // try and match a range, NB only a single character can match + if(set_->cranges) + { + if((e.m_flags & regex_constants::collate) == 0) + s1.assign(1, col); + else + { + charT a[2] = { col, charT(0), }; + s1 = traits_inst.transform(a, a + 1); + } + for(i = 0; i < set_->cranges; ++i) + { + if(STR_COMP(s1, p) >= 0) + { + do{ ++p; }while(*p); + ++p; + if(STR_COMP(s1, p) <= 0) + return set_->isnot ? next : ++next; + } + else + { + // skip first string + do{ ++p; }while(*p); + ++p; + } + // skip second string + do{ ++p; }while(*p); + ++p; + } + } + // + // try and match an equivalence class, NB only a single character can match + if(set_->cequivalents) + { + charT a[2] = { col, charT(0), }; + s1 = traits_inst.transform_primary(a, a +1); + for(i = 0; i < set_->cequivalents; ++i) + { + if(STR_COMP(s1, p) == 0) + return set_->isnot ? next : ++next; + // skip string + do{ ++p; }while(*p); + ++p; + } + } + } + if(traits_inst.isctype(col, set_->cclasses) == true) + return set_->isnot ? next : ++next; + if((set_->cnclasses != 0) && (traits_inst.isctype(col, set_->cnclasses) == false)) + return set_->isnot ? next : ++next; + return set_->isnot ? ++next : next; +} + +template +class repeater_count +{ + repeater_count** stack; + repeater_count* next; + int state_id; + std::size_t count; // the number of iterations so far + BidiIterator start_pos; // where the last repeat started + + repeater_count* unwind_until(int n, repeater_count* p, int current_recursion_id) + { + while(p && (p->state_id != n)) + { + if(-2 - current_recursion_id == p->state_id) + return 0; + p = p->next; + if(p && (p->state_id < 0)) + { + p = unwind_until(p->state_id, p, current_recursion_id); + if(!p) + return p; + p = p->next; + } + } + return p; + } +public: + repeater_count(repeater_count** s) : stack(s), next(0), state_id(-1), count(0), start_pos() {} + + repeater_count(int i, repeater_count** s, BidiIterator start, int current_recursion_id) + : start_pos(start) + { + state_id = i; + stack = s; + next = *stack; + *stack = this; + if((state_id > next->state_id) && (next->state_id >= 0)) + count = 0; + else + { + repeater_count* p = next; + p = unwind_until(state_id, p, current_recursion_id); + if(p) + { + count = p->count; + start_pos = p->start_pos; + } + else + count = 0; + } + } + ~repeater_count() + { + if(next) + *stack = next; + } + std::size_t get_count() { return count; } + int get_id() { return state_id; } + std::size_t operator++() { return ++count; } + bool check_null_repeat(const BidiIterator& pos, std::size_t max) + { + // this is called when we are about to start a new repeat, + // if the last one was NULL move our count to max, + // otherwise save the current position. + bool result = (count == 0) ? false : (pos == start_pos); + if(result) + count = max; + else + start_pos = pos; + return result; + } +}; + +struct saved_state; + +enum saved_state_type +{ + saved_type_end = 0, + saved_type_paren = 1, + saved_type_recurse = 2, + saved_type_assertion = 3, + saved_state_alt = 4, + saved_state_repeater_count = 5, + saved_state_extra_block = 6, + saved_state_greedy_single_repeat = 7, + saved_state_rep_slow_dot = 8, + saved_state_rep_fast_dot = 9, + saved_state_rep_char = 10, + saved_state_rep_short_set = 11, + saved_state_rep_long_set = 12, + saved_state_non_greedy_long_repeat = 13, + saved_state_count = 14 +}; + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable:26495) +#endif +#endif +template +struct recursion_info +{ + typedef typename Results::value_type value_type; + typedef typename value_type::iterator iterator; + int idx; + const re_syntax_base* preturn_address; + Results results; + repeater_count* repeater_stack; + iterator location_of_start; +}; +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +template +class perl_matcher +{ +public: + typedef typename traits::char_type char_type; + typedef perl_matcher self_type; + typedef bool (self_type::*matcher_proc_type)(); + typedef std::size_t traits_size_type; + typedef typename is_byte::width_type width_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef match_results results_type; + + perl_matcher(BidiIterator first, BidiIterator end, + match_results& what, + const basic_regex& e, + match_flag_type f, + BidiIterator l_base) + : m_result(what), base(first), last(end), + position(first), backstop(l_base), re(e), traits_inst(e.get_traits()), + m_independent(false), next_count(&rep_obj), rep_obj(&next_count) + , m_recursions(0) + { + construct_init(e, f); + } + + bool match(); + bool find(); + + void setf(match_flag_type f) + { m_match_flags |= f; } + void unsetf(match_flag_type f) + { m_match_flags &= ~f; } + +private: + void construct_init(const basic_regex& e, match_flag_type f); + + bool find_imp(); + bool match_imp(); + void estimate_max_state_count(std::random_access_iterator_tag*); + void estimate_max_state_count(void*); + bool match_prefix(); + bool match_all_states(); + + // match procs, stored in s_match_vtable: + bool match_startmark(); + bool match_endmark(); + bool match_literal(); + bool match_start_line(); + bool match_end_line(); + bool match_wild(); + bool match_match(); + bool match_word_boundary(); + bool match_within_word(); + bool match_word_start(); + bool match_word_end(); + bool match_buffer_start(); + bool match_buffer_end(); + bool match_backref(); + bool match_long_set(); + bool match_set(); + bool match_jump(); + bool match_alt(); + bool match_rep(); + bool match_combining(); + bool match_soft_buffer_end(); + bool match_restart_continue(); + bool match_long_set_repeat(); + bool match_set_repeat(); + bool match_char_repeat(); + bool match_dot_repeat_fast(); + bool match_dot_repeat_slow(); + bool match_dot_repeat_dispatch() + { + return ::boost::is_random_access_iterator::value ? match_dot_repeat_fast() : match_dot_repeat_slow(); + } + bool match_backstep(); + bool match_assert_backref(); + bool match_toggle_case(); + bool match_recursion(); + bool match_fail(); + bool match_accept(); + bool match_commit(); + bool match_then(); + bool skip_until_paren(int index, bool match = true); + + // find procs stored in s_find_vtable: + bool find_restart_any(); + bool find_restart_word(); + bool find_restart_line(); + bool find_restart_buf(); + bool find_restart_lit(); + +private: + // final result structure to be filled in: + match_results& m_result; + // temporary result for POSIX matches: + std::unique_ptr > m_temp_match; + // pointer to actual result structure to fill in: + match_results* m_presult; + // start of sequence being searched: + BidiIterator base; + // end of sequence being searched: + BidiIterator last; + // current character being examined: + BidiIterator position; + // where to restart next search after failed match attempt: + BidiIterator restart; + // where the current search started from, acts as base for $` during grep: + BidiIterator search_base; + // how far we can go back when matching lookbehind: + BidiIterator backstop; + // the expression being examined: + const basic_regex& re; + // the expression's traits class: + const ::boost::regex_traits_wrapper& traits_inst; + // the next state in the machine being matched: + const re_syntax_base* pstate; + // matching flags in use: + match_flag_type m_match_flags; + // how many states we have examined so far: + std::ptrdiff_t state_count; + // max number of states to examine before giving up: + std::ptrdiff_t max_state_count; + // whether we should ignore case or not: + bool icase; + // set to true when (position == last), indicates that we may have a partial match: + bool m_has_partial_match; + // set to true whenever we get a match: + bool m_has_found_match; + // set to true whenever we're inside an independent sub-expression: + bool m_independent; + // the current repeat being examined: + repeater_count* next_count; + // the first repeat being examined (top of linked list): + repeater_count rep_obj; + // the mask to pass when matching word boundaries: + typename traits::char_class_type m_word_mask; + // the bitmask to use when determining whether a match_any matches a newline or not: + unsigned char match_any_mask; + // recursion information: + std::vector > recursion_stack; + // + // additional members for non-recursive version: + // + typedef bool (self_type::*unwind_proc_type)(bool); + + void extend_stack(); + bool unwind(bool); + bool unwind_end(bool); + bool unwind_paren(bool); + bool unwind_recursion_stopper(bool); + bool unwind_assertion(bool); + bool unwind_alt(bool); + bool unwind_repeater_counter(bool); + bool unwind_extra_block(bool); + bool unwind_greedy_single_repeat(bool); + bool unwind_slow_dot_repeat(bool); + bool unwind_fast_dot_repeat(bool); + bool unwind_char_repeat(bool); + bool unwind_short_set_repeat(bool); + bool unwind_long_set_repeat(bool); + bool unwind_non_greedy_repeat(bool); + bool unwind_recursion(bool); + bool unwind_recursion_pop(bool); + bool unwind_commit(bool); + bool unwind_then(bool); + bool unwind_case(bool); + void destroy_single_repeat(); + void push_matched_paren(int index, const sub_match& sub); + void push_recursion_stopper(); + void push_assertion(const re_syntax_base* ps, bool positive); + void push_alt(const re_syntax_base* ps); + void push_repeater_count(int i, repeater_count** s); + void push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id); + void push_non_greedy_repeat(const re_syntax_base* ps); + void push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2); + void push_recursion_pop(); + void push_case_change(bool); + + // pointer to base of stack: + saved_state* m_stack_base; + // pointer to current stack position: + saved_state* m_backup_state; + // how many memory blocks have we used up?: + unsigned used_block_count; + // determines what value to return when unwinding from recursion, + // allows for mixed recursive/non-recursive algorithm: + bool m_recursive_result; + // We have unwound to a lookahead/lookbehind, used by COMMIT/PRUNE/SKIP: + bool m_unwound_lookahead; + // We have unwound to an alternative, used by THEN: + bool m_unwound_alt; + // We are unwinding a commit - used by independent subs to determine whether to stop there or carry on unwinding: + //bool m_unwind_commit; + // Recursion limit: + unsigned m_recursions; + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#if BOOST_REGEX_MSVC >= 1800 +#pragma warning(disable:26495) +#endif +#endif + // these operations aren't allowed, so are declared private, + // bodies are provided to keep explicit-instantiation requests happy: + perl_matcher& operator=(const perl_matcher&) + { + return *this; + } + perl_matcher(const perl_matcher& that) + : m_result(that.m_result), re(that.re), traits_inst(that.traits_inst), rep_obj(0) {} +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif +}; + +} // namespace BOOST_REGEX_DETAIL_NS + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +} // namespace boost + +// +// include the implementation of perl_matcher: +// +#include +// this one has to be last: +#include + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/perl_matcher_common.hpp b/third-party/boost_regex/include/boost/regex/v5/perl_matcher_common.hpp new file mode 100644 index 0000000000..dcce9e6ac1 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/perl_matcher_common.hpp @@ -0,0 +1,921 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE perl_matcher_common.cpp + * VERSION see + * DESCRIPTION: Definitions of perl_matcher member functions that are + * common to both the recursive and non-recursive versions. + */ + +#ifndef BOOST_REGEX_V5_PERL_MATCHER_COMMON_HPP +#define BOOST_REGEX_V5_PERL_MATCHER_COMMON_HPP + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable:4459) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable:26812) +#endif + template +void perl_matcher::construct_init(const basic_regex& e, match_flag_type f) +{ + typedef typename std::iterator_traits::iterator_category category; + typedef typename basic_regex::flag_type expression_flag_type; + + if(e.empty()) + { + // precondition failure: e is not a valid regex. + std::invalid_argument ex("Invalid regular expression object"); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(ex); +#else + throw e; +#endif + } + pstate = 0; + m_match_flags = f; + estimate_max_state_count(static_cast(0)); + expression_flag_type re_f = re.flags(); + icase = re_f & regex_constants::icase; + if(!(m_match_flags & (match_perl|match_posix))) + { + if((re_f & (regbase::main_option_type|regbase::no_perl_ex)) == 0) + m_match_flags |= match_perl; + else if((re_f & (regbase::main_option_type|regbase::emacs_ex)) == (regbase::basic_syntax_group|regbase::emacs_ex)) + m_match_flags |= match_perl; + else if((re_f & (regbase::main_option_type|regbase::literal)) == (regbase::literal)) + m_match_flags |= match_perl; + else + m_match_flags |= match_posix; + } + if(m_match_flags & match_posix) + { + m_temp_match.reset(new match_results()); + m_presult = m_temp_match.get(); + } + else + m_presult = &m_result; + m_stack_base = 0; + m_backup_state = 0; + // find the value to use for matching word boundaries: + m_word_mask = re.get_data().m_word_mask; + // find bitmask to use for matching '.': + match_any_mask = static_cast((f & match_not_dot_newline) ? BOOST_REGEX_DETAIL_NS::test_not_newline : BOOST_REGEX_DETAIL_NS::test_newline); + // Disable match_any if requested in the state machine: + if(e.get_data().m_disable_match_any) + m_match_flags &= regex_constants::match_not_any; +} +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +template +void perl_matcher::estimate_max_state_count(std::random_access_iterator_tag*) +{ + // + // How many states should we allow our machine to visit before giving up? + // This is a heuristic: it takes the greater of O(N^2) and O(NS^2) + // where N is the length of the string, and S is the number of states + // in the machine. It's tempting to up this to O(N^2S) or even O(N^2S^2) + // but these take unreasonably amounts of time to bale out in pathological + // cases. + // + // Calculate NS^2 first: + // + static const std::ptrdiff_t k = 100000; + std::ptrdiff_t dist = std::distance(base, last); + if(dist == 0) + dist = 1; + std::ptrdiff_t states = re.size(); + if(states == 0) + states = 1; + if ((std::numeric_limits::max)() / states < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= states; + if((std::numeric_limits::max)() / dist < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= dist; + if((std::numeric_limits::max)() - k < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states += k; + + max_state_count = states; + + // + // Now calculate N^2: + // + states = dist; + if((std::numeric_limits::max)() / dist < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states *= dist; + if((std::numeric_limits::max)() - k < states) + { + max_state_count = (std::min)((std::ptrdiff_t)BOOST_REGEX_MAX_STATE_COUNT, (std::numeric_limits::max)() - 2); + return; + } + states += k; + // + // N^2 can be a very large number indeed, to prevent things getting out + // of control, cap the max states: + // + if(states > BOOST_REGEX_MAX_STATE_COUNT) + states = BOOST_REGEX_MAX_STATE_COUNT; + // + // If (the possibly capped) N^2 is larger than our first estimate, + // use this instead: + // + if(states > max_state_count) + max_state_count = states; +} + +template +inline void perl_matcher::estimate_max_state_count(void*) +{ + // we don't know how long the sequence is: + max_state_count = BOOST_REGEX_MAX_STATE_COUNT; +} + +template +inline bool perl_matcher::match() +{ + return match_imp(); +} + +template +bool perl_matcher::match_imp() +{ + // initialise our stack if we are non-recursive: + save_state_init init(&m_stack_base, &m_backup_state); + used_block_count = BOOST_REGEX_MAX_BLOCKS; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + + // reset our state machine: + position = base; + search_base = base; + state_count = 0; + m_match_flags |= regex_constants::match_all; + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), search_base, last); + m_presult->set_base(base); + m_presult->set_named_subs(this->re.get_named_subs()); + if(m_match_flags & match_posix) + m_result = *m_presult; + verify_options(re.flags(), m_match_flags); + if(0 == match_prefix()) + return false; + return (m_result[0].second == last) && (m_result[0].first == base); + +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif +} + +template +inline bool perl_matcher::find() +{ + return find_imp(); +} + +template +bool perl_matcher::find_imp() +{ + static matcher_proc_type const s_find_vtable[7] = + { + &perl_matcher::find_restart_any, + &perl_matcher::find_restart_word, + &perl_matcher::find_restart_line, + &perl_matcher::find_restart_buf, + &perl_matcher::match_prefix, + &perl_matcher::find_restart_lit, + &perl_matcher::find_restart_lit, + }; + + // initialise our stack if we are non-recursive: + save_state_init init(&m_stack_base, &m_backup_state); + used_block_count = BOOST_REGEX_MAX_BLOCKS; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + + state_count = 0; + if((m_match_flags & regex_constants::match_init) == 0) + { + // reset our state machine: + search_base = position = base; + pstate = re.get_first_state(); + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), base, last); + m_presult->set_base(base); + m_presult->set_named_subs(this->re.get_named_subs()); + m_match_flags |= regex_constants::match_init; + } + else + { + // start again: + search_base = position = m_result[0].second; + // If last match was null and match_not_null was not set then increment + // our start position, otherwise we go into an infinite loop: + if(((m_match_flags & match_not_null) == 0) && (m_result.length() == 0)) + { + if(position == last) + return false; + else + ++position; + } + // reset $` start: + m_presult->set_size((m_match_flags & match_nosubs) ? 1u : static_cast(1u + re.mark_count()), search_base, last); + //if((base != search_base) && (base == backstop)) + // m_match_flags |= match_prev_avail; + } + if(m_match_flags & match_posix) + { + m_result.set_size(static_cast(1u + re.mark_count()), base, last); + m_result.set_base(base); + } + + verify_options(re.flags(), m_match_flags); + // find out what kind of expression we have: + unsigned type = (m_match_flags & match_continuous) ? + static_cast(regbase::restart_continue) + : static_cast(re.get_restart_type()); + + // call the appropriate search routine: + matcher_proc_type proc = s_find_vtable[type]; + return (this->*proc)(); + +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif +} + +template +bool perl_matcher::match_prefix() +{ + m_has_partial_match = false; + m_has_found_match = false; + pstate = re.get_first_state(); + m_presult->set_first(position); + restart = position; + match_all_states(); + if(!m_has_found_match && m_has_partial_match && (m_match_flags & match_partial)) + { + m_has_found_match = true; + m_presult->set_second(last, 0, false); + position = last; + if((m_match_flags & match_posix) == match_posix) + { + m_result.maybe_assign(*m_presult); + } + } +#ifdef BOOST_REGEX_MATCH_EXTRA + if(m_has_found_match && (match_extra & m_match_flags)) + { + // + // we have a match, reverse the capture information: + // + for(unsigned i = 0; i < m_presult->size(); ++i) + { + typename sub_match::capture_sequence_type & seq = ((*m_presult)[i]).get_captures(); + std::reverse(seq.begin(), seq.end()); + } + } +#endif + if(!m_has_found_match) + position = restart; // reset search postion + return m_has_found_match; +} + +template +bool perl_matcher::match_literal() +{ + unsigned int len = static_cast(pstate)->length; + const char_type* what = reinterpret_cast(static_cast(pstate) + 1); + // + // compare string with what we stored in + // our records: + for(unsigned int i = 0; i < len; ++i, ++position) + { + if((position == last) || (traits_inst.translate(*position, icase) != what[i])) + return false; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_start_line() +{ + if(position == backstop) + { + if((m_match_flags & match_prev_avail) == 0) + { + if((m_match_flags & match_not_bol) == 0) + { + pstate = pstate->next.p; + return true; + } + return false; + } + } + else if(m_match_flags & match_single_line) + return false; + + // check the previous value character: + BidiIterator t(position); + --t; + if(position != last) + { + if(is_separator(*t) && !((*t == static_cast('\r')) && (*position == static_cast('\n'))) ) + { + pstate = pstate->next.p; + return true; + } + } + else if(is_separator(*t)) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_end_line() +{ + if(position != last) + { + if(m_match_flags & match_single_line) + return false; + // we're not yet at the end so *first is always valid: + if(is_separator(*position)) + { + if((position != backstop) || (m_match_flags & match_prev_avail)) + { + // check that we're not in the middle of \r\n sequence + BidiIterator t(position); + --t; + if((*t == static_cast('\r')) && (*position == static_cast('\n'))) + { + return false; + } + } + pstate = pstate->next.p; + return true; + } + } + else if((m_match_flags & match_not_eol) == 0) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_wild() +{ + if(position == last) + return false; + if(is_separator(*position) && ((match_any_mask & static_cast(pstate)->mask) == 0)) + return false; + if((*position == char_type(0)) && (m_match_flags & match_not_dot_null)) + return false; + pstate = pstate->next.p; + ++position; + return true; +} + +template +bool perl_matcher::match_word_boundary() +{ + bool b; // indcates whether next character is a word character + if(position != last) + { + // prev and this character must be opposites: + b = traits_inst.isctype(*position, m_word_mask); + } + else + { + if (m_match_flags & match_not_eow) + return false; + b = false; + } + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + { + if(m_match_flags & match_not_bow) + return false; + else + b ^= false; + } + else + { + --position; + b ^= traits_inst.isctype(*position, m_word_mask); + ++position; + } + if(b) + { + pstate = pstate->next.p; + return true; + } + return false; // no match if we get to here... +} + +template +bool perl_matcher::match_within_word() +{ + bool b = !match_word_boundary(); + if(b) + pstate = pstate->next.p; + return b; + /* + if(position == last) + return false; + // both prev and this character must be m_word_mask: + bool prev = traits_inst.isctype(*position, m_word_mask); + { + bool b; + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + return false; + else + { + --position; + b = traits_inst.isctype(*position, m_word_mask); + ++position; + } + if(b == prev) + { + pstate = pstate->next.p; + return true; + } + } + return false; + */ +} + +template +bool perl_matcher::match_word_start() +{ + if(position == last) + return false; // can't be starting a word if we're already at the end of input + if(!traits_inst.isctype(*position, m_word_mask)) + return false; // next character isn't a word character + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + { + if(m_match_flags & match_not_bow) + return false; // no previous input + } + else + { + // otherwise inside buffer: + BidiIterator t(position); + --t; + if(traits_inst.isctype(*t, m_word_mask)) + return false; // previous character not non-word + } + // OK we have a match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_word_end() +{ + if((position == backstop) && ((m_match_flags & match_prev_avail) == 0)) + return false; // start of buffer can't be end of word + BidiIterator t(position); + --t; + if(traits_inst.isctype(*t, m_word_mask) == false) + return false; // previous character wasn't a word character + + if(position == last) + { + if(m_match_flags & match_not_eow) + return false; // end of buffer but not end of word + } + else + { + // otherwise inside buffer: + if(traits_inst.isctype(*position, m_word_mask)) + return false; // next character is a word character + } + pstate = pstate->next.p; + return true; // if we fall through to here then we've succeeded +} + +template +bool perl_matcher::match_buffer_start() +{ + if((position != backstop) || (m_match_flags & match_not_bob)) + return false; + // OK match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_buffer_end() +{ + if((position != last) || (m_match_flags & match_not_eob)) + return false; + // OK match: + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_backref() +{ + // + // Compare with what we previously matched. + // Note that this succeeds if the backref did not partisipate + // in the match, this is in line with ECMAScript, but not Perl + // or PCRE. + // + int index = static_cast(pstate)->index; + if(index >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(index); + BOOST_REGEX_ASSERT(r.first != r.second); + do + { + index = r.first->index; + ++r.first; + }while((r.first != r.second) && ((*m_presult)[index].matched != true)); + } + + if((m_match_flags & match_perl) && !(*m_presult)[index].matched) + return false; + + BidiIterator i = (*m_presult)[index].first; + BidiIterator j = (*m_presult)[index].second; + while(i != j) + { + if((position == last) || (traits_inst.translate(*position, icase) != traits_inst.translate(*i, icase))) + return false; + ++i; + ++position; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_long_set() +{ + typedef typename traits::char_class_type char_class_type; + // let the traits class do the work: + if(position == last) + return false; + BidiIterator t = re_is_set_member(position, last, static_cast*>(pstate), re.get_data(), icase); + if(t != position) + { + pstate = pstate->next.p; + position = t; + return true; + } + return false; +} + +template +bool perl_matcher::match_set() +{ + if(position == last) + return false; + if(static_cast(pstate)->_map[static_cast(traits_inst.translate(*position, icase))]) + { + pstate = pstate->next.p; + ++position; + return true; + } + return false; +} + +template +bool perl_matcher::match_jump() +{ + pstate = static_cast(pstate)->alt.p; + return true; +} + +template +bool perl_matcher::match_combining() +{ + if(position == last) + return false; + if(is_combining(traits_inst.translate(*position, icase))) + return false; + ++position; + while((position != last) && is_combining(traits_inst.translate(*position, icase))) + ++position; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_soft_buffer_end() +{ + if(m_match_flags & match_not_eob) + return false; + BidiIterator p(position); + while((p != last) && is_separator(traits_inst.translate(*p, icase)))++p; + if(p != last) + return false; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_restart_continue() +{ + if(position == search_base) + { + pstate = pstate->next.p; + return true; + } + return false; +} + +template +bool perl_matcher::match_backstep() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + if( ::boost::is_random_access_iterator::value) + { + std::ptrdiff_t maxlen = std::distance(backstop, position); + if(maxlen < static_cast(pstate)->index) + return false; + std::advance(position, -static_cast(pstate)->index); + } + else + { + int c = static_cast(pstate)->index; + while(c--) + { + if(position == backstop) + return false; + --position; + } + } + pstate = pstate->next.p; + return true; +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +inline bool perl_matcher::match_assert_backref() +{ + // return true if marked sub-expression N has been matched: + int index = static_cast(pstate)->index; + bool result = false; + if(index == 9999) + { + // Magic value for a (DEFINE) block: + return false; + } + else if(index > 0) + { + // Have we matched subexpression "index"? + // Check if index is a hash value: + if(index >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(index); + while(r.first != r.second) + { + if((*m_presult)[r.first->index].matched) + { + result = true; + break; + } + ++r.first; + } + } + else + { + result = (*m_presult)[index].matched; + } + pstate = pstate->next.p; + } + else + { + // Have we recursed into subexpression "index"? + // If index == 0 then check for any recursion at all, otherwise for recursion to -index-1. + int idx = -(index+1); + if(idx >= hash_value_mask) + { + named_subexpressions::range_type r = re.get_data().equal_range(idx); + int stack_index = recursion_stack.empty() ? -1 : recursion_stack.back().idx; + while(r.first != r.second) + { + result |= (stack_index == r.first->index); + if(result)break; + ++r.first; + } + } + else + { + result = !recursion_stack.empty() && ((recursion_stack.back().idx == idx) || (index == 0)); + } + pstate = pstate->next.p; + } + return result; +} + +template +bool perl_matcher::match_fail() +{ + // Just force a backtrack: + return false; +} + +template +bool perl_matcher::match_accept() +{ + if(!recursion_stack.empty()) + { + return skip_until_paren(recursion_stack.back().idx); + } + else + { + return skip_until_paren(INT_MAX); + } +} + +template +bool perl_matcher::find_restart_any() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + const unsigned char* _map = re.get_map(); + while(true) + { + // skip everything we can't match: + while((position != last) && !can_start(*position, _map, (unsigned char)mask_any) ) + ++position; + if(position == last) + { + // run out of characters, try a null match if possible: + if(re.can_be_null()) + return match_prefix(); + break; + } + // now try and obtain a match: + if(match_prefix()) + return true; + if(position == last) + return false; + ++position; + } + return false; +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::find_restart_word() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif + // do search optimised for word starts: + const unsigned char* _map = re.get_map(); + if((m_match_flags & match_prev_avail) || (position != base)) + --position; + else if(match_prefix()) + return true; + do + { + while((position != last) && traits_inst.isctype(*position, m_word_mask)) + ++position; + while((position != last) && !traits_inst.isctype(*position, m_word_mask)) + ++position; + if(position == last) + break; + + if(can_start(*position, _map, (unsigned char)mask_any) ) + { + if(match_prefix()) + return true; + } + if(position == last) + break; + } while(true); + return false; +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::find_restart_line() +{ + // do search optimised for line starts: + const unsigned char* _map = re.get_map(); + if(match_prefix()) + return true; + while(position != last) + { + while((position != last) && !is_separator(*position)) + ++position; + if(position == last) + return false; + ++position; + if(position == last) + { + if(re.can_be_null() && match_prefix()) + return true; + return false; + } + + if( can_start(*position, _map, (unsigned char)mask_any) ) + { + if(match_prefix()) + return true; + } + if(position == last) + return false; + //++position; + } + return false; +} + +template +bool perl_matcher::find_restart_buf() +{ + if((position == base) && ((m_match_flags & match_not_bob) == 0)) + return match_prefix(); + return false; +} + +template +bool perl_matcher::find_restart_lit() +{ + return false; +} + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/perl_matcher_non_recursive.hpp b/third-party/boost_regex/include/boost/regex/v5/perl_matcher_non_recursive.hpp new file mode 100644 index 0000000000..28d6c462fe --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/perl_matcher_non_recursive.hpp @@ -0,0 +1,1874 @@ +/* + * + * Copyright (c) 2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE perl_matcher_common.cpp + * VERSION see + * DESCRIPTION: Definitions of perl_matcher member functions that are + * specific to the non-recursive implementation. + */ + +#ifndef BOOST_REGEX_V5_PERL_MATCHER_NON_RECURSIVE_HPP +#define BOOST_REGEX_V5_PERL_MATCHER_NON_RECURSIVE_HPP + +#include + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +# pragma warning(disable: 4706 4459) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +template +inline void inplace_destroy(T* p) +{ + (void)p; // warning suppression + p->~T(); +} + +struct saved_state +{ + union{ + unsigned int state_id; + // this padding ensures correct alignment on 64-bit platforms: + std::size_t padding1; + std::ptrdiff_t padding2; + void* padding3; + }; + saved_state(unsigned i) : state_id(i) {} +}; + +template +struct saved_matched_paren : public saved_state +{ + int index; + sub_match sub; + saved_matched_paren(int i, const sub_match& s) : saved_state(1), index(i), sub(s){} +}; + +template +struct saved_position : public saved_state +{ + const re_syntax_base* pstate; + BidiIterator position; + saved_position(const re_syntax_base* ps, BidiIterator pos, int i) : saved_state(i), pstate(ps), position(pos){} +}; + +template +struct saved_assertion : public saved_position +{ + bool positive; + saved_assertion(bool p, const re_syntax_base* ps, BidiIterator pos) + : saved_position(ps, pos, saved_type_assertion), positive(p){} +}; + +template +struct saved_repeater : public saved_state +{ + repeater_count count; + saved_repeater(int i, repeater_count** s, BidiIterator start, int current_recursion_id) + : saved_state(saved_state_repeater_count), count(i, s, start, current_recursion_id){} +}; + +struct saved_extra_block : public saved_state +{ + saved_state *base, *end; + saved_extra_block(saved_state* b, saved_state* e) + : saved_state(saved_state_extra_block), base(b), end(e) {} +}; + +struct save_state_init +{ + saved_state** stack; + save_state_init(saved_state** base, saved_state** end) + : stack(base) + { + *base = static_cast(get_mem_block()); + *end = reinterpret_cast(reinterpret_cast(*base)+BOOST_REGEX_BLOCKSIZE); + --(*end); + (void) new (*end)saved_state(0); + BOOST_REGEX_ASSERT(*end > *base); + } + ~save_state_init() + { + put_mem_block(*stack); + *stack = 0; + } +}; + +template +struct saved_single_repeat : public saved_state +{ + std::size_t count; + const re_repeat* rep; + BidiIterator last_position; + saved_single_repeat(std::size_t c, const re_repeat* r, BidiIterator lp, int arg_id) + : saved_state(arg_id), count(c), rep(r), last_position(lp){} +}; + +template +struct saved_recursion : public saved_state +{ + saved_recursion(int idx, const re_syntax_base* p, Results* pr, Results* pr2) + : saved_state(14), recursion_id(idx), preturn_address(p), internal_results(*pr), prior_results(*pr2) {} + int recursion_id; + const re_syntax_base* preturn_address; + Results internal_results, prior_results; +}; + +struct saved_change_case : public saved_state +{ + bool icase; + saved_change_case(bool c) : saved_state(18), icase(c) {} +}; + +struct incrementer +{ + incrementer(unsigned* pu) : m_pu(pu) { ++*m_pu; } + ~incrementer() { --*m_pu; } + bool operator > (unsigned i) { return *m_pu > i; } +private: + unsigned* m_pu; +}; + +template +bool perl_matcher::match_all_states() +{ + static matcher_proc_type const s_match_vtable[34] = + { + (&perl_matcher::match_startmark), + &perl_matcher::match_endmark, + &perl_matcher::match_literal, + &perl_matcher::match_start_line, + &perl_matcher::match_end_line, + &perl_matcher::match_wild, + &perl_matcher::match_match, + &perl_matcher::match_word_boundary, + &perl_matcher::match_within_word, + &perl_matcher::match_word_start, + &perl_matcher::match_word_end, + &perl_matcher::match_buffer_start, + &perl_matcher::match_buffer_end, + &perl_matcher::match_backref, + &perl_matcher::match_long_set, + &perl_matcher::match_set, + &perl_matcher::match_jump, + &perl_matcher::match_alt, + &perl_matcher::match_rep, + &perl_matcher::match_combining, + &perl_matcher::match_soft_buffer_end, + &perl_matcher::match_restart_continue, + // Although this next line *should* be evaluated at compile time, in practice + // some compilers (VC++) emit run-time initialisation which breaks thread + // safety, so use a dispatch function instead: + //(::boost::is_random_access_iterator::value ? &perl_matcher::match_dot_repeat_fast : &perl_matcher::match_dot_repeat_slow), + &perl_matcher::match_dot_repeat_dispatch, + &perl_matcher::match_char_repeat, + &perl_matcher::match_set_repeat, + &perl_matcher::match_long_set_repeat, + &perl_matcher::match_backstep, + &perl_matcher::match_assert_backref, + &perl_matcher::match_toggle_case, + &perl_matcher::match_recursion, + &perl_matcher::match_fail, + &perl_matcher::match_accept, + &perl_matcher::match_commit, + &perl_matcher::match_then, + }; + incrementer inc(&m_recursions); + if(inc > 80) + raise_error(traits_inst, regex_constants::error_complexity); + push_recursion_stopper(); + do{ + while(pstate) + { + matcher_proc_type proc = s_match_vtable[pstate->type]; + ++state_count; + if(!(this->*proc)()) + { + if(state_count > max_state_count) + raise_error(traits_inst, regex_constants::error_complexity); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + bool successful_unwind = unwind(false); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(!successful_unwind) + return m_recursive_result; + } + } + }while(unwind(true)); + return m_recursive_result; +} + +template +void perl_matcher::extend_stack() +{ + if(used_block_count) + { + --used_block_count; + saved_state* stack_base; + saved_state* backup_state; + stack_base = static_cast(get_mem_block()); + backup_state = reinterpret_cast(reinterpret_cast(stack_base)+BOOST_REGEX_BLOCKSIZE); + saved_extra_block* block = static_cast(backup_state); + --block; + (void) new (block) saved_extra_block(m_stack_base, m_backup_state); + m_stack_base = stack_base; + m_backup_state = block; + } + else + raise_error(traits_inst, regex_constants::error_stack); +} + +template +inline void perl_matcher::push_matched_paren(int index, const sub_match& sub) +{ + //BOOST_REGEX_ASSERT(index); + saved_matched_paren* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_matched_paren(index, sub); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_case_change(bool c) +{ + //BOOST_REGEX_ASSERT(index); + saved_change_case* pmp = static_cast(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast(m_backup_state); + --pmp; + } + (void) new (pmp)saved_change_case(c); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_recursion_stopper() +{ + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(saved_type_recurse); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_assertion(const re_syntax_base* ps, bool positive) +{ + saved_assertion* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_assertion(positive, ps, position); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_alt(const re_syntax_base* ps) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_position(ps, position, saved_state_alt); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_non_greedy_repeat(const re_syntax_base* ps) +{ + saved_position* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_position(ps, position, saved_state_non_greedy_long_repeat); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_repeater_count(int i, repeater_count** s) +{ + saved_repeater* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_repeater(i, s, position, this->recursion_stack.empty() ? (INT_MIN + 3) : this->recursion_stack.back().idx); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_single_repeat(std::size_t c, const re_repeat* r, BidiIterator last_position, int state_id) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_single_repeat(c, r, last_position, state_id); + m_backup_state = pmp; +} + +template +inline void perl_matcher::push_recursion(int idx, const re_syntax_base* p, results_type* presults, results_type* presults2) +{ + saved_recursion* pmp = static_cast*>(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast*>(m_backup_state); + --pmp; + } + (void) new (pmp)saved_recursion(idx, p, presults, presults2); + m_backup_state = pmp; +} + +template +bool perl_matcher::match_toggle_case() +{ + // change our case sensitivity: + push_case_change(this->icase); + this->icase = static_cast(pstate)->icase; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_startmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + switch(index) + { + case 0: + pstate = pstate->next.p; + break; + case -1: + case -2: + { + // forward lookahead assert: + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + push_assertion(next_pstate, index == -1); + break; + } + case -3: + { + // independent sub-expression, currently this is always recursive: + bool old_independent = m_independent; + m_independent = true; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; + bool r = false; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + r = match_all_states(); + if(!r && !m_independent) + { + // Must be unwinding from a COMMIT/SKIP/PRUNE and the independent + // sub failed, need to unwind everything else: + while (m_backup_state->state_id) + unwind(false); + return false; + } +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)) {} + throw; + } +#endif + pstate = next_pstate; + m_independent = old_independent; +#ifdef BOOST_REGEX_MATCH_EXTRA + if(r && (m_match_flags & match_extra)) + { + // + // our captures have been stored in *m_presult + // we need to unpack them, and insert them + // back in the right order when we unwind the stack: + // + match_results temp_match(*m_presult); + unsigned i; + for(i = 0; i < temp_match.size(); ++i) + (*m_presult)[i].get_captures().clear(); + // match everything else: +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + r = match_all_states(); +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)) {} + throw; + } +#endif + // now place the stored captures back: + for(i = 0; i < temp_match.size(); ++i) + { + typedef typename sub_match::capture_sequence_type seq; + seq& s1 = (*m_presult)[i].get_captures(); + const seq& s2 = temp_match[i].captures(); + s1.insert( + s1.end(), + s2.begin(), + s2.end()); + } + } +#endif + return r; + } + case -4: + { + // conditional expression: + const re_alt* alt = static_cast(pstate->next.p); + BOOST_REGEX_ASSERT(alt->type == syntax_element_alt); + pstate = alt->next.p; + if(pstate->type == syntax_element_assert_backref) + { + if(!match_assert_backref()) + pstate = alt->alt.p; + break; + } + else + { + // zero width assertion, have to match this recursively: + BOOST_REGEX_ASSERT(pstate->type == syntax_element_startmark); + bool negated = static_cast(pstate)->index == -2; + BidiIterator saved_position = position; + const re_syntax_base* next_pstate = static_cast(pstate->next.p)->alt.p->next.p; + pstate = pstate->next.p->next.p; +#if !defined(BOOST_NO_EXCEPTIONS) + try{ +#endif + bool r = match_all_states(); + position = saved_position; + if(negated) + r = !r; + if(r) + pstate = next_pstate; + else + pstate = alt->alt.p; +#if !defined(BOOST_NO_EXCEPTIONS) + } + catch(...) + { + pstate = next_pstate; + // unwind all pushed states, apart from anything else this + // ensures that all the states are correctly destructed + // not just the memory freed. + while(unwind(true)){} + throw; + } +#endif + break; + } + } + case -5: + { + push_matched_paren(0, (*m_presult)[0]); + m_presult->set_first(position, 0, true); + pstate = pstate->next.p; + break; + } + default: + { + BOOST_REGEX_ASSERT(index > 0); + if((m_match_flags & match_nosubs) == 0) + { + push_matched_paren(index, (*m_presult)[index]); + m_presult->set_first(position, index); + } + pstate = pstate->next.p; + break; + } + } + return true; +} + +template +bool perl_matcher::match_alt() +{ + bool take_first, take_second; + const re_alt* jmp = static_cast(pstate); + + // find out which of these two alternatives we need to take: + if(position == last) + { + take_first = jmp->can_be_null & mask_take; + take_second = jmp->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, jmp->_map, (unsigned char)mask_take); + take_second = can_start(*position, jmp->_map, (unsigned char)mask_skip); + } + + if(take_first) + { + // we can take the first alternative, + // see if we need to push next alternative: + if(take_second) + { + push_alt(jmp->alt.p); + } + pstate = pstate->next.p; + return true; + } + if(take_second) + { + pstate = jmp->alt.p; + return true; + } + return false; // neither option is possible +} + +template +bool perl_matcher::match_rep() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127 4244) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + + // find out which of these two alternatives we need to take: + bool take_first, take_second; + if(position == last) + { + take_first = rep->can_be_null & mask_take; + take_second = rep->can_be_null & mask_skip; + } + else + { + take_first = can_start(*position, rep->_map, (unsigned char)mask_take); + take_second = can_start(*position, rep->_map, (unsigned char)mask_skip); + } + + if((m_backup_state->state_id != saved_state_repeater_count) + || (static_cast*>(m_backup_state)->count.get_id() != rep->state_id) + || (next_count->get_id() != rep->state_id)) + { + // we're moving to a different repeat from the last + // one, so set up a counter object: + push_repeater_count(rep->state_id, &next_count); + } + // + // If we've had at least one repeat already, and the last one + // matched the NULL string then set the repeat count to + // maximum: + // + next_count->check_null_repeat(position, rep->max); + + if(next_count->get_count() < rep->min) + { + // we must take the repeat: + if(take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + return false; + } + + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // try and take the repeat if we can: + if((next_count->get_count() < rep->max) && take_first) + { + if(take_second) + { + // store position in case we fail: + push_alt(rep->alt.p); + } + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + else if(take_second) + { + pstate = rep->alt.p; + return true; + } + return false; // can't take anything, fail... + } + else // non-greedy + { + // try and skip the repeat if we can: + if(take_second) + { + if((next_count->get_count() < rep->max) && take_first) + { + // store position in case we fail: + push_non_greedy_repeat(rep->next.p); + } + pstate = rep->alt.p; + return true; + } + if((next_count->get_count() < rep->max) && take_first) + { + // increase the counter: + ++(*next_count); + pstate = rep->next.p; + return true; + } + } + return false; +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_dot_repeat_slow() +{ + std::size_t count = 0; + const re_repeat* rep = static_cast(pstate); + re_syntax_base* psingle = rep->next.p; + // match compulsory repeats first: + while(count < rep->min) + { + pstate = psingle; + if(!match_wild()) + return false; + ++count; + } + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + if(greedy) + { + // repeat for as long as we can: + while(count < rep->max) + { + pstate = psingle; + if(!match_wild()) + break; + ++count; + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_slow_dot); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +} + +template +bool perl_matcher::match_dot_repeat_fast() +{ + if(m_match_flags & match_not_dot_null) + return match_dot_repeat_slow(); + if((static_cast(pstate->next.p)->mask & match_any_mask) == 0) + return match_dot_repeat_slow(); + + const re_repeat* rep = static_cast(pstate); + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t count = static_cast((std::min)(static_cast(std::distance(position, last)), greedy ? rep->max : rep->min)); + if(rep->min > count) + { + position = last; + return false; // not enough text left to match + } + std::advance(position, count); + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_fast_dot); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +} + +template +bool perl_matcher::match_char_repeat() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + BOOST_REGEX_ASSERT(1 == static_cast(rep->next.p)->length); + const char_type what = *reinterpret_cast(static_cast(rep->next.p) + 1); + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : std::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && (traits_inst.translate(*position, icase) == what)) + { + ++position; + } + count = (unsigned)std::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && (traits_inst.translate(*position, icase) == what)) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_char); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_set_repeat() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + const re_repeat* rep = static_cast(pstate); + const unsigned char* map = static_cast(rep->next.p)->_map; + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : std::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + } + count = (unsigned)std::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && map[static_cast(traits_inst.translate(*position, icase))]) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_short_set); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_long_set_repeat() +{ +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4127) +#endif +#ifdef BOOST_BORLANDC +#pragma option push -w-8008 -w-8066 -w-8004 +#endif + typedef typename traits::char_class_type m_type; + const re_repeat* rep = static_cast(pstate); + const re_set_long* set = static_cast*>(pstate->next.p); + std::size_t count = 0; + // + // start by working out how much we can skip: + // + bool greedy = (rep->greedy) && (!(m_match_flags & regex_constants::match_any) || m_independent); + std::size_t desired = greedy ? rep->max : rep->min; + if(::boost::is_random_access_iterator::value) + { + BidiIterator end = position; + // Move end forward by "desired", preferably without using distance or advance if we can + // as these can be slow for some iterator types. + std::size_t len = (desired == (std::numeric_limits::max)()) ? 0u : std::distance(position, last); + if(desired >= len) + end = last; + else + std::advance(end, desired); + BidiIterator origin(position); + while((position != end) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + } + count = (unsigned)std::distance(origin, position); + } + else + { + while((count < desired) && (position != last) && (position != re_is_set_member(position, last, set, re.get_data(), icase))) + { + ++position; + ++count; + } + } + + if(count < rep->min) + return false; + + if(greedy) + { + if((rep->leading) && (count < rep->max)) + restart = position; + // push backtrack info if available: + if(count - rep->min) + push_single_repeat(count, rep, position, saved_state_greedy_single_repeat); + // jump to next state: + pstate = rep->alt.p; + return true; + } + else + { + // non-greedy, push state and return true if we can skip: + if(count < rep->max) + push_single_repeat(count, rep, position, saved_state_rep_long_set); + pstate = rep->alt.p; + return (position == last) ? (rep->can_be_null & mask_skip) : can_start(*position, rep->_map, mask_skip); + } +#ifdef BOOST_BORLANDC +#pragma option pop +#endif +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif +} + +template +bool perl_matcher::match_recursion() +{ + BOOST_REGEX_ASSERT(pstate->type == syntax_element_recurse); + // + // See if we've seen this recursion before at this location, if we have then + // we need to prevent infinite recursion: + // + for(typename std::vector >::reverse_iterator i = recursion_stack.rbegin(); i != recursion_stack.rend(); ++i) + { + if(i->idx == static_cast(static_cast(pstate)->alt.p)->index) + { + if(i->location_of_start == position) + return false; + break; + } + } + // + // Backup call stack: + // + push_recursion_pop(); + // + // Set new call stack: + // + if(recursion_stack.capacity() == 0) + { + recursion_stack.reserve(50); + } + recursion_stack.push_back(recursion_info()); + recursion_stack.back().preturn_address = pstate->next.p; + recursion_stack.back().results = *m_presult; + pstate = static_cast(pstate)->alt.p; + recursion_stack.back().idx = static_cast(pstate)->index; + recursion_stack.back().location_of_start = position; + //if(static_cast(pstate)->state_id > 0) + { + push_repeater_count(-(2 + static_cast(pstate)->index), &next_count); + } + + return true; +} + +template +bool perl_matcher::match_endmark() +{ + int index = static_cast(pstate)->index; + icase = static_cast(pstate)->icase; + if(index > 0) + { + if((m_match_flags & match_nosubs) == 0) + { + m_presult->set_second(position, index); + } + if(!recursion_stack.empty()) + { + if(index == recursion_stack.back().idx) + { + pstate = recursion_stack.back().preturn_address; + *m_presult = recursion_stack.back().results; + push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results); + recursion_stack.pop_back(); + push_repeater_count(-(2 + index), &next_count); + } + } + } + else if((index < 0) && (index != -4)) + { + // matched forward lookahead: + pstate = 0; + return true; + } + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_match() +{ + if(!recursion_stack.empty()) + { + BOOST_REGEX_ASSERT(0 == recursion_stack.back().idx); + pstate = recursion_stack.back().preturn_address; + push_recursion(recursion_stack.back().idx, recursion_stack.back().preturn_address, m_presult, &recursion_stack.back().results); + *m_presult = recursion_stack.back().results; + recursion_stack.pop_back(); + return true; + } + if((m_match_flags & match_not_null) && (position == (*m_presult)[0].first)) + return false; + if((m_match_flags & match_all) && (position != last)) + return false; + if((m_match_flags & regex_constants::match_not_initial_null) && (position == search_base)) + return false; + m_presult->set_second(position); + pstate = 0; + m_has_found_match = true; + if((m_match_flags & match_posix) == match_posix) + { + m_result.maybe_assign(*m_presult); + if((m_match_flags & match_any) == 0) + return false; + } +#ifdef BOOST_REGEX_MATCH_EXTRA + if(match_extra & m_match_flags) + { + for(unsigned i = 0; i < m_presult->size(); ++i) + if((*m_presult)[i].matched) + ((*m_presult)[i]).get_captures().push_back((*m_presult)[i]); + } +#endif + return true; +} + +template +bool perl_matcher::match_commit() +{ + // Ideally we would just junk all the states that are on the stack, + // however we might not unwind correctly in that case, so for now, + // just mark that we don't backtrack into whatever is left (or rather + // we'll unwind it unconditionally without pausing to try other matches). + + switch(static_cast(pstate)->action) + { + case commit_commit: + restart = last; + break; + case commit_skip: + if(base != position) + { + restart = position; + // Have to decrement restart since it will get incremented again later: + --restart; + } + break; + case commit_prune: + break; + } + + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(16); + m_backup_state = pmp; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::match_then() +{ + // Just leave a mark that we need to skip to next alternative: + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(17); + m_backup_state = pmp; + pstate = pstate->next.p; + return true; +} + +template +bool perl_matcher::skip_until_paren(int index, bool have_match) +{ + while(pstate) + { + if(pstate->type == syntax_element_endmark) + { + if(static_cast(pstate)->index == index) + { + if(have_match) + return this->match_endmark(); + pstate = pstate->next.p; + return true; + } + else + { + // Unenclosed closing ), occurs when (*ACCEPT) is inside some other + // parenthesis which may or may not have other side effects associated with it. + const re_syntax_base* sp = pstate; + match_endmark(); + if(!pstate) + { + unwind(true); + // unwind may leave pstate NULL if we've unwound a forward lookahead, in which + // case just move to the next state and keep looking... + if (!pstate) + pstate = sp->next.p; + } + } + continue; + } + else if(pstate->type == syntax_element_match) + return true; + else if(pstate->type == syntax_element_startmark) + { + int idx = static_cast(pstate)->index; + pstate = pstate->next.p; + skip_until_paren(idx, false); + continue; + } + pstate = pstate->next.p; + } + return true; +} + +/**************************************************************************** + +Unwind and associated procedures follow, these perform what normal stack +unwinding does in the recursive implementation. + +****************************************************************************/ + +template +bool perl_matcher::unwind(bool have_match) +{ + static unwind_proc_type const s_unwind_table[19] = + { + &perl_matcher::unwind_end, + &perl_matcher::unwind_paren, + &perl_matcher::unwind_recursion_stopper, + &perl_matcher::unwind_assertion, + &perl_matcher::unwind_alt, + &perl_matcher::unwind_repeater_counter, + &perl_matcher::unwind_extra_block, + &perl_matcher::unwind_greedy_single_repeat, + &perl_matcher::unwind_slow_dot_repeat, + &perl_matcher::unwind_fast_dot_repeat, + &perl_matcher::unwind_char_repeat, + &perl_matcher::unwind_short_set_repeat, + &perl_matcher::unwind_long_set_repeat, + &perl_matcher::unwind_non_greedy_repeat, + &perl_matcher::unwind_recursion, + &perl_matcher::unwind_recursion_pop, + &perl_matcher::unwind_commit, + &perl_matcher::unwind_then, + &perl_matcher::unwind_case, + }; + + m_recursive_result = have_match; + m_unwound_lookahead = false; + m_unwound_alt = false; + unwind_proc_type unwinder; + bool cont; + // + // keep unwinding our stack until we have something to do: + // + do + { + unwinder = s_unwind_table[m_backup_state->state_id]; + cont = (this->*unwinder)(m_recursive_result); + }while(cont); + // + // return true if we have more states to try: + // + return pstate ? true : false; +} + +template +bool perl_matcher::unwind_end(bool) +{ + pstate = 0; // nothing left to search + return false; // end of stack nothing more to search +} + +template +bool perl_matcher::unwind_case(bool) +{ + saved_change_case* pmp = static_cast(m_backup_state); + icase = pmp->icase; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +bool perl_matcher::unwind_paren(bool have_match) +{ + saved_matched_paren* pmp = static_cast*>(m_backup_state); + // restore previous values if no match was found: + if(!have_match) + { + m_presult->set_first(pmp->sub.first, pmp->index, pmp->index == 0); + m_presult->set_second(pmp->sub.second, pmp->index, pmp->sub.matched, pmp->index == 0); + } +#ifdef BOOST_REGEX_MATCH_EXTRA + // + // we have a match, push the capture information onto the stack: + // + else if(pmp->sub.matched && (match_extra & m_match_flags)) + ((*m_presult)[pmp->index]).get_captures().push_back(pmp->sub); +#endif + // unwind stack: + m_backup_state = pmp+1; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp); + return true; // keep looking +} + +template +bool perl_matcher::unwind_recursion_stopper(bool) +{ + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + pstate = 0; // nothing left to search + return false; // end of stack nothing more to search +} + +template +bool perl_matcher::unwind_assertion(bool r) +{ + saved_assertion* pmp = static_cast*>(m_backup_state); + pstate = pmp->pstate; + position = pmp->position; + bool result = (r == pmp->positive); + m_recursive_result = pmp->positive ? r : !r; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + m_unwound_lookahead = true; + return !result; // return false if the assertion was matched to stop search. +} + +template +bool perl_matcher::unwind_alt(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + pstate = pmp->pstate; + position = pmp->position; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + m_unwound_alt = !r; + return r; +} + +template +bool perl_matcher::unwind_repeater_counter(bool) +{ + saved_repeater* pmp = static_cast*>(m_backup_state); + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; // keep looking +} + +template +bool perl_matcher::unwind_extra_block(bool) +{ + ++used_block_count; + saved_extra_block* pmp = static_cast(m_backup_state); + void* condemmed = m_stack_base; + m_stack_base = pmp->base; + m_backup_state = pmp->end; + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp); + put_mem_block(condemmed); + return true; // keep looking +} + +template +inline void perl_matcher::destroy_single_repeat() +{ + saved_single_repeat* p = static_cast*>(m_backup_state); + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(p++); + m_backup_state = p; +} + +template +bool perl_matcher::unwind_greedy_single_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + + count -= rep->min; + + if((m_match_flags & match_partial) && (position == last)) + m_has_partial_match = true; + + BOOST_REGEX_ASSERT(count); + position = pmp->last_position; + + // backtrack till we can skip out: + do + { + --position; + --count; + ++state_count; + }while(count && !can_start(*position, rep->_map, mask_skip)); + + // if we've hit base, destroy this state: + if(count == 0) + { + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count + rep->min; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_slow_dot_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + BOOST_REGEX_ASSERT(rep->type == syntax_element_dot_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_wild); + + BOOST_REGEX_ASSERT(count < rep->max); + pstate = rep->next.p; + position = pmp->last_position; + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(!match_wild()) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_fast_dot_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + + BOOST_REGEX_ASSERT(count < rep->max); + position = pmp->last_position; + if(position != last) + { + + // wind forward until we can skip out of the repeat: + do + { + ++position; + ++count; + ++state_count; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_char_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const char_type what = *reinterpret_cast(static_cast(pstate) + 1); + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_char_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_literal); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(traits_inst.translate(*position, icase) != what) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++ position; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_short_set_repeat(bool r) +{ + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const unsigned char* map = static_cast(rep->next.p)->_map; + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_short_set_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_set); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(!map[static_cast(traits_inst.translate(*position, icase))]) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++count; + ++ position; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_long_set_repeat(bool r) +{ + typedef typename traits::char_class_type m_type; + saved_single_repeat* pmp = static_cast*>(m_backup_state); + + // if we have a match, just discard this state: + if(r) + { + destroy_single_repeat(); + return true; + } + + const re_repeat* rep = pmp->rep; + std::size_t count = pmp->count; + pstate = rep->next.p; + const re_set_long* set = static_cast*>(pstate); + position = pmp->last_position; + + BOOST_REGEX_ASSERT(rep->type == syntax_element_long_set_rep); + BOOST_REGEX_ASSERT(rep->next.p != 0); + BOOST_REGEX_ASSERT(rep->alt.p != 0); + BOOST_REGEX_ASSERT(rep->next.p->type == syntax_element_long_set); + BOOST_REGEX_ASSERT(count < rep->max); + + if(position != last) + { + // wind forward until we can skip out of the repeat: + do + { + if(position == re_is_set_member(position, last, set, re.get_data(), icase)) + { + // failed repeat match, discard this state and look for another: + destroy_single_repeat(); + return true; + } + ++position; + ++count; + ++state_count; + pstate = rep->next.p; + }while((count < rep->max) && (position != last) && !can_start(*position, rep->_map, mask_skip)); + } + // remember where we got to if this is a leading repeat: + if((rep->leading) && (count < rep->max)) + restart = position; + if(position == last) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if((m_match_flags & match_partial) && (position == last) && (position != search_base)) + m_has_partial_match = true; + if(0 == (rep->can_be_null & mask_skip)) + return true; + } + else if(count == rep->max) + { + // can't repeat any more, remove the pushed state: + destroy_single_repeat(); + if(!can_start(*position, rep->_map, mask_skip)) + return true; + } + else + { + pmp->count = count; + pmp->last_position = position; + } + pstate = rep->alt.p; + return false; +} + +template +bool perl_matcher::unwind_non_greedy_repeat(bool r) +{ + saved_position* pmp = static_cast*>(m_backup_state); + if(!r) + { + position = pmp->position; + pstate = pmp->pstate; + ++(*next_count); + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return r; +} + +template +bool perl_matcher::unwind_recursion(bool r) +{ + // We are backtracking back inside a recursion, need to push the info + // back onto the recursion stack, and do so unconditionally, otherwise + // we can get mismatched pushes and pops... + saved_recursion* pmp = static_cast*>(m_backup_state); + if (!r) + { + recursion_stack.push_back(recursion_info()); + recursion_stack.back().idx = pmp->recursion_id; + recursion_stack.back().preturn_address = pmp->preturn_address; + recursion_stack.back().results = pmp->prior_results; + recursion_stack.back().location_of_start = position; + *m_presult = pmp->internal_results; + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +bool perl_matcher::unwind_recursion_pop(bool r) +{ + // Backtracking out of a recursion, we must pop state off the recursion + // stack unconditionally to ensure matched pushes and pops: + saved_state* pmp = static_cast(m_backup_state); + if (!r && !recursion_stack.empty()) + { + *m_presult = recursion_stack.back().results; + position = recursion_stack.back().location_of_start; + recursion_stack.pop_back(); + } + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(pmp++); + m_backup_state = pmp; + return true; +} + +template +void perl_matcher::push_recursion_pop() +{ + saved_state* pmp = static_cast(m_backup_state); + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = static_cast(m_backup_state); + --pmp; + } + (void) new (pmp)saved_state(15); + m_backup_state = pmp; +} + +template +bool perl_matcher::unwind_commit(bool b) +{ + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + while(unwind(b) && !m_unwound_lookahead){} + if(m_unwound_lookahead && pstate) + { + // + // If we stop because we just unwound an assertion, put the + // commit state back on the stack again: + // + m_unwound_lookahead = false; + saved_state* pmp = m_backup_state; + --pmp; + if(pmp < m_stack_base) + { + extend_stack(); + pmp = m_backup_state; + --pmp; + } + (void) new (pmp)saved_state(16); + m_backup_state = pmp; + } + // This prevents us from stopping when we exit from an independent sub-expression: + m_independent = false; + return false; +} + +template +bool perl_matcher::unwind_then(bool b) +{ + // Unwind everything till we hit an alternative: + boost::BOOST_REGEX_DETAIL_NS::inplace_destroy(m_backup_state++); + bool result = false; + result = unwind(b); + while(result && !m_unwound_alt) + { + result = unwind(b); + } + // We're now pointing at the next alternative, need one more backtrack + // since *all* the other alternatives must fail once we've reached a THEN clause: + if(result && m_unwound_alt) + unwind(b); + return false; +} + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/primary_transform.hpp b/third-party/boost_regex/include/boost/regex/v5/primary_transform.hpp new file mode 100644 index 0000000000..ed46f39221 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/primary_transform.hpp @@ -0,0 +1,120 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE: primary_transform.hpp + * VERSION: see + * DESCRIPTION: Heuristically determines the sort string format in use + * by the current locale. + */ + +#ifndef BOOST_REGEX_PRIMARY_TRANSFORM +#define BOOST_REGEX_PRIMARY_TRANSFORM + +namespace boost{ + namespace BOOST_REGEX_DETAIL_NS{ + + +enum{ + sort_C, + sort_fixed, + sort_delim, + sort_unknown +}; + +template +unsigned count_chars(const S& s, charT c) +{ + // + // Count how many occurrences of character c occur + // in string s: if c is a delimeter between collation + // fields, then this should be the same value for all + // sort keys: + // + unsigned int count = 0; + for(unsigned pos = 0; pos < s.size(); ++pos) + { + if(s[pos] == c) ++count; + } + return count; +} + + +template +unsigned find_sort_syntax(const traits* pt, charT* delim) +{ + // + // compare 'a' with 'A' to see how similar they are, + // should really use a-accute but we can't portably do that, + // + typedef typename traits::string_type string_type; + typedef typename traits::char_type char_type; + + // Suppress incorrect warning for MSVC + (void)pt; + + char_type a[2] = {'a', '\0', }; + string_type sa(pt->transform(a, a+1)); + if(sa == a) + { + *delim = 0; + return sort_C; + } + char_type A[2] = { 'A', '\0', }; + string_type sA(pt->transform(A, A+1)); + char_type c[2] = { ';', '\0', }; + string_type sc(pt->transform(c, c+1)); + + int pos = 0; + while((pos <= static_cast(sa.size())) && (pos <= static_cast(sA.size())) && (sa[pos] == sA[pos])) ++pos; + --pos; + if(pos < 0) + { + *delim = 0; + return sort_unknown; + } + // + // at this point sa[pos] is either the end of a fixed width field + // or the character that acts as a delimiter: + // + charT maybe_delim = sa[pos]; + if((pos != 0) && (count_chars(sa, maybe_delim) == count_chars(sA, maybe_delim)) && (count_chars(sa, maybe_delim) == count_chars(sc, maybe_delim))) + { + *delim = maybe_delim; + return sort_delim; + } + // + // OK doen't look like a delimiter, try for fixed width field: + // + if((sa.size() == sA.size()) && (sa.size() == sc.size())) + { + // note assumes that the fixed width field is less than + // (numeric_limits::max)(), should be true for all types + // I can't imagine 127 character fields... + *delim = static_cast(++pos); + return sort_fixed; + } + // + // don't know what it is: + // + *delim = 0; + return sort_unknown; +} + + + } // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#endif + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regbase.hpp b/third-party/boost_regex/include/boost/regex/v5/regbase.hpp new file mode 100644 index 0000000000..5cefb36b4c --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regbase.hpp @@ -0,0 +1,158 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regbase.cpp + * VERSION see + * DESCRIPTION: Declares class regbase. + */ + +#ifndef BOOST_REGEX_V5_REGBASE_HPP +#define BOOST_REGEX_V5_REGBASE_HPP + +namespace boost{ +// +// class regbase +// handles error codes and flags +// +class regbase +{ +public: + enum flag_type_ + { + // + // Divide the flags up into logical groups: + // bits 0-7 indicate main synatx type. + // bits 8-15 indicate syntax subtype. + // bits 16-31 indicate options that are common to all + // regex syntaxes. + // In all cases the default is 0. + // + // Main synatx group: + // + perl_syntax_group = 0, // default + basic_syntax_group = 1, // POSIX basic + literal = 2, // all characters are literals + main_option_type = literal | basic_syntax_group | perl_syntax_group, // everything! + // + // options specific to perl group: + // + no_bk_refs = 1 << 8, // \d not allowed + no_perl_ex = 1 << 9, // disable perl extensions + no_mod_m = 1 << 10, // disable Perl m modifier + mod_x = 1 << 11, // Perl x modifier + mod_s = 1 << 12, // force s modifier on (overrides match_not_dot_newline) + no_mod_s = 1 << 13, // force s modifier off (overrides match_not_dot_newline) + + // + // options specific to basic group: + // + no_char_classes = 1 << 8, // [[:CLASS:]] not allowed + no_intervals = 1 << 9, // {x,y} not allowed + bk_plus_qm = 1 << 10, // uses \+ and \? + bk_vbar = 1 << 11, // use \| for alternatives + emacs_ex = 1 << 12, // enables emacs extensions + + // + // options common to all groups: + // + no_escape_in_lists = 1 << 16, // '\' not special inside [...] + newline_alt = 1 << 17, // \n is the same as | + no_except = 1 << 18, // no exception on error + failbit = 1 << 19, // error flag + icase = 1 << 20, // characters are matched regardless of case + nocollate = 0, // don't use locale specific collation (deprecated) + collate = 1 << 21, // use locale specific collation + nosubs = 1 << 22, // don't mark sub-expressions + save_subexpression_location = 1 << 23, // save subexpression locations + no_empty_expressions = 1 << 24, // no empty expressions allowed + optimize = 0, // not really supported + + + + basic = basic_syntax_group | collate | no_escape_in_lists, + extended = no_bk_refs | collate | no_perl_ex | no_escape_in_lists, + normal = 0, + emacs = basic_syntax_group | collate | emacs_ex | bk_vbar, + awk = no_bk_refs | collate | no_perl_ex, + grep = basic | newline_alt, + egrep = extended | newline_alt, + sed = basic, + perl = normal, + ECMAScript = normal, + JavaScript = normal, + JScript = normal + }; + typedef unsigned int flag_type; + + enum restart_info + { + restart_any = 0, + restart_word = 1, + restart_line = 2, + restart_buf = 3, + restart_continue = 4, + restart_lit = 5, + restart_fixed_lit = 6, + restart_count = 7 + }; +}; + +// +// provide std lib proposal compatible constants: +// +namespace regex_constants{ + + enum flag_type_ + { + + no_except = ::boost::regbase::no_except, + failbit = ::boost::regbase::failbit, + literal = ::boost::regbase::literal, + icase = ::boost::regbase::icase, + nocollate = ::boost::regbase::nocollate, + collate = ::boost::regbase::collate, + nosubs = ::boost::regbase::nosubs, + optimize = ::boost::regbase::optimize, + bk_plus_qm = ::boost::regbase::bk_plus_qm, + bk_vbar = ::boost::regbase::bk_vbar, + no_intervals = ::boost::regbase::no_intervals, + no_char_classes = ::boost::regbase::no_char_classes, + no_escape_in_lists = ::boost::regbase::no_escape_in_lists, + no_mod_m = ::boost::regbase::no_mod_m, + mod_x = ::boost::regbase::mod_x, + mod_s = ::boost::regbase::mod_s, + no_mod_s = ::boost::regbase::no_mod_s, + save_subexpression_location = ::boost::regbase::save_subexpression_location, + no_empty_expressions = ::boost::regbase::no_empty_expressions, + + basic = ::boost::regbase::basic, + extended = ::boost::regbase::extended, + normal = ::boost::regbase::normal, + emacs = ::boost::regbase::emacs, + awk = ::boost::regbase::awk, + grep = ::boost::regbase::grep, + egrep = ::boost::regbase::egrep, + sed = basic, + perl = normal, + ECMAScript = normal, + JavaScript = normal, + JScript = normal + }; + typedef ::boost::regbase::flag_type syntax_option_type; + +} // namespace regex_constants + +} // namespace boost + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex.hpp b/third-party/boost_regex/include/boost/regex/v5/regex.hpp new file mode 100644 index 0000000000..eb6dc72822 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex.hpp @@ -0,0 +1,106 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex.cpp + * VERSION see + * DESCRIPTION: Declares boost::basic_regex<> and associated + * functions and classes. This header is the main + * entry point for the template regex code. + */ + +#ifndef BOOST_RE_REGEX_HPP_INCLUDED +#define BOOST_RE_REGEX_HPP_INCLUDED + +#ifdef __cplusplus + +// what follows is all C++ don't include in C builds!! + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ +#ifdef BOOST_REGEX_NO_FWD +typedef basic_regex > regex; +#ifndef BOOST_NO_WREGEX +typedef basic_regex > wregex; +#endif +#endif + +typedef match_results cmatch; +typedef match_results smatch; +#ifndef BOOST_NO_WREGEX +typedef match_results wcmatch; +typedef match_results wsmatch; +#endif + +} // namespace boost + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // __cplusplus + +#endif // include + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_format.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_format.hpp new file mode 100644 index 0000000000..4c82d185aa --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_format.hpp @@ -0,0 +1,1124 @@ +/* + * + * Copyright (c) 1998-2009 John Maddock + * Copyright 2008 Eric Niebler. + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_FORMAT_HPP +#define BOOST_REGEX_FORMAT_HPP + +#include +#include + +namespace boost{ + +// +// Forward declaration: +// + template >::allocator_type > +class match_results; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// struct trivial_format_traits: +// defines minimum localisation support for formatting +// in the case that the actual regex traits is unavailable. +// +template +struct trivial_format_traits +{ + typedef charT char_type; + + static std::ptrdiff_t length(const charT* p) + { + return global_length(p); + } + static charT tolower(charT c) + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c); + } + static charT toupper(charT c) + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c); + } + static int value(const charT c, int radix) + { + int result = global_value(c); + return result >= radix ? -1 : result; + } + int toi(const charT*& p1, const charT* p2, int radix)const + { + return (int)global_toi(p1, p2, radix, *this); + } +}; + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#pragma warning(disable:26812) +#endif +template +class basic_regex_formatter +{ +public: + typedef typename traits::char_type char_type; + basic_regex_formatter(OutputIterator o, const Results& r, const traits& t) + : m_traits(t), m_results(r), m_out(o), m_position(), m_end(), m_flags(), m_state(output_copy), m_restore_state(output_copy), m_have_conditional(false) {} + OutputIterator format(ForwardIter p1, ForwardIter p2, match_flag_type f); + OutputIterator format(ForwardIter p1, match_flag_type f) + { + return format(p1, p1 + m_traits.length(p1), f); + } +private: + typedef typename Results::value_type sub_match_type; + enum output_state + { + output_copy, + output_next_lower, + output_next_upper, + output_lower, + output_upper, + output_none + }; + + void put(char_type c); + void put(const sub_match_type& sub); + void format_all(); + void format_perl(); + void format_escape(); + void format_conditional(); + void format_until_scope_end(); + bool handle_perl_verb(bool have_brace); + + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const std::integral_constant&) + { + std::vector v(i, j); + return (i != j) ? this->m_results.named_subexpression(&v[0], &v[0] + v.size()) + : this->m_results.named_subexpression(static_cast(0), static_cast(0)); + } + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j, const std::integral_constant&) + { + return this->m_results.named_subexpression(i, j); + } + inline typename Results::value_type const& get_named_sub(ForwardIter i, ForwardIter j) + { + typedef typename std::is_convertible::type tag_type; + return get_named_sub(i, j, tag_type()); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j, const std::integral_constant&) + { + std::vector v(i, j); + return (i != j) ? this->m_results.named_subexpression_index(&v[0], &v[0] + v.size()) + : this->m_results.named_subexpression_index(static_cast(0), static_cast(0)); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j, const std::integral_constant&) + { + return this->m_results.named_subexpression_index(i, j); + } + inline int get_named_sub_index(ForwardIter i, ForwardIter j) + { + typedef typename std::is_convertible::type tag_type; + return get_named_sub_index(i, j, tag_type()); + } +#ifdef BOOST_REGEX_MSVC + // msvc-8.0 issues a spurious warning on the call to std::advance here: +#pragma warning(push) +#pragma warning(disable:4244) +#endif + inline int toi(ForwardIter& i, ForwardIter j, int base, const std::integral_constant&) + { + if(i != j) + { + std::vector v(i, j); + const char_type* start = &v[0]; + const char_type* pos = start; + int r = (int)m_traits.toi(pos, &v[0] + v.size(), base); + std::advance(i, pos - start); + return r; + } + return -1; + } +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + inline int toi(ForwardIter& i, ForwardIter j, int base, const std::integral_constant&) + { + return m_traits.toi(i, j, base); + } + inline int toi(ForwardIter& i, ForwardIter j, int base) + { +#if defined(_MSC_VER) && defined(__INTEL_COMPILER) && ((__INTEL_COMPILER == 9999) || (__INTEL_COMPILER == 1210)) + // Workaround for Intel support issue #656654. + // See also https://svn.boost.org/trac/boost/ticket/6359 + return toi(i, j, base, std::integral_constant()); +#else + typedef typename std::is_convertible::type tag_type; + return toi(i, j, base, tag_type()); +#endif + } + + const traits& m_traits; // the traits class for localised formatting operations + const Results& m_results; // the match_results being used. + OutputIterator m_out; // where to send output. + ForwardIter m_position; // format string, current position + ForwardIter m_end; // format string end + match_flag_type m_flags; // format flags to use + output_state m_state; // what to do with the next character + output_state m_restore_state; // what state to restore to. + bool m_have_conditional; // we are parsing a conditional +private: + basic_regex_formatter(const basic_regex_formatter&); + basic_regex_formatter& operator=(const basic_regex_formatter&); +}; +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +template +OutputIterator basic_regex_formatter::format(ForwardIter p1, ForwardIter p2, match_flag_type f) +{ + m_position = p1; + m_end = p2; + m_flags = f; + format_all(); + return m_out; +} + +template +void basic_regex_formatter::format_all() +{ + // over and over: + while(m_position != m_end) + { + switch(*m_position) + { + case '&': + if(m_flags & ::boost::regex_constants::format_sed) + { + ++m_position; + put(m_results[0]); + break; + } + put(*m_position++); + break; + case '\\': + format_escape(); + break; + case '(': + if(m_flags & boost::regex_constants::format_all) + { + ++m_position; + bool have_conditional = m_have_conditional; + m_have_conditional = false; + format_until_scope_end(); + m_have_conditional = have_conditional; + if(m_position == m_end) + return; + BOOST_REGEX_ASSERT(*m_position == static_cast(')')); + ++m_position; // skip the closing ')' + break; + } + put(*m_position); + ++m_position; + break; + case ')': + if(m_flags & boost::regex_constants::format_all) + { + return; + } + put(*m_position); + ++m_position; + break; + case ':': + if((m_flags & boost::regex_constants::format_all) && m_have_conditional) + { + return; + } + put(*m_position); + ++m_position; + break; + case '?': + if(m_flags & boost::regex_constants::format_all) + { + ++m_position; + format_conditional(); + break; + } + put(*m_position); + ++m_position; + break; + case '$': + if((m_flags & format_sed) == 0) + { + format_perl(); + break; + } + // not a special character: + BOOST_REGEX_FALLTHROUGH; + default: + put(*m_position); + ++m_position; + break; + } + } +} + +template +void basic_regex_formatter::format_perl() +{ + // + // On entry *m_position points to a '$' character + // output the information that goes with it: + // + BOOST_REGEX_ASSERT(*m_position == '$'); + // + // see if this is a trailing '$': + // + if(++m_position == m_end) + { + --m_position; + put(*m_position); + ++m_position; + return; + } + // + // OK find out what kind it is: + // + bool have_brace = false; + ForwardIter save_position = m_position; + switch(*m_position) + { + case '&': + ++m_position; + put(this->m_results[0]); + break; + case '`': + ++m_position; + put(this->m_results.prefix()); + break; + case '\'': + ++m_position; + put(this->m_results.suffix()); + break; + case '$': + put(*m_position++); + break; + case '+': + if((++m_position != m_end) && (*m_position == '{')) + { + ForwardIter base = ++m_position; + while((m_position != m_end) && (*m_position != '}')) ++m_position; + if(m_position != m_end) + { + // Named sub-expression: + put(get_named_sub(base, m_position)); + ++m_position; + break; + } + else + { + m_position = --base; + } + } + put((this->m_results)[this->m_results.size() > 1 ? static_cast(this->m_results.size() - 1) : 1]); + break; + case '{': + have_brace = true; + ++m_position; + BOOST_REGEX_FALLTHROUGH; + default: + // see if we have a number: + { + std::ptrdiff_t len = std::distance(m_position, m_end); + //len = (std::min)(static_cast(2), len); + int v = this->toi(m_position, m_position + len, 10); + if((v < 0) || (have_brace && ((m_position == m_end) || (*m_position != '}')))) + { + // Look for a Perl-5.10 verb: + if(!handle_perl_verb(have_brace)) + { + // leave the $ as is, and carry on: + m_position = --save_position; + put(*m_position); + ++m_position; + } + break; + } + // otherwise output sub v: + put(this->m_results[v]); + if(have_brace) + ++m_position; + } + } +} + +template +bool basic_regex_formatter::handle_perl_verb(bool have_brace) +{ + // + // We may have a capitalised string containing a Perl action: + // + static const char_type MATCH[] = { 'M', 'A', 'T', 'C', 'H' }; + static const char_type PREMATCH[] = { 'P', 'R', 'E', 'M', 'A', 'T', 'C', 'H' }; + static const char_type POSTMATCH[] = { 'P', 'O', 'S', 'T', 'M', 'A', 'T', 'C', 'H' }; + static const char_type LAST_PAREN_MATCH[] = { 'L', 'A', 'S', 'T', '_', 'P', 'A', 'R', 'E', 'N', '_', 'M', 'A', 'T', 'C', 'H' }; + static const char_type LAST_SUBMATCH_RESULT[] = { 'L', 'A', 'S', 'T', '_', 'S', 'U', 'B', 'M', 'A', 'T', 'C', 'H', '_', 'R', 'E', 'S', 'U', 'L', 'T' }; + static const char_type LAST_SUBMATCH_RESULT_ALT[] = { '^', 'N' }; + + if(m_position == m_end) + return false; + if(have_brace && (*m_position == '^')) + ++m_position; + + std::ptrdiff_t max_len = m_end - m_position; + + if((max_len >= 5) && std::equal(m_position, m_position + 5, MATCH)) + { + m_position += 5; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 5; + return false; + } + } + put(this->m_results[0]); + return true; + } + if((max_len >= 8) && std::equal(m_position, m_position + 8, PREMATCH)) + { + m_position += 8; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 8; + return false; + } + } + put(this->m_results.prefix()); + return true; + } + if((max_len >= 9) && std::equal(m_position, m_position + 9, POSTMATCH)) + { + m_position += 9; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 9; + return false; + } + } + put(this->m_results.suffix()); + return true; + } + if((max_len >= 16) && std::equal(m_position, m_position + 16, LAST_PAREN_MATCH)) + { + m_position += 16; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 16; + return false; + } + } + put((this->m_results)[this->m_results.size() > 1 ? static_cast(this->m_results.size() - 1) : 1]); + return true; + } + if((max_len >= 20) && std::equal(m_position, m_position + 20, LAST_SUBMATCH_RESULT)) + { + m_position += 20; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 20; + return false; + } + } + put(this->m_results.get_last_closed_paren()); + return true; + } + if((max_len >= 2) && std::equal(m_position, m_position + 2, LAST_SUBMATCH_RESULT_ALT)) + { + m_position += 2; + if(have_brace) + { + if((m_position != m_end) && (*m_position == '}')) + ++m_position; + else + { + m_position -= 2; + return false; + } + } + put(this->m_results.get_last_closed_paren()); + return true; + } + return false; +} + +template +void basic_regex_formatter::format_escape() +{ + // skip the escape and check for trailing escape: + if(++m_position == m_end) + { + put(static_cast('\\')); + return; + } + // now switch on the escape type: + switch(*m_position) + { + case 'a': + put(static_cast('\a')); + ++m_position; + break; + case 'f': + put(static_cast('\f')); + ++m_position; + break; + case 'n': + put(static_cast('\n')); + ++m_position; + break; + case 'r': + put(static_cast('\r')); + ++m_position; + break; + case 't': + put(static_cast('\t')); + ++m_position; + break; + case 'v': + put(static_cast('\v')); + ++m_position; + break; + case 'x': + if(++m_position == m_end) + { + put(static_cast('x')); + return; + } + // maybe have \x{ddd} + if(*m_position == static_cast('{')) + { + ++m_position; + int val = this->toi(m_position, m_end, 16); + if(val < 0) + { + // invalid value treat everything as literals: + put(static_cast('x')); + put(static_cast('{')); + return; + } + if((m_position == m_end) || (*m_position != static_cast('}'))) + { + --m_position; + while(*m_position != static_cast('\\')) + --m_position; + ++m_position; + put(*m_position++); + return; + } + ++m_position; + put(static_cast(val)); + return; + } + else + { + std::ptrdiff_t len = std::distance(m_position, m_end); + len = (std::min)(static_cast(2), len); + int val = this->toi(m_position, m_position + len, 16); + if(val < 0) + { + --m_position; + put(*m_position++); + return; + } + put(static_cast(val)); + } + break; + case 'c': + if(++m_position == m_end) + { + --m_position; + put(*m_position++); + return; + } + put(static_cast(*m_position++ % 32)); + break; + case 'e': + put(static_cast(27)); + ++m_position; + break; + default: + // see if we have a perl specific escape: + if((m_flags & boost::regex_constants::format_sed) == 0) + { + bool breakout = false; + switch(*m_position) + { + case 'l': + ++m_position; + m_restore_state = m_state; + m_state = output_next_lower; + breakout = true; + break; + case 'L': + ++m_position; + m_state = output_lower; + breakout = true; + break; + case 'u': + ++m_position; + m_restore_state = m_state; + m_state = output_next_upper; + breakout = true; + break; + case 'U': + ++m_position; + m_state = output_upper; + breakout = true; + break; + case 'E': + ++m_position; + m_state = output_copy; + breakout = true; + break; + } + if(breakout) + break; + } + // see if we have a \n sed style backreference: + std::ptrdiff_t len = std::distance(m_position, m_end); + len = (std::min)(static_cast(1), len); + int v = this->toi(m_position, m_position+len, 10); + if((v > 0) || ((v == 0) && (m_flags & ::boost::regex_constants::format_sed))) + { + put(m_results[v]); + break; + } + else if(v == 0) + { + // octal ecape sequence: + --m_position; + len = std::distance(m_position, m_end); + len = (std::min)(static_cast(4), len); + v = this->toi(m_position, m_position + len, 8); + BOOST_REGEX_ASSERT(v >= 0); + put(static_cast(v)); + break; + } + // Otherwise output the character "as is": + put(*m_position++); + break; + } +} + +template +void basic_regex_formatter::format_conditional() +{ + if(m_position == m_end) + { + // oops trailing '?': + put(static_cast('?')); + return; + } + int v; + if(*m_position == '{') + { + ForwardIter base = m_position; + ++m_position; + v = this->toi(m_position, m_end, 10); + if(v < 0) + { + // Try a named subexpression: + while((m_position != m_end) && (*m_position != '}')) + ++m_position; + v = this->get_named_sub_index(base + 1, m_position); + } + if((v < 0) || (*m_position != '}')) + { + m_position = base; + // oops trailing '?': + put(static_cast('?')); + return; + } + // Skip trailing '}': + ++m_position; + } + else + { + std::ptrdiff_t len = std::distance(m_position, m_end); + len = (std::min)(static_cast(2), len); + v = this->toi(m_position, m_position + len, 10); + } + if(v < 0) + { + // oops not a number: + put(static_cast('?')); + return; + } + + // output varies depending upon whether sub-expression v matched or not: + if(m_results[v].matched) + { + m_have_conditional = true; + format_all(); + m_have_conditional = false; + if((m_position != m_end) && (*m_position == static_cast(':'))) + { + // skip the ':': + ++m_position; + // save output state, then turn it off: + output_state saved_state = m_state; + m_state = output_none; + // format the rest of this scope: + format_until_scope_end(); + // restore output state: + m_state = saved_state; + } + } + else + { + // save output state, then turn it off: + output_state saved_state = m_state; + m_state = output_none; + // format until ':' or ')': + m_have_conditional = true; + format_all(); + m_have_conditional = false; + // restore state: + m_state = saved_state; + if((m_position != m_end) && (*m_position == static_cast(':'))) + { + // skip the ':': + ++m_position; + // format the rest of this scope: + format_until_scope_end(); + } + } +} + +template +void basic_regex_formatter::format_until_scope_end() +{ + do + { + format_all(); + if((m_position == m_end) || (*m_position == static_cast(')'))) + return; + put(*m_position++); + }while(m_position != m_end); +} + +template +void basic_regex_formatter::put(char_type c) +{ + // write a single character to output + // according to which case translation mode we are in: + switch(this->m_state) + { + case output_none: + return; + case output_next_lower: + c = m_traits.tolower(c); + this->m_state = m_restore_state; + break; + case output_next_upper: + c = m_traits.toupper(c); + this->m_state = m_restore_state; + break; + case output_lower: + c = m_traits.tolower(c); + break; + case output_upper: + c = m_traits.toupper(c); + break; + default: + break; + } + *m_out = c; + ++m_out; +} + +template +void basic_regex_formatter::put(const sub_match_type& sub) +{ + typedef typename sub_match_type::iterator iterator_type; + iterator_type i = sub.first; + while(i != sub.second) + { + put(*i); + ++i; + } +} + +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; + } + + typedef std::ptrdiff_t difference_type; + typedef typename S::value_type value_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef std::output_iterator_tag iterator_category; +}; + +template +OutputIterator regex_format_imp(OutputIterator out, + const match_results& m, + ForwardIter p1, ForwardIter p2, + match_flag_type flags, + const traits& t + ) +{ + if(flags & regex_constants::format_literal) + { + return BOOST_REGEX_DETAIL_NS::copy(p1, p2, out); + } + + BOOST_REGEX_DETAIL_NS::basic_regex_formatter< + OutputIterator, + match_results, + traits, ForwardIter> f(out, m, t); + return f.format(p1, p2, flags); +} + +template +struct has_const_iterator +{ + template + static typename U::const_iterator tester(U*); + static char tester(...); + + static T* get(); + + static const bool value = sizeof(tester(get())) != sizeof(char); +}; + +struct any_type +{ + template + any_type(const T&); + template + any_type(const T&, const U&); + template + any_type(const T&, const U&, const V&); +}; +typedef char no_type; +typedef char (&unary_type)[2]; +typedef char (&binary_type)[3]; +typedef char (&ternary_type)[4]; + +no_type check_is_formatter(unary_type, binary_type, ternary_type); +template +unary_type check_is_formatter(T const &, binary_type, ternary_type); +template +binary_type check_is_formatter(unary_type, T const &, ternary_type); +template +binary_type check_is_formatter(T const &, U const &, ternary_type); +template +ternary_type check_is_formatter(unary_type, binary_type, T const &); +template +ternary_type check_is_formatter(T const &, binary_type, U const &); +template +ternary_type check_is_formatter(unary_type, T const &, U const &); +template +ternary_type check_is_formatter(T const &, U const &, V const &); + +struct unary_binary_ternary +{ + typedef unary_type (*unary_fun)(any_type); + typedef binary_type (*binary_fun)(any_type, any_type); + typedef ternary_type (*ternary_fun)(any_type, any_type, any_type); + operator unary_fun(); + operator binary_fun(); + operator ternary_fun(); +}; + +template::value> +struct formatter_wrapper + : Formatter + , unary_binary_ternary +{ + formatter_wrapper(){} +}; + +template +struct formatter_wrapper + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template +struct formatter_wrapper + : unary_binary_ternary +{ + operator Formatter *(); +}; + +template +struct do_unwrap_reference +{ + typedef T type; +}; +template +struct do_unwrap_reference > +{ + typedef T type; +}; + +template +T& do_unwrap_ref(T& r) { return r; } +template +T& do_unwrap_ref(std::reference_wrapper const& r) { return r.get(); } + +template +struct format_traits_imp +{ +private: + // + // F must be a pointer, a function, or a class with a function call operator: + // + static_assert((::std::is_pointer::value || ::std::is_function::value || ::std::is_class::value), "The functor must be a pointer or a class with a function call operator"); + static formatter_wrapper::type> f; + static M m; + static O out; + static boost::regex_constants::match_flag_type flags; +public: + static const int value = sizeof(check_is_formatter(f(m), f(m, out), f(m, out, flags))); +}; + +template +struct format_traits +{ +public: + // + // Type is std::integral_constant where N is one of: + // + // 0 : F is a pointer to a presumably null-terminated string. + // 1 : F is a character-container such as a std::string. + // 2 : F is a Unary Functor. + // 3 : F is a Binary Functor. + // 4 : F is a Ternary Functor. + // + typedef typename std::conditional< + std::is_pointer::value && !std::is_function::type>::value, + std::integral_constant, + typename std::conditional< + has_const_iterator::value, + std::integral_constant, + std::integral_constant::value> + >::type + >::type type; + // + // This static assertion will fail if the functor passed does not accept + // the same type of arguments passed. + // + static_assert( std::is_class::value && !has_const_iterator::value ? (type::value > 1) : true, "Argument mismatch in Functor type"); +}; + +template +struct format_functor3 +{ + format_functor3(Base b) : func(b) {} + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f) + { + return do_unwrap_ref(func)(m, i, f); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor3(const format_functor3&); + format_functor3& operator=(const format_functor3&); +}; + +template +struct format_functor2 +{ + format_functor2(Base b) : func(b) {} + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/) + { + return do_unwrap_ref(func)(m, i); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor2(const format_functor2&); + format_functor2& operator=(const format_functor2&); +}; + +template +struct format_functor1 +{ + format_functor1(Base b) : func(b) {} + + template + OutputIter do_format_string(const S& s, OutputIter i) + { + return std::copy(s.begin(), s.end(), i); + } + template + inline OutputIter do_format_string(const S* s, OutputIter i) + { + while(s && *s) + { + *i = *s; + ++i; + ++s; + } + return i; + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type /*f*/) + { + return do_format_string(do_unwrap_ref(func)(m), i); + } + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits&) + { + return (*this)(m, i, f); + } +private: + Base func; + format_functor1(const format_functor1&); + format_functor1& operator=(const format_functor1&); +}; + +template +struct format_functor_c_string +{ + format_functor_c_string(const charT* ps) : func(ps) {} + + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits()) + { + //typedef typename Match::char_type char_type; + const charT* end = func; + while(*end) ++end; + return regex_format_imp(i, m, func, end, f, t); + } +private: + const charT* func; + format_functor_c_string(const format_functor_c_string&); + format_functor_c_string& operator=(const format_functor_c_string&); +}; + +template +struct format_functor_container +{ + format_functor_container(const Container& c) : func(c) {} + + template + OutputIter operator()(const Match& m, OutputIter i, boost::regex_constants::match_flag_type f, const Traits& t = Traits()) + { + //typedef typename Match::char_type char_type; + return BOOST_REGEX_DETAIL_NS::regex_format_imp(i, m, func.begin(), func.end(), f, t); + } +private: + const Container& func; + format_functor_container(const format_functor_container&); + format_functor_container& operator=(const format_functor_container&); +}; + +template > +struct compute_functor_type +{ + typedef typename format_traits::type tag; + typedef typename std::remove_cv< typename std::remove_pointer::type>::type maybe_char_type; + + typedef typename std::conditional< + tag::value == 0, format_functor_c_string, + typename std::conditional< + tag::value == 1, format_functor_container, + typename std::conditional< + tag::value == 2, format_functor1, + typename std::conditional< + tag::value == 3, format_functor2, + format_functor3 + >::type + >::type + >::type + >::type type; +}; + +} // namespace BOOST_REGEX_DETAIL_NS + +template +inline OutputIterator regex_format(OutputIterator out, + const match_results& m, + Functor fmt, + match_flag_type flags = format_all + ) +{ + return m.format(out, fmt, flags); +} + +template +inline std::basic_string::char_type> regex_format(const match_results& m, + Functor fmt, + match_flag_type flags = format_all) +{ + return m.format(fmt, flags); +} + +} // namespace boost + +#endif // BOOST_REGEX_FORMAT_HPP + + + + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_fwd.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_fwd.hpp new file mode 100644 index 0000000000..3076b069ac --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_fwd.hpp @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_fwd.cpp + * VERSION see + * DESCRIPTION: Forward declares boost::basic_regex<> and + * associated typedefs. + */ + +#ifndef BOOST_REGEX_FWD_HPP_INCLUDED +#define BOOST_REGEX_FWD_HPP_INCLUDED + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +// +// define BOOST_REGEX_NO_FWD if this +// header doesn't work! +// +#ifdef BOOST_REGEX_NO_FWD +# ifndef BOOST_RE_REGEX_HPP +# include +# endif +#else + +namespace boost{ + +template +class cpp_regex_traits; +template +struct c_regex_traits; +template +class w32_regex_traits; + +#ifdef BOOST_REGEX_USE_WIN32_LOCALE +template > +struct regex_traits; +#elif defined(BOOST_REGEX_USE_CPP_LOCALE) +template > +struct regex_traits; +#else +template > +struct regex_traits; +#endif + +template > +class basic_regex; + +typedef basic_regex > regex; +#ifndef BOOST_NO_WREGEX +typedef basic_regex > wregex; +#endif + +} // namespace boost + +#endif // BOOST_REGEX_NO_FWD + +#endif + + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_grep.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_grep.hpp new file mode 100644 index 0000000000..6cd625d606 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_grep.hpp @@ -0,0 +1,98 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_grep.hpp + * VERSION see + * DESCRIPTION: Provides regex_grep implementation. + */ + +#ifndef BOOST_REGEX_V5_REGEX_GREP_HPP +#define BOOST_REGEX_V5_REGEX_GREP_HPP + + +namespace boost{ + +// +// regex_grep: +// find all non-overlapping matches within the sequence first last: +// +template +inline unsigned int regex_grep(Predicate foo, + BidiIterator first, + BidiIterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + if(e.flags() & regex_constants::failbit) + return false; + + typedef typename match_results::allocator_type match_allocator_type; + + match_results m; + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, first); + unsigned int count = 0; + while(matcher.find()) + { + ++count; + if(0 == foo(m)) + return count; // caller doesn't want to go on + if(m[0].second == last) + return count; // we've reached the end, don't try and find an extra null match. + if(m.length() == 0) + { + if(m[0].second == last) + return count; + // we found a NULL-match, now try to find + // a non-NULL one at the same position: + match_results m2(m); + matcher.setf(match_not_null | match_continuous); + if(matcher.find()) + { + ++count; + if(0 == foo(m)) + return count; + } + else + { + // reset match back to where it was: + m = m2; + } + matcher.unsetf((match_not_null | match_continuous) & ~flags); + } + } + return count; +} + +// +// regex_grep convenience interfaces: +// +template +inline unsigned int regex_grep(Predicate foo, const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, str, str + traits::length(str), e, flags); +} + +template +inline unsigned int regex_grep(Predicate foo, const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_grep(foo, s.begin(), s.end(), e, flags); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_GREP_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_iterator.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_iterator.hpp new file mode 100644 index 0000000000..b2e9d2ced5 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_iterator.hpp @@ -0,0 +1,173 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_iterator.hpp + * VERSION see + * DESCRIPTION: Provides regex_iterator implementation. + */ + +#ifndef BOOST_REGEX_V5_REGEX_ITERATOR_HPP +#define BOOST_REGEX_V5_REGEX_ITERATOR_HPP + +#include + +namespace boost{ + +template +class regex_iterator_implementation +{ + typedef basic_regex regex_type; + + match_results what; // current match + BidirectionalIterator base; // start of sequence + BidirectionalIterator end; // end of sequence + const regex_type re; // the expression + match_flag_type flags; // flags for matching + +public: + regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f) + : base(), end(last), re(*p), flags(f){} + regex_iterator_implementation(const regex_iterator_implementation& other) + :what(other.what), base(other.base), end(other.end), re(other.re), flags(other.flags){} + bool init(BidirectionalIterator first) + { + base = first; + return regex_search(first, end, what, re, flags); + } + bool compare(const regex_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second); + } + const match_results& get() + { return what; } + bool next() + { + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail; + BidirectionalIterator next_start = what[0].second; + match_flag_type f(flags); + if(!what.length() || (f & regex_constants::match_posix)) + f |= regex_constants::match_not_initial_null; + //if(base != next_start) + // f |= regex_constants::match_not_bob; + bool result = regex_search(next_start, end, what, re, f, base); + if(result) + what.set_base(base); + return result; + } +private: + regex_iterator_implementation& operator=(const regex_iterator_implementation&); +}; + +template ::value_type, + class traits = regex_traits > +class regex_iterator +{ +private: + typedef regex_iterator_implementation impl; + typedef std::shared_ptr pimpl; +public: + typedef basic_regex regex_type; + typedef match_results value_type; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + regex_iterator(){} + regex_iterator(BidirectionalIterator a, BidirectionalIterator b, + const regex_type& re, + match_flag_type m = match_default) + : pdata(new impl(&re, b, m)) + { + if(!pdata->init(a)) + { + pdata.reset(); + } + } + regex_iterator(const regex_iterator& that) + : pdata(that.pdata) {} + regex_iterator& operator=(const regex_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const regex_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const regex_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + regex_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + regex_iterator operator++(int) + { + regex_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && (pdata.use_count() > 1)) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef regex_iterator cregex_iterator; +typedef regex_iterator sregex_iterator; +#ifndef BOOST_NO_WREGEX +typedef regex_iterator wcregex_iterator; +typedef regex_iterator wsregex_iterator; +#endif + +// make_regex_iterator: +template +inline regex_iterator make_regex_iterator(const charT* p, const basic_regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_iterator(p, p+traits::length(p), e, m); +} +template +inline regex_iterator::const_iterator, charT, traits> make_regex_iterator(const std::basic_string& p, const basic_regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, m); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_match.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_match.hpp new file mode 100644 index 0000000000..217535769b --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_match.hpp @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_match.hpp + * VERSION see + * DESCRIPTION: Regular expression matching algorithms. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + + +#ifndef BOOST_REGEX_MATCH_HPP +#define BOOST_REGEX_MATCH_HPP + +namespace boost{ + +// +// proc regex_match +// returns true if the specified regular expression matches +// the whole of the input. Fills in what matched in m. +// +template +bool regex_match(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, first); + return matcher.match(); +} +template +bool regex_match(iterator first, iterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(first, last, m, e, flags | regex_constants::match_any); +} +// +// query_match convenience interfaces: +// +template +inline bool regex_match(const charT* str, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_match(str, str + traits::length(str), m, e, flags); +} + +template +inline bool regex_match(const std::basic_string& s, + match_results::const_iterator, Allocator>& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_match(s.begin(), s.end(), m, e, flags); +} +template +inline bool regex_match(const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + match_results m; + return regex_match(str, str + traits::length(str), m, e, flags | regex_constants::match_any); +} + +template +inline bool regex_match(const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + typedef typename std::basic_string::const_iterator iterator; + match_results m; + return regex_match(s.begin(), s.end(), m, e, flags | regex_constants::match_any); +} + + +} // namespace boost + +#endif // BOOST_REGEX_MATCH_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_merge.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_merge.hpp new file mode 100644 index 0000000000..a5103c53e8 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_merge.hpp @@ -0,0 +1,71 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_V5_REGEX_MERGE_HPP +#define BOOST_REGEX_V5_REGEX_MERGE_HPP + + +namespace boost{ + +template +inline OutputIterator regex_merge(OutputIterator out, + Iterator first, + Iterator last, + const basic_regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + return regex_replace(out, first, last, e, fmt, flags); +} + +template +inline OutputIterator regex_merge(OutputIterator out, + Iterator first, + Iterator last, + const basic_regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + return regex_merge(out, first, last, e, fmt.c_str(), flags); +} + +template +inline std::basic_string regex_merge(const std::basic_string& s, + const basic_regex& e, + const charT* fmt, + match_flag_type flags = match_default) +{ + return regex_replace(s, e, fmt, flags); +} + +template +inline std::basic_string regex_merge(const std::basic_string& s, + const basic_regex& e, + const std::basic_string& fmt, + match_flag_type flags = match_default) +{ + return regex_replace(s, e, fmt, flags); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_MERGE_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_raw_buffer.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_raw_buffer.hpp new file mode 100644 index 0000000000..443c57a25b --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_raw_buffer.hpp @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_raw_buffer.hpp + * VERSION see + * DESCRIPTION: Raw character buffer for regex code. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_RAW_BUFFER_HPP +#define BOOST_REGEX_RAW_BUFFER_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#include +#include + +namespace boost{ + namespace BOOST_REGEX_DETAIL_NS{ + +struct empty_padding{}; + +union padding +{ + void* p; + unsigned int i; +}; + +template +struct padding3 +{ + enum{ + padding_size = 8, + padding_mask = 7 + }; +}; + +template<> +struct padding3<2> +{ + enum{ + padding_size = 2, + padding_mask = 1 + }; +}; + +template<> +struct padding3<4> +{ + enum{ + padding_size = 4, + padding_mask = 3 + }; +}; + +template<> +struct padding3<8> +{ + enum{ + padding_size = 8, + padding_mask = 7 + }; +}; + +template<> +struct padding3<16> +{ + enum{ + padding_size = 16, + padding_mask = 15 + }; +}; + +enum{ + padding_size = padding3::padding_size, + padding_mask = padding3::padding_mask +}; + +// +// class raw_storage +// basically this is a simplified vector +// this is used by basic_regex for expression storage +// + +class raw_storage +{ +public: + typedef std::size_t size_type; + typedef unsigned char* pointer; +private: + pointer last, start, end; +public: + + raw_storage(); + raw_storage(size_type n); + + ~raw_storage() + { + ::operator delete(start); + } + + void resize(size_type n) + { + size_type newsize = start ? last - start : 1024; + while (newsize < n) + newsize *= 2; + size_type datasize = end - start; + // extend newsize to WORD/DWORD boundary: + newsize = (newsize + padding_mask) & ~(padding_mask); + + // allocate and copy data: + pointer ptr = static_cast(::operator new(newsize)); + BOOST_REGEX_NOEH_ASSERT(ptr) + if (start) + std::memcpy(ptr, start, datasize); + + // get rid of old buffer: + ::operator delete(start); + + // and set up pointers: + start = ptr; + end = ptr + datasize; + last = ptr + newsize; + } + + void* extend(size_type n) + { + if(size_type(last - end) < n) + resize(n + (end - start)); + pointer result = end; + end += n; + return result; + } + + void* insert(size_type pos, size_type n) + { + BOOST_REGEX_ASSERT(pos <= size_type(end - start)); + if (size_type(last - end) < n) + resize(n + (end - start)); + void* result = start + pos; + std::memmove(start + pos + n, start + pos, (end - start) - pos); + end += n; + return result; + } + + size_type size() + { + return size_type(end - start); + } + + size_type capacity() + { + return size_type(last - start); + } + + void* data()const + { + return start; + } + + size_type index(void* ptr) + { + return size_type(static_cast(ptr) - static_cast(data())); + } + + void clear() + { + end = start; + } + + void align() + { + // move end up to a boundary: + end = start + (((end - start) + padding_mask) & ~padding_mask); + } + void swap(raw_storage& that) + { + std::swap(start, that.start); + std::swap(end, that.end); + std::swap(last, that.last); + } +}; + +inline raw_storage::raw_storage() +{ + last = start = end = 0; +} + +inline raw_storage::raw_storage(size_type n) +{ + start = end = static_cast(::operator new(n)); + BOOST_REGEX_NOEH_ASSERT(start) + last = start + n; +} + +} // namespace BOOST_REGEX_DETAIL_NS +} // namespace boost + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_replace.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_replace.hpp new file mode 100644 index 0000000000..75f8894fe9 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_replace.hpp @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 1998-2009 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_format.hpp + * VERSION see + * DESCRIPTION: Provides formatting output routines for search and replace + * operations. Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_V5_REGEX_REPLACE_HPP +#define BOOST_REGEX_V5_REGEX_REPLACE_HPP + + +namespace boost{ + +template +OutputIterator regex_replace(OutputIterator out, + BidirectionalIterator first, + BidirectionalIterator last, + const basic_regex& e, + Formatter fmt, + match_flag_type flags = match_default) +{ + regex_iterator i(first, last, e, flags); + regex_iterator j; + if(i == j) + { + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(first, last, out); + } + else + { + BidirectionalIterator last_m(first); + while(i != j) + { + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(i->prefix().first, i->prefix().second, out); + out = i->format(out, fmt, flags, e); + last_m = (*i)[0].second; + if(flags & regex_constants::format_first_only) + break; + ++i; + } + if(!(flags & regex_constants::format_no_copy)) + out = BOOST_REGEX_DETAIL_NS::copy(last_m, last, out); + } + return out; +} + +template +std::basic_string regex_replace(const std::basic_string& s, + const basic_regex& e, + Formatter fmt, + match_flag_type flags = match_default) +{ + std::basic_string result; + BOOST_REGEX_DETAIL_NS::string_out_iterator > i(result); + regex_replace(i, s.begin(), s.end(), e, fmt, flags); + return result; +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_REPLACE_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_search.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_search.hpp new file mode 100644 index 0000000000..d0addb1948 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_search.hpp @@ -0,0 +1,103 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_search.hpp + * VERSION see + * DESCRIPTION: Provides regex_search implementation. + */ + +#ifndef BOOST_REGEX_V5_REGEX_SEARCH_HPP +#define BOOST_REGEX_V5_REGEX_SEARCH_HPP + + +namespace boost{ + +template +bool regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(first, last, m, e, flags, first); +} + +template +bool regex_search(BidiIterator first, BidiIterator last, + match_results& m, + const basic_regex& e, + match_flag_type flags, + BidiIterator base) +{ + if(e.flags() & regex_constants::failbit) + return false; + + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags, base); + return matcher.find(); +} + +// +// regex_search convenience interfaces: +// +template +inline bool regex_search(const charT* str, + match_results& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + traits::length(str), m, e, flags); +} + +template +inline bool regex_search(const std::basic_string& s, + match_results::const_iterator, Allocator>& m, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), m, e, flags); +} + +template +bool regex_search(BidiIterator first, BidiIterator last, + const basic_regex& e, + match_flag_type flags = match_default) +{ + if(e.flags() & regex_constants::failbit) + return false; + + match_results m; + typedef typename match_results::allocator_type match_alloc_type; + BOOST_REGEX_DETAIL_NS::perl_matcher matcher(first, last, m, e, flags | regex_constants::match_any, first); + return matcher.find(); +} + +template +inline bool regex_search(const charT* str, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(str, str + traits::length(str), e, flags); +} + +template +inline bool regex_search(const std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_search(s.begin(), s.end(), e, flags); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_SEARCH_HPP + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_split.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_split.hpp new file mode 100644 index 0000000000..8d93289649 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_split.hpp @@ -0,0 +1,152 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_split.hpp + * VERSION see + * DESCRIPTION: Implements regex_split and associated functions. + * Note this is an internal header file included + * by regex.hpp, do not include on its own. + */ + +#ifndef BOOST_REGEX_SPLIT_HPP +#define BOOST_REGEX_SPLIT_HPP + +namespace boost{ + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +namespace BOOST_REGEX_DETAIL_NS{ + +template +const basic_regex& get_default_expression(charT) +{ + static const charT expression_text[4] = { '\\', 's', '+', '\00', }; + static const basic_regex e(expression_text); + return e; +} + +template +class split_pred +{ + typedef std::basic_string string_type; + typedef typename string_type::const_iterator iterator_type; + iterator_type* p_last; + OutputIterator* p_out; + std::size_t* p_max; + std::size_t initial_max; +public: + split_pred(iterator_type* a, OutputIterator* b, std::size_t* c) + : p_last(a), p_out(b), p_max(c), initial_max(*c) {} + + bool operator()(const match_results& what); +}; + +template +bool split_pred::operator() + (const match_results& what) +{ + *p_last = what[0].second; + if(what.size() > 1) + { + // output sub-expressions only: + for(unsigned i = 1; i < what.size(); ++i) + { + *(*p_out) = what.str(i); + ++(*p_out); + if(0 == --*p_max) return false; + } + return *p_max != 0; + } + else + { + // output $` only if it's not-null or not at the start of the input: + const sub_match& sub = what[-1]; + if((sub.first != sub.second) || (*p_max != initial_max)) + { + *(*p_out) = sub.str(); + ++(*p_out); + return --*p_max; + } + } + // + // initial null, do nothing: + return true; +} + +} // namespace BOOST_REGEX_DETAIL_NS + +template +std::size_t regex_split(OutputIterator out, + std::basic_string& s, + const basic_regex& e, + match_flag_type flags, + std::size_t max_split) +{ + typedef typename std::basic_string::const_iterator ci_t; + //typedef typename match_results::allocator_type match_allocator; + ci_t last = s.begin(); + std::size_t init_size = max_split; + BOOST_REGEX_DETAIL_NS::split_pred pred(&last, &out, &max_split); + ci_t i, j; + i = s.begin(); + j = s.end(); + regex_grep(pred, i, j, e, flags); + // + // if there is still input left, do a final push as long as max_split + // is not exhausted, and we're not splitting sub-expressions rather + // than whitespace: + if(max_split && (last != s.end()) && (e.mark_count() == 0)) + { + *out = std::basic_string((ci_t)last, (ci_t)s.end()); + ++out; + last = s.end(); + --max_split; + } + // + // delete from the string everything that has been processed so far: + s.erase(0, last - s.begin()); + // + // return the number of new records pushed: + return init_size - max_split; +} + +template +inline std::size_t regex_split(OutputIterator out, + std::basic_string& s, + const basic_regex& e, + match_flag_type flags = match_default) +{ + return regex_split(out, s, e, flags, UINT_MAX); +} + +template +inline std::size_t regex_split(OutputIterator out, + std::basic_string& s) +{ + return regex_split(out, s, BOOST_REGEX_DETAIL_NS::get_default_expression(charT(0)), match_default, UINT_MAX); +} + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +} // namespace boost + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_token_iterator.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_token_iterator.hpp new file mode 100644 index 0000000000..16832746f7 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_token_iterator.hpp @@ -0,0 +1,255 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_token_iterator.hpp + * VERSION see + * DESCRIPTION: Provides regex_token_iterator implementation. + */ + +#ifndef BOOST_REGEX_V5_REGEX_TOKEN_ITERATOR_HPP +#define BOOST_REGEX_V5_REGEX_TOKEN_ITERATOR_HPP + +#include + +namespace boost{ + +template +class regex_token_iterator_implementation +{ + typedef basic_regex regex_type; + typedef sub_match value_type; + + match_results what; // current match + BidirectionalIterator base; // start of search area + BidirectionalIterator end; // end of search area + const regex_type re; // the expression + match_flag_type flags; // match flags + value_type result; // the current string result + int N; // the current sub-expression being enumerated + std::vector subs; // the sub-expressions to enumerate + +public: + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, int sub, match_flag_type f) + : end(last), re(*p), flags(f), N(0){ subs.push_back(sub); } + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const std::vector& v, match_flag_type f) + : end(last), re(*p), flags(f), N(0), subs(v){} + template + regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const int (&submatches)[CN], match_flag_type f) + : end(last), re(*p), flags(f), N(0) + { + for(std::size_t i = 0; i < CN; ++i) + { + subs.push_back(submatches[i]); + } + } + regex_token_iterator_implementation(const regex_token_iterator_implementation& other) = default; + bool init(BidirectionalIterator first) + { + N = 0; + base = first; + if(regex_search(first, end, what, re, flags, base) == true) + { + N = 0; + result = ((subs[N] == -1) ? what.prefix() : what[(int)subs[N]]); + return true; + } + else if((subs[N] == -1) && (first != end)) + { + result.first = first; + result.second = end; + result.matched = (first != end); + N = -1; + return true; + } + return false; + } + bool compare(const regex_token_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) + && (end == that.end) + && (flags == that.flags) + && (N == that.N) + && (what[0].first == that.what[0].first) + && (what[0].second == that.what[0].second); + } + const value_type& get() + { return result; } + bool next() + { + if(N == -1) + return false; + if(N+1 < (int)subs.size()) + { + ++N; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + //if(what.prefix().first != what[0].second) + // flags |= /*match_prev_avail |*/ regex_constants::match_not_bob; + BidirectionalIterator last_end(what[0].second); + if(regex_search(last_end, end, what, re, ((what[0].first == what[0].second) ? flags | regex_constants::match_not_initial_null : flags), base)) + { + N =0; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + else if((last_end != end) && (subs[0] == -1)) + { + N =-1; + result.first = last_end; + result.second = end; + result.matched = (last_end != end); + return true; + } + return false; + } +private: + regex_token_iterator_implementation& operator=(const regex_token_iterator_implementation&); +}; + +template ::value_type, + class traits = regex_traits > +class regex_token_iterator +{ +private: + typedef regex_token_iterator_implementation impl; + typedef std::shared_ptr pimpl; +public: + typedef basic_regex regex_type; + typedef sub_match value_type; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + regex_token_iterator(){} + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + int submatch = 0, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatch, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const std::vector& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + template + regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const int (&submatches)[N], match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + regex_token_iterator(const regex_token_iterator& that) + : pdata(that.pdata) {} + regex_token_iterator& operator=(const regex_token_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const regex_token_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const regex_token_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + regex_token_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + regex_token_iterator operator++(int) + { + regex_token_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && (pdata.use_count() > 1)) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef regex_token_iterator cregex_token_iterator; +typedef regex_token_iterator sregex_token_iterator; +#ifndef BOOST_NO_WREGEX +typedef regex_token_iterator wcregex_token_iterator; +typedef regex_token_iterator wsregex_token_iterator; +#endif + +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} +template +inline regex_token_iterator make_regex_token_iterator(const charT* p, const basic_regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator(p, p+traits::length(p), e, submatch, m); +} +template +inline regex_token_iterator::const_iterator, charT, traits> make_regex_token_iterator(const std::basic_string& p, const basic_regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return regex_token_iterator::const_iterator, charT, traits>(p.begin(), p.end(), e, submatch, m); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_TOKEN_ITERATOR_HPP + + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_traits.hpp new file mode 100644 index 0000000000..6c64695b61 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_traits.hpp @@ -0,0 +1,130 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits classes. + */ + +#ifndef BOOST_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_REGEX_TRAITS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#if defined(_WIN32) && !defined(BOOST_REGEX_NO_W32) +# include +#endif +#include + +namespace boost{ + +template +struct regex_traits : public implementationT +{ + regex_traits() : implementationT() {} +}; + +// +// class regex_traits_wrapper. +// this is what our implementation will actually store; +// it provides default implementations of the "optional" +// interfaces that we support, in addition to the +// required "standard" ones: +// +namespace BOOST_REGEX_DETAIL_NS{ + + template + struct has_boost_extensions_tag + { + template + static double checker(U*, typename U::boost_extensions_tag* = nullptr); + static char checker(...); + static T* get(); + + static const bool value = sizeof(checker(get())) > 1; + }; + + +template +struct default_wrapper : public BaseT +{ + typedef typename BaseT::char_type char_type; + std::string error_string(::boost::regex_constants::error_type e)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::get_default_error_string(e); + } + ::boost::regex_constants::syntax_type syntax_type(char_type c)const + { + return (char_type(c & 0x7f) == c) ? get_default_syntax_type(static_cast(c)) : ::boost::regex_constants::syntax_char; + } + ::boost::regex_constants::escape_syntax_type escape_syntax_type(char_type c)const + { + return (char_type(c & 0x7f) == c) ? get_default_escape_syntax_type(static_cast(c)) : ::boost::regex_constants::escape_type_identity; + } + std::intmax_t toi(const char_type*& p1, const char_type* p2, int radix)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + char_type translate(char_type c, bool icase)const + { + return (icase ? this->translate_nocase(c) : this->translate(c)); + } + char_type translate(char_type c)const + { + return BaseT::translate(c); + } + char_type tolower(char_type c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_lower(c); + } + char_type toupper(char_type c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_upper(c); + } +}; + +template +struct compute_wrapper_base +{ + typedef BaseT type; +}; +template +struct compute_wrapper_base +{ + typedef default_wrapper type; +}; + +} // namespace BOOST_REGEX_DETAIL_NS + +template +struct regex_traits_wrapper + : public ::boost::BOOST_REGEX_DETAIL_NS::compute_wrapper_base< + BaseT, + ::boost::BOOST_REGEX_DETAIL_NS::has_boost_extensions_tag::value + >::type +{ + regex_traits_wrapper(){} +private: + regex_traits_wrapper(const regex_traits_wrapper&); + regex_traits_wrapper& operator=(const regex_traits_wrapper&); +}; + +} // namespace boost + +#endif // include + diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_traits_defaults.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_traits_defaults.hpp new file mode 100644 index 0000000000..4b81441ffe --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_traits_defaults.hpp @@ -0,0 +1,996 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_traits_defaults.hpp + * VERSION see + * DESCRIPTION: Declares API's for access to regex_traits default properties. + */ + +#ifndef BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED +#define BOOST_REGEX_TRAITS_DEFAULTS_HPP_INCLUDED + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + + +// +// helpers to suppress warnings: +// +template +inline bool is_extended(charT c) +{ + typedef typename std::make_unsigned::type unsigned_type; + return (sizeof(charT) > 1) && (static_cast(c) >= 256u); +} +inline bool is_extended(char) +{ return false; } + +inline const char* get_default_syntax(regex_constants::syntax_type n) +{ + // if the user hasn't supplied a message catalog, then this supplies + // default "messages" for us to load in the range 1-100. + const char* messages[] = { + "", + "(", + ")", + "$", + "^", + ".", + "*", + "+", + "?", + "[", + "]", + "|", + "\\", + "#", + "-", + "{", + "}", + "0123456789", + "b", + "B", + "<", + ">", + "", + "", + "A`", + "z'", + "\n", + ",", + "a", + "f", + "n", + "r", + "t", + "v", + "x", + "c", + ":", + "=", + "e", + "", + "", + "", + "", + "", + "", + "", + "", + "E", + "Q", + "X", + "C", + "Z", + "G", + "!", + "p", + "P", + "N", + "gk", + "K", + "R", + }; + + return ((n >= (sizeof(messages) / sizeof(messages[1]))) ? "" : messages[n]); +} + +inline const char* get_default_error_string(regex_constants::error_type n) +{ + static const char* const s_default_error_messages[] = { + "Success", /* REG_NOERROR 0 error_ok */ + "No match", /* REG_NOMATCH 1 error_no_match */ + "Invalid regular expression.", /* REG_BADPAT 2 error_bad_pattern */ + "Invalid collation character.", /* REG_ECOLLATE 3 error_collate */ + "Invalid character class name, collating name, or character range.", /* REG_ECTYPE 4 error_ctype */ + "Invalid or unterminated escape sequence.", /* REG_EESCAPE 5 error_escape */ + "Invalid back reference: specified capturing group does not exist.", /* REG_ESUBREG 6 error_backref */ + "Unmatched [ or [^ in character class declaration.", /* REG_EBRACK 7 error_brack */ + "Unmatched marking parenthesis ( or \\(.", /* REG_EPAREN 8 error_paren */ + "Unmatched quantified repeat operator { or \\{.", /* REG_EBRACE 9 error_brace */ + "Invalid content of repeat range.", /* REG_BADBR 10 error_badbrace */ + "Invalid range end in character class", /* REG_ERANGE 11 error_range */ + "Out of memory.", /* REG_ESPACE 12 error_space NOT USED */ + "Invalid preceding regular expression prior to repetition operator.", /* REG_BADRPT 13 error_badrepeat */ + "Premature end of regular expression", /* REG_EEND 14 error_end NOT USED */ + "Regular expression is too large.", /* REG_ESIZE 15 error_size NOT USED */ + "Unmatched ) or \\)", /* REG_ERPAREN 16 error_right_paren NOT USED */ + "Empty regular expression.", /* REG_EMPTY 17 error_empty */ + "The complexity of matching the regular expression exceeded predefined bounds. " + "Try refactoring the regular expression to make each choice made by the state machine unambiguous. " + "This exception is thrown to prevent \"eternal\" matches that take an " + "indefinite period time to locate.", /* REG_ECOMPLEXITY 18 error_complexity */ + "Ran out of stack space trying to match the regular expression.", /* REG_ESTACK 19 error_stack */ + "Invalid or unterminated Perl (?...) sequence.", /* REG_E_PERL 20 error_perl */ + "Unknown error.", /* REG_E_UNKNOWN 21 error_unknown */ + }; + + return (n > ::boost::regex_constants::error_unknown) ? s_default_error_messages[::boost::regex_constants::error_unknown] : s_default_error_messages[n]; +} + +inline regex_constants::syntax_type get_default_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::syntax_type char_syntax[] = { + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_newline, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /* */ // 32 + regex_constants::syntax_not, /*!*/ + regex_constants::syntax_char, /*"*/ + regex_constants::syntax_hash, /*#*/ + regex_constants::syntax_dollar, /*$*/ + regex_constants::syntax_char, /*%*/ + regex_constants::syntax_char, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::syntax_star, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::syntax_comma, /*,*/ + regex_constants::syntax_dash, /*-*/ + regex_constants::syntax_dot, /*.*/ + regex_constants::syntax_char, /*/*/ + regex_constants::syntax_digit, /*0*/ + regex_constants::syntax_digit, /*1*/ + regex_constants::syntax_digit, /*2*/ + regex_constants::syntax_digit, /*3*/ + regex_constants::syntax_digit, /*4*/ + regex_constants::syntax_digit, /*5*/ + regex_constants::syntax_digit, /*6*/ + regex_constants::syntax_digit, /*7*/ + regex_constants::syntax_digit, /*8*/ + regex_constants::syntax_digit, /*9*/ + regex_constants::syntax_colon, /*:*/ + regex_constants::syntax_char, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::syntax_equal, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::syntax_char, /*@*/ + regex_constants::syntax_char, /*A*/ + regex_constants::syntax_char, /*B*/ + regex_constants::syntax_char, /*C*/ + regex_constants::syntax_char, /*D*/ + regex_constants::syntax_char, /*E*/ + regex_constants::syntax_char, /*F*/ + regex_constants::syntax_char, /*G*/ + regex_constants::syntax_char, /*H*/ + regex_constants::syntax_char, /*I*/ + regex_constants::syntax_char, /*J*/ + regex_constants::syntax_char, /*K*/ + regex_constants::syntax_char, /*L*/ + regex_constants::syntax_char, /*M*/ + regex_constants::syntax_char, /*N*/ + regex_constants::syntax_char, /*O*/ + regex_constants::syntax_char, /*P*/ + regex_constants::syntax_char, /*Q*/ + regex_constants::syntax_char, /*R*/ + regex_constants::syntax_char, /*S*/ + regex_constants::syntax_char, /*T*/ + regex_constants::syntax_char, /*U*/ + regex_constants::syntax_char, /*V*/ + regex_constants::syntax_char, /*W*/ + regex_constants::syntax_char, /*X*/ + regex_constants::syntax_char, /*Y*/ + regex_constants::syntax_char, /*Z*/ + regex_constants::syntax_open_set, /*[*/ + regex_constants::syntax_escape, /*\*/ + regex_constants::syntax_close_set, /*]*/ + regex_constants::syntax_caret, /*^*/ + regex_constants::syntax_char, /*_*/ + regex_constants::syntax_char, /*`*/ + regex_constants::syntax_char, /*a*/ + regex_constants::syntax_char, /*b*/ + regex_constants::syntax_char, /*c*/ + regex_constants::syntax_char, /*d*/ + regex_constants::syntax_char, /*e*/ + regex_constants::syntax_char, /*f*/ + regex_constants::syntax_char, /*g*/ + regex_constants::syntax_char, /*h*/ + regex_constants::syntax_char, /*i*/ + regex_constants::syntax_char, /*j*/ + regex_constants::syntax_char, /*k*/ + regex_constants::syntax_char, /*l*/ + regex_constants::syntax_char, /*m*/ + regex_constants::syntax_char, /*n*/ + regex_constants::syntax_char, /*o*/ + regex_constants::syntax_char, /*p*/ + regex_constants::syntax_char, /*q*/ + regex_constants::syntax_char, /*r*/ + regex_constants::syntax_char, /*s*/ + regex_constants::syntax_char, /*t*/ + regex_constants::syntax_char, /*u*/ + regex_constants::syntax_char, /*v*/ + regex_constants::syntax_char, /*w*/ + regex_constants::syntax_char, /*x*/ + regex_constants::syntax_char, /*y*/ + regex_constants::syntax_char, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::syntax_char, /*~*/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + regex_constants::syntax_char, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + +inline regex_constants::escape_syntax_type get_default_escape_syntax_type(char c) +{ + // + // char_syntax determines how the compiler treats a given character + // in a regular expression. + // + static regex_constants::escape_syntax_type char_syntax[] = { + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /* */ // 32 + regex_constants::escape_type_identity, /*!*/ + regex_constants::escape_type_identity, /*"*/ + regex_constants::escape_type_identity, /*#*/ + regex_constants::escape_type_identity, /*$*/ + regex_constants::escape_type_identity, /*%*/ + regex_constants::escape_type_identity, /*&*/ + regex_constants::escape_type_end_buffer, /*'*/ + regex_constants::syntax_open_mark, /*(*/ + regex_constants::syntax_close_mark, /*)*/ + regex_constants::escape_type_identity, /***/ + regex_constants::syntax_plus, /*+*/ + regex_constants::escape_type_identity, /*,*/ + regex_constants::escape_type_identity, /*-*/ + regex_constants::escape_type_identity, /*.*/ + regex_constants::escape_type_identity, /*/*/ + regex_constants::escape_type_decimal, /*0*/ + regex_constants::escape_type_backref, /*1*/ + regex_constants::escape_type_backref, /*2*/ + regex_constants::escape_type_backref, /*3*/ + regex_constants::escape_type_backref, /*4*/ + regex_constants::escape_type_backref, /*5*/ + regex_constants::escape_type_backref, /*6*/ + regex_constants::escape_type_backref, /*7*/ + regex_constants::escape_type_backref, /*8*/ + regex_constants::escape_type_backref, /*9*/ + regex_constants::escape_type_identity, /*:*/ + regex_constants::escape_type_identity, /*;*/ + regex_constants::escape_type_left_word, /*<*/ + regex_constants::escape_type_identity, /*=*/ + regex_constants::escape_type_right_word, /*>*/ + regex_constants::syntax_question, /*?*/ + regex_constants::escape_type_identity, /*@*/ + regex_constants::escape_type_start_buffer, /*A*/ + regex_constants::escape_type_not_word_assert, /*B*/ + regex_constants::escape_type_C, /*C*/ + regex_constants::escape_type_not_class, /*D*/ + regex_constants::escape_type_E, /*E*/ + regex_constants::escape_type_not_class, /*F*/ + regex_constants::escape_type_G, /*G*/ + regex_constants::escape_type_not_class, /*H*/ + regex_constants::escape_type_not_class, /*I*/ + regex_constants::escape_type_not_class, /*J*/ + regex_constants::escape_type_reset_start_mark, /*K*/ + regex_constants::escape_type_not_class, /*L*/ + regex_constants::escape_type_not_class, /*M*/ + regex_constants::escape_type_named_char, /*N*/ + regex_constants::escape_type_not_class, /*O*/ + regex_constants::escape_type_not_property, /*P*/ + regex_constants::escape_type_Q, /*Q*/ + regex_constants::escape_type_line_ending, /*R*/ + regex_constants::escape_type_not_class, /*S*/ + regex_constants::escape_type_not_class, /*T*/ + regex_constants::escape_type_not_class, /*U*/ + regex_constants::escape_type_not_class, /*V*/ + regex_constants::escape_type_not_class, /*W*/ + regex_constants::escape_type_X, /*X*/ + regex_constants::escape_type_not_class, /*Y*/ + regex_constants::escape_type_Z, /*Z*/ + regex_constants::escape_type_identity, /*[*/ + regex_constants::escape_type_identity, /*\*/ + regex_constants::escape_type_identity, /*]*/ + regex_constants::escape_type_identity, /*^*/ + regex_constants::escape_type_identity, /*_*/ + regex_constants::escape_type_start_buffer, /*`*/ + regex_constants::escape_type_control_a, /*a*/ + regex_constants::escape_type_word_assert, /*b*/ + regex_constants::escape_type_ascii_control, /*c*/ + regex_constants::escape_type_class, /*d*/ + regex_constants::escape_type_e, /*e*/ + regex_constants::escape_type_control_f, /*f*/ + regex_constants::escape_type_extended_backref, /*g*/ + regex_constants::escape_type_class, /*h*/ + regex_constants::escape_type_class, /*i*/ + regex_constants::escape_type_class, /*j*/ + regex_constants::escape_type_extended_backref, /*k*/ + regex_constants::escape_type_class, /*l*/ + regex_constants::escape_type_class, /*m*/ + regex_constants::escape_type_control_n, /*n*/ + regex_constants::escape_type_class, /*o*/ + regex_constants::escape_type_property, /*p*/ + regex_constants::escape_type_class, /*q*/ + regex_constants::escape_type_control_r, /*r*/ + regex_constants::escape_type_class, /*s*/ + regex_constants::escape_type_control_t, /*t*/ + regex_constants::escape_type_class, /*u*/ + regex_constants::escape_type_control_v, /*v*/ + regex_constants::escape_type_class, /*w*/ + regex_constants::escape_type_hex, /*x*/ + regex_constants::escape_type_class, /*y*/ + regex_constants::escape_type_end_buffer, /*z*/ + regex_constants::syntax_open_brace, /*{*/ + regex_constants::syntax_or, /*|*/ + regex_constants::syntax_close_brace, /*}*/ + regex_constants::escape_type_identity, /*~*/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + regex_constants::escape_type_identity, /**/ + }; + + return char_syntax[(unsigned char)c]; +} + +// is charT c a combining character? +inline bool is_combining_implementation(std::uint_least16_t c) +{ + const std::uint_least16_t combining_ranges[] = { 0x0300, 0x0361, + 0x0483, 0x0486, + 0x0903, 0x0903, + 0x093E, 0x0940, + 0x0949, 0x094C, + 0x0982, 0x0983, + 0x09BE, 0x09C0, + 0x09C7, 0x09CC, + 0x09D7, 0x09D7, + 0x0A3E, 0x0A40, + 0x0A83, 0x0A83, + 0x0ABE, 0x0AC0, + 0x0AC9, 0x0ACC, + 0x0B02, 0x0B03, + 0x0B3E, 0x0B3E, + 0x0B40, 0x0B40, + 0x0B47, 0x0B4C, + 0x0B57, 0x0B57, + 0x0B83, 0x0B83, + 0x0BBE, 0x0BBF, + 0x0BC1, 0x0BCC, + 0x0BD7, 0x0BD7, + 0x0C01, 0x0C03, + 0x0C41, 0x0C44, + 0x0C82, 0x0C83, + 0x0CBE, 0x0CBE, + 0x0CC0, 0x0CC4, + 0x0CC7, 0x0CCB, + 0x0CD5, 0x0CD6, + 0x0D02, 0x0D03, + 0x0D3E, 0x0D40, + 0x0D46, 0x0D4C, + 0x0D57, 0x0D57, + 0x0F7F, 0x0F7F, + 0x20D0, 0x20E1, + 0x3099, 0x309A, + 0xFE20, 0xFE23, + 0xffff, 0xffff, }; + + const std::uint_least16_t* p = combining_ranges + 1; + while (*p < c) p += 2; + --p; + if ((c >= *p) && (c <= *(p + 1))) + return true; + return false; +} + +template +inline bool is_combining(charT c) +{ + return (c <= static_cast(0)) ? false : ((c >= static_cast((std::numeric_limits::max)())) ? false : is_combining_implementation(static_cast(c))); +} +template <> +inline bool is_combining(char) +{ + return false; +} +template <> +inline bool is_combining(signed char) +{ + return false; +} +template <> +inline bool is_combining(unsigned char) +{ + return false; +} +#ifdef _MSC_VER +template<> +inline bool is_combining(wchar_t c) +{ + return is_combining_implementation(static_cast(c)); +} +#elif !defined(__DECCXX) && !defined(__osf__) && !defined(__OSF__) && defined(WCHAR_MIN) && (WCHAR_MIN == 0) && !defined(BOOST_NO_INTRINSIC_WCHAR_T) +#if defined(WCHAR_MAX) && (WCHAR_MAX <= USHRT_MAX) +template<> +inline bool is_combining(wchar_t c) +{ + return is_combining_implementation(static_cast(c)); +} +#else +template<> +inline bool is_combining(wchar_t c) +{ + return (c >= (std::numeric_limits::max)()) ? false : is_combining_implementation(static_cast(c)); +} +#endif +#endif + +// +// is a charT c a line separator? +// +template +inline bool is_separator(charT c) +{ + return BOOST_REGEX_MAKE_BOOL( + (c == static_cast('\n')) + || (c == static_cast('\r')) + || (c == static_cast('\f')) + || (static_cast(c) == 0x2028u) + || (static_cast(c) == 0x2029u) + || (static_cast(c) == 0x85u)); +} +template <> +inline bool is_separator(char c) +{ + return BOOST_REGEX_MAKE_BOOL((c == '\n') || (c == '\r') || (c == '\f')); +} + +// +// get a default collating element: +// +inline std::string lookup_default_collate_name(const std::string& name) +{ + // + // these are the POSIX collating names: + // + static const char* def_coll_names[] = { + "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "alert", "backspace", "tab", "newline", + "vertical-tab", "form-feed", "carriage-return", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", + "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "IS4", "IS3", "IS2", "IS1", "space", "exclamation-mark", + "quotation-mark", "number-sign", "dollar-sign", "percent-sign", "ampersand", "apostrophe", + "left-parenthesis", "right-parenthesis", "asterisk", "plus-sign", "comma", "hyphen", + "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", + "colon", "semicolon", "less-than-sign", "equals-sign", "greater-than-sign", + "question-mark", "commercial-at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", + "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "left-square-bracket", "backslash", + "right-square-bracket", "circumflex", "underscore", "grave-accent", "a", "b", "c", "d", "e", "f", + "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "left-curly-bracket", + "vertical-line", "right-curly-bracket", "tilde", "DEL", "", + }; + + // these multi-character collating elements + // should keep most Western-European locales + // happy - we should really localise these a + // little more - but this will have to do for + // now: + + static const char* def_multi_coll[] = { + "ae", + "Ae", + "AE", + "ch", + "Ch", + "CH", + "ll", + "Ll", + "LL", + "ss", + "Ss", + "SS", + "nj", + "Nj", + "NJ", + "dz", + "Dz", + "DZ", + "lj", + "Lj", + "LJ", + "", + }; + + unsigned int i = 0; + while (*def_coll_names[i]) + { + if (def_coll_names[i] == name) + { + return std::string(1, char(i)); + } + ++i; + } + i = 0; + while (*def_multi_coll[i]) + { + if (def_multi_coll[i] == name) + { + return def_multi_coll[i]; + } + ++i; + } + return std::string(); +} + +// +// get the state_id of a character classification, the individual +// traits classes then transform that state_id into a bitmask: +// +template +struct character_pointer_range +{ + const charT* p1; + const charT* p2; + + bool operator < (const character_pointer_range& r)const + { + return std::lexicographical_compare(p1, p2, r.p1, r.p2); + } + bool operator == (const character_pointer_range& r)const + { + // Not only do we check that the ranges are of equal size before + // calling std::equal, but there is no other algorithm available: + // not even a non-standard MS one. So forward to unchecked_equal + // in the MS case. +#ifdef __cpp_lib_robust_nonmodifying_seq_ops + return std::equal(p1, p2, r.p1, r.p2); +#elif defined(BOOST_REGEX_MSVC) + if (((p2 - p1) != (r.p2 - r.p1))) + return false; + const charT* with = r.p1; + const charT* pos = p1; + while (pos != p2) + if (*pos++ != *with++) return false; + return true; + +#else + return ((p2 - p1) == (r.p2 - r.p1)) && std::equal(p1, p2, r.p1); +#endif + } +}; +template +int get_default_class_id(const charT* p1, const charT* p2) +{ + static const charT data[73] = { + 'a', 'l', 'n', 'u', 'm', + 'a', 'l', 'p', 'h', 'a', + 'b', 'l', 'a', 'n', 'k', + 'c', 'n', 't', 'r', 'l', + 'd', 'i', 'g', 'i', 't', + 'g', 'r', 'a', 'p', 'h', + 'l', 'o', 'w', 'e', 'r', + 'p', 'r', 'i', 'n', 't', + 'p', 'u', 'n', 'c', 't', + 's', 'p', 'a', 'c', 'e', + 'u', 'n', 'i', 'c', 'o', 'd', 'e', + 'u', 'p', 'p', 'e', 'r', + 'v', + 'w', 'o', 'r', 'd', + 'x', 'd', 'i', 'g', 'i', 't', + }; + + static const character_pointer_range ranges[21] = + { + {data+0, data+5,}, // alnum + {data+5, data+10,}, // alpha + {data+10, data+15,}, // blank + {data+15, data+20,}, // cntrl + {data+20, data+21,}, // d + {data+20, data+25,}, // digit + {data+25, data+30,}, // graph + {data+29, data+30,}, // h + {data+30, data+31,}, // l + {data+30, data+35,}, // lower + {data+35, data+40,}, // print + {data+40, data+45,}, // punct + {data+45, data+46,}, // s + {data+45, data+50,}, // space + {data+57, data+58,}, // u + {data+50, data+57,}, // unicode + {data+57, data+62,}, // upper + {data+62, data+63,}, // v + {data+63, data+64,}, // w + {data+63, data+67,}, // word + {data+67, data+73,}, // xdigit + }; + const character_pointer_range* ranges_begin = ranges; + const character_pointer_range* ranges_end = ranges + (sizeof(ranges)/sizeof(ranges[0])); + + character_pointer_range t = { p1, p2, }; + const character_pointer_range* p = std::lower_bound(ranges_begin, ranges_end, t); + if((p != ranges_end) && (t == *p)) + return static_cast(p - ranges); + return -1; +} + +// +// helper functions: +// +template +std::ptrdiff_t global_length(const charT* p) +{ + std::ptrdiff_t n = 0; + while(*p) + { + ++p; + ++n; + } + return n; +} +template<> +inline std::ptrdiff_t global_length(const char* p) +{ + return (std::strlen)(p); +} +#ifndef BOOST_NO_WREGEX +template<> +inline std::ptrdiff_t global_length(const wchar_t* p) +{ + return (std::ptrdiff_t)(std::wcslen)(p); +} +#endif +template +inline charT global_lower(charT c) +{ + return c; +} +template +inline charT global_upper(charT c) +{ + return c; +} + +inline char do_global_lower(char c) +{ + return static_cast((std::tolower)((unsigned char)c)); +} + +inline char do_global_upper(char c) +{ + return static_cast((std::toupper)((unsigned char)c)); +} +#ifndef BOOST_NO_WREGEX +inline wchar_t do_global_lower(wchar_t c) +{ + return (std::towlower)(c); +} + +inline wchar_t do_global_upper(wchar_t c) +{ + return (std::towupper)(c); +} +#endif +// +// This sucks: declare template specialisations of global_lower/global_upper +// that just forward to the non-template implementation functions. We do +// this because there is one compiler (Compaq Tru64 C++) that doesn't seem +// to differentiate between templates and non-template overloads.... +// what's more, the primary template, plus all overloads have to be +// defined in the same translation unit (if one is inline they all must be) +// otherwise the "local template instantiation" compiler option can pick +// the wrong instantiation when linking: +// +template<> inline char global_lower(char c) { return do_global_lower(c); } +template<> inline char global_upper(char c) { return do_global_upper(c); } +#ifndef BOOST_NO_WREGEX +template<> inline wchar_t global_lower(wchar_t c) { return do_global_lower(c); } +template<> inline wchar_t global_upper(wchar_t c) { return do_global_upper(c); } +#endif + +template +int global_value(charT c) +{ + static const charT zero = '0'; + static const charT nine = '9'; + static const charT a = 'a'; + static const charT f = 'f'; + static const charT A = 'A'; + static const charT F = 'F'; + + if(c > f) return -1; + if(c >= a) return 10 + (c - a); + if(c > F) return -1; + if(c >= A) return 10 + (c - A); + if(c > nine) return -1; + if(c >= zero) return c - zero; + return -1; +} +template +std::intmax_t global_toi(const charT*& p1, const charT* p2, int radix, const traits& t) +{ + (void)t; // warning suppression + std::intmax_t limit = (std::numeric_limits::max)() / radix; + std::intmax_t next_value = t.value(*p1, radix); + if((p1 == p2) || (next_value < 0) || (next_value >= radix)) + return -1; + std::intmax_t result = 0; + while(p1 != p2) + { + next_value = t.value(*p1, radix); + if((next_value < 0) || (next_value >= radix)) + break; + result *= radix; + result += next_value; + ++p1; + if (result > limit) + return -1; + } + return result; +} + +template +inline typename std::enable_if<(sizeof(charT) > 1), const charT*>::type get_escape_R_string() +{ +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +# pragma warning(disable:4309 4245) +#endif + static const charT e1[] = { '(', '?', '-', 'x', ':', '(', '?', '>', '\x0D', '\x0A', '?', + '|', '[', '\x0A', '\x0B', '\x0C', static_cast(0x85), static_cast(0x2028), + static_cast(0x2029), ']', ')', ')', '\0' }; + static const charT e2[] = { '(', '?', '-', 'x', ':', '(', '?', '>', '\x0D', '\x0A', '?', + '|', '[', '\x0A', '\x0B', '\x0C', static_cast(0x85), ']', ')', ')', '\0' }; + + charT c = static_cast(0x2029u); + bool b = (static_cast(c) == 0x2029u); + + return (b ? e1 : e2); +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif +} + +template +inline typename std::enable_if<(sizeof(charT) == 1), const charT*>::type get_escape_R_string() +{ +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +# pragma warning(disable:4309 4245) +#endif + static const charT e2[] = { + static_cast('('), + static_cast('?'), + static_cast('-'), + static_cast('x'), + static_cast(':'), + static_cast('('), + static_cast('?'), + static_cast('>'), + static_cast('\x0D'), + static_cast('\x0A'), + static_cast('?'), + static_cast('|'), + static_cast('['), + static_cast('\x0A'), + static_cast('\x0B'), + static_cast('\x0C'), + static_cast('\x85'), + static_cast(']'), + static_cast(')'), + static_cast(')'), + static_cast('\0') + }; + return e2; +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif +} + +} // BOOST_REGEX_DETAIL_NS +} // boost + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/regex_workaround.hpp b/third-party/boost_regex/include/boost/regex/v5/regex_workaround.hpp new file mode 100644 index 0000000000..8cd9044ce5 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/regex_workaround.hpp @@ -0,0 +1,159 @@ +/* + * + * Copyright (c) 1998-2005 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE regex_workarounds.cpp + * VERSION see + * DESCRIPTION: Declares Misc workarounds. + */ + +#ifndef BOOST_REGEX_WORKAROUND_HPP +#define BOOST_REGEX_WORKAROUND_HPP + +#include +#include +#include +#include + +#ifndef BOOST_REGEX_STANDALONE +#include +#include +#endif + +#ifdef BOOST_REGEX_NO_BOOL +# define BOOST_REGEX_MAKE_BOOL(x) static_cast((x) ? true : false) +#else +# define BOOST_REGEX_MAKE_BOOL(x) static_cast(x) +#endif + +/***************************************************************************** + * + * helper functions pointer_construct/pointer_destroy: + * + ****************************************************************************/ + +#ifdef __cplusplus +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +#ifdef BOOST_REGEX_MSVC +#pragma warning (push) +#pragma warning (disable : 4100) +#endif + +template +inline void pointer_destroy(T* p) +{ p->~T(); (void)p; } + +#ifdef BOOST_REGEX_MSVC +#pragma warning (pop) +#endif + +template +inline void pointer_construct(T* p, const T& t) +{ new (p) T(t); } + +}} // namespaces +#endif + +/***************************************************************************** + * + * helper function copy: + * + ****************************************************************************/ + +#if defined(BOOST_WORKAROUND) +#if BOOST_WORKAROUND(BOOST_REGEX_MSVC, >= 1400) && defined(__STDC_WANT_SECURE_LIB__) && __STDC_WANT_SECURE_LIB__ +#define BOOST_REGEX_HAS_STRCPY_S +#endif +#endif + +#ifdef __cplusplus +namespace boost{ namespace BOOST_REGEX_DETAIL_NS{ + +#if defined(BOOST_REGEX_MSVC) && (BOOST_REGEX_MSVC < 1910) + // + // MSVC 10 will either emit warnings or else refuse to compile + // code that makes perfectly legitimate use of std::copy, when + // the OutputIterator type is a user-defined class (apparently all user + // defined iterators are "unsafe"). What's more Microsoft have removed their + // non-standard "unchecked" versions, even though they are still in the MS + // documentation!! Work around this as best we can: + // + template + inline OutputIterator copy( + InputIterator first, + InputIterator last, + OutputIterator dest + ) + { + while (first != last) + *dest++ = *first++; + return dest; + } +#else + using std::copy; +#endif + + +#if defined(BOOST_REGEX_HAS_STRCPY_S) + + // use safe versions of strcpy etc: + using ::strcpy_s; + using ::strcat_s; +#else + inline std::size_t strcpy_s( + char *strDestination, + std::size_t sizeInBytes, + const char *strSource + ) + { + std::size_t lenSourceWithNull = std::strlen(strSource) + 1; + if (lenSourceWithNull > sizeInBytes) + return 1; + std::memcpy(strDestination, strSource, lenSourceWithNull); + return 0; + } + inline std::size_t strcat_s( + char *strDestination, + std::size_t sizeInBytes, + const char *strSource + ) + { + std::size_t lenSourceWithNull = std::strlen(strSource) + 1; + std::size_t lenDestination = std::strlen(strDestination); + if (lenSourceWithNull + lenDestination > sizeInBytes) + return 1; + std::memcpy(strDestination + lenDestination, strSource, lenSourceWithNull); + return 0; + } + +#endif + + inline void overflow_error_if_not_zero(std::size_t i) + { + if(i) + { + std::overflow_error e("String buffer too small"); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif + } + } + +}} // namespaces + +#endif // __cplusplus + +#endif // include guard + diff --git a/third-party/boost_regex/include/boost/regex/v5/states.hpp b/third-party/boost_regex/include/boost/regex/v5/states.hpp new file mode 100644 index 0000000000..60fc99d0a8 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/states.hpp @@ -0,0 +1,299 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE states.cpp + * VERSION see + * DESCRIPTION: Declares internal state machine structures. + */ + +#ifndef BOOST_REGEX_V5_STATES_HPP +#define BOOST_REGEX_V5_STATES_HPP + +namespace boost{ +namespace BOOST_REGEX_DETAIL_NS{ + +/*** mask_type ******************************************************* +Whenever we have a choice of two alternatives, we use an array of bytes +to indicate which of the two alternatives it is possible to take for any +given input character. If mask_take is set, then we can take the next +state, and if mask_skip is set then we can take the alternative. +***********************************************************************/ +enum mask_type +{ + mask_take = 1, + mask_skip = 2, + mask_init = 4, + mask_any = mask_skip | mask_take, + mask_all = mask_any +}; + +/*** helpers ********************************************************** +These helpers let us use function overload resolution to detect whether +we have narrow or wide character strings: +***********************************************************************/ +struct _narrow_type{}; +struct _wide_type{}; +template struct is_byte; +template<> struct is_byte { typedef _narrow_type width_type; }; +template<> struct is_byte{ typedef _narrow_type width_type; }; +template<> struct is_byte { typedef _narrow_type width_type; }; +template struct is_byte { typedef _wide_type width_type; }; + +/*** enum syntax_element_type ****************************************** +Every record in the state machine falls into one of the following types: +***********************************************************************/ +enum syntax_element_type +{ + // start of a marked sub-expression, or perl-style (?...) extension + syntax_element_startmark = 0, + // end of a marked sub-expression, or perl-style (?...) extension + syntax_element_endmark = syntax_element_startmark + 1, + // any sequence of literal characters + syntax_element_literal = syntax_element_endmark + 1, + // start of line assertion: ^ + syntax_element_start_line = syntax_element_literal + 1, + // end of line assertion $ + syntax_element_end_line = syntax_element_start_line + 1, + // match any character: . + syntax_element_wild = syntax_element_end_line + 1, + // end of expression: we have a match when we get here + syntax_element_match = syntax_element_wild + 1, + // perl style word boundary: \b + syntax_element_word_boundary = syntax_element_match + 1, + // perl style within word boundary: \B + syntax_element_within_word = syntax_element_word_boundary + 1, + // start of word assertion: \< + syntax_element_word_start = syntax_element_within_word + 1, + // end of word assertion: \> + syntax_element_word_end = syntax_element_word_start + 1, + // start of buffer assertion: \` + syntax_element_buffer_start = syntax_element_word_end + 1, + // end of buffer assertion: \' + syntax_element_buffer_end = syntax_element_buffer_start + 1, + // backreference to previously matched sub-expression + syntax_element_backref = syntax_element_buffer_end + 1, + // either a wide character set [..] or one with multicharacter collating elements: + syntax_element_long_set = syntax_element_backref + 1, + // narrow character set: [...] + syntax_element_set = syntax_element_long_set + 1, + // jump to a new state in the machine: + syntax_element_jump = syntax_element_set + 1, + // choose between two production states: + syntax_element_alt = syntax_element_jump + 1, + // a repeat + syntax_element_rep = syntax_element_alt + 1, + // match a combining character sequence + syntax_element_combining = syntax_element_rep + 1, + // perl style soft buffer end: \z + syntax_element_soft_buffer_end = syntax_element_combining + 1, + // perl style continuation: \G + syntax_element_restart_continue = syntax_element_soft_buffer_end + 1, + // single character repeats: + syntax_element_dot_rep = syntax_element_restart_continue + 1, + syntax_element_char_rep = syntax_element_dot_rep + 1, + syntax_element_short_set_rep = syntax_element_char_rep + 1, + syntax_element_long_set_rep = syntax_element_short_set_rep + 1, + // a backstep for lookbehind repeats: + syntax_element_backstep = syntax_element_long_set_rep + 1, + // an assertion that a mark was matched: + syntax_element_assert_backref = syntax_element_backstep + 1, + syntax_element_toggle_case = syntax_element_assert_backref + 1, + // a recursive expression: + syntax_element_recurse = syntax_element_toggle_case + 1, + // Verbs: + syntax_element_fail = syntax_element_recurse + 1, + syntax_element_accept = syntax_element_fail + 1, + syntax_element_commit = syntax_element_accept + 1, + syntax_element_then = syntax_element_commit + 1 +}; + +#ifdef BOOST_REGEX_DEBUG +// dwa 09/26/00 - This is needed to suppress warnings about an ambiguous conversion +std::ostream& operator<<(std::ostream&, syntax_element_type); +#endif + +struct re_syntax_base; + +/*** union offset_type ************************************************ +Points to another state in the machine. During machine construction +we use integral offsets, but these are converted to pointers before +execution of the machine. +***********************************************************************/ +union offset_type +{ + re_syntax_base* p; + std::ptrdiff_t i; +}; + +/*** struct re_syntax_base ******************************************** +Base class for all states in the machine. +***********************************************************************/ +struct re_syntax_base +{ + syntax_element_type type; // what kind of state this is + offset_type next; // next state in the machine +}; + +/*** struct re_brace ************************************************** +A marked parenthesis. +***********************************************************************/ +struct re_brace : public re_syntax_base +{ + // The index to match, can be zero (don't mark the sub-expression) + // or negative (for perl style (?...) extensions): + int index; + bool icase; +}; + +/*** struct re_dot ************************************************** +Match anything. +***********************************************************************/ +enum +{ + dont_care = 1, + force_not_newline = 0, + force_newline = 2, + + test_not_newline = 2, + test_newline = 3 +}; +struct re_dot : public re_syntax_base +{ + unsigned char mask; +}; + +/*** struct re_literal ************************************************ +A string of literals, following this structure will be an +array of characters: charT[length] +***********************************************************************/ +struct re_literal : public re_syntax_base +{ + unsigned int length; +}; + +/*** struct re_case ************************************************ +Indicates whether we are moving to a case insensive block or not +***********************************************************************/ +struct re_case : public re_syntax_base +{ + bool icase; +}; + +/*** struct re_set_long *********************************************** +A wide character set of characters, following this structure will be +an array of type charT: +First csingles null-terminated strings +Then 2 * cranges NULL terminated strings +Then cequivalents NULL terminated strings +***********************************************************************/ +template +struct re_set_long : public re_syntax_base +{ + unsigned int csingles, cranges, cequivalents; + mask_type cclasses; + mask_type cnclasses; + bool isnot; + bool singleton; +}; + +/*** struct re_set **************************************************** +A set of narrow-characters, matches any of _map which is none-zero +***********************************************************************/ +struct re_set : public re_syntax_base +{ + unsigned char _map[1 << CHAR_BIT]; +}; + +/*** struct re_jump *************************************************** +Jump to a new location in the machine (not next). +***********************************************************************/ +struct re_jump : public re_syntax_base +{ + offset_type alt; // location to jump to +}; + +/*** struct re_alt *************************************************** +Jump to a new location in the machine (possibly next). +***********************************************************************/ +struct re_alt : public re_jump +{ + unsigned char _map[1 << CHAR_BIT]; // which characters can take the jump + unsigned int can_be_null; // true if we match a NULL string +}; + +/*** struct re_repeat ************************************************* +Repeat a section of the machine +***********************************************************************/ +struct re_repeat : public re_alt +{ + std::size_t min, max; // min and max allowable repeats + int state_id; // Unique identifier for this repeat + bool leading; // True if this repeat is at the start of the machine (lets us optimize some searches) + bool greedy; // True if this is a greedy repeat +}; + +/*** struct re_recurse ************************************************ +Recurse to a particular subexpression. +**********************************************************************/ +struct re_recurse : public re_jump +{ + int state_id; // identifier of first nested repeat within the recursion. +}; + +/*** struct re_commit ************************************************* +Used for the PRUNE, SKIP and COMMIT verbs which basically differ only in what happens +if no match is found and we start searching forward. +**********************************************************************/ +enum commit_type +{ + commit_prune, + commit_skip, + commit_commit +}; +struct re_commit : public re_syntax_base +{ + commit_type action; +}; + +/*** enum re_jump_size_type ******************************************* +Provides compiled size of re_jump structure (allowing for trailing alignment). +We provide this so we know how manybytes to insert when constructing the machine +(The value of padding_mask is defined in regex_raw_buffer.hpp). +***********************************************************************/ +enum re_jump_size_type +{ + re_jump_size = (sizeof(re_jump) + padding_mask) & ~(padding_mask), + re_repeater_size = (sizeof(re_repeat) + padding_mask) & ~(padding_mask), + re_alt_size = (sizeof(re_alt) + padding_mask) & ~(padding_mask) +}; + +/*** proc re_is_set_member ********************************************* +Forward declaration: we'll need this one later... +***********************************************************************/ + +template +struct regex_data; + +template +iterator re_is_set_member(iterator next, + iterator last, + const re_set_long* set_, + const regex_data& e, bool icase); + +} // namespace BOOST_REGEX_DETAIL_NS + +} // namespace boost + +#endif + + diff --git a/third-party/boost_regex/include/boost/regex/v5/sub_match.hpp b/third-party/boost_regex/include/boost/regex/v5/sub_match.hpp new file mode 100644 index 0000000000..aa61b560dd --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/sub_match.hpp @@ -0,0 +1,382 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE sub_match.cpp + * VERSION see + * DESCRIPTION: Declares template class sub_match. + */ + +#ifndef BOOST_REGEX_V5_SUB_MATCH_HPP +#define BOOST_REGEX_V5_SUB_MATCH_HPP + +namespace boost{ + +template +struct sub_match : public std::pair +{ + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef BidiIterator iterator_type; + typedef BidiIterator iterator; + typedef BidiIterator const_iterator; + + bool matched; + + sub_match() : std::pair(), matched(false) {} + sub_match(BidiIterator i) : std::pair(i, i), matched(false) {} + template + operator std::basic_string ()const + { + return matched ? std::basic_string(this->first, this->second) : std::basic_string(); + } + difference_type length()const + { + difference_type n = matched ? std::distance((BidiIterator)this->first, (BidiIterator)this->second) : 0; + return n; + } + std::basic_string str()const + { + std::basic_string result; + if(matched) + { + std::size_t len = std::distance((BidiIterator)this->first, (BidiIterator)this->second); + result.reserve(len); + BidiIterator i = this->first; + while(i != this->second) + { + result.append(1, *i); + ++i; + } + } + return result; + } + int compare(const sub_match& s)const + { + if(matched != s.matched) + return static_cast(matched) - static_cast(s.matched); + return str().compare(s.str()); + } + int compare(const std::basic_string& s)const + { + return str().compare(s); + } + int compare(const value_type* p)const + { + return str().compare(p); + } + + bool operator==(const sub_match& that)const + { return compare(that) == 0; } + bool operator !=(const sub_match& that)const + { return compare(that) != 0; } + bool operator<(const sub_match& that)const + { return compare(that) < 0; } + bool operator>(const sub_match& that)const + { return compare(that) > 0; } + bool operator<=(const sub_match& that)const + { return compare(that) <= 0; } + bool operator>=(const sub_match& that)const + { return compare(that) >= 0; } + +#ifdef BOOST_REGEX_MATCH_EXTRA + typedef std::vector > capture_sequence_type; + + const capture_sequence_type& captures()const + { + if(!m_captures) + m_captures.reset(new capture_sequence_type()); + return *m_captures; + } + // + // Private implementation API: DO NOT USE! + // + capture_sequence_type& get_captures()const + { + if(!m_captures) + m_captures.reset(new capture_sequence_type()); + return *m_captures; + } + +private: + mutable std::unique_ptr m_captures; +public: + +#endif + sub_match(const sub_match& that, bool +#ifdef BOOST_REGEX_MATCH_EXTRA + deep_copy +#endif + = true + ) + : std::pair(that), + matched(that.matched) + { +#ifdef BOOST_REGEX_MATCH_EXTRA + if(that.m_captures) + if(deep_copy) + m_captures.reset(new capture_sequence_type(*(that.m_captures))); +#endif + } + sub_match& operator=(const sub_match& that) + { + this->first = that.first; + this->second = that.second; + matched = that.matched; +#ifdef BOOST_REGEX_MATCH_EXTRA + if(that.m_captures) + get_captures() = *(that.m_captures); +#endif + return *this; + } + // + // Make this type a range, for both Boost.Range, and C++11: + // + BidiIterator begin()const { return this->first; } + BidiIterator end()const { return this->second; } +}; + +typedef sub_match csub_match; +typedef sub_match ssub_match; +#ifndef BOOST_NO_WREGEX +typedef sub_match wcsub_match; +typedef sub_match wssub_match; +#endif + +// comparison to std::basic_string<> part 1: +template +inline bool operator == (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) == 0; } +template +inline bool operator != (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) != 0; } +template +inline bool operator < (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) < 0; } +template +inline bool operator <= (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) <= 0; } +template +inline bool operator >= (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) >= 0; } +template +inline bool operator > (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ return s.compare(m.str()) > 0; } +// comparison to std::basic_string<> part 2: +template +inline bool operator == (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) != 0; } +template +inline bool operator < (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) < 0; } +template +inline bool operator > (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) > 0; } +template +inline bool operator <= (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) <= 0; } +template +inline bool operator >= (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ return m.str().compare(s) >= 0; } +// comparison to const charT* part 1: +template +inline bool operator == (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) != 0; } +template +inline bool operator > (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) > 0; } +template +inline bool operator < (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) < 0; } +template +inline bool operator >= (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) >= 0; } +template +inline bool operator <= (const sub_match& m, + typename std::iterator_traits::value_type const* s) +{ return m.str().compare(s) <= 0; } +// comparison to const charT* part 2: +template +inline bool operator == (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) == 0; } +template +inline bool operator != (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) != 0; } +template +inline bool operator < (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) > 0; } +template +inline bool operator > (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) < 0; } +template +inline bool operator <= (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) >= 0; } +template +inline bool operator >= (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ return m.str().compare(s) <= 0; } + +// comparison to const charT& part 1: +template +inline bool operator == (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) == 0; } +template +inline bool operator != (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) != 0; } +template +inline bool operator > (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) > 0; } +template +inline bool operator < (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) < 0; } +template +inline bool operator >= (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) >= 0; } +template +inline bool operator <= (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ return m.str().compare(0, m.length(), &s, 1) <= 0; } +// comparison to const charT* part 2: +template +inline bool operator == (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) == 0; } +template +inline bool operator != (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) != 0; } +template +inline bool operator < (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) > 0; } +template +inline bool operator > (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) < 0; } +template +inline bool operator <= (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) >= 0; } +template +inline bool operator >= (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ return m.str().compare(0, m.length(), &s, 1) <= 0; } + +// addition operators: +template +inline std::basic_string::value_type, traits, Allocator> +operator + (const std::basic_string::value_type, traits, Allocator>& s, + const sub_match& m) +{ + std::basic_string::value_type, traits, Allocator> result; + result.reserve(s.size() + m.length() + 1); + return result.append(s).append(m.first, m.second); +} +template +inline std::basic_string::value_type, traits, Allocator> +operator + (const sub_match& m, + const std::basic_string::value_type, traits, Allocator>& s) +{ + std::basic_string::value_type, traits, Allocator> result; + result.reserve(s.size() + m.length() + 1); + return result.append(m.first, m.second).append(s); +} +template +inline std::basic_string::value_type> +operator + (typename std::iterator_traits::value_type const* s, + const sub_match& m) +{ + std::basic_string::value_type> result; + result.reserve(std::char_traits::value_type>::length(s) + m.length() + 1); + return result.append(s).append(m.first, m.second); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m, + typename std::iterator_traits::value_type const * s) +{ + std::basic_string::value_type> result; + result.reserve(std::char_traits::value_type>::length(s) + m.length() + 1); + return result.append(m.first, m.second).append(s); +} +template +inline std::basic_string::value_type> +operator + (typename std::iterator_traits::value_type const& s, + const sub_match& m) +{ + std::basic_string::value_type> result; + result.reserve(m.length() + 2); + return result.append(1, s).append(m.first, m.second); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m, + typename std::iterator_traits::value_type const& s) +{ + std::basic_string::value_type> result; + result.reserve(m.length() + 2); + return result.append(m.first, m.second).append(1, s); +} +template +inline std::basic_string::value_type> +operator + (const sub_match& m1, + const sub_match& m2) +{ + std::basic_string::value_type> result; + result.reserve(m1.length() + m2.length() + 1); + return result.append(m1.first, m1.second).append(m2.first, m2.second); +} +template +std::basic_ostream& + operator << (std::basic_ostream& os, + const sub_match& s) +{ + return (os << s.str()); +} + +} // namespace boost + +#endif + diff --git a/third-party/boost_regex/include/boost/regex/v5/syntax_type.hpp b/third-party/boost_regex/include/boost/regex/v5/syntax_type.hpp new file mode 100644 index 0000000000..3efdf0b0f9 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/syntax_type.hpp @@ -0,0 +1,105 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE syntax_type.hpp + * VERSION see + * DESCRIPTION: Declares regular expression synatx type enumerator. + */ + +#ifndef BOOST_REGEX_SYNTAX_TYPE_HPP +#define BOOST_REGEX_SYNTAX_TYPE_HPP + +namespace boost{ +namespace regex_constants{ + +typedef unsigned char syntax_type; + +// +// values chosen are binary compatible with previous version: +// +static const syntax_type syntax_char = 0; +static const syntax_type syntax_open_mark = 1; +static const syntax_type syntax_close_mark = 2; +static const syntax_type syntax_dollar = 3; +static const syntax_type syntax_caret = 4; +static const syntax_type syntax_dot = 5; +static const syntax_type syntax_star = 6; +static const syntax_type syntax_plus = 7; +static const syntax_type syntax_question = 8; +static const syntax_type syntax_open_set = 9; +static const syntax_type syntax_close_set = 10; +static const syntax_type syntax_or = 11; +static const syntax_type syntax_escape = 12; +static const syntax_type syntax_dash = 14; +static const syntax_type syntax_open_brace = 15; +static const syntax_type syntax_close_brace = 16; +static const syntax_type syntax_digit = 17; +static const syntax_type syntax_comma = 27; +static const syntax_type syntax_equal = 37; +static const syntax_type syntax_colon = 36; +static const syntax_type syntax_not = 53; + +// extensions: + +static const syntax_type syntax_hash = 13; +static const syntax_type syntax_newline = 26; + +// escapes: + +typedef syntax_type escape_syntax_type; + +static const escape_syntax_type escape_type_word_assert = 18; +static const escape_syntax_type escape_type_not_word_assert = 19; +static const escape_syntax_type escape_type_control_f = 29; +static const escape_syntax_type escape_type_control_n = 30; +static const escape_syntax_type escape_type_control_r = 31; +static const escape_syntax_type escape_type_control_t = 32; +static const escape_syntax_type escape_type_control_v = 33; +static const escape_syntax_type escape_type_ascii_control = 35; +static const escape_syntax_type escape_type_hex = 34; +static const escape_syntax_type escape_type_unicode = 0; // not used +static const escape_syntax_type escape_type_identity = 0; // not used +static const escape_syntax_type escape_type_backref = syntax_digit; +static const escape_syntax_type escape_type_decimal = syntax_digit; // not used +static const escape_syntax_type escape_type_class = 22; +static const escape_syntax_type escape_type_not_class = 23; + +// extensions: + +static const escape_syntax_type escape_type_left_word = 20; +static const escape_syntax_type escape_type_right_word = 21; +static const escape_syntax_type escape_type_start_buffer = 24; // for \` +static const escape_syntax_type escape_type_end_buffer = 25; // for \' +static const escape_syntax_type escape_type_control_a = 28; // for \a +static const escape_syntax_type escape_type_e = 38; // for \e +static const escape_syntax_type escape_type_E = 47; // for \Q\E +static const escape_syntax_type escape_type_Q = 48; // for \Q\E +static const escape_syntax_type escape_type_X = 49; // for \X +static const escape_syntax_type escape_type_C = 50; // for \C +static const escape_syntax_type escape_type_Z = 51; // for \Z +static const escape_syntax_type escape_type_G = 52; // for \G + +static const escape_syntax_type escape_type_property = 54; // for \p +static const escape_syntax_type escape_type_not_property = 55; // for \P +static const escape_syntax_type escape_type_named_char = 56; // for \N +static const escape_syntax_type escape_type_extended_backref = 57; // for \g +static const escape_syntax_type escape_type_reset_start_mark = 58; // for \K +static const escape_syntax_type escape_type_line_ending = 59; // for \R + +static const escape_syntax_type syntax_max = 60; + +} +} + + +#endif diff --git a/third-party/boost_regex/include/boost/regex/v5/u32regex_iterator.hpp b/third-party/boost_regex/include/boost/regex/v5/u32regex_iterator.hpp new file mode 100644 index 0000000000..6677019aca --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/u32regex_iterator.hpp @@ -0,0 +1,177 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE u32regex_iterator.hpp + * VERSION see + * DESCRIPTION: Provides u32regex_iterator implementation. + */ + +#ifndef BOOST_REGEX_V5_U32REGEX_ITERATOR_HPP +#define BOOST_REGEX_V5_U32REGEX_ITERATOR_HPP + +namespace boost{ + +template +class u32regex_iterator_implementation +{ + typedef u32regex regex_type; + + match_results what; // current match + BidirectionalIterator base; // start of sequence + BidirectionalIterator end; // end of sequence + const regex_type re; // the expression + match_flag_type flags; // flags for matching + +public: + u32regex_iterator_implementation(const regex_type* p, BidirectionalIterator last, match_flag_type f) + : base(), end(last), re(*p), flags(f){} + bool init(BidirectionalIterator first) + { + base = first; + return u32regex_search(first, end, what, re, flags, base); + } + bool compare(const u32regex_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) && (end == that.end) && (flags == that.flags) && (what[0].first == that.what[0].first) && (what[0].second == that.what[0].second); + } + const match_results& get() + { return what; } + bool next() + { + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail; + BidirectionalIterator next_start = what[0].second; + match_flag_type f(flags); + if(!what.length()) + f |= regex_constants::match_not_initial_null; + //if(base != next_start) + // f |= regex_constants::match_not_bob; + bool result = u32regex_search(next_start, end, what, re, f, base); + if(result) + what.set_base(base); + return result; + } +private: + u32regex_iterator_implementation& operator=(const u32regex_iterator_implementation&); +}; + +template +class u32regex_iterator +{ +private: + typedef u32regex_iterator_implementation impl; + typedef std::shared_ptr pimpl; +public: + typedef u32regex regex_type; + typedef match_results value_type; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + u32regex_iterator(){} + u32regex_iterator(BidirectionalIterator a, BidirectionalIterator b, + const regex_type& re, + match_flag_type m = match_default) + : pdata(new impl(&re, b, m)) + { + if(!pdata->init(a)) + { + pdata.reset(); + } + } + u32regex_iterator(const u32regex_iterator& that) + : pdata(that.pdata) {} + u32regex_iterator& operator=(const u32regex_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const u32regex_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const u32regex_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + u32regex_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + u32regex_iterator operator++(int) + { + u32regex_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && (pdata.use_count() > 1)) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef u32regex_iterator utf8regex_iterator; +typedef u32regex_iterator utf16regex_iterator; +typedef u32regex_iterator utf32regex_iterator; + +inline u32regex_iterator make_u32regex_iterator(const char* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+std::strlen(p), e, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_iterator make_u32regex_iterator(const wchar_t* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+std::wcslen(p), e, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +inline u32regex_iterator make_u32regex_iterator(const UChar* p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(p, p+u_strlen(p), e, m); +} +#endif +template +inline u32regex_iterator::const_iterator> make_u32regex_iterator(const std::basic_string& p, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_iterator(p.begin(), p.end(), e, m); +} +inline u32regex_iterator make_u32regex_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, m); +} + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v5/u32regex_token_iterator.hpp b/third-party/boost_regex/include/boost/regex/v5/u32regex_token_iterator.hpp new file mode 100644 index 0000000000..3d3032652f --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/u32regex_token_iterator.hpp @@ -0,0 +1,312 @@ +/* + * + * Copyright (c) 2003 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE u32regex_token_iterator.hpp + * VERSION see + * DESCRIPTION: Provides u32regex_token_iterator implementation. + */ + +#ifndef BOOST_REGEX_V5_U32REGEX_TOKEN_ITERATOR_HPP +#define BOOST_REGEX_V5_U32REGEX_TOKEN_ITERATOR_HPP + +namespace boost{ + +#ifdef BOOST_REGEX_MSVC +# pragma warning(push) +# pragma warning(disable:4700) +#endif + +template +class u32regex_token_iterator_implementation +{ + typedef u32regex regex_type; + typedef sub_match value_type; + + match_results what; // current match + BidirectionalIterator end; // end of search area + BidirectionalIterator base; // start of search area + const regex_type re; // the expression + match_flag_type flags; // match flags + value_type result; // the current string result + int N; // the current sub-expression being enumerated + std::vector subs; // the sub-expressions to enumerate + +public: + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, int sub, match_flag_type f) + : end(last), re(*p), flags(f){ subs.push_back(sub); } + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const std::vector& v, match_flag_type f) + : end(last), re(*p), flags(f), subs(v){} + template + u32regex_token_iterator_implementation(const regex_type* p, BidirectionalIterator last, const int (&submatches)[CN], match_flag_type f) + : end(last), re(*p), flags(f) + { + for(std::size_t i = 0; i < CN; ++i) + { + subs.push_back(submatches[i]); + } + } + + bool init(BidirectionalIterator first) + { + base = first; + N = 0; + if(u32regex_search(first, end, what, re, flags, base) == true) + { + N = 0; + result = ((subs[N] == -1) ? what.prefix() : what[(int)subs[N]]); + return true; + } + else if((subs[N] == -1) && (first != end)) + { + result.first = first; + result.second = end; + result.matched = (first != end); + N = -1; + return true; + } + return false; + } + bool compare(const u32regex_token_iterator_implementation& that) + { + if(this == &that) return true; + return (&re.get_data() == &that.re.get_data()) + && (end == that.end) + && (flags == that.flags) + && (N == that.N) + && (what[0].first == that.what[0].first) + && (what[0].second == that.what[0].second); + } + const value_type& get() + { return result; } + bool next() + { + if(N == -1) + return false; + if(N+1 < (int)subs.size()) + { + ++N; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + //if(what.prefix().first != what[0].second) + // flags |= match_prev_avail | regex_constants::match_not_bob; + BidirectionalIterator last_end(what[0].second); + if(u32regex_search(last_end, end, what, re, ((what[0].first == what[0].second) ? flags | regex_constants::match_not_initial_null : flags), base)) + { + N =0; + result =((subs[N] == -1) ? what.prefix() : what[subs[N]]); + return true; + } + else if((last_end != end) && (subs[0] == -1)) + { + N =-1; + result.first = last_end; + result.second = end; + result.matched = (last_end != end); + return true; + } + return false; + } +private: + u32regex_token_iterator_implementation& operator=(const u32regex_token_iterator_implementation&); +}; + +template +class u32regex_token_iterator +{ +private: + typedef u32regex_token_iterator_implementation impl; + typedef std::shared_ptr pimpl; +public: + typedef u32regex regex_type; + typedef sub_match value_type; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef std::forward_iterator_tag iterator_category; + + u32regex_token_iterator(){} + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + int submatch = 0, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatch, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const std::vector& submatches, match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + template + u32regex_token_iterator(BidirectionalIterator a, BidirectionalIterator b, const regex_type& re, + const int (&submatches)[N], match_flag_type m = match_default) + : pdata(new impl(&re, b, submatches, m)) + { + if(!pdata->init(a)) + pdata.reset(); + } + u32regex_token_iterator(const u32regex_token_iterator& that) + : pdata(that.pdata) {} + u32regex_token_iterator& operator=(const u32regex_token_iterator& that) + { + pdata = that.pdata; + return *this; + } + bool operator==(const u32regex_token_iterator& that)const + { + if((pdata.get() == 0) || (that.pdata.get() == 0)) + return pdata.get() == that.pdata.get(); + return pdata->compare(*(that.pdata.get())); + } + bool operator!=(const u32regex_token_iterator& that)const + { return !(*this == that); } + const value_type& operator*()const + { return pdata->get(); } + const value_type* operator->()const + { return &(pdata->get()); } + u32regex_token_iterator& operator++() + { + cow(); + if(0 == pdata->next()) + { + pdata.reset(); + } + return *this; + } + u32regex_token_iterator operator++(int) + { + u32regex_token_iterator result(*this); + ++(*this); + return result; + } +private: + + pimpl pdata; + + void cow() + { + // copy-on-write + if(pdata.get() && (pdata.use_count() > 1)) + { + pdata.reset(new impl(*(pdata.get()))); + } + } +}; + +typedef u32regex_token_iterator utf8regex_token_iterator; +typedef u32regex_token_iterator utf16regex_token_iterator; +typedef u32regex_token_iterator utf32regex_token_iterator; + +// construction from an integral sub_match state_id: +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, int submatch = 0, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +// construction from a reference to an array: +template +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +template +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(BOOST_REGEX_UCHAR_IS_WCHAR_T) +template +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +template +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, const int (&submatch)[N], regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +// construction from a vector of sub_match state_id's: +inline u32regex_token_iterator make_u32regex_token_iterator(const char* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::strlen(p), e, submatch, m); +} +#ifndef BOOST_NO_WREGEX +inline u32regex_token_iterator make_u32regex_token_iterator(const wchar_t* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+std::wcslen(p), e, submatch, m); +} +#endif +#if !defined(U_WCHAR_IS_UTF16) && (U_SIZEOF_WCHAR_T != 2) +inline u32regex_token_iterator make_u32regex_token_iterator(const UChar* p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(p, p+u_strlen(p), e, submatch, m); +} +#endif +template +inline u32regex_token_iterator::const_iterator> make_u32regex_token_iterator(const std::basic_string& p, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + typedef typename std::basic_string::const_iterator iter_type; + return u32regex_token_iterator(p.begin(), p.end(), e, submatch, m); +} +inline u32regex_token_iterator make_u32regex_token_iterator(const U_NAMESPACE_QUALIFIER UnicodeString& s, const u32regex& e, const std::vector& submatch, regex_constants::match_flag_type m = regex_constants::match_default) +{ + return u32regex_token_iterator(s.getBuffer(), s.getBuffer() + s.length(), e, submatch, m); +} + +#ifdef BOOST_REGEX_MSVC +# pragma warning(pop) +#endif + +} // namespace boost + +#endif // BOOST_REGEX_V5_REGEX_TOKEN_ITERATOR_HPP + + + + diff --git a/third-party/boost_regex/include/boost/regex/v5/unicode_iterator.hpp b/third-party/boost_regex/include/boost/regex/v5/unicode_iterator.hpp new file mode 100644 index 0000000000..9d3dd8b962 --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/unicode_iterator.hpp @@ -0,0 +1,862 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE unicode_iterator.hpp + * VERSION see + * DESCRIPTION: Iterator adapters for converting between different Unicode encodings. + */ + +/**************************************************************************** + +Contents: +~~~~~~~~~ + +1) Read Only, Input Adapters: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +template +class u32_to_u8_iterator; + +Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-8. + +template +class u8_to_u32_iterator; + +Adapts sequence of UTF-8 code points to "look like" a sequence of UTF-32. + +template +class u32_to_u16_iterator; + +Adapts sequence of UTF-32 code points to "look like" a sequence of UTF-16. + +template +class u16_to_u32_iterator; + +Adapts sequence of UTF-16 code points to "look like" a sequence of UTF-32. + +2) Single pass output iterator adapters: + +template +class utf8_output_iterator; + +Accepts UTF-32 code points and forwards them on as UTF-8 code points. + +template +class utf16_output_iterator; + +Accepts UTF-32 code points and forwards them on as UTF-16 code points. + +****************************************************************************/ + +#ifndef BOOST_REGEX_UNICODE_ITERATOR_HPP +#define BOOST_REGEX_UNICODE_ITERATOR_HPP +#include +#include +#include +#include +#include +#include // CHAR_BIT + +#ifndef BOOST_REGEX_STANDALONE +#include +#endif + +namespace boost{ + +namespace detail{ + +static const std::uint16_t high_surrogate_base = 0xD7C0u; +static const std::uint16_t low_surrogate_base = 0xDC00u; +static const std::uint32_t ten_bit_mask = 0x3FFu; + +inline bool is_high_surrogate(std::uint16_t v) +{ + return (v & 0xFFFFFC00u) == 0xd800u; +} +inline bool is_low_surrogate(std::uint16_t v) +{ + return (v & 0xFFFFFC00u) == 0xdc00u; +} +template +inline bool is_surrogate(T v) +{ + return (v & 0xFFFFF800u) == 0xd800; +} + +inline unsigned utf8_byte_count(std::uint8_t c) +{ + // if the most significant bit with a zero in it is in position + // 8-N then there are N bytes in this UTF-8 sequence: + std::uint8_t mask = 0x80u; + unsigned result = 0; + while(c & mask) + { + ++result; + mask >>= 1; + } + return (result == 0) ? 1 : ((result > 4) ? 4 : result); +} + +inline unsigned utf8_trailing_byte_count(std::uint8_t c) +{ + return utf8_byte_count(c) - 1; +} + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4100) +#endif +#ifndef BOOST_NO_EXCEPTIONS +BOOST_REGEX_NORETURN +#endif +inline void invalid_utf32_code_point(std::uint32_t val) +{ + std::stringstream ss; + ss << "Invalid UTF-32 code point U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-16 sequence"; + std::out_of_range e(ss.str()); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif +} +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + + +} // namespace detail + +template +class u32_to_u16_iterator +{ + typedef typename std::iterator_traits::value_type base_value_type; + + static_assert(sizeof(base_value_type)*CHAR_BIT == 32, "Incorrectly sized template argument"); + static_assert(sizeof(U16Type)*CHAR_BIT == 16, "Incorrectly sized template argument"); + +public: + typedef std::ptrdiff_t difference_type; + typedef U16Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_current == 2) + extract_current(); + return m_values[m_current]; + } + bool operator==(const u32_to_u16_iterator& that)const + { + if(m_position == that.m_position) + { + // Both m_currents must be equal, or both even + // this is the same as saying their sum must be even: + return (m_current + that.m_current) & 1u ? false : true; + } + return false; + } + bool operator!=(const u32_to_u16_iterator& that)const + { + return !(*this == that); + } + u32_to_u16_iterator& operator++() + { + // if we have a pending read then read now, so that we know whether + // to skip a position, or move to a low-surrogate: + if(m_current == 2) + { + // pending read: + extract_current(); + } + // move to the next surrogate position: + ++m_current; + // if we've reached the end skip a position: + if(m_values[m_current] == 0) + { + m_current = 2; + ++m_position; + } + return *this; + } + u32_to_u16_iterator operator++(int) + { + u32_to_u16_iterator r(*this); + ++(*this); + return r; + } + u32_to_u16_iterator& operator--() + { + if(m_current != 1) + { + // decrementing an iterator always leads to a valid position: + --m_position; + extract_current(); + m_current = m_values[1] ? 1 : 0; + } + else + { + m_current = 0; + } + return *this; + } + u32_to_u16_iterator operator--(int) + { + u32_to_u16_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u32_to_u16_iterator() : m_position(), m_current(0) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + } + u32_to_u16_iterator(BaseIterator b) : m_position(b), m_current(2) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + } +private: + + void extract_current()const + { + // begin by checking for a code point out of range: + std::uint32_t v = *m_position; + if(v >= 0x10000u) + { + if(v > 0x10FFFFu) + detail::invalid_utf32_code_point(*m_position); + // split into two surrogates: + m_values[0] = static_cast(v >> 10) + detail::high_surrogate_base; + m_values[1] = static_cast(v & detail::ten_bit_mask) + detail::low_surrogate_base; + m_current = 0; + BOOST_REGEX_ASSERT(detail::is_high_surrogate(m_values[0])); + BOOST_REGEX_ASSERT(detail::is_low_surrogate(m_values[1])); + } + else + { + // 16-bit code point: + m_values[0] = static_cast(*m_position); + m_values[1] = 0; + m_current = 0; + // value must not be a surrogate: + if(detail::is_surrogate(m_values[0])) + detail::invalid_utf32_code_point(*m_position); + } + } + BaseIterator m_position; + mutable U16Type m_values[3]; + mutable unsigned m_current; +}; + +template +class u16_to_u32_iterator +{ + // special values for pending iterator reads: + static const U32Type pending_read = 0xffffffffu; + + typedef typename std::iterator_traits::value_type base_value_type; + + static_assert(sizeof(base_value_type)*CHAR_BIT == 16, "Incorrectly sized template argument"); + static_assert(sizeof(U32Type)*CHAR_BIT == 32, "Incorrectly sized template argument"); + +public: + typedef std::ptrdiff_t difference_type; + typedef U32Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_value == pending_read) + extract_current(); + return m_value; + } + bool operator==(const u16_to_u32_iterator& that)const + { + return m_position == that.m_position; + } + bool operator!=(const u16_to_u32_iterator& that)const + { + return !(*this == that); + } + u16_to_u32_iterator& operator++() + { + // skip high surrogate first if there is one: + if(detail::is_high_surrogate(*m_position)) ++m_position; + ++m_position; + m_value = pending_read; + return *this; + } + u16_to_u32_iterator operator++(int) + { + u16_to_u32_iterator r(*this); + ++(*this); + return r; + } + u16_to_u32_iterator& operator--() + { + --m_position; + // if we have a low surrogate then go back one more: + if(detail::is_low_surrogate(*m_position)) + --m_position; + m_value = pending_read; + return *this; + } + u16_to_u32_iterator operator--(int) + { + u16_to_u32_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u16_to_u32_iterator() : m_position() + { + m_value = pending_read; + } + u16_to_u32_iterator(BaseIterator b) : m_position(b) + { + m_value = pending_read; + } + // + // Range checked version: + // + u16_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b) + { + m_value = pending_read; + // + // The range must not start with a low surrogate, or end in a high surrogate, + // otherwise we run the risk of running outside the underlying input range. + // Likewise b must not be located at a low surrogate. + // + std::uint16_t val; + if(start != end) + { + if((b != start) && (b != end)) + { + val = *b; + if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u)) + invalid_code_point(val); + } + val = *start; + if(detail::is_surrogate(val) && ((val & 0xFC00u) == 0xDC00u)) + invalid_code_point(val); + val = *--end; + if(detail::is_high_surrogate(val)) + invalid_code_point(val); + } + } +private: + static void invalid_code_point(std::uint16_t val) + { + std::stringstream ss; + ss << "Misplaced UTF-16 surrogate U+" << std::showbase << std::hex << val << " encountered while trying to encode UTF-32 sequence"; + std::out_of_range e(ss.str()); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif + } + void extract_current()const + { + m_value = static_cast(static_cast< std::uint16_t>(*m_position)); + // if the last value is a high surrogate then adjust m_position and m_value as needed: + if(detail::is_high_surrogate(*m_position)) + { + // precondition; next value must have be a low-surrogate: + BaseIterator next(m_position); + std::uint16_t t = *++next; + if((t & 0xFC00u) != 0xDC00u) + invalid_code_point(t); + m_value = (m_value - detail::high_surrogate_base) << 10; + m_value |= (static_cast(static_cast< std::uint16_t>(t)) & detail::ten_bit_mask); + } + // postcondition; result must not be a surrogate: + if(detail::is_surrogate(m_value)) + invalid_code_point(static_cast< std::uint16_t>(m_value)); + } + BaseIterator m_position; + mutable U32Type m_value; +}; + +template +class u32_to_u8_iterator +{ + typedef typename std::iterator_traits::value_type base_value_type; + + static_assert(sizeof(base_value_type)*CHAR_BIT == 32, "Incorrectly sized template argument"); + static_assert(sizeof(U8Type)*CHAR_BIT == 8, "Incorrectly sized template argument"); + +public: + typedef std::ptrdiff_t difference_type; + typedef U8Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_current == 4) + extract_current(); + return m_values[m_current]; + } + bool operator==(const u32_to_u8_iterator& that)const + { + if(m_position == that.m_position) + { + // either the m_current's must be equal, or one must be 0 and + // the other 4: which means neither must have bits 1 or 2 set: + return (m_current == that.m_current) + || (((m_current | that.m_current) & 3) == 0); + } + return false; + } + bool operator!=(const u32_to_u8_iterator& that)const + { + return !(*this == that); + } + u32_to_u8_iterator& operator++() + { + // if we have a pending read then read now, so that we know whether + // to skip a position, or move to a low-surrogate: + if(m_current == 4) + { + // pending read: + extract_current(); + } + // move to the next surrogate position: + ++m_current; + // if we've reached the end skip a position: + if(m_values[m_current] == 0) + { + m_current = 4; + ++m_position; + } + return *this; + } + u32_to_u8_iterator operator++(int) + { + u32_to_u8_iterator r(*this); + ++(*this); + return r; + } + u32_to_u8_iterator& operator--() + { + if((m_current & 3) == 0) + { + --m_position; + extract_current(); + m_current = 3; + while(m_current && (m_values[m_current] == 0)) + --m_current; + } + else + --m_current; + return *this; + } + u32_to_u8_iterator operator--(int) + { + u32_to_u8_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u32_to_u8_iterator() : m_position(), m_current(0) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + m_values[3] = 0; + m_values[4] = 0; + } + u32_to_u8_iterator(BaseIterator b) : m_position(b), m_current(4) + { + m_values[0] = 0; + m_values[1] = 0; + m_values[2] = 0; + m_values[3] = 0; + m_values[4] = 0; + } +private: + + void extract_current()const + { + std::uint32_t c = *m_position; + if(c > 0x10FFFFu) + detail::invalid_utf32_code_point(c); + if(c < 0x80u) + { + m_values[0] = static_cast(c); + m_values[1] = static_cast(0u); + m_values[2] = static_cast(0u); + m_values[3] = static_cast(0u); + } + else if(c < 0x800u) + { + m_values[0] = static_cast(0xC0u + (c >> 6)); + m_values[1] = static_cast(0x80u + (c & 0x3Fu)); + m_values[2] = static_cast(0u); + m_values[3] = static_cast(0u); + } + else if(c < 0x10000u) + { + m_values[0] = static_cast(0xE0u + (c >> 12)); + m_values[1] = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + m_values[2] = static_cast(0x80u + (c & 0x3Fu)); + m_values[3] = static_cast(0u); + } + else + { + m_values[0] = static_cast(0xF0u + (c >> 18)); + m_values[1] = static_cast(0x80u + ((c >> 12) & 0x3Fu)); + m_values[2] = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + m_values[3] = static_cast(0x80u + (c & 0x3Fu)); + } + m_current= 0; + } + BaseIterator m_position; + mutable U8Type m_values[5]; + mutable unsigned m_current; +}; + +template +class u8_to_u32_iterator +{ + // special values for pending iterator reads: + static const U32Type pending_read = 0xffffffffu; + + typedef typename std::iterator_traits::value_type base_value_type; + + static_assert(sizeof(base_value_type)*CHAR_BIT == 8, "Incorrectly sized template argument"); + static_assert(sizeof(U32Type)*CHAR_BIT == 32, "Incorrectly sized template argument"); + +public: + typedef std::ptrdiff_t difference_type; + typedef U32Type value_type; + typedef value_type const* pointer; + typedef value_type const reference; + typedef std::bidirectional_iterator_tag iterator_category; + + reference operator*()const + { + if(m_value == pending_read) + extract_current(); + return m_value; + } + bool operator==(const u8_to_u32_iterator& that)const + { + return m_position == that.m_position; + } + bool operator!=(const u8_to_u32_iterator& that)const + { + return !(*this == that); + } + u8_to_u32_iterator& operator++() + { + // We must not start with a continuation character: + if((static_cast(*m_position) & 0xC0) == 0x80) + invalid_sequence(); + // skip high surrogate first if there is one: + unsigned c = detail::utf8_byte_count(*m_position); + if(m_value == pending_read) + { + // Since we haven't read in a value, we need to validate the code points: + for(unsigned i = 0; i < c; ++i) + { + ++m_position; + // We must have a continuation byte: + if((i != c - 1) && ((static_cast(*m_position) & 0xC0) != 0x80)) + invalid_sequence(); + } + } + else + { + std::advance(m_position, c); + } + m_value = pending_read; + return *this; + } + u8_to_u32_iterator operator++(int) + { + u8_to_u32_iterator r(*this); + ++(*this); + return r; + } + u8_to_u32_iterator& operator--() + { + // Keep backtracking until we don't have a trailing character: + unsigned count = 0; + while((*--m_position & 0xC0u) == 0x80u) ++count; + // now check that the sequence was valid: + if(count != detail::utf8_trailing_byte_count(*m_position)) + invalid_sequence(); + m_value = pending_read; + return *this; + } + u8_to_u32_iterator operator--(int) + { + u8_to_u32_iterator r(*this); + --(*this); + return r; + } + BaseIterator base()const + { + return m_position; + } + // construct: + u8_to_u32_iterator() : m_position() + { + m_value = pending_read; + } + u8_to_u32_iterator(BaseIterator b) : m_position(b) + { + m_value = pending_read; + } + // + // Checked constructor: + // + u8_to_u32_iterator(BaseIterator b, BaseIterator start, BaseIterator end) : m_position(b) + { + m_value = pending_read; + // + // We must not start with a continuation character, or end with a + // truncated UTF-8 sequence otherwise we run the risk of going past + // the start/end of the underlying sequence: + // + if(start != end) + { + unsigned char v = *start; + if((v & 0xC0u) == 0x80u) + invalid_sequence(); + if((b != start) && (b != end) && ((*b & 0xC0u) == 0x80u)) + invalid_sequence(); + BaseIterator pos = end; + do + { + v = *--pos; + } + while((start != pos) && ((v & 0xC0u) == 0x80u)); + std::ptrdiff_t extra = detail::utf8_byte_count(v); + if(std::distance(pos, end) < extra) + invalid_sequence(); + } + } +private: + static void invalid_sequence() + { + std::out_of_range e("Invalid UTF-8 sequence encountered while trying to encode UTF-32 character"); +#ifndef BOOST_REGEX_STANDALONE + boost::throw_exception(e); +#else + throw e; +#endif + } + void extract_current()const + { + m_value = static_cast(static_cast< std::uint8_t>(*m_position)); + // we must not have a continuation character: + if((m_value & 0xC0u) == 0x80u) + invalid_sequence(); + // see how many extra bytes we have: + unsigned extra = detail::utf8_trailing_byte_count(*m_position); + // extract the extra bits, 6 from each extra byte: + BaseIterator next(m_position); + for(unsigned c = 0; c < extra; ++c) + { + ++next; + m_value <<= 6; + // We must have a continuation byte: + if((static_cast(*next) & 0xC0) != 0x80) + invalid_sequence(); + m_value += static_cast(*next) & 0x3Fu; + } + // we now need to remove a few of the leftmost bits, but how many depends + // upon how many extra bytes we've extracted: + static const std::uint32_t masks[4] = + { + 0x7Fu, + 0x7FFu, + 0xFFFFu, + 0x1FFFFFu, + }; + m_value &= masks[extra]; + // check the result is in range: + if(m_value > static_cast(0x10FFFFu)) + invalid_sequence(); + // The result must not be a surrogate: + if((m_value >= static_cast(0xD800)) && (m_value <= static_cast(0xDFFF))) + invalid_sequence(); + // We should not have had an invalidly encoded UTF8 sequence: + if((extra > 0) && (m_value <= static_cast(masks[extra - 1]))) + invalid_sequence(); + } + BaseIterator m_position; + mutable U32Type m_value; +}; + +template +class utf16_output_iterator +{ +public: + typedef void difference_type; + typedef void value_type; + typedef std::uint32_t* pointer; + typedef std::uint32_t& reference; + typedef std::output_iterator_tag iterator_category; + + utf16_output_iterator(const BaseIterator& b) + : m_position(b){} + utf16_output_iterator(const utf16_output_iterator& that) + : m_position(that.m_position){} + utf16_output_iterator& operator=(const utf16_output_iterator& that) + { + m_position = that.m_position; + return *this; + } + const utf16_output_iterator& operator*()const + { + return *this; + } + void operator=(std::uint32_t val)const + { + push(val); + } + utf16_output_iterator& operator++() + { + return *this; + } + utf16_output_iterator& operator++(int) + { + return *this; + } + BaseIterator base()const + { + return m_position; + } +private: + void push(std::uint32_t v)const + { + if(v >= 0x10000u) + { + // begin by checking for a code point out of range: + if(v > 0x10FFFFu) + detail::invalid_utf32_code_point(v); + // split into two surrogates: + *m_position++ = static_cast(v >> 10) + detail::high_surrogate_base; + *m_position++ = static_cast(v & detail::ten_bit_mask) + detail::low_surrogate_base; + } + else + { + // 16-bit code point: + // value must not be a surrogate: + if(detail::is_surrogate(v)) + detail::invalid_utf32_code_point(v); + *m_position++ = static_cast(v); + } + } + mutable BaseIterator m_position; +}; + +template +class utf8_output_iterator +{ +public: + typedef void difference_type; + typedef void value_type; + typedef std::uint32_t* pointer; + typedef std::uint32_t& reference; + typedef std::output_iterator_tag iterator_category; + + utf8_output_iterator(const BaseIterator& b) + : m_position(b){} + utf8_output_iterator(const utf8_output_iterator& that) + : m_position(that.m_position){} + utf8_output_iterator& operator=(const utf8_output_iterator& that) + { + m_position = that.m_position; + return *this; + } + const utf8_output_iterator& operator*()const + { + return *this; + } + void operator=(std::uint32_t val)const + { + push(val); + } + utf8_output_iterator& operator++() + { + return *this; + } + utf8_output_iterator& operator++(int) + { + return *this; + } + BaseIterator base()const + { + return m_position; + } +private: + void push(std::uint32_t c)const + { + if(c > 0x10FFFFu) + detail::invalid_utf32_code_point(c); + if(c < 0x80u) + { + *m_position++ = static_cast(c); + } + else if(c < 0x800u) + { + *m_position++ = static_cast(0xC0u + (c >> 6)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + else if(c < 0x10000u) + { + *m_position++ = static_cast(0xE0u + (c >> 12)); + *m_position++ = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + else + { + *m_position++ = static_cast(0xF0u + (c >> 18)); + *m_position++ = static_cast(0x80u + ((c >> 12) & 0x3Fu)); + *m_position++ = static_cast(0x80u + ((c >> 6) & 0x3Fu)); + *m_position++ = static_cast(0x80u + (c & 0x3Fu)); + } + } + mutable BaseIterator m_position; +}; + +} // namespace boost + +#endif // BOOST_REGEX_UNICODE_ITERATOR_HPP + diff --git a/third-party/boost_regex/include/boost/regex/v5/w32_regex_traits.hpp b/third-party/boost_regex/include/boost/regex/v5/w32_regex_traits.hpp new file mode 100644 index 0000000000..16f7ee4eaa --- /dev/null +++ b/third-party/boost_regex/include/boost/regex/v5/w32_regex_traits.hpp @@ -0,0 +1,1311 @@ +/* + * + * Copyright (c) 2004 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE w32_regex_traits.hpp + * VERSION see + * DESCRIPTION: Declares regular expression traits class w32_regex_traits. + */ + +#ifndef BOOST_W32_REGEX_TRAITS_HPP_INCLUDED +#define BOOST_W32_REGEX_TRAITS_HPP_INCLUDED + +#ifndef BOOST_REGEX_NO_WIN32_LOCALE + +#include +#include +#ifdef BOOST_HAS_THREADS +#include +#endif +#include +#include + +#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(UNDER_CE) +#pragma comment(lib, "user32.lib") +#endif + +#ifdef BOOST_REGEX_MSVC +#pragma warning(push) +#pragma warning(disable:4786) +#if BOOST_REGEX_MSVC < 1910 +#pragma warning(disable:4800) +#endif +#endif + +#ifndef BASETYPES +// +// windows.h not included, so lets forward declare what we need: +// +#ifndef NO_STRICT +#ifndef STRICT +#define STRICT 1 +#endif +#endif + +#if defined(STRICT) +#define BOOST_RE_DETAIL_DECLARE_HANDLE(x) struct x##__; typedef struct x##__ *x +#else +#define BOOST_RE_DETAIL_DECLARE_HANDLE(x) typedef void* x +#endif +// +// This must be in the global namespace: +// +extern "C" { + + BOOST_RE_DETAIL_DECLARE_HANDLE(HINSTANCE); + typedef HINSTANCE HMODULE; +} +#endif + +namespace boost{ + +// +// forward declaration is needed by some compilers: +// +template +class w32_regex_traits; + +namespace BOOST_REGEX_DETAIL_NS{ + +// +// start by typedeffing the types we'll need: +// +typedef unsigned long lcid_type; // placeholder for LCID. +typedef std::shared_ptr cat_type; // placeholder for dll HANDLE. + +// +// then add wrappers around the actual Win32 API's (ie implementation hiding): +// +lcid_type w32_get_default_locale(); +bool w32_is_lower(char, lcid_type); +#ifndef BOOST_NO_WREGEX +bool w32_is_lower(wchar_t, lcid_type); +#endif +bool w32_is_upper(char, lcid_type); +#ifndef BOOST_NO_WREGEX +bool w32_is_upper(wchar_t, lcid_type); +#endif +cat_type w32_cat_open(const std::string& name); +std::string w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::string& def); +#ifndef BOOST_NO_WREGEX +std::wstring w32_cat_get(const cat_type& cat, lcid_type state_id, int i, const std::wstring& def); +#endif +std::string w32_transform(lcid_type state_id, const char* p1, const char* p2); +#ifndef BOOST_NO_WREGEX +std::wstring w32_transform(lcid_type state_id, const wchar_t* p1, const wchar_t* p2); +#endif +char w32_tolower(char c, lcid_type); +#ifndef BOOST_NO_WREGEX +wchar_t w32_tolower(wchar_t c, lcid_type); +#endif +char w32_toupper(char c, lcid_type); +#ifndef BOOST_NO_WREGEX +wchar_t w32_toupper(wchar_t c, lcid_type); +#endif +bool w32_is(lcid_type, std::uint32_t mask, char c); +#ifndef BOOST_NO_WREGEX +bool w32_is(lcid_type, std::uint32_t mask, wchar_t c); +#endif + +#ifndef BASETYPES +// +// Forward declarations of the small number of windows types and API's we use: +// + +#if !defined(__LP64__) +using dword = unsigned long; +#else +using DWORD = unsigned int; +#endif +using word = unsigned short; +using lctype = dword; + +static constexpr dword ct_ctype1 = 0x00000001; +static constexpr dword c1_upper = 0x0001; // upper case +static constexpr dword c1_lower = 0x0002; // lower case +static constexpr dword c1_digit = 0x0004; // decimal digits +static constexpr dword c1_space = 0x0008; // spacing characters +static constexpr dword c1_punct = 0x0010; // punctuation characters +static constexpr dword c1_cntrl = 0x0020; // control characters +static constexpr dword c1_blank = 0x0040; // blank characters +static constexpr dword c1_xdigit = 0x0080; // other digits +static constexpr dword c1_alpha = 0x0100; // any linguistic character +static constexpr dword c1_defined = 0x0200; // defined character +static constexpr unsigned int cp_acp = 0; +static constexpr dword lcmap_lowercase = 0x00000100; +static constexpr dword lcmap_uppercase = 0x00000200; +static constexpr dword lcmap_sortkey = 0x00000400; // WC sort key (normalize) +static constexpr lctype locale_idefaultansicodepage = 0x00001004; + +# ifdef UNDER_CE +# ifndef WINAPI +# ifndef _WIN32_WCE_EMULATION +# define BOOST_RE_STDCALL __cdecl // Note this doesn't match the desktop definition +# else +# define BOOST_RE_STDCALL __stdcall +# endif +# endif +# else +# if defined(_M_IX86) || defined(__i386__) +# define BOOST_RE_STDCALL __stdcall +# else + // On architectures other than 32-bit x86 __stdcall is ignored. Clang also issues a warning. +# define BOOST_RE_STDCALL +# endif +# endif + +#if defined (WIN32_PLATFORM_PSPC) +#define BOOST_RE_IMPORT __declspec( dllimport ) +#elif defined (_WIN32_WCE) +#define BOOST_RE_IMPORT +#else +#define BOOST_RE_IMPORT __declspec( dllimport ) +#endif + +extern "C" { + + BOOST_RE_IMPORT int BOOST_RE_STDCALL FreeLibrary(HMODULE hLibModule); + BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringA(lcid_type Locale, dword dwMapFlags, const char* lpSrcStr, int cchSrc, char* lpDestStr, int cchDest); + BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest); + BOOST_RE_IMPORT int BOOST_RE_STDCALL MultiByteToWideChar(unsigned int CodePage, dword dwFlags, const char* lpMultiByteStr, int cbMultiByte, wchar_t* lpWideCharStr, int cchWideChar); + BOOST_RE_IMPORT int BOOST_RE_STDCALL LCMapStringW(lcid_type Locale, dword dwMapFlags, const wchar_t* lpSrcStr, int cchSrc, wchar_t* lpDestStr, int cchDest); + BOOST_RE_IMPORT int BOOST_RE_STDCALL WideCharToMultiByte(unsigned int CodePage, dword dwFlags, const wchar_t* lpWideCharStr, int cchWideChar, char* lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, int* lpUsedDefaultChar); + BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType); + BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType); + BOOST_RE_IMPORT lcid_type BOOST_RE_STDCALL GetUserDefaultLCID(); + BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExA(lcid_type Locale, dword dwInfoType, const char* lpSrcStr, int cchSrc, word* lpCharType); + BOOST_RE_IMPORT int BOOST_RE_STDCALL GetStringTypeExW(lcid_type Locale, dword dwInfoType, const wchar_t* lpSrcStr, int cchSrc, word* lpCharType); + BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryA(const char* lpLibFileName); + BOOST_RE_IMPORT HMODULE BOOST_RE_STDCALL LoadLibraryW(const wchar_t* lpLibFileName); + BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringW(HINSTANCE hInstance, unsigned int uID, wchar_t* lpBuffer, int cchBufferMax); + BOOST_RE_IMPORT int BOOST_RE_STDCALL LoadStringA(HINSTANCE hInstance, unsigned int uID, char* lpBuffer, int cchBufferMax); + BOOST_RE_IMPORT int BOOST_RE_STDCALL GetLocaleInfoW(lcid_type Locale, lctype LCType, wchar_t* lpLCData, int cchData); +} + +#else +// +// We have windows.h already included: +// +using dword = DWORD; +using word = WORD; +using lctype = LCTYPE; + +static constexpr dword ct_ctype1 = 0x00000001; +static constexpr dword c1_upper = 0x0001; // upper case +static constexpr dword c1_lower = 0x0002; // lower case +static constexpr dword c1_digit = 0x0004; // decimal digits +static constexpr dword c1_space = 0x0008; // spacing characters +static constexpr dword c1_punct = 0x0010; // punctuation characters +static constexpr dword c1_cntrl = 0x0020; // control characters +static constexpr dword c1_blank = 0x0040; // blank characters +static constexpr dword c1_xdigit = 0x0080; // other digits +static constexpr dword c1_alpha = 0x0100; // any linguistic character +static constexpr dword c1_defined = 0x0200; // defined character +static constexpr unsigned int cp_acp = 0; +static constexpr dword lcmap_lowercase = 0x00000100; +static constexpr dword lcmap_uppercase = 0x00000200; +static constexpr dword lcmap_sortkey = 0x00000400; // WC sort key (normalize) +static constexpr lctype locale_idefaultansicodepage = 0x00001004; + +using ::FreeLibrary; +using ::LCMapStringA; +using ::LCMapStringW; +using ::MultiByteToWideChar; +using ::LCMapStringW; +using ::WideCharToMultiByte; +using ::GetStringTypeExA; +using ::GetStringTypeExW; +using ::GetUserDefaultLCID; +using ::GetStringTypeExA; +using ::GetStringTypeExW; +using ::LoadLibraryA; +using ::LoadLibraryW; +using ::LoadStringW; +using ::LoadStringA; +using ::GetLocaleInfoW; + +#endif +// +// class w32_regex_traits_base: +// acts as a container for locale and the facets we are using. +// +template +struct w32_regex_traits_base +{ + w32_regex_traits_base(lcid_type l) + { imbue(l); } + lcid_type imbue(lcid_type l); + + lcid_type m_locale; +}; + +template +inline lcid_type w32_regex_traits_base::imbue(lcid_type l) +{ + lcid_type result(m_locale); + m_locale = l; + return result; +} + +// +// class w32_regex_traits_char_layer: +// implements methods that require specialisation for narrow characters: +// +template +class w32_regex_traits_char_layer : public w32_regex_traits_base +{ + typedef std::basic_string string_type; + typedef std::map map_type; + typedef typename map_type::const_iterator map_iterator_type; +public: + w32_regex_traits_char_layer(const lcid_type l); + + regex_constants::syntax_type syntax_type(charT c)const + { + map_iterator_type i = m_char_map.find(c); + return ((i == m_char_map.end()) ? 0 : i->second); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + map_iterator_type i = m_char_map.find(c); + if(i == m_char_map.end()) + { + if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_lower(c, this->m_locale)) return regex_constants::escape_type_class; + if(::boost::BOOST_REGEX_DETAIL_NS::w32_is_upper(c, this->m_locale)) return regex_constants::escape_type_not_class; + return 0; + } + return i->second; + } + charT tolower(charT c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_tolower(c, this->m_locale); + } + bool isctype(std::uint32_t mask, charT c)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, mask, c); + } + +private: + string_type get_default_message(regex_constants::syntax_type); + // TODO: use a hash table when available! + map_type m_char_map; +}; + +template +w32_regex_traits_char_layer::w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) + : w32_regex_traits_base(l) +{ + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if(cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if(!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if(cat) + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_message(i)); + for(typename string_type::size_type j = 0; j < mss.size(); ++j) + { + this->m_char_map[mss[j]] = i; + } + } + } + else + { + for(regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while(ptr && *ptr) + { + this->m_char_map[static_cast(*ptr)] = i; + ++ptr; + } + } + } +} + +template +typename w32_regex_traits_char_layer::string_type + w32_regex_traits_char_layer::get_default_message(regex_constants::syntax_type i) +{ + const char* ptr = get_default_syntax(i); + string_type result; + while(ptr && *ptr) + { + result.append(1, static_cast(*ptr)); + ++ptr; + } + return result; +} + +// +// specialised version for narrow characters: +// +template <> +class w32_regex_traits_char_layer : public w32_regex_traits_base +{ + typedef std::string string_type; +public: + w32_regex_traits_char_layer(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) + : w32_regex_traits_base(l) + { + init(); + } + + regex_constants::syntax_type syntax_type(char c)const + { + return m_char_map[static_cast(c)]; + } + regex_constants::escape_syntax_type escape_syntax_type(char c) const + { + return m_char_map[static_cast(c)]; + } + char tolower(char c)const + { + return m_lower_map[static_cast(c)]; + } + bool isctype(std::uint32_t mask, char c)const + { + return m_type_map[static_cast(c)] & mask; + } + +private: + regex_constants::syntax_type m_char_map[1u << CHAR_BIT]; + char m_lower_map[1u << CHAR_BIT]; + std::uint16_t m_type_map[1u << CHAR_BIT]; + template + void init(); +}; + +// +// class w32_regex_traits_implementation: +// provides pimpl implementation for w32_regex_traits. +// +template +class w32_regex_traits_implementation : public w32_regex_traits_char_layer +{ +public: + typedef typename w32_regex_traits::char_class_type char_class_type; + static const char_class_type mask_word = 0x0400; // must be C1_DEFINED << 1 + static const char_class_type mask_unicode = 0x0800; // must be C1_DEFINED << 2 + static const char_class_type mask_horizontal = 0x1000; // must be C1_DEFINED << 3 + static const char_class_type mask_vertical = 0x2000; // must be C1_DEFINED << 4 + static const char_class_type mask_base = 0x3ff; // all the masks used by the CT_CTYPE1 group + + typedef std::basic_string string_type; + typedef charT char_type; + w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l); + std::string error_string(regex_constants::error_type n) const + { + if(!m_error_strings.empty()) + { + std::map::const_iterator p = m_error_strings.find(n); + return (p == m_error_strings.end()) ? std::string(get_default_error_string(n)) : p->second; + } + return get_default_error_string(n); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + char_class_type result = lookup_classname_imp(p1, p2); + if(result == 0) + { + typedef typename string_type::size_type size_type; + string_type temp(p1, p2); + for(size_type i = 0; i < temp.size(); ++i) + temp[i] = this->tolower(temp[i]); + result = lookup_classname_imp(&*temp.begin(), &*temp.begin() + temp.size()); + } + return result; + } + string_type lookup_collatename(const charT* p1, const charT* p2) const; + string_type transform_primary(const charT* p1, const charT* p2) const; + string_type transform(const charT* p1, const charT* p2) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_locale, p1, p2); + } +private: + std::map m_error_strings; // error messages indexed by numberic ID + std::map m_custom_class_names; // character class names + std::map m_custom_collate_names; // collating element names + unsigned m_collate_type; // the form of the collation string + charT m_collate_delim; // the collation group delimiter + // + // helpers: + // + char_class_type lookup_classname_imp(const charT* p1, const charT* p2) const; +}; + +template +typename w32_regex_traits_implementation::string_type + w32_regex_traits_implementation::transform_primary(const charT* p1, const charT* p2) const +{ + string_type result; + // + // What we do here depends upon the format of the sort key returned by + // sort key returned by this->transform: + // + switch(m_collate_type) + { + case sort_C: + case sort_unknown: + // the best we can do is translate to lower case, then get a regular sort key: + { + result.assign(p1, p2); + typedef typename string_type::size_type size_type; + for(size_type i = 0; i < result.size(); ++i) + result[i] = this->tolower(result[i]); + result = this->transform(&*result.begin(), &*result.begin() + result.size()); + break; + } + case sort_fixed: + { + // get a regular sort key, and then truncate it: + result.assign(this->transform(p1, p2)); + result.erase(this->m_collate_delim); + break; + } + case sort_delim: + // get a regular sort key, and then truncate everything after the delim: + result.assign(this->transform(p1, p2)); + std::size_t i; + for(i = 0; i < result.size(); ++i) + { + if(result[i] == m_collate_delim) + break; + } + result.erase(i); + break; + } + if(result.empty()) + result = string_type(1, charT(0)); + return result; +} + +template +typename w32_regex_traits_implementation::string_type + w32_regex_traits_implementation::lookup_collatename(const charT* p1, const charT* p2) const +{ + typedef typename std::map::const_iterator iter_type; + if(m_custom_collate_names.size()) + { + iter_type pos = m_custom_collate_names.find(string_type(p1, p2)); + if(pos != m_custom_collate_names.end()) + return pos->second; + } + std::string name(p1, p2); + name = lookup_default_collate_name(name); + if(name.size()) + return string_type(name.begin(), name.end()); + if(p2 - p1 == 1) + return string_type(1, *p1); + return string_type(); +} + +template +w32_regex_traits_implementation::w32_regex_traits_implementation(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) +: w32_regex_traits_char_layer(l) +{ + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if(cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if(!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if(cat) + { + // + // Error messages: + // + for(boost::regex_constants::error_type i = static_cast(0); + i <= boost::regex_constants::error_unknown; + i = static_cast(i + 1)) + { + const char* p = get_default_error_string(i); + string_type default_message; + while(*p) + { + default_message.append(1, static_cast(*p)); + ++p; + } + string_type s = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i+200, default_message); + std::string result; + for(std::string::size_type j = 0; j < s.size(); ++j) + { + result.append(1, static_cast(s[j])); + } + m_error_strings[i] = result; + } + // + // Custom class names: + // + static const char_class_type masks[14] = + { + 0x0104u, // C1_ALPHA | C1_DIGIT + 0x0100u, // C1_ALPHA + 0x0020u, // C1_CNTRL + 0x0004u, // C1_DIGIT + (~(0x0020u|0x0008u) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE + 0x0002u, // C1_LOWER + (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL + 0x0010u, // C1_PUNCT + 0x0008u, // C1_SPACE + 0x0001u, // C1_UPPER + 0x0080u, // C1_XDIGIT + 0x0040u, // C1_BLANK + w32_regex_traits_implementation::mask_word, + w32_regex_traits_implementation::mask_unicode, + }; + static const string_type null_string; + for(unsigned int j = 0; j <= 13; ++j) + { + string_type s(::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, j+300, null_string)); + if(s.size()) + this->m_custom_class_names[s] = masks[j]; + } + } + // + // get the collation format used by m_pcollate: + // + m_collate_type = BOOST_REGEX_DETAIL_NS::find_sort_syntax(this, &m_collate_delim); +} + +template +typename w32_regex_traits_implementation::char_class_type + w32_regex_traits_implementation::lookup_classname_imp(const charT* p1, const charT* p2) const +{ + static const char_class_type masks[22] = + { + 0, + 0x0104u, // C1_ALPHA | C1_DIGIT + 0x0100u, // C1_ALPHA + 0x0040u, // C1_BLANK + 0x0020u, // C1_CNTRL + 0x0004u, // C1_DIGIT + 0x0004u, // C1_DIGIT + (~(0x0020u|0x0008u|0x0040) & 0x01ffu) | 0x0400u, // not C1_CNTRL or C1_SPACE or C1_BLANK + w32_regex_traits_implementation::mask_horizontal, + 0x0002u, // C1_LOWER + 0x0002u, // C1_LOWER + (~0x0020u & 0x01ffu) | 0x0400, // not C1_CNTRL + 0x0010u, // C1_PUNCT + 0x0008u, // C1_SPACE + 0x0008u, // C1_SPACE + 0x0001u, // C1_UPPER + w32_regex_traits_implementation::mask_unicode, + 0x0001u, // C1_UPPER + w32_regex_traits_implementation::mask_vertical, + 0x0104u | w32_regex_traits_implementation::mask_word, + 0x0104u | w32_regex_traits_implementation::mask_word, + 0x0080u, // C1_XDIGIT + }; + if(m_custom_class_names.size()) + { + typedef typename std::map, char_class_type>::const_iterator map_iter; + map_iter pos = m_custom_class_names.find(string_type(p1, p2)); + if(pos != m_custom_class_names.end()) + return pos->second; + } + std::size_t state_id = 1u + (std::size_t)BOOST_REGEX_DETAIL_NS::get_default_class_id(p1, p2); + if(state_id < sizeof(masks) / sizeof(masks[0])) + return masks[state_id]; + return masks[0]; +} + + +template +std::shared_ptr > create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::lcid_type l) +{ + // TODO: create a cache for previously constructed objects. + return boost::object_cache< ::boost::BOOST_REGEX_DETAIL_NS::lcid_type, w32_regex_traits_implementation >::get(l, 5); +} + +} // BOOST_REGEX_DETAIL_NS + +template +class w32_regex_traits +{ +public: + typedef charT char_type; + typedef std::size_t size_type; + typedef std::basic_string string_type; + typedef ::boost::BOOST_REGEX_DETAIL_NS::lcid_type locale_type; + typedef std::uint_least32_t char_class_type; + + struct boost_extensions_tag{}; + + w32_regex_traits() + : m_pimpl(BOOST_REGEX_DETAIL_NS::create_w32_regex_traits(::boost::BOOST_REGEX_DETAIL_NS::w32_get_default_locale())) + { } + static size_type length(const char_type* p) + { + return std::char_traits::length(p); + } + regex_constants::syntax_type syntax_type(charT c)const + { + return m_pimpl->syntax_type(c); + } + regex_constants::escape_syntax_type escape_syntax_type(charT c) const + { + return m_pimpl->escape_syntax_type(c); + } + charT translate(charT c) const + { + return c; + } + charT translate_nocase(charT c) const + { + return this->m_pimpl->tolower(c); + } + charT translate(charT c, bool icase) const + { + return icase ? this->m_pimpl->tolower(c) : c; + } + charT tolower(charT c) const + { + return this->m_pimpl->tolower(c); + } + charT toupper(charT c) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_toupper(c, this->m_pimpl->m_locale); + } + string_type transform(const charT* p1, const charT* p2) const + { + return ::boost::BOOST_REGEX_DETAIL_NS::w32_transform(this->m_pimpl->m_locale, p1, p2); + } + string_type transform_primary(const charT* p1, const charT* p2) const + { + return m_pimpl->transform_primary(p1, p2); + } + char_class_type lookup_classname(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_classname(p1, p2); + } + string_type lookup_collatename(const charT* p1, const charT* p2) const + { + return m_pimpl->lookup_collatename(p1, p2); + } + bool isctype(charT c, char_class_type f) const + { + if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_base) + && (this->m_pimpl->isctype(f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_base, c))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_unicode) && BOOST_REGEX_DETAIL_NS::is_extended(c)) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_vertical) + && (::boost::BOOST_REGEX_DETAIL_NS::is_separator(c) || (c == '\v'))) + return true; + else if((f & BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_horizontal) + && this->isctype(c, 0x0008u) && !this->isctype(c, BOOST_REGEX_DETAIL_NS::w32_regex_traits_implementation::mask_vertical)) + return true; + return false; + } + std::intmax_t toi(const charT*& p1, const charT* p2, int radix)const + { + return ::boost::BOOST_REGEX_DETAIL_NS::global_toi(p1, p2, radix, *this); + } + int value(charT c, int radix)const + { + int result = (int)::boost::BOOST_REGEX_DETAIL_NS::global_value(c); + return result < radix ? result : -1; + } + locale_type imbue(locale_type l) + { + ::boost::BOOST_REGEX_DETAIL_NS::lcid_type result(getloc()); + m_pimpl = BOOST_REGEX_DETAIL_NS::create_w32_regex_traits(l); + return result; + } + locale_type getloc()const + { + return m_pimpl->m_locale; + } + std::string error_string(regex_constants::error_type n) const + { + return m_pimpl->error_string(n); + } + + // + // extension: + // set the name of the message catalog in use (defaults to "boost_regex"). + // + static std::string catalog_name(const std::string& name); + static std::string get_catalog_name(); + +private: + std::shared_ptr > m_pimpl; + // + // catalog name handler: + // + static std::string& get_catalog_name_inst(); + +#ifdef BOOST_HAS_THREADS + static std::mutex& get_mutex_inst(); +#endif +}; + +template +std::string w32_regex_traits::catalog_name(const std::string& name) +{ +#ifdef BOOST_HAS_THREADS + std::lock_guard lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + get_catalog_name_inst() = name; + return result; +} + +template +std::string& w32_regex_traits::get_catalog_name_inst() +{ + static std::string s_name; + return s_name; +} + +template +std::string w32_regex_traits::get_catalog_name() +{ +#ifdef BOOST_HAS_THREADS + std::lock_guard lk(get_mutex_inst()); +#endif + std::string result(get_catalog_name_inst()); + return result; +} + +#ifdef BOOST_HAS_THREADS +template +std::mutex& w32_regex_traits::get_mutex_inst() +{ + static std::mutex s_mutex; + return s_mutex; +} +#endif + +namespace BOOST_REGEX_DETAIL_NS { + +#ifdef BOOST_NO_ANSI_APIS + inline unsigned int get_code_page_for_locale_id(lcid_type idx) + { + wchar_t code_page_string[7]; + if (boost::BOOST_REGEX_DETAIL_NS::GetLocaleInfoW(idx, locale_idefaultansicodepage, code_page_string, 7) == 0) + return 0; + + return static_cast(_wtol(code_page_string)); +} +#endif + + template + inline void w32_regex_traits_char_layer::init() + { + // we need to start by initialising our syntax map so we know which + // character is used for which purpose: + std::memset(m_char_map, 0, sizeof(m_char_map)); + cat_type cat; + std::string cat_name(w32_regex_traits::get_catalog_name()); + if (cat_name.size()) + { + cat = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_open(cat_name); + if (!cat) + { + std::string m("Unable to open message catalog: "); + std::runtime_error err(m + cat_name); + ::boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); + } + } + // + // if we have a valid catalog then load our messages: + // + if (cat) + { + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + string_type mss = ::boost::BOOST_REGEX_DETAIL_NS::w32_cat_get(cat, this->m_locale, i, get_default_syntax(i)); + for (string_type::size_type j = 0; j < mss.size(); ++j) + { + m_char_map[static_cast(mss[j])] = i; + } + } + } + else + { + for (regex_constants::syntax_type i = 1; i < regex_constants::syntax_max; ++i) + { + const char* ptr = get_default_syntax(i); + while (ptr && *ptr) + { + m_char_map[static_cast(*ptr)] = i; + ++ptr; + } + } + } + // + // finish off by calculating our escape types: + // + unsigned char i = 'A'; + do + { + if (m_char_map[i] == 0) + { + if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0002u, (char)i)) + m_char_map[i] = regex_constants::escape_type_class; + else if (::boost::BOOST_REGEX_DETAIL_NS::w32_is(this->m_locale, 0x0001u, (char)i)) + m_char_map[i] = regex_constants::escape_type_not_class; + } + } while (0xFF != i++); + + // + // fill in lower case map: + // + char char_map[1 << CHAR_BIT]; + for (int ii = 0; ii < (1 << CHAR_BIT); ++ii) + char_map[ii] = static_cast(ii); +#ifndef BOOST_NO_ANSI_APIS + int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA(this->m_locale, lcmap_lowercase, char_map, 1 << CHAR_BIT, this->m_lower_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(r != 0); +#else + unsigned int code_page = get_code_page_for_locale_id(this->m_locale); + BOOST_REGEX_ASSERT(code_page != 0); + + wchar_t wide_char_map[1 << CHAR_BIT]; + int conv_r = boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, char_map, 1 << CHAR_BIT, wide_char_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(conv_r != 0); + + wchar_t wide_lower_map[1 << CHAR_BIT]; + int r = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW(this->m_locale, lcmap_lowercase, wide_char_map, 1 << CHAR_BIT, wide_lower_map, 1 << CHAR_BIT); + BOOST_REGEX_ASSERT(r != 0); + + conv_r = boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, wide_lower_map, r, this->m_lower_map, 1 << CHAR_BIT, NULL, NULL); + BOOST_REGEX_ASSERT(conv_r != 0); +#endif + if (r < (1 << CHAR_BIT)) + { + // if we have multibyte characters then not all may have been given + // a lower case mapping: + for (int jj = r; jj < (1 << CHAR_BIT); ++jj) + this->m_lower_map[jj] = static_cast(jj); + } + +#ifndef BOOST_NO_ANSI_APIS + r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(this->m_locale, ct_ctype1, char_map, 1 << CHAR_BIT, this->m_type_map); +#else + r = boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(this->m_locale, ct_ctype1, wide_char_map, 1 << CHAR_BIT, this->m_type_map); +#endif + BOOST_REGEX_ASSERT(0 != r); + } + + inline lcid_type w32_get_default_locale() + { + return boost::BOOST_REGEX_DETAIL_NS::GetUserDefaultLCID(); + } + + inline bool w32_is_lower(char c, lcid_type idx) + { +#ifndef BOOST_NO_ANSI_APIS + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower)) + return true; + return false; +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + wchar_t wide_c; + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_lower)) + return true; + return false; +#endif + } + + inline bool w32_is_lower(wchar_t c, lcid_type idx) + { + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_lower)) + return true; + return false; + } + + inline bool w32_is_upper(char c, lcid_type idx) + { +#ifndef BOOST_NO_ANSI_APIS + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper)) + return true; + return false; +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + wchar_t wide_c; + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & c1_upper)) + return true; + return false; +#endif + } + + inline bool w32_is_upper(wchar_t c, lcid_type idx) + { + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & c1_upper)) + return true; + return false; + } + + inline void free_module(void* mod) + { + boost::BOOST_REGEX_DETAIL_NS::FreeLibrary(static_cast(mod)); + } + + inline cat_type w32_cat_open(const std::string& name) + { +#ifndef BOOST_NO_ANSI_APIS + cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryA(name.c_str()), &free_module); + return result; +#else + wchar_t* wide_name = (wchar_t*)_alloca((name.size() + 1) * sizeof(wchar_t)); + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(cp_acp, 0, name.c_str(), (int)name.size(), wide_name, (int)(name.size() + 1)) == 0) + return cat_type(); + + cat_type result(boost::BOOST_REGEX_DETAIL_NS::LoadLibraryW(wide_name), &free_module); + return result; +#endif + } + + inline std::string w32_cat_get(const cat_type& cat, lcid_type, int i, const std::string& def) + { +#ifndef BOOST_NO_ANSI_APIS + char buf[256]; + if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringA( + static_cast(cat.get()), + i, + buf, + 256 + )) + { + return def; + } +#else + wchar_t wbuf[256]; + int r = boost::BOOST_REGEX_DETAIL_NS::LoadStringW( + static_cast(cat.get()), + i, + wbuf, + 256 + ); + if (r == 0) + return def; + + + int buf_size = 1 + boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, NULL, 0, NULL, NULL); + char* buf = (char*)_alloca(buf_size); + if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(cp_acp, 0, wbuf, r, buf, buf_size, NULL, NULL) == 0) + return def; // failed conversion. +#endif + return std::string(buf); + } + +#ifndef BOOST_NO_WREGEX + inline std::wstring w32_cat_get(const cat_type& cat, lcid_type, int i, const std::wstring& def) + { + wchar_t buf[256]; + if (0 == boost::BOOST_REGEX_DETAIL_NS::LoadStringW(static_cast(cat.get()), i, buf, 256)) + { + return def; + } + return std::wstring(buf); + } +#endif + inline std::string w32_transform(lcid_type idx, const char* p1, const char* p2) + { +#ifndef BOOST_NO_ANSI_APIS + int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + &*result.begin(), // destination buffer + bytes // size of destination buffer + ); +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return std::string(p1, p2); + + int src_len = static_cast(p2 - p1); + wchar_t* wide_p1 = (wchar_t*)_alloca((src_len + 1) * 2); + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, p1, src_len, wide_p1, src_len + 1) == 0) + return std::string(p1, p2); + + int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::string(p1, p2); + std::string result(++bytes, '\0'); + bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + wide_p1, // source string + src_len, // number of characters in source string + (wchar_t*) & *result.begin(), // destination buffer + bytes // size of destination buffer + ); +#endif + if (bytes > static_cast(result.size())) + return std::string(p1, p2); + while (result.size() && result[result.size() - 1] == '\0') + { + result.erase(result.size() - 1); + } + return result; + } + +#ifndef BOOST_NO_WREGEX + inline std::wstring w32_transform(lcid_type idx, const wchar_t* p1, const wchar_t* p2) + { + int bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + 0, // destination buffer + 0 // size of destination buffer + ); + if (!bytes) + return std::wstring(p1, p2); + std::string result(++bytes, '\0'); + bytes = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_sortkey, // mapping transformation type + p1, // source string + static_cast(p2 - p1), // number of characters in source string + reinterpret_cast(&*result.begin()), // destination buffer *of bytes* + bytes // size of destination buffer + ); + if (bytes > static_cast(result.size())) + return std::wstring(p1, p2); + while (result.size() && result[result.size() - 1] == L'\0') + { + result.erase(result.size() - 1); + } + std::wstring r2; + for (std::string::size_type i = 0; i < result.size(); ++i) + r2.append(1, static_cast(static_cast(result[i]))); + return r2; + } +#endif + inline char w32_tolower(char c, lcid_type idx) + { + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA( + idx, // locale identifier + lcmap_lowercase, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return c; + + wchar_t wide_c; + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + wchar_t wide_result; + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_lowercase, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + + if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte lower case equivalent available +#endif + return result[0]; + } + +#ifndef BOOST_NO_WREGEX + inline wchar_t w32_tolower(wchar_t c, lcid_type idx) + { + wchar_t result[2]; + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_lowercase, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + return result[0]; + } +#endif + inline char w32_toupper(char c, lcid_type idx) + { + char result[2]; +#ifndef BOOST_NO_ANSI_APIS + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringA( + idx, // locale identifier + lcmap_uppercase, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return c; + + wchar_t wide_c; + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return c; + + wchar_t wide_result; + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_uppercase, // mapping transformation type + &wide_c, // source string + 1, // number of characters in source string + &wide_result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + + if (boost::BOOST_REGEX_DETAIL_NS::WideCharToMultiByte(code_page, 0, &wide_result, 1, result, 2, NULL, NULL) == 0) + return c; // No single byte upper case equivalent available. +#endif + return result[0]; + } + +#ifndef BOOST_NO_WREGEX + inline wchar_t w32_toupper(wchar_t c, lcid_type idx) + { + wchar_t result[2]; + int b = boost::BOOST_REGEX_DETAIL_NS::LCMapStringW( + idx, // locale identifier + lcmap_uppercase, // mapping transformation type + &c, // source string + 1, // number of characters in source string + result, // destination buffer + 1); // size of destination buffer + if (b == 0) + return c; + return result[0]; + } +#endif + inline bool w32_is(lcid_type idx, std::uint32_t m, char c) + { + word mask; +#ifndef BOOST_NO_ANSI_APIS + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExA(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#else + unsigned int code_page = get_code_page_for_locale_id(idx); + if (code_page == 0) + return false; + + wchar_t wide_c; + if (boost::BOOST_REGEX_DETAIL_NS::MultiByteToWideChar(code_page, 0, &c, 1, &wide_c, 1) == 0) + return false; + + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &wide_c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; +#endif + if ((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + return false; + } + +#ifndef BOOST_NO_WREGEX + inline bool w32_is(lcid_type idx, std::uint32_t m, wchar_t c) + { + word mask; + if (boost::BOOST_REGEX_DETAIL_NS::GetStringTypeExW(idx, ct_ctype1, &c, 1, &mask) && (mask & m & w32_regex_traits_implementation::mask_base)) + return true; + if ((m & w32_regex_traits_implementation::mask_word) && (c == '_')) + return true; + if ((m & w32_regex_traits_implementation::mask_unicode) && (c > 0xff)) + return true; + return false; + } +#endif + +} // BOOST_REGEX_DETAIL_NS + + +} // boost + +#ifdef BOOST_REGEX_MSVC +#pragma warning(pop) +#endif + +#endif // BOOST_REGEX_NO_WIN32_LOCALE + +#endif diff --git a/third-party/boost_regex/include/boost/regex_fwd.hpp b/third-party/boost_regex/include/boost/regex_fwd.hpp new file mode 100644 index 0000000000..99371b8cae --- /dev/null +++ b/third-party/boost_regex/include/boost/regex_fwd.hpp @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 1998-2002 + * John Maddock + * + * Use, modification and distribution are subject to the + * Boost Software License, Version 1.0. (See accompanying file + * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + * + */ + + /* + * LOCATION: see http://www.boost.org/libs/regex for documentation. + * FILE regex_fwd.cpp + * VERSION see + * DESCRIPTION: Forward declares boost::basic_regex<> and + * associated typedefs. + */ + +#ifndef BOOST_REGEX_FWD_HPP +#define BOOST_REGEX_FWD_HPP + +#ifndef BOOST_REGEX_CONFIG_HPP +#include +#endif + +#ifdef BOOST_REGEX_CXX03 +#include +#else +#include +#endif + +#endif + + + + diff --git a/third-party/libprisma/BUILD b/third-party/libprisma/BUILD new file mode 100644 index 0000000000..7caecf7ac5 --- /dev/null +++ b/third-party/libprisma/BUILD @@ -0,0 +1,76 @@ +load( + "@build_bazel_rules_apple//apple:resources.bzl", + "apple_resource_bundle", + "apple_resource_group", +) +load("//build-system/bazel-utils:plist_fragment.bzl", + "plist_fragment", +) + +filegroup( + name = "LibprismaResources", + srcs = glob([ + "Resources/**/*.dat", + ]), + visibility = ["//visibility:public"], +) + +plist_fragment( + name = "LibprismaInfoPlist", + extension = "plist", + template = + """ + CFBundleIdentifier + org.telegram.Libprisma + CFBundleDevelopmentRegion + en + CFBundleName + Libprisma + """ +) + +apple_resource_bundle( + name = "LibprismaBundle", + infoplists = [ + ":LibprismaInfoPlist", + ], + resources = [ + ":LibprismaResources", + ], +) + +objc_library( + name = "libprisma", + enable_modules = True, + module_name = "libprisma", + srcs = glob([ + "Sources/**/*.c", + "Sources/**/*.cpp", + "Sources/**/*.m", + "Sources/**/*.mm", + "Sources/**/*.h", + "Sources/**/*.hpp", + ]), + hdrs = glob([ + "include/libprisma/*.h", + ]), + includes = [ + "include", + ], + data = [ + ":LibprismaBundle", + ], + copts = [ + "-Ithird-party/libprisma/include/libprisma", + ], + deps = [ + "//third-party/boost_regex", + ], + sdk_frameworks = [ + "Foundation", + "UIKit", + ], + visibility = [ + "//visibility:public", + ], +) diff --git a/third-party/libprisma/Resources/grammars.dat b/third-party/libprisma/Resources/grammars.dat new file mode 100644 index 0000000000000000000000000000000000000000..13b0d21f2af26eb5aff2a7a7c9f52af3dfccce82 GIT binary patch literal 620919 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

bo=X+)+)COMT_ti68@raFcip%E3maMx@IwG6n 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

ZRhwM?EXo2bH;#k&&~d|I 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

>Ja6jN)W!kG zoLkh@1alG*P@dwEm*ximYTtnYdE_Hu?f0>nDQ<=1 zALQmZis{e;m240rv6Q4h)eYhl-CBv~M#!c!ELovkEVJJj%H%qJv+HoU4{CN6282Vk zZgQX6*N*};IF`j2$q+Vc0K{jql8)(4nuQE(v6-oSgvm{+8GQyopjbd4em_X8X%wC| zL6VD;)HW^D;!`7EZ!Ic{$x#f>xh*(=VV0~_b{OtoOkliYA~eao)dm;{+ZPR4Bu5uG zwWtq~jo>_0Q4H)eV|oGb?>G=sn+xl7u%dYvr;5iOurHPQPcRoEZ7FqnsmKSG@dC;? z(@+}`$Mh!1V0r0faZg!k9c{YcAqO0Spb@Q?y@-45Q%3f_)Pi2|A#)?koVjSTbgbw5 z{f+)12a-(d;(0n3-OHN1Qf4rxtG&UZk)z)U)e_QlrZbCb*$3h-4tK~HPp+9e2rnRW z)WB|qDg+4&O)pS1mh&8W3w^6Z0AJ^_vH=wA!##8=0|yHlT0}`ZCHe|MnKvn z&&-|{FjiqLPz5$>DkWQ4f4C&u!*-A;o5IhLjGt7sy`ttDa%jAwU1D^BHiLUdE5ooa=Jvzl&Th` z5wWS^SzN`KX0hlRpd=6F-p3L+!PuDVRyVA0Vm;v=#g#6~ih z7&^_M*k}f6KeG(Pav6MJ?R2%}89I)lLdGDvqv14~6XU2*pj_MkURbLnxje0Hei*&Z?+1l$nYB6*fV?0wV`l05P*na=+Z}A-~sq zQwWA~_5~4O=A*d`*`$m)Qkpb>er0IW$XUmy$6ZvVjDvko3cP3prt568y%}6TTauIs z3gnK&c+_uZ3}KFJ=j8nY`qbp1(-;mQG@AustSlR@$U`XIQYhu}dF9ag7RiC7;*9Y= z5(Ae-1F1?Ly2g!l7B-q5m`gtmB>KIAt1yqewr5WEDRAx-jG{y5UI2`odof5iJ@=w0 zC|LDoa*5&zhdlC#Jxf{!ad%Hm13y$G&s~ouB1 zvi2Gp&035tmwSNLE5#CLqYq6Bd1?Ej$XlNYM(9Q&0lrXHD^`&QYlp8mj1U09d{8y# zj_)W681YC>ZFOMNA;NX&fL!Y1VsMllqFPU(4yA_0 z8iLFjTO*2sXtFTee;XdEC65w1g%K;~gPrCWaR{!L!F{>_K7NHD@hnxyK-3LIh)1Q2 z>VCl@?cx;I#x9K%&3k8>j3-YE+jS~&n+}37MWMs<8N_|%;wcRmN}wIdYBM|3EXuxS zeG#(KX(_@AATW{SGHSUsr`kGfiP_A_{%l0jWD!$r8Xv2wH7YgCm#mkWp?Lt^7Wc^) zsA)L7V_RDc8}nS#T?*bh&%wBL`bW`cfTh@x>WpOwY<~Gj9=pZ<$x_L>=p~muV_M

qpuK6pHi7I`}0x4 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 literal 0 HcmV?d00001 diff --git a/third-party/libprisma/Sources/Highlight.cpp b/third-party/libprisma/Sources/Highlight.cpp new file mode 100644 index 0000000000..8d5545256d --- /dev/null +++ b/third-party/libprisma/Sources/Highlight.cpp @@ -0,0 +1,42 @@ +#include "Highlight.h" + +#include "LanguageTree.h" + +GrammarPtr::GrammarPtr(std::shared_ptr tree, size_t path) + : m_tree(tree) + , m_path(path) +{ + +} + +const Grammar* GrammarPtr::operator->() const +{ + return get(); +} + +const Grammar* GrammarPtr::get() const +{ + return m_tree->resolveGrammar(m_path); +} + +PatternPtr::PatternPtr(std::shared_ptr tree, size_t path) + : m_tree(tree) + , m_path(path) +{ + +} + +const Pattern* PatternPtr::get() const +{ + return m_tree->resolvePattern(m_path); +} + +const Grammar* Pattern::inside() const +{ + if (m_inside) + { + return m_inside->get(); + } + + return nullptr; +} diff --git a/third-party/libprisma/Sources/Highlight.h b/third-party/libprisma/Sources/Highlight.h new file mode 100644 index 0000000000..a1130e069a --- /dev/null +++ b/third-party/libprisma/Sources/Highlight.h @@ -0,0 +1,146 @@ +#pragma once +#include +#include +#include +#include +#include + +class GrammarPtr; +class GrammarToken; +class Pattern; +class TokenList; + +class LanguageTree; + +struct Grammar { + std::vector tokens; +}; + +class GrammarPtr +{ +public: + GrammarPtr(std::shared_ptr tree, size_t path); + + const Grammar* operator->() const; + const Grammar* get() const; + +private: + std::shared_ptr m_tree; + size_t m_path; +}; + +class Pattern +{ +public: + Pattern(std::string_view pattern, boost::regex_constants::syntax_option_type flags, bool lookbehind, bool greedy, std::string alias, GrammarPtr inside) + : Pattern(pattern, flags, lookbehind, greedy, alias, std::make_shared(inside)) + { + + } + + Pattern(std::string_view pattern, boost::regex_constants::syntax_option_type flags, bool lookbehind = false, bool greedy = false, std::string alias = "", std::shared_ptr inside = nullptr) + : m_regex(boost::regex(std::string{pattern}, flags | boost::regex_constants::optimize)) + , m_lookbehind(lookbehind) + , m_greedy(greedy) + , m_alias(alias) + , m_inside(inside) + { + } + + std::string_view match(bool& success, size_t& pos, std::string_view text) const + { + boost::cmatch m; + + auto flags = boost::regex_constants::match_not_dot_newline; + auto match = boost::regex_search(text.data() + pos, text.data() + text.size(), m, m_regex, flags); + if (match) + { + success = true; + pos += m.position(); + + if (m_lookbehind && m[1].matched) + { + // change the match to remove the text matched by the Prism lookbehind group + auto lookbehindLength = m[1].length(); + pos += lookbehindLength; + + return text.substr(pos, m[0].length() - lookbehindLength); + } + + return text.substr(pos, m[0].length()); + } + + return {}; + } + + bool lookbehind() const + { + return m_lookbehind; + } + + bool greedy() const + { + return m_greedy; + } + + std::string alias() const + { + return m_alias; + } + + const Grammar* inside() const; + +private: + boost::regex m_regex; + bool m_lookbehind; + bool m_greedy; + std::string m_alias; + std::shared_ptr m_inside; +}; + +class PatternPtr +{ +public: + PatternPtr(std::shared_ptr tree, size_t path); + + const Pattern* operator->() const + { + return get(); + } + + const Pattern* get() const; + +private: + std::shared_ptr m_tree; + size_t m_path; +}; + +class GrammarToken +{ +public: + GrammarToken(const std::string name, std::vector patterns) + : m_name(name) + , m_patterns(std::move(patterns)) + { + + } + + const std::string &name() const + { + return m_name; + } + + std::vector::const_iterator cbegin() const noexcept + { + return m_patterns.cbegin(); + } + + std::vector::const_iterator cend() const noexcept + { + return m_patterns.cend(); + } + +private: + std::string m_name; + const std::vector m_patterns; +}; diff --git a/third-party/libprisma/Sources/LanguageTree.cpp b/third-party/libprisma/Sources/LanguageTree.cpp new file mode 100644 index 0000000000..1518bcb72a --- /dev/null +++ b/third-party/libprisma/Sources/LanguageTree.cpp @@ -0,0 +1,184 @@ +#include "LanguageTree.h" + +#include "TokenList.h" +#include + +void LanguageTree::load(const std::string& content) +{ + Buffer buffer{ content }; + parsePatterns(buffer); + parseGrammars(buffer); + parseLanguages(buffer); +} + +inline uint8_t freadUint8(Buffer &buffer) +{ + uint8_t value = 0; + if (buffer.offset + sizeof(uint8_t) <= buffer.content.size()) { + memcpy(&value, &buffer.content[buffer.offset], sizeof(uint8_t)); + buffer.offset += sizeof(uint8_t); + } + return value; +} + +inline uint16_t freadUint16(Buffer &buffer) +{ + uint16_t value = 0; + if (buffer.offset + sizeof(uint16_t) <= buffer.content.size()) { + memcpy(&value, &buffer.content[buffer.offset], sizeof(uint16_t)); + buffer.offset += sizeof(uint16_t); + } + return value; +} + +inline std::string freadString(Buffer &buffer) +{ + size_t length = freadUint8(buffer); + if (length >= 254) + { + size_t a = freadUint8(buffer); + size_t b = freadUint8(buffer); + size_t c = freadUint8(buffer); + length = a | (b << 8) | (c << 16); + } + + std::string str(length, '\0'); + if (buffer.offset + length <= buffer.content.size()) + { + memcpy(&str[0], &buffer.content[buffer.offset], length); + buffer.offset += length; + } + return str; +} + +void LanguageTree::parseLanguages(Buffer &buffer) +{ + uint16_t count = freadUint16(buffer); + + for (int i = 0; i < count; ++i) + { + std::string name = freadString(buffer); + std::string displayName = freadString(buffer); + size_t index = freadUint16(buffer); + m_languages.emplace(name, std::pair(displayName, index)); + } +} + +void LanguageTree::parseGrammars(Buffer &buffer) +{ + uint16_t count = freadUint16(buffer); + + for (int i = 0; i < count; ++i) + { + auto grammar = std::make_shared(); + const auto keys = freadUint8(buffer); + + for (int j = 0; j < keys; ++j) + { + std::vector indices; + + const auto key = freadString(buffer); + uint8_t ids = freadUint8(buffer); + + for (int k = 0; k < ids; ++k) + { + indices.push_back(PatternPtr(shared_from_this(), freadUint16(buffer))); + } + + grammar->tokens.push_back(GrammarToken(key, indices)); + } + + m_grammars.push_back(grammar); + } +} + +void LanguageTree::parsePatterns(Buffer &buffer) +{ + uint16_t count = freadUint16(buffer); + + for (int i = 0; i < count; ++i) + { + std::string item = freadString(buffer); + std::string_view value(item); + std::string alias; + + size_t beg = value.find_first_of('/'); + size_t end = value.find_last_of('/'); + + if (beg != std::string::npos && end != std::string::npos) + { + std::string_view pattern = value.substr(beg + 1, end - (beg + 1)); + std::string_view options = value.substr(end + 1); + + size_t aliasBeg = options.find_first_of(','); + size_t aliasEnd = options.find_last_of(','); + + std::string alias{ options.substr(aliasBeg + 1, aliasEnd - (aliasBeg + 1)) }; + size_t inside = 0; + + if (aliasEnd + 1 < options.size()) + { + for (int i = aliasEnd + 1; i < options.size(); i++) + { + char c = options[i]; + if (c >= '0' && c <= '9') + { + inside = inside * 10 + (c - '0'); + } + else + { + assert(false); + } + } + } + else + { + inside = std::string::npos; + } + + bool lookbehind = false; + bool greedy = false; + + boost::regex_constants::syntax_option_type flags + = boost::regex_constants::ECMAScript | boost::regex_constants::no_mod_m; + + for (char c : options.substr(0, aliasBeg)) + { + switch (c) + { + case 'l': + lookbehind = true; + break; + case 'y': + greedy = true; + break; + case 'i': + flags |= boost::regex_constants::icase; + break; + case 'm': + flags &= ~boost::regex_constants::no_mod_m; + break; + } + } + + if (inside != std::string::npos) + { + m_patterns.push_back(std::make_shared(pattern, flags, lookbehind, greedy, std::string{ alias }, std::make_shared(shared_from_this(), inside))); + } + else + { + m_patterns.push_back(std::make_shared(pattern, flags, lookbehind, greedy, std::string{ alias })); + } + } + } +} + +const Pattern* LanguageTree::resolvePattern(size_t path) +{ + return m_patterns[path].get(); +} + +const Grammar* LanguageTree::resolveGrammar(size_t path) +{ + return m_grammars[path].get(); +} diff --git a/third-party/libprisma/Sources/LanguageTree.h b/third-party/libprisma/Sources/LanguageTree.h new file mode 100644 index 0000000000..422a2ff26a --- /dev/null +++ b/third-party/libprisma/Sources/LanguageTree.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include + +#include "Highlight.h" + +struct Buffer { + const std::string &content; + int64_t offset = 0; +}; + +class LanguageTree : public std::enable_shared_from_this +{ +public: + LanguageTree() = default; + + void load(const std::string& content); + + const Pattern* resolvePattern(size_t path); + const Grammar* resolveGrammar(size_t path); + + std::map keys() const + { + std::map keys; + + for (const auto& kv : m_languages) + { + if (kv.second.first.empty()) + { + continue; + } + + keys.emplace(kv.first, kv.second.first); + } + + return keys; + } + + const Grammar* find(const std::string& key) const + { + const auto& value = m_languages.find(key); + if (value != m_languages.end()) + { + return m_grammars[value->second.second].get(); + } + + return nullptr; + } + +private: + void parseLanguages(Buffer &buffer); + void parseGrammars(Buffer &buffer); + void parsePatterns(Buffer &buffer); + + std::map> m_languages; + std::vector> m_grammars; + std::vector> m_patterns; +}; \ No newline at end of file diff --git a/third-party/libprisma/Sources/SyntaxHighlighter.cpp b/third-party/libprisma/Sources/SyntaxHighlighter.cpp new file mode 100644 index 0000000000..5fe8535b0e --- /dev/null +++ b/third-party/libprisma/Sources/SyntaxHighlighter.cpp @@ -0,0 +1,199 @@ +#include "SyntaxHighlighter.h" +#include "LanguageTree.h" +#include "TokenList.h" + +SyntaxHighlighter::SyntaxHighlighter(const std::string& path) +{ + m_tree = std::make_shared(); + m_tree->load(path); +} + +TokenList SyntaxHighlighter::tokenize(const std::string& text, const std::string& language) +{ + const Grammar* grammar = m_tree->find(language); + if (grammar) + { + return tokenize(text, grammar); + } + + return TokenList(text); +} + +std::map SyntaxHighlighter::languages() const +{ + return m_tree->keys(); +} + +TokenList SyntaxHighlighter::tokenize(std::string_view text, const Grammar* grammar) +{ + TokenList tokenList(text); + matchGrammar(text, tokenList, grammar, tokenList.head, 0, nullptr); + + return tokenList; +} + +void SyntaxHighlighter::matchGrammar(std::string_view text, TokenList& tokenList, const Grammar* grammar, TokenListPtr startNode, size_t startPos, RematchOptions* rematch) +{ + for (const auto& token : grammar->tokens) + { + int x = 0; + for (auto j = token.cbegin(); j != token.cend(); ++j) + { + if (rematch && rematch->j == x && rematch->token == token.name()) + { + return; + } + + const auto& pattern = *j; + const auto& inside = pattern->inside(); + const bool greedy = pattern->greedy(); + + size_t pos = startPos; + + // iterate the token list and keep track of the current token/string position + for (TokenListPtr currentNode = startNode->next; + currentNode != tokenList.head; + pos += currentNode->length(), currentNode = currentNode->next) + { + if (rematch && pos >= rematch->reach) + { + break; + } + + if (tokenList.length > text.length()) + { + // Something went terribly wrong, ABORT, ABORT! + return; + } + + if (currentNode->isSyntax()) + { + continue; + } + + const auto& currentText = dynamic_cast(*currentNode); + std::string_view str = currentText.value(); + + auto removeCount = 1; // this is the to parameter of removeBetween + std::string_view match; + bool matchSuccess = false; + size_t matchIndex = pos; + + if (greedy) + { + match = pattern->match(matchSuccess, matchIndex, text); + if (!matchSuccess || matchIndex >= text.length()) + { + break; + } + + auto from = matchIndex; + auto to = matchIndex + match.length(); + auto p = pos; + + // find the node that contains the match + p += currentNode->length(); + while (from >= p) + { + currentNode = currentNode->next; + p += currentNode->length(); + } + // adjust pos (and p) + p -= currentNode->length(); + pos = p; + + // the current node is a Token, then the match starts inside another Token, which is invalid + if (currentNode->isSyntax()) + { + continue; + } + + // find the last node which is affected by this match + for (TokenListPtr k = currentNode; + k != tokenList.head && (p < to || !k->isSyntax()); + k = k->next) + { + removeCount++; + p += k->length(); + } + removeCount--; + + // replace with the new match + str = text.substr(pos, p - pos); + matchIndex -= pos; + } + else + { + matchIndex = 0; + match = pattern->match(matchSuccess, matchIndex, str); + if (!matchSuccess) + { + continue; + } + } + + auto from = matchIndex; + auto before = str.substr(0, from); + auto after = str.substr(from + match.length()); + + auto reach = pos + str.length(); + if (rematch && reach > rematch->reach) + { + rematch->reach = reach; + } + + TokenListPtr removeFrom = currentNode->prev; + + if (before.size()) + { + removeFrom = tokenList.addAfter(removeFrom, before); + pos += before.length(); + } + + tokenList.removeRange(removeFrom, removeCount); + + TokenList tokenEntries = [&]() { + if (inside) + { + return tokenize(match, inside); + } + else + { + return TokenList(match); + } + }(); + + currentNode = tokenList.addAfter(removeFrom, token.name(), + std::move(tokenEntries), + pattern->alias(), + match.size()); + + if (after.size()) + { + tokenList.addAfter(currentNode, after); + } + + if (removeCount > 1) + { + // at least one Token object was removed, so we have to do some rematching + // this can only happen if the current pattern is greedy + RematchOptions nestedRematch = { + .token = token.name(), + .reach = reach, + .j = x + }; + + matchGrammar(text, tokenList, grammar, currentNode->prev, pos, &nestedRematch); + + // the reach might have been extended because of the rematching + if (rematch && nestedRematch.reach > rematch->reach) + { + rematch->reach = nestedRematch.reach; + } + } + } + + ++x; + } + } +} diff --git a/third-party/libprisma/Sources/SyntaxHighlighter.h b/third-party/libprisma/Sources/SyntaxHighlighter.h new file mode 100644 index 0000000000..2510d4cd66 --- /dev/null +++ b/third-party/libprisma/Sources/SyntaxHighlighter.h @@ -0,0 +1,33 @@ +#pragma once +#include + +#include "TokenList.h" +#include +#include +#include + +class LanguageTree; +struct Grammar; + +struct RematchOptions +{ + std::string token; + size_t reach; + int j; +}; + +class SyntaxHighlighter +{ +public: + SyntaxHighlighter(const std::string& languages); + + TokenList tokenize(const std::string& text, const std::string& language); + + std::map languages() const; + +private: + TokenList tokenize(std::string_view text, const Grammar* grammar); + void matchGrammar(std::string_view text, TokenList& tokenList, const Grammar* grammar, TokenListPtr startNode, size_t startPos, RematchOptions* rematch); + + std::shared_ptr m_tree; +}; \ No newline at end of file diff --git a/third-party/libprisma/Sources/Syntaxer.mm b/third-party/libprisma/Sources/Syntaxer.mm new file mode 100644 index 0000000000..0e65479f2e --- /dev/null +++ b/third-party/libprisma/Sources/Syntaxer.mm @@ -0,0 +1,245 @@ +// +// SyntaxHighligher.m +// CodeSyntax +// +// Created by Mike Renoir on 26.10.2023. +// + +#import "Syntaxer.h" +#import "SyntaxHighlighter.h" +#import "TokenList.h" + +UIColor * color(UInt32 rgb, UInt32 alpha) { + return [UIColor colorWithRed:((rgb >> 16) & 0xff) / 255.0 green: ((rgb >> 8) & 0xff) / 255.0 blue: (rgb & 0xff) / 255.0 alpha: alpha]; +} + + + +NSDictionary *light = @{ + @"comment": color(0x708090, 1.0), + @"block-comment": color(0x708090, 1.0), + @"prolog": color(0x708090, 1.0), + @"doctype": color(0x708090, 1.0), + @"cdata": color(0x708090, 1.0), + @"punctuation": color(0x999999, 1.0), + @"property": color(0x990055, 1.0), + @"tag": color(0x990055, 1.0), + @"boolean": color(0x990055, 1.0), + @"number": color(0x990055, 1.0), + @"constant": color(0x990055, 1.0), + @"symbol": color(0x990055, 1.0), + @"deleted": color(0x990055, 1.0), + @"selector": color(0x669900, 1.0), + @"attr-name": color(0x669900, 1.0), + @"string": color(0x669900, 1.0), + @"char": color(0x669900, 1.0), + @"builtin": color(0x669900, 1.0), + @"inserted": color(0x669900, 1.0), + @"operator": color(0x9AAE6C, 1.0), + @"entity": color(0x9AAE6C, 1.0), + @"url": color(0x9AAE6C, 1.0), + @"atrule": color(0x0077AA, 1.0), + @"attr-value": color(0x0077AA, 1.0), + @"keyword": color(0x0077AA, 1.0), + @"function-definition": color(0x0077AA, 1.0), + @"class-name": color(0xDD4A68, 1.0), +}; + +NSDictionary *dark = @{ + @"comment": color(0x999999, 1.0), + @"block-comment": color(0x999999, 1.0), + @"prolog": color(0x999999, 1.0), + @"doctype": color(0x999999, 1.0), + @"cdata": color(0x999999, 1.0), + @"punctuation": color(0xcccccc, 1.0), + @"property": color(0xf8c555, 1.0), + @"tag": color(0xe2777a, 1.0), + @"boolean": color(0xf08d49, 1.0), + @"number": color(0xf08d49, 1.0), + @"constant": color(0xf8c555, 1.0), + @"symbol": color(0xf8c555, 1.0), + @"deleted": color(0xe2777a, 1.0), + @"selector": color(0xcc99cd, 1.0), + @"attr-name": color(0xe2777a, 1.0), + @"string": color(0x7ec699, 1.0), + @"char": color(0x7ec699, 1.0), + @"builtin": color(0xcc99cd, 1.0), + @"inserted": color(0x669900, 1.0), + @"operator": color(0x67cdcc, 1.0), + @"entity": color(0x67cdcc, 1.0), + @"url": color(0x67cdcc, 1.0), + @"atrule": color(0xcc99cd, 1.0), + @"attr-value": color(0x7ec699, 1.0), + @"keyword": color(0xcc99cd, 1.0), + @"function-definition": color(0xf08d49, 1.0), + @"class-name": color(0xf8c555, 1.0), +}; + + + +std::string dataToString(NSData *nsData) { + const void *dataBytes = [nsData bytes]; + NSUInteger dataLength = [nsData length]; + + return std::string(static_cast(dataBytes), dataLength); +} + +NSString* stringViewToNSString(std::string_view sv) { + std::string cppString(sv.data(), sv.length()); + return [NSString stringWithUTF8String:cppString.c_str()]; +} + +NSString* stringToNSString(const std::string& cppString) { + return [NSString stringWithUTF8String:cppString.c_str()]; +} + +@implementation SyntaxterTheme + +-(id)initWithDark:(BOOL)dark textColor:(UIColor *)textColor textFont:(UIFont *)textFont italicFont:(UIFont *)italicFont mediumFont:(UIFont *)mediumFont { + if (self = [super init]) { + _dark = dark; + _textColor = textColor; + _textFont = textFont; + _italicFont = italicFont; + _mediumFont = mediumFont; + } + return self; +} + +@end + + +@interface Brush : NSObject +@property (nonatomic, strong) UIFont *font; +@property (nonatomic, strong) UIColor *color; +@end + +@implementation Brush + +-(id)initWith:(UIFont *)font color:(UIColor *)color { + if (self = [super init]) { + _font = font; + _color = color; + } + return self; +} + +@end + + +void applyString(NSString * string, NSMutableAttributedString * attributed, Brush *brush) { + if (string != nil) { + NSMutableAttributedString *substring = [[NSMutableAttributedString alloc] initWithString: string]; + NSRange range = NSMakeRange(0, string.length); + [substring addAttribute:NSForegroundColorAttributeName value: brush.color range:range]; + [substring addAttribute:NSFontAttributeName value:brush.font range:range]; + [attributed appendAttributedString:substring]; + } +} + +Brush *makeBrush(std::string alias, std::string type, SyntaxterTheme * theme, Brush *previous) { + NSString * aliasKey = stringToNSString(alias); + NSString * typeKey = stringToNSString(type); + + + + NSDictionary *colors; + if (theme.dark) { + colors = dark; + } else { + colors = light; + } + + UIColor *color = colors[aliasKey]; + UIFont *font = theme.textFont; + + if (color == nil) { + color = colors[typeKey]; + } + if (color == nil) { + color = previous.color; + } + if (color == nil) { + color = theme.textColor; + } + if ([typeKey isEqualToString:@"bold"]) { + font = theme.mediumFont; + } + if ([typeKey isEqualToString:@"italic"]) { + font = theme.italicFont; + } + + if (previous != nil) { + font = previous.font; + } + + return [[Brush alloc] initWith:font color:color]; +} + +@interface Syntaxer () +@property (atomic) std::shared_ptr m_highlighter; +@end + +@implementation Syntaxer +-(id)init { + if (self = [super init]) { + NSString *path = [[[[NSBundle bundleForClass:[self class]] bundlePath] stringByAppendingPathComponent:@"LibprismaBundle.bundle"] stringByAppendingPathComponent:@"grammars.dat"]; + NSData *grammar = [NSData dataWithContentsOfFile:path]; + if (grammar == nil) { + return nil; + } + + std::string text = dataToString(grammar); + _m_highlighter = std::make_shared(text); + } + return self; +} + +-(NSAttributedString *)syntax:(NSString *)code language: (NSString *)language theme: (SyntaxterTheme *) theme { + NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init]; + std::string c_code = code.UTF8String; + std::string c_language = language.UTF8String; + + TokenList tokens = _m_highlighter->tokenize(c_code, c_language); + for (auto it = tokens.begin(); it != tokens.end(); ++it) + { + auto& node = *it; + Brush *brush; + if (node.isSyntax()) { + const auto& child = dynamic_cast(node); + brush = makeBrush(child.alias(), child.type(), theme, nil); + } else { + brush = makeBrush("", "", theme, nil); + } + [self paint:node string:string brush:brush theme: theme]; + } + return string; +} + + +- (void) paint:(const TokenListNode &)node string: (NSMutableAttributedString *) string brush:(Brush *)upperBrash theme: (SyntaxterTheme *) theme { + if (node.isSyntax()) + { + const auto& child = dynamic_cast(node); + + for (auto j = child.begin(); j != child.end(); ++j) + { + auto& innerNode = *j; + if (innerNode.isSyntax()) + { + const auto& innerChild = dynamic_cast(innerNode); + Brush *brush = makeBrush(innerChild.alias(), innerChild.type(), theme, upperBrash); + [self paint:innerNode string:string brush:brush theme: theme]; + } else { + const auto& innerChild = dynamic_cast(innerNode); + applyString(stringViewToNSString(innerChild.value()), string, upperBrash); + } + } + } else { + const auto& child = dynamic_cast(node); + applyString(stringViewToNSString(child.value()), string, upperBrash); + } +} + + +@end diff --git a/third-party/libprisma/Sources/TokenList.cpp b/third-party/libprisma/Sources/TokenList.cpp new file mode 100644 index 0000000000..b8832dc295 --- /dev/null +++ b/third-party/libprisma/Sources/TokenList.cpp @@ -0,0 +1,71 @@ +#include "TokenList.h" + +TokenList::TokenList(std::string_view value) + : head(new TokenListNode()) + , length(1) +{ + const TokenListPtr newNode = new Text(head, head, value); + head->next = newNode; +} + +TokenList::~TokenList() +{ + TokenListPtr next = head->next; + while (head != next) + { + TokenListPtr current = next; + next = next->next; + delete current; + } + + delete head; +} + +TokenListPtr TokenList::addAfter(TokenListPtr node, const std::string& type, TokenList&& children, const std::string& alias, size_t textLength) +{ + const TokenListPtr next = node->next; + const TokenListPtr newNode = new Syntax(node, next, type, std::move(children), alias, textLength); + + node->next = newNode; + next->prev = newNode; + length++; + + return newNode; +} + +TokenListPtr TokenList::addAfter(TokenListPtr node, std::string_view value) +{ + const TokenListPtr next = node->next; + const TokenListPtr newNode = new Text(node, next, value); + + node->next = newNode; + next->prev = newNode; + length++; + + return newNode; +} + +void TokenList::removeRange(TokenListPtr node, size_t count) +{ + TokenListPtr item = node->next; + + for (size_t i = 0; i < count && item != nullptr; i++) + { + node->next = item->next; + node->next->prev = node; + delete item; + + item = node->next; + length--; + } +} + +Syntax::Syntax(TokenListPtr prev, TokenListPtr next, const std::string& type, TokenList&& children, const std::string& alias, size_t length) + : TokenListNode(prev, next) + , m_type(type) + , m_children(std::move(children)) + , m_alias(alias) + , m_length(length) +{ + +} diff --git a/third-party/libprisma/Sources/TokenList.h b/third-party/libprisma/Sources/TokenList.h new file mode 100644 index 0000000000..11e768bfe2 --- /dev/null +++ b/third-party/libprisma/Sources/TokenList.h @@ -0,0 +1,170 @@ +#pragma once + +#include +#include + +struct TokenListNode +{ + TokenListNode(TokenListNode* prev, TokenListNode* next) + : prev(prev) + , next(next) + { + } + + TokenListNode() + : prev(nullptr) + , next(nullptr) + { + } + + virtual ~TokenListNode() = default; + + TokenListNode(const TokenListNode&) = delete; + TokenListNode& operator=(const TokenListNode&) = delete; + + virtual size_t length() const + { + return 0; + } + + virtual bool isSyntax() const + { + return true; + } + + TokenListNode* prev; + TokenListNode* next; +}; + +typedef TokenListNode* TokenListPtr; + +class TokenList +{ +public: + TokenList(std::string_view text); + ~TokenList(); + + TokenList(const TokenList&) = delete; + TokenList& operator=(const TokenList&) = delete; + TokenList(TokenList&& old) noexcept + { + head = old.head; + length = old.length; + + old.head = new TokenListNode(); + old.head->next = old.head; + old.length = 0; + } + + struct ConstIterator + { + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = const TokenListNode; + using pointer = const TokenListNode*; + using reference = const TokenListNode&; + + ConstIterator(pointer ptr) : m_ptr(ptr) {} + + reference operator*() const { return *m_ptr; } + pointer operator->() { return m_ptr; } + ConstIterator& operator++() { m_ptr = m_ptr->next; return *this; } + friend bool operator== (const ConstIterator& a, const ConstIterator& b) { return a.m_ptr == b.m_ptr; }; + friend bool operator!= (const ConstIterator& a, const ConstIterator& b) { return a.m_ptr != b.m_ptr; }; + + private: + pointer m_ptr; + }; + + ConstIterator begin() const { return ConstIterator(head->next); } + ConstIterator end() const { return ConstIterator(head); } + + TokenListPtr addAfter(TokenListPtr node, const std::string& type, TokenList&& children, const std::string& alias, size_t length); + TokenListPtr addAfter(TokenListPtr node, std::string_view value); + void removeRange(TokenListPtr node, size_t count); + + TokenListPtr head; + size_t length; +}; + +class Text : public TokenListNode +{ +public: + Text(TokenListPtr prev, TokenListPtr next, std::string_view value) + : TokenListNode(prev, next) + , m_value(value) + { + + } + + Text(const Text&) = delete; + Text& operator=(const Text&) = delete; + + const std::string_view& value() const + { + return m_value; + } + + size_t length() const + { + return m_value.size(); + } + + bool isSyntax() const + { + return false; + } + +private: + const std::string_view m_value; +}; + +class Syntax : public TokenListNode +{ +public: + Syntax(TokenListPtr prev, TokenListPtr next, const std::string& type, TokenList&& children, const std::string& alias, size_t length); + + Syntax(const Syntax&) = delete; + Syntax& operator=(const Syntax&) = delete; + + size_t length() const + { + return m_length; + } + + bool isSyntax() const + { + return true; + } + + const std::string &type() const + { + return m_type; + } + + TokenList::ConstIterator begin() const + { + return m_children.begin(); + } + + TokenList::ConstIterator end() const + { + return m_children.end(); + } + + const std::string &alias() const + { + return m_alias; + } + + const TokenList &children() const + { + return m_children; + } + +public: + std::string m_type; + TokenList m_children; + std::string m_alias; + size_t m_length; +}; diff --git a/third-party/libprisma/include/libprisma/Syntaxer.h b/third-party/libprisma/include/libprisma/Syntaxer.h new file mode 100644 index 0000000000..82017e748c --- /dev/null +++ b/third-party/libprisma/include/libprisma/Syntaxer.h @@ -0,0 +1,27 @@ +// +// SyntaxHighligher.h +// CodeSyntax +// +// Created by Mike Renoir on 26.10.2023. +// + +#import +#import + +@interface SyntaxterTheme : NSObject +@property (nonatomic, assign) BOOL dark; +@property (nonatomic, strong) UIColor *textColor; +@property (nonatomic, strong) UIFont *textFont; +@property (nonatomic, strong) UIFont *italicFont; +@property (nonatomic, strong) UIFont *mediumFont; +-(id)initWithDark:(BOOL)dark textColor:(UIColor *)textColor textFont:(UIFont *)textFont italicFont:(UIFont *)italicFont mediumFont:(UIFont *) mediumFont; +@end + +@interface Syntaxer : NSObject +-(id)init; +-(NSAttributedString *)syntax:(NSString *)code language: (NSString *)language theme:(SyntaxterTheme *) theme; + + + +@end +