module Text.PortableLines.ByteString
    ( lines8
    ) where

import Prelude as P hiding (lines)

import Data.ByteString.Char8 (ByteString)
import Data.ByteString.Unsafe (unsafeIndex, unsafeTail, unsafeDrop)

import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8

-- | Like the 'B8.lines' function from Data.ByteString.Char8, but treat the
-- @\"\\r\\n\"@ and @\"\\r\"@ sequences as newlines too, not just @\"\\n\"@.
--
-- Input is assumed to be in ASCII or an ASCII-compatible encoding (at least
-- with respect to newline characters).  For example, UTF-8 is fine, but UTF-16
-- is not.
lines8 :: ByteString -> [ByteString]
lines8 str | B.null str = []
           | otherwise  = let (line, rest) = breakNewline8 str
                           in line : lines8 rest

breakNewline8 :: ByteString -> (ByteString, ByteString)
breakNewline8 str =
    case B.break (\c -> c == 13 || c == 10) str of
        (line, rest) | B.null rest                      -> (line, rest)
                     | B.length rest >= 2 &&
                       rest `unsafeIndex` 0 == 13 &&
                       rest `unsafeIndex` 1 == 10       -> (line, unsafeDrop 2 rest)
                     | otherwise                        -> (line, unsafeTail rest)