content: {-# LANGUAGE CPP, BangPatterns #-}
  {-# OPTIONS -Wall #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Language.C.Data.InputStream
  -- Copyright   :  (c) 2008,2011 Benedikt Huber
  -- License     :  BSD-style
  -- Maintainer  :  benedikt.huber@gmail.com
  -- Stability   :  experimental
  -- Portability :  ghc
  --
  -- Compile time input abstraction for the parser, relying on ByteString.
  -- The String interface only supports Latin-1 since alex-3, as alex now requires
  -- byte based access to the input stream.
  -------------------------------------------------------------------------------
  module Language.C.Data.InputStream (
      InputStream, readInputStream,inputStreamToString,inputStreamFromString,
      takeByte, takeChar, inputStreamEmpty, takeChars,
      countLines,
  )
  where
  
  import Data.Word
  
  #ifndef NO_BYTESTRING
  import Data.ByteString (ByteString)
  import qualified Data.ByteString as BSW
  import qualified Data.ByteString.Char8 as BSC
  #else
  import qualified Data.Char as Char
  #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
  
  -- | @(b,is') = takeByte is@ reads and removes
  -- the first byte @b@ from the 'InputStream' @is@
  takeByte :: InputStream -> (Word8, InputStream)
  {-# INLINE takeByte #-}
  
  -- | @(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
  takeByte bs = BSW.head  bs `seq`  (BSW.head bs, BSW.tail bs)
  takeChar bs = BSC.head bs `seq`  (BSC.head bs, BSC.tail bs)
  inputStreamEmpty = BSW.null
  #ifndef __HADDOCK__
  takeChars !n bstr = BSC.unpack $ BSC.take n bstr --leaks
  #endif
  readInputStream       = BSW.readFile
  
  inputStreamToString   = BSC.unpack
  inputStreamFromString = BSC.pack
  countLines             = length . BSC.lines
  
  
  #else
  
  type InputStream = String
  takeByte bs
    | Char.isLatin1 c = let b = fromIntegral (Char.ord c) in b `seq` (b, tail bs)
    | otherwise       = error "takeByte: not a latin-1 character"
    where c = head bs
  takeChar bs = (head bs, tail bs)
  inputStreamEmpty = null
  takeChars n str = take n str
  readInputStream = readFile
  inputStreamToString = id
  inputStreamFromString = id
  countLines = length . lines
  #endif
  
  