|
@@ -33,9 +33,10 @@ module System.IO.Uniform.Streamline (
|
|
|
scan',
|
|
|
recieveTill,
|
|
|
recieveTill',
|
|
|
- -- * Behavior settings
|
|
|
+ -- * Behavior changing and status
|
|
|
startTls,
|
|
|
isSecure,
|
|
|
+ isEOF,
|
|
|
transformTarget,
|
|
|
limitInput,
|
|
|
echoTo,
|
|
@@ -65,11 +66,13 @@ import Data.IP (IP)
|
|
|
|
|
|
import qualified Data.Attoparsec.ByteString as A
|
|
|
|
|
|
+import Debug.Trace
|
|
|
+
|
|
|
-- | Internal state for a Streamline monad
|
|
|
-data StreamlineState = StreamlineState {str :: SomeIO, buff :: ByteString, isEOF :: Bool, echo :: Maybe Handle, inLimit :: Int, sentEmpty :: Bool}
|
|
|
+data StreamlineState = StreamlineState {str :: SomeIO, buff :: ByteString, targetEOF :: Bool, echo :: Maybe Handle, inLimit :: Int}
|
|
|
instance Default StreamlineState where
|
|
|
-- | Will open StdIO
|
|
|
- def = StreamlineState (SomeIO Std.StdIO) BS.empty False Nothing (-1) False
|
|
|
+ def = StreamlineState (SomeIO Std.StdIO) BS.empty False Nothing (-1)
|
|
|
|
|
|
-- | Monad that emulates character stream IO over block IO.
|
|
|
newtype Streamline m a = Streamline {withTarget' :: StreamlineState -> m (a, StreamlineState)}
|
|
@@ -86,7 +89,10 @@ readF = -- Must try just not to read more than the limit, actual limiting is don
|
|
|
else if lim <= blockSize then lim
|
|
|
else blockSize
|
|
|
l <- liftIO $ S.uRead (str cl) sz
|
|
|
- let cl' = cl{buff= l}
|
|
|
+ let cl' = cl{
|
|
|
+ buff = l,
|
|
|
+ targetEOF = BS.null l
|
|
|
+ }
|
|
|
case echo cl of
|
|
|
Just h -> do
|
|
|
liftIO $ BS.hPutStr h "< "
|
|
@@ -100,18 +106,14 @@ takeBuff = do
|
|
|
readF
|
|
|
Streamline $ \cl ->
|
|
|
let lim = inLimit cl
|
|
|
- eof = isEOF cl
|
|
|
+ eof = targetEOF cl
|
|
|
b = buff cl
|
|
|
- in if eof then eofError "System.IO.Uniform.Streamline"
|
|
|
- else if lim < 0 then return (b, cl{buff="", isEOF=BS.null b})
|
|
|
- else let (r, b') = BS.splitAt lim b
|
|
|
- in return (r, cl{
|
|
|
- -- EOF is at the real end of file, not on limited input
|
|
|
- isEOF = lim /= 0 && (BS.null b || sentEmpty cl),
|
|
|
- sentEmpty = BS.null r,
|
|
|
- buff = b',
|
|
|
- inLimit = lim - BS.length r
|
|
|
- })
|
|
|
+ in if lim < 0 then return (b, cl{buff=""})
|
|
|
+ else let (r, b') = BS.splitAt lim b
|
|
|
+ in return (r, cl{
|
|
|
+ buff = b',
|
|
|
+ inLimit = lim - BS.length r
|
|
|
+ })
|
|
|
|
|
|
-- | Pushes remaining data back into the buffer
|
|
|
pushBuff :: Monad m => ByteString -> Streamline m ()
|
|
@@ -332,6 +334,17 @@ runAttoparsec p = snd <$> runAttoparsecAndReturn p
|
|
|
isSecure :: Monad m => Streamline m Bool
|
|
|
isSecure = Streamline $ \cl -> return (S.isSecure $ str cl, cl)
|
|
|
|
|
|
+{- |
|
|
|
+True if the input is at the end of stream.
|
|
|
+
|
|
|
+If the input is limited, will be true when either the limit is reached,
|
|
|
+or the underlining target was at actual end of stream. In case of EOF
|
|
|
+due to reaching the limit, changing the limit will immediately make this
|
|
|
+return False again.
|
|
|
+-}
|
|
|
+isEOF :: Monad m => Streamline m Bool
|
|
|
+isEOF = Streamline $ \cl -> return (targetEOF cl || inLimit cl == 0, cl)
|
|
|
+
|
|
|
-- | Sets echo of the streamlines IO target.
|
|
|
-- If echo is set, all the data read an written to the target
|
|
|
-- will be echoed in stdout, with ">" and "<" markers indicating
|