module Matchers.Pcre.Base
( CaseSensitive(..)
, PCRE
, compile
, exec
) where
import Foreign.Storable
import Foreign.C
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.ForeignPtr.Safe
import Foreign.Ptr
import Data.ByteString
import Data.Text
import Data.Text.Encoding
data CaseSensitive = Sensitive | Insensitive
deriving (Eq, Ord, Show)
caseless :: CInt
caseless = 1
data PCREData
instance Show PCREData where
show _ = "PCREData"
data PCRE_Extra
instance Show PCRE_Extra where
show _ = "PCRE_Extra"
foreign import ccall unsafe "stdlib.h &free"
c_free :: FunPtr (Ptr a -> IO ())
foreign import ccall unsafe "pcre.h pcre_compile"
c_pcre_compile
:: CString
-> CInt
-> Ptr CString
-> Ptr CInt
-> Ptr CUChar
-> IO (Ptr PCREData)
foreign import ccall unsafe "pcre.h pcre_exec"
c_pcre_exec
:: Ptr PCREData
-> Ptr PCRE_Extra
-> CString
-> CInt
-> CInt
-> CInt
-> Ptr CInt
-> CInt
-> IO CInt
pcre_compile
:: CaseSensitive
-> Text
-> IO (Either String (Ptr PCREData))
pcre_compile cl pat
= useAsCString (encodeUtf8 pat) $ \patC ->
alloca $ \ptrMsg ->
alloca $ \ptrOffset -> do
let cOpt = if cl == Insensitive then caseless else 0
ptrPcre <- c_pcre_compile patC cOpt ptrMsg ptrOffset nullPtr
if ptrPcre == nullPtr
then do
ptrErr <- peek ptrMsg
msg <- peekCAString ptrErr
return . Left $ msg
else return . Right $ ptrPcre
pcre_exec :: Ptr PCREData -> Text -> IO (Maybe Bool)
pcre_exec ptr txt
= useAsCStringLen (encodeUtf8 txt) $ \(ptrSubj, len) ->
allocaArray 30 $ \array -> do
r <- c_pcre_exec ptr nullPtr ptrSubj (fromIntegral len)
0 0 array 30
return $ case () of
_ | r == (1) -> Just False
| r < (1) -> Nothing
| otherwise -> Just True
newtype PCRE = PCRE (ForeignPtr PCREData)
deriving Show
compile :: CaseSensitive -> Text -> IO (Either String PCRE)
compile cl pat = do
ei <- pcre_compile cl pat
case ei of
Left e -> return . Left $ e
Right ptr -> do
fp <- newForeignPtr c_free ptr
return . Right $ PCRE fp
exec :: PCRE -> Text -> IO (Maybe Bool)
exec (PCRE fp) s = withForeignPtr fp $ \p -> pcre_exec p s