{-# LANGUAGE CPP #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- | Streaming functions for interacting with the filesystem.
module System.Directory.OsPath.Streaming
( DirStream
, openDirStream
, readDirStream
, closeDirStream
) where
import System.OsPath (osp)
#ifdef mingw32_HOST_OS
import Control.Concurrent.Counter (Counter)
import Control.Concurrent.Counter qualified as Counter
import Control.Monad (unless)
import System.OsPath.Types (OsPath)
import System.OsString.Internal.Types (OsString(OsString), getOsString)
import System.OsString.Windows (pstr)
import System.Win32.Types qualified as Win32
import System.Win32.WindowsString.File qualified as Win32
data DirStream = DirStream !Win32.HANDLE !Win32.FindData !Counter
openDirStream :: OsPath -> IO DirStream
openDirStream fp = do
(h, fdat) <- Win32.findFirstFile $ getOsString fp <> [pstr|\*|]
hasMore <- Counter.new 1 -- always at least two records, "." and ".."
pure $! DirStream h fdat hasMore
closeDirStream :: DirStream -> IO ()
closeDirStream (DirStream h _ _) = Win32.findClose h
readDirStream :: DirStream -> IO (Maybe OsPath)
readDirStream (DirStream h fdat hasMore) = go
where
go = do
hasMore' <- Counter.get hasMore
if hasMore' /= 0
then do
filename <- Win32.getFindDataFileName fdat
hasMore'' <- Win32.findNextFile h fdat
unless hasMore'' $
Counter.set hasMore 0
if filename == getOsString [osp|.|] || filename == getOsString [osp|..|]
then go
else pure $ Just $ OsString filename
else pure Nothing
#else
import System.OsPath.Types (OsPath)
import System.OsString.Internal.Types (OsString(OsString), getOsString)
import System.Posix.Directory.PosixPath (DirStream, closeDirStream)
import System.Posix.Directory.PosixPath qualified as Posix
openDirStream :: OsPath -> IO DirStream
openDirStream = Posix.openDirStream . getOsString
{-# INLINE readDirStream #-}
readDirStream :: DirStream -> IO (Maybe OsPath)
readDirStream ds = go
where
go = do
fp <- Posix.readDirStream ds
case () of
_ | fp == mempty
-> pure Nothing
| fp == getOsString [osp|.|] || fp == getOsString [osp|..|]
-> go
| otherwise
-> pure $ Just $ OsString fp
#endif