LINUX.ORG.RU

История изменений

Исправление quasimoto, (текущая версия) :

про passwd

Вот, по возможности более обфусцировано — с сигнатурами, (<|>) для IO, (<*>) и (>>=) для функций и point-free местами:

catching :: IO a -> (SomeException -> IO a) -> IO a
catching = catch

instance Alternative IO where
  empty = error "empty IO" -- throwIO (EmptyIO :: EmptyIO)
  a <|> b = catching a (const b)

unlessM :: Monad m => m Bool -> m () -> m ()
unlessM p a = p >>= (`unless` a)

synA :: Applicative f => (f b -> t) -> f (a -> b) -> f a -> t
synA from guar to = from $ guar <*> to

synM :: Monad m => ((a -> m ()) -> t) -> (a -> m Bool) -> (a -> m ()) -> t
synM from guar = synA from (unlessM . guar)

-- Binary [?] -> ?

fromBinaryList :: Binary e => FilePath -> (e -> IO a) -> IO ()
fromBinaryList path f = mapM_ f =<< decodeFile path

-- ? -> HashTable ?

synToHT :: (Eq k, Hashable k, HashTable h) =>
  ((v -> IO ()) -> t) -> (v -> k) -> IOHashTable h k v -> t
synToHT f key ht = synM f (fmap isJust . HT.lookup ht . key) $ HT.insert ht =<< key

-- User

data User = User
  { _login :: !ByteString, _uid :: !Word, _gid :: !Word
  , _name :: !ByteString, _home :: !ByteString, _shell :: !ByteString
  } deriving ( Show, Eq, Generic )

-- Binary [User]

instance Binary User where

-- HashTable User

type MyHT = BasicHashTable ByteString User

-- Binary [User] -> HashTable User

synBinaryUsersToHT :: FilePath -> MyHT -> IO ()
synBinaryUsersToHT = (`synToHT` _name) . fromBinaryList

-- Passwd -> ? User

fromPasswd :: (User -> IO a) -> IO ()
fromPasswd f = (mapM_ (f . readUser) . BS8.lines =<< BS.readFile "/etc/passwd")
               <|> error "while reading /etc/passwd" where
  readUser bs = case BS8.split ':' bs of
    [login, _, uid, gid, name, home, shell] ->
      User login (read $ BS8.unpack uid) (read $ BS8.unpack gid) name home shell
      -- read :: Read a => ByteString -> a ?

-- Passwd -> HashTable User

synPasswdToHT :: MyHT -> IO ()
synPasswdToHT = synToHT fromPasswd _name

test :: IO ()
test = do
  
  let root = User "root" 0 0 "root" "/root" "sh"
      user = User "user" 1 1 "user" "/user" "sh"

  encodeFile "/tmp/test" [root, user]
  ht <- HT.new
  synBinaryUsersToHT "/tmp/test" ht
  root' <- HT.lookup ht "root"
  user' <- HT.lookup ht "user"
  assert (isJust root' && isJust user' && root == fromJust root' && user == fromJust user') $! return ()

  ht <- HT.new
  synPasswdToHT ht
  mapM_ print =<< HT.toList ht

Исходная версия quasimoto, :

про passwd

Вот, по возможности более обфусцировано — с сигнатурами, (<|>) для IO, (<*>) и (>>=) для функций и point-free местами:

catching :: IO a -> (SomeException -> IO a) -> IO a
catching = catch

instance Alternative IO where
  empty = error "empty IO" -- throwIO (EmptyIO :: EmptyIO)
  a <|> b = catching a (const b)

unlessM :: Monad m => m Bool -> m () -> m ()
unlessM p a = p >>= (`unless` a)

synA :: Applicative f => (f b -> t) -> f (a -> b) -> f a -> t
synA from guar to = from $ guar <*> to

synM :: Monad m => ((a -> m ()) -> t) -> (a -> m Bool) -> (a -> m ()) -> t
synM from guar = synA from (unlessM . guar)

-- Binary [?] -> ?

fromBinaryList :: Binary e => FilePath -> (e -> IO a) -> IO ()
fromBinaryList path f = mapM_ f =<< decodeFile path

-- ? -> HashTable ?

synToHT :: (Eq k, Hashable k, HashTable h) =>
  ((v -> IO ()) -> t) -> (v -> k) -> IOHashTable h k v -> t
synToHT f key ht = synM f (fmap isJust . HT.lookup ht . key) $ HT.insert ht =<< key

-- User

data User = User
  { _login :: !ByteString, _uid :: !Word, _gid :: !Word
  , _name :: !ByteString, _home :: !ByteString, _shell :: !ByteString
  } deriving ( Show, Eq, Generic )

-- Binary [User]

instance Binary User where

-- HashTable User

type MyHT = BasicHashTable ByteString User

-- Binary [User] -> HashTable User

synBinaryUsersToHT :: FilePath -> MyHT -> IO ()
synBinaryUsersToHT = (`synToHT` _name) . fromBinaryList

-- Passwd -> ? User

fromPasswd :: (User -> IO a) -> IO ()
fromPasswd f = (mapM_ (f . readUser) . BS8.lines =<< BS.readFile "/etc/passwd")
               <|> error "while reading /etc/passwd" where
  readUser bs = case BS8.split ':' bs of
    [login, _, uid, gid, name, home, shell] ->
      User login (read $ BS8.unpack uid) (read $ BS8.unpack gid) name home shell
      -- read :: Read a => ByteString -> a ?

-- Passwd -> HashTable User

synPasswdToHT :: MyHT -> IO ()
synPasswdToHT = synToHT fromPasswd _name

test :: IO ()
test = do
  
  let root = User "root" 0 0 "root" "/root" "sh"
      user = User "user" 1 1 "user" "/user" "sh"

  encodeFile "/tmp/test" [root, user]
  ht <- HT.new
  synBinaryUsersToHT "/tmp/test2" ht
  root' <- HT.lookup ht "root"
  user' <- HT.lookup ht "user"
  assert (isJust root' && isJust user' && root == fromJust root' && user == fromJust user') $! return ()

  ht <- HT.new
  synPasswdToHT ht
  mapM_ print =<< HT.toList ht