#!/usr/bin/runhaskell import Network import Data.Char import IO import System.Timeout import Directory repo = "repo" fn x = repo ++ "/" ++ x port = 12345 split p a = s1 a where s1 (x:xs) | not$p x = s2 xs [x] s1 (x:xs) = s1 xs s1 [] = [] s2 (x:xs) c | p x = reverse c : s1 xs s2 (x:xs) c = s2 xs (x:c) s2 [] c = [reverse c] tr s = case reads s of [] -> Nothing ((x, _):_) -> Just x fl = (foldl step 0) . lines where step x ('+':_) = x + 1 step x ('-':_) = x - 1 step x _ = x change file pos char = do f <- readFile file if fl f > pos then appendFile file ("*" ++ show pos ++ ' ':char:[] ++ "\n") >> return True else return False fold (Just x) str | x >= 0 && x <= (length $ lines str) = '+' : foldl step "" (take x (lines str)) where step x ('+':c:[]) = x ++ [c] step x ('-':_) = tail x step x ('*':str) = let ps = split isSpace str pos = read (ps!!0) c = last (ps!!1) in take pos x ++ [c] ++ drop (pos + 1) x fold Nothing str = fold (Just (length $ lines str)) str fold _ _ = "-" h _ = return () main = let f s = do (handle, host, _) <- accept s do res <- timeout 5000000 (inter handle) case res of Nothing -> hPutStrLn handle "time is out" Just socket -> return () hClose handle `catch` h f s in listenOn (PortNumber port) >>= f inter handle = do hSetBuffering handle LineBuffering ls <- hGetContents handle `catch` \_ -> return "" mapM_ (process1 handle) (lines ls) `catch` h return handle process1 h cmd = process h cmd `catch` \e -> hPutStrLn h "-" process h "l" = getDirectoryContents repo >>= (hPutStr h) . (foldl (++) "") . (map (++"\n")) . (filter (\x -> x /= ".." && x /= ".")) process h ('+':str) = let (file,chars) = break isSpace str in appendFile (fn file) ("+" ++ [last chars] ++ "\n") >> hPutStrLn h "+" process h ('-':str) = let (file,chars) = break isSpace str in do f <- readFile (fn file) if fl f > 0 then appendFile (fn file) ("-" ++ [last chars] ++ "\n") >> hPutStrLn h "+" else hPutStrLn h "-" process h ('*':str) = case split isSpace str of (file:pos:chars:[]) -> case tr pos of Just rev -> change (fn file) rev (last chars) >>= \x -> hPutStrLn h (if x then "+" else "-") Nothing -> hPutStrLn h "-" _ -> hPutStrLn h "-" process h other = let (file, revision) = break isSpace other in do ans <- (openFile (fn file) ReadMode >>= hGetContents >>= return . (fold (tr revision))) hPutStrLn h ans