diff --git a/attoparsec.cabal b/attoparsec.cabal
--- a/attoparsec.cabal
+++ b/attoparsec.cabal
@@ -1,11 +1,13 @@
 name:            attoparsec
-version:         0.5.1
+version:         0.6
 license:         BSD3
 license-file:    LICENSE
 category:        Text, Parsing
 author:          Bryan O'Sullivan <bos@serpentine.com>
+maintainer:      Bryan O'Sullivan <bos@serpentine.com>
 stability:       experimental
-synopsis:        Combinator parsing with Data.ByteString.Lazy
+synopsis:        Fast combinator parsing with Data.ByteString.Lazy
+description:     Fast combinator parsing with Data.ByteString.Lazy
 cabal-version:   >= 1.2
 build-type:      Simple
 description:     Fast, flexible text-oriented parsing of lazy ByteStrings.
@@ -26,6 +28,8 @@
     cpp-options: -DAPPLICATIVE_IN_BASE
   else
     build-depends: base < 2.0
+
+  build-depends: bytestring-lexing >= 0.2
 
   extensions:      CPP
   exposed-modules: Data.ParserCombinators.Attoparsec
diff --git a/src/Data/ParserCombinators/Attoparsec.hs b/src/Data/ParserCombinators/Attoparsec.hs
--- a/src/Data/ParserCombinators/Attoparsec.hs
+++ b/src/Data/ParserCombinators/Attoparsec.hs
@@ -28,6 +28,8 @@
 
     -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
     , try
+    , many
+    , many1
     , manyTill
     , eof
     , skipMany
diff --git a/src/Data/ParserCombinators/Attoparsec/Char8.hs b/src/Data/ParserCombinators/Attoparsec/Char8.hs
--- a/src/Data/ParserCombinators/Attoparsec/Char8.hs
+++ b/src/Data/ParserCombinators/Attoparsec/Char8.hs
@@ -28,6 +28,8 @@
 
     -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
     , try
+    , many
+    , many1
     , manyTill
     , eof
     , skipMany
@@ -52,6 +54,11 @@
     -- * Parser converters.
     , eitherP
 
+    -- * Numeric parsers.
+    , int
+    , integer
+    , double
+
     -- * Miscellaneous functions.
     , getInput
     , getConsumed
@@ -59,6 +66,7 @@
     , takeWhile1
     , takeTill
     , takeAll
+    , takeCount
     , skipWhile
     , skipSpace
     , notEmpty
@@ -79,7 +87,9 @@
 import Data.ParserCombinators.Attoparsec.Internal
     (Parser, ParseError, (<?>), parse, parseAt, parseTest, try, manyTill, eof,
      skipMany, skipMany1, count, lookAhead, peek, sepBy, sepBy1, string,
-     eitherP, getInput, getConsumed, takeAll, notEmpty, match, endOfLine)
+     eitherP, getInput, getConsumed, takeAll, takeCount, notEmpty, match,
+     endOfLine, setInput, many, many1)
+import Data.ByteString.Lex.Lazy.Double (readDouble)
 import Prelude hiding (takeWhile)
 
 -- | Character parser.
@@ -155,3 +165,22 @@
 skipSpace :: Parser ()
 skipSpace = takeWhile isSpace >> return ()
 {-# INLINE skipSpace #-}
+
+numeric :: String -> (LB.ByteString -> Maybe (a,LB.ByteString)) -> Parser a
+numeric desc f = do
+  s <- getInput
+  case f s of
+    Nothing -> fail desc
+    Just (i,s') -> setInput s' >> return i
+                   
+-- | Parse an integer.  The position counter is not updated.
+int :: Parser Int
+int = numeric "Int" LB.readInt
+
+-- | Parse an integer.  The position counter is not updated.
+integer :: Parser Integer
+integer = numeric "Integer" LB.readInteger
+
+-- | Parse a Double.  The position counter is not updated.
+double :: Parser Double
+double = numeric "Double" readDouble
diff --git a/src/Data/ParserCombinators/Attoparsec/Internal.hs b/src/Data/ParserCombinators/Attoparsec/Internal.hs
--- a/src/Data/ParserCombinators/Attoparsec/Internal.hs
+++ b/src/Data/ParserCombinators/Attoparsec/Internal.hs
@@ -28,6 +28,8 @@
 
     -- * Things vaguely like those in @Parsec.Combinator@ (and @Parsec.Prim@)
     , try
+    , many
+    , many1
     , manyTill
     , eof
     , skipMany
@@ -52,10 +54,12 @@
     -- * Miscellaneous functions.
     , getInput
     , getConsumed
+    , setInput
     , takeWhile
     , takeWhile1
     , takeTill
     , takeAll
+    , takeCount
     , skipWhile
     , notEmpty
     , match
@@ -77,6 +81,9 @@
 
 type ParseError = String
 
+-- State invariants:
+-- * If both strict and lazy bytestrings are empty, the entire input
+--   is considered to be empty.
 data S = S {-# UNPACK #-} !SB.ByteString
            LB.ByteString
            {-# UNPACK #-} !Int64
@@ -167,6 +174,10 @@
 getInput :: Parser LB.ByteString
 getInput = Parser $ \s@(S sb lb _) -> Right (sb +: lb, s)
 
+-- | Set the remaining input.
+setInput :: LB.ByteString -> Parser ()
+setInput bs = Parser $ \(S _ _ n) -> Right ((), mkState bs n)
+
 -- | Get number of bytes consumed so far.
 getConsumed :: Parser Int64
 getConsumed = Parser $ \s@(S _ _ n) -> Right (n, s)
@@ -176,7 +187,7 @@
 satisfy p =
     Parser $ \s@(S sb lb n) ->
            case SB.uncons sb of
-             Just (c, sb') | p c -> Right (c, S sb' lb (n + 1))
+             Just (c, sb') | p c -> Right (c, mkState (sb' +: lb) (n + 1))
                            | otherwise -> Left (sb +: lb, [])
              Nothing -> unParser (nextChunk >> satisfy p) s
 {-# INLINE satisfy #-}
@@ -215,14 +226,16 @@
 endOfLine :: Parser ()
 endOfLine = Parser $ \(S sb lb n) ->
             let bs = sb +: lb
-            in case I.w2c (U.unsafeHead sb) of
-                 '\n' -> Right ((), mkState (LB.tail bs) (n + 1))
-                 '\r' -> let (h,t) = LB.splitAt 2 bs
-                             rn = L8.pack "\r\n"
-                         in if h == rn
-                            then Right ((), mkState t (n + 2))
-                            else Right ((), mkState (LB.tail bs) (n + 1))
-                 _ -> Left (bs, ["EOL"])
+            in if SB.null sb
+               then Left (bs, ["EOL"])
+               else case I.w2c (U.unsafeHead sb) of
+                     '\n' -> Right ((), mkState (LB.tail bs) (n + 1))
+                     '\r' -> let (h,t) = LB.splitAt 2 bs
+                                 rn = L8.pack "\r\n"
+                             in if h == rn
+                                then Right ((), mkState t (n + 2))
+                                else Right ((), mkState (LB.tail bs) (n + 1))
+                     _ -> Left (bs, ["EOL"])
 
 -- | Satisfy a literal string, after applying a transformation to both
 -- it and the matching text.
@@ -260,6 +273,15 @@
           let bs = sb +: lb
           in Right (bs, mkState LB.empty (n + LB.length bs))
 
+takeCount :: Int64 -> Parser LB.ByteString
+takeCount k =
+  Parser $ \(S sb lb n) ->
+      let bs = sb +: lb
+          (h,t) = LB.splitAt k bs
+      in if LB.length h == k
+         then Right (h, mkState t (n + k))
+         else Left (bs, [show k ++ " bytes"])
+
 -- | Consume characters while the predicate is true.
 takeWhile :: (Word8 -> Bool) -> Parser LB.ByteString
 takeWhile p =
@@ -293,6 +315,12 @@
 manyTill p end = scan
     where scan = (end >> return []) <|> liftM2 (:) p scan
 
+many :: Parser a -> Parser [a]
+many p = ((:) <$> p <*> many p) <|> return []
+
+many1 :: Parser a -> Parser [a]
+many1 p = (:) <$> p <*> many p
+
 -- |'skipMany' - skip zero or many instances of the parser
 skipMany :: Parser a -> Parser ()
 skipMany p = scan
@@ -342,7 +370,7 @@
 parseAt p bs n = 
     case unParser p (mkState bs n) of
       Left (bs', msg) -> (bs', Left $ showError msg)
-      Right (a, S sb lb n') -> (sb +: lb, Right (a, n'))
+      Right (a, ~(S sb lb n')) -> (sb +: lb, Right (a, n'))
     where
       showError [""] = "Parser error\n"
       showError [msg] = "Parser error, expected:\n" ++ msg ++ "\n"
