module Graphics.Text.Font.Choose.Strings (StrSet, StrSet_, StrList, StrList_, withStrSet, withFilenameSet, thawStrSet, thawStrSet_, withStrList, thawStrList, thawStrList_) where import Data.Set (Set) import qualified Data.Set as Set import Graphics.Text.Font.Choose.Result (throwNull, throwFalse) import Foreign.Ptr (Ptr, nullPtr) import Foreign.C.String (CString, withCString, peekCString) import Control.Exception (bracket) import Control.Monad (forM) type StrSet = Set String data StrSet' type StrSet_ = Ptr StrSet' withNewStrSet :: (StrSet_ -> IO a) -> IO a withNewStrSet = bracket (throwNull <$> fcStrSetCreate) fcStrSetDestroy foreign import ccall "FcStrSetCreate" fcStrSetCreate :: IO StrSet_ foreign import ccall "FcStrSetDestroy" fcStrSetDestroy :: StrSet_ -> IO () withStrSet :: StrSet -> (StrSet_ -> IO a) -> IO a withStrSet strs cb = withNewStrSet $ \strs' -> do forM (Set.elems strs) $ \str -> throwFalse <$> (withCString str $ fcStrSetAdd strs') cb strs' foreign import ccall "FcStrSetAdd" fcStrSetAdd :: StrSet_ -> CString -> IO Bool withFilenameSet :: StrSet -> (StrSet_ -> IO a) -> IO a withFilenameSet paths cb = withNewStrSet $ \paths' -> do forM (Set.elems paths) $ \path -> throwFalse <$> (withCString path $ fcStrSetAddFilename paths') cb paths' foreign import ccall "FcStrSetAddFilename" fcStrSetAddFilename :: StrSet_ -> CString -> IO Bool thawStrSet :: StrSet_ -> IO StrSet thawStrSet strs = Set.fromList <$> withStrList strs thawStrList thawStrSet_ :: IO StrSet_ -> IO StrSet thawStrSet_ cb = bracket (throwNull <$> cb) fcStrSetDestroy thawStrSet ------------ type StrList = [String] data StrList' type StrList_ = Ptr StrList' withStrList :: StrSet_ -> (StrList_ -> IO a) -> IO a withStrList strs = bracket (throwNull <$> fcStrListCreate strs) fcStrListDone foreign import ccall "FcStrListCreate" fcStrListCreate :: StrSet_ -> IO StrList_ foreign import ccall "FcStrListDone" fcStrListDone :: StrList_ -> IO () thawStrList :: StrList_ -> IO StrList thawStrList strs' = do fcStrListFirst strs' go where go = do item' <- fcStrListNext strs' if item' == nullPtr then return [] else do item <- peekCString item' items <- go return (item : items) foreign import ccall "FcStrListFirst" fcStrListFirst :: StrList_ -> IO () foreign import ccall "FcStrListNext" fcStrListNext :: StrList_ -> IO CString thawStrList_ :: IO StrList_ -> IO StrList thawStrList_ cb = bracket (throwNull <$> cb) fcStrListDone thawStrList