summaryrefslogtreecommitdiff
path: root/Utility/SimpleProtocol.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Utility/SimpleProtocol.hs')
-rw-r--r--Utility/SimpleProtocol.hs44
1 files changed, 34 insertions, 10 deletions
diff --git a/Utility/SimpleProtocol.hs b/Utility/SimpleProtocol.hs
index 473129218..7ab3c8c77 100644
--- a/Utility/SimpleProtocol.hs
+++ b/Utility/SimpleProtocol.hs
@@ -1,6 +1,6 @@
{- Simple line-based protocols.
-
- - Copyright 2013-2014 Joey Hess <id@joeyh.name>
+ - Copyright 2013-2016 Joey Hess <id@joeyh.name>
-
- License: BSD-2-clause
-}
@@ -20,6 +20,7 @@ module Utility.SimpleProtocol (
parse2,
parse3,
dupIoHandles,
+ getProtocolLine,
) where
import Data.Char
@@ -48,6 +49,16 @@ class Serializable a where
serialize :: a -> String
deserialize :: String -> Maybe a
+instance Serializable [Char] where
+ serialize = id
+ deserialize = Just
+
+instance Serializable ExitCode where
+ serialize ExitSuccess = "0"
+ serialize (ExitFailure n) = show n
+ deserialize "0" = Just ExitSuccess
+ deserialize s = ExitFailure <$> readish s
+
{- Parsing the parameters of messages. Using the right parseN ensures
- that the string is split into exactly the requested number of words,
- which allows the last parameter of a message to contain arbitrary
@@ -93,12 +104,25 @@ dupIoHandles = do
stderr `hDuplicateTo` stdout
return (readh, writeh)
-instance Serializable [Char] where
- serialize = id
- deserialize = Just
-
-instance Serializable ExitCode where
- serialize ExitSuccess = "0"
- serialize (ExitFailure n) = show n
- deserialize "0" = Just ExitSuccess
- deserialize s = ExitFailure <$> readish s
+{- Reads a line, but to avoid super-long lines eating memory, returns
+ - Nothing if 32 kb have been read without seeing a '\n'
+ -
+ - If there is a '\r' before the '\n', it is removed, to support
+ - systems using "\r\n" at ends of lines
+ -
+ - This implementation is not super efficient, but as long as the Handle
+ - supports buffering, it avoids reading a character at a time at the
+ - syscall level.
+ -}
+getProtocolLine :: Handle -> IO (Maybe String)
+getProtocolLine h = go (32768 :: Int) []
+ where
+ go 0 _ = return Nothing
+ go n l = do
+ c <- hGetChar h
+ if c == '\n'
+ then return $ Just $ reverse $
+ case l of
+ ('\r':rest) -> rest
+ _ -> l
+ else go (n-1) (c:l)