{-# OPTIONS -fffi -fglasgow-exts #-}---------------------------------------------------------------------- |-- Module : Network.Curl.Types-- Copyright : (c) Galois Inc 2007-- License : BSD3---- Maintainer: emertens@galois.com-- Stability : provisional-- Portability: portable---- Basic set of types for the Haskell curl binding, including the-- @Curl@ handle type which holds the C library stateful connection-- handle along with a set of cleanup actions tht should be performed-- upon shutting down the curl session.----------------------------------------------------------------------moduleNetwork.Curl.Types(CurlH,URLString,Port,Long,LLong,Slist_,Curl,curlPrim,mkCurl,mkCurlWithCleanup,OptionMap,shareCleanup,runCleanup,updateCleanup)whereimportNetwork.Curl.DebugimportForeign.PtrimportForeign.ForeignPtrimportData.WordimportControl.ConcurrentimportControl.Monad.Fix(mfix)importData.Maybe(fromMaybe)importqualifiedData.IntMapasMimportData.IORefimportSystem.IOdataCurl_typeCurlH=PtrCurl_typeURLString=StringtypePort=LongtypeLong=Word32typeLLong=Word64dataSlist_dataCurl=Curl{curlH::MVar(ForeignPtrCurl_)-- libcurl is not thread-safe.,curlCleanup::IORefOptionMap-- deallocate Haskell curl data }-- | Execute a "primitve" curl operation.-- NOTE: See warnings about the use of 'withForeginPtr'.curlPrim::Curl->(IORefOptionMap->CurlH->IOa)->IOacurlPrimcf=withMVar(curlHc)$\h->withForeignPtrh$f$curlCleanupc-- | Allocates a Haskell handle from a C handle.mkCurl::CurlH->IOCurlmkCurlh=mkCurlWithCleanuphom_empty-- | Allocates a Haskell handle from a C handle.mkCurlWithCleanup::CurlH->OptionMap->IOCurlmkCurlWithCleanuphclean=dodebug"ALLOC: CURL"fh<-newForeignPtr_hv1<-newMVarfhv2<-newIORefcleanletnew_h=Curl{curlH=v1,curlCleanup=v2}fin<-mkIOfin$dodebug"FREE: CURL"easy_cleanuphrunCleanupv2addForeignPtrFinalizerfinfhreturnnew_h-- Admin code for cleaning up marshalled data.-- Note that these functions assume that they are running atomically,-- so access to them should be protected by a lock.--------------------------------------------------------------------------------runCleanup::IORefOptionMap->IO()runCleanupr=dom<-readIORefrom_cleanupmwriteIORefrom_emptyshareCleanup::IORefOptionMap->IOOptionMapshareCleanupr=doold<-readIORefrnew<-om_dupoldwriteIORefrnewreturnnewupdateCleanup::IORefOptionMap->Int->IO()->IO()updateCleanuproptionact=writeIORefr=<<om_setoptionact=<<readIORefr-- Maps that associate curl options with IO actions to-- perform cleanup for them.--------------------------------------------------------------------------------typeOptionMap=M.IntMap(IO())-- | An empty option map.om_empty::OptionMapom_empty=M.empty-- | Set the IO action for an option,-- executing the previvous action, if there was one.om_set::Int->IO()->OptionMap->IOOptionMapom_setoptnew_actold_map=dofromMaybe(return())old_actreturnnew_mapwhere(old_act,new_map)=M.insertLookupWithKey(\_a_->a)optnew_actold_map-- | Execute all IO actions in the map.om_cleanup::OptionMap->IO()om_cleanupm=sequence_(M.elemsm)-- | Replace the actions in a map, with actions that-- will only be executed the second time they are invoked.om_dup::OptionMap->IOOptionMapom_dupold_map=M.fromList`fmap`mapMdup(M.assocsold_map)wheredup(x,old_io)=donew_io<-shareIOold_ioreturn(x,new_io)-- Share a cleanup action. When we share cleanup duty between two handles-- we need to ensure that the first handle to perform the cleanup will do-- nothing (because the other handle still needs the resources).shareIO::IO()->IO(IO())shareIOact=dov<-newMVarFalseletnew_act=dob<-takeMVarvifbthenactelseputMVarvTruereturnnew_act---------------------------------------------------------------------------------- FFI for inalizers.-- | Make a finalizer from an IO action.mkIOfin::IOa->IO(FinalizerPtrb)mkIOfinm=mfix(\ptr->ioFinalizer(m>>freeHaskellFunPtrptr))foreignimportccall"curl/curl.h curl_easy_cleanup"easy_cleanup::CurlH->IO()foreignimportccall"wrapper"ioFinalizer::IO()->IO(FinalizerPtra)