content: {-# LANGUAGE CPP               #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE RankNTypes        #-}
  module Main (main) where
  
  import Control.Concurrent (threadDelay)
  import Control.Exception  (bracket)
  import System.Environment (getArgs)
  import System.IO          (Handle, IOMode (ReadWriteMode), hClose, openFile)
  
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.Char8 as BS8
  
  import Lukko
  
  #ifdef HAS_OFD_LOCKING
  import qualified Lukko.OFD as OFD
  #endif
  
  #ifdef HAS_FLOCK
  import qualified Lukko.FLock as FLock
  #endif
  
  main :: IO ()
  main = withArgs $ \withLock -> do
      putStrLn "starting..."
      withLock $ do
          contents <- BS.readFile "test-actual"
          threadDelay 10000 -- 10 ms
          BS.writeFile "test-actual" $ BS.append contents $ BS8.pack "another line\n"
  
  withArgs
      :: ((forall r. IO r -> IO r) -> IO ())
      -> IO ()
  withArgs k = do
      args <- getArgs
      case args of
          ["default"] -> k (genWithLock hLock hUnlock "test-lock")
  #ifdef HAS_OFD_LOCKING
          ["ofd"]     -> k (genWithLock OFD.hLock OFD.hUnlock "test-lock")
  #endif
  #ifdef HAS_FLOCK
          ["flock"]   -> k (genWithLock FLock.hLock FLock.hUnlock "test-lock")
  #endif
          ["noop"]    -> k (genWithLock noOpLock noOpUnlock "test-lock")
          _           -> putStrLn "Unknown paramters. Doing nothing."
  
  -------------------------------------------------------------------------------
  -- copy pasted
  -------------------------------------------------------------------------------
  
  noOpLock :: Handle -> LockMode -> IO ()
  noOpLock _ _ = return ()
  
  noOpUnlock :: Handle -> IO ()
  noOpUnlock _ = return ()
  
  genWithLock
      :: (Handle -> LockMode -> IO ())
      -> (Handle -> IO ())
      -> FilePath
      -> IO a
      -> IO a
  genWithLock implLock implUnlock fp action =
      bracket takeLock releaseLock (const action)
    where
      takeLock = do
          h <- openFile fp ReadWriteMode
          implLock h ExclusiveLock
          return h
  
      releaseLock :: Handle -> IO ()
      releaseLock h = do
          implUnlock h
          hClose h
  