[Haskell-cafe] Opening the same file multiple times

Bulat Ziganshin bulatz at HotPOP.com
Tue Dec 13 04:29:51 EST 2005

Hello Einar,

Monday, December 12, 2005, 5:01:20 PM, you wrote:

EK> 3) Using System.Posix.IO

EK> Using the fd{Read,Close,Write} functions from System.Posix.IO
EK> could solve the problem - except that there is no way to
EK> write binary buffers (Ptr Word8) with the API. Thus no
EK> solution.

you can easily import these functions via FFI:

foreign import ccall unsafe "HsBase.h read"
   c_read :: CInt -> Ptr CChar -> CSize -> IO CSsize

moreover, they are already imported by System.Posix.Internals. and
even more - it works both under Windows and Unix

below is a part of file api i proposed for inclusion in ghc. i think
it is exactly what you need:

{-# OPTIONS_GHC -fvia-C -fglasgow-exts -fno-monomorphism-restriction#-}
module FD where

import Control.Monad
import Data.Bits
import Data.Int
import Data.Word
import Foreign.C.Types
import Foreign.C.Error
import Foreign.C.String
import Foreign.Marshal.Alloc
import Foreign.Ptr
import System.IO
import System.IO.Error
import System.Posix.Internals
import System.Posix.Types
import System.Win32

type FD = CInt                -- handle of open file
type CWFilePath   = CString   -- filename in C land
type CWFileOffset = COff      -- filesize or filepos in C land
type FileSize     = Integer   -- filesize or filepos in Haskell land
withCWFilePath = withCString  -- FilePath->CWFilePath conversion
peekCWFilePath = peekCString  -- CWFilePath->FilePath conversion

fdOpen :: String -> CInt -> CMode -> IO FD
fdOpen name access mode =
  modifyIOError (`ioeSetFileName` name) $
    withCWFilePath name $ \ p_name ->
      throwErrnoIfMinus1Retry "fdOpen" $
        c_open p_name access mode

fdClose :: FD -> IO ()
fdClose fd =
  throwErrnoIfMinus1Retry_ "fdClose" $
    c_close fd

fdGetBuf :: FD -> Ptr a -> Int -> IO Int
fdGetBuf fd buf size =
  fromIntegral `liftM`
    (throwErrnoIfMinus1Retry "fdGetBuf" $
      c_read fd (castPtr buf) (fromIntegral size))

fdPutBuf :: FD -> Ptr a -> Int -> IO ()
fdPutBuf fd buf size =
  throwErrnoIfMinus1Retry_ "fdPutBuf" $
    c_write fd (castPtr buf) (fromIntegral size)           -- to do: check that result==size?

fdTell :: FD -> IO FileSize
fdTell fd =
  fromIntegral `liftM`
    throwErrnoIfMinus1Retry "fdTell"
      (c_tell fd)

fdSeek :: FD -> SeekMode -> FileSize -> IO ()
fdSeek fd mode offset =
  throwErrnoIfMinus1Retry_ "fdSeek" $
    c_lseek fd (fromIntegral offset) whence
  where whence = case mode of
                   AbsoluteSeek -> sEEK_SET
                   RelativeSeek -> sEEK_CUR
                   SeekFromEnd  -> sEEK_END

fdFileSize :: FD -> IO FileSize
fdFileSize fd =
  fromIntegral `liftM`
    throwErrnoIfMinus1Retry "fdFileSize"
      (c_filelength fd)


  new_fd <- throwErrnoIfMinus1 "dupHandle" $
                c_dup (fromIntegral (haFD h_))
  new_fd <- throwErrnoIfMinus1 "dupHandleTo" $
                c_dup2 (fromIntegral (haFD h_)) (fromIntegral (haFD hto_))

foreign import ccall unsafe "HsBase.h tell"
   c_tell :: CInt -> IO COff

foreign import ccall unsafe "HsBase.h filelength"
   c_filelength :: CInt -> IO COff

foreign import ccall unsafe "__hscore_bufsiz"   dEFAULT_BUFFER_SIZE :: Int
foreign import ccall unsafe "__hscore_seek_cur" sEEK_CUR :: CInt
foreign import ccall unsafe "__hscore_seek_set" sEEK_SET :: CInt
foreign import ccall unsafe "__hscore_seek_end" sEEK_END :: CInt


Best regards,
 Bulat                            mailto:bulatz at HotPOP.com

More information about the Haskell-Cafe mailing list