{-# LANGUAGE CPP, ScopedTypeVariables #-}
-- GIMP Toolkit (GTK) Binding for Haskell: binding to libgnomevfs -*-haskell-*-
--
-- Author : Peter Gavin
-- Created: 1-Apr-2007
--
-- Copyright (c) 2007 Peter Gavin
--
-- This library is free software: you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public License
-- as published by the Free Software Foundation, either version 3 of
-- the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this program. If not, see
-- .
--
-- GnomeVFS, the C library which this Haskell library depends on, is
-- available under LGPL Version 2. The documentation included with
-- this library is based on the original GnomeVFS documentation,
-- Copyright (c) 2001 Seth Nickell . The
-- documentation is covered by the GNU Free Documentation License,
-- version 1.2.
--
-- | Maintainer : gtk2hs-devel@lists.sourceforge.net
-- Stability : alpha
-- Portability : portable (depends on GHC)
--
-- Functions for creating, removing, and accessing directories and
-- their contents.
--
module System.Gnome.VFS.Directory (
-- * Types
DirectoryHandle,
DirectoryVisitOptions(..),
DirectoryVisitResult(..),
-- * Directory Creation
makeDirectory,
makeDirectoryForURI,
-- * Directory Removal
removeDirectory,
removeDirectoryFromURI,
-- * Directory Access
directoryOpen,
directoryOpenFromURI,
directoryReadNext,
directoryClose,
directoryListLoad,
-- * Directory Traversal
directoryVisit,
directoryVisitURI,
directoryVisitFiles,
directoryVisitFilesAtURI
) where
import Control.Exception ( assert
, bracket )
import Control.Monad ( liftM )
import System.Glib.GList ( GList()
, toGList
, readGList )
import System.Glib.UTFString ( withUTFString
, peekUTFString
, newUTFString )
import System.Glib.FFI
{#import System.Gnome.VFS.FileInfo#}
-- {#import System.Gnome.VFS.Types#}
{#import System.Gnome.VFS.BasicTypes#}
{#import System.Gnome.VFS.Marshal#}
{# context lib = "gnomevfs" prefix = "gnome_vfs" #}
-- | Create @textURI@ as a directory. Only succeeds if a file or
-- directory does not already exist at @textURI@.
makeDirectory :: TextURI -- ^ @textURI@ - String representation of the URI of the directory to create
-> [FilePermissions] -- ^ @perm@ - 'FilePermissions' for the newly created directory
-> IO ()
makeDirectory textURI perm =
let cPerm = cFromFlags perm
in withUTFString textURI $ \cTextURI ->
voidResultMarshal $ {# call make_directory #} cTextURI cPerm
-- | Create @uri@ as a directory. Only succeeds if a file or
-- directory does not already exist at @uri@.
makeDirectoryForURI :: URI -- ^ @uri@ - 'URI' of the directory to be created
-> [FilePermissions] -- ^ @perm@ - 'FilePermissions' for the newly created directory
-> IO ()
makeDirectoryForURI uri perm =
let cPerm = cFromFlags perm
in voidResultMarshal $ {# call make_directory_for_uri #} uri cPerm
-- | Remove the directory at @textURI@. The object at @textURI@ must be an empty directory.
removeDirectory :: TextURI -- ^ @textURI@ - URI of the directory to be removed
-> IO ()
removeDirectory textURI =
withUTFString textURI $ voidResultMarshal . {# call remove_directory #}
-- | Remove the directory at @uri@. The object at @uri@ must be an empty directory.
removeDirectoryFromURI :: URI -- ^ @uri@ - 'URI' of the directory to be removed
-> IO ()
removeDirectoryFromURI uri =
voidResultMarshal $ {# call remove_directory_from_uri #} uri
-- | Open directory textURI for reading. Returns a 'DirectoryHandle'
-- which can be used to read directory entries one by one.
directoryOpen :: TextURI -- ^ @textURI@ - String representation of the URI of the directory to open
-> [FileInfoOptions] -- ^ @fileInfoOptions@ - options for reading file information
-> IO DirectoryHandle -- ^ handle to the opened directory
directoryOpen textURI fileInfoOptions =
let cFileInfoOptions = cFromFlags fileInfoOptions
in withUTFString textURI $ \cTextURI ->
newObjectResultMarshal DirectoryHandle $ \cHandlePtr ->
{# call directory_open #} (castPtr cHandlePtr) cTextURI cFileInfoOptions
-- | Open directory textURI for reading. Returns a 'DirectoryHandle'
-- which can be used to read directory entries one by one.
directoryOpenFromURI :: URI -- ^ @uri@ - 'URI' of the directory to open
-> [FileInfoOptions] -- ^ @fileInfoOptions@ - options for reading file information
-> IO DirectoryHandle -- ^ handle to the opened directory
directoryOpenFromURI uri fileInfoOptions =
let cFileInfoOptions = cFromFlags fileInfoOptions
in newObjectResultMarshal DirectoryHandle $ \cHandlePtr ->
{# call directory_open_from_uri #} (castPtr cHandlePtr) uri cFileInfoOptions
-- | Read the next directory entry from a 'DirectoryHandle'.
directoryReadNext :: DirectoryHandle -- ^ @handle@ - a directory handle
-> IO FileInfo -- ^ file information for the next directory entry
directoryReadNext handle =
alloca $ \(cFileInfoPtr :: Ptr FileInfo) ->
genericResultMarshal ({# call directory_read_next #} handle $ castPtr cFileInfoPtr)
(peek cFileInfoPtr)
(return ())
-- | Close a 'DirectoryHandle'.
directoryClose :: DirectoryHandle -- ^ @handle@ - a directory handle
-> IO ()
directoryClose handle =
voidResultMarshal $ {# call directory_close #} handle
type CDirectoryVisitFunc = CString -- rel_path
-> Ptr FileInfo -- info
-> {# type gboolean #} -- recursing_will_loop
-> {# type gpointer #} -- user_data
-> Ptr {# type gboolean #} -- recurse
-> IO {# type gboolean #}
directoryVisitCallbackMarshal :: DirectoryVisitCallback
-> IO {# type GnomeVFSDirectoryVisitFunc #}
directoryVisitCallbackMarshal callback =
let cCallback :: CDirectoryVisitFunc
cCallback cRelPath cInfo cRecursingWillLoop cUserData cRecursePtr =
do relPath <- peekUTFString cRelPath
info <- peek cInfo
let recursingWillLoop = toBool cRecursingWillLoop
result <- callback relPath info recursingWillLoop
case result of
DirectoryVisitStop -> return $ fromBool False
DirectoryVisitContinue -> return $ fromBool True
DirectoryVisitRecurse -> do poke cRecursePtr $ fromBool True
return $ fromBool True
in makeDirectoryVisitFunc cCallback
foreign import ccall safe "wrapper"
makeDirectoryVisitFunc :: CDirectoryVisitFunc
-> IO {# type GnomeVFSDirectoryVisitFunc #}
type DirectoryVisit = [FileInfoOptions]
-> [DirectoryVisitOptions]
-> DirectoryVisitCallback
-> IO ()
type CDirectoryVisit = {# type GnomeVFSFileInfoOptions #}
-> {# type GnomeVFSDirectoryVisitOptions #}
-> {# type GnomeVFSDirectoryVisitFunc #}
-> {# type gpointer #}
-> IO {# type GnomeVFSResult #}
directoryVisitMarshal :: CDirectoryVisit
-> DirectoryVisit
directoryVisitMarshal cVisitAction infoOptions visitOptions callback =
let cInfoOptions = cFromFlags infoOptions
cVisitOptions = cFromFlags visitOptions
in bracket (directoryVisitCallbackMarshal callback)
freeHaskellFunPtr
(\cDirectoryVisitFunc ->
voidResultMarshal $ cVisitAction cInfoOptions cVisitOptions cDirectoryVisitFunc nullPtr)
-- | Visit each entry in a directory at a 'TextURI', calling a
-- 'DirectoryVisitCallback' for each one.
directoryVisit :: String -- ^ @textURI@ - string representation of the URI of the directory to visit
-> [FileInfoOptions] -- ^ @infoOptions@ - options for reading file information
-> [DirectoryVisitOptions] -- ^ @visitOptions@ - options for visiting the directory
-> DirectoryVisitCallback -- ^ @callback@ - a function to be called for each entry
-> IO ()
directoryVisit textURI infoOptions visitOptions callback =
withUTFString textURI $ \cTextURI ->
directoryVisitMarshal ({# call directory_visit #} cTextURI) infoOptions visitOptions callback
-- | Visit each entry in a directory at a 'URI', calling a
-- 'DirectoryVisitCallback' for each one.
directoryVisitURI :: URI -- ^ @uri@ - the URI of the directory to visit
-> [FileInfoOptions] -- ^ @infoOptions@ - options for reading file information
-> [DirectoryVisitOptions] -- ^ @visitOptions@ - options for visiting the directory
-> DirectoryVisitCallback -- ^ @callback@ - a function to be called for each entry
-> IO ()
directoryVisitURI uri =
directoryVisitMarshal ({# call directory_visit_uri #} uri)
-- | Visit each file in a list contained with a directory at a
-- 'TextURI', calling a 'DirectoryVisitCallback' for each one.
directoryVisitFiles :: TextURI -- ^ @textURI@ - string representation of the URI of the directory to visit
-> [String] -- ^ @files@ - the files contained in @textURI@ to be visited
-> [FileInfoOptions] -- ^ @infoOptions@ - options for reading file information
-> [DirectoryVisitOptions] -- ^ @visitOptions@ - options for visiting the directory
-> DirectoryVisitCallback -- ^ @callback@ - a function to be called for each entry
-> IO ()
directoryVisitFiles textURI files infoOptions visitOptions callback =
do cFiles <- mapM newUTFString files >>= toGList
withUTFString textURI $ \cTextURI ->
directoryVisitMarshal ({# call directory_visit_files #} cTextURI cFiles) infoOptions visitOptions callback
-- | Visit each file in a list contained with a directory at a
-- 'URI', calling a 'DirectoryVisitCallback' for each one.
directoryVisitFilesAtURI :: URI -- ^ @uri@ - the 'URI' of the directory to visit
-> [String] -- ^ @files@ - the files contained in @textURI@ to be visited
-> [FileInfoOptions] -- ^ @infoOptions@ - options for reading file information
-> [DirectoryVisitOptions] -- ^ @visitOptions@ - options for visiting the directory
-> DirectoryVisitCallback -- ^ @callback@ - a function to be called for each entry
-> IO ()
directoryVisitFilesAtURI uri files infoOptions visitOptions callback =
do cFiles <- mapM newUTFString files >>= toGList
directoryVisitMarshal ({# call directory_visit_files_at_uri #} uri cFiles) infoOptions visitOptions callback
-- | Create a list of 'FileInfo' objects representing each entry in the
-- directory at @textURI@, using options @options@.
directoryListLoad :: TextURI -- ^ @textURI@ - String representation of the URI of the directory to load
-> [FileInfoOptions] -- ^ @options@ - options for reading file information
-> IO [FileInfo] -- ^ the entries contined in the directory
directoryListLoad textURI options =
let cOptions = cFromFlags options
in withUTFString textURI $ \cTextURI ->
alloca $ \cListPtr ->
genericResultMarshal ({# call directory_list_load #} cListPtr cTextURI cOptions)
(peek cListPtr >>= readGList >>= mapM peek)
(do cList <- peek cListPtr
assert (cList == nullPtr) $ return ())