    {-# LANGUAGE CPP, BangPatterns #-}
    {-# OPTIONS -Wall #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Language.C.Data.InputStream
    -- Copyright   :  (c) 2008 Benedikt Huber
    -- License     :  BSD-style
    -- Maintainer  :  benedikt.huber@gmail.com
    -- Stability   :  experimental
    -- Portability :  ghc
    --
    -- Compile time input abstraction for the parser.
    -- Supports either ByteString or String.
    -------------------------------------------------------------------------------
    module Language.C.Data.InputStream (
        InputStream, readInputStream,inputStreamToString,inputStreamFromString,
        takeChar,inputStreamEmpty,takeChars,
        countLines,
    )
    where
    #ifndef NO_BYTESTRING
    import Data.ByteString.Char8 (ByteString)
    import qualified Data.ByteString.Char8 as BS
    #endif

    -- Generic InputStream stuff

    -- | read a file into an 'InputStream'
    readInputStream :: FilePath -> IO InputStream

    -- | convert 'InputStream' to 'String'
    inputStreamToString :: InputStream -> String
    {-# INLINE inputStreamToString #-}

    -- | convert a 'String' to an 'InputStream'
    inputStreamFromString :: String -> InputStream

    -- | @(c,is') = takeChar is@ reads and removes
    -- the first character @c@ from the 'InputStream' @is@
    takeChar :: InputStream -> (Char, InputStream)
    {-# INLINE takeChar #-}

    -- | return @True@ if the given input stream is empty
    inputStreamEmpty :: InputStream -> Bool
    {-# INLINE inputStreamEmpty #-}

    -- | @str = takeChars n is@ returns the first @n@ characters
    -- of the given input stream, without removing them
    takeChars :: Int -> InputStream -> [Char]
    {-# INLINE takeChars #-}

    -- | @countLines@ returns the number of text lines  in the
    -- given 'InputStream'
    countLines :: InputStream -> Int

    #ifndef NO_BYTESTRING
    type InputStream = ByteString
    takeChar bs = BS.head bs `seq`  (BS.head bs, BS.tail bs)
    inputStreamEmpty = BS.null
    #ifndef __HADDOCK__
    takeChars !n bstr = BS.unpack $ BS.take n bstr --leaks
    #endif
    readInputStream = BS.readFile
    inputStreamToString = BS.unpack
    inputStreamFromString = BS.pack
    countLines = length . BS.lines
    #else
    type InputStream = String
    takeChar bs = (head bs, tail bs)
    inputStreamEmpty = null
    takeChars n str = take n str
    readInputStream = readFile
    inputStreamToString = id
    inputStreamFromString = id
    countLines = length . lines
    #endif