packages feed

regex-tre (empty) → 0.91

raw patch · 9 files changed

+997/−0 lines, 9 filesdep +basedep +regex-basebuild-type:Customsetup-changed

Dependencies added: base, regex-base

Files

+ LICENSE view
@@ -0,0 +1,12 @@+This modile is under this "3 clause" BSD license:++Copyright (c) 2007, Christopher Kuklewicz+All rights reserved.++Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.+    * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,11 @@+#!/usr/bin/env runhaskell++-- I usually compile this with "ghc --make -o setup Setup.hs"++import Distribution.Simple(defaultMain)+main = do putStrLn msg+          defaultMain++msg = "regex-tre needs to compile against the libtre libary from http://laurikari.net/tre/\n\+      \You might also need to edit the end of the regex-tre.cabal file to point at\n\+      \the directories where libtre 'include' and 'lib' have been installed.\n"
+ Text/Regex/TRE.hs view
@@ -0,0 +1,64 @@+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-|+The "Text.Regex.TRE" module provides a backend for regular+expressions. To use it should be imported along with+"Text.Regex.Lazy".  If you import this along with other backends, then+you should do so with qualified imports, perhaps renamed for+convenience.++You will need to have libpcre, from <http://www.pcre.org/>, to use+this module.  The haskell must be compiled with -DHAVE_TRE_H and+linked with pcre.  This is the default in the cabal file.++If you do not compile with HAVE_TRE_H then the functions will still+exist, but using them will create a run time error.  You can test for+the existance of TRE by checking 'getVersion' which is 'Nothing' if+not compiled with TRE or 'Just' 'String' if TRE is present.++Using the provided 'CompOption' and 'ExecOption' values and if+'configUTF8' is True, then you might be able to send UTF8 encoded+ByteStrings to TRE and get sensible results.  This is currently+untested.++The regular expression can be provided as a 'ByteString', but it will+be copied and a NUL byte appended unless such a byte is already+present.  Thus the regular expression cannot contain an explicit NUL+byte. The search string is passed as a CStringLen and may contain NUL+bytes and does not need to end in a NUL byte, and is searched in+place.++A 'String' will be converted into a CString or CStringLen for+processing.  Doing this repeatedly will be very inefficient.+-}+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE(getVersion_Text_Regex_TRE+  ,module Text.Regex.Base+  -- ** "Text.Regex.TRE.Wrap", a hsc module+  ,module Text.Regex.TRE.Wrap+  -- ** "Text.Regex.TRE.String", instances only+  ,module Text.Regex.TRE.String+  -- ** "Text.Regex.TRE.Sequence", instances only+  ,module Text.Regex.TRE.Sequence+  -- ** "Text.Regex.TRE.ByteString", instances only+  ,module Text.Regex.TRE.ByteString+  -- ** "Text.Regex.TRE.ByteString.Lazy", instances only+  ,module Text.Regex.TRE.ByteString.Lazy+                     ) where++import Text.Regex.TRE.Wrap(Regex, CompOption(CompOption),+  ExecOption(ExecOption), (=~), (=~~), ReturnCode, WrapError,+  unusedRegOffset, getVersion,+  compBlank, compExtended, compIgnoreCase, compNoSub, compNewline,+  execBlank, execNotBOL, execNotEOL)+import Text.Regex.TRE.String()+import Text.Regex.TRE.Sequence()+import Text.Regex.TRE.ByteString()+import Text.Regex.TRE.ByteString.Lazy()+import Data.Version(Version(..))+import Text.Regex.Base++getVersion_Text_Regex_TRE :: Version+getVersion_Text_Regex_TRE =+  Version { versionBranch = [0,91]+          , versionTags = ["unstable"]+          }
+ Text/Regex/TRE/ByteString.hs view
@@ -0,0 +1,123 @@+{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}+{-|+This exports instances of the high level API and the medium level+API of 'compile','execute', and 'regexec'.+-}+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE.ByteString(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  CompOption(CompOption),+  ExecOption(ExecOption),+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  getVersion,+  -- ** Medium level API functions+  compile,+  execute,+  regexec,+  -- ** CompOption flags+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** ExecOption flags+  execBlank,+  execNotBOL,      -- not at begining of line+  execNotEOL       -- not at end of line+  ) where++import Text.Regex.TRE.Wrap -- all+import Data.Array(Array,listArray)+import Data.ByteString(ByteString)+import qualified Data.ByteString as B(empty,take,drop)+import qualified Data.ByteString.Base as B(unsafeUseAsCStringLen)+import System.IO.Unsafe(unsafePerformIO)+import Foreign.C.String(CStringLen)+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)+import Text.Regex.Base.Impl(polymatch,polymatchM)++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.TRE.ByteString died: "++show err)+                     Right v -> return v++asCStringLen ::  ByteString -> (Foreign.C.String.CStringLen -> IO a) -> IO a+asCStringLen = B.unsafeUseAsCStringLen++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 $+    asCStringLen bs (wrapTest regex) >>= unwrap+  matchOnce regex bs = unsafePerformIO $+    execute regex bs >>= unwrap+  matchAll regex bs = unsafePerformIO $ +    asCStringLen bs (wrapMatchAll regex) >>= unwrap+  matchCount regex bs = unsafePerformIO $ +    asCStringLen bs (wrapCount regex) >>= unwrap++-- ---------------------------------------------------------------------+-- | Compiles a regular expression+--+compile :: CompOption  -- ^ (summed together)+        -> ExecOption  -- ^ (summed together)+        -> ByteString  -- ^ The regular expression to compile+        -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression+compile c e pattern = asCStringLen pattern (wrapCompile c e)++-- ---------------------------------------------------------------------+-- | Matches a regular expression against a buffer, returning the buffer+-- indicies of the match, and any submatches+--+-- | Matches a regular expression against a string+execute :: Regex      -- ^ Compiled regular expression+        -> ByteString -- ^ String to match against+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.+execute regex bs = do+  maybeStartEnd <- asCStringLen bs (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> +      return . Right . Just . listArray (0,pred (length parts))+      . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts++regexec :: Regex      -- ^ Compiled regular expression+        -> ByteString -- ^ String to match against+        -> IO (Either WrapError (Maybe (ByteString, ByteString, ByteString, [ByteString])))+regexec regex bs = do+  let getSub :: (RegOffset,RegOffset) -> ByteString +      getSub (start',stop') | start' == unusedRegOffset = B.empty+                            | otherwise = B.take (stop-start) . B.drop start $ bs+        where (start,stop) = (fromIntegral start', fromIntegral stop') :: (Int,Int)+      matchedParts [] = (B.empty,B.empty,bs,[]) -- no information+      matchedParts ((start',stop'):subStartStop) = +        let (start,stop) = (fromIntegral start', fromIntegral stop')+        in (B.take start bs+           ,getSub (start',stop')+           ,B.drop stop bs+           ,map getSub subStartStop)+  maybeStartEnd <- asCStringLen bs (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> return . Right . Just . matchedParts $ parts++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset
+ Text/Regex/TRE/ByteString/Lazy.hs view
@@ -0,0 +1,115 @@+{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}+{-|+This exports instances of the high level API and the medium level+API of 'compile','execute', and 'regexec'.+-}+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE.ByteString.Lazy(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  CompOption(CompOption),+  ExecOption(ExecOption),+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  getVersion,+  -- ** Medium level API functions+  compile,+  execute,+  regexec,+  -- ** CompOption flags+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** ExecOption flags+  execBlank,+  execNotBOL,      -- not at begining of line+  execNotEOL       -- not at end of line+  ) where++import Text.Regex.TRE.Wrap -- all+import Data.Array(Array)+import qualified Data.ByteString.Lazy as L(ByteString,toChunks,fromChunks)+import qualified Data.ByteString as B(ByteString,concat)+import qualified Data.ByteString.Base as B(unsafeUseAsCStringLen)+import System.IO.Unsafe(unsafePerformIO)+import Foreign.C.String(CStringLen)+import Text.Regex.Base.RegexLike(RegexContext(..),RegexMaker(..),RegexLike(..),MatchOffset,MatchLength)+import qualified Text.Regex.TRE.ByteString as BS(execute,regexec)+import Text.Regex.Base.Impl(polymatch,polymatchM)++instance RegexContext Regex L.ByteString L.ByteString where+  match = polymatch+  matchM = polymatchM++{-# INLINE fromLazy #-}+fromLazy :: L.ByteString -> B.ByteString+fromLazy = B.concat . L.toChunks++{-# INLINE toLazy #-}+toLazy :: B.ByteString -> L.ByteString+toLazy = L.fromChunks . return++unwrap :: (Show e) => Either e v -> IO v+unwrap x = case x of Left err -> fail ("Text.Regex.TRE.ByteString died: "++show err)+                     Right v -> return v++{-# INLINE asCStringLen #-}+asCStringLen :: L.ByteString -> (CStringLen -> IO a) -> IO a+asCStringLen s = B.unsafeUseAsCStringLen (fromLazy s)++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 $+    asCStringLen bs (wrapTest regex) >>= unwrap+  matchOnce regex bs = unsafePerformIO $+    execute regex bs >>= unwrap+  matchAll regex bs = unsafePerformIO $ +    asCStringLen bs (wrapMatchAll regex) >>= unwrap+  matchCount regex bs = unsafePerformIO $ +    asCStringLen bs (wrapCount regex) >>= unwrap++-- ---------------------------------------------------------------------+-- | Compiles a regular expression+--+compile :: CompOption  -- ^ (summed together)+        -> ExecOption  -- ^ (summed together)+        -> L.ByteString  -- ^ The regular expression to compile+        -> IO (Either WrapError Regex) -- ^ Returns: the compiled regular expression+compile c e pattern = asCStringLen pattern (wrapCompile c e)++-- ---------------------------------------------------------------------+-- | Matches a regular expression against a buffer, returning the buffer+-- indicies of the match, and any submatches+--+-- | Matches a regular expression against a string+execute :: Regex      -- ^ Compiled regular expression+        -> L.ByteString -- ^ String to match against+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.+execute regex bs = BS.execute regex (fromLazy bs)++regexec :: Regex      -- ^ Compiled regular expression+        -> L.ByteString -- ^ String to match against+        -> IO (Either WrapError (Maybe (L.ByteString, L.ByteString, L.ByteString, [L.ByteString])))+regexec regex bs = do+  x <- BS.regexec regex (fromLazy bs)+  return $ case x of+             Left e -> Left e+             Right Nothing -> Right Nothing+             Right (Just (a,b,c,ds)) -> Right (Just (toLazy a,toLazy b,toLazy c,map toLazy ds))++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset
+ Text/Regex/TRE/Sequence.hs view
@@ -0,0 +1,129 @@+{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}+{-|+This exports instances of the high level API and the medium level+API of 'compile','execute', and 'regexec'.+-}+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE.Sequence(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  CompOption(CompOption),+  ExecOption(ExecOption),+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  getVersion,+  -- ** Medium level API functions+  compile,+  regexec,+  execute,+  -- ** CompOption flags+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** ExecOption flags+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL     -- not at end of line+  ) where++import Text.Regex.TRE.Wrap -- all+import Data.Array(Array,listArray)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchOffset,MatchLength,Extract(..))+import Text.Regex.Base.Impl(polymatch,polymatchM)+import Data.Sequence as S hiding (length)+import qualified Data.Sequence as S (length)+import Foreign.C.String+import Foreign.Marshal.Array+import Foreign.Marshal.Alloc+import Foreign.Storable++instance RegexContext Regex (Seq Char) (Seq Char) where+  match = polymatch+  matchM = polymatchM++unusedOffset :: Int+unusedOffset = fromIntegral unusedRegOffset++unwrap :: (Show e) => Either e v -> IO v+unwrap x = case x of Left err -> fail ("Text.Regex.TRE.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 $+    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++-- | Compiles a regular expression+compile :: CompOption -- ^ Flags (summed together)+        -> ExecOption -- ^ Flags (summed together)+        -> (Seq Char)     -- ^ The regular expression to compile+        -> IO (Either WrapError Regex) -- ^ Returns: an error string and offset or the compiled regular expression+compile c e pattern = withSeq pattern (wrapCompile c e)++-- | Matches a regular expression against a string+execute :: Regex      -- ^ Compiled regular expression+        -> (Seq Char)     -- ^ (Seq Char) to match against+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.+execute regex str = do+  maybeStartEnd <- withSeq str (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> +      return . Right . Just . listArray (0,pred (length parts))+      . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts+++-- | execute match and extract substrings rather than just offsets+regexec  :: Regex      -- ^ compiled regular expression+         -> (Seq Char)     -- ^ string to match+         -> IO (Either WrapError (Maybe ((Seq Char), (Seq Char),(Seq Char), [(Seq Char)])))+                      -- ^ Returns: Nothing if no match, else+                      --   (text before match, text after match, array of matches with 0 being the whole match)+regexec regex str = do+  let getSub (start',stop') | start == unusedOffset = S.empty+                            | otherwise = extract (start,stop-start) $ str+        where (start,stop) = (fromIntegral start', fromIntegral stop')+      matchedParts [] = (S.empty,S.empty,str,[]) -- no information+      matchedParts ((start',stop'):subStartStop) = +        let matchedStartStop@(start,stop) = (fromIntegral start', fromIntegral stop')+        in (before start str+           ,getSub matchedStartStop+           ,after stop str+           ,map getSub subStartStop)+  maybeStartEnd <- withSeq str (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> return . Right . Just . matchedParts $ parts++withSeq :: Seq Char -> (CStringLen -> IO a) -> IO a+withSeq s f =+  let -- Ensure null at end of s+      len = S.length s+      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,len))+
+ Text/Regex/TRE/String.hs view
@@ -0,0 +1,114 @@+{-# OPTIONS_GHC -fglasgow-exts -fno-warn-orphans #-}+{-|+This exports instances of the high level API and the medium level+API of 'compile','execute', and 'regexec'.+-}+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE.String(+  -- ** Types+  Regex,+  MatchOffset,+  MatchLength,+  CompOption(CompOption),+  ExecOption(ExecOption),+  ReturnCode,+  WrapError,+  -- ** Miscellaneous+  unusedOffset,+  getVersion,+  -- ** Medium level API functions+  compile,+  regexec,+  execute,+  -- ** CompOption flags+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  -- ** ExecOption flags+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL     -- not at end of line+  ) where++import Text.Regex.TRE.Wrap -- all+import Foreign.C.String(withCStringLen)+import Data.Array(Array,listArray)+import System.IO.Unsafe(unsafePerformIO)+import Text.Regex.Base.RegexLike(RegexMaker(..),RegexLike(..),RegexContext(..),MatchOffset,MatchLength)+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.TRE.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 $+    withCStringLen str (wrapTest regex) >>= unwrap+  matchOnce regex str = unsafePerformIO $+    execute regex str >>= unwrap+  matchAll regex str = unsafePerformIO $ +    withCStringLen str (wrapMatchAll regex) >>= unwrap+  matchCount regex str = unsafePerformIO $ +    withCStringLen str (wrapCount regex) >>= unwrap++-- | Compiles a regular expression+compile :: CompOption -- ^ Flags (summed together)+        -> ExecOption -- ^ Flags (summed together)+        -> String     -- ^ The regular expression to compile+        -> IO (Either WrapError Regex) -- ^ Returns: an error string and offset or the compiled regular expression+compile c e pattern = withCStringLen pattern (wrapCompile c e)++-- | Matches a regular expression against a string+execute :: Regex      -- ^ Compiled regular expression+        -> String     -- ^ String to match against+        -> IO (Either WrapError (Maybe (Array Int (MatchOffset,MatchLength))))+                -- ^ Returns: 'Nothing' if the regex did not match the+                -- string, or:+                --   'Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions.+execute regex str = do+  maybeStartEnd <- withCStringLen str (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> +      return . Right . Just . listArray (0,pred (length parts))+      . map (\(s,e)->(fromIntegral s, fromIntegral (e-s))) $ parts+++-- | execute match and extract substrings rather than just offsets+regexec  :: Regex      -- ^ compiled regular expression+         -> String     -- ^ string to match+         -> IO (Either WrapError (Maybe (String, String,String, [String])))+                      -- ^ Returns: Nothing if no match, else+                      --   (text before match, text after match, array of matches with 0 being the whole match)+regexec regex str = do+  let getSub (start',stop') | start == unusedOffset = ""+                            | otherwise = take (stop-start) . drop start $ str+        where (start,stop) = (fromIntegral start', fromIntegral stop')+      matchedParts [] = ("","",str,[]) -- no information+      matchedParts ((start',stop'):subStartStop) = +        let matchedStartStop@(start,stop) = (fromIntegral start', fromIntegral stop')+        in (take start str+           ,getSub matchedStartStop+           ,drop stop str+           ,map getSub subStartStop)+  maybeStartEnd <- withCStringLen str (wrapMatch regex)+  case maybeStartEnd of+    Left err -> return (Left err)+    Right Nothing -> return (Right Nothing)+    Right (Just parts) -> return . Right . Just . matchedParts $ parts
+ Text/Regex/TRE/Wrap.hsc view
@@ -0,0 +1,385 @@+{-# OPTIONS_GHC  -fglasgow-exts -fffi -fno-warn-unused-imports #-}+-- | http://laurikari.net/tre/index.html http://laurikari.net/tre/api.html+-- +-- This will fail or error only if allocation fails or a nullPtr is passed in.+{- Copyright   :  (c) Chris Kuklewicz 2007 -}+module Text.Regex.TRE.Wrap(+  -- ** High-level interface+  Regex,+  CompOption(CompOption),+  ExecOption(ExecOption),+  (=~),+  (=~~),++  -- ** Low-level interface+  RegOffset,+  ReturnCode(ReturnCode),+  WrapError,+  wrapCompile,+  wrapTest,+  wrapMatch,+  wrapMatchAll,+  wrapCount,++  -- ** Miscellaneous+  getVersion,+  getNumSubs,+  unusedRegOffset,++  -- ** CompOption values+  compBlank,+  compExtended,   -- use extended regex syntax+  compIgnoreCase, -- ignore case when matching+  compNoSub,      -- no substring matching needed+  compNewline,    -- '.' doesn't match newline+  compRightAssoc, -- flip from left to right assoc++  -- ** ExecOption values+  execBlank,+  execNotBOL,     -- not at begining of line+  execNotEOL,     -- not at end of line++  -- ** ReturnCode values+  retOk,+  retBadbr,+  retBadpat,+  retBadrpt,+  retEcollate,+  retEctype,+  retEescape,+  retEsubreg,+  retEbrack,+  retEparen,+  retEbrace,+  retErange,+  retEspace+  ) where++#if defined(HAVE_TRE_H)+import Control.Monad(when)+import Data.Int+import Data.Array(listArray)+import Data.Bits(Bits((.|.))) -- ((.&.),(.|.),complement))+import Foreign+import Foreign.C(CInt,CChar,CSize)+import Foreign.C.String(CString,CStringLen,peekCString)+import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)+#else+import Data.Array(Array)+import Data.Bits(Bits)+import Foreign(ForeignPtr)+import Foreign.C(CInt)+import Foreign.C.String(CString,CStringLen)+import Text.Regex.Base.RegexLike(RegexOptions(..),RegexMaker(..),RegexContext(..),MatchArray)+#endif+++-- | return version of libtre used or Nothing if libtre is not available.+getVersion :: Maybe String++type CRegMatch = () -- dummy regmatch_t used below to read out so and eo values+type Regex_t = () -- regex_t placeholder+type RegOffset = (#type regoff_t)++newtype CompOption = CompOption CInt deriving (Eq,Show,Num,Bits)+newtype ExecOption = ExecOption CInt deriving (Eq,Show,Num,Bits)+newtype ReturnCode = ReturnCode CInt deriving (Eq,Show)++-- | A compiled regular expression+data Regex = Regex (ForeignPtr Regex_t) CompOption ExecOption++type WrapError = (ReturnCode,String)++wrapCompile :: CompOption -- ^ Flags (summed together)+            -> ExecOption -- ^ Flags (summed together)+            -> CStringLen  -- ^ The regular expression to compile+            -> IO (Either WrapError Regex) -- ^ Returns: an error offset and string or the compiled regular expression+wrapTest :: Regex       -- ^ Compiled regular expression+         -> CStringLen  -- ^ String to match against and length in bytes+         -> IO (Either WrapError Bool)+wrapMatch :: Regex       -- ^ Compiled regular expression+          -> CStringLen  -- ^ String to match against and length in bytes+          -> IO (Either WrapError (Maybe [(RegOffset,RegOffset)]))+                -- ^ Returns: 'Right Nothing' if the regex did not match the+                -- string, or:+                --   'Right Just' an array of (offset,length) pairs where index 0 is whole match, and the rest are the captured subexpressions, or:+                --   'Left WrapError' if there is some strange error+wrapMatchAll :: Regex -> CStringLen -> IO (Either WrapError [ MatchArray ])+wrapCount :: Regex -> CStringLen -> IO (Either WrapError Int)+getNumSubs :: Regex -> Int++(=~)  :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target)+      => source1 -> source -> target+(=~~) :: (RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m)+      => source1 -> source -> m target++compBlank :: CompOption+execBlank :: ExecOption+unusedRegOffset :: RegOffset+retOk :: ReturnCode++#if defined(HAVE_TRE_H)+#include <tre/regex.h>++compBlank = CompOption 0+execBlank = ExecOption 0+unusedRegOffset = (-1)+retOk = ReturnCode 0++fi :: (Integral i,Num n ) => i -> n+fi x = fromIntegral x++{-# INLINE getNumSubs #-}+getNumSubs (Regex r _ _) = fi . unsafePerformIO $ withForeignPtr r getNumSubs'++getNumSubs' :: Ptr Regex_t -> IO CSize+{-# INLINE getNumSubs' #-}+getNumSubs' x = (#peek regex_t,re_nsub) x++size_Regex_t :: Int+size_Regex_t = (#size regex_t)++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 q :: Regex+               q = makeRegex r+           in match q x++-- (=~~) ::(RegexMaker Regex CompOption ExecOption source,RegexContext Regex source1 target,Monad m) => source1 -> source -> m target+(=~~) x r = do (q :: Regex) <- makeRegexM r+               matchM q x++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++wrapRC :: ReturnCode -> IO (Either WrapError b)+{-# INLINE wrapRC #-}+wrapRC r = return (Left (r,"Error in Text.Regex.TRE.Wrap: "++show r))++-- | Compiles a regular expression+wrapCompile flags e (pattern,len) = do+ nullTest pattern "wrapCompile pattern" $ do+  fregex <- newForeignPtr finalizerFree =<< mallocBytes size_Regex_t+  withForeignPtr fregex $ \regex -> do+    if regex == nullPtr+      then return (Left (retOk,"Could not malloc regex in Text.Regex.TRE.Wrap.wrapCompile"))+      else do+        ret <- c_regncomp regex pattern (fi len) flags+        if ret == retOk+          then return (Right (Regex fregex flags e))+          else wrapRC ret++wrapTest (Regex fregex _ flags) (cstr,len) = do+ nullTest cstr "wrapTest cstr" $ do+  withForeignPtr fregex $ \regex -> do+    r@(ReturnCode r') <- c_regnexec regex cstr (fi len) 0 nullPtr flags+    if r == retNoMatch+      then return (Right False)+      else if r' < 0+             then wrapRC r+             else return (Right True)++-- | Matches a regular expression against a string+wrapMatch (Regex fregex _ flags) (cstr,len) = do+ nullTest cstr "wrapMatch cstr" $ do+  withForeignPtr fregex $ \regex -> do+    nsub <- getNumSubs' regex+    let nmatch = 1 + fi nsub+        pmatch_bytes = nmatch * (#size regmatch_t)+    allocaBytes pmatch_bytes $ \pmatch -> do+      r@(ReturnCode r') <- c_regnexec regex cstr (fi len) (succ nsub) pmatch flags+      if r == retNoMatch+        then return (Right Nothing)+        else if r' < 0+          then wrapRC r+          else do+            regions <- mapM getOffsets . take nmatch+                       . iterate (`plusPtr` (#size regmatch_t)) $ pmatch+            return (Right (Just regions)) -- regions will not be []++-- | wrapMatchAll is an improvement over wrapMatch since it only+-- allocates memory with allocaBytes once at the start.+-- +-- +wrapMatchAll (Regex fregex _ flags) full_source = do+ nullTest (fst full_source) "wrapMatchAll source" $ do+  withForeignPtr fregex $ \regex -> do+    nsub <- getNumSubs' regex+    let nmatch = 1 + fi nsub+        pmatch_bytes = (nmatch) * (#size regmatch_t)+        flags' = (execNotBOL .|. flags)+    allocaBytes pmatch_bytes $ \pmatch ->+      let loop acc flags_in_use (source,len) pos | pos `seq` len `seq` source `seq` False = undefined+                                                 | otherwise  = do+            r@(ReturnCode r') <- c_regnexec regex source (fi len) (succ nsub) pmatch flags_in_use+            if r == retNoMatch+              then return (Right (acc []))+              else if r' < 0+                then wrapRC r+                else do+                  start_ends <- mapM getOffsets . take nmatch+                                . iterate (`plusPtr` (#size regmatch_t)) $ pmatch+                  let start_offs = map (\(s,e) -> (pos + fi s,fi (e-s))) start_ends :: [(Int,Int)]+                      arr = listArray (0,fi nsub) start_offs+                      acc' = acc . (arr:)+                      delta = fi (snd (head start_ends)) :: Int+                      pos' = pos + delta  :: Int+                      source' = plusPtr source delta :: CString+                      len' = len - delta :: Int+                  if (arr `seq` delta) == 0+                    then return (Right (acc' []))+                    else loop acc' flags' (source',len') pos'+      in loop id flags full_source 0++getOffsets :: Ptr CRegMatch -> IO (RegOffset,RegOffset)+getOffsets p_match = do+  start <- (#peek regmatch_t, rm_so) p_match :: IO RegOffset+  end   <- (#peek regmatch_t, rm_eo) p_match :: IO RegOffset+  return (start,end)++wrapCount (Regex fregex _ flags) (in_source,in_len) = do+ nullTest in_source "wrapCount source" $ do+  withForeignPtr fregex $ \regex -> +    allocaBytes (#size regmatch_t) $ \pmatch -> do+     nullTest pmatch "wrapCount pmatch" $+      let flags' = (execNotBOL .|. flags)+          loop flags_in_use (source,len) count | count `seq` False = undefined+                                               | otherwise = do+            r@(ReturnCode r') <- c_regnexec regex source len 1 pmatch flags_in_use+            if r == retNoMatch+              then return (Right count)+              else if r'<0+                then wrapRC r+                else do+                  (start,end) <- getOffsets pmatch+                  --  (start == unusedRegOffset) check omitted+                  let len' = len - fi end+                      source' = plusPtr source (fi end)+                  if end > start+                    then loop flags' (source',len') (succ count)+                    else return (Right (succ count))+      in loop flags (in_source,fi in_len) 0++getVersion = unsafePerformIO $ do+  version <- c_tre_version+  if version == nullPtr+    then return (Just "tre_version was null")+    else return . Just =<< peekCString version++foreign import ccall unsafe "tre/regex.h regncomp"+  c_regncomp :: Ptr Regex_t -> CString -> CSize -> CompOption+             -> IO ReturnCode++foreign import ccall unsafe "tre/regex.h tre_version"+  c_tre_version :: IO (Ptr CChar)++foreign import ccall unsafe "tre/regex.h regnexec"+  c_regnexec :: Ptr Regex_t -> CString -> CSize +             -> CSize -> Ptr CRegMatch -> ExecOption+             -> IO ReturnCode++{-+newtype InfoWhat = InfoWhat CInt deriving (Eq,Show)+newtype ConfigWhat = ConfigWhat CInt deriving (Eq,Show)++foreign import ccall unsafe "tre/regex.h tre_config"+  c_tre_config :: ConfigWhat -> Ptr a+               -> IO ReturnCode+-}+++-- 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, \+  compRightAssoc = REG_RIGHT_ASSOC++-- 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++#else /* do not HAVE_TRE_H */++instance RegexOptions Regex CompOption ExecOption where+  blankCompOpt = err+  blankExecOpt = err+  defaultCompOpt = err+  defaultExecOpt = err+  getExecOpts = err+  setExecOpts = err++msg :: String+msg = "WrapTre.hsc was not compiled against libtre regex library with HAVE_TRE_H defined"+err :: a+err = error msg++(=~) = err+(=~~) = err++-- Hack to avoid the constructor from being unused+wrapCompile _ _ _ = err >> return (Right (Regex err err err))+wrapTest = err+wrapMatch = err+wrapMatchAll = err+wrapCount = err++compExtended,compIgnoreCase,compNoSub,compNewline :: CompOption+compBlank = err+compExtended = err+compIgnoreCase = err+compNoSub = err+compNewline = err+execNotBOL,execNotEOL :: ExecOption+execBlank = err+execNotBOL = err+execNotEOL = err++retBadbr, retBadpat, retBadrpt, retEcollate, retEctype, retEescape, retEsubreg, retEbrack, retEparen, retEbrace, retErange, retEspace :: ReturnCode+retBadbr = err+retBadpat = err+retBadrpt = err+retEcollate = err+retEctype = err+retEescape = err+retEsubreg = err+retEbrack = err+retEparen = err+retEbrace = err+retErange = err+retEspace = err++getVersion = Nothing++#endif /* HAVE_TRE_H */
+ regex-tre.cabal view
@@ -0,0 +1,44 @@+Name:                   regex-tre+Version:                0.91+-- Cabal-Version:       >=1.1.4+License:                BSD3+License-File:           LICENSE+Copyright:              Copyright (c) 2006, 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-tre/+Synopsis:               Replaces/Enhances Text.Regex+Description:            The TRE backend to accompany regex-base+Category:               Text+Tested-With:            GHC+Build-Depends:          base >= 2.0, regex-base >= 0.80+-- Data-Files:+-- Extra-Source-Files:+-- Extra-Tmp-Files:+Exposed-Modules:        Text.Regex.TRE+                        Text.Regex.TRE.Wrap+                        Text.Regex.TRE.String+                        Text.Regex.TRE.Sequence+                        Text.Regex.TRE.ByteString+                        Text.Regex.TRE.ByteString.Lazy+Buildable:              True+-- Other-Modules:+-- HS-Source-Dirs:         "."+-- Extensions:+Extensions:             MultiParamTypeClasses, FunctionalDependencies+-- GHC-Options:            -Wall -Werror+GHC-Options:            -Wall -Werror -O2+-- GHC-Options:            -Wall -ddump-minimal-imports+-- GHC-Prof-Options: +-- Hugs-Options:+-- NHC-Options:+-- Includes:+-- C-Sources:+-- LD-Options:+-- Frameworks:+CC-Options:             -DHAVE_TRE_H+Extra-Libraries:        tre+-- Include-Dirs:           /opt/local/include+-- Extra-Lib-Dirs:         /opt/local/lib