{-# LANGUAGE CPP #-}
module Text.Regex.PCRE.Light (
Regex
, compile, compileM
, match
, captureCount
, captureNames
, PCREOption
, anchored
, auto_callout
, caseless
, dollar_endonly
, dotall
, dupnames
, extended
, extra
, firstline
, multiline
, newline_cr
, newline_crlf
, newline_lf
, no_auto_capture
, ungreedy
, utf8
, no_utf8_check
, PCREExecOption
, exec_anchored
, exec_newline_cr
, exec_newline_crlf
, exec_newline_lf
, exec_notbol
, exec_noteol
, exec_notempty
, exec_no_utf8_check
, exec_partial
) where
import Text.Regex.PCRE.Light.Base
import qualified Data.ByteString as S
#if __GLASGOW_HASKELL__ >= 608
import qualified Data.ByteString.Internal as S
import qualified Data.ByteString.Unsafe as S
#else
import qualified Data.ByteString.Base as S
#endif
import System.IO.Unsafe (unsafePerformIO)
import Data.List (sortBy)
import Data.Function (on)
import Foreign (newForeignPtr, withForeignPtr)
import Foreign.Ptr
import Foreign.C.Types
import Foreign.C.String
import Foreign.Storable
import Foreign.Marshal.Alloc
compile :: S.ByteString -> [PCREOption] -> Regex
compile :: ByteString -> [PCREOption] -> Regex
compile ByteString
s [PCREOption]
o = case ByteString -> [PCREOption] -> Either String Regex
compileM ByteString
s [PCREOption]
o of
Right Regex
r -> Regex
r
Left String
e -> String -> Regex
forall a. HasCallStack => String -> a
error (String
"Text.Regex.PCRE.Light: Error in regex: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
e)
compileM :: S.ByteString -> [PCREOption] -> Either String Regex
compileM :: ByteString -> [PCREOption] -> Either String Regex
compileM ByteString
str [PCREOption]
os = IO (Either String Regex) -> Either String Regex
forall a. IO a -> a
unsafePerformIO (IO (Either String Regex) -> Either String Regex)
-> IO (Either String Regex) -> Either String Regex
forall a b. (a -> b) -> a -> b
$
ByteString
-> (Ptr CChar -> IO (Either String Regex))
-> IO (Either String Regex)
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
S.useAsCString ByteString
str ((Ptr CChar -> IO (Either String Regex))
-> IO (Either String Regex))
-> (Ptr CChar -> IO (Either String Regex))
-> IO (Either String Regex)
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
pattern -> do
(Ptr (Ptr CChar) -> IO (Either String Regex))
-> IO (Either String Regex)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr (Ptr CChar) -> IO (Either String Regex))
-> IO (Either String Regex))
-> (Ptr (Ptr CChar) -> IO (Either String Regex))
-> IO (Either String Regex)
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr CChar)
errptr -> do
(Ptr CInt -> IO (Either String Regex)) -> IO (Either String Regex)
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CInt -> IO (Either String Regex))
-> IO (Either String Regex))
-> (Ptr CInt -> IO (Either String Regex))
-> IO (Either String Regex)
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
erroffset -> do
Ptr PCRE
pcre_ptr <- Ptr CChar
-> PCREOption
-> Ptr (Ptr CChar)
-> Ptr CInt
-> Ptr Word8
-> IO (Ptr PCRE)
c_pcre_compile Ptr CChar
pattern ([PCREOption] -> PCREOption
combineOptions [PCREOption]
os) Ptr (Ptr CChar)
errptr Ptr CInt
erroffset Ptr Word8
forall a. Ptr a
nullPtr
if Ptr PCRE
pcre_ptr Ptr PCRE -> Ptr PCRE -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr PCRE
forall a. Ptr a
nullPtr
then do
String
err <- Ptr CChar -> IO String
peekCString (Ptr CChar -> IO String) -> IO (Ptr CChar) -> IO String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr (Ptr CChar) -> IO (Ptr CChar)
forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr CChar)
errptr
Either String Regex -> IO (Either String Regex)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Either String Regex
forall a b. a -> Either a b
Left String
err)
else do
ForeignPtr PCRE
reg <- FinalizerPtr PCRE -> Ptr PCRE -> IO (ForeignPtr PCRE)
forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
newForeignPtr FinalizerPtr PCRE
forall a. FinalizerPtr a
c_pcre_free Ptr PCRE
pcre_ptr
Either String Regex -> IO (Either String Regex)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Regex -> Either String Regex
forall a b. b -> Either a b
Right (ForeignPtr PCRE -> ByteString -> Regex
Regex ForeignPtr PCRE
reg ByteString
str))
match :: Regex -> S.ByteString -> [PCREExecOption] -> Maybe [S.ByteString]
match :: Regex -> ByteString -> [PCREExecOption] -> Maybe [ByteString]
match (Regex ForeignPtr PCRE
pcre_fp ByteString
_) ByteString
subject [PCREExecOption]
os = IO (Maybe [ByteString]) -> Maybe [ByteString]
forall a. IO a -> a
unsafePerformIO (IO (Maybe [ByteString]) -> Maybe [ByteString])
-> IO (Maybe [ByteString]) -> Maybe [ByteString]
forall a b. (a -> b) -> a -> b
$ do
ForeignPtr PCRE
-> (Ptr PCRE -> IO (Maybe [ByteString])) -> IO (Maybe [ByteString])
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PCRE
pcre_fp ((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 -> do
Int
n_capt <- Ptr PCRE -> CInt -> IO Int
forall {b}. Num b => Ptr PCRE -> CInt -> IO b
fullInfoInt Ptr PCRE
pcre_ptr CInt
info_capturecount
let ovec_size :: Int
ovec_size = (Int
n_capt Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
3
ovec_bytes :: Int
ovec_bytes = Int
ovec_size Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
size_of_cint
Int
-> (Ptr CInt -> IO (Maybe [ByteString])) -> IO (Maybe [ByteString])
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
ovec_bytes ((Ptr CInt -> IO (Maybe [ByteString])) -> IO (Maybe [ByteString]))
-> (Ptr CInt -> IO (Maybe [ByteString])) -> IO (Maybe [ByteString])
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
ovec -> do
let (ForeignPtr Word8
str_fp, Int
off, Int
len) = ByteString -> (ForeignPtr Word8, Int, Int)
S.toForeignPtr ByteString
subject
ForeignPtr Word8
-> (Ptr Word8 -> IO (Maybe [ByteString]))
-> IO (Maybe [ByteString])
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr Word8
str_fp ((Ptr Word8 -> IO (Maybe [ByteString])) -> IO (Maybe [ByteString]))
-> (Ptr Word8 -> IO (Maybe [ByteString]))
-> IO (Maybe [ByteString])
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
cstr -> do
let exec :: Ptr Word8 -> a -> IO CInt
exec Ptr Word8
csub a
clen = Ptr PCRE
-> Ptr PCRE
-> Ptr Word8
-> CInt
-> CInt
-> PCREExecOption
-> Ptr CInt
-> CInt
-> IO CInt
c_pcre_exec
Ptr PCRE
pcre_ptr
Ptr PCRE
forall a. Ptr a
nullPtr
Ptr Word8
csub
(a -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
clen)
CInt
0
([PCREExecOption] -> PCREExecOption
combineExecOptions [PCREExecOption]
os)
Ptr CInt
ovec
(Int -> CInt
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
ovec_size)
CInt
r <- if Ptr Word8
cstr Ptr Word8 -> Ptr Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr Word8
forall a. Ptr a
nullPtr
then Int -> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
1 ((Ptr Word8 -> IO CInt) -> IO CInt)
-> (Ptr Word8 -> IO CInt) -> IO CInt
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
buf -> Ptr Word8 -> Integer -> IO CInt
forall {a}. Integral a => Ptr Word8 -> a -> IO CInt
exec Ptr Word8
buf Integer
0
else Ptr Word8 -> Int -> IO CInt
forall {a}. Integral a => Ptr Word8 -> a -> IO CInt
exec (Ptr Word8
cstr Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
off) Int
len
if CInt
r CInt -> CInt -> Bool
forall a. Ord a => a -> a -> Bool
< CInt
0
then Maybe [ByteString] -> IO (Maybe [ByteString])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe [ByteString]
forall a. Maybe a
Nothing
else let loop :: CInt -> Int -> [ByteString] -> IO (Maybe [ByteString])
loop CInt
n Int
o [ByteString]
acc =
if CInt
n CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
r
then Maybe [ByteString] -> IO (Maybe [ByteString])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([ByteString] -> Maybe [ByteString]
forall a. a -> Maybe a
Just ([ByteString] -> [ByteString]
forall a. [a] -> [a]
reverse [ByteString]
acc))
else do
CInt
i <- Ptr CInt -> Int -> IO CInt
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr CInt
ovec (Int -> IO CInt) -> Int -> IO CInt
forall a b. (a -> b) -> a -> b
$! Int
o
CInt
j <- Ptr CInt -> Int -> IO CInt
forall a. Storable a => Ptr a -> Int -> IO a
peekElemOff Ptr CInt
ovec (Int
oInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
let s :: ByteString
s = CInt -> CInt -> ByteString -> ByteString
substring CInt
i CInt
j ByteString
subject
ByteString
s ByteString -> IO (Maybe [ByteString]) -> IO (Maybe [ByteString])
forall a b. a -> b -> b
`seq` CInt -> Int -> [ByteString] -> IO (Maybe [ByteString])
loop (CInt
nCInt -> CInt -> CInt
forall a. Num a => a -> a -> a
+CInt
1) (Int
oInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
2) (ByteString
s ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
acc)
in CInt -> Int -> [ByteString] -> IO (Maybe [ByteString])
loop CInt
0 Int
0 []
where
substring :: CInt -> CInt -> S.ByteString -> S.ByteString
substring :: CInt -> CInt -> ByteString -> ByteString
substring CInt
x CInt
y ByteString
_ | CInt
x CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== CInt
y = ByteString
S.empty
substring CInt
a CInt
b ByteString
s = ByteString
end
where
start :: ByteString
start = Int -> ByteString -> ByteString
S.unsafeDrop (CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CInt
a) ByteString
s
end :: ByteString
end = Int -> ByteString -> ByteString
S.unsafeTake (CInt -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt
bCInt -> CInt -> CInt
forall a. Num a => a -> a -> a
-CInt
a)) ByteString
start
fullInfoInt :: Ptr PCRE -> CInt -> IO b
fullInfoInt Ptr PCRE
pcre_ptr CInt
what =
(Ptr CInt -> IO b) -> IO b
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr CInt -> IO b) -> IO b) -> (Ptr CInt -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \Ptr CInt
n_ptr -> do
Ptr PCRE -> Ptr PCRE -> CInt -> Ptr CInt -> IO CInt
forall a. Ptr PCRE -> Ptr PCRE -> CInt -> Ptr a -> IO CInt
c_pcre_fullinfo Ptr PCRE
pcre_ptr Ptr PCRE
forall a. Ptr a
nullPtr CInt
what Ptr CInt
n_ptr
b -> IO b
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> IO b) -> (CInt -> b) -> CInt -> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CInt -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CInt -> IO b) -> IO CInt -> IO b
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Ptr CInt -> IO CInt
forall a. Storable a => Ptr a -> IO a
peek (Ptr CInt
n_ptr :: Ptr CInt)
captureCount :: Regex -> Int
captureCount :: Regex -> Int
captureCount (Regex ForeignPtr PCRE
pcre_fp ByteString
_) = IO Int -> Int
forall a. IO a -> a
unsafePerformIO (IO Int -> Int) -> IO Int -> Int
forall a b. (a -> b) -> a -> b
$
ForeignPtr PCRE -> (Ptr PCRE -> IO Int) -> IO Int
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PCRE
pcre_fp ((Ptr PCRE -> IO Int) -> IO Int) -> (Ptr PCRE -> IO Int) -> IO Int
forall a b. (a -> b) -> a -> b
$ \Ptr PCRE
pcre_ptr ->
Ptr PCRE -> CInt -> IO Int
forall {b}. Num b => Ptr PCRE -> CInt -> IO b
fullInfoInt Ptr PCRE
pcre_ptr CInt
info_capturecount
captureNames :: Regex -> [(S.ByteString, Int)]
captureNames :: Regex -> [(ByteString, Int)]
captureNames (Regex ForeignPtr PCRE
pcre_fp ByteString
_) = IO [(ByteString, Int)] -> [(ByteString, Int)]
forall a. IO a -> a
unsafePerformIO (IO [(ByteString, Int)] -> [(ByteString, Int)])
-> IO [(ByteString, Int)] -> [(ByteString, Int)]
forall a b. (a -> b) -> a -> b
$
ForeignPtr PCRE
-> (Ptr PCRE -> IO [(ByteString, Int)]) -> IO [(ByteString, Int)]
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
withForeignPtr ForeignPtr PCRE
pcre_fp ((Ptr PCRE -> IO [(ByteString, Int)]) -> IO [(ByteString, Int)])
-> (Ptr PCRE -> IO [(ByteString, Int)]) -> IO [(ByteString, Int)]
forall a b. (a -> b) -> a -> b
$ \Ptr PCRE
pcre_ptr -> do
Int
count <- Ptr PCRE -> CInt -> IO Int
forall {b}. Num b => Ptr PCRE -> CInt -> IO b
fullInfoInt Ptr PCRE
pcre_ptr CInt
info_namecount
Int
entrysize <- Ptr PCRE -> CInt -> IO Int
forall {b}. Num b => Ptr PCRE -> CInt -> IO b
fullInfoInt Ptr PCRE
pcre_ptr CInt
info_nameentrysize
ByteString
buf <- (Ptr (Ptr CChar) -> IO ByteString) -> IO ByteString
forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca ((Ptr (Ptr CChar) -> IO ByteString) -> IO ByteString)
-> (Ptr (Ptr CChar) -> IO ByteString) -> IO ByteString
forall a b. (a -> b) -> a -> b
$ \Ptr (Ptr CChar)
n_ptr -> do
Ptr PCRE -> Ptr PCRE -> CInt -> Ptr (Ptr CChar) -> IO CInt
forall a. Ptr PCRE -> Ptr PCRE -> CInt -> Ptr a -> IO CInt
c_pcre_fullinfo Ptr PCRE
pcre_ptr Ptr PCRE
forall a. Ptr a
nullPtr CInt
info_nametable Ptr (Ptr CChar)
n_ptr
Ptr CChar
buf <- Ptr (Ptr CChar) -> IO (Ptr CChar)
forall a. Storable a => Ptr a -> IO a
peek Ptr (Ptr CChar)
n_ptr
CStringLen -> IO ByteString
S.packCStringLen (Ptr CChar
buf, Int
countInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
entrysize)
let results :: [(ByteString, Int)]
results = Int -> ByteString -> [(ByteString, Int)]
split Int
entrysize ByteString
buf
zeroIndexed :: [(ByteString, Int)]
zeroIndexed = (Int -> Int) -> (ByteString, Int) -> (ByteString, Int)
forall a b. (a -> b) -> (ByteString, a) -> (ByteString, b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract Int
1) ((ByteString, Int) -> (ByteString, Int))
-> [(ByteString, Int)] -> [(ByteString, Int)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(ByteString, Int)]
results
sorted :: [(ByteString, Int)]
sorted = ((ByteString, Int) -> (ByteString, Int) -> Ordering)
-> [(ByteString, Int)] -> [(ByteString, Int)]
forall a. (a -> a -> Ordering) -> [a] -> [a]
sortBy (Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Int -> Int -> Ordering)
-> ((ByteString, Int) -> Int)
-> (ByteString, Int)
-> (ByteString, Int)
-> Ordering
forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
`on` (ByteString, Int) -> Int
forall a b. (a, b) -> b
snd) [(ByteString, Int)]
zeroIndexed
[(ByteString, Int)] -> IO [(ByteString, Int)]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [(ByteString, Int)]
sorted
where
split :: Int -> S.ByteString -> [(S.ByteString, Int)]
split :: Int -> ByteString -> [(ByteString, Int)]
split Int
entrysize ByteString
buf
| ByteString -> Bool
S.null ByteString
buf = []
| Bool
otherwise =
let
(ByteString
entry, ByteString
tail) = Int -> ByteString -> (ByteString, ByteString)
S.splitAt Int
entrysize ByteString
buf
idx :: Int -> Int
idx = Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8 -> Int) -> (Int -> Word8) -> Int -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. HasCallStack => ByteString -> Int -> Word8
ByteString -> Int -> Word8
S.index ByteString
entry
num :: Int
num = Int -> Int
idx Int
0 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
256 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int -> Int
idx Int
1
name :: ByteString
name = (Word8 -> Bool) -> ByteString -> ByteString
S.takeWhile (Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
/= Word8
0) (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Int -> ByteString -> ByteString
S.drop Int
2 ByteString
entry
in (ByteString
name, Int
num) (ByteString, Int) -> [(ByteString, Int)] -> [(ByteString, Int)]
forall a. a -> [a] -> [a]
: Int -> ByteString -> [(ByteString, Int)]
split Int
entrysize ByteString
tail