{-# LANGUAGE MagicHash, BangPatterns #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Text.Regex.PCRE.Rex
-- Copyright   :  (c) Michael Sloan 2011
--
-- Maintainer  :  Michael Sloan (mgsloan@gmail.com)
-- Stability   :  unstable
-- Portability :  unportable
-- 
-- This module provides support for accessing the compiled representation of
-- PCRE regular expressions.  This byte array encodes a lookup-table based
-- representation for the regular expression, and can be safely written
-- out and read back by compatible PCRE versions.
--
-----------------------------------------------------------------------------

module Text.Regex.PCRE.Precompile where

import Control.Monad            (liftM)
import Data.ByteString.Char8    (ByteString, packCStringLen)
import Data.ByteString.Internal (toForeignPtr)
import Foreign.C.Types          (CSize)
import Foreign.ForeignPtr       (withForeignPtr)
import Foreign.Ptr              (nullPtr, castPtr)
import Foreign.Marshal          (alloca)
import Foreign.Storable         (peek)
import GHC.Exts                 (Int(..), plusAddr#)
import GHC.ForeignPtr           (ForeignPtr(..))
import Text.Regex.PCRE.Light
import Text.Regex.PCRE.Light.Base

-- | A synonym indicating which ByteStrings represent PCRE-format compiled data.
type CompiledBytes = ByteString

-- | Compiles the given regular expression, and assuming nothing bad happens,
-- yields the bytestring filled with PCRE's compiled representation.
precompile :: ByteString -> [PCREOption] -> IO (Maybe CompiledBytes)
precompile :: ByteString -> [PCREOption] -> IO (Maybe ByteString)
precompile ByteString
pat [PCREOption]
opts = Regex -> IO (Maybe ByteString)
regexToTable (Regex -> IO (Maybe ByteString)) -> Regex -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ ByteString -> [PCREOption] -> Regex
compile ByteString
pat [PCREOption]
opts

-- | Takes a compiled regular expression, and if successful, yields the
-- compiled representation.
regexToTable :: Regex -> IO (Maybe CompiledBytes)
regexToTable :: Regex -> IO (Maybe ByteString)
regexToTable (Regex ForeignPtr PCRE
p ByteString
_) =
  ForeignPtr PCRE
-> (Ptr PCRE -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PCRE
p ((Ptr PCRE -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr PCRE -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr PCRE
pcre -> (Ptr CSize -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CSize -> IO (Maybe ByteString)) -> IO (Maybe ByteString))
-> (Ptr CSize -> IO (Maybe ByteString)) -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ \Ptr CSize
res -> do
    CInt
success <- Ptr PCRE -> Ptr PCRE -> CInt -> Ptr CSize -> IO CInt
forall a. Ptr PCRE -> Ptr PCRE -> CInt -> Ptr a -> IO CInt
c_pcre_fullinfo Ptr PCRE
pcre Ptr PCRE
forall a. Ptr a
nullPtr CInt
info_size Ptr CSize
res
    Int
len <- Int -> IO Int
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> IO Int) -> (CSize -> Int) -> CSize -> IO Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CSize -> IO Int) -> IO CSize -> IO Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< (Ptr CSize -> IO CSize
forall a. Storable a => Ptr a -> IO a
peek Ptr CSize
res :: IO CSize)
    if CInt
success CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
>= CInt
0 
      then (ByteString -> Maybe ByteString)
-> IO ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (IO ByteString -> IO (Maybe ByteString))
-> IO ByteString -> IO (Maybe ByteString)
forall a b. (a -> b) -> a -> b
$ CStringLen -> IO ByteString
packCStringLen (Ptr PCRE -> Ptr CChar
forall a b. Ptr a -> Ptr b
castPtr Ptr PCRE
pcre, Int
len)
      else Maybe ByteString -> IO (Maybe ByteString)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ByteString
forall a. Maybe a
Nothing

-- | Creates a regular expression from the compiled representation.
regexFromTable :: CompiledBytes  -> IO Regex
regexFromTable :: ByteString -> IO Regex
regexFromTable ByteString
bytes =
  Regex -> IO Regex
forall (m :: * -> *) a. Monad m => a -> m a
return (Regex -> IO Regex) -> Regex -> IO Regex
forall a b. (a -> b) -> a -> b
$ ForeignPtr PCRE -> ByteString -> Regex
Regex (Addr# -> ForeignPtrContents -> ForeignPtr PCRE
forall a. Addr# -> ForeignPtrContents -> ForeignPtr a
ForeignPtr (Addr# -> Int# -> Addr#
plusAddr# Addr#
addr Int#
offset) ForeignPtrContents
content) ByteString
bytes
 where
  !(ForeignPtr Addr#
addr ForeignPtrContents
content, I# Int#
offset, Int
_) = ByteString -> (ForeignPtr Word8, Int, Int)
toForeignPtr ByteString
bytes