packages feed

regex-posix 0.94.2 → 0.96.0.2

raw patch · 19 files changed

Files

+ ChangeLog.md view
@@ -0,0 +1,40 @@+## 0.96.0.2 (2025-03-02)++- Drop support for GHC 7+- Make `Prelude` imports explicit, add `LANGUAGE NoImplicitPrelude`+- Make upper bounds of dependencies major-major (all are shipped with GHC)+- Tested with GHC 8.0 - 9.12.1++## 0.96.0.1 Revision 3 (2023-09-28)++- Allow `containers-0.7`++## 0.96.0.1 Revision 2 (2023-07-07)++- Allow `bytestring-0.12`++## 0.96.0.1 Revision 1 (2022-05-25)++- Allow `base >= 4.17` (GHC 9.4)++## 0.96.0.1 (2021-07-19)++- Compatibility with `base-4.16` (GHC 9.2)+- Fix stack installation problems on Windows around flag `_regex-posix-clib`+  (issues+  [#4](https://github.com/haskell-hvr/regex-posix/issues/4) and+  [#7](https://github.com/haskell-hvr/regex-posix/issues/7)).++## 0.96.0.0 Revision 2 (2021-02-20)++- Compatibility with `base-4.15` (GHC 9.0)++## 0.96.0.0 Revision 1 (2020-03-25)++- Compatibility with `base-4.14` (GHC 8.10)++## 0.96.0.0 (2019-09-30)++- Update to `regex-base-0.94.0.0` API+- Compatibility with `base-4.13.0`+- Remove internal regex C implementation
LICENSE view
@@ -1,5 +1,3 @@-This modile is under this "3 clause" BSD license:- Copyright (c) 2007, Christopher Kuklewicz All rights reserved. 
+ README.md view
@@ -0,0 +1,9 @@+[![Hackage version](https://img.shields.io/hackage/v/regex-posix.svg?label=Hackage&color=informational)](http://hackage.haskell.org/package/regex-posix)+[![Stackage Nightly](http://stackage.org/package/regex-posix/badge/nightly)](http://stackage.org/nightly/package/regex-posix)+[![Stackage LTS](http://stackage.org/package/regex-posix/badge/lts)](http://stackage.org/lts/package/regex-posix)+[![Haskell-CI](https://github.com/haskell-hvr/regex-posix/actions/workflows/haskell-ci.yml/badge.svg?branch=master&event=push)](https://github.com/haskell-hvr/regex-posix/actions/workflows/haskell-ci.yml)+[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)+regex-posix+===========++[Documentation](https://hackage.haskell.org/package/regex-posix/docs/Text-Regex-Posix.html) on hackage.
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
− Text/Regex/Posix.hs
@@ -1,73 +0,0 @@-{- OPTIONS_GHC -fno-warn-unused-imports -}--------------------------------------------------------------------------------- |------ Module      :  Text.Regex.Posix--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ Module that provides the Regex backend that wraps the c posix regex api.--- This is the backend being used by the regex-compat package to replace--- Text.Regex------ The "Text.Regex.Posix" 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.------ If the '=~' and '=~~' functions are too high level, you can use the--- compile, regexec, and execute functions from importing either--- "Text.Regex.Posix.String" or "Text.Regex.Posix.ByteString".  If you--- want to use a low-level 'Foreign.C.CString' interface to the library,--- then import "Text.Regex.Posix.Wrap" and use the wrap* functions.------ This module is only efficient with 'Data.ByteString.ByteString' only--- if it is null terminated, i.e. @(Bytestring.last bs)==0@.  Otherwise the--- library must make a temporary copy of the 'Data.ByteString.ByteString'--- and append the NUL byte.------ A 'String' will be converted into a 'Foreign.C.CString' for processing.--- Doing this repeatedly will be very inefficient.------ Note that the posix library works with single byte characters, and--- does not understand Unicode.  If you need Unicode support you will--- have to use a different backend.------ When offsets are reported for subexpression captures, a subexpression--- that did not match anything (as opposed to matching an empty string)--- will have its offset set to the 'unusedRegOffset' value, which is (-1).------ Benchmarking shows the default regex library on many platforms is very--- inefficient.  You might increase performace by an order of magnitude--- by obtaining libpcre and regex-pcre or libtre and regex-tre.  If you--- do not need the captured substrings then you can also get great--- performance from regex-dfa.  If you do need the capture substrings--- then you may be able to use regex-parsec to improve performance.--------------------------------------------------------------------------------module Text.Regex.Posix(getVersion_Text_Regex_Posix- ,module Text.Regex.Base-  -- ** Wrap, for '=~' and '=~~', types and constants- ,module Text.Regex.Posix.Wrap) where--import Text.Regex.Posix.Wrap(Regex, CompOption(CompOption),-  ExecOption(ExecOption), (=~), (=~~),-  unusedRegOffset,-  compBlank, compExtended, compIgnoreCase, compNoSub, compNewline,-  execBlank, execNotBOL, execNotEOL)-import Text.Regex.Posix.String()-import Text.Regex.Posix.Sequence()-import Text.Regex.Posix.ByteString()-import Text.Regex.Posix.ByteString.Lazy()-import Data.Version(Version(..))-import Text.Regex.Base--getVersion_Text_Regex_Posix :: Version-getVersion_Text_Regex_Posix =-  Version { versionBranch = [0,93,2]  -- Keep in sync with regex-posix.cabal-          , versionTags = ["unstable"]-          }
− Text/Regex/Posix/ByteString.hs
@@ -1,152 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Posix.ByteString--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ This provides 'ByteString' instances for RegexMaker and RegexLike--- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex--- ByteString ByteString) instance.------ To use these instance, you would normally import--- "Text.Regex.Posix".  You only need to import this module to use--- the medium level API of the compile, regexec, and execute--- functions.  All of these report error by returning Left values--- instead of undefined or error or fail.------ The ByteString will only be passed to the library efficiently (as a--- pointer) if it ends in a NUL byte.  Otherwise a temporary copy must--- be made with the 0 byte appended.--------------------------------------------------------------------------------module Text.Regex.Posix.ByteString(-  -- ** Types-  Regex,-  MatchOffset,-  MatchLength,-  ReturnCode,-  WrapError,-  -- ** Miscellaneous-  unusedOffset,-  -- ** Medium level API functions-  compile,-  execute,-  regexec,-  -- ** Compilation options-  CompOption(CompOption),-  compBlank,-  compExtended,   -- use extended regex syntax-  compIgnoreCase, -- ignore case when matching-  compNoSub,      -- no substring matching needed-  compNewline,    -- '.' doesn't match newline-  -- ** Execution options-  ExecOption(ExecOption),-  execBlank,-  execNotBOL,      -- not at begining of line-  execNotEOL       -- not at end of line-  ) where--import Data.Array(Array,listArray)-import Data.ByteString(ByteString)-import qualified Data.ByteString as B(empty,useAsCString,last,take,drop,null)-#ifdef SPLIT_BASE-import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)-#else-import qualified Data.ByteString.Base as B(unsafeUseAsCString)-#endif-import System.IO.Unsafe(unsafePerformIO)-import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)-import Text.Regex.Posix.Wrap -- all-import Text.Regex.Base.Impl(polymatch,polymatchM)-import Foreign.C.String(CString)--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.Posix.ByteString died: "++ show err)-                     Right v -> return v--instance RegexMaker Regex CompOption ExecOption 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 $-    asCString bs (wrapTest regex) >>=  unwrap-  matchOnce regex bs = unsafePerformIO $ -    execute regex bs >>= unwrap-  matchAll regex bs = unsafePerformIO $-    asCString bs (wrapMatchAll regex) >>= unwrap-  matchCount regex bs = unsafePerformIO $-    asCString bs (wrapCount regex) >>= unwrap---- ------------------------------------------------------------------------ | Compiles a regular expression----compile :: CompOption    -- ^ Flags (summed together)-        -> ExecOption    -- ^ Flags (summed together)-        -> ByteString  -- ^ The regular expression to compile-        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression-compile c e pattern =-  asCString 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 <- asCString bs (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)---  Right (Just []) -> ...-    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 == unusedRegOffset = B.empty-                          | otherwise = B.take (fi (stop-start)) . B.drop (fi start) $ bs-      matchedParts [] = (B.empty,B.empty,bs,[]) -- no information-      matchedParts (matchedStartStop@(start,stop):subStartStop) = -        (B.take (fi start) bs-        ,getSub matchedStartStop-        ,B.drop (fi stop) bs-        ,map getSub subStartStop)-  maybeStartEnd <- asCString bs (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)---  Right (Just []) -> ...-    Right (Just parts) -> return . Right . Just . matchedParts $ parts-    Left err -> return (Left err)--unusedOffset :: Int-unusedOffset = fromIntegral unusedRegOffset--fi :: (Integral i,Num n) => i->n-fi = fromIntegral--asCString :: ByteString -> (CString -> IO a) -> IO a-asCString bs = if (not (B.null bs)) && (0==B.last bs)-                  then B.unsafeUseAsCString bs-                  else B.useAsCString bs
− Text/Regex/Posix/ByteString/Lazy.hs
@@ -1,141 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Posix.ByteString.Lazy--- Copyright   :  (c) Chris Kuklewicz 2007--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ This provides 'ByteString.Lazy' instances for RegexMaker and RegexLike--- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex--- ByteString ByteString) instance.------ To use these instance, you would normally import--- "Text.Regex.Posix".  You only need to import this module to use--- the medium level API of the compile, regexec, and execute--- functions.  All of these report error by returning Left values--- instead of undefined or error or fail.------ A Lazy ByteString with more than one chunk cannot be be passed to--- the library efficiently (as a pointer).  It will have to converted--- via a full copy to a temporary normal bytestring (with a null byte--- appended if necessary).--------------------------------------------------------------------------------module Text.Regex.Posix.ByteString.Lazy(-  -- ** Types-  Regex,-  MatchOffset,-  MatchLength,-  ReturnCode,-  WrapError,-  -- ** Miscellaneous-  unusedOffset,-  -- ** Medium level API functions-  compile,-  execute,-  regexec,-  -- ** Compilation options-  CompOption(CompOption),-  compBlank,-  compExtended,   -- use extended regex syntax-  compIgnoreCase, -- ignore case when matching-  compNoSub,      -- no substring matching needed-  compNewline,    -- '.' doesn't match newline-  -- ** Execution options-  ExecOption(ExecOption),-  execBlank,-  execNotBOL,      -- not at begining of line-  execNotEOL       -- not at end of line-  ) where--import Data.Array(Array)-import qualified Data.ByteString.Lazy as L (ByteString,null,toChunks,fromChunks,last,snoc)-import qualified Data.ByteString as B(ByteString,concat)-#ifdef SPLIT_BASE-import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)-#else-import qualified Data.ByteString.Base as B(unsafeUseAsCString)-#endif-import System.IO.Unsafe(unsafePerformIO)-import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)-import Text.Regex.Posix.Wrap -- all-import qualified Text.Regex.Posix.ByteString as BS(execute,regexec)-import Text.Regex.Base.Impl(polymatch,polymatchM)-import Foreign.C.String(CString)--instance RegexContext Regex L.ByteString L.ByteString where-  match = polymatch-  matchM = polymatchM--fromLazy :: L.ByteString -> B.ByteString-fromLazy = B.concat . L.toChunks--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.Posix.ByteString.Lazy died: "++ show err)-                     Right v -> return v--{-# INLINE asCString #-}-asCString :: L.ByteString -> (CString -> IO a) -> IO a-asCString s = if (not (L.null s)) && (0==L.last s)-                then B.unsafeUseAsCString (fromLazy s)-                else B.unsafeUseAsCString (fromLazy (L.snoc s 0))--instance RegexMaker Regex CompOption ExecOption 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 $-    asCString bs (wrapTest regex) >>=  unwrap-  matchOnce regex bs = unsafePerformIO $ -    execute regex bs >>= unwrap-  matchAll regex bs = unsafePerformIO $-    asCString bs (wrapMatchAll regex) >>= unwrap-  matchCount regex bs = unsafePerformIO $-    asCString bs (wrapCount regex) >>= unwrap---- ------------------------------------------------------------------------ | Compiles a regular expression----compile :: CompOption    -- ^ Flags (summed together)-        -> ExecOption    -- ^ Flags (summed together)-        -> L.ByteString  -- ^ The regular expression to compile-        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression-compile c e pattern = asCString 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 = if (not (L.null bs)) && (0==L.last bs)-                     then BS.execute regex (fromLazy bs)-                     else BS.execute regex (fromLazy (L.snoc bs 0))--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 <- if (not (L.null bs)) && (0==L.last bs)-         then BS.regexec regex (fromLazy bs)-         else BS.regexec regex (fromLazy (L.snoc bs 0))-  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))--unusedOffset :: Int-unusedOffset = fromIntegral unusedRegOffset
− Text/Regex/Posix/Sequence.hs
@@ -1,165 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Posix.Sequence--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ This provides 'String' instances for 'RegexMaker' and 'RegexLike' based--- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')--- instance.------ To use these instance, you would normally import--- "Text.Regex.Posix".  You only need to import this module to use--- the medium level API of the compile, regexec, and execute--- functions.  All of these report error by returning Left values--- instead of undefined or error or fail.-----------------------------------------------------------------------------------module Text.Regex.Posix.Sequence(-  -- ** Types-  Regex,-  MatchOffset,-  MatchLength,-  ReturnCode,-  WrapError,-  -- ** Miscellaneous-  unusedOffset,-  -- ** Medium level API functions-  compile,-  regexec,-  execute,-  -- ** Compilation options-  CompOption(CompOption),-  compBlank,-  compExtended,   -- use extended regex syntax-  compIgnoreCase, -- ignore case when matching-  compNoSub,      -- no substring matching needed-  compNewline,    -- '.' doesn't match newline--  ExecOption(ExecOption),-  execBlank,-  execNotBOL,     -- not at begining of line-  execNotEOL     -- not at end of line-  ) where--import Data.Array(listArray, Array)-import System.IO.Unsafe(unsafePerformIO)-import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength,Extract(..))-import Text.Regex.Posix.Wrap-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--unusedOffset :: Int-unusedOffset = fromIntegral unusedRegOffset--unwrap :: (Show e) => Either e v -> IO v-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.Sequence died: "++ show err)-                     Right v -> return v--instance RegexMaker Regex CompOption ExecOption (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 $ do-    withSeq str (wrapTest 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---- compile-compile  :: CompOption -- ^ Flags (summed together)-         -> ExecOption -- ^ Flags (summed together)-         -> (Seq Char)     -- ^ The regular expression to compile (ASCII only, no null bytes)-         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression-compile flags e pattern =  withSeq pattern (wrapCompile flags e)---- -------------------------------------------------------------------------------- regexec---- | 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' (array of offset length pairs)-                -- @-execute regex str = do-  maybeStartEnd <- withSeq str (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)---  Right (Just []) ->  fail "got [] back!" -- return wierd array instead-    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---- | Matches a regular expression against a string-regexec :: Regex      -- ^ Compiled regular expression-        -> (Seq Char)     -- ^ (Seq Char) to match against-        -> IO (Either WrapError (Maybe ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])))-                -- ^ Returns: 'Nothing' if the regex did not match the-                -- string, or:-                ---                -- @-                --   'Just' (everything before match,-                --         matched portion,-                --         everything after match,-                --         subexpression matches)-                -- @-regexec regex str = do-  let getSub :: (RegOffset,RegOffset) -> (Seq Char)-      getSub (start,stop) | start == unusedRegOffset = S.empty-                          | otherwise = -        extract (fromEnum start,fromEnum $ stop-start) $ str-      matchedParts :: [(RegOffset,RegOffset)] -> ((Seq Char), (Seq Char), (Seq Char), [(Seq Char)])-      matchedParts [] = (str,S.empty,S.empty,[]) -- no information-      matchedParts (matchedStartStop@(start,stop):subStartStop) = -        (before (fromEnum start) str-        ,getSub matchedStartStop-        ,after (fromEnum stop) str-        ,map getSub subStartStop)-  maybeStartEnd <- withSeq str (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)-    Right (Just parts) -> return . Right . Just . matchedParts $ parts-    Left err -> return (Left err)--withSeq :: Seq Char -> (CString -> IO a) -> IO a-withSeq s f =-  let -- Ensure null at end of s-      s' = case viewr s of                 -- bang !s-             EmptyR -> singleton '\0'-             _ :> '\0' -> s-             _ -> s |> '\0'-      pokes p a = case viewl a of         -- bang pokes !p !a-                    EmptyL -> return ()-                    c :< a' -> poke p (castCharToCChar c) >> pokes (advancePtr p 1) a'-  in allocaBytes (S.length s') (\ptr -> pokes ptr s' >> f ptr)
− Text/Regex/Posix/String.hs
@@ -1,147 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Posix.String--- Copyright   :  (c) Chris Kuklewicz 2006--- License     :  BSD-style (see the file LICENSE)--- --- Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ This provides 'String' instances for 'RegexMaker' and 'RegexLike' based--- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')--- instance.------ To use these instance, you would normally import--- "Text.Regex.Posix".  You only need to import this module to use--- the medium level API of the compile, regexec, and execute--- functions.  All of these report error by returning Left values--- instead of undefined or error or fail.-----------------------------------------------------------------------------------module Text.Regex.Posix.String(-  -- ** Types-  Regex,-  MatchOffset,-  MatchLength,-  ReturnCode,-  WrapError,-  -- ** Miscellaneous-  unusedOffset,-  -- ** Medium level API functions-  compile,-  regexec,-  execute,-  -- ** Compilation options-  CompOption(CompOption),-  compBlank,-  compExtended,   -- use extended regex syntax-  compIgnoreCase, -- ignore case when matching-  compNoSub,      -- no substring matching needed-  compNewline,    -- '.' doesn't match newline-  -- ** Execution options-  ExecOption(ExecOption),-  execBlank,-  execNotBOL,     -- not at begining of line-  execNotEOL     -- not at end of line-  ) where--import Data.Array(listArray, Array)-import Data.List(genericDrop, genericTake)-import Foreign.C.String(withCAString)-import System.IO.Unsafe(unsafePerformIO)-import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)-import Text.Regex.Posix.Wrap-import Text.Regex.Base.Impl(polymatch,polymatchM)--instance RegexContext Regex String String where-  match = polymatch-  matchM = polymatchM--unusedOffset :: Int-unusedOffset = fromIntegral unusedRegOffset--unwrap :: (Show e) => Either e v -> IO v-unwrap x = case x of Left err -> fail ("Text.Regex.Posix.String died: "++ show err)-                     Right v -> return v--instance RegexMaker Regex CompOption ExecOption 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 $ do-    withCAString str (wrapTest regex) >>= unwrap-  matchOnce regex str = unsafePerformIO $ -    execute regex str >>= unwrap-  matchAll regex str = unsafePerformIO $ -    withCAString str (wrapMatchAll regex) >>= unwrap-  matchCount regex str = unsafePerformIO $-    withCAString str (wrapCount regex) >>= unwrap---- compile-compile  :: CompOption -- ^ Flags (summed together)-         -> ExecOption -- ^ Flags (summed together)-         -> String     -- ^ The regular expression to compile (ASCII only, no null bytes)-         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression-compile flags e pattern =  withCAString pattern (wrapCompile flags e)---- -------------------------------------------------------------------------------- regexec---- | 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' (array of offset length pairs)-                -- @-execute regex str = do-  maybeStartEnd <- withCAString str (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)---  Right (Just []) ->  fail "got [] back!" -- return wierd array instead-    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---- | Matches a regular expression against a string-regexec :: Regex      -- ^ Compiled regular expression-        -> String     -- ^ String to match against-        -> IO (Either WrapError (Maybe (String, String, String, [String])))-                -- ^ Returns: 'Nothing' if the regex did not match the-                -- string, or:-                ---                -- @-                --   'Just' (everything before match,-                --         matched portion,-                --         everything after match,-                --         subexpression matches)-                -- @-regexec regex str = do-  let getSub (start,stop) | start == unusedRegOffset = ""-                          | otherwise = -        genericTake (stop-start) . genericDrop start $ str-      matchedParts [] = (str,"","",[]) -- no information-      matchedParts (matchedStartStop@(start,stop):subStartStop) = -        (genericTake start str-        ,getSub matchedStartStop-        ,genericDrop stop str-        ,map getSub subStartStop)-  maybeStartEnd <- withCAString str (wrapMatch regex)-  case maybeStartEnd of-    Right Nothing -> return (Right Nothing)-    Right (Just parts) -> return . Right . Just . matchedParts $ parts-    Left err -> return (Left err)
− Text/Regex/Posix/Wrap.hsc
@@ -1,648 +0,0 @@-{-# OPTIONS_GHC -fno-warn-unused-imports #-}--------------------------------------------------------------------------------- |--- Module      :  Text.Regex.Posix.Wrap--- Copyright   :  (c) Chris Kuklewicz 2006,2007,2008 derived from (c) The University of Glasgow 2002--- License     :  BSD-style (see the file LICENSE)------ Maintainer  :  libraries@haskell.org, textregexlazy@personal.mightyreason.com--- Stability   :  experimental--- Portability :  non-portable (regex-base needs MPTC+FD)------ WrapPosix.hsc exports a wrapped version of the ffi imports.  To--- increase type safety, the flags are newtype'd.  The other important--- export is a 'Regex' type that is specific to the Posix library--- backend.  The flags are documented in "Text.Regex.Posix".  The--- 'defaultCompOpt' is @(compExtended .|. compNewline)@.------ The 'Regex', 'CompOption', and 'ExecOption' types and their 'RegexOptions'--- instance is declared.  The '=~' and '=~~' convenience functions are--- defined.------ The exported symbols are the same whether HAVE_REGEX_H is defined, but--- when it is not defined then @getVersion == Nothing@ and all other--- exported values will call error or fail.------ This module will fail or error only if allocation fails or a nullPtr--- is passed in.------ 2009-January : wrapMatchAll and wrapCount now adjust the execution--- option execNotBOL after the first result to take into account '\n'--- in the text immediately before the next matches. (version 0.93.3)--- --- 2009-January : wrapMatchAll and wrapCount have been changed to--- return all non-overlapping matches, including empty matches even if--- they coincide with the end of the previous non-empty match.  The--- change is that the first non-empty match no longer terminates the--- search.  One can filter the results to obtain the old behavior or--- to obtain the behavior of "sed", where "sed" eliminates the empty--- matches which coincide with the end of non-empty matches. (version--- 0.94.0)--------------------------------------------------------------------------------module Text.Regex.Posix.Wrap(-  -- ** High-level API-  Regex,-  RegOffset,-  RegOffsetT,-  (=~),-  (=~~),--  -- ** Low-level API-  WrapError,-  wrapCompile,-  wrapTest,-  wrapMatch,-  wrapMatchAll,-  wrapCount,--  -- ** Miscellaneous-  unusedRegOffset,--  -- ** Compilation options-  CompOption(CompOption),-  compBlank,-  compExtended,   -- use extended regex syntax-  compIgnoreCase, -- ignore case when matching-  compNoSub,      -- no substring matching needed-  compNewline,    -- '.' doesn't match newline--  -- ** Execution options-  ExecOption(ExecOption),-  execBlank,-  execNotBOL,     -- not at begining of line-  execNotEOL,     -- not at end of line--  -- ** Return codes-  ReturnCode(ReturnCode),-  retBadbr,-  retBadpat,-  retBadrpt,-  retEcollate,-  retEctype,-  retEescape,-  retEsubreg,-  retEbrack,-  retEparen,-  retEbrace,-  retErange,-  retEspace-  ) where--#ifdef HAVE_REGEX_H-#define HAVE_REGCOMP 1-#else-#ifndef __NHC__-#include "HsRegexPosixConfig.h"-#else-#define HAVE_REGEX_H 1-#define HAVE_REGCOMP 1-#endif-#endif--#include <sys/types.h>--#define _POSIX_C_SOURCE 1-#if HAVE_REGEX_H && HAVE_REGCOMP-#include "regex.h"-#else-#include "regex/regex.h"---- CFILES stuff is Hugs only-{-# CFILES cbits/reallocf.c #-}-{-# CFILES cbits/regcomp.c #-}-{-# CFILES cbits/regerror.c #-}-{-# CFILES cbits/regexec.c #-}-{-# CFILES cbits/regfree.c #-}-#endif--import Control.Monad(liftM)-import Data.Array(Array,listArray)-import Data.Bits(Bits(..))-import Data.Int(Int32,Int64)   -- need whatever RegeOffset or #regoff_t type will be-import Data.Word(Word32,Word64) -- need whatever RegeOffset or #regoff_t type will be-import Foreign(Ptr, FunPtr, nullPtr, mallocForeignPtrBytes,-               addForeignPtrFinalizer, Storable(peekByteOff), allocaArray,-               allocaBytes, withForeignPtr,ForeignPtr,plusPtr,peekElemOff)-import Foreign.C(CSize,CInt,CChar)-import Foreign.C.String(peekCAString, CString)-import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)--type CRegex = ()   -- dummy regex_t used below to read out nsub value---- | RegOffset is "typedef int regoff_t" on Linux and ultimately "typedef--- long long __int64_t" on Max OS X.  So rather than saying--- 2,147,483,647 is all the length you need, I'll take the larger:--- 9,223,372,036,854,775,807 should be enough bytes for anyone, no--- need for Integer. The alternative is to compile to different sizes--- in a platform dependent manner with "type RegOffset = (#type--- regoff_t)", which I do not want to do.------ There is also a special value 'unusedRegOffset' :: 'RegOffset' which is--- (-1) and as a starting index means that the subgroup capture was--- unused.  Otherwise the RegOffset indicates a character boundary that--- is before the character at that index offset, with the first--- character at index offset 0. So starting at 1 and ending at 2 means--- to take only the second character.-type RegOffset = Int64---debugging 64-bit ubuntu-type RegOffsetT = (#type regoff_t)---- | A bitmapped 'CInt' containing options for compilation of regular--- expressions.  Option values (and their man 3 regcomp names) are------  * 'compBlank' which is a completely zero value for all the flags.---    This is also the 'blankCompOpt' value.------  * 'compExtended' (REG_EXTENDED) which can be set to use extended instead---    of basic regular expressions.---    This is set in the 'defaultCompOpt' value.------  * 'compNewline' (REG_NEWLINE) turns on newline sensitivity: The dot (.)---    and inverted set @[^ ]@ never match newline, and ^ and $ anchors do---    match after and before newlines.---    This is set in the 'defaultCompOpt' value.------  * 'compIgnoreCase' (REG_ICASE) which can be set to match ignoring upper---    and lower distinctions.------  * 'compNoSub' (REG_NOSUB) which turns off all information from matching---    except whether a match exists.-#ifdef __GLASGOW_HASKELL__-newtype CompOption = CompOption CInt deriving (Eq,Show,Num,Bits)-#else-newtype CompOption = CompOption CInt deriving (Eq,Show)--instance Num CompOption where-	CompOption x + CompOption y = CompOption (x + y)-	CompOption x - CompOption y = CompOption (x - y)-	CompOption x * CompOption y = CompOption (x * y)-	abs (CompOption x) = CompOption (abs x)-	signum (CompOption x) = CompOption (signum x)-	fromInteger n = CompOption (fromInteger n)--instance Bits CompOption where-	CompOption x .&. CompOption y = CompOption (x .&. y)-	CompOption x .|. CompOption y = CompOption (x .|. y)-	CompOption x `xor` CompOption y = CompOption (x `xor` y)-	complement (CompOption x) = CompOption (complement x)-	shift (CompOption x) n = CompOption (shift x n)-	rotate (CompOption x) n = CompOption (rotate x n)-	bitSize (CompOption x) = bitSize x-	isSigned (CompOption x) = isSigned x-#endif---- | A bitmapped 'CInt' containing options for execution of compiled--- regular expressions.  Option values (and their man 3 regexec names) are------  * 'execBlank' which is a complete zero value for all the flags.  This is---    the blankExecOpt value.------  * 'execNotBOL' (REG_NOTBOL) can be set to prevent ^ from matching at the---    start of the input.------  * 'execNotEOL' (REG_NOTEOL) can be set to prevent $ from matching at the---    end of the input (before the terminating NUL).-#ifdef __GLASGOW_HASKELL__-newtype ExecOption = ExecOption CInt deriving (Eq,Show,Num,Bits)-#else-newtype ExecOption = ExecOption CInt deriving (Eq,Show)--instance Num ExecOption where-	ExecOption x + ExecOption y = ExecOption (x + y)-	ExecOption x - ExecOption y = ExecOption (x - y)-	ExecOption x * ExecOption y = ExecOption (x * y)-	abs (ExecOption x) = ExecOption (abs x)-	signum (ExecOption x) = ExecOption (signum x)-	fromInteger n = ExecOption (fromInteger n)--instance Bits ExecOption where-	ExecOption x .&. ExecOption y = ExecOption (x .&. y)-	ExecOption x .|. ExecOption y = ExecOption (x .|. y)-	ExecOption x `xor` ExecOption y = ExecOption (x `xor` y)-	complement (ExecOption x) = ExecOption (complement x)-	shift (ExecOption x) n = ExecOption (shift x n)-	rotate (ExecOption x) n = ExecOption (rotate x n)-	bitSize (ExecOption x) = bitSize x-	isSigned (ExecOption x) = isSigned x-#endif---- | ReturnCode is an enumerated 'CInt', corresponding to the error codes--- from @man 3 regex@:------ * 'retBadbr' (@REG_BADBR@) invalid repetition count(s) in @{ }@------ * 'retBadpat' (@REG_BADPAT@) invalid regular expression------ * 'retBadrpt' (@REG_BADRPT@) @?@, @*@, or @+@ operand invalid------ * 'retEcollate' (@REG_ECOLLATE@) invalid collating element------ * 'retEctype' (@REG_ECTYPE@) invalid character class------ * 'retEescape' (@REG_EESCAPE@) @\\@ applied to unescapable character------ * 'retEsubreg' (@REG_ESUBREG@) invalid backreference number------ * 'retEbrack' (@REG_EBRACK@) brackets @[ ]@ not balanced------ * 'retEparen' (@REG_EPAREN@) parentheses @( )@ not balanced------ * 'retEbrace' (@REG_EBRACE@) braces @{ }@ not balanced------ * 'retErange' (@REG_ERANGE@) invalid character range in @[ ]@------ * 'retEspace' (@REG_ESPACE@) ran out of memory------ * 'retNoMatch' (@REG_NOMATCH@) The regexec() function failed to match----newtype ReturnCode = ReturnCode CInt deriving (Eq,Show)---- | A compiled regular expression.-data Regex = Regex (ForeignPtr CRegex) CompOption ExecOption---- | A completely zero value for all the flags.--- This is also the 'blankCompOpt' value.-compBlank :: CompOption-compBlank = CompOption 0---- | A completely zero value for all the flags.--- This is also the 'blankExecOpt' value.-execBlank :: ExecOption-execBlank = ExecOption 0--unusedRegOffset :: RegOffset-unusedRegOffset = (-1)---- | The return code will be retOk when it is the Haskell wrapper and--- not the underlying library generating the error message.-type WrapError = (ReturnCode,String)--wrapCompile :: CompOption -- ^ Flags (bitmapped)-            -> ExecOption -- ^ Flags (bitmapped)-            -> CString -- ^ The regular expression to compile (ASCII only, no null bytes)-            -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression--wrapTest :: Regex -> CString-         -> IO (Either WrapError Bool)---- | wrapMatch returns offsets for the begin and end of each capture.--- Unused captures have offsets of unusedRegOffset which is (-1)-wrapMatch :: Regex -> CString-          -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))---- | wrapMatchAll returns the offset and length of each capture.--- Unused captures have an offset of unusedRegOffset which is (-1) and--- length of 0.-wrapMatchAll :: Regex -> CString-             -> IO (Either WrapError [MatchArray])--wrapCount :: Regex -> CString-          -> IO (Either WrapError Int)--(=~)  :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target)-      => source1 -> source -> target-(=~~) :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m)-      => source1 -> source -> m target--instance RegexOptions Regex CompOption ExecOption where-  blankCompOpt = compBlank-  blankExecOpt = execBlank-  defaultCompOpt = compExtended .|. compNewline-  defaultExecOpt = execBlank-  setExecOpts e' (Regex r c _) = Regex r c e'-  getExecOpts (Regex _ _ e) = e---- (=~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target) => source1 -> source -> target-(=~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex-               make = makeRegex-           in match (make r) x---- (=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m) => source1 -> source -> m target-(=~~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex-                make = makeRegex-            in matchM (make r) x--type CRegMatch = () -- dummy regmatch_t used below to read out so and eo values---- -------------------------------------------------------------------------------- The POSIX regex C interface--#if __GLASGOW_HASKELL__ || __HUGS__--foreign import ccall unsafe "regcomp"-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode--foreign import ccall unsafe "&regfree"-  c_regfree :: FunPtr (Ptr CRegex -> IO ())--foreign import ccall unsafe "regexec"-  c_regexec :: Ptr CRegex -> CString -> CSize-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode--foreign import ccall unsafe "regerror"-  c_regerror :: ReturnCode -> Ptr CRegex-             -> CString -> CSize -> IO CSize--#elif HAVE_REGEX_H && HAVE_REGCOMP--foreign import ccall unsafe "regex.h regcomp"-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode--foreign import ccall unsafe "regex.h &regfree"-  c_regfree :: FunPtr (Ptr CRegex -> IO ())--foreign import ccall unsafe "regex.h regexec"-  c_regexec :: Ptr CRegex -> CString -> CSize-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode--foreign import ccall unsafe "regex.h regerror"-  c_regerror :: ReturnCode -> Ptr CRegex-             -> CString -> CSize -> IO CSize--#else--foreign import ccall unsafe "regex/regex.h regcomp"-  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode--foreign import ccall unsafe "regex/regex.h &regfree"-  c_regfree :: FunPtr (Ptr CRegex -> IO ())--foreign import ccall unsafe "regex/regex.h regexec"-  c_regexec :: Ptr CRegex -> CString -> CSize-            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode--foreign import ccall unsafe "regex/regex.h regerror"-  c_regerror :: ReturnCode -> Ptr CRegex-             -> CString -> CSize -> IO CSize-#endif--retOk :: ReturnCode-retOk = ReturnCode 0---- Flags for regexec-#enum ExecOption,ExecOption, \-  execNotBOL = REG_NOTBOL, \-  execNotEOL = REG_NOTEOL---- Flags for regcomp-#enum CompOption,CompOption, \-  compExtended = REG_EXTENDED, \-  compIgnoreCase = REG_ICASE, \-  compNoSub = REG_NOSUB, \-  compNewline = REG_NEWLINE---- Return values from regexec (REG_NOMATCH, REG_ESPACE,...)--- Error codes from regcomp (not REG_NOMATCH)--- Though calling retNoMatch an error is rather missing the point...-#enum ReturnCode,ReturnCode, \-  retNoMatch = REG_NOMATCH, \-  retBadbr = REG_BADBR, \-  retBadpat = REG_BADPAT, \-  retBadrpt = REG_BADRPT, \-  retEcollate = REG_ECOLLATE, \-  retEctype = REG_ECTYPE, \-  retEescape = REG_EESCAPE, \-  retEsubreg = REG_ESUBREG, \-  retEbrack = REG_EBRACK, \-  retEparen = REG_EPAREN, \-  retEbrace = REG_EBRACE, \-  retErange = REG_ERANGE, \-  retEspace = REG_ESPACE-------- error helpers--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.TRE.Wrap."++msg))-    else io--isNewline,isNull :: Ptr CChar -> Int -> IO Bool-isNewline cstr pos = liftM (newline ==) (peekElemOff cstr pos)-  where newline = toEnum 10-isNull cstr pos = liftM (nullChar ==) (peekElemOff cstr pos)-  where nullChar = toEnum 0--{--wrapRC :: ReturnCode -> IO (Either WrapError b)-{-# INLINE wrapRC #-}-wrapRC r = return (Left (r,"Error in Text.Regex.Posix.Wrap: "++show r))--}-wrapError :: ReturnCode -> Ptr CRegex -> IO (Either WrapError b)-wrapError errCode regex_ptr = do-  -- Call once to compute the error message buffer size-  errBufSize <- c_regerror errCode regex_ptr nullPtr 0-  -- Allocate a temporary buffer to hold the error message-  allocaArray (fromIntegral errBufSize) $ \errBuf -> do-   nullTest errBuf "wrapError errBuf" $ do-    _ <- c_regerror errCode regex_ptr errBuf errBufSize-    msg <- peekCAString errBuf :: IO String-    return (Left (errCode, msg))-------------wrapCompile flags e pattern = do- nullTest pattern "wrapCompile pattern" $ do-  regex_fptr <- mallocForeignPtrBytes (#const sizeof(regex_t))-  withForeignPtr regex_fptr $ \regex_ptr -> do-    if nullPtr == regex_ptr-      then return (Left (retOk,"Text.Regex.Posix.Wrap.wrapCompile could not malloc"))-      else do-        errCode <- c_regcomp regex_ptr pattern flags-        addForeignPtrFinalizer c_regfree regex_fptr-        if (errCode == retOk)-          then return . Right $ Regex regex_fptr flags e-          else wrapError errCode regex_ptr------------wrapTest (Regex regex_fptr _ flags) cstr = do- nullTest cstr "wrapTest" $ do-  withForeignPtr regex_fptr $ \regex_ptr -> do-    r <- c_regexec regex_ptr cstr 0 nullPtr flags-    if r == retOk-      then return (Right True)-      else if r == retNoMatch-              then return (Right False)-              else wrapError r regex_ptr------------wrapMatch regex@(Regex regex_fptr compileOptions flags) cstr = do- nullTest cstr "wrapMatch cstr" $ do-  if (0 /= compNoSub .&. compileOptions)-    then do-      r <- wrapTest regex cstr-      case r of-        Right True -> return (Right (Just [])) -- Source of much "wtf?" crap-        Right False -> return (Right Nothing)-        Left err -> return (Left err)-    else do-      withForeignPtr regex_fptr $ \regex_ptr -> do-        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize-        let nsub_int,nsub_bytes :: Int-            nsub_int = fromIntegral nsub-            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))-        -- add one because index zero covers the whole match-        allocaBytes nsub_bytes $ \p_match -> do-         nullTest p_match "wrapMatch allocaBytes" $ do-          doMatch regex_ptr cstr nsub p_match flags---- Very very thin wrapper--- Requires, but does not check, that nsub>=0--- Cannot return (Right (Just []))-doMatch :: Ptr CRegex -> CString -> CSize -> Ptr CRegMatch -> ExecOption-        -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))-{-# INLINE doMatch #-}-doMatch regex_ptr cstr nsub p_match flags = do-  r <- c_regexec regex_ptr cstr (1 + nsub) p_match flags-  if r == retOk-    then do-       regions <- mapM getOffsets . take (1+fromIntegral nsub)-                  . iterate (`plusPtr` (#const sizeof(regmatch_t))) $ p_match-       return (Right (Just regions)) -- regions will not be []-    else if r == retNoMatch-       then return (Right Nothing)-       else wrapError r regex_ptr-  where-    getOffsets :: Ptr CRegMatch -> IO (RegOffset,RegOffset)-    {-# INLINE getOffsets #-}-    getOffsets pmatch' = do-      start <- (#peek regmatch_t, rm_so) pmatch' :: IO (#type regoff_t)-      end   <- (#peek regmatch_t, rm_eo) pmatch' :: IO (#type regoff_t)-      return (fromIntegral start,fromIntegral end)--wrapMatchAll regex@(Regex regex_fptr compileOptions flags) cstr = do- nullTest cstr "wrapMatchAll cstr" $ do-  if (0 /= compNoSub .&. compileOptions)-    then do-      r <- wrapTest regex cstr-      case r of-        Right True -> return (Right [(toMA 0 [])]) -- Source of much "wtf?" crap-        Right False -> return (Right [])-        Left err -> return (Left err)-    else do-      withForeignPtr regex_fptr $ \regex_ptr -> do-        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize-        let nsub_int,nsub_bytes :: Int-            nsub_int = fromIntegral nsub-            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))-        -- add one because index zero covers the whole match-        allocaBytes nsub_bytes $ \p_match -> do-         nullTest p_match "wrapMatchAll p_match" $ do-          let flagsBOL = (complement execNotBOL) .&. flags-              flagsMIDDLE = execNotBOL .|. flags-              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsBOL-              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsMIDDLE-              loop acc old (s,e) | acc `seq` old `seq` False = undefined-                                 | s == e = do-                let pos = old + fromIntegral e -- pos may be 0-                atEnd <- isNull cstr pos-                if atEnd then return (Right (acc []))-                  else loop acc old (s,succ e)-                                 | otherwise = do-                let pos = old + fromIntegral e -- pos must be greater than 0 (tricky but true)-                prev'newline <- isNewline cstr (pred pos) -- safe-                result <- if prev'newline then atBOL pos else atMIDDLE pos-                case result of-                  Right Nothing -> return (Right (acc []))-                  Right (Just parts@(whole:_)) -> let ma = toMA pos parts-                                                 in loop (acc.(ma:)) pos whole-                  Left err -> return (Left err)-                  Right (Just []) -> return (Right (acc [(toMA pos [])])) -- should never happen-          result <- doMatch regex_ptr cstr nsub p_match flags-          case result of-            Right Nothing -> return (Right [])-            Right (Just parts@(whole:_)) -> let ma = toMA 0 parts-                                            in loop (ma:) 0 whole-            Left err -> return (Left err)-            Right (Just []) -> return (Right [(toMA 0 [])]) -- should never happen-  where-    toMA :: Int -> [(RegOffset,RegOffset)] -> Array Int (Int,Int)-    toMA pos [] = listArray (0,0) [(pos,0)] -- wtf?-    toMA pos parts = listArray (0,pred (length parts))-      . map (\(s,e)-> if s>=0 then (pos+fromIntegral s, fromIntegral (e-s)) else (-1,0))-      $ parts------------wrapCount regex@(Regex regex_fptr compileOptions flags) cstr = do- nullTest cstr "wrapCount cstr" $ do-  if (0 /= compNoSub .&. compileOptions)-    then do-      r <- wrapTest regex cstr-      case r of-        Right True -> return (Right 1)-        Right False -> return (Right 0)-        Left err -> return (Left err)-    else do-      withForeignPtr regex_fptr $ \regex_ptr -> do-        let nsub_bytes = (#size regmatch_t)-        allocaBytes nsub_bytes $ \p_match -> do-         nullTest p_match "wrapCount p_match" $ do-          let flagsBOL = (complement execNotBOL) .&. flags-              flagsMIDDLE = execNotBOL .|. flags-              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsBOL-              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsMIDDLE-              loop acc old (s,e) | acc `seq` old `seq` False = undefined-                                 | s == e = do-                let pos = old + fromIntegral e -- 0 <= pos-                atEnd <- isNull cstr pos-                if atEnd then return (Right acc)-                  else loop acc old (s,succ e)-                                 | otherwise = do-                let pos = old + fromIntegral e -- 0 < pos-                prev'newline <- isNewline cstr (pred pos) -- safe-                result <- if prev'newline then atBOL pos else atMIDDLE pos-                case result of-                  Right Nothing -> return (Right acc)-                  Right (Just (whole:_)) -> loop (succ acc) pos whole-                  Left err -> return (Left err)-                  Right (Just []) -> return (Right acc) -- should never happen-          result <- doMatch regex_ptr cstr 0 p_match flags-          case result of-            Right Nothing -> return (Right 0)-            Right (Just (whole:_)) -> loop 1 0 whole-            Left err -> return (Left err)-            Right (Just []) -> return (Right 0) -- should never happen--{----- This is the slower 0.66 version of the code (91s instead of 79s on 10^6 bytes)--wrapMatchAll regex cstr = do-  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex-      at pos = wrapMatch regex' (plusPtr cstr pos)-      loop old (s,e) | s == e = return []-                     | otherwise = do-        let pos = old + fromIntegral e-        result <- at pos-        case unwrap result of-          Nothing -> return []-          Just [] -> return ((toMA pos []):[]) -- wtf?-          Just parts@(whole:_) -> do rest <- loop pos whole-                                     return ((toMA pos parts) : rest)-  result <- wrapMatch regex cstr-  case unwrap result of-    Nothing -> return []-    Just [] -> return ((toMA 0 []):[]) -- wtf?-    Just parts@(whole:_) -> do rest <- loop 0 whole-                               return ((toMA 0 parts) : rest)------------- This was also changed to match wrapMatchAll after 0.66-wrapCount regex cstr = do-  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex-      at pos = wrapMatch regex' (plusPtr cstr pos)-      loop acc old (s,e) | acc `seq` old `seq` False = undefined-                         | s == e = return acc-                         | otherwise = do-        let pos = old + fromIntegral e-        result <- at pos-        case unwrap result of-          Nothing -> return acc-          Just [] -> return (succ acc) -- wtf?-          Just (whole:_) -> loop (succ acc) pos whole-  result <- wrapMatch regex cstr-  case unwrap result of-    Nothing -> return 0-    Just [] -> return 1 -- wtf?-    Just (whole:_) -> loop 1 0 whole--}
+ cbits/myfree.c view
@@ -0,0 +1,14 @@+#include <regex.h>+#include <stdlib.h>++#include "myfree.h"++/* +void free(void *ptr);+void regfree(regex_t *preg);+*/++void hs_regex_regfree(void *preg) {+  regfree(preg);+  free(preg);+}
+ cbits/myfree.h view
@@ -0,0 +1,1 @@+void hs_regex_regfree(void *);
regex-posix.cabal view
@@ -1,73 +1,99 @@-Name:                   regex-posix--- Keep the Version below in sync with ./Text/Regex/Posix.hs value getVersion_Text_Regex_Posix :: Version-Version:                0.94.2-Cabal-Version:          >=1.2-Build-Type:             Custom-License:                BSD3-License-File:           LICENSE-Copyright:              Copyright (c) 2007, Christopher Kuklewicz-Author:                 Christopher Kuklewicz-Maintainer:             TextRegexLazy@personal.mightyreason.com-Stability:              Seems to work, passes a few tests-Homepage:               http://sourceforge.net/projects/lazy-regex-Package-URL:            http://darcs.haskell.org/packages/regex-unstable/regex-posix/-Synopsis:               Replaces/Enhances Text.Regex-Description:            The posix regex backend for regex-base-Category:               Text-Tested-With:            GHC-Build-Type:             Simple-flag newBase-  description: Choose base >= 4-  default: True-flag splitBase-  description: Choose the new smaller, split-up base package.-  default: True+cabal-version:          1.24+name:                   regex-posix+version:                0.96.0.2++build-type:             Simple+license:                BSD3+license-file:           LICENSE+copyright:              Copyright (c) 2007-2010, Christopher Kuklewicz+author:                 Christopher Kuklewicz+maintainer:             Andreas Abel+bug-reports:            https://github.com/haskell-hvr/regex-posix+synopsis:               POSIX Backend for "Text.Regex" (regex-base)+category:               Text+description:+  The POSIX regex backend for <//hackage.haskell.org/package/regex-base regex-base>.+  .+  The main appeal of this backend is that it's very lightweight due to its reliance on the ubiquitous <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/regex.h.html POSIX.2 regex> facility that is provided by the standard C library on most POSIX platforms.+  .+  See also <https://wiki.haskell.org/Regular_expressions> for more information.++extra-doc-files:+  README.md+  ChangeLog.md++extra-source-files:+  cbits/myfree.h++tested-with:+  GHC == 9.12.1+  GHC == 9.10.1+  GHC == 9.8.4+  GHC == 9.6.6+  GHC == 9.4.8+  GHC == 9.2.8+  GHC == 9.0.2+  GHC == 8.10.7+  GHC == 8.8.4+  GHC == 8.6.5+  GHC == 8.4.4+  GHC == 8.2.2+  GHC == 8.0.2++source-repository head+  type:     git+  location: https://github.com/haskell-hvr/regex-posix.git++source-repository this+  type:     git+  location: https://github.com/haskell-hvr/regex-base.git+  tag:      v0.96.0.2++flag _regex-posix-clib+  manual: False+  default: False+  description: Use <//hackage.haskell.org/package/regex-posix-clib regex-posix-clib> package (used by default on Windows)+ library-  if flag(newBase)-      Build-Depends: regex-base >= 0.93, base >= 4 && < 5, array, containers, bytestring-      -- Need the next symbol for using CPP to get Data.ByteString.Base|Unsafe in-      --  ./Text/Regex/Posix/ByteString.hs and  ./Text/Regex/Posix/ByteString/Lazy.hs-      CPP-Options: "-DSPLIT_BASE=1"-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving, FlexibleContexts, TypeSynonymInstances, FlexibleInstances+  hs-source-dirs: src+  exposed-modules:+      Text.Regex.Posix+      Text.Regex.Posix.Wrap+      Text.Regex.Posix.String+      Text.Regex.Posix.Sequence+      Text.Regex.Posix.ByteString+      Text.Regex.Posix.ByteString.Lazy -  else-    if flag(splitBase)-      Build-Depends:      regex-base >= 0.93, base >= 3.0, array, containers, bytestring-      -- Need the next symbol for using CPP to get Data.ByteString.Base|Unsafe in-      --  ./Text/Regex/Posix/ByteString.hs and  ./Text/Regex/Posix/ByteString/Lazy.hs-      CPP-Options: "-DSPLIT_BASE=1"-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP, ForeignFunctionInterface, GeneralizedNewtypeDeriving, FlexibleContexts, TypeSynonymInstances, FlexibleInstances+  other-modules:+      Paths_regex_posix -    else-      Build-Depends:      regex-base >= 0.93, base < 3.0-      Extensions:         MultiParamTypeClasses, FunctionalDependencies, CPP+  c-sources:        cbits/myfree.c+  include-dirs:     cbits -  -- Data-Files:-  -- Extra-Source-Files:-  -- Extra-Tmp-Files:-  -- This is the library-  Exposed-Modules:        Text.Regex.Posix-                          Text.Regex.Posix.Wrap-                          Text.Regex.Posix.String-                          Text.Regex.Posix.Sequence-                          Text.Regex.Posix.ByteString-                          Text.Regex.Posix.ByteString.Lazy-  -- Futher fields-  Buildable:              True-  -- Other-Modules:-  -- HS-Source-Dirs:         "."-  -- The CPP is for using -DSPLIT_BASE=1 to get Data.ByteString.Base|Unsafe-  GHC-Options:            -Wall -O2-  -- GHC-Options:            -Wall -Werror -O2-  -- GHC-Options:            -Wall -ddump-minimal-imports-  -- GHC-Prof-Options: -  -- Hugs-Options:-  -- NHC-Options:-  -- C-Sources:-  -- LD-Options:-  -- Frameworks:-  CC-Options:             -DHAVE_REGEX_H-  -- Includes:-  -- Include-Dirs:           include-  -- Extra-Libraries:-  -- Extra-Lib-Dirs:+  if flag(_regex-posix-clib) || os(windows)+    build-depends: regex-posix-clib == 2.7.*+    -- Otherwise, use POSIX.2 regex implementation from @libc@.+    -- However, Windows/msys2 doesn't provide a POSIX.2 regex impl in its @libc@.++  default-language:+      Haskell2010+  default-extensions:+      NoImplicitPrelude+      MultiParamTypeClasses+      FunctionalDependencies+      ForeignFunctionInterface+      GeneralizedNewtypeDeriving+      FlexibleContexts+      FlexibleInstances++  build-depends:+        regex-base == 0.94.*+      , base       >= 4.9  && < 5+      , containers >= 0.5  && < 1+      , bytestring >= 0.10 && < 1+      , array      >= 0.5  && < 1++  ghc-options:+      -Wall+      -Wcompat+      -Wno-orphans
+ src/Text/Regex/Posix.hs view
@@ -0,0 +1,74 @@+-----------------------------------------------------------------------------+-- |+--+-- Module      :  Text.Regex.Posix+-- Copyright   :  (c) Chris Kuklewicz 2006+-- License     :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- Module that provides the Regex backend that wraps the+-- <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/regex.h.html C POSIX.2 regex api>.+-- This is the backend being used by the <//hackage.haskell.org/regex-compat regex-compat> package to replace+-- "Text.Regex".+--+-- The "Text.Regex.Posix" 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.+--+-- If the '=~' and '=~~' functions are too high level, you can use the+-- compile, regexec, and execute functions from importing either+-- "Text.Regex.Posix.String" or "Text.Regex.Posix.ByteString".  If you+-- want to use a low-level 'Foreign.C.CString' interface to the library,+-- then import "Text.Regex.Posix.Wrap" and use the wrap* functions.+--+-- This module is only efficient with 'Data.ByteString.ByteString' only+-- if it is null terminated, i.e. @(Bytestring.last bs)==0@.  Otherwise the+-- library must make a temporary copy of the 'Data.ByteString.ByteString'+-- and append the @NUL@ byte.+--+-- A 'String' will be converted into a 'Foreign.C.CString' for processing.+-- Doing this repeatedly will be very inefficient.+--+-- Note that the posix library works with single byte characters, and+-- does not understand Unicode.  If you need Unicode support you will+-- have to use a different backend.+--+-- When offsets are reported for subexpression captures, a subexpression+-- that did not match anything (as opposed to matching an empty string)+-- will have its offset set to the 'unusedRegOffset' value, which is @(-1)@.+--+-- Benchmarking shows the default regex library on many platforms is very+-- inefficient.  You might increase performace by an order of magnitude+-- by obtaining @libpcre@ and <//hackage.haskell.org/package/regex-pcre regex-pcre>+-- or @libtre@ and <//hackage.haskell.org/package/regex-tre regex-tre>.  If you+-- do not need the captured substrings then you can also get great+-- performance from <//hackage.haskell.org/package/regex-dfa regex-dfa>.  If you do need the capture substrings+-- then you may be able to use <//hackage.haskell.org/package/regex-parsec regex-parsec> to improve performance.+-----------------------------------------------------------------------------++module Text.Regex.Posix(getVersion_Text_Regex_Posix+ ,module Text.Regex.Base+  -- ** Wrap, for '=~' and '=~~', types and constants+ ,module Text.Regex.Posix.Wrap) where++import Prelude ()++import Text.Regex.Posix.Wrap(Regex, CompOption(CompOption),+  ExecOption(ExecOption), (=~), (=~~),+  unusedRegOffset,+  compBlank, compExtended, compIgnoreCase, compNoSub, compNewline,+  execBlank, execNotBOL, execNotEOL)+import Text.Regex.Posix.String()+import Text.Regex.Posix.Sequence()+import Text.Regex.Posix.ByteString()+import Text.Regex.Posix.ByteString.Lazy()+import Data.Version(Version)+import Text.Regex.Base+import qualified Paths_regex_posix++getVersion_Text_Regex_Posix :: Version+getVersion_Text_Regex_Posix = Paths_regex_posix.version
+ src/Text/Regex/Posix/ByteString.hs view
@@ -0,0 +1,158 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Posix.ByteString+-- Copyright   :  (c) Chris Kuklewicz 2006+-- License     :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- This provides 'ByteString' instances for RegexMaker and RegexLike+-- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex+-- ByteString ByteString) instance.+--+-- To use these instance, you would normally import+-- "Text.Regex.Posix".  You only need to import this module to use+-- the medium level API of the compile, regexec, and execute+-- functions.  All of these report error by returning Left values+-- instead of undefined or error or fail.+--+-- The ByteString will only be passed to the library efficiently (as a+-- pointer) if it ends in a NUL byte.  Otherwise a temporary copy must+-- be made with the 0 byte appended.+-----------------------------------------------------------------------------++module Text.Regex.Posix.ByteString(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  -- ** Medium level API functions+  compile,+  execute,+  regexec,+  -- ** Compilation options+  CompOption(CompOption),+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** Execution options+  ExecOption(ExecOption),+  execBlank,+  execNotBOL,      -- not at begining of line+  execNotEOL       -- not at end of line+  ) where++import Prelude+  ( Int, Integral, Num, (-), fromIntegral, pred+  , Either(Left, Right), either+  , Show(show)+  , IO, (>>=), return+  , Maybe(Nothing, Just)+  , ($), (.), (==), (&&), otherwise, not+  , (++), length, map+  )+import Control.Monad.Fail (MonadFail(fail))++import Data.Array(Array,listArray)+import Data.ByteString(ByteString)+import qualified Data.ByteString as B(empty,useAsCString,last,take,drop,null)+import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)+import Text.Regex.Posix.Wrap -- all+import Text.Regex.Base.Impl(polymatch,polymatchM)+import Foreign.C.String(CString)++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.Posix.ByteString died: "++ show err)+                     Right v -> return v++instance RegexMaker Regex CompOption ExecOption 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 $+    asCString bs (wrapTest regex) >>=  unwrap+  matchOnce regex bs = unsafePerformIO $+    execute regex bs >>= unwrap+  matchAll regex bs = unsafePerformIO $+    asCString bs (wrapMatchAll regex) >>= unwrap+  matchCount regex bs = unsafePerformIO $+    asCString bs (wrapCount regex) >>= unwrap++-- ---------------------------------------------------------------------+-- | Compiles a regular expression+--+compile :: CompOption    -- ^ Flags (summed together)+        -> ExecOption    -- ^ Flags (summed together)+        -> ByteString  -- ^ The regular expression to compile+        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression+compile c e pattern =+  asCString 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 <- asCString bs (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+--  Right (Just []) -> ...+    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 == unusedRegOffset = B.empty+                          | otherwise = B.take (fi (stop-start)) . B.drop (fi start) $ bs+      matchedParts [] = (B.empty,B.empty,bs,[]) -- no information+      matchedParts (matchedStartStop@(start,stop):subStartStop) =+        (B.take (fi start) bs+        ,getSub matchedStartStop+        ,B.drop (fi stop) bs+        ,map getSub subStartStop)+  maybeStartEnd <- asCString bs (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+--  Right (Just []) -> ...+    Right (Just parts) -> return . Right . Just . matchedParts $ parts+    Left err -> return (Left err)++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset++fi :: (Integral i,Num n) => i->n+fi = fromIntegral++asCString :: ByteString -> (CString -> IO a) -> IO a+asCString bs = if (not (B.null bs)) && (0==B.last bs)+                  then B.unsafeUseAsCString bs+                  else B.useAsCString bs
+ src/Text/Regex/Posix/ByteString/Lazy.hs view
@@ -0,0 +1,148 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Posix.ByteString.Lazy+-- Copyright   :  (c) Chris Kuklewicz 2007+-- License     :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- This provides 'ByteString.Lazy' instances for RegexMaker and RegexLike+-- based on "Text.Regex.Posix.Wrap", and a (RegexContext Regex+-- ByteString ByteString) instance.+--+-- To use these instance, you would normally import+-- "Text.Regex.Posix".  You only need to import this module to use+-- the medium level API of the compile, regexec, and execute+-- functions.  All of these report error by returning Left values+-- instead of undefined or error or fail.+--+-- A Lazy ByteString with more than one chunk cannot be be passed to+-- the library efficiently (as a pointer).  It will have to converted+-- via a full copy to a temporary normal bytestring (with a null byte+-- appended if necessary).+-----------------------------------------------------------------------------++module Text.Regex.Posix.ByteString.Lazy(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  -- ** Medium level API functions+  compile,+  execute,+  regexec,+  -- ** Compilation options+  CompOption(CompOption),+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** Execution options+  ExecOption(ExecOption),+  execBlank,+  execNotBOL,      -- not at begining of line+  execNotEOL       -- not at end of line+  ) where++import Prelude+  ( Int, fromIntegral+  , Either(Left, Right), either+  , Show(show)+  , IO, (>>=), return+  , Maybe(Nothing, Just)+  , (.), ($), (==)+  , (&&), not+  , (++), map+  )+import Control.Monad.Fail (MonadFail(fail))++import Data.Array(Array)+import qualified Data.ByteString.Lazy as L (ByteString,null,toChunks,fromChunks,last,snoc)+import qualified Data.ByteString as B(ByteString,concat)+import qualified Data.ByteString.Unsafe as B(unsafeUseAsCString)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexContext(..),RegexLike(..),MatchOffset,MatchLength)+import Text.Regex.Posix.Wrap -- all+import qualified Text.Regex.Posix.ByteString as BS(execute,regexec)+import Text.Regex.Base.Impl(polymatch,polymatchM)+import Foreign.C.String(CString)++instance RegexContext Regex L.ByteString L.ByteString where+  match = polymatch+  matchM = polymatchM++fromLazy :: L.ByteString -> B.ByteString+fromLazy = B.concat . L.toChunks++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.Posix.ByteString.Lazy died: "++ show err)+                     Right v -> return v++{-# INLINE asCString #-}+asCString :: L.ByteString -> (CString -> IO a) -> IO a+asCString s = if (not (L.null s)) && (0==L.last s)+                then B.unsafeUseAsCString (fromLazy s)+                else B.unsafeUseAsCString (fromLazy (L.snoc s 0))++instance RegexMaker Regex CompOption ExecOption 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 $+    asCString bs (wrapTest regex) >>=  unwrap+  matchOnce regex bs = unsafePerformIO $+    execute regex bs >>= unwrap+  matchAll regex bs = unsafePerformIO $+    asCString bs (wrapMatchAll regex) >>= unwrap+  matchCount regex bs = unsafePerformIO $+    asCString bs (wrapCount regex) >>= unwrap++-- ---------------------------------------------------------------------+-- | Compiles a regular expression+--+compile :: CompOption    -- ^ Flags (summed together)+        -> ExecOption    -- ^ Flags (summed together)+        -> L.ByteString  -- ^ The regular expression to compile+        -> IO (Either WrapError Regex)      -- ^ Returns: the compiled regular expression+compile c e pattern = asCString 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 = if (not (L.null bs)) && (0==L.last bs)+                     then BS.execute regex (fromLazy bs)+                     else BS.execute regex (fromLazy (L.snoc bs 0))++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 <- if (not (L.null bs)) && (0==L.last bs)+         then BS.regexec regex (fromLazy bs)+         else BS.regexec regex (fromLazy (L.snoc bs 0))+  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))++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset
+ src/Text/Regex/Posix/Sequence.hs view
@@ -0,0 +1,176 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Posix.Sequence+-- Copyright   :  (c) Chris Kuklewicz 2006+-- License     :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based+-- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')+-- instance.+--+-- To use these instance, you would normally import+-- "Text.Regex.Posix".  You only need to import this module to use+-- the medium level API of the compile, regexec, and execute+-- functions.  All of these report error by returning Left values+-- instead of undefined or error or fail.+--+-----------------------------------------------------------------------------++module Text.Regex.Posix.Sequence(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  -- ** Medium level API functions+  compile,+  regexec,+  execute,+  -- ** Compilation options+  CompOption(CompOption),+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline++  ExecOption(ExecOption),+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL     -- not at end of line+  ) where++import Prelude+  ( Char+  , Int, (-), fromEnum, fromIntegral, pred+  , Show(show)+  , Either(Left, Right), either+  , IO, (>>), (>>=), return+  , Maybe(Nothing, Just)+  , ($), (.), (==), otherwise+  , (++), length, map+  )+import Control.Monad.Fail (MonadFail(fail))++import Data.Array(listArray, Array)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength,Extract(..))+import Text.Regex.Posix.Wrap+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++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset++unwrap :: (Show e) => Either e v -> IO v+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.Sequence died: "++ show err)+                     Right v -> return v++instance RegexMaker Regex CompOption ExecOption (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 $ do+    withSeq str (wrapTest 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++-- compile+compile  :: CompOption -- ^ Flags (summed together)+         -> ExecOption -- ^ Flags (summed together)+         -> Seq Char   -- ^ The regular expression to compile (ASCII only, no null bytes)+         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression+compile flags e pattern =  withSeq pattern (wrapCompile flags e)++-- -----------------------------------------------------------------------------+-- regexec++-- | Matches a regular expression against a string+execute :: Regex      -- ^ Compiled regular expression+        -> Seq Char   -- ^ Text to match against+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --+                -- @+                --   'Just' (array of offset length pairs)+                -- @+execute regex str = do+  maybeStartEnd <- withSeq str (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+--  Right (Just []) ->  fail "got [] back!" -- return weird array instead+    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++-- | Matches a regular expression against a string+regexec :: Regex      -- ^ Compiled regular expression+        -> Seq Char   -- ^ Text to match against+        -> IO (Either WrapError (Maybe (Seq Char, Seq Char, Seq Char, [Seq Char])))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --+                -- @+                --   'Just' (everything before match,+                --         matched portion,+                --         everything after match,+                --         subexpression matches)+                -- @+regexec regex str = do+  let getSub :: (RegOffset,RegOffset) -> Seq Char+      getSub (start,stop) | start == unusedRegOffset = S.empty+                          | otherwise =+        extract (fromEnum start,fromEnum $ stop-start) $ str+      matchedParts :: [(RegOffset,RegOffset)] -> (Seq Char, Seq Char, Seq Char, [Seq Char])+      matchedParts [] = (str,S.empty,S.empty,[]) -- no information+      matchedParts (matchedStartStop@(start,stop):subStartStop) =+        (before (fromEnum start) str+        ,getSub matchedStartStop+        ,after (fromEnum stop) str+        ,map getSub subStartStop)+  maybeStartEnd <- withSeq str (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> return . Right . Just . matchedParts $ parts+    Left err -> return (Left err)++withSeq :: Seq Char -> (CString -> IO a) -> IO a+withSeq s f =+  let -- Ensure null at end of s+      s' = case viewr s of                 -- bang !s+             EmptyR -> singleton '\0'+             _ :> '\0' -> s+             _ -> s |> '\0'+      pokes p a = case viewl a of         -- bang pokes !p !a+                    EmptyL -> return ()+                    c :< a' -> poke p (castCharToCChar c) >> pokes (advancePtr p 1) a'+  in allocaBytes (S.length s') (\ptr -> pokes ptr s' >> f ptr)
+ src/Text/Regex/Posix/String.hs view
@@ -0,0 +1,160 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Posix.String+-- Copyright   :  (c) Chris Kuklewicz 2006+-- License     :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- This provides 'String' instances for 'RegexMaker' and 'RegexLike' based+-- on "Text.Regex.Posix.Wrap", and a ('RegexContext' 'Regex' 'String' 'String')+-- instance.+--+-- To use these instance, you would normally import+-- "Text.Regex.Posix".  You only need to import this module to use+-- the medium level API of the compile, regexec, and execute+-- functions.  All of these report error by returning Left values+-- instead of undefined or error or fail.+--+-----------------------------------------------------------------------------++module Text.Regex.Posix.String(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  -- ** Medium level API functions+  compile,+  regexec,+  execute,+  -- ** Compilation options+  CompOption(CompOption),+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** Execution options+  ExecOption(ExecOption),+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL     -- not at end of line+  ) where++import Prelude+  ( Int, String, IO+  , Either(Left, Right), either+  , Maybe(Nothing, Just)+  , Show(show)+  , fromIntegral, pred+  , (.), ($), (==), otherwise+  , (++), (-)+  , (>>=), return+  , length, map+  )++import Control.Monad.Fail (MonadFail(fail))++import Data.Array(listArray, Array)+import Data.List(genericDrop, genericTake)+import Foreign.C.String(withCAString)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)+import Text.Regex.Posix.Wrap+import Text.Regex.Base.Impl(polymatch,polymatchM)++instance RegexContext Regex String String where+  match = polymatch+  matchM = polymatchM++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset++unwrap :: (Show e) => Either e v -> IO v+unwrap x = case x of Left err -> fail ("Text.Regex.Posix.String died: "++ show err)+                     Right v -> return v++instance RegexMaker Regex CompOption ExecOption 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 $ do+    withCAString str (wrapTest regex) >>= unwrap+  matchOnce regex str = unsafePerformIO $+    execute regex str >>= unwrap+  matchAll regex str = unsafePerformIO $+    withCAString str (wrapMatchAll regex) >>= unwrap+  matchCount regex str = unsafePerformIO $+    withCAString str (wrapCount regex) >>= unwrap++-- compile+compile  :: CompOption -- ^ Flags (summed together)+         -> ExecOption -- ^ Flags (summed together)+         -> String     -- ^ The regular expression to compile (ASCII only, no null bytes)+         -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression+compile flags e pattern =  withCAString pattern (wrapCompile flags e)++-- -----------------------------------------------------------------------------+-- regexec++-- | 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' (array of offset length pairs)+                -- @+execute regex str = do+  maybeStartEnd <- withCAString str (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+--  Right (Just []) ->  fail "got [] back!" -- return wierd array instead+    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++-- | Matches a regular expression against a string+regexec :: Regex      -- ^ Compiled regular expression+        -> String     -- ^ String to match against+        -> IO (Either WrapError (Maybe (String, String, String, [String])))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --+                -- @+                --   'Just' (everything before match,+                --         matched portion,+                --         everything after match,+                --         subexpression matches)+                -- @+regexec regex str = do+  let getSub (start,stop) | start == unusedRegOffset = ""+                          | otherwise =+        genericTake (stop-start) . genericDrop start $ str+      matchedParts [] = (str,"","",[]) -- no information+      matchedParts (matchedStartStop@(start,stop):subStartStop) =+        (genericTake start str+        ,getSub matchedStartStop+        ,genericDrop stop str+        ,map getSub subStartStop)+  maybeStartEnd <- withCAString str (wrapMatch regex)+  case maybeStartEnd of+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> return . Right . Just . matchedParts $ parts+    Left err -> return (Left err)
+ src/Text/Regex/Posix/Wrap.hsc view
@@ -0,0 +1,584 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -Wno-unused-imports #-}++-----------------------------------------------------------------------------+-- |+-- Module      :  Text.Regex.Posix.Wrap+-- Copyright   :  (c) Chris Kuklewicz 2006,2007,2008 derived from (c) The University of Glasgow 2002+-- Identifier  :  BSD-3-Clause+--+-- Maintainer  :  Andreas Abel+-- Stability   :  stable+-- Portability :  non-portable (regex-base needs MPTC+FD)+--+-- WrapPosix.hsc exports a wrapped version of the ffi imports.  To+-- increase type safety, the flags are newtype'd.  The other important+-- export is a 'Regex' type that is specific to the Posix library+-- backend.  The flags are documented in "Text.Regex.Posix".  The+-- 'defaultCompOpt' is @(compExtended .|. compNewline)@.+--+-- The 'Regex', 'CompOption', and 'ExecOption' types and their 'RegexOptions'+-- instance is declared.  The '=~' and '=~~' convenience functions are+-- defined.+--+-- This module will fail or error only if allocation fails or a nullPtr+-- is passed in.+--+-- 2009-January : 'wrapMatchAll' and 'wrapCount' now adjust the execution+-- option 'execNotBOL' after the first result to take into account '\n'+-- in the text immediately before the next matches. (version 0.93.3)+--+-- 2009-January : 'wrapMatchAll' and 'wrapCount' have been changed to+-- return all non-overlapping matches, including empty matches even if+-- they coincide with the end of the previous non-empty match.  The+-- change is that the first non-empty match no longer terminates the+-- search.  One can filter the results to obtain the old behavior or+-- to obtain the behavior of "sed", where "sed" eliminates the empty+-- matches which coincide with the end of non-empty matches. (version+-- 0.94.0)+-----------------------------------------------------------------------------++module Text.Regex.Posix.Wrap(+  -- ** High-level API+  Regex,+  RegOffset,+  RegOffsetT,+  (=~),+  (=~~),++  -- ** Low-level API+  WrapError,+  wrapCompile,+  wrapTest,+  wrapMatch,+  wrapMatchAll,+  wrapCount,++  -- ** Miscellaneous+  unusedRegOffset,++  -- ** Compilation options+  CompOption(CompOption),+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline++  -- ** Execution options+  ExecOption(ExecOption),+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL,     -- not at end of line++  -- ** Return codes+  ReturnCode(ReturnCode),+  retBadbr,+  retBadpat,+  retBadrpt,+  retEcollate,+  retEctype,+  retEescape,+  retEsubreg,+  retEbrack,+  retEparen,+  retEbrace,+  retErange,+  retEspace+  ) where++#include <sys/types.h>+#include <string.h>++#ifndef _POSIX_C_SOURCE+#define _POSIX_C_SOURCE 1+#endif++#include <regex.h>++#include "myfree.h"++import Prelude+  ( Bool(True, False), otherwise+  , Either(Left, Right)+  , Eq, (==), (/=), (>=)+  , IO, return, mapM+  , Int, Num, (+), (*), (-), fromIntegral, pred, succ, toEnum+  , Maybe(Nothing, Just)+  , Show(show)+  , String+  , ($), (.), seq, undefined+  , (++), iterate, length, map, take+  )+import Control.Monad.Fail (MonadFail)++import Control.Monad(liftM)+import Data.Array(Array,listArray)+import Data.Bits(Bits(..))+import Data.Int(Int32,Int64)   -- need whatever RegeOffset or #regoff_t type will be+import Data.Word(Word32,Word64) -- need whatever RegeOffset or #regoff_t type will be+import Foreign(Ptr, FunPtr, nullPtr, newForeignPtr,+               Storable(peekByteOff), allocaArray,+               allocaBytes, withForeignPtr,ForeignPtr,plusPtr,peekElemOff)+import Foreign.Marshal.Alloc(mallocBytes)+import Foreign.C(CChar)+import Foreign.C(CSize(CSize),CInt(CInt))+import Foreign.C.String(peekCAString, CString)+import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)+-- deprecated: import qualified System.IO.Error as IOERROR(try)+import qualified Control.Exception(try,IOException)++try :: IO a -> IO (Either Control.Exception.IOException a)+try = Control.Exception.try++data CRegex   -- pointer tag for regex_t C type++-- | 'RegOffset' is @typedef int regoff_t@ on Linux and ultimately @typedef+-- long long __int64_t@ on Max OS X.  So rather than saying+-- 2,147,483,647 is all the length you need, I'll take the larger:+-- 9,223,372,036,854,775,807 should be enough bytes for anyone, no+-- need for Integer. The alternative is to compile to different sizes+-- in a platform dependent manner with @type RegOffset = (#type+-- regoff_t)@, which I do not want to do.+--+-- There is also a special value @'unusedRegOffset' :: 'RegOffset'@ which is+-- (-1) and as a starting index means that the subgroup capture was+-- unused.  Otherwise the 'RegOffset' indicates a character boundary that+-- is before the character at that index offset, with the first+-- character at index offset 0. So starting at 1 and ending at 2 means+-- to take only the second character.+type RegOffset = Int64+--debugging 64-bit ubuntu+type RegOffsetT = (#type regoff_t)++-- | A bitmapped 'CInt' containing options for compilation of regular+-- expressions.  Option values (and their man 3 regcomp names) are+--+--  * 'compBlank' which is a completely zero value for all the flags.+--    This is also the 'blankCompOpt' value.+--+--  * 'compExtended' (REG_EXTENDED) which can be set to use extended instead+--    of basic regular expressions.+--    This is set in the 'defaultCompOpt' value.+--+--  * 'compNewline' (REG_NEWLINE) turns on newline sensitivity: The dot (.)+--    and inverted set @[^ ]@ never match newline, and ^ and $ anchors do+--    match after and before newlines.+--    This is set in the 'defaultCompOpt' value.+--+--  * 'compIgnoreCase' (REG_ICASE) which can be set to match ignoring upper+--    and lower distinctions.+--+--  * 'compNoSub' (REG_NOSUB) which turns off all information from matching+--    except whether a match exists.++newtype CompOption = CompOption CInt deriving (Eq,Show,Num,Bits)++-- | A bitmapped 'CInt' containing options for execution of compiled+-- regular expressions.  Option values (and their man 3 regexec names) are+--+--  * 'execBlank' which is a complete zero value for all the flags.  This is+--    the @blankExecOpt@ value.+--+--  * 'execNotBOL' (REG_NOTBOL) can be set to prevent ^ from matching at the+--    start of the input.+--+--  * 'execNotEOL' (REG_NOTEOL) can be set to prevent $ from matching at the+--    end of the input (before the terminating NUL).+newtype ExecOption = ExecOption CInt deriving (Eq,Show,Num,Bits)++-- | ReturnCode is an enumerated 'CInt', corresponding to the error codes+-- from @man 3 regex@:+--+-- * 'retBadbr' (@REG_BADBR@) invalid repetition count(s) in @{ }@+--+-- * 'retBadpat' (@REG_BADPAT@) invalid regular expression+--+-- * 'retBadrpt' (@REG_BADRPT@) @?@, @*@, or @+@ operand invalid+--+-- * 'retEcollate' (@REG_ECOLLATE@) invalid collating element+--+-- * 'retEctype' (@REG_ECTYPE@) invalid character class+--+-- * 'retEescape' (@REG_EESCAPE@) @\\@ applied to unescapable character+--+-- * 'retEsubreg' (@REG_ESUBREG@) invalid backreference number+--+-- * 'retEbrack' (@REG_EBRACK@) brackets @[ ]@ not balanced+--+-- * 'retEparen' (@REG_EPAREN@) parentheses @( )@ not balanced+--+-- * 'retEbrace' (@REG_EBRACE@) braces @{ }@ not balanced+--+-- * 'retErange' (@REG_ERANGE@) invalid character range in @[ ]@+--+-- * 'retEspace' (@REG_ESPACE@) ran out of memory+--+-- * 'retNoMatch' (@REG_NOMATCH@) The regexec() function failed to match+--+newtype ReturnCode = ReturnCode CInt deriving (Eq,Show)++-- | A compiled regular expression.+data Regex = Regex (ForeignPtr CRegex) CompOption ExecOption++-- | A completely zero value for all the flags.+-- This is also the 'blankCompOpt' value.+compBlank :: CompOption+compBlank = CompOption 0++-- | A completely zero value for all the flags.+-- This is also the 'blankExecOpt' value.+execBlank :: ExecOption+execBlank = ExecOption 0++unusedRegOffset :: RegOffset+unusedRegOffset = (-1)++-- | The return code will be @retOk@ when it is the Haskell wrapper and+-- not the underlying library generating the error message.+type WrapError = (ReturnCode,String)++wrapCompile :: CompOption -- ^ Flags (bitmapped)+            -> ExecOption -- ^ Flags (bitmapped)+            -> CString -- ^ The regular expression to compile (ASCII only, no null bytes)+            -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression++wrapTest :: Regex -> CString+         -> IO (Either WrapError Bool)++-- | 'wrapMatch' returns offsets for the begin and end of each capture.+-- Unused captures have offsets of 'unusedRegOffset' which is (-1).+wrapMatch :: Regex -> CString+          -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))++-- | 'wrapMatchAll' returns the offset and length of each capture.+-- Unused captures have an offset of 'unusedRegOffset' which is (-1) and+-- length of 0.+wrapMatchAll :: Regex -> CString+             -> IO (Either WrapError [MatchArray])++wrapCount :: Regex -> CString+          -> IO (Either WrapError Int)++(=~)  :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target)+      => source1 -> source -> target+(=~~) :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,MonadFail m)+      => source1 -> source -> m target++instance RegexOptions Regex CompOption ExecOption where+  blankCompOpt = compBlank+  blankExecOpt = execBlank+  defaultCompOpt = compExtended .|. compNewline+  defaultExecOpt = execBlank+  setExecOpts e' (Regex r c _) = Regex r c e'+  getExecOpts (Regex _ _ e) = e++-- (=~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target) => source1 -> source -> target+(=~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex+               make = makeRegex+           in match (make r) x++-- (=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,MonadFail m) => source1 -> source -> m target+(=~~) x r = let make :: RegexMaker Regex CompOption ExecOption a => a -> Regex+                make = makeRegex+            in matchM (make r) x++type CRegMatch = () -- dummy regmatch_t used below to read out so and eo values++-- -----------------------------------------------------------------------------+-- The POSIX regex C interface++-- string.h+foreign import ccall unsafe "memset"+  c_memset :: Ptr CRegex -> CInt -> CSize -> IO (Ptr CRegex)++-- cbits/myfree.h and cbits/myfree.c+foreign import ccall unsafe "&hs_regex_regfree"+  c_myregfree :: FunPtr (Ptr CRegex -> IO ())++foreign import ccall unsafe "regex.h regcomp"+  c_regcomp :: Ptr CRegex -> CString -> CompOption -> IO ReturnCode++{- currently unused+foreign import ccall unsafe "regex.h &regfree"+  c_regfree :: FunPtr (Ptr CRegex -> IO ())+-}++foreign import ccall unsafe "regex.h regexec"+  c_regexec :: Ptr CRegex -> CString -> CSize+            -> Ptr CRegMatch -> ExecOption -> IO ReturnCode++foreign import ccall unsafe "regex.h regerror"+  c_regerror :: ReturnCode -> Ptr CRegex+             -> CString -> CSize -> IO CSize++retOk :: ReturnCode+retOk = ReturnCode 0++-- Flags for regexec+#enum ExecOption,ExecOption, \+  execNotBOL = REG_NOTBOL, \+  execNotEOL = REG_NOTEOL++-- Flags for regcomp+#enum CompOption,CompOption, \+  compExtended = REG_EXTENDED, \+  compIgnoreCase = REG_ICASE, \+  compNoSub = REG_NOSUB, \+  compNewline = REG_NEWLINE++-- Return values from regexec (REG_NOMATCH, REG_ESPACE,...)+-- Error codes from regcomp (not REG_NOMATCH)+-- Though calling retNoMatch an error is rather missing the point...+#enum ReturnCode,ReturnCode, \+  retNoMatch = REG_NOMATCH, \+  retBadbr = REG_BADBR, \+  retBadpat = REG_BADPAT, \+  retBadrpt = REG_BADRPT, \+  retEcollate = REG_ECOLLATE, \+  retEctype = REG_ECTYPE, \+  retEescape = REG_EESCAPE, \+  retEsubreg = REG_ESUBREG, \+  retEbrack = REG_EBRACK, \+  retEparen = REG_EPAREN, \+  retEbrace = REG_EBRACE, \+  retErange = REG_ERANGE, \+  retEspace = REG_ESPACE+----+-- error helpers++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.TRE.Wrap."++msg))+    else io++isNewline,isNull :: Ptr CChar -> Int -> IO Bool+isNewline cstr pos = liftM (newline ==) (peekElemOff cstr pos)+  where newline = toEnum 10+isNull cstr pos = liftM (nullChar ==) (peekElemOff cstr pos)+  where nullChar = toEnum 0++{-+wrapRC :: ReturnCode -> IO (Either WrapError b)+{-# INLINE wrapRC #-}+wrapRC r = return (Left (r,"Error in Text.Regex.Posix.Wrap: "++show r))+-}+wrapError :: ReturnCode -> Ptr CRegex -> IO (Either WrapError b)+wrapError errCode regex_ptr = do+  -- Call once to compute the error message buffer size+  errBufSize <- c_regerror errCode regex_ptr nullPtr 0+  -- Allocate a temporary buffer to hold the error message+  allocaArray (fromIntegral errBufSize) $ \errBuf -> do+   nullTest errBuf "wrapError errBuf" $ do+    _ <- c_regerror errCode regex_ptr errBuf errBufSize+    msg <- peekCAString errBuf :: IO String+    return (Left (errCode, msg))++----------+wrapCompile flags e pattern = do+ nullTest pattern "wrapCompile pattern" $ do+  e_regex_ptr <- try $ mallocBytes (#const sizeof(regex_t)) -- ioError called if nullPtr+  case e_regex_ptr of+    Left ioerror -> return (Left (retOk,"Text.Regex.Posix.Wrap.wrapCompile: IOError from mallocBytes(regex_t) : "++show ioerror))+    Right raw_regex_ptr -> do+      zero_regex_ptr <- c_memset raw_regex_ptr 0 (#const sizeof(regex_t)) -- no calloc, so clear the new area to zero+      regex_fptr <- newForeignPtr c_myregfree zero_regex_ptr -- once pointed-to area is clear it should be safe to add finalizer+      withForeignPtr regex_fptr $ \regex_ptr -> do  -- withForeignPtr is best hygiene here+        errCode <- c_regcomp regex_ptr pattern flags+        if (errCode == retOk)+          then return . Right $ Regex regex_fptr flags e+          else wrapError errCode regex_ptr++---------+wrapTest (Regex regex_fptr _ flags) cstr = do+ nullTest cstr "wrapTest" $ do+  withForeignPtr regex_fptr $ \regex_ptr -> do+    r <- c_regexec regex_ptr cstr 0 nullPtr flags+    if r == retOk+      then return (Right True)+      else if r == retNoMatch+              then return (Right False)+              else wrapError r regex_ptr++---------+wrapMatch regex@(Regex regex_fptr compileOptions flags) cstr = do+ nullTest cstr "wrapMatch cstr" $ do+  if (0 /= compNoSub .&. compileOptions)+    then do+      r <- wrapTest regex cstr+      case r of+        Right True -> return (Right (Just [])) -- Source of much "wtf?" crap+        Right False -> return (Right Nothing)+        Left err -> return (Left err)+    else do+      withForeignPtr regex_fptr $ \regex_ptr -> do+        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize+        let nsub_int,nsub_bytes :: Int+            nsub_int = fromIntegral nsub+            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))+        -- add one because index zero covers the whole match+        allocaBytes nsub_bytes $ \p_match -> do+         nullTest p_match "wrapMatch allocaBytes" $ do+          doMatch regex_ptr cstr nsub p_match flags++-- Very very thin wrapper+-- Requires, but does not check, that nsub>=0+-- Cannot return (Right (Just []))+doMatch :: Ptr CRegex -> CString -> CSize -> Ptr CRegMatch -> ExecOption+        -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))+{-# INLINE doMatch #-}+doMatch regex_ptr cstr nsub p_match flags = do+  r <- c_regexec regex_ptr cstr (1 + nsub) p_match flags+  if r == retOk+    then do+       regions <- mapM getOffsets . take (1+fromIntegral nsub)+                  . iterate (`plusPtr` (#const sizeof(regmatch_t))) $ p_match+       return (Right (Just regions)) -- regions will not be []+    else if r == retNoMatch+       then return (Right Nothing)+       else wrapError r regex_ptr+  where+    getOffsets :: Ptr CRegMatch -> IO (RegOffset,RegOffset)+    {-# INLINE getOffsets #-}+    getOffsets pmatch' = do+      start <- (#peek regmatch_t, rm_so) pmatch' :: IO (#type regoff_t)+      end   <- (#peek regmatch_t, rm_eo) pmatch' :: IO (#type regoff_t)+      return (fromIntegral start,fromIntegral end)++wrapMatchAll regex@(Regex regex_fptr compileOptions flags) cstr = do+ nullTest cstr "wrapMatchAll cstr" $ do+  if (0 /= compNoSub .&. compileOptions)+    then do+      r <- wrapTest regex cstr+      case r of+        Right True -> return (Right [(toMA 0 [])]) -- Source of much "wtf?" crap+        Right False -> return (Right [])+        Left err -> return (Left err)+    else do+      withForeignPtr regex_fptr $ \regex_ptr -> do+        nsub <- (#peek regex_t, re_nsub) regex_ptr :: IO CSize+        let nsub_int,nsub_bytes :: Int+            nsub_int = fromIntegral nsub+            nsub_bytes = ((1 + nsub_int) * (#const sizeof(regmatch_t)))+        -- add one because index zero covers the whole match+        allocaBytes nsub_bytes $ \p_match -> do+         nullTest p_match "wrapMatchAll p_match" $ do+          let flagsBOL = (complement execNotBOL) .&. flags+              flagsMIDDLE = execNotBOL .|. flags+              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsBOL+              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) nsub p_match flagsMIDDLE+              loop acc old (s,e) | acc `seq` old `seq` False = undefined+                                 | s == e = do+                let pos = old + fromIntegral e -- pos may be 0+                atEnd <- isNull cstr pos+                if atEnd then return (Right (acc []))+                  else loop acc old (s,succ e)+                                 | otherwise = do+                let pos = old + fromIntegral e -- pos must be greater than 0 (tricky but true)+                prev'newline <- isNewline cstr (pred pos) -- safe+                result <- if prev'newline then atBOL pos else atMIDDLE pos+                case result of+                  Right Nothing -> return (Right (acc []))+                  Right (Just parts@(whole:_)) -> let ma = toMA pos parts+                                                 in loop (acc.(ma:)) pos whole+                  Left err -> return (Left err)+                  Right (Just []) -> return (Right (acc [(toMA pos [])])) -- should never happen+          result <- doMatch regex_ptr cstr nsub p_match flags+          case result of+            Right Nothing -> return (Right [])+            Right (Just parts@(whole:_)) -> let ma = toMA 0 parts+                                            in loop (ma:) 0 whole+            Left err -> return (Left err)+            Right (Just []) -> return (Right [(toMA 0 [])]) -- should never happen+  where+    toMA :: Int -> [(RegOffset,RegOffset)] -> Array Int (Int,Int)+    toMA pos [] = listArray (0,0) [(pos,0)] -- wtf?+    toMA pos parts = listArray (0,pred (length parts))+      . map (\(s,e)-> if s>=0 then (pos+fromIntegral s, fromIntegral (e-s)) else (-1,0))+      $ parts++---------+wrapCount regex@(Regex regex_fptr compileOptions flags) cstr = do+ nullTest cstr "wrapCount cstr" $ do+  if (0 /= compNoSub .&. compileOptions)+    then do+      r <- wrapTest regex cstr+      case r of+        Right True -> return (Right 1)+        Right False -> return (Right 0)+        Left err -> return (Left err)+    else do+      withForeignPtr regex_fptr $ \regex_ptr -> do+        let nsub_bytes = (#size regmatch_t)+        allocaBytes nsub_bytes $ \p_match -> do+         nullTest p_match "wrapCount p_match" $ do+          let flagsBOL = (complement execNotBOL) .&. flags+              flagsMIDDLE = execNotBOL .|. flags+              atBOL pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsBOL+              atMIDDLE pos = doMatch regex_ptr (plusPtr cstr pos) 0 p_match flagsMIDDLE+              loop acc old (s,e) | acc `seq` old `seq` False = undefined+                                 | s == e = do+                let pos = old + fromIntegral e -- 0 <= pos+                atEnd <- isNull cstr pos+                if atEnd then return (Right acc)+                  else loop acc old (s,succ e)+                                 | otherwise = do+                let pos = old + fromIntegral e -- 0 < pos+                prev'newline <- isNewline cstr (pred pos) -- safe+                result <- if prev'newline then atBOL pos else atMIDDLE pos+                case result of+                  Right Nothing -> return (Right acc)+                  Right (Just (whole:_)) -> loop (succ acc) pos whole+                  Left err -> return (Left err)+                  Right (Just []) -> return (Right acc) -- should never happen+          result <- doMatch regex_ptr cstr 0 p_match flags+          case result of+            Right Nothing -> return (Right 0)+            Right (Just (whole:_)) -> loop 1 0 whole+            Left err -> return (Left err)+            Right (Just []) -> return (Right 0) -- should never happen++{-++-- This is the slower 0.66 version of the code (91s instead of 79s on 10^6 bytes)++wrapMatchAll regex cstr = do+  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex+      at pos = wrapMatch regex' (plusPtr cstr pos)+      loop old (s,e) | s == e = return []+                     | otherwise = do+        let pos = old + fromIntegral e+        result <- at pos+        case unwrap result of+          Nothing -> return []+          Just [] -> return ((toMA pos []):[]) -- wtf?+          Just parts@(whole:_) -> do rest <- loop pos whole+                                     return ((toMA pos parts) : rest)+  result <- wrapMatch regex cstr+  case unwrap result of+    Nothing -> return []+    Just [] -> return ((toMA 0 []):[]) -- wtf?+    Just parts@(whole:_) -> do rest <- loop 0 whole+                               return ((toMA 0 parts) : rest)+---------+-- This was also changed to match wrapMatchAll after 0.66+wrapCount regex cstr = do+  let regex' = setExecOpts (execNotBOL .|. (getExecOpts regex)) regex+      at pos = wrapMatch regex' (plusPtr cstr pos)+      loop acc old (s,e) | acc `seq` old `seq` False = undefined+                         | s == e = return acc+                         | otherwise = do+        let pos = old + fromIntegral e+        result <- at pos+        case unwrap result of+          Nothing -> return acc+          Just [] -> return (succ acc) -- wtf?+          Just (whole:_) -> loop (succ acc) pos whole+  result <- wrapMatch regex cstr+  case unwrap result of+    Nothing -> return 0+    Just [] -> return 1 -- wtf?+    Just (whole:_) -> loop 1 0 whole+-}