
I've been fiddling with binary read/write in Haskell. I put together a little example demonstrating my lack of understanding. It creates a connection requestion XAtom and spits it out over a socket. My real hangup occurs when I get a String back from the Socket and would like it nicely marshalled into the ConnectSuccess type. These techniques I would assume apply to binary read/write for files as well. Any criticism/suggestions are appreciated. import IO import Monad import GHC.IO import GHC.Storable import Network import Network.Socket import Data.Char import Data.Word import System.Environment import Parsec -- A Parser that looks for everything before the colon beforeColon :: Parser String beforeColon = many1 (satisfy $ \c -> c /= ':') -- Parse out the display name from the environment Variable DISPLAY parseDisplay :: String -> String parseDisplay s = if (name == "") then "localhost" else name where name = case (parse beforeColon "" s) of Left err -> "" Right x -> x -- repeat an IO action multiple times repeat' :: Int -> IO a -> IO () repeat' n f = foldr (>>) (return ()) (take n (repeat f)) -- Send the X11 Connection Request to a handle sendConnectReq :: Handle -> IO () sendConnectReq h = do -- O'Reilly claims this should be '\x66' -- Try it with this and it crashes like so -- *** Exception: user error -- Reason: Pattern match failure in do expression, open.hs:xx hPutChar h '\x6c' --platform dependent byte-ordering, MSB hPutChar h '\x00' --unused hPutChar h '\x0b' --protocol major 11 hPutChar h '\x00' --protocol minor 0 repeat' 8 (hPutChar h '\x00') -- pad it out to boundary hFlush h -- Totally clueless on this one -- What's the best for this? marshallSuccess :: String -> ConnectSuccess marshallSuccess s = let v = drop 39 s in ConnectSuccess 0 0 0 0 0 0 0 0 0 0 0 0 v -- Get the reply getConnectReply :: Handle -> IO (Either ConnectFail ConnectSuccess) getConnectReply h = do (r:rs) <- hGetContents h -- This is the line that crashes with an invalid request (reply ""?) if (r == '\x00') then return (Left (drop 7 rs)) else return (Right (marshallSuccess rs)) -- Error string, this probably should be an ioexception type type ConnectFail = String -- Connection success type to fill up with wonderful stuff data ConnectSuccess = ConnectSuccess { release :: Word32, id_base :: Word32, id_mask :: Word32, motion_buf :: Word32, max_req :: Word16, screens :: Word8, img_order :: Word8, bit_order :: Word8, bit_unit :: Word8, bit_pad :: Word8, min_keycode :: Word8, max_keycode :: Word8, vendor :: String } -- Main program to make an X11 connection request. main :: IO () main = withSocketsDo $ do hostname <- liftM parseDisplay (getEnv "DISPLAY") h <- connectTo hostname (Service "x11") sendConnectReq h reply <- getConnectReply h case reply of Left s -> putStr "Failure: " >> putStr s >> putChar '\n' Right s -> putStr "Success: " >> putStr (vendor s) >> putChar '\n'