module RRegex.PCRE (
Regex,
compile,
execute,
executeExtract,
pcreCaseless,
pcreMultiline,
pcreDotall,
pcreExtended,
pcreAnchored,
pcreDollarEndonly,
pcreExtra,
pcreNotbol,
pcreNoteol,
pcreUngreedy,
pcreNotempty,
pcreUtf8,
numSubs,
getVersion
) where
import Data.Generics.Basics
import Prelude
import Foreign
import Foreign.C
import Foreign.C.String
import Array
import Data.Typeable
getVersion :: Maybe String
data PCRE = PCRE
deriving (Typeable, Data)
_PCRE :: PCRE
_PCRE = PCRE
newtype Regex = Regex (ForeignPtr PCRE)
deriving (Show, Eq, Ord, Data)
instance Typeable Regex where typeOf _ = mkTyConApp (mkTyCon "Regex") []
fi :: (Num b, Integral a) => a -> b
fi x = fromIntegral x
compile
:: String
-> Int
-> IO (Either (Int,String) Regex)
compile pattern flags = withCString pattern $ \cstr ->
alloca $ \errOffset -> alloca $ \errPtr -> do
v <- c_pcre_compile cstr (fromIntegral flags) errPtr errOffset nullPtr
if v == nullPtr then do
es <- peek errPtr >>= peekCString
eo <- peek errOffset
return $ Left (fi eo,es)
else fmap (Right . Regex) (newForeignPtr_ v)
numSubs :: Regex -> IO Int
numSubs (Regex pcre_fptr) = withForeignPtr pcre_fptr $ \pcre_ptr -> do
nsub <- getNumSubs pcre_ptr
return $ fromIntegral nsub
getNumSubs :: Ptr PCRE -> IO CInt
getNumSubs (pcre_ptr) =
alloca $ \st -> do
c_pcre_fullinfo pcre_ptr nullPtr (fi pcreInfoCapturecount) (st :: Ptr CInt)
peek st
execute :: Regex
-> String
-> Int
-> IO (Maybe (Array Int (Int,Int)))
execute (Regex pcre_fptr) str _ = withCStringLen str $ \(cstr,clen) ->
withForeignPtr pcre_fptr $ \pcre_ptr -> do
nsub <- getNumSubs pcre_ptr
let nsub_int = fromIntegral ((nsub + 1) * 3)
allocaBytes (nsub_int * (4)) $ \p_match -> do
r <- c_pcre_exec pcre_ptr nullPtr cstr (fi clen) 0 0 p_match (fi nsub_int)
if r < 0 then return Nothing else do
ri <- mapM (peekElemOff p_match) [0 .. fi r*2 1]
let f [] = []
f (a:b:rest) = (fromIntegral a,fromIntegral (b a)):f rest
f _ = error "unmatched pair"
let ex = fi $ nsub + 1 r
return $ Just (listArray (0,fi nsub) ((f ri) ++ replicate ex (1,0)))
executeExtract :: Regex
-> String
-> Int
-> IO (Maybe (String, String, (Array Int String)))
executeExtract pcre str flags = do
a <- execute pcre str flags
case a of
Nothing -> return Nothing
Just a -> return $ Just (before,after,fmap f a) where
(bo, bl) = a ! 0
before = take bo str
after = drop (bo + bl) str
f (o,l) = take l (drop o str)
getVersion = unsafePerformIO $ do
s <- c_pcre_version
hs <- peekCString s
return $ Just hs
foreign import ccall unsafe "pcre_compile"
c_pcre_compile :: Ptr CChar -> CInt -> Ptr (Ptr CChar) -> Ptr CInt -> Ptr CChar -> IO (Ptr PCRE)
foreign import ccall unsafe "pcre_exec"
c_pcre_exec :: Ptr PCRE -> Ptr () -> Ptr CChar -> CInt -> CInt -> CInt -> Ptr CInt -> CInt -> IO CInt
foreign import ccall unsafe "pcre_fullinfo"
c_pcre_fullinfo :: Ptr PCRE -> Ptr () -> CInt -> Ptr a -> IO CInt
foreign import ccall unsafe "pcre_version"
c_pcre_version :: IO (Ptr CChar)
pcreCaseless :: Int
pcreCaseless = 1
pcreMultiline :: Int
pcreMultiline = 2
pcreDotall :: Int
pcreDotall = 4
pcreExtended :: Int
pcreExtended = 8
pcreAnchored :: Int
pcreAnchored = 16
pcreDollarEndonly :: Int
pcreDollarEndonly = 32
pcreExtra :: Int
pcreExtra = 64
pcreNotbol :: Int
pcreNotbol = 128
pcreNoteol :: Int
pcreNoteol = 256
pcreUngreedy :: Int
pcreUngreedy = 512
pcreNotempty :: Int
pcreNotempty = 1024
pcreUtf8 :: Int
pcreUtf8 = 2048
pcreInfoCapturecount :: Int
pcreInfoCapturecount = 2