% % (c) The University of Glasgow, 1997-2003 % \section{String buffers} Buffers for scanning string input stored in external arrays. \begin{code} module StringBuffer ( StringBuffer(..), -- non-abstract for vs/HaskellService -- * Creation/destruction hGetStringBuffer, -- :: FilePath -> IO StringBuffer stringToStringBuffer, -- :: String -> IO StringBuffer -- * Lookup currentChar, -- :: StringBuffer -> Char prevChar, -- :: StringBuffer -> Char -> Char lookAhead, -- :: StringBuffer -> Int -> Char atEnd, -- :: StringBuffer -> Bool -- * Moving stepOn, stepOnBy, -- * Conversion lexemeToString, -- :: StringBuffer -> Int -> String lexemeToFastString, -- :: StringBuffer -> Int -> FastString -- * Parsing integers parseInteger, ) where #include "HsVersions.h" import FastString import Panic import GLAEXTS import Foreign #if __GLASGOW_HASKELL__ < 503 import PrelIOBase import PrelHandle #else import GHC.IOBase import GHC.IO ( slurpFile ) #endif import IO ( openFile, hFileSize, IOMode(ReadMode), hClose ) #if __GLASGOW_HASKELL__ >= 601 import System.IO ( openBinaryFile ) #else import IOExts ( openFileEx, IOModeEx(..) ) #endif #if __GLASGOW_HASKELL__ < 503 import IArray ( listArray ) import ArrayBase ( UArray(..) ) import MutableArray import IOExts ( hGetBufBA ) #else import Data.Array.IArray ( listArray ) import Data.Array.MArray ( unsafeFreeze, newArray_ ) import Data.Array.Base ( UArray(..) ) import Data.Array.IO ( IOArray, hGetArray ) #endif import Char ( ord ) #if __GLASGOW_HASKELL__ < 601 openBinaryFile fp mode = openFileEx fp (BinaryMode mode) #endif -- ----------------------------------------------------------------------------- -- The StringBuffer type -- A StringBuffer is a ByteArray# with a pointer into it. We also cache -- the length of the ByteArray# for speed. data StringBuffer = StringBuffer ByteArray# Int# -- length Int# -- current pos instance Show StringBuffer where showsPrec _ s = showString "" -- ----------------------------------------------------------------------------- -- Creation / Destruction hGetStringBuffer :: FilePath -> IO StringBuffer hGetStringBuffer fname = do h <- openBinaryFile fname ReadMode size <- hFileSize h let size_i@(I# sz#) = fromIntegral size #if __GLASGOW_HASKELL__ < 503 arr <- stToIO (newCharArray (0,size_i-1)) r <- hGetBufBA h arr size_i #else arr <- newArray_ (0,size_i-1) r <- if size_i == 0 then return 0 else hGetArray h arr size_i #endif hClose h if (r /= size_i) then ioError (userError "short read of file") else do #if __GLASGOW_HASKELL__ < 503 frozen <- stToIO (unsafeFreezeByteArray arr) case frozen of ByteArray _ _ bytearr# -> return (StringBuffer bytearr# sz# 0#) #else frozen <- unsafeFreeze arr case frozen of UArray _ _ bytearr# -> return (StringBuffer bytearr# sz# 0#) #endif #if __GLASGOW_HASKELL__ >= 502 stringToStringBuffer str = do let size@(I# sz#) = length str arr = listArray (0,size-1) (map (fromIntegral.ord) str) :: UArray Int Word8 case arr of UArray _ _ bytearr# -> return (StringBuffer bytearr# sz# 0#) #else stringToStringBuffer = panic "stringToStringBuffer: not implemented" #endif -- ----------------------------------------------------------------------------- -- Lookup currentChar :: StringBuffer -> Char currentChar (StringBuffer arr# l# current#) = ASSERT(current# <# l#) C# (indexCharArray# arr# current#) prevChar :: StringBuffer -> Char -> Char prevChar (StringBuffer _ _ 0#) deflt = deflt prevChar s deflt = lookAhead s (-1) lookAhead :: StringBuffer -> Int -> Char lookAhead (StringBuffer arr# l# c#) (I# i#) = ASSERT(off <# l# && off >=# 0#) C# (indexCharArray# arr# off) where off = c# +# i# -- ----------------------------------------------------------------------------- -- Moving stepOn :: StringBuffer -> StringBuffer stepOn s = stepOnBy 1 s stepOnBy :: Int -> StringBuffer -> StringBuffer stepOnBy (I# i#) (StringBuffer fo# l# c#) = StringBuffer fo# l# (c# +# i#) atEnd :: StringBuffer -> Bool atEnd (StringBuffer _ l# c#) = l# ==# c# -- ----------------------------------------------------------------------------- -- Conversion lexemeToString :: StringBuffer -> Int -> String lexemeToString _ 0 = "" lexemeToString (StringBuffer arr# _ current#) (I# len#) = unpack current# where end = current# +# len# unpack nh | nh >=# end = [] | otherwise = C# ch : unpack (nh +# 1#) where ch = indexCharArray# arr# nh lexemeToFastString :: StringBuffer -> Int -> FastString lexemeToFastString _ 0 = mkFastString "" lexemeToFastString (StringBuffer fo _ current#) (I# len) = mkFastSubStringBA# fo current# len -- ----------------------------------------------------------------------------- -- Parsing integer strings in various bases parseInteger :: StringBuffer -> Int -> Integer -> (Char->Int) -> Integer parseInteger buf len radix to_int = go 0 0 where go i x | i == len = x | otherwise = go (i+1) (x * radix + toInteger (to_int (lookAhead buf i))) \end{code}