regex-pcre2-1.0.0.0/0000755000000000000000000000000007346545000012162 5ustar0000000000000000regex-pcre2-1.0.0.0/ChangeLog.md0000644000000000000000000000111507346545000014331 0ustar0000000000000000See also http://pvp.haskell.org/faq ## 1.0.0.0 - Migrate from the obsolete pcre3 library to the new (confusingly-named) pcre2 one ## 0.95.0.0 revision 6 - Allow `containers-0.7` ## 0.95.0.0 revision 5 - Allow `bytestring-0.12` ## 0.95.0.0 revision 4 - Compatibility with `base >= 4.17` (GHC 9.4) ## 0.95.0.0 revision 3 - Compatibility with `base-4.16` (GHC 9.2) ## 0.95.0.0 revision 2 - Compatibility with `base-4.15` (GHC 9.0) and `bytestring-0.11` ## 0.95.0.0 - Update to `regex-0.94.0.0` API - Compatibility with `base-4.13.0` - Use `pkg-config` for locating `pcre` ---- regex-pcre2-1.0.0.0/LICENSE0000644000000000000000000000270207346545000013170 0ustar0000000000000000Copyright (c) 2025, Homebrew Holdings Copyright (c) 2007, Christopher Kuklewicz Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. regex-pcre2-1.0.0.0/Setup.hs0000644000000000000000000000005607346545000013617 0ustar0000000000000000import Distribution.Simple main = defaultMain regex-pcre2-1.0.0.0/regex-pcre2.cabal0000644000000000000000000000505007346545000015271 0ustar0000000000000000Cabal-Version: 1.12 Name: regex-pcre2 Version: 1.0.0.0 build-type: Simple license: BSD3 license-file: LICENSE copyright: Copyright (c) 2025, Homebrew Holdings Copyright (c) 2006, Christopher Kuklewicz author: Pete Ryland, based on regex-pcre by Christopher Kuklewicz maintainer: Pete Ryland homepage: https://dev.piglet.ch/pdr/regex-pcre2 bug-reports: https://dev.piglet.ch/pdr/regex-pcre2/-/issues category: Text synopsis: PCRE2 Backend for "Text.Regex" (regex-base) description: This package provides a backend for the API. extra-source-files: ChangeLog.md tested-with: GHC == 9.6.6 flag pkg-config default: True manual: True description: Use @pkg-config(1)@ to locate foreign @pcre2@ library. source-repository head type: git location: https://dev.piglet.ch/pdr/regex-pcre2 source-repository this type: git location: https://dev.piglet.ch/pdr/regex-pcre2 tag: v1.0.0.0 library hs-source-dirs: src exposed-modules: Text.Regex.PCRE2 Text.Regex.PCRE2.Wrap Text.Regex.PCRE2.String Text.Regex.PCRE2.Sequence Text.Regex.PCRE2.ByteString Text.Regex.PCRE2.ByteString.Lazy other-modules: Paths_regex_pcre2 default-language: Haskell2010 default-extensions: MultiParamTypeClasses FunctionalDependencies ForeignFunctionInterface ScopedTypeVariables GeneralizedNewtypeDeriving FlexibleContexts TypeSynonymInstances FlexibleInstances build-depends: regex-base == 0.94.* , base >= 4.3 && < 5 , containers >= 0.4 && < 0.8 , bytestring >= 0.9 && < 0.13 , array >= 0.3 && < 0.6 if !impl(ghc >= 8) build-depends: fail == 4.9.* if flag(pkg-config) pkgconfig-depends: libpcre2-8 else extra-libraries: pcre2-8 ghc-options: -O2 -Wall test-suite regex-pcre2-test default-language: Haskell2010 ghc-options: -Wall type: exitcode-stdio-1.0 hs-source-dirs: test main-is: Main.hs build-depends: base >= 4.3 && < 5 , bytestring >= 0.9 && < 0.13 , HUnit >= 1.6 && < 1.7 , regex-pcre2 , utf8-string >= 1.0 && < 1.1 if flag(pkg-config) pkgconfig-depends: libpcre2-8 else extra-libraries: pcre2-8 regex-pcre2-1.0.0.0/src/Text/Regex/0000755000000000000000000000000007346545000014747 5ustar0000000000000000regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2.hs0000644000000000000000000000442307346545000016121 0ustar0000000000000000{-| The "Text.Regex.PCRE2" module provides a backend for regular expressions. If you import this along with other backends, then you should do so with qualified imports, perhaps renamed for convenience. This library uses the newer libpcre2, which supports UTF8-encoded strings by default. The regular expression can be provided as a 'ByteString'. The regular expression and search string are passed as 'CStringLen's and may contain NUL bytes and do not need to end in a NUL byte. 'ByteString's are searched in place (via unsafeUseAsCStringLen). A 'String' will be converted into a 'CStringLen' for processing. Doing this repeatedly will be very inefficient. The "Text.Regex.PCRE2.String", "Text.Regex.PCRE2.ByteString", and "Text.Regex.PCRE2.Wrap" modules provide both the high-level interface exported by this module and medium- and low-level interfaces that return errors using 'Either' structures. -} {- Copyright: (c) 2025 Homebrew Holdings -} {- Copyright: (c) 2007 Chris Kuklewicz -} module Text.Regex.PCRE2(getVersion_Text_Regex_PCRE2 ,module Text.Regex.Base -- ** Wrap, for '=~' and '=~~', types and constants ,module Text.Regex.PCRE2.Wrap) where import Prelude hiding (fail) import Text.Regex.PCRE2.Wrap( Regex, CompOption(CompOption), MatchOption(MatchOption), (=~), (=~~), unusedOffset, getNumSubs, getVersion, compBlank, compAnchored, compEndAnchored, compAllowEmptyClass, compAltBSUX, compAltExtendedClass, compAltVerbnames, compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, compExtended, compExtendedMore, compFirstLine, compLiteral, compMatchUnsetBackref, compMultiline, compNeverBackslashC, compNoAutoCapture, compNoAutoPossess, compNoDotstarAnchor, compNoUTFCheck, compUngreedy, compUTF, matchBlank, matchAnchored, matchCopyMatchedSubject, matchDisableRecurseLoopCheck, matchEndAnchored, matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, matchNoUTFCheck, matchPartialHard, matchPartialSoft) import Text.Regex.PCRE2.String() import Text.Regex.PCRE2.Sequence() import Text.Regex.PCRE2.ByteString() import Text.Regex.PCRE2.ByteString.Lazy() import Data.Version(Version(..)) import Text.Regex.Base import qualified Paths_regex_pcre2 getVersion_Text_Regex_PCRE2 :: Version getVersion_Text_Regex_PCRE2 = Paths_regex_pcre2.version regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/0000755000000000000000000000000007346545000015562 5ustar0000000000000000regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/ByteString.hs0000644000000000000000000001371007346545000020212 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} {-| This exports instances of the high-level API and the medium-level API of 'compile', 'execute', and 'regexec'. -} {- Copyright: (c) 2025 Homebrew Holdings -} {- Copyright: (c) 2007 Chris Kuklewicz -} module Text.Regex.PCRE2.ByteString( -- ** Types Regex, MatchOffset, MatchLength, CompOption(CompOption), MatchOption(MatchOption), ReturnCode, WrapError, -- ** Miscellaneous unusedOffset, getVersion, -- ** Medium level API functions compile, execute, regexec, -- ** CompOption flags compBlank, compAnchored, compEndAnchored, -- new in v1.0.0.0 (pcre2) compAllowEmptyClass, -- new in v1.0.0.0 (pcre2) compAltBSUX, -- new in v1.0.0.0 (pcre2) compAltExtendedClass, -- new in v1.0.0.0 (pcre2) compAltVerbnames, -- new in v1.0.0.0 (pcre2) compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, -- new in v1.0.0.0 (pcre2) compExtended, compExtendedMore, -- new in v1.0.0.0 (pcre2) -- compExtra, -- obsoleted in v1.0.0.0, pcre2 is always strict in this way compFirstLine, compLiteral, -- new in v1.0.0.0 (pcre2) compMatchUnsetBackref, -- new in v1.0.0.0 (pcre2) compMultiline, compNeverBackslashC, -- new in v1.0.0.0 (pcre2) compNoAutoCapture, compNoAutoPossess, -- new in v1.0.0.0 (pcre2) compNoDotstarAnchor, -- new in v1.0.0.0 (pcre2) -- compNoUTF8Check, -- obsoleted in v1.0.0.0 (pcre2), use compNoUTFCheck compNoUTFCheck, compUngreedy, -- compUTF8, -- obsoleted in v1.0.0.0 (pcre2), use compUTF compUTF, -- ** MatchOption flags, new to v1.0.0.0 (pcre2), replacing the obsolete ExecOptions matchBlank, matchAnchored, matchCopyMatchedSubject, -- new in v1.0.0.0 (pcre2) matchDisableRecurseLoopCheck, -- new in v1.0.0.0 (pcre2) matchEndAnchored, -- new in v1.0.0.0 (pcre2) matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, -- new in v1.0.0.0 (pcre2) matchNoUTFCheck, matchPartialHard, matchPartialSoft ) where import Prelude hiding (fail) import Control.Monad.Fail (MonadFail(fail)) import Text.Regex.PCRE2.Wrap -- all import Data.Array(Array,listArray) import Data.ByteString(ByteString) import qualified Data.ByteString as B(empty,take,drop,pack) import qualified Data.ByteString.Unsafe as B(unsafeUseAsCStringLen) import System.IO.Unsafe(unsafePerformIO) import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength) import Text.Regex.Base.Impl(polymatch,polymatchM) import Foreign.C.String(CStringLen) import Foreign(nullPtr) instance RegexContext Regex ByteString ByteString where match = polymatch matchM = polymatchM unwrap :: (Show e) => Either e v -> IO v unwrap x = case x of Left err -> fail ("Text.Regex.PCRE2.ByteString died: "++ show err) Right v -> return v {-# INLINE asCStringLen #-} asCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a asCStringLen s op = B.unsafeUseAsCStringLen s checked where checked cs@(ptr,_) | ptr == nullPtr = B.unsafeUseAsCStringLen myEmpty (op . trim) | otherwise = op cs myEmpty = B.pack [0] trim (ptr,_) = (ptr,0) instance RegexMaker Regex CompOption MatchOption ByteString where makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern instance RegexLike Regex ByteString where matchTest regex bs = unsafePerformIO $ asCStringLen bs (wrapTest 0 regex) >>= unwrap matchOnce regex bs = unsafePerformIO $ execute regex bs >>= unwrap matchAll regex bs = unsafePerformIO $ asCStringLen bs (wrapMatchAll regex) >>= unwrap matchCount regex bs = unsafePerformIO $ asCStringLen bs (wrapCount regex) >>= unwrap -- --------------------------------------------------------------------- -- | Compiles a regular expression -- compile :: CompOption -- ^ (summed together) -> MatchOption -- ^ (summed together) -> ByteString -- ^ The regular expression to compile -> IO (Either (MatchOffset,String) Regex) -- ^ Returns: the compiled regular expression compile c e pattern = B.unsafeUseAsCStringLen pattern (wrapCompile c e) -- --------------------------------------------------------------------- -- | Matches a regular expression against a buffer, returning the buffer -- indicies of the match, and any submatches -- -- | Matches a regular expression against a string execute :: Regex -- ^ Compiled regular expression -> ByteString -- ^ String to match against -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength)))) -- ^ Returns: 'Nothing' if the regex did not match the -- string, or: -- 'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions. execute regex bs = do maybeStartEnd <- asCStringLen bs (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) Right (Just parts) -> return . Right . Just . listArray (0,pred (length parts)) . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts Left err -> return (Left err) regexec :: Regex -- ^ Compiled regular expression -> ByteString -- ^ String to match against -> IO (Either WrapError (Maybe (ByteString, ByteString, ByteString, [ByteString]))) regexec regex bs = do let getSub (start,stop) | start == unusedOffset = B.empty | otherwise = B.take (stop-start) . B.drop start $ bs matchedParts [] = (B.empty,B.empty,bs,[]) -- no information matchedParts (matchedStartStop@(start,stop):subStartStop) = (B.take start bs ,getSub matchedStartStop ,B.drop stop bs ,map getSub subStartStop) maybeStartEnd <- asCStringLen bs (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) Right (Just parts) -> return . Right . Just . matchedParts $ parts Left err -> return (Left err) regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/ByteString/0000755000000000000000000000000007346545000017654 5ustar0000000000000000regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/ByteString/Lazy.hs0000644000000000000000000001321007346545000021124 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} {-| This exports instances of the high-level API and the medium-level API of 'compile', 'execute', and 'regexec'. -} {- Copyright: (c) 2025 Homebrew Holdings -} {- Copyright: (c) 2007 Chris Kuklewicz -} module Text.Regex.PCRE2.ByteString.Lazy( -- ** Types Regex, MatchOffset, MatchLength, CompOption(CompOption), MatchOption(MatchOption), ReturnCode, WrapError, -- ** Miscellaneous unusedOffset, getVersion, -- ** Medium level API functions compile, execute, regexec, -- ** CompOption flags compBlank, compAnchored, compEndAnchored, -- new in v1.0.0.0 (pcre2) compAllowEmptyClass, -- new in v1.0.0.0 (pcre2) compAltBSUX, -- new in v1.0.0.0 (pcre2) compAltExtendedClass, -- new in v1.0.0.0 (pcre2) compAltVerbnames, -- new in v1.0.0.0 (pcre2) compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, -- new in v1.0.0.0 (pcre2) compExtended, compExtendedMore, -- new in v1.0.0.0 (pcre2) -- compExtra, -- obsoleted in v1.0.0.0, pcre2 is always strict in this way compFirstLine, compLiteral, -- new in v1.0.0.0 (pcre2) compMatchUnsetBackref, -- new in v1.0.0.0 (pcre2) compMultiline, compNeverBackslashC, -- new in v1.0.0.0 (pcre2) compNoAutoCapture, compNoAutoPossess, -- new in v1.0.0.0 (pcre2) compNoDotstarAnchor, -- new in v1.0.0.0 (pcre2) -- compNoUTF8Check, -- obsoleted in v1.0.0.0 (pcre2), use compNoUTFCheck compNoUTFCheck, compUngreedy, -- compUTF8, -- obsoleted in v1.0.0.0 (pcre2), use compUTF compUTF, -- ** MatchOption flags, new to v1.0.0.0 (pcre2), replacing the obsolete ExecOptions matchBlank, matchAnchored, matchCopyMatchedSubject, -- new in v1.0.0.0 (pcre2) matchDisableRecurseLoopCheck, -- new in v1.0.0.0 (pcre2) matchEndAnchored, -- new in v1.0.0.0 (pcre2) matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, -- new in v1.0.0.0 (pcre2) matchNoUTFCheck, matchPartialHard, matchPartialSoft ) where import Prelude hiding (fail) import Control.Monad.Fail (MonadFail(fail)) import Text.Regex.PCRE2.Wrap -- all import Data.Array(Array) import qualified Data.ByteString.Lazy as L(ByteString,toChunks,fromChunks) import qualified Data.ByteString as B(ByteString,concat,pack) import qualified Data.ByteString.Unsafe as B(unsafeUseAsCStringLen) import System.IO.Unsafe(unsafePerformIO) import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength) import Text.Regex.Base.Impl(polymatch,polymatchM) import qualified Text.Regex.PCRE2.ByteString as BS(execute,regexec) import Foreign.C.String(CStringLen) import Foreign(nullPtr) instance RegexContext Regex L.ByteString L.ByteString where match = polymatch matchM = polymatchM {-# INLINE fromLazy #-} fromLazy :: L.ByteString -> B.ByteString fromLazy = B.concat . L.toChunks {-# INLINE toLazy #-} toLazy :: B.ByteString -> L.ByteString toLazy = L.fromChunks . return unwrap :: (Show e) => Either e v -> IO v unwrap x = case x of Left err -> fail ("Text.Regex.PCRE2.ByteString.Lazy died: "++ show err) Right v -> return v {-# INLINE asCStringLen #-} asCStringLen :: L.ByteString -> (CStringLen -> IO a) -> IO a asCStringLen ls op = B.unsafeUseAsCStringLen (fromLazy ls) checked where checked cs@(ptr,_) | ptr == nullPtr = B.unsafeUseAsCStringLen myEmpty (op . trim) | otherwise = op cs myEmpty = B.pack [0] trim (ptr,_) = (ptr,0) instance RegexMaker Regex CompOption MatchOption L.ByteString where makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern instance RegexLike Regex L.ByteString where matchTest regex bs = unsafePerformIO $ asCStringLen bs (wrapTest 0 regex) >>= unwrap matchOnce regex bs = unsafePerformIO $ execute regex bs >>= unwrap matchAll regex bs = unsafePerformIO $ asCStringLen bs (wrapMatchAll regex) >>= unwrap matchCount regex bs = unsafePerformIO $ asCStringLen bs (wrapCount regex) >>= unwrap -- --------------------------------------------------------------------- -- | Compiles a regular expression -- compile :: CompOption -- ^ (summed together) -> MatchOption -- ^ (summed together) -> L.ByteString -- ^ The regular expression to compile -> IO (Either (MatchOffset,String) Regex) -- ^ Returns: the compiled regular expression compile c e pattern = B.unsafeUseAsCStringLen (fromLazy pattern) (wrapCompile c e) -- --------------------------------------------------------------------- -- | Matches a regular expression against a buffer, returning the buffer -- indicies of the match, and any submatches -- -- | Matches a regular expression against a string execute :: Regex -- ^ Compiled regular expression -> L.ByteString -- ^ String to match against -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength)))) -- ^ Returns: 'Nothing' if the regex did not match the -- string, or: -- 'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions. execute regex bs = BS.execute regex (fromLazy bs) regexec :: Regex -- ^ Compiled regular expression -> L.ByteString -- ^ String to match against -> IO (Either WrapError (Maybe (L.ByteString, L.ByteString, L.ByteString, [L.ByteString]))) regexec regex bs = do x <- BS.regexec regex (fromLazy bs) return $ case x of Left e -> Left e Right Nothing -> Right Nothing Right (Just (a,b,c,ds)) -> Right (Just (toLazy a,toLazy b,toLazy c,map toLazy ds)) regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/Sequence.hs0000644000000000000000000001417207346545000017673 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} {-| This exports instances of the high-level API and the medium-level API of 'compile', 'execute', and 'regexec'. -} {- Copyright: (c) 2025 Homebrew Holdings -} {- Copyright: (c) 2007 Chris Kuklewicz -} module Text.Regex.PCRE2.Sequence( -- ** Types Regex, MatchOffset, MatchLength, CompOption(CompOption), MatchOption(MatchOption), ReturnCode, WrapError, -- ** Miscellaneous unusedOffset, getVersion, -- ** Medium level API functions compile, execute, regexec, -- ** CompOption flags compBlank, compAnchored, compEndAnchored, -- new in v1.0.0.0 (pcre2) compAllowEmptyClass, -- new in v1.0.0.0 (pcre2) compAltBSUX, -- new in v1.0.0.0 (pcre2) compAltExtendedClass, -- new in v1.0.0.0 (pcre2) compAltVerbnames, -- new in v1.0.0.0 (pcre2) compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, -- new in v1.0.0.0 (pcre2) compExtended, compExtendedMore, -- new in v1.0.0.0 (pcre2) -- compExtra, -- obsoleted in v1.0.0.0, pcre2 is always strict in this way compFirstLine, compLiteral, -- new in v1.0.0.0 (pcre2) compMatchUnsetBackref, -- new in v1.0.0.0 (pcre2) compMultiline, compNeverBackslashC, -- new in v1.0.0.0 (pcre2) compNoAutoCapture, compNoAutoPossess, -- new in v1.0.0.0 (pcre2) compNoDotstarAnchor, -- new in v1.0.0.0 (pcre2) -- compNoUTF8Check, -- obsoleted in v1.0.0.0 (pcre2), use compNoUTFCheck compNoUTFCheck, compUngreedy, -- compUTF8, -- obsoleted in v1.0.0.0 (pcre2), use compUTF compUTF, -- ** MatchOption flags, new to v1.0.0.0 (pcre2), replacing the obsolete ExecOptions matchBlank, matchAnchored, matchCopyMatchedSubject, -- new in v1.0.0.0 (pcre2) matchDisableRecurseLoopCheck, -- new in v1.0.0.0 (pcre2) matchEndAnchored, -- new in v1.0.0.0 (pcre2) matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, -- new in v1.0.0.0 (pcre2) matchNoUTFCheck, matchPartialHard, matchPartialSoft ) where import Prelude hiding (fail) import Control.Monad.Fail (MonadFail(fail)) import Text.Regex.PCRE2.Wrap -- all --import Foreign.C.String(withCStringLen,withCString) import Data.Array(Array,listArray) import System.IO.Unsafe(unsafePerformIO) import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchLength,MatchOffset,Extract(..)) import Text.Regex.Base.Impl(polymatch,polymatchM) import Data.Sequence as S hiding (length) import qualified Data.Sequence as S (length) import Foreign.C.String import Foreign.Marshal.Array import Foreign.Marshal.Alloc import Foreign.Storable instance RegexContext Regex (Seq Char) (Seq Char) where match = polymatch matchM = polymatchM unwrap :: (Show e) => Either e v -> IO v unwrap x = case x of Left err -> fail ("Text.Regex.PCRE2.Sequence died: "++ show err) Right v -> return v instance RegexMaker Regex CompOption MatchOption (Seq Char) where makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern instance RegexLike Regex (Seq Char) where matchTest regex str = unsafePerformIO $ withSeq str (wrapTest 0 regex) >>= unwrap matchOnce regex str = unsafePerformIO $ execute regex str >>= unwrap matchAll regex str = unsafePerformIO $ withSeq str (wrapMatchAll regex) >>= unwrap matchCount regex str = unsafePerformIO $ withSeq str (wrapCount regex) >>= unwrap -- | Compiles a regular expression compile :: CompOption -- ^ Flags (summed together) -> MatchOption -- ^ Flags (summed together) -> (Seq Char) -- ^ The regular expression to compile -> IO (Either (MatchOffset,String) Regex) -- ^ Returns: an error string and offset or the compiled regular expression compile c e pattern = withSeq pattern (wrapCompile c e) -- | Matches a regular expression against a string execute :: Regex -- ^ Compiled regular expression -> (Seq Char) -- ^ (Seq Char) to match against -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength)))) -- ^ Returns: 'Nothing' if the regex did not match the -- string, or: -- 'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions. execute regex str = do maybeStartEnd <- withSeq str (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) -- Right (Just []) -> fail "got [] back!" -- should never happen Right (Just parts) -> return . Right . Just . listArray (0,pred (length parts)) . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts Left err -> return (Left err) -- | execute match and extract substrings rather than just offsets regexec :: Regex -- ^ compiled regular expression -> (Seq Char) -- ^ string to match -> IO (Either WrapError (Maybe ((Seq Char), (Seq Char),(Seq Char), [(Seq Char)]))) -- ^ Returns: Nothing if no match, else -- (text before match, text after match, array of matches with 0 being the whole match) regexec regex str = do let getSub (start,stop) | start == unusedOffset = S.empty | otherwise = extract (start,stop-start) str matchedParts [] = (S.empty,S.empty,str,[]) -- no information matchedParts (matchedStartStop@(start,stop):subStartStop) = (before start str ,getSub matchedStartStop ,after stop str ,map getSub subStartStop) maybeStartEnd <- withSeq str (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) -- Right (Just []) -> fail "got [] back!" -- should never happen Right (Just parts) -> return . Right . Just . matchedParts $ parts Left err -> return (Left err) withSeq :: Seq Char -> (CStringLen -> IO a) -> IO a withSeq s f = let len = S.length s pokes p a | seq p (seq a False) = undefined | otherwise = case viewl a of EmptyL -> return () c :< a' -> poke p (castCharToCChar c) >> pokes (advancePtr p 1) a' in allocaBytes (S.length s) (\ptr -> pokes ptr s >> f (ptr,len)) regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/String.hs0000644000000000000000000001302707346545000017367 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-orphans #-} {-| This exports instances of the high-level API and the medium-level API of 'compile', 'execute', and 'regexec'. -} {- Copyright: (c) 2025 Homebrew Holdings -} {- Copyright: (c) 2007 Chris Kuklewicz -} module Text.Regex.PCRE2.String( -- ** Types Regex, MatchOffset, MatchLength, CompOption(CompOption), MatchOption(MatchOption), ReturnCode, WrapError, -- ** Miscellaneous unusedOffset, getVersion, -- ** Medium level API functions compile, execute, regexec, -- ** CompOption flags compBlank, compAnchored, compEndAnchored, -- new in v1.0.0.0 (pcre2) compAllowEmptyClass, -- new in v1.0.0.0 (pcre2) compAltBSUX, -- new in v1.0.0.0 (pcre2) compAltExtendedClass, -- new in v1.0.0.0 (pcre2) compAltVerbnames, -- new in v1.0.0.0 (pcre2) compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, -- new in v1.0.0.0 (pcre2) compExtended, compExtendedMore, -- new in v1.0.0.0 (pcre2) -- compExtra, -- obsoleted in v1.0.0.0, pcre2 is always strict in this way compFirstLine, compLiteral, -- new in v1.0.0.0 (pcre2) compMatchUnsetBackref, -- new in v1.0.0.0 (pcre2) compMultiline, compNeverBackslashC, -- new in v1.0.0.0 (pcre2) compNoAutoCapture, compNoAutoPossess, -- new in v1.0.0.0 (pcre2) compNoDotstarAnchor, -- new in v1.0.0.0 (pcre2) -- compNoUTF8Check, -- obsoleted in v1.0.0.0 (pcre2), use compNoUTFCheck compNoUTFCheck, compUngreedy, -- compUTF8, -- obsoleted in v1.0.0.0 (pcre2), use compUTF compUTF, -- ** MatchOption flags, new to v1.0.0.0 (pcre2), replacing the obsolete ExecOptions matchBlank, matchAnchored, matchCopyMatchedSubject, -- new in v1.0.0.0 (pcre2) matchDisableRecurseLoopCheck, -- new in v1.0.0.0 (pcre2) matchEndAnchored, -- new in v1.0.0.0 (pcre2) matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, -- new in v1.0.0.0 (pcre2) matchNoUTFCheck, matchPartialHard, matchPartialSoft ) where import Prelude hiding (fail) import Control.Monad.Fail (MonadFail(fail)) import Text.Regex.PCRE2.Wrap -- all import Foreign.C.String(withCStringLen) import Data.Array(Array,listArray) import System.IO.Unsafe(unsafePerformIO) import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchLength,MatchOffset) import Text.Regex.Base.Impl(polymatch,polymatchM) instance RegexContext Regex String String where match = polymatch matchM = polymatchM unwrap :: (Show e) => Either e v -> IO v unwrap x = case x of Left err -> fail ("Text.Regex.PCRE2.String died: "++ show err) Right v -> return v instance RegexMaker Regex CompOption MatchOption String where makeRegexOpts c e pattern = unsafePerformIO $ compile c e pattern >>= unwrap makeRegexOptsM c e pattern = either (fail.show) return $ unsafePerformIO $ compile c e pattern instance RegexLike Regex String where matchTest regex str = unsafePerformIO $ withCStringLen str (wrapTest 0 regex) >>= unwrap matchOnce regex str = unsafePerformIO $ execute regex str >>= unwrap matchAll regex str = unsafePerformIO $ withCStringLen str (wrapMatchAll regex) >>= unwrap matchCount regex str = unsafePerformIO $ withCStringLen str (wrapCount regex) >>= unwrap -- | Compiles a regular expression compile :: CompOption -- ^ Flags (summed together) -> MatchOption -- ^ Flags (summed together) -> String -- ^ The regular expression to compile -> IO (Either (MatchOffset,String) Regex) -- ^ Returns: an error string and offset or the compiled regular expression compile c e pattern = withCStringLen pattern (wrapCompile c e) -- | Matches a regular expression against a string execute :: Regex -- ^ Compiled regular expression -> String -- ^ String to match against -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength)))) -- ^ Returns: 'Nothing' if the regex did not match the -- string, or: -- 'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions. execute regex str = do maybeStartEnd <- withCStringLen str (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) -- Right (Just []) -> fail "got [] back!" -- should never happen Right (Just parts) -> return . Right . Just . listArray (0,pred (length parts)) . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts Left err -> return (Left err) -- | execute match and extract substrings rather than just offsets regexec :: Regex -- ^ compiled regular expression -> String -- ^ string to match -> IO (Either WrapError (Maybe (String, String,String, [String]))) -- ^ Returns: Nothing if no match, else -- (text before match, text after match, array of matches with 0 being the whole match) regexec regex str = do let getSub (start,stop) | start == unusedOffset = "" | otherwise = take (stop-start) . drop start $ str matchedParts [] = ("","",str,[]) -- no information matchedParts (matchedStartStop@(start,stop):subStartStop) = (take start str ,getSub matchedStartStop ,drop stop str ,map getSub subStartStop) maybeStartEnd <- withCStringLen str (wrapMatch 0 regex) case maybeStartEnd of Right Nothing -> return (Right Nothing) -- Right (Just []) -> fail "got [] back!" -- should never happen Right (Just parts) -> return . Right . Just . matchedParts $ parts Left err -> return (Left err) regex-pcre2-1.0.0.0/src/Text/Regex/PCRE2/Wrap.hsc0000644000000000000000000004034307346545000017176 0ustar0000000000000000-- The exported symbols are the same whether HAVE_PCRE2_H is defined, -- but when if it is not defined then 'getVersion == Nothing' and all -- other exported values will call error or fail. -- | This will fail or error only if allocation fails or a nullPtr is passed in. -- TODO :: Consider wrapMatchAll using list of start/end offsets and not MatchArray -- {- Copyright : (c) Chris Kuklewicz 2007 -} module Text.Regex.PCRE2.Wrap( -- ** High-level interface Regex, CompOption(CompOption), MatchOption(MatchOption), (=~), (=~~), -- ** Low-level interface StartOffset, EndOffset, ReturnCode(ReturnCode), WrapError, wrapCompile, wrapTest, wrapMatch, wrapMatchAll, wrapCount, -- ** Miscellaneous getVersion, getNumSubs, unusedOffset, -- ** CompOption values compBlank, compAnchored, compEndAnchored, -- new in v1.0.0.0 (pcre2) compAllowEmptyClass, -- new in v1.0.0.0 (pcre2) compAltBSUX, -- new in v1.0.0.0 (pcre2) compAltExtendedClass, -- new in v1.0.0.0 (pcre2) compAltVerbnames, -- new in v1.0.0.0 (pcre2) compAutoCallout, compCaseless, compDollarEndOnly, compDotAll, compDupNames, -- new in v1.0.0.0 (pcre2) compExtended, compExtendedMore, -- new in v1.0.0.0 (pcre2) compFirstLine, compLiteral, -- new in v1.0.0.0 (pcre2) compMatchUnsetBackref, -- new in v1.0.0.0 (pcre2) compMultiline, compNeverBackslashC, -- new in v1.0.0.0 (pcre2) compNoAutoCapture, compNoAutoPossess, -- new in v1.0.0.0 (pcre2) compNoDotstarAnchor, -- new in v1.0.0.0 (pcre2) compNoUTFCheck, compUngreedy, compUTF, matchBlank, matchAnchored, matchCopyMatchedSubject, -- new in v1.0.0.0 (pcre2) matchDisableRecurseLoopCheck, -- new in v1.0.0.0 (pcre2) matchEndAnchored, -- new in v1.0.0.0 (pcre2) matchNotBOL, matchNotEOL, matchNotEmpty, matchNotEmptyAtStart, -- new in v1.0.0.0 (pcre2) matchNoUTFCheck, matchPartialHard, matchPartialSoft, -- equivalent to the obsolete execPartial -- ** ReturnCode values retOk, retNoMatch, retPartial, -- new in v1.0.0.0 (pcre2) retNull, retBadOption, retBadMagic, retNoMemory, retNoSubstring ) where import Prelude hiding (fail) import Control.Monad.Fail (MonadFail(fail)) import Control.Exception(bracket) import Control.Monad(when) import Data.Array(Array,accumArray) import Data.Bits(Bits((.|.))) import Data.Word(Word32) import System.IO.Unsafe(unsafePerformIO) import Foreign(Ptr,ForeignPtr,FinalizerPtr -- ,FunPtr ,alloca,allocaBytes,nullPtr ,mallocBytes,free ,peek,peekElemOff ,newForeignPtr,withForeignPtr) #if __GLASGOW_HASKELL__ >= 703 import Foreign.C(CInt(CInt),CSize(CSize)) #else import Foreign.C(CInt,CSize) #endif import Foreign.C.String(CString,CStringLen,peekCString) import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray,MatchOffset) -- | Version string of PCRE2 library {-# NOINLINE getVersion #-} getVersion :: Maybe String type PCRE = () type CompContext = () type MatchContext = () type MatchData = () type StartOffset = MatchOffset type EndOffset = MatchOffset type WrapError = (ReturnCode,String) newtype CompOption = CompOption Word32 deriving (Eq,Show,Num,Bits) newtype MatchOption = MatchOption Word32 deriving (Eq,Show,Num,Bits) newtype ReturnCode = ReturnCode CInt deriving (Eq,Show) -- | A compiled regular expression data Regex = Regex (ForeignPtr PCRE) CompOption MatchOption Int compBlank :: CompOption matchBlank :: MatchOption unusedOffset :: MatchOffset retOk :: ReturnCode wrapCompile :: CompOption -- ^ Flags (summed together) -> MatchOption -- ^ Flags (summed together) -> CStringLen -- ^ The regular expression to compile -> IO (Either (MatchOffset,String) Regex) -- ^ Returns: an error offset and string or the compiled regular expression wrapTest :: StartOffset -- ^ Starting index in CStringLen -> Regex -- ^ Compiled regular expression -> CStringLen -- ^ String to match against and length in bytes -> IO (Either WrapError Bool) wrapMatch :: StartOffset -- ^ Starting index in CStringLen -> Regex -- ^ Compiled regular expression -> CStringLen -- ^ String to match against and length in bytes -> IO (Either WrapError (Maybe [(StartOffset,EndOffset)])) -- ^ Returns: 'Right Nothing' if the regex did not match the string, or: -- 'Right Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions, or: -- 'Left ReturnCode' if there is some strange error wrapMatchAll :: Regex -> CStringLen -> IO (Either WrapError [ MatchArray ]) wrapCount :: Regex -> CStringLen -> IO (Either WrapError Int) getNumSubs :: Regex -> Int (=~) :: (RegexMaker Regex CompOption MatchOption source,RegexContext Regex source1 target) => source1 -> source -> target (=~~) :: (RegexMaker Regex CompOption MatchOption source,RegexContext Regex source1 target,MonadFail m) => source1 -> source -> m target #include #define PCRE2_CODE_UNIT_WIDTH 8 #include instance RegexOptions Regex CompOption MatchOption where blankCompOpt = compBlank blankExecOpt = matchBlank defaultCompOpt = compMultiline defaultExecOpt = matchBlank setExecOpts e' (Regex r c _ n) = Regex r c e' n getExecOpts (Regex _ _ e _) = e -- (=~) :: (RegexMaker Regex CompOption MatchOption source,RegexContext Regex source1 target) => source1 -> source -> target (=~) x r = let q :: Regex q = makeRegex r in match q x -- (=~~) ::(RegexMaker Regex CompOption MatchOption source,RegexContext Regex source1 target,MonadFail m) => source1 -> source -> m target (=~~) x r = do (q :: Regex) <- makeRegexM r matchM q x fi :: (Integral i,Num n) => i -> n fi x = fromIntegral x compBlank = CompOption 0 matchBlank = MatchOption 0 unusedOffset = (-1) retOk = ReturnCode 0 newtype InfoWhat = InfoWhat Word32 deriving (Eq,Show) newtype ConfigWhat = ConfigWhat Word32 deriving (Eq,Show) nullTest' :: Ptr a -> String -> IO (Either (MatchOffset,String) b) -> IO (Either (MatchOffset,String) b) {-# INLINE nullTest' #-} nullTest' ptr msg io = do if nullPtr == ptr then return (Left (0,"Ptr parameter was nullPtr in Text.Regex.PCRE2.Wrap."++msg)) else io nullTest :: Ptr a -> String -> IO (Either WrapError b) -> IO (Either WrapError b) {-# INLINE nullTest #-} nullTest ptr msg io = do if nullPtr == ptr then return (Left (retOk,"Ptr parameter was nullPtr in Text.Regex.PCRE2.Wrap."++msg)) else io getErrMsg :: CInt -> IO String {-# INLINE getErrMsg #-} getErrMsg errnum = do errstr <- mallocBytes 1024 if nullPtr == errstr then return "Ptr parameter was nullPtr in Text.Regex.PCRE2.Wrap.getErrMsg errstr" else do _ <- c_pcre2_get_error_message errnum errstr 1024 errstr' <- peekCString errstr free errstr return errstr' wrapRC :: ReturnCode -> IO (Either WrapError b) {-# INLINE wrapRC #-} wrapRC errnum@(ReturnCode errnum') = do errstr <- getErrMsg errnum' return (Left (errnum,"Error in Text.Regex.PCRE2.Wrap: "++errstr)) -- | Compiles a regular expression wrapCompile flags e (pattern,len) = do nullTest' pattern "wrapCompile pattern" $ do alloca $ \errOffset -> alloca $ \errPtr -> do nullTest' errPtr "wrapCompile errPtr" $ do pcre_ptr <- c_pcre2_compile pattern (fi len) flags errPtr errOffset nullPtr if pcre_ptr == nullPtr then do -- No need to use c_pcre2_code_free in the error case (e.g. pcredemo.c) offset <- peek errOffset errstr <- getErrMsg =<< peek errPtr return (Left (fi offset, errstr)) else do alloca $ \st -> do when (st == nullPtr) (fail "Text.Regex.PCRE2.Wrap.wrapCompile could not allocate a CInt for the capture count.") ok0 <- c_pcre2_pattern_info pcre_ptr pcre2InfoCapturecount st when (ok0 /= 0) (fail $ "Impossible/fatal: Haskell package regex-pcre2 error in Text.Posix.PCRE2.Wrap.getNumSubs' of ok0 /= 0. ok0 is from pcre2_pattern_info c-function which returned "++show ok0) n <- peek st regex <- newForeignPtr c_pcre2_code_free pcre_ptr return . Right $ Regex regex flags e n getNumSubs (Regex _ _ _ n) = n withDataPtr :: IO (Ptr MatchData) -> String -> (Ptr MatchData -> IO (Either WrapError a)) -> IO (Either WrapError a) withDataPtr data_create jobname job = bracket data_create c_pcre2_match_data_free job' where job' dataPtr = nullTest dataPtr (jobname++" dataPtr") (job dataPtr) wrapTest startOffset (Regex pcre_fptr _ flags _) (cstr,len) = do nullTest cstr "wrapTest cstr" $ do withForeignPtr pcre_fptr $ \pcre_ptr -> do withDataPtr (c_pcre2_match_data_create 1 nullPtr) "wrapTest" $ \dataPtr -> do r@(ReturnCode r') <- c_pcre2_match pcre_ptr cstr (fi len) (fi startOffset) flags dataPtr nullPtr if r == retNoMatch then return (Right False) else if r' < 0 then wrapRC r else return (Right True) -- | Matches a regular expression against a string -- -- Should never return (Right (Just [])) wrapMatch startOffset (Regex pcre_fptr _ flags nsub) (cstr,len) = do nullTest cstr "wrapMatch cstr" $ do withForeignPtr pcre_fptr $ \pcre_ptr -> do withDataPtr (c_pcre2_match_data_create_from_pattern pcre_ptr nullPtr) "wrapMatch" $ \dataPtr -> do r@(ReturnCode r') <- c_pcre2_match pcre_ptr cstr (fi len) (fi startOffset) flags dataPtr nullPtr if r == retNoMatch then do return (Right Nothing) else if r' < 0 then wrapRC r else do ovecsize <- fi <$> c_pcre2_get_ovector_count dataPtr ovec <- c_pcre2_get_ovector_pointer dataPtr let extraPairs :: [(Int,Int)] extraPairs = replicate (nsub + 1 - ovecsize) (unusedOffset,unusedOffset) pairs <- return . toPairs =<< mapM (peekElemOff ovec) [0 .. ((ovecsize*2)-1)] return . Right . Just $ (pairs ++ extraPairs) -- | wrapMatchAll is an improvement over wrapMatch since it only -- allocates memory with allocaBytes once at the start. wrapMatchAll (Regex pcre_fptr _ flags nsub) (cstr,len) = do nullTest cstr "wrapMatchAll cstr" $ do withForeignPtr pcre_fptr $ \pcre_ptr -> do let flags' = (matchNotEmpty .|. matchAnchored .|. flags) withDataPtr (c_pcre2_match_data_create_from_pattern pcre_ptr nullPtr) "wrapMatchAll" $ \dataPtr -> let loop acc flags_in_use pos = do r@(ReturnCode r') <- c_pcre2_match pcre_ptr cstr (fi len) (fi pos) flags_in_use dataPtr nullPtr if r == retNoMatch then return (Right (acc [])) else if r' < 0 then wrapRC r else do ovecsize <- fi <$> c_pcre2_get_ovector_count dataPtr ovec <- c_pcre2_get_ovector_pointer dataPtr pairs <- return . toPairs =<< mapM (peekElemOff ovec) [0 .. ((ovecsize*2)-1)] let acc' = acc . (toMatchArray nsub pairs:) case pairs of [] -> return (Right (acc' [])) ((s,e):_) | s==e -> if s == len then return (Right (acc' [])) else loop acc' flags' e | otherwise -> loop acc' flags e in loop id flags 0 toMatchArray :: Int -> [(Int,Int)] -> Array Int (Int,Int) toMatchArray n pairs = accumArray (\_ (s,e) -> (s,(e-s))) (-1,0) (0,n) (zip [0..] pairs) toPairs :: [CSize] -> [(Int,Int)] toPairs [] = [] toPairs (a:b:rest) = (fi a,fi b):toPairs rest toPairs [_] = error "Should not have just one element in Text.Regex.Wrap.PCRE2.toPairs" wrapCount (Regex pcre_fptr _ flags _) (cstr,len) = do nullTest cstr "wrapCount cstr" $ do withForeignPtr pcre_fptr $ \pcre_ptr -> do withDataPtr (c_pcre2_match_data_create_from_pattern pcre_ptr nullPtr) "wrapCount" $ \dataPtr -> let act pos = c_pcre2_match pcre_ptr cstr (fi len) (fi pos) flags dataPtr nullPtr loop acc pos | acc `seq` pos `seq` False = undefined | otherwise = do r@(ReturnCode r') <- act pos if r == retNoMatch then return (Right acc) else if r' < 0 then wrapRC r else do ovec <- c_pcre2_get_ovector_pointer dataPtr pairs <- return . toPairs =<< mapM (peekElemOff ovec) [0,1] case pairs of [] -> return (Right (succ acc)) ((s,e):_) | s==e -> return (Right (succ acc)) | otherwise -> loop (succ acc) e in loop 0 0 getVersion = unsafePerformIO $ do vsize <- c_pcre2_config pcre2ConfigVersion nullPtr allocaBytes vsize $ \v -> do if v == nullPtr then return Nothing else do _ <- c_pcre2_config pcre2ConfigVersion v Just <$> peekCString v foreign import ccall unsafe "pcre2.h pcre2_config_8" c_pcre2_config :: ConfigWhat -> Ptr a -> IO Int foreign import ccall unsafe "pcre2.h pcre2_compile_8" c_pcre2_compile :: CString -> CSize -> CompOption -> Ptr CInt -> Ptr CSize -> Ptr CompContext -> IO (Ptr PCRE) foreign import ccall unsafe "pcre2.h pcre2_get_error_message_8" c_pcre2_get_error_message :: CInt -> CString -> CSize -> IO CInt foreign import ccall unsafe "pcre2.h pcre2_pattern_info_8" c_pcre2_pattern_info :: Ptr PCRE -> InfoWhat -> Ptr a -> IO CInt foreign import ccall unsafe "pcre2.h &pcre2_code_free_8" c_pcre2_code_free :: FinalizerPtr PCRE foreign import ccall unsafe "pcre2.h pcre2_match_data_create_8" c_pcre2_match_data_create :: Word32 -> Ptr MatchContext -> IO (Ptr MatchData) foreign import ccall unsafe "pcre2.h pcre2_match_data_create_from_pattern_8" c_pcre2_match_data_create_from_pattern :: Ptr PCRE -> Ptr MatchContext -> IO (Ptr MatchData) foreign import ccall unsafe "pcre2.h pcre2_match_8" c_pcre2_match :: Ptr PCRE -> CString -> CSize -> CSize -> MatchOption -> Ptr MatchData -> Ptr MatchContext -> IO ReturnCode foreign import ccall unsafe "pcre2.h pcre2_get_ovector_count_8" c_pcre2_get_ovector_count :: Ptr MatchData -> IO Word32 foreign import ccall unsafe "pcre2.h pcre2_get_ovector_pointer_8" c_pcre2_get_ovector_pointer :: Ptr MatchData -> IO (Ptr CSize) foreign import ccall unsafe "pcre2.h pcre2_match_data_free_8" c_pcre2_match_data_free :: Ptr MatchData -> IO () #enum CompOption,CompOption, \ compAllowEmptyClass = PCRE2_ALLOW_EMPTY_CLASS, \ compAltBSUX = PCRE2_ALT_BSUX, \ compAltExtendedClass = PCRE2_ALT_EXTENDED_CLASS, \ compAltVerbnames = PCRE2_ALT_VERBNAMES, \ compAnchored = PCRE2_ANCHORED, \ compAutoCallout = PCRE2_AUTO_CALLOUT, \ compCaseless = PCRE2_CASELESS, \ compDollarEndOnly = PCRE2_DOLLAR_ENDONLY, \ compDotAll = PCRE2_DOTALL, \ compDupNames = PCRE2_DUPNAMES, \ compEndAnchored = PCRE2_ENDANCHORED, \ compExtended = PCRE2_EXTENDED, \ compExtendedMore = PCRE2_EXTENDED_MORE, \ compFirstLine = PCRE2_FIRSTLINE, \ compLiteral = PCRE2_LITERAL, \ compMatchUnsetBackref = PCRE2_MATCH_UNSET_BACKREF, \ compMultiline = PCRE2_MULTILINE, \ compNeverBackslashC = PCRE2_NEVER_BACKSLASH_C, \ compNoAutoCapture = PCRE2_NO_AUTO_CAPTURE, \ compNoAutoPossess = PCRE2_NO_AUTO_POSSESS, \ compNoDotstarAnchor = PCRE2_NO_DOTSTAR_ANCHOR, \ compNoUTFCheck = PCRE2_NO_UTF_CHECK, \ compUngreedy = PCRE2_UNGREEDY, \ compUTF = PCRE2_UTF #enum MatchOption,MatchOption, \ matchAnchored = PCRE2_ANCHORED, \ matchCopyMatchedSubject = PCRE2_COPY_MATCHED_SUBJECT, \ matchDisableRecurseLoopCheck = PCRE2_DISABLE_RECURSELOOP_CHECK, \ matchEndAnchored = PCRE2_ENDANCHORED, \ matchNotBOL = PCRE2_NOTBOL, \ matchNotEOL = PCRE2_NOTEOL, \ matchNotEmpty = PCRE2_NOTEMPTY, \ matchNotEmptyAtStart = PCRE2_NOTEMPTY_ATSTART, \ matchNoUTFCheck = PCRE2_NO_UTF_CHECK, \ matchPartialHard = PCRE2_PARTIAL_HARD, \ matchPartialSoft = PCRE2_PARTIAL_SOFT #enum ReturnCode,ReturnCode, \ retNoMatch = PCRE2_ERROR_NOMATCH, \ retPartial = PCRE2_ERROR_PARTIAL, \ retNull = PCRE2_ERROR_NULL, \ retBadOption = PCRE2_ERROR_BADOPTION, \ retBadMagic = PCRE2_ERROR_BADMAGIC, \ retNoMemory = PCRE2_ERROR_NOMEMORY, \ retNoSubstring = PCRE2_ERROR_NOSUBSTRING #enum InfoWhat,InfoWhat, \ PCRE2_INFO_CAPTURECOUNT #enum ConfigWhat,ConfigWhat, \ PCRE2_CONFIG_VERSION regex-pcre2-1.0.0.0/test/0000755000000000000000000000000007346545000013141 5ustar0000000000000000regex-pcre2-1.0.0.0/test/Main.hs0000644000000000000000000000262207346545000014363 0ustar0000000000000000{- Copyright: (c) 2025 Homebrew Holdings -} module Main where import Text.Regex.PCRE2 import Test.HUnit import qualified Data.ByteString.UTF8 as BSU import qualified System.Exit as Exit test_tester :: Test test_tester = TestCase $ assertBool "always True" $ (1 :: Int) == 1 test_version :: Test test_version = TestCase $ assertBool "should be a non-empty string" $ maybe False ((>4) . length) getVersion test_string :: Test test_string = TestCase $ assertBool "should match successfully" $ "abcdef" =~ "[abc]+[def]{3}" test_bytestring :: Test test_bytestring = TestCase $ assertBool "should match successfully" $ (BSU.fromString "abbabbbbabbabc") =~ (BSU.fromString "^(abba|bbbb|bc)*$") emailRegex :: String emailRegex = "<([^>@]*)@([a-zA-Z.-]*)>" test_capture :: Test test_capture = TestCase $ assertEqual "should capture correctly" ("abc","","xyz",["test","example.com"]) $ "abcxyz" =~ emailRegex tests :: Test tests = TestList [ TestLabel "test_tester" test_tester , TestLabel "test_version" test_version , TestLabel "test_string" test_string , TestLabel "test_bytestring" test_bytestring , TestLabel "test_capture" test_capture ] main :: IO () main = do result <- runTestTT tests if failures result > 0 then Exit.exitFailure else Exit.exitSuccess