{-# LANGUAGE ScopedTypeVariables #-} import Text.XML.Expat.Chunked import Text.XML.Expat.Format import Control.Exception import Control.Monad import Control.Monad.Trans import qualified Data.ByteString as B import Data.Iteratee import Data.Iteratee.Base.StreamChunk (ReadableChunk (..)) import Data.List.Class import Data.Text (Text) import qualified Data.Text as T import System.IO import Foreign.Ptr import Foreign.ForeignPtr import Foreign.Storable main :: IO () main = do eErr <- myFileDriver (parse defaultParserOptions dump) "sudoku.xml" case eErr of Left err -> putStrLn $ "failed: "++show err Right () -> putStrLn "" dump :: UNode IO Text -> XMLT IO () dump doc = do let txt = formatG doc forIter txt $ liftIO . B.hPutStr stdout return () forIter :: (List l) => l a -> (a -> ItemM l b) -> ItemM l [b] forIter iter body = fi iter [] where fi iter acc = do elt <- runList iter case elt of Cons value iter' -> do b <- body value fi iter' (b:acc) Nil -> return (reverse acc) -- ------------------------------------------------------------------------ -- Binary Random IO enumerators myBufSize = 16 -- |The enumerator of a file Handle. This version enumerates -- over the entire contents of a file, in order, unless stopped by -- the iteratee. In particular, seeking is not supported. myEnumHandle :: forall s el m a.(ReadableChunk s el, MonadIO m) => Handle -> EnumeratorGM s el m a myEnumHandle h i = liftIO (mallocForeignPtrBytes (fromIntegral buffer_size)) >>= loop i where buffer_size = myBufSize - mod myBufSize (sizeOf (undefined :: el)) loop iter fp = do s <- liftIO . withForeignPtr fp $ \p -> do n <- try $ hGetBuf h p buffer_size :: IO (Either SomeException Int) case n of Left _ -> return $ Left "IO error" Right 0 -> return $ Right Nothing Right n' -> liftM (Right . Just) $ readFromPtr p (fromIntegral n') liftIO $ putStr "|" -- ### checkres fp iter s checkres fp iter = either (flip enumErr iter) (maybe (return iter) (check fp <=< runIter iter . Chunk)) check _p (Done x _) = return . return $ x check p (Cont i' Nothing) = loop i' p check _p (Cont _ (Just e)) = return $ throwErr e -- |Process a file using the given IterateeGM. This function wraps -- enumHandle as a convenience. myFileDriver :: (MonadIO m, ReadableChunk s el) => IterateeG s el m a -> FilePath -> m a myFileDriver iter filepath = do h <- liftIO $ openBinaryFile filepath ReadMode result <- myEnumHandle h iter >>= run liftIO $ hClose h return result