diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Release 0.28.0.0
+
+* Renamed everything from System.Console.MultiArg to Multiarg
+  (shorter; note also case change from MultiArg to Multiarg)
+
+* Removed existentials from Multiarg.CommandLine
+
 Release 0.24.0.4, February 24, 2014
 
 * Changed lower bound on base down to 4.5.0.0
diff --git a/lib/Multiarg.hs b/lib/Multiarg.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg.hs
@@ -0,0 +1,167 @@
+-- | A combinator library for building command-line parsers.
+
+module Multiarg (
+
+  -- | To say this library is inspired by Parsec would probably insult the
+  -- creators of Parsec, as this library could not possibly be as
+  -- elegant or throughly considered as Parsec is. Nevertheless this
+  -- library can be used in a similar style as Parsec, but is
+  -- specialized for parsing command lines.
+  --
+  -- This parser was built because I could not find anything that would
+  -- readily parse command lines where the options took more than one
+  -- argument. For example, for the @tail@ command on GNU systems, the
+  -- --lines option takes one argument to specify how many lines you
+  -- want to see. Well, what if you want to build a program with an
+  -- option that takes /two/ arguments, like @--foo bar baz@? I found no
+  -- such library so I built this one. Nevertheless, using this library
+  -- you can build parsers to parse a variety of command line
+  -- vocabularies, from simple to complex.
+
+  -- * Terminology
+
+  -- | Some terms are used throughout multiarg:
+  --
+  -- [@word@] When you run your program from the Unix shell prompt,
+  -- your shell is responsible for splitting the command line into
+  -- words. Typically you separate words with spaces, although quoting
+  -- can affect this. multiarg parses lists of words. Each word can
+  -- consist of a single long option, a single long option and an
+  -- accompanying option argument, a single short option, multiple
+  -- short options, and even one or more multiple short options and an
+  -- accompanying short option argument. Or, a word can be a
+  -- positional argument or a stopper. All these are described below.
+  --
+  -- [@option@] Options allow a user to specify ways to tune the
+  -- operation of a program. Typically options are indeed optional,
+  -- although some programs do sport \"required options\" (a bit of an
+  -- oxymoron). Options can be either short options or long
+  -- options. Also, options can take arguments.
+  --
+  -- [@short option@] An option that is specified with a single hyphen
+  -- and a single letter. For example, for the program @tail(1)@,
+  -- possible short options include @n@ and @v@. With multiarg it is
+  -- possible to easily parse short options that are specified in
+  -- different words or in the same word. For example, if a user wants
+  -- to run @tail@ with two options, he might type @tail -v -f@ or he
+  -- might type @tail -vf@.
+  --
+  -- [@long option@] An option that is specified using two hyphens and
+  -- what is usually a mnemonic word, though it could be as short as a
+  -- single letter. For example, @tail(1)@ has long options including
+  -- @follow@ and @verbose@. The user would specify these on the
+  -- command line by typing @tail --follow --verbose@.
+  --
+  -- [@option argument@] Some options take additional arguments that
+  -- are specific to the option and change what the option does. For
+  -- instance, the @lines@ option to @tail(1)@ takes a single,
+  -- optional argument, which is the number of lines to show. Option
+  -- arguments can be optional or required, and a single option can
+  -- take a mulitple, fixed number of arguments and it can take a
+  -- variable number of arguments. Option arguments can be given in
+  -- various ways. They can be specified in the same word as a long
+  -- option by using an equals sign; they can also be specified in the
+  -- same word as a short option simply by placing them in the same
+  -- word, or they can be specified in the following word. For
+  -- example, these different command lines all mean the same thing;
+  -- @tail --verbose --lines=20@, @tail --verbose --lines 20@, @tail
+  -- -vn 20@, @tail -v -n20@, @tail -vn20@, and @tail -v -n 20@, and
+  -- numerous other combinations also have the same meaning.
+  --
+  -- [@GNU-style option argument@] A long option with an argument
+  -- given with an equal sign, such as [@lines=20@].
+  --
+  -- [@positional argument@] A word on the command line that is not an
+  -- option or an argument to an option. For instance, with @tail(1)@,
+  -- you specify the files you want to see by using positional
+  -- arguments. In the command @tail -n 10 myfile@, @myfile@ is a
+  -- positional argument. For some programs, such as @git@ or @darcs@,
+  -- a positional argument might be a \"command\" or a \"mode\", such
+  -- as the @commit@ in @git commit@ or the @whatsnew@ in @darcs
+  -- whatsnew@. multiarg has no primitive parsers that treat these
+  -- positional arguments specially but it is trivial to build a
+  -- parser for command lines such as this, too.
+  --
+  -- [@stopper@] A single word consisting solely of two hyphens,
+  -- @--@. The user types this to indicate that all subsequent words
+  -- on the command line are positional arguments, even if they begin
+  -- with hyphens and therefore look like they might be options.
+  --
+  -- [@pending@] The user might specify more than one short option, or
+  -- a short option and a short option argument, in a single word. For
+  -- example, she might type @tail -vl20@. After parsing the @v@
+  -- option, the Parser makes @l20@ into a \"pending\". The next
+  -- parser can then treat @l20@ as an option argument to the @v@
+  -- option (which is probably not what was wanted) or the next parser
+  -- can parse @l@ as a short option. This would result in a
+  -- \"pending\" of @20@. Then, the next parser can treat @20@ as an
+  -- option argument. After that parse there will be no pendings.
+
+  -- * Getting started
+
+  -- |If your needs are simple to moderately complicated just look at the
+  -- "Multiarg.CommandLine" module, which uses the
+  -- underlying combinators to build a simple parser for you. That
+  -- module is already exported from this module for easy usage.
+  --
+  -- "Multiarg.CommandLine" also has a parser that can
+  -- handle multi-mode commands (examples include @git@, @darcs@, and
+  -- @cvs@.)
+  --
+  -- For maximum flexibility you will want to start with the
+  -- "Multiarg.Prim" module. Using those parsers you
+  -- can easily build parsers that are quite complicated. The parsers
+  -- can check for errors along the way, simplifying the sometimes
+  -- complex task of ensuring that data a user supplied on the command
+  -- line is good. You can easily build parsers for programs that take
+  -- no options, take dozens of options, require that options be given
+  -- in a particular order, require that some options be given, or bar
+  -- some combinations of options. You might also require particular
+  -- positional arguments. Other helpful functions are in
+  -- "Multiarg.Combinator". You will also want to
+  -- examine the source code for "Multiarg.Combinator"
+  -- and "Multiarg.CommandLine" as these show some
+  -- ways to use the primitive parsers and combinators.
+
+  -- * Non-features and shortcomings
+  --
+  -- | multiarg isn't perfect; no software is. multiarg does not
+  -- automatically make online help for your command line
+  -- parsers. Getting this right would be tricky given the nature of
+  -- the code and I don't even want to bother trying, as I just write
+  -- my own online help in a text editor.
+  --
+  -- multiarg partially embraces \"The Tao of Option Parsing\" that
+  -- Python's Optik (<http://optik.sourceforge.net/>) follows. Read
+  -- \"The Tao of Option Parsing\" here:
+  --
+  -- <http://optik.sourceforge.net/doc/1.5/tao.html>
+  --
+  -- multiarg's philosophy is similar to that of Optik, which
+  -- means you won't be able to use multiarg to (easily) build a clone
+  -- to the UNIX @find(1)@ command. (You could do it, but multiarg won't
+  -- help you very much.)
+  --
+  -- multiarg can be complicated, although I'd like to believe this is
+  -- because it addresses a complicated problem in a flexible way.
+
+  -- * Projects usings multiarg
+
+  -- | * Penny, an extensible double-entry accounting
+  -- system. <http://hackage.haskell.org/package/penny-lib> The code
+  -- using multiarg is woven throughout the system; for example, see
+  -- the Penny.Liberty module.
+
+
+    module Multiarg.Combinator
+  , module Multiarg.CommandLine
+  , module Multiarg.Option
+  , module Multiarg.Prim
+  , module System.Environment
+  ) where
+
+import Multiarg.Combinator
+import Multiarg.CommandLine
+import Multiarg.Option
+import Multiarg.Prim
+import System.Environment
diff --git a/lib/Multiarg/Combinator.hs b/lib/Multiarg/Combinator.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg/Combinator.hs
@@ -0,0 +1,478 @@
+-- | Combinators that are useful for building command-line
+-- parsers. These build off the functions in
+-- "Multiarg.Prim". Unlike those functions, these
+-- functions have no access to the internals of the parser.
+module Multiarg.Combinator (
+  -- * Parser combinators
+  notFollowedBy,
+
+  -- * Combined long and short option parser
+  OptSpec(OptSpec, longOpts, shortOpts, argSpec),
+  InputError(..),
+  reader,
+  optReader,
+  ArgSpec(..),
+  parseOption,
+
+  -- * Formatting errors
+  formatError
+  ) where
+
+import Data.List (isPrefixOf, intersperse, nubBy)
+import Data.Set ( Set )
+import qualified Data.Set as Set
+import Control.Applicative
+       ((<*>), optional, (<$), (*>), (<|>), many)
+
+import Multiarg.Prim
+  ( Parser, try, approxLongOpt,
+    nextWord, pendingShortOptArg, nonOptionPosArg,
+    pendingShortOpt, nonPendingShortOpt, nextWord, (<?>),
+    Error(..), Description(..))
+import Multiarg.Option
+  ( LongOpt, ShortOpt, unLongOpt,
+    makeLongOpt, makeShortOpt, unShortOpt )
+import qualified Data.Map as M
+import Data.Map ((!))
+import Data.Maybe (fromMaybe, mapMaybe)
+import Data.Monoid ( mconcat )
+
+
+-- | @notFollowedBy p@ succeeds only if parser p fails. If p fails,
+-- notFollowedBy succeeds without consuming any input. If p succeeds
+-- and consumes input, notFollowedBy fails and consumes input. If p
+-- succeeds and does not consume any input, notFollowedBy fails and
+-- does not consume any input.
+notFollowedBy :: Parser a -> Parser ()
+notFollowedBy p =
+  () <$ ((try p >> fail "notFollowedBy failed")
+         <|> return ())
+
+
+unsafeShortOpt :: Char -> ShortOpt
+unsafeShortOpt c =
+  fromMaybe (error $ "invalid short option: " ++ [c])
+            (makeShortOpt c)
+
+unsafeLongOpt :: String -> LongOpt
+unsafeLongOpt c =
+  fromMaybe (error $ "invalid long option: " ++ c)
+            (makeLongOpt c)
+
+
+-- |Specifies options for the 'parseOption' function. Each OptSpec
+-- represents one command-line option.
+data OptSpec a = OptSpec {
+  longOpts :: [String]
+  -- ^ Each String is a single long option, such as @version@. When
+  -- the user specifies long options on the command line, she must
+  -- type two dashes; however, do not include the dashes when you
+  -- specify the long option here. Strings you specify as long options
+  -- cannot include a dash as either the first or the second
+  -- character, and they cannot include an equal sign anywhere. If
+  -- your long option does not meet these conditions, a runtime error
+  -- will occur.
+
+
+  , shortOpts :: [Char]
+    -- ^ Each Char is a single short option, such as @v@. The
+    -- character cannot be a dash; if it is, a runtime error will occur.
+
+  , argSpec :: ArgSpec a
+    -- ^ What to do each time one of the given long options or
+    -- short options appears on the command line.
+  }
+
+instance Functor OptSpec where
+  fmap f (OptSpec ls ss as) = OptSpec ls ss (fmap f as)
+
+-- | Reads in values that are members of Read. Provides a generic
+-- error message if the read fails.
+reader :: Read a => String -> Either InputError a
+reader s = case reads s of
+  (x, ""):[] -> return x
+  _ -> Left . ErrorMsg $ "could not parse option argument"
+
+-- | Reads in values that are members of Read, but the value does not
+-- have to appear on the command line. Provides a generic error
+-- message if the read fails. If the argument is Nothing, returns
+-- Nothing.
+optReader
+  :: Read a
+  => Maybe String
+  -> Either InputError (Maybe a)
+optReader ms = case ms of
+  Nothing -> return Nothing
+  Just s -> case reads s of
+    (x, ""):[] -> return (Just x)
+    _ -> Left . ErrorMsg $ "could not parse option argument"
+
+-- | Indicates errors when parsing options to arguments.
+data InputError
+  = NoMsg
+  -- ^ No error message accompanies this failure. multiarg will create
+  -- a generic error message for you.
+
+  | ErrorMsg String
+  -- ^ Parsing the argument failed with this error message. An example
+  -- might be @option argument is not an integer@ or @option argument
+  -- is too large@. The text of the options the user provided is
+  -- automatically prepended to the error message, so do not replicate
+  -- this in your message.
+
+  deriving (Eq, Show)
+
+-- | Create an error message from an InputError.
+errorMsg
+  :: Either LongOpt ShortOpt
+  -- ^ The option with the faulty argument
+
+  -> [String]
+  -- ^ The faulty command line arguments
+
+  -> InputError
+  -> String
+errorMsg badOpt ss err = arg ++ opt ++ msg
+  where
+    arg = let aw = if length ss > 1 then "arguments " else "argument "
+              ws = concat . intersperse " " . map quote $ ss
+              quote s = "\"" ++ s ++ "\""
+          in aw ++ ws
+    opt = " to option " ++ optDesc
+    optDesc = case badOpt of
+      Left lo -> "--" ++ unLongOpt lo
+      Right so -> "-" ++ [unShortOpt so]
+    msg = " invalid" ++ detail
+    detail = case err of
+      NoMsg -> ""
+      ErrorMsg s -> ": " ++ s
+
+
+
+-- | Specifies how many arguments each option takes. As with
+-- 'System.Console.GetOpt.ArgDescr', there are (at least) two ways to
+-- use this type. You can simply represent each possible option using
+-- different data constructors in an algebraic data type. Or you can
+-- have each ArgSpec yield a function that transforms a record. For an
+-- example that uses an algebraic data type, see
+-- "Multiarg.SampleParser".
+--
+-- Most of these value constructors take as an argument a function
+-- that returns an Either.  The function should return a @Left
+-- InputError@ if the parsing of the arguments failed--if, for
+-- example, the user needs to enter an integer but she instead input a
+-- letter.  The functions should return a Right if parsing of the
+-- arguments was successful.
+data ArgSpec a =
+  NoArg a
+  -- ^ This option takes no arguments
+
+  | OptionalArg (Maybe String -> Either InputError a)
+    -- ^ This option takes an optional argument. As noted in \"The Tao
+    -- of Option Parsing\", optional arguments can result in some
+    -- ambiguity. (Read it here:
+    -- <http://optik.sourceforge.net/doc/1.5/tao.html>) If option @a@
+    -- takes an optional argument, and @b@ is also an option, what
+    -- does @-ab@ mean? SimpleParser resolves this ambiguity by
+    -- assuming that @b@ is an argument to @a@. If the user does not
+    -- like this, she can specify @-a -b@ (in such an instance @-b@ is
+    -- not parsed as an option to @-a@, because @-b@ begins with a
+    -- hyphen and therefore \"looks like\" an option.) Certainly
+    -- though, optional arguments lead to ambiguity, so if you don't
+    -- like it, don't use them :)
+
+  | OneArg (String -> Either InputError a)
+    -- ^ This option takes one argument. Here, if option @a@ takes one
+    -- argument, @-a -b@ will be parsed with @-b@ being an argument to
+    -- option @a@, even though @-b@ starts with a hyphen and therefore
+    -- \"looks like\" an option.
+
+  | TwoArg (String -> String -> Either InputError a)
+    -- ^ This option takes two arguments. Parsed similarly to
+    -- 'OneArg'.
+
+  | ThreeArg (String -> String -> String -> Either InputError a)
+    -- ^ This option takes three arguments. Parsed similarly to
+    -- 'OneArg'.
+
+  | VariableArg ([String] -> Either InputError a)
+    -- ^ This option takes a variable number of arguments--zero or
+    -- more. Option arguments continue until the command line contains
+    -- a word that begins with a hyphen. For example, if option @a@
+    -- takes a variable number of arguments, then @-a one two three
+    -- -b@ will be parsed as @a@ taking three arguments, and @-a -b@
+    -- will be parsed as @a@ taking no arguments. If the user enters
+    -- @-a@ as the last option on the command line, then the only way
+    -- to indicate the end of arguments for @a@ and the beginning of
+    -- positional argments is with a stopper.
+
+  | ChoiceArg [(String, a)]
+    -- ^ This option takes a single argument, which must match one of
+    -- the strings given in the list. The user may supply the shortest
+    -- unambiguous string. If the argument list to ChoiceArg has
+    -- duplicate strings, only the first string is used. For instance,
+    -- ChoiceArg could be useful if you were parsing the @--color@
+    -- option to GNU grep, which requires the user to supply one of
+    -- three arguments: @always@, @never@, or @auto@.
+
+
+instance Functor ArgSpec where
+  fmap f a = case a of
+    NoArg i -> NoArg $ f i
+    ChoiceArg gs ->
+      ChoiceArg . map (\(s, r) -> (s, f r)) $ gs
+
+    OptionalArg g -> OptionalArg $ \ms -> fmap f (g ms)
+
+    OneArg g ->
+      OneArg $ \s1 -> fmap f (g s1)
+
+    TwoArg g ->
+      TwoArg $ \s1 s2 -> fmap f (g s1 s2)
+
+    ThreeArg g ->
+      ThreeArg $ \s1 s2 s3 -> fmap f (g s1 s2 s3)
+
+    VariableArg g ->
+      VariableArg $ \ls -> fmap f (g ls)
+
+
+-- | Parses a single command line option. Examines all the options
+-- specified using multiple OptSpec and parses one option on the
+-- command line accordingly. Fails without consuming any input if the
+-- next word on the command line is not a recognized option. Allows
+-- the user to specify the shortest unambiguous match for long
+-- options; for example, the user could type @--verb@ for @--verbose@
+-- and @--vers@ for @--version@.
+--
+-- This function is applied to a list of OptSpec, rather than to a
+-- single OptSpec, because in order to correctly handle the parsing of
+-- shortened long options (e.g. @--verb@ rather than @--verbose@) it
+-- is necessary for one function to have access to all of the
+-- OptSpec. Applying this function multiple times to different lists
+-- of OptSpec and then using the @<|>@ function to combine them will
+-- break the proper parsing of shortened long options.
+--
+-- For an example that uses this function, see
+-- "Multiarg.SimpleParser".
+parseOption :: [OptSpec a] -> Parser a
+parseOption os =
+  let longs = longOptParser os
+  in case mconcat ([shortOpt] <*> os) of
+    Nothing -> longs
+    Just shorts -> longs <|> shorts
+
+longOptParser :: [OptSpec a] -> Parser a
+longOptParser os = longOpt (longOptSet os) (longOptMap os)
+
+
+longOptSet :: [OptSpec a] -> Set LongOpt
+longOptSet = Set.fromList . concatMap toOpts where
+  toOpts = map unsafeLongOpt . longOpts
+
+longOptMap :: [OptSpec a] -> M.Map LongOpt (ArgSpec a)
+longOptMap = M.fromList . concatMap toPairs where
+  toPairs (OptSpec los _ as) = map (toPair as) los where
+    toPair a s = (unsafeLongOpt s, a)
+
+longOpt ::
+  Set LongOpt
+  -> M.Map LongOpt (ArgSpec a)
+  -> Parser a
+longOpt set mp = do
+  (_, lo, maybeArg) <- approxLongOpt set
+  let spec = mp ! lo
+      maybeNextArg = maybe nextWord return maybeArg
+  case spec of
+    NoArg a -> case maybeArg of
+      Nothing -> return a
+      Just _ -> fail $ "option " ++ unLongOpt lo
+                  ++ " does not take argument"
+    ChoiceArg ls -> do
+      s <- maybeNextArg
+      case matchAbbrev ls s of
+        Nothing -> fail $ "option " ++ unLongOpt lo
+                   ++ " requires an argument: "
+                   ++ (concat . intersperse ", " . map fst $ ls)
+        Just g -> return g
+
+    OptionalArg f -> case maybeArg of
+      Nothing -> either (fail . errorMsg (Left lo) []) return
+                 $ f Nothing
+      Just s -> either (fail . errorMsg (Left lo) [s]) return
+                $ f (Just s)
+
+
+    OneArg f -> maybeNextArg >>= g
+      where
+        g a = either (fail . errorMsg (Left lo) [a]) return
+              $ f a
+
+    TwoArg f -> do
+      a1 <- maybeNextArg
+      a2 <- nextWord
+      either (fail . errorMsg (Left lo) [a1, a2]) return
+        $ f a1 a2
+
+    ThreeArg f -> do
+      a1 <- maybeNextArg
+      a2 <- nextWord
+      a3 <- nextWord
+      either (fail . errorMsg (Left lo) [a1, a2, a3]) return
+        $ f a1 a2 a3
+
+    VariableArg f -> do
+      as <- many nonOptionPosArg
+      let args = case maybeArg of
+            Nothing -> as
+            Just a -> a:as
+      either (fail . errorMsg (Left lo) args) return
+        $ f args
+
+
+shortOpt :: OptSpec a -> Maybe (Parser a)
+shortOpt o = mconcat parsers where
+  parsers = map mkParser . shortOpts $ o
+  mkParser c =
+    let opt = unsafeShortOpt c
+    in Just $ nextShort opt *> case argSpec o of
+      NoArg a -> return a
+      ChoiceArg ls -> shortChoiceArg opt ls
+      OptionalArg f -> shortOptionalArg opt f
+      OneArg f -> shortOneArg opt f
+      TwoArg f -> shortTwoArg opt f
+      ThreeArg f -> shortThreeArg opt f
+      VariableArg f -> shortVariableArg opt f
+
+-- | Parses a short option without an argument, either pending or
+-- non-pending. Fails with a single error message rather than two.
+nextShort :: ShortOpt -> Parser ()
+nextShort o = p <?> ("short option: -" ++ [unShortOpt o])
+  where
+    p = do
+      r1 <- optional $ pendingShortOpt o
+      case r1 of
+        Just () -> return ()
+        Nothing -> nonPendingShortOpt o
+
+
+shortVariableArg
+  :: ShortOpt
+  -> ([String] -> Either InputError a)
+  -> Parser a
+shortVariableArg so f = do
+  maybeSameWordArg <- optional pendingShortOptArg
+  args <- many nonOptionPosArg
+  let as = case maybeSameWordArg of
+        Nothing -> args
+        Just a -> a:args
+  either (fail . errorMsg (Right so) as) return $ f as
+
+
+shortOneArg
+  :: ShortOpt
+  -> (String -> Either InputError a)
+  -> Parser a
+shortOneArg so f = do
+  a <- firstShortArg
+  either (fail . errorMsg (Right so) [a]) return $ f a
+
+firstShortArg :: Parser String
+firstShortArg =
+  optional pendingShortOptArg >>= maybe nextWord return
+
+
+shortChoiceArg :: ShortOpt -> [(String, a)] -> Parser a
+shortChoiceArg opt ls =
+  firstShortArg
+  >>= maybe err return . matchAbbrev ls
+  where
+    err = fail $ "option " ++ [unShortOpt opt] ++ " requires "
+          ++ "one argument: "
+          ++ (concat . intersperse " " . map fst $ ls)
+
+
+shortTwoArg
+  :: ShortOpt
+  -> (String -> String -> Either InputError a)
+  -> Parser a
+shortTwoArg so f = do
+  a1 <- firstShortArg
+  a2 <- nextWord
+  either (fail . errorMsg (Right so) [a1, a2]) return
+    $ f a1 a2
+
+
+shortThreeArg
+  :: ShortOpt
+  -> (String -> String -> String -> Either InputError a)
+  -> Parser a
+shortThreeArg so f = do
+  a1 <- firstShortArg
+  a2 <- nextWord
+  a3 <- nextWord
+  either (fail . errorMsg (Right so) [a1, a2, a3]) return
+    $ f a1 a2 a3
+
+shortOptionalArg
+  :: ShortOpt
+  -> (Maybe String -> Either InputError a)
+  -> Parser a
+shortOptionalArg so f = do
+  maybeSameWordArg <- optional pendingShortOptArg
+  case maybeSameWordArg of
+    Nothing -> do
+      maybeArg <- optional nonOptionPosArg
+      case maybeArg of
+        Nothing -> either (fail . errorMsg (Right so) []) return
+                   $ f Nothing
+        Just a -> either (fail . errorMsg (Right so) [a]) return
+                  $ f (Just a)
+    Just a -> either (fail . errorMsg (Right so) [a]) return
+              $ f (Just a)
+
+
+
+-- | Finds the unambiguous short match for a string, if there is
+-- one. Returns a string describing the error condition if there is
+-- one, or the matching result if successful.
+matchAbbrev :: [(String, a)] -> String -> Maybe a
+matchAbbrev ls s =
+  let ls' = nubBy (\x y -> fst x == fst y) ls
+  in case lookup s ls' of
+    Just a -> return a
+    Nothing ->
+      let pdct (t, _) = s `isPrefixOf` t
+      in case filter pdct ls of
+        (_, a):[] -> return a
+        _ -> Nothing
+
+-- | Formats error messages for nice display. Returns a multi-line
+-- string (there is no need to append a newline to the end of the
+-- string returned).
+formatError
+  :: String
+  -- ^ Pass the name of your program here. Displayed at the beginning
+  -- of the error message.
+
+  -> Error
+  -> String
+formatError p (Error loc ls) =
+  p ++ ": error: could not parse command line.\n"
+  ++ "Error at: " ++ loc ++ "\n"
+  ++ expError
+  ++ genError
+  ++ unk
+  where
+    toExp m = case m of { Expected s -> Just s; _ -> Nothing }
+    expc = unlines . mapMaybe toExp $ ls
+    expError = if null expc then "" else "Expecting:\n" ++ expc
+    toGeneral m = case m of { General s -> Just s; _ -> Nothing }
+    gen = unlines . mapMaybe toGeneral $ ls
+    genError = if null gen
+               then ""
+               else let sep = if null expError
+                              then "" else "\n"
+                        in sep ++ gen
+    unk = if any (== Unknown) ls then "Unknown error\n" else ""
+    
diff --git a/lib/Multiarg/CommandLine.hs b/lib/Multiarg/CommandLine.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg/CommandLine.hs
@@ -0,0 +1,563 @@
+-- | Some pre-built command line parsers. One is a simple command line
+-- parser that can parse options that take an optional argument, one
+-- or two arguments, or a variable number of arguments. For sample
+-- code that uses this parser, see
+-- "Multiarg.SampleParser".
+--
+-- Another parser is provided for multi-mode programs that are similar
+-- to @git@ or @darcs@.
+--
+-- Previously there was a bug in System.Environment.getArgs that would
+-- not properly encode Unicode command line arguments.  multiarg used
+-- to provide its own GetArgs module to deal with this.  This bug was
+-- in base 4.3.1.0, which was bundled with ghc 7.0.4.  This bug was
+-- fixed in base 4.4.0.0, which came with ghc 7.2.  Since this bug has
+-- been fixed for awhile, multiarg no longer has its own GetArgs
+-- module.
+module Multiarg.CommandLine (
+  -- * Interspersion control
+  Intersperse (Intersperse, StopOptions)
+
+  -- * Types
+  , ProgName
+  , Opts(..)
+  , OptsWithPosArgs(..)
+
+  -- ** Modes
+  , Mode
+  , mode
+  , mModeName
+  , renameMode
+
+  -- * Simple parsers
+  , simplePure
+  , simpleIO
+  , simpleHelp
+  , simpleHelpVersion
+
+  -- * Mode parsers
+  , modesPure
+  , modesIO
+
+  -- * Helpers to create various options and modes
+  , optsHelp
+  , optsHelpVersion
+  , modeHelp
+
+  ) where
+
+import qualified Multiarg.Combinator as C
+import qualified Multiarg.Prim as P
+import System.Environment (getArgs, getProgName)
+import System.Exit (exitFailure, exitSuccess)
+import qualified System.IO as IO
+import Control.Applicative ( many, (<|>), optional,
+                             (<$), (<*>), (<*), (<$>))
+import Data.Bifunctor
+import Data.List (find)
+import Data.Maybe (catMaybes, fromJust)
+import qualified Data.Set as Set
+
+
+-- | What to do after encountering the first non-option,
+-- non-option-argument word on the command line? In either case, no
+-- more options are parsed after a stopper.
+data Intersperse =
+  Intersperse
+  -- ^ Additional options are allowed on the command line after
+  -- encountering the first positional argument. For example, if @a@
+  -- and @b@ are options, in the command line @-a posarg -b@, @b@ will
+  -- be parsed as an option. If @b@ is /not/ an option and the same
+  -- command line is entered, then @-b@ will result in an error
+  -- because @-b@ starts with a hyphen and therefore \"looks like\" an
+  -- option.
+
+  | StopOptions
+    -- ^ No additional options will be parsed after encountering the
+    -- first positional argument. For example, if @a@ and @b@ are
+    -- options, in the command line @-a posarg -b@, @b@ will be parsed
+    -- as a positional argument rather than as an option.
+
+
+-- | Specifies a set of options.
+data Opts s a = Opts
+  { oShortcuts :: [C.OptSpec s]
+  -- ^ Shortcut options are commonly options such as @--help@ or
+  -- @--version@. Such options must be specified alone on the command
+  -- line.  The parser looks for one of these options first.  If it
+  -- finds one and it is the only option on the command line, only
+  -- this option is processed and returned.  If the option is not
+  -- alone on the command line, an error occurs.  If no shortcut
+  -- option is found, the parser processes non-shortcut options
+  -- instead.
+
+  , oOptions :: [C.OptSpec a]
+  -- ^ If the user does not specify any shortcut options, she may
+  -- specify any number of these options.
+
+  }
+
+instance Bifunctor Opts where
+  bimap fa fc o = Opts
+    { oShortcuts = map (fmap fa) . oShortcuts $ o
+    , oOptions = map (fmap fc) . oOptions $ o
+    }
+
+instance Functor (Opts a) where
+  fmap f o = o { oOptions = fmap (fmap f) . oOptions $ o }
+
+-- | Creates an Opts with a help shortcut option.
+optsHelp
+  :: h
+  -- ^ Whatever type you wish to use for help
+  -> [C.OptSpec a]
+  -> Opts h a
+optsHelp h = Opts [C.OptSpec ["help"] "h" (C.NoArg h)]
+
+-- | Creates an Opts with help and version shortcut options.
+optsHelpVersion
+  :: h
+  -- ^ What you wish to use for help
+
+  -> h
+  -- ^ What you wish to use for version
+
+  -> [C.OptSpec a]
+  -> Opts h a
+optsHelpVersion h v = Opts [ C.OptSpec ["help"] "h" (C.NoArg h)
+                            , C.OptSpec ["version"] "v" (C.NoArg v) ]
+
+-- | Specification for both options and positional arguments.
+data OptsWithPosArgs s a = OptsWithPosArgs
+  { opOpts :: Opts s a
+  , opIntersperse :: Intersperse
+  , opPosArg :: String -> Either C.InputError a
+  }
+
+instance Bifunctor OptsWithPosArgs where
+  bimap fa fc o = OptsWithPosArgs
+    { opOpts = bimap fa fc . opOpts $ o
+    , opIntersperse = opIntersperse o
+    , opPosArg = fmap (fmap fc) . opPosArg $ o
+    }
+
+instance Functor (OptsWithPosArgs s) where
+  fmap f o = o
+    { opOpts = fmap f . opOpts $ o
+    , opPosArg = fmap (fmap f) . opPosArg $ o
+    }
+
+-- | Creates a mode.
+mode
+  :: String
+  -- ^ How the user specifies the mode on the command line.  For @git@
+  -- for example this might be @commit@ or @log@.
+
+
+  -> OptsWithPosArgs s a
+  -- ^ Options and positional arguments that are specific to this
+  -- mode.  For example, in the command line @git commit -a -m 'this
+  -- is a log message'@, @commit@ is the mode name and everything
+  -- after that is specified here as an option or positional argument
+  -- that is specific to this mode.
+
+  -> ([a] -> r)
+  -- ^ This function is applied to a list of the results of parsing the
+  -- options that are specific to this mode.  The function returns a
+  -- type of your choosing (though all modes in the same parser will
+  -- have to return the same type.)
+
+  -> Mode s r
+mode n os f = Mode n (processMode f os)
+
+
+
+-- | Specifies a mode.
+data Mode s r = Mode
+  { mModeName :: String
+  -- ^ How the user specifies the mode on the command line.  For @git@
+  -- for example this might be @commit@ or @log@.
+
+  , mParser :: P.Parser (Either s r)
+  }
+
+instance Bifunctor Mode where
+  bimap fa fc (Mode n p) = Mode n (fmap (bimap fa fc) p)
+
+instance Functor (Mode s) where
+  fmap f (Mode n p) = Mode n (fmap (fmap f) p)
+
+-- | Changes the mode name that a user specifies on the command line.
+renameMode
+  :: (String -> String)
+  -- ^ This function is applied to the existing name of the mode.
+  -> Mode s r
+  -> Mode s r
+
+renameMode f (Mode n p) = Mode (f n) p
+
+-- | Creates a Mode with a help option (help specific to the mode.)
+modeHelp
+  :: String
+  -- ^ Mode name
+
+  -> h
+  -- ^ Whatever you want to use for the help (perhaps a string, or a
+  -- function, or an IO action).  Its type will have to match up with
+  -- the type of the global shortcut options and with the shortcut
+  -- type of the other modes.
+
+  -> ([a] -> r)
+  -- ^ When applied to the the mode options, returns the result.
+
+  -> [C.OptSpec a]
+  -- ^ Options for this mode
+
+  -> Intersperse
+  -- ^ Allow interspersion of mode options and positional arguments?
+
+  -> (String -> Either C.InputError a)
+  -- ^ Parses positional arguments
+
+  -> Mode h r
+
+modeHelp n h getR os i p = mode n (OptsWithPosArgs (Opts ss os) i p) getR
+  where
+    ss = [C.OptSpec ["help"] "h" (C.NoArg h)]
+
+parseOpts :: Opts s a -> P.Parser (Either s [a])
+parseOpts os = do
+  let specials = oShortcuts os
+  maySpecial <- optional (C.parseOption specials <* P.end)
+  case maySpecial of
+    Nothing -> fmap Right
+      $ P.manyTill (C.parseOption (oOptions os)) endOrNonOpt
+    Just spec -> return . Left $ spec
+
+parseOptsWithPosArgs
+  :: OptsWithPosArgs s a
+  -> P.Parser (Either s [a])
+parseOptsWithPosArgs os = do
+  let specials = oShortcuts . opOpts $ os
+  maySpecial <- optional (C.parseOption specials <* P.end)
+  case maySpecial of
+    Nothing ->
+      let f = case opIntersperse os of
+            Intersperse -> parseIntersperse
+            StopOptions -> parseStopOpts
+          parser = C.parseOption (oOptions . opOpts $ os)
+      in fmap Right $ f parser (opPosArg os)
+    Just spec -> return . Left $ spec
+
+processMode
+  :: ([a] -> r)
+  -> OptsWithPosArgs s a
+  -> P.Parser (Either s r)
+processMode gr os = do
+  eiOpts <- parseOptsWithPosArgs os
+  return $ case eiOpts of
+    Left x -> Left x
+    Right opts -> Right (gr opts)
+
+
+parseModes
+  :: [Mode s r]
+  -> P.Parser (Either s r)
+parseModes ms = do
+  let modeWords = Set.fromList . map mModeName $ ms
+  (_, w) <- P.matchApproxWord modeWords
+  mParser . fromJust . find (\c -> mModeName c == w) $ ms
+
+
+-- | A pure (non-IO) parser for simple command lines--that is, command
+-- lines that do not have modes.
+simplePure
+  :: OptsWithPosArgs s a
+  -- ^ Specifies allowed regular options, allowed shortcut options,
+  -- and how to parse positional arguments.  Also specifies whether
+  -- the user may intersperse options with positional arguments.
+
+  -> [String]
+  -- ^ The command line arguments to parse
+
+  -> Either P.Error (Either s [a])
+  -- ^ Returns an error if the command line arguments could not be
+  -- parsed. If the parse was successful, returns an Either.  A Left
+  -- indicates that the user selected a shortcut option.  A Right
+  -- indicates that the user did not specify a shortcut option, and
+  -- will contain a list of the options and positional arguments.
+simplePure os ss = P.parse ss (parseOptsWithPosArgs os)
+
+-- | A pure (non-IO) parser for command lines that contain modes.
+modesPure
+  :: Opts s g
+  -- ^ Global options.  These are specified before any mode.  For
+  -- instance, in the command @git --no-pager commit -a@, the option
+  -- @--no-pager@ is a global option.  Global options can contain
+  -- shortcut options.  For instance, @git --help@ contains a single
+  -- shortcut option.
+
+  -> ([g] -> Either String (Either r [Mode s r]))
+  -- ^ This function processes the global options.  If there are no
+  -- shortcut options specified in the global options, it is applied
+  -- to the result of processing the global options.  This function
+  -- may return a Left if there is something wrong with the
+  -- global options (a nonsensical combination, perhaps.)  Otherwise,
+  -- it returns a @Right Either@.  Return a Left if there is no need to
+  -- process any modes at all after seeing the global options.
+  -- Otherwise, return a Right with a list of modes.
+
+  -> [String]
+  -- ^ Command line arguments to parse
+
+  -> Either P.Error (Either s r)
+  -- ^ If the command line arguments fail to parse, this will be a
+  -- Left with the error.  If the parser is successful, this
+  -- returns a @Right Either@. A Left indicates that the user entered a
+  -- shortcut option, either in the global options or in one of the
+  -- mode-specific options.  A Right indicates that the user selected
+  -- a mode.
+modesPure os process ss = P.parse ss p
+  where
+    p = do
+      eiGs <- parseOpts os
+      case eiGs of
+        Left spec -> return . Left $ spec
+        Right gs -> case process gs of
+          Left s -> fail s
+          Right eiModes -> case eiModes of
+            Left r -> return (Right r)
+            Right modes -> parseModes modes
+
+-- | A parser for simple command lines that do not contain modes.
+-- Runs in the IO monad.
+simpleIO
+  :: [C.OptSpec a]
+  -- ^ Options to parse
+
+  -> Intersperse
+  -- ^ Allow interspersion of options and arguments?
+
+  -> (String -> Either C.InputError a)
+  -- ^ How to parse positional arguments
+
+  -> IO [a]
+  -- ^ If there is an error parsing the command line, the program will
+  -- exit with an error message.  If successful the results are
+  -- returned here.
+simpleIO os i getArg = do
+  let optsWithArgs = OptsWithPosArgs (Opts os []) i getArg
+  ss <- getArgs
+  case simplePure optsWithArgs ss of
+    Left e -> errorAct e
+    Right g -> case g of
+      Left _ ->
+        error "simpleIO: should never happen: no shortcut options"
+      Right gs -> return gs
+
+simpleIOCustomError
+  :: (P.Error -> IO ())
+  -> OptsWithPosArgs s a
+  -> IO (Either s [a])
+simpleIOCustomError showErr os = do
+  ss <- getArgs
+  case simplePure os ss of
+    Left e -> showErr e >> exitFailure
+    Right g -> return g
+  
+
+-- | A command line parser for multi-mode command lines.  Runs in the
+-- IO monad.
+modesIO
+  :: Opts s g
+  -- ^ Specifies global options and global shortcut options
+
+  -> ([g] -> Either String (Either r [Mode s r]))
+  -- ^ This function processes the global options.  If there are no
+  -- shortcut options specified in the global options, it is applied
+  -- to the result of processing the global options.  This function
+  -- may return a Left if there is something wrong with the
+  -- global options (a nonsensical combination, perhaps.)  Otherwise,
+  -- it returns a @Right Either@.  Return a Left if there is no need to
+  -- process any modes at all after seeing the global options.
+  -- Otherwise, return a Right with a list of modes.
+
+  -> IO (Either s r)
+  -- ^ If parsing fails, the program will exit with a failure. If
+  -- successful, the result is returned here.  A Left indicates a
+  -- shortcut option, either from the global options or from the
+  -- mode-specific options; a Right indicates the mode a user
+  -- selected.
+modesIO os ms = do
+  ss <- getArgs
+  case modesPure os ms ss of
+    Left e -> errorAct e
+    Right g -> return g
+
+
+-- | The name of the program that was entered on the command line,
+-- obtained from System.Environment.getProgName.
+type ProgName = String
+
+displayAct :: (ProgName -> String) -> IO a
+displayAct getHelp = do
+  pn <- getProgName
+  putStr $ getHelp pn
+  exitSuccess
+
+errorAct :: P.Error -> IO a
+errorAct e = do
+  pn <- getProgName
+  IO.hPutStr IO.stderr $ C.formatError pn e
+  exitFailure
+
+errorActDisplayHelp :: P.Error -> IO a
+errorActDisplayHelp e = do
+  pn <- getProgName
+  IO.hPutStr IO.stderr $ C.formatError pn e
+  IO.hPutStrLn IO.stderr $ "enter \"" ++ pn ++ " -h\" for help."
+  exitFailure
+
+-- | A parser for simple command lines. Adds a @--help@ option for
+-- you.
+simpleHelp
+  :: (ProgName -> String)
+  -- ^ Indicate the help here. This function, when applied to the name
+  -- of the program, returns help.  simpleHelp automatically adds
+  -- options for @--help@ and @-h@ for you.
+
+  -> [C.OptSpec a]
+  -- ^ Options to parse
+
+  -> Intersperse
+  -- ^ Allow interspersion of options and positional arguments?
+
+  -> (String -> Either C.InputError a)
+  -- ^ How to parse positional arguments
+
+  -> IO [a]
+  -- ^ If the parser fails, the program will exit with an error.  If
+  -- the user requested help, it will be displayed and the program
+  -- exits successfully.  Otherwise, the options and positional
+  -- arguments are returned here.
+simpleHelp getHelp os ir getArg = do
+  let shortcuts = [C.OptSpec ["help"] "h" (C.NoArg (displayAct getHelp))]
+      opts = OptsWithPosArgs (Opts shortcuts os) ir getArg
+  ei <- simpleIOCustomError errorActDisplayHelp opts
+  case ei of
+    Left act -> act
+    Right as -> return as
+
+-- | A parser for simple command lines without modes.  Adds options
+-- for @--help@ and @--version@ for you.
+simpleHelpVersion
+  :: (ProgName -> String)
+  -- ^ Indicate the help here. This function, when applied to the name
+  -- of the program, returns help.  simpleHelpVersion automatically adds
+  -- options for @--help@ and @-h@ for you.
+
+  -> (ProgName -> String)
+  -- ^ Indicate the version here. This function, when applied to the
+  -- name of the program, returns a version string.  simpleHelpVersion
+  -- automatically adds an option for @--version@ for you.
+
+  -> [C.OptSpec a]
+  -- ^ Options to parse
+
+  -> Intersperse
+  -- ^ Allow interspersion of options and positional arguments?
+
+  -> (String -> Either C.InputError a)
+  -- ^ How to parse positional arguments
+
+  -> IO [a]
+  -- ^ If the parser fails, the program will exit with an error.  If
+  -- the user requested help or version information, it will be
+  -- displayed and the program exits successfully.  Otherwise, the
+  -- options and positional arguments are returned here.
+
+simpleHelpVersion getHelp getVer os ir getArg = do
+  let shortcuts = [ C.OptSpec ["help"] "h"
+                      (C.NoArg (displayAct getHelp))
+                  , C.OptSpec ["version"] ""
+                      (C.NoArg (displayAct getVer)) ]
+      opts = OptsWithPosArgs (Opts shortcuts os) ir getArg
+  ei <- simpleIOCustomError errorActDisplayHelp opts
+  case ei of
+    Left act -> act
+    Right as -> return as
+
+-- # Helpers
+
+-- | Handles positional arguments and errors with them.  The parser for
+-- the positional argument must be passed in (this way it can
+-- be parsed with nonOptionPosArg or nextWord, as appropriate; when
+-- parsing interpsersed command lines, you will want nonOptionPosArg;
+-- when parsing non-interspersed command lines, you will need
+-- nextWord.)
+parsePosArg
+  :: P.Parser String
+  -- ^ Parser for Word for next positional argument
+  -> (String -> Either C.InputError a)
+  -- ^ Function to handle positional arguments
+  -> P.Parser a
+parsePosArg pa f = do
+  a <- pa
+  case f a of
+    Left e ->
+      let msg = "invalid positional argument: \"" ++ a ++ "\""
+      in case e of
+          C.NoMsg -> fail msg
+          C.ErrorMsg s -> fail $ msg ++ ": " ++ s
+    Right g -> return g
+
+-- | Parses options only, where they are not interspersed with
+-- positional arguments.  Stops parsing only where it encouters a word
+-- that does not begin with a dash.  This way if the user enters a bad
+-- option, it shows in the error message as a bad option rather than
+-- simply not getting parsed.
+parseOptsNoIntersperse :: P.Parser a -> P.Parser [a]
+parseOptsNoIntersperse p = P.manyTill p e where
+  e = P.end <|> nonOpt
+  nonOpt = P.lookAhead next
+  next = (() <$ P.nonOptionPosArg) <|> P.stopper
+
+-- | Parses options and positional arguments where the two are not
+-- interspersed. Stops parsing options when a stopper is encountered
+-- or at the first word that does not look like an option.
+parseStopOpts
+  :: P.Parser a
+  -> (String -> Either C.InputError a)
+  -> P.Parser [a]
+parseStopOpts optParser p =
+  (++)
+  <$> parseOptsNoIntersperse optParser
+  <* optional P.stopper
+  <*> many (parsePosArg P.nextWord p)
+
+
+-- | @parseIntersperse o p@ parses options and positional arguments,
+-- where o is a parser that parses options, and p is a function that,
+-- when applied to a string, returns the appropriate type.
+--
+-- If a stopper has not yet been seen, any word that begins with a
+-- hyphen will not be parsed as a positional argument.  Therefore, if
+-- there is a word before a stopper and it begins with a hyphen, if it
+-- is not a valid option then the parse will fail with an error.
+parseIntersperse
+  :: P.Parser a
+  -> (String -> Either C.InputError a)
+  -> P.Parser [a]
+parseIntersperse optParser p =
+  let pa = Just <$> parsePosArg P.nonOptionPosArg p
+      po = Just <$> optParser
+      ps = Nothing <$ P.stopper
+      parser = po <|> ps <|> pa
+  in catMaybes <$> P.manyTill parser P.end
+
+-- | Looks at the next word. Succeeds if it is a non-option, or if we
+-- are at the end of input. Fails otherwise.
+endOrNonOpt :: P.Parser ()
+endOrNonOpt = (P.lookAhead P.nonOptionPosArg >> return ())
+              <|> P.end
+
diff --git a/lib/Multiarg/Option.hs b/lib/Multiarg/Option.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg/Option.hs
@@ -0,0 +1,45 @@
+-- | These types represent options. Option names cannot have a dash as
+-- their first or second character, and long option names cannot have
+-- an equals sign anywhere in the name.
+module Multiarg.Option (
+  ShortOpt,
+  unShortOpt,
+  makeShortOpt,
+  LongOpt,
+  unLongOpt,
+  makeLongOpt )
+  where
+
+-- | Short options. Options that are preceded with a single dash on
+-- the command line and consist of a single letter. That single letter
+-- cannot be a dash. Any other Unicode character is good (including
+-- pathological ones like newlines).
+newtype ShortOpt = ShortOpt { unShortOpt :: Char } deriving (Show, Eq, Ord)
+
+-- | Creates a short option. Returns Nothing if the character is not
+-- valid for a short option.
+makeShortOpt :: Char -> Maybe ShortOpt
+makeShortOpt c = case c of
+  '-' -> Nothing
+  x -> Just $ ShortOpt x
+
+-- | Long options. Options that are preceded with two dashes on the
+-- command line and typically consist of an entire mnemonic word, such
+-- as @lines@. However, anything that is at least one letter long is
+-- fine for a long option name. The name must be at least one
+-- character long. It cannot have an equal sign anywhere in its
+-- name. Otherwise any Unicode character is good (including
+-- pathological ones like newlines).
+data LongOpt = LongOpt { unLongOpt :: String } deriving (Show, Eq, Ord)
+
+-- | Makes a long option. Returns Nothing if the string is not a valid
+-- long option.
+makeLongOpt :: String -> Maybe LongOpt
+makeLongOpt t =
+  if isValidLongOptText t then Just $ LongOpt t else Nothing
+
+
+isValidLongOptText :: String -> Bool
+isValidLongOptText s = case s of
+  [] -> False
+  xs -> not $ '=' `elem` xs
diff --git a/lib/Multiarg/Prim.hs b/lib/Multiarg/Prim.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg/Prim.hs
@@ -0,0 +1,681 @@
+-- | Parser primitives. These are the only functions that have access
+-- to the internals of the parser. Use these functions if you want to
+-- build your own parser from scratch. If your needs are simpler, you
+-- will want to look at "Multiarg.SimpleParser" or
+-- "Multiarg.Combinator", which do a lot of grunt work
+-- for you.
+--
+-- Internal design, especially the error handling, is based in large
+-- part on Parsec, as described in the paper at
+-- <http://legacy.cs.uu.nl/daan/pubs.html#parsec>.
+module Multiarg.Prim (
+    -- * Parser types
+  Parser,
+
+  -- * Running a parser
+
+  -- | Each parser runner is applied to a list of Strings, which are the
+  -- command line arguments to parse.
+  parse,
+
+  -- * Higher-level parser combinators
+  good,
+  choice,
+  bind,
+  lookAhead,
+
+  -- ** Running parsers multiple times
+  several,
+  several1,
+  manyTill,
+
+  -- ** Failure and errors
+  failString,
+  genericThrow,
+  (<?>),
+  try,
+
+  -- * Parsers
+  -- ** Short options and arguments
+  pendingShortOpt,
+  nonPendingShortOpt,
+  pendingShortOptArg,
+
+  -- ** Long options and arguments
+  exactLongOpt,
+  approxLongOpt,
+
+  -- ** Stoppers
+  stopper,
+  resetStopper,
+
+  -- ** Positional (non-option) arguments
+  nextWord,
+  nextWordIs,
+  nonOptionPosArg,
+  matchApproxWord,
+
+  -- ** Miscellaneous
+  end,
+
+  -- * Errors
+  Description(..),
+  Error(Error),
+  InputDesc
+
+  ) where
+
+
+import Multiarg.Option
+  (ShortOpt,
+    unShortOpt,
+    LongOpt,
+    unLongOpt,
+    makeLongOpt )
+import Control.Applicative ( Applicative, Alternative, optional )
+import qualified Control.Applicative as A
+import qualified Data.Set as Set
+import Data.Set ( Set )
+import qualified Control.Monad
+import Control.Monad ( when, MonadPlus(mzero, mplus), guard, liftM )
+import Data.Maybe (mapMaybe)
+import Data.Monoid ( Monoid ( mempty, mappend ) )
+import qualified Data.List as L
+import Data.List (isPrefixOf)
+
+-- | Parsers. Internally the parser tracks what input remains to be
+-- parsed, whether there are any pending short options, and whether a
+-- stopper has been seen. A parser can return a value of any type.
+--
+-- The parser also includes the notion of failure. Any parser can
+-- fail; a failed parser affects the behavior of combinators such as
+-- choice.
+newtype Parser a = Parser { runParser :: State -> Consumed a }
+
+instance Monad Parser where
+  (>>=) = bind
+  return = good
+  fail = failString
+
+instance Functor Parser where
+  fmap = liftM
+
+instance Applicative Parser where
+  (<*>) = Control.Monad.ap
+  pure = return
+
+instance Alternative Parser where
+  empty = genericThrow
+  (<|>) = choice
+  some = several1
+  many = several
+
+instance Monoid (Parser a) where
+  mempty = genericThrow
+  mappend = choice
+
+instance MonadPlus Parser where
+  mzero = genericThrow
+  mplus = choice
+
+type PendingShort = String
+type Remaining = [String]
+type SawStopper = Bool
+data State = State PendingShort Remaining SawStopper
+
+type InputDesc = String
+data Description = Unknown | General String | Expected String
+  deriving (Eq, Show, Ord)
+
+-- | Error messages. To format error messages for nice display, see
+-- 'Multiarg.Combinator.formatError'.
+data Error = Error InputDesc [Description]
+  deriving (Eq, Show, Ord)
+
+data Reply a = Ok a State Error
+             | Fail Error
+
+data Consumed a = Consumed (Reply a)
+                | Empty (Reply a)
+
+-- | @good a@ always succeeds without consuming any input and has
+-- result a. This provides the implementation for
+-- 'Control.Monad.Monad.return' and
+-- 'Control.Applicative.Applicative.pure'.
+good :: a -> Parser a
+good x = Parser $ \st -> Empty (Ok x st (Error (descLocation st) []))
+
+-- | Combines two parsers into a single parser. The second parser can
+-- optionally depend upon the result from the first parser.
+--
+-- This applies the first parser. If the first parser succeeds,
+-- combine then takes the result from the first parser, applies the
+-- function given to the result from the first parser, and then
+-- applies the resulting parser.
+--
+-- If the first parser fails, combine will not apply the second
+-- function but instead will bypass the second parser.
+--
+-- This provides the implementation for '>>=' in
+-- 'Control.Monad.Monad'.
+bind :: Parser a -> (a -> Parser b) -> Parser b
+bind (Parser p) f = Parser $ \s ->
+  case p s of
+    Empty r1 -> case r1 of
+      Ok x s' _ -> runParser (f x) s'
+      Fail m -> Empty (Fail m)
+    Consumed r1 -> Consumed $
+      case r1 of
+        Ok x s' _ -> case runParser (f x) s' of
+          Consumed r -> r
+          Empty r -> r
+        Fail e -> Fail e
+
+descLocation :: State -> InputDesc
+descLocation (State ps rm st) = pending ++ next ++ stop
+  where
+    pending
+      | null ps = ""
+      | otherwise = "short option or short option argument: "
+                  ++ ps ++ " "
+    next = case rm of
+      [] -> "no words remaining"
+      x:_ -> "next word: " ++ x
+    stop = if st then " (stopper already seen)" else ""
+
+
+-- | @failString s@ always fails without consuming any input. The
+-- failure contains a record of the string passed in by s. This
+-- provides the implementation for 'Control.Monad.Monad.fail'.
+failString :: String -> Parser a
+failString str = Parser $ \s ->
+  Empty (Fail (Error (descLocation s) [General str]))
+
+
+-- | Fail with an unhelpful error message. Usually 'throwString' is
+-- more useful, but this is handy to implement some typeclass
+-- instances.
+genericThrow :: Parser a
+genericThrow = Parser $ \s ->
+  Empty (Fail (Error (descLocation s) [Unknown]))
+
+-- | Runs the first parser. If it fails without consuming any input,
+-- then runs the second parser. If the first parser succeeds, then
+-- returns the result of the first parser. If the first parser fails
+-- and consumes input, then returns the result of the first
+-- parser. This provides the implementation for
+-- '<|>' in 'Control.Applicative.Alternative'.
+choice :: Parser a -> Parser a -> Parser a
+choice p q = Parser $ \s ->
+  case runParser p s of
+    Empty (Fail msg1) ->
+      case runParser q s of
+        Empty (Fail msg2) -> mergeError msg1 msg2
+        Empty (Ok x s' msg2) -> mergeOk x s' msg1 msg2
+        c -> c
+    Empty (Ok x s' msg1) ->
+      case runParser q s of
+        Empty (Fail msg2) -> mergeOk x s' msg1 msg2
+        Empty (Ok _ _ msg2) -> mergeOk x s' msg1 msg2
+        c -> c
+    c -> c
+  where
+    mergeOk x s msg1 msg2 = Empty (Ok x s (merge msg1 msg2))
+    mergeError msg1 msg2 = Empty (Fail (merge msg1 msg2))
+    merge (Error loc exp1) (Error _ exp2) =
+      Error loc (exp1 ++ exp2)
+
+-- | Applies 'error' if a parser would succeed without consuming any
+-- input. Useful for preventing infinite loops on parsers like
+-- 'several1'.
+crashOnEmptyOk
+  :: String
+  -- ^ Use this label when applying 'error'
+
+  -> Parser a
+  -> Parser a
+crashOnEmptyOk str p = Parser $ \s ->
+  case runParser p s of
+    Empty r -> case r of
+      Ok _ _ _ ->
+         error $ "multiarg: error: " ++ str
+               ++ " applied to parser that succeeds without "
+               ++ "consuming any input. Aborted to prevent "
+               ++ "an infinite loop."
+      e -> Empty e
+    o -> o
+               
+
+-- | Runs a parser one or more times. Runs the parser once and then
+-- applies 'several'.
+several1 :: Parser a -> Parser [a]
+several1 p = do
+  r1 <- p
+  rs <- several p
+  return $ r1:rs
+
+
+-- | Runs a parser zero or more times. If the last run of the parser
+-- fails without consuming any input, this parser succeeds without
+-- consuming any input. If the last run of the parser fails while
+-- consuming input, this parser fails while consuming input. This
+-- provides the implementation for 'many' in Control.Applicative.
+several :: Parser a -> Parser [a]
+several unwrapped =
+  let p = crashOnEmptyOk "several" unwrapped
+  in do
+    maybeA <- optional p
+    case maybeA of
+      Nothing -> return []
+      Just a -> do
+        rest <- several unwrapped
+        return $ a:rest
+  
+
+-- | Runs the parser given. If it fails without consuming any input,
+-- replaces all Expected messages with the one given. Otherwise,
+-- returns the result of the parser unchanged.
+(<?>) :: Parser a -> String -> Parser a
+p <?> str = Parser $ \s ->
+  case runParser p s of
+    Empty (Fail m) -> Empty (Fail (expect m str))
+    Empty (Ok x s' m) -> Empty (Ok x s' (expect m str))
+    x -> x
+  where
+    expect (Error pos ls) s =
+      let ls' = mapMaybe notExpected ls
+          notExpected d = case d of
+            Expected _ -> Nothing
+            x -> Just x
+      in Error pos ((Expected s) : ls')
+
+infix 0 <?>
+
+-- | Runs a parser. This is the only way to change a value of type
+-- @Parser a@ into a value of type @a@ (that is, it is the only way to
+-- \"get out of the Parser monad\" or to \"escape the Parser monad\".)
+parse
+  :: [String]
+  -- ^ Command line arguments to parse. Presumably you got these from
+  -- 'getArgs'. If there is any chance that you will be parsing
+  -- Unicode strings, see the documentation in
+  -- "Multiarg.GetArgs" before you use
+  -- 'System.Environment.getArgs'.
+
+  -> Parser a
+  -- ^ Parser to run
+
+  -> Either Error a
+  -- ^ Success or failure. Any parser might fail; for example, the
+  -- command line might not have any values left to parse. Use of the
+  -- 'choice' combinator can lead to a list of failures.
+
+parse ss p =
+  let s = State "" ss False
+      procReply r = case r of
+        Ok x _ _ -> Right x
+        Fail m -> Left m
+  in case runParser p s of
+      Consumed r -> procReply r
+      Empty r -> procReply r
+
+-- | Parses only pending short options. Fails without consuming any
+-- input if there has already been a stopper or if there are no
+-- pending short options. Fails without consuming any input if there
+-- is a pending short option, but it does not match the short option
+-- given. Succeeds and consumes a pending short option if it matches
+-- the short option given.
+pendingShortOpt :: ShortOpt -> Parser ()
+pendingShortOpt so = Parser $ \s@(State pends rm stop) ->
+  let msg = Error (descLocation s)
+        [Expected ("pending short option: -" ++ [unShortOpt so])]
+      gd s' = Consumed (Ok () s' msg)
+      err = Empty (Fail msg)
+  in maybe err gd $ do
+    guard $ not stop
+    (first, rest) <- case pends of
+      [] -> mzero
+      x:xs -> return (x, xs)
+    when (unShortOpt so /= first) mzero
+    return $ State rest rm stop
+
+-- | @lookAhead p@ runs parser p. If p succeeds, lookAhead p succeeds
+-- without consuming any input. If p fails without consuming any
+-- input, so does lookAhead. If p fails and consumes input, lookAhead
+-- also fails and consumes input. If this is undesirable, combine with
+-- "try".
+lookAhead :: Parser a -> Parser a
+lookAhead p = Parser $ \s ->
+  case runParser p s of
+    Consumed r -> case r of
+      Ok x _ e -> Empty (Ok x s e)
+      e -> Consumed e
+    e -> e
+
+nextW :: Remaining -> Maybe (String, Remaining)
+nextW rm = case rm of
+  [] -> Nothing
+  x:xs -> Just (x, xs)
+
+-- | Parses only non-pending short options. Fails without consuming
+-- any input if:
+--
+-- * there are pending short options
+--
+-- * there has already been a stopper
+--
+-- * there are no arguments left to parse
+--
+-- * the next argument is an empty string
+--
+-- * the next argument does not begin with a dash
+--
+-- * the next argument is a single dash
+--
+-- * the next argument is a short option but it does not match
+--   the one given
+--
+-- * the next argument is a stopper
+--
+-- Otherwise, consumes the next argument, puts any remaining letters
+-- from the argument into a pending short, and removes the first word
+-- from remaining arguments to be parsed.
+nonPendingShortOpt :: ShortOpt -> Parser ()
+nonPendingShortOpt so = Parser $ \s@(State ps rm stop) ->
+  let dsc = [Expected
+            $ "non pending short option: -" ++ [unShortOpt so]]
+      err = Error (descLocation s) dsc
+      errRet = Empty (Fail err)
+      gd (ps'', rm'') = Consumed (Ok () (State ps'' rm'' stop) err)
+  in maybe errRet gd $ do
+    guard $ null ps
+    guard $ not stop
+    (a, rm') <- nextW rm
+    (maybeDash, word) <- case a of
+      [] -> mzero
+      x:xs -> return (x, xs)
+    guard (maybeDash == '-')
+    (letter, arg) <- case word of
+      [] -> mzero
+      x:xs -> return (x, xs)
+    guard (letter == unShortOpt so)
+    return (arg, rm')
+
+
+-- | Parses an exact long option. That is, the text of the
+-- command-line option must exactly match the text of the
+-- option. Returns any argument that is attached to
+-- the same word of the option with an equal sign (for example,
+-- @--follow=\/dev\/random@ will return @Just \"\/dev\/random\"@ for the
+-- argument.) If there is no equal sign, returns Nothing for the
+-- argument. If there is an equal sign but there is nothing after it,
+-- returns @Just \"\"@ for the argument.
+--
+-- If you do not want your long option to have equal signs and
+-- GNU-style option arguments, wrap this parser in something that will
+-- fail if there is an option argument.
+--
+-- Fails without consuming any input if:
+--
+-- * there are pending short options
+--
+-- * a stopper has been parsed
+--
+-- * there are no arguments left on the command line
+--
+-- * the next argument on the command line does not begin with
+--   two dashes
+--
+-- * the next argument on the command line is @--@ (a stopper)
+--
+-- * the next argument on the command line does begin with two
+--   dashes but its text does not match the argument we're looking for
+
+exactLongOpt :: LongOpt -> Parser (Maybe String)
+exactLongOpt lo = Parser $ \s@(State ps rm sp) ->
+  let msg = Error (descLocation s)
+            [Expected ("long option: --" ++ unLongOpt lo)]
+      gd (arg, newRm) = Consumed (Ok arg (State ps newRm sp) msg)
+      err = Empty (Fail msg)
+  in maybe err gd $ do
+    guard $ null ps
+    guard $ not sp
+    (x, rm') <- nextW rm
+    (word, afterEq) <- getLongOption x
+    guard (word == unLongOpt lo)
+    return (afterEq, rm')
+    
+
+getLongOption :: String -> Maybe (String, Maybe String)
+getLongOption str = do
+  guard (str /= "--")
+  let (pre, word, afterEq) = splitLongWord str
+  guard (pre == "--")
+  return (word, afterEq)
+
+-- | Takes a single String and returns a tuple, where the first element
+-- is the first two letters, the second element is everything from the
+-- third letter to the equal sign, and the third element is Nothing if
+-- there is no equal sign, or Just String with everything after the
+-- equal sign if there is one.
+splitLongWord :: String -> (String, String, Maybe String)
+splitLongWord t = (f, s, r) where
+  (f, rest) = L.splitAt 2 t
+  (s, withEq) = L.break (== '=') rest
+  r = case withEq of
+    [] -> Nothing
+    _:xs -> Just xs
+
+approxLongOptError :: [LongOpt] -> [Description]
+approxLongOptError =
+  map (Expected . ("long option: --" ++) . unLongOpt)
+
+
+assert :: e -> Bool -> Either e ()
+assert e b = if b then Right () else Left e
+
+fromMaybe :: e -> Maybe a -> Either e a
+fromMaybe e = maybe (Left e) Right
+
+-- | Examines the next word. If it matches a LongOpt in the set
+-- unambiguously, returns a tuple of the word actually found and the
+-- matching word in the set and the accompanying text after the equal
+-- sign (if any). If the Set is empty, this parser will always fail.
+approxLongOpt ::
+  Set LongOpt
+  -> Parser (String, LongOpt, Maybe String)
+approxLongOpt ts = Parser $ \s@(State ps rm stop) ->
+  let err ls = Error (descLocation s) (approxLongOptError ls)
+      ert ls = Empty (Fail $ err ls)
+      gd (found, opt, arg, rm'') =
+        Consumed (Ok (found, opt, arg) (State ps rm'' stop)
+                     (err allOpts))
+      allOpts = Set.toList ts
+  in either ert gd $ do
+    assert allOpts $ null ps
+    assert allOpts $ not stop
+    (x, rm') <- fromMaybe allOpts $ nextW rm
+    (word, afterEq) <- fromMaybe allOpts $ getLongOption x
+    opt <- fromMaybe allOpts $ makeLongOpt word
+    if Set.member opt ts
+      then return (word, opt, afterEq, rm')
+      else do
+      let p t = word `isPrefixOf` unLongOpt t
+          matches = Set.filter p ts
+      case Set.toList matches of
+        [] -> Left allOpts
+        (m:[]) -> return (word, m, afterEq, rm')
+        ls -> Left ls
+
+
+-- | Parses only pending short option arguments. For example, for the
+-- @tail@ command, if you enter the option @-c25@, then after parsing
+-- the @-c@ option the @25@ becomes a pending short option argument
+-- because it was in the same command line argument as the @-c@.
+--
+-- Fails without consuming any input if:
+--
+-- * a stopper has already been parsed
+--
+-- * there are no pending short option arguments
+--
+-- On success, returns the String of the pending short option argument
+-- (this String will never be empty).
+pendingShortOptArg :: Parser String
+pendingShortOptArg = Parser $ \st@(State ps rm sp) ->
+  let msg = [Expected "pending short option argument"]
+      err = Error (descLocation st) msg
+      ert = Empty (Fail err)
+      gd str = Consumed (Ok str (State "" rm sp) err)
+  in maybe ert gd $ do
+     guard $ not sp
+     case ps of
+      [] -> mzero
+      xs -> return xs
+
+
+-- | Parses a \"stopper\" - that is, a double dash. Changes the internal
+-- state of the parser to reflect that a stopper has been seen.
+stopper :: Parser ()
+stopper = Parser $ \s@(State ps rm sp) ->
+  let err = Error (descLocation s)
+        [Expected "stopper, \"--\""]
+      ert = Empty (Fail err)
+      gd rm'' = Consumed (Ok () (State ps rm'' True) err)
+  in maybe ert gd $ do
+     guard $ not sp
+     guard . null $ ps
+     (x, rm') <- nextW rm
+     guard $ x == "--"
+     return rm'
+
+
+-- | If a stopper has already been seen, change the internal state
+-- back to indicating that no stopper has been seen.
+resetStopper :: Parser ()
+resetStopper = Parser $ \s@(State ps rm _) ->
+  Empty (Ok () (State ps rm False) (Error (descLocation s) []))
+
+
+-- | try p behaves just like p, but if p fails, try p will not consume
+-- any input.
+try :: Parser a -> Parser a
+try a = Parser $ \s ->
+  case runParser a s of
+    Consumed r -> case r of
+      Fail e -> Empty (Fail e)
+      o -> Consumed o
+    o -> o
+
+
+-- | Returns the next string on the command line as long as there are
+-- no pendings. Succeeds even if a stopper is present. Be careful -
+-- this will return the next string even if it looks like an option
+-- (that is, it starts with a dash.) Consider whether you should be
+-- using nonOptionPosArg instead. However this can be useful when
+-- parsing command line options after a stopper.
+nextWord :: Parser String
+nextWord = Parser $ \s@(State ps rm sp) ->
+  let err = Error (descLocation s) [dsc]
+      dsc = Expected "next word"
+      ert = Empty (Fail err)
+      gd (str, rm'') = Consumed $ Ok str (State ps rm'' sp) err
+  in maybe ert gd $ do
+      guard $ null ps
+      nextW rm
+      
+
+-- | Parses the next word on the command line, but only if it exactly
+-- matches the word given. Otherwise, fails without consuming any
+-- input. Also fails without consuming any input if there are pending
+-- short options or if a stopper has already been parsed. Does not pay
+-- any attention to whether a stopper is present.
+nextWordIs :: String -> Parser ()
+nextWordIs str = Parser $ \s@(State ps rm sp) ->
+  let err = Error (descLocation s) [dsc]
+      dsc = Expected $ "next argument \"" ++ str ++ "\""
+      ert = Empty $ Fail err
+      gd rm'' = Consumed $ Ok () (State ps rm'' sp) err
+  in maybe ert gd $ do
+      guard $ null ps
+      (a, rm') <- nextW rm
+      guard (a == str)
+      return rm'
+
+
+-- | If there are pending short options, fails without consuming any input.
+--
+-- Otherwise, if a stopper has NOT already been parsed, then returns
+-- the next word if it is either a single dash or any other word that
+-- does not begin with a dash. If the next word does not meet these
+-- criteria, fails without consuming any input.
+--
+-- Otherwise, if a stopper has already been parsed, then returns the
+-- next word, regardless of whether it begins with a dash or not.
+nonOptionPosArg :: Parser String
+nonOptionPosArg = Parser $ \s@(State ps rm sp) ->
+  let err = Error (descLocation s) [dsc]
+      dsc = Expected "non option positional argument"
+      ert = Empty $ Fail err
+      gd (str, rm'') = Consumed $ Ok str (State ps rm'' sp) err
+  in maybe ert gd $ do
+    guard $ null ps
+    (x, rm') <- nextW rm
+    result <- if sp
+              then return x
+              else case x of
+                [] -> return x
+                '-':[] -> return "-"
+                f:_ -> if f == '-' then mzero else return x
+    return (result, rm')
+
+
+-- | Succeeds if there is no more input left.
+end :: Parser ()
+end = Parser $ \s@(State ps rm _) ->
+  let err = Error (descLocation s) [dsc]
+      dsc = Expected "end of input"
+      ert = Empty $ Fail err
+      gd = Empty $ Ok () s err
+  in if null ps && null rm then gd else ert
+
+
+-- | Examines the possible words in Set. If there are no pendings,
+-- then get the next word and see if it matches one of the words in
+-- Set. If so, returns the word actually parsed and the matching word
+-- from Set. If there is no match, fails without consuming any
+-- input. Pays no attention to whether a stopper has been seen.
+matchApproxWord :: Set String -> Parser (String, String)
+matchApproxWord set = Parser $ \s@(State ps rm sp) ->
+  let err = Error (descLocation s) . lsDsc
+      lsDsc = map (Expected . ("next word: " ++))
+      ert = Empty . Fail . err
+      gd (act, mtch, rm'') =
+        Consumed $ Ok (act, mtch) (State ps rm'' sp) (err allWords)
+      allWords = Set.toList set
+  in either ert gd $ do
+      assert allWords $ null ps
+      (x, rm') <- fromMaybe allWords $ nextW rm
+      let matches = Set.filter p set
+          p t = x `isPrefixOf` t
+      case Set.toList matches of
+        [] -> Left allWords
+        r:[] -> return (x, r, rm')
+        xs -> Left xs
+      
+-- | @manyTill p end@ runs parser p zero or more times until parser
+-- @end@ succeeds. If @end@ succeeds and consumes input, that input is
+-- also consumed. in the result of @manyTill@. If that is a problem,
+-- wrap it in @lookAhead@. Also, if @end@ fails and consumes input,
+-- @manyTill@ fails and consumes input. If that is a problem, wrap
+-- @end@ in @try@.
+manyTill :: Parser a -> Parser end -> Parser [a]
+manyTill p e = do
+  maybeEnd <- optional e
+  case maybeEnd of
+    Just _ -> return []
+    Nothing -> do
+      a <- crashOnEmptyOk "manyTill" p
+      rs <- manyTill p e
+      return $ a:rs
+
diff --git a/lib/Multiarg/SampleParser.hs b/lib/Multiarg/SampleParser.hs
new file mode 100644
--- /dev/null
+++ b/lib/Multiarg/SampleParser.hs
@@ -0,0 +1,70 @@
+-- | This is sample code using "Multiarg". This could
+-- be a command-line parser for the version of the Unix command @tail@
+-- that is included with GNU coreutils version 8.5. "main" simply gets
+-- the command line arguments, parses them, and prints out what was
+-- parsed. To test it out, simply compile an executable that looks
+-- like this and then feed it different options:
+--
+-- > import Multiarg.SampleParser
+-- > main = sampleMain Intersperse
+--
+-- or:
+--
+-- > import Multiarg.SampleParser
+-- > main = sampleMain StopOptions
+--
+-- The code in the module is the sample code; the sample code is not
+-- in the Haddock documentation! If you're reading this in Haddock,
+-- you will want to also take a look at the actual source code.
+module Multiarg.SampleParser where
+
+import qualified Multiarg.Combinator as C
+import qualified Multiarg.CommandLine as P
+
+data Flag =
+  Bytes String
+  | Follow (Maybe String)
+  | Retry
+  | Lines String
+  | Stats String
+  | Pid String
+  | Quiet
+  | Sleep String
+  | Verbose
+  | Help
+  | Version
+  | Filename String
+  deriving Show
+
+specs :: [C.OptSpec Flag]
+
+specs =
+  [ C.OptSpec ["bytes"]                     ['c']
+              (C.OneArg (return . Bytes))
+
+  , C.OptSpec ["follow"]                    ['f']
+              (C.OptionalArg (return . Follow))
+
+  , C.OptSpec ["follow-retry"]              ['F']     (C.NoArg Retry)
+
+  , C.OptSpec ["lines"]                     ['n']
+              (C.OneArg (return . Lines))
+
+  , C.OptSpec ["max-unchanged-stats"]       []
+              (C.OneArg (return . Stats))
+
+  , C.OptSpec ["pid"]                       []
+              (C.OneArg (return . Pid))
+  , C.OptSpec ["quiet"]                     ['q']     (C.NoArg Quiet)
+
+  , C.OptSpec ["sleep-interval"]            ['s']
+              (C.OneArg (return . Sleep))
+  , C.OptSpec ["verbose"]                   ['v']     (C.NoArg Verbose)
+  , C.OptSpec ["help"]                      []        (C.NoArg Help)
+  , C.OptSpec ["version"]                   []        (C.NoArg Version)
+  ]
+
+sampleMain :: P.Intersperse -> IO ()
+sampleMain i = do
+  r <- P.simpleIO specs i (return . Filename)
+  print r
diff --git a/lib/System/Console/MultiArg.hs b/lib/System/Console/MultiArg.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg.hs
+++ /dev/null
@@ -1,167 +0,0 @@
--- | A combinator library for building command-line parsers.
-
-module System.Console.MultiArg (
-
-  -- | To say this library is inspired by Parsec would probably insult the
-  -- creators of Parsec, as this library could not possibly be as
-  -- elegant or throughly considered as Parsec is. Nevertheless this
-  -- library can be used in a similar style as Parsec, but is
-  -- specialized for parsing command lines.
-  --
-  -- This parser was built because I could not find anything that would
-  -- readily parse command lines where the options took more than one
-  -- argument. For example, for the @tail@ command on GNU systems, the
-  -- --lines option takes one argument to specify how many lines you
-  -- want to see. Well, what if you want to build a program with an
-  -- option that takes /two/ arguments, like @--foo bar baz@? I found no
-  -- such library so I built this one. Nevertheless, using this library
-  -- you can build parsers to parse a variety of command line
-  -- vocabularies, from simple to complex.
-
-  -- * Terminology
-
-  -- | Some terms are used throughout multiarg:
-  --
-  -- [@word@] When you run your program from the Unix shell prompt,
-  -- your shell is responsible for splitting the command line into
-  -- words. Typically you separate words with spaces, although quoting
-  -- can affect this. multiarg parses lists of words. Each word can
-  -- consist of a single long option, a single long option and an
-  -- accompanying option argument, a single short option, multiple
-  -- short options, and even one or more multiple short options and an
-  -- accompanying short option argument. Or, a word can be a
-  -- positional argument or a stopper. All these are described below.
-  --
-  -- [@option@] Options allow a user to specify ways to tune the
-  -- operation of a program. Typically options are indeed optional,
-  -- although some programs do sport \"required options\" (a bit of an
-  -- oxymoron). Options can be either short options or long
-  -- options. Also, options can take arguments.
-  --
-  -- [@short option@] An option that is specified with a single hyphen
-  -- and a single letter. For example, for the program @tail(1)@,
-  -- possible short options include @n@ and @v@. With multiarg it is
-  -- possible to easily parse short options that are specified in
-  -- different words or in the same word. For example, if a user wants
-  -- to run @tail@ with two options, he might type @tail -v -f@ or he
-  -- might type @tail -vf@.
-  --
-  -- [@long option@] An option that is specified using two hyphens and
-  -- what is usually a mnemonic word, though it could be as short as a
-  -- single letter. For example, @tail(1)@ has long options including
-  -- @follow@ and @verbose@. The user would specify these on the
-  -- command line by typing @tail --follow --verbose@.
-  --
-  -- [@option argument@] Some options take additional arguments that
-  -- are specific to the option and change what the option does. For
-  -- instance, the @lines@ option to @tail(1)@ takes a single,
-  -- optional argument, which is the number of lines to show. Option
-  -- arguments can be optional or required, and a single option can
-  -- take a mulitple, fixed number of arguments and it can take a
-  -- variable number of arguments. Option arguments can be given in
-  -- various ways. They can be specified in the same word as a long
-  -- option by using an equals sign; they can also be specified in the
-  -- same word as a short option simply by placing them in the same
-  -- word, or they can be specified in the following word. For
-  -- example, these different command lines all mean the same thing;
-  -- @tail --verbose --lines=20@, @tail --verbose --lines 20@, @tail
-  -- -vn 20@, @tail -v -n20@, @tail -vn20@, and @tail -v -n 20@, and
-  -- numerous other combinations also have the same meaning.
-  --
-  -- [@GNU-style option argument@] A long option with an argument
-  -- given with an equal sign, such as [@lines=20@].
-  --
-  -- [@positional argument@] A word on the command line that is not an
-  -- option or an argument to an option. For instance, with @tail(1)@,
-  -- you specify the files you want to see by using positional
-  -- arguments. In the command @tail -n 10 myfile@, @myfile@ is a
-  -- positional argument. For some programs, such as @git@ or @darcs@,
-  -- a positional argument might be a \"command\" or a \"mode\", such
-  -- as the @commit@ in @git commit@ or the @whatsnew@ in @darcs
-  -- whatsnew@. multiarg has no primitive parsers that treat these
-  -- positional arguments specially but it is trivial to build a
-  -- parser for command lines such as this, too.
-  --
-  -- [@stopper@] A single word consisting solely of two hyphens,
-  -- @--@. The user types this to indicate that all subsequent words
-  -- on the command line are positional arguments, even if they begin
-  -- with hyphens and therefore look like they might be options.
-  --
-  -- [@pending@] The user might specify more than one short option, or
-  -- a short option and a short option argument, in a single word. For
-  -- example, she might type @tail -vl20@. After parsing the @v@
-  -- option, the Parser makes @l20@ into a \"pending\". The next
-  -- parser can then treat @l20@ as an option argument to the @v@
-  -- option (which is probably not what was wanted) or the next parser
-  -- can parse @l@ as a short option. This would result in a
-  -- \"pending\" of @20@. Then, the next parser can treat @20@ as an
-  -- option argument. After that parse there will be no pendings.
-
-  -- * Getting started
-
-  -- |If your needs are simple to moderately complicated just look at the
-  -- "System.Console.MultiArg.CommandLine" module, which uses the
-  -- underlying combinators to build a simple parser for you. That
-  -- module is already exported from this module for easy usage.
-  --
-  -- "System.Console.MultiArg.CommandLine" also has a parser that can
-  -- handle multi-mode commands (examples include @git@, @darcs@, and
-  -- @cvs@.)
-  --
-  -- For maximum flexibility you will want to start with the
-  -- "System.Console.MultiArg.Prim" module. Using those parsers you
-  -- can easily build parsers that are quite complicated. The parsers
-  -- can check for errors along the way, simplifying the sometimes
-  -- complex task of ensuring that data a user supplied on the command
-  -- line is good. You can easily build parsers for programs that take
-  -- no options, take dozens of options, require that options be given
-  -- in a particular order, require that some options be given, or bar
-  -- some combinations of options. You might also require particular
-  -- positional arguments. Other helpful functions are in
-  -- "System.Console.MultiArg.Combinator". You will also want to
-  -- examine the source code for "System.Console.MultiArg.Combinator"
-  -- and "System.Console.MultiArg.CommandLine" as these show some
-  -- ways to use the primitive parsers and combinators.
-
-  -- * Non-features and shortcomings
-  --
-  -- | multiarg isn't perfect; no software is. multiarg does not
-  -- automatically make online help for your command line
-  -- parsers. Getting this right would be tricky given the nature of
-  -- the code and I don't even want to bother trying, as I just write
-  -- my own online help in a text editor.
-  --
-  -- multiarg partially embraces \"The Tao of Option Parsing\" that
-  -- Python's Optik (<http://optik.sourceforge.net/>) follows. Read
-  -- \"The Tao of Option Parsing\" here:
-  --
-  -- <http://optik.sourceforge.net/doc/1.5/tao.html>
-  --
-  -- multiarg's philosophy is similar to that of Optik, which
-  -- means you won't be able to use multiarg to (easily) build a clone
-  -- to the UNIX @find(1)@ command. (You could do it, but multiarg won't
-  -- help you very much.)
-  --
-  -- multiarg can be complicated, although I'd like to believe this is
-  -- because it addresses a complicated problem in a flexible way.
-
-  -- * Projects usings multiarg
-
-  -- | * Penny, an extensible double-entry accounting
-  -- system. <http://hackage.haskell.org/package/penny-lib> The code
-  -- using multiarg is woven throughout the system; for example, see
-  -- the Penny.Liberty module.
-
-
-    module System.Console.MultiArg.Combinator
-  , module System.Console.MultiArg.CommandLine
-  , module System.Console.MultiArg.Option
-  , module System.Console.MultiArg.Prim
-  , module System.Environment
-  ) where
-
-import System.Console.MultiArg.Combinator
-import System.Console.MultiArg.CommandLine
-import System.Console.MultiArg.Option
-import System.Console.MultiArg.Prim
-import System.Environment
diff --git a/lib/System/Console/MultiArg/Combinator.hs b/lib/System/Console/MultiArg/Combinator.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg/Combinator.hs
+++ /dev/null
@@ -1,478 +0,0 @@
--- | Combinators that are useful for building command-line
--- parsers. These build off the functions in
--- "System.Console.MultiArg.Prim". Unlike those functions, these
--- functions have no access to the internals of the parser.
-module System.Console.MultiArg.Combinator (
-  -- * Parser combinators
-  notFollowedBy,
-
-  -- * Combined long and short option parser
-  OptSpec(OptSpec, longOpts, shortOpts, argSpec),
-  InputError(..),
-  reader,
-  optReader,
-  ArgSpec(..),
-  parseOption,
-
-  -- * Formatting errors
-  formatError
-  ) where
-
-import Data.List (isPrefixOf, intersperse, nubBy)
-import Data.Set ( Set )
-import qualified Data.Set as Set
-import Control.Applicative
-       ((<*>), optional, (<$), (*>), (<|>), many)
-
-import System.Console.MultiArg.Prim
-  ( Parser, try, approxLongOpt,
-    nextWord, pendingShortOptArg, nonOptionPosArg,
-    pendingShortOpt, nonPendingShortOpt, nextWord, (<?>),
-    Error(..), Description(..))
-import System.Console.MultiArg.Option
-  ( LongOpt, ShortOpt, unLongOpt,
-    makeLongOpt, makeShortOpt, unShortOpt )
-import qualified Data.Map as M
-import Data.Map ((!))
-import Data.Maybe (fromMaybe, mapMaybe)
-import Data.Monoid ( mconcat )
-
-
--- | @notFollowedBy p@ succeeds only if parser p fails. If p fails,
--- notFollowedBy succeeds without consuming any input. If p succeeds
--- and consumes input, notFollowedBy fails and consumes input. If p
--- succeeds and does not consume any input, notFollowedBy fails and
--- does not consume any input.
-notFollowedBy :: Parser a -> Parser ()
-notFollowedBy p =
-  () <$ ((try p >> fail "notFollowedBy failed")
-         <|> return ())
-
-
-unsafeShortOpt :: Char -> ShortOpt
-unsafeShortOpt c =
-  fromMaybe (error $ "invalid short option: " ++ [c])
-            (makeShortOpt c)
-
-unsafeLongOpt :: String -> LongOpt
-unsafeLongOpt c =
-  fromMaybe (error $ "invalid long option: " ++ c)
-            (makeLongOpt c)
-
-
--- |Specifies options for the 'parseOption' function. Each OptSpec
--- represents one command-line option.
-data OptSpec a = OptSpec {
-  longOpts :: [String]
-  -- ^ Each String is a single long option, such as @version@. When
-  -- the user specifies long options on the command line, she must
-  -- type two dashes; however, do not include the dashes when you
-  -- specify the long option here. Strings you specify as long options
-  -- cannot include a dash as either the first or the second
-  -- character, and they cannot include an equal sign anywhere. If
-  -- your long option does not meet these conditions, a runtime error
-  -- will occur.
-
-
-  , shortOpts :: [Char]
-    -- ^ Each Char is a single short option, such as @v@. The
-    -- character cannot be a dash; if it is, a runtime error will occur.
-
-  , argSpec :: ArgSpec a
-    -- ^ What to do each time one of the given long options or
-    -- short options appears on the command line.
-  }
-
-instance Functor OptSpec where
-  fmap f (OptSpec ls ss as) = OptSpec ls ss (fmap f as)
-
--- | Reads in values that are members of Read. Provides a generic
--- error message if the read fails.
-reader :: Read a => String -> Either InputError a
-reader s = case reads s of
-  (x, ""):[] -> return x
-  _ -> Left . ErrorMsg $ "could not parse option argument"
-
--- | Reads in values that are members of Read, but the value does not
--- have to appear on the command line. Provides a generic error
--- message if the read fails. If the argument is Nothing, returns
--- Nothing.
-optReader
-  :: Read a
-  => Maybe String
-  -> Either InputError (Maybe a)
-optReader ms = case ms of
-  Nothing -> return Nothing
-  Just s -> case reads s of
-    (x, ""):[] -> return (Just x)
-    _ -> Left . ErrorMsg $ "could not parse option argument"
-
--- | Indicates errors when parsing options to arguments.
-data InputError
-  = NoMsg
-  -- ^ No error message accompanies this failure. multiarg will create
-  -- a generic error message for you.
-
-  | ErrorMsg String
-  -- ^ Parsing the argument failed with this error message. An example
-  -- might be @option argument is not an integer@ or @option argument
-  -- is too large@. The text of the options the user provided is
-  -- automatically prepended to the error message, so do not replicate
-  -- this in your message.
-
-  deriving (Eq, Show)
-
--- | Create an error message from an InputError.
-errorMsg
-  :: Either LongOpt ShortOpt
-  -- ^ The option with the faulty argument
-
-  -> [String]
-  -- ^ The faulty command line arguments
-
-  -> InputError
-  -> String
-errorMsg badOpt ss err = arg ++ opt ++ msg
-  where
-    arg = let aw = if length ss > 1 then "arguments " else "argument "
-              ws = concat . intersperse " " . map quote $ ss
-              quote s = "\"" ++ s ++ "\""
-          in aw ++ ws
-    opt = " to option " ++ optDesc
-    optDesc = case badOpt of
-      Left lo -> "--" ++ unLongOpt lo
-      Right so -> "-" ++ [unShortOpt so]
-    msg = " invalid" ++ detail
-    detail = case err of
-      NoMsg -> ""
-      ErrorMsg s -> ": " ++ s
-
-
-
--- | Specifies how many arguments each option takes. As with
--- 'System.Console.GetOpt.ArgDescr', there are (at least) two ways to
--- use this type. You can simply represent each possible option using
--- different data constructors in an algebraic data type. Or you can
--- have each ArgSpec yield a function that transforms a record. For an
--- example that uses an algebraic data type, see
--- "System.Console.MultiArg.SampleParser".
---
--- Most of these value constructors take as an argument a function
--- that returns an Either.  The function should return a @Left
--- InputError@ if the parsing of the arguments failed--if, for
--- example, the user needs to enter an integer but she instead input a
--- letter.  The functions should return a Right if parsing of the
--- arguments was successful.
-data ArgSpec a =
-  NoArg a
-  -- ^ This option takes no arguments
-
-  | OptionalArg (Maybe String -> Either InputError a)
-    -- ^ This option takes an optional argument. As noted in \"The Tao
-    -- of Option Parsing\", optional arguments can result in some
-    -- ambiguity. (Read it here:
-    -- <http://optik.sourceforge.net/doc/1.5/tao.html>) If option @a@
-    -- takes an optional argument, and @b@ is also an option, what
-    -- does @-ab@ mean? SimpleParser resolves this ambiguity by
-    -- assuming that @b@ is an argument to @a@. If the user does not
-    -- like this, she can specify @-a -b@ (in such an instance @-b@ is
-    -- not parsed as an option to @-a@, because @-b@ begins with a
-    -- hyphen and therefore \"looks like\" an option.) Certainly
-    -- though, optional arguments lead to ambiguity, so if you don't
-    -- like it, don't use them :)
-
-  | OneArg (String -> Either InputError a)
-    -- ^ This option takes one argument. Here, if option @a@ takes one
-    -- argument, @-a -b@ will be parsed with @-b@ being an argument to
-    -- option @a@, even though @-b@ starts with a hyphen and therefore
-    -- \"looks like\" an option.
-
-  | TwoArg (String -> String -> Either InputError a)
-    -- ^ This option takes two arguments. Parsed similarly to
-    -- 'OneArg'.
-
-  | ThreeArg (String -> String -> String -> Either InputError a)
-    -- ^ This option takes three arguments. Parsed similarly to
-    -- 'OneArg'.
-
-  | VariableArg ([String] -> Either InputError a)
-    -- ^ This option takes a variable number of arguments--zero or
-    -- more. Option arguments continue until the command line contains
-    -- a word that begins with a hyphen. For example, if option @a@
-    -- takes a variable number of arguments, then @-a one two three
-    -- -b@ will be parsed as @a@ taking three arguments, and @-a -b@
-    -- will be parsed as @a@ taking no arguments. If the user enters
-    -- @-a@ as the last option on the command line, then the only way
-    -- to indicate the end of arguments for @a@ and the beginning of
-    -- positional argments is with a stopper.
-
-  | ChoiceArg [(String, a)]
-    -- ^ This option takes a single argument, which must match one of
-    -- the strings given in the list. The user may supply the shortest
-    -- unambiguous string. If the argument list to ChoiceArg has
-    -- duplicate strings, only the first string is used. For instance,
-    -- ChoiceArg could be useful if you were parsing the @--color@
-    -- option to GNU grep, which requires the user to supply one of
-    -- three arguments: @always@, @never@, or @auto@.
-
-
-instance Functor ArgSpec where
-  fmap f a = case a of
-    NoArg i -> NoArg $ f i
-    ChoiceArg gs ->
-      ChoiceArg . map (\(s, r) -> (s, f r)) $ gs
-
-    OptionalArg g -> OptionalArg $ \ms -> fmap f (g ms)
-
-    OneArg g ->
-      OneArg $ \s1 -> fmap f (g s1)
-
-    TwoArg g ->
-      TwoArg $ \s1 s2 -> fmap f (g s1 s2)
-
-    ThreeArg g ->
-      ThreeArg $ \s1 s2 s3 -> fmap f (g s1 s2 s3)
-
-    VariableArg g ->
-      VariableArg $ \ls -> fmap f (g ls)
-
-
--- | Parses a single command line option. Examines all the options
--- specified using multiple OptSpec and parses one option on the
--- command line accordingly. Fails without consuming any input if the
--- next word on the command line is not a recognized option. Allows
--- the user to specify the shortest unambiguous match for long
--- options; for example, the user could type @--verb@ for @--verbose@
--- and @--vers@ for @--version@.
---
--- This function is applied to a list of OptSpec, rather than to a
--- single OptSpec, because in order to correctly handle the parsing of
--- shortened long options (e.g. @--verb@ rather than @--verbose@) it
--- is necessary for one function to have access to all of the
--- OptSpec. Applying this function multiple times to different lists
--- of OptSpec and then using the @<|>@ function to combine them will
--- break the proper parsing of shortened long options.
---
--- For an example that uses this function, see
--- "System.Console.MultiArg.SimpleParser".
-parseOption :: [OptSpec a] -> Parser a
-parseOption os =
-  let longs = longOptParser os
-  in case mconcat ([shortOpt] <*> os) of
-    Nothing -> longs
-    Just shorts -> longs <|> shorts
-
-longOptParser :: [OptSpec a] -> Parser a
-longOptParser os = longOpt (longOptSet os) (longOptMap os)
-
-
-longOptSet :: [OptSpec a] -> Set LongOpt
-longOptSet = Set.fromList . concatMap toOpts where
-  toOpts = map unsafeLongOpt . longOpts
-
-longOptMap :: [OptSpec a] -> M.Map LongOpt (ArgSpec a)
-longOptMap = M.fromList . concatMap toPairs where
-  toPairs (OptSpec los _ as) = map (toPair as) los where
-    toPair a s = (unsafeLongOpt s, a)
-
-longOpt ::
-  Set LongOpt
-  -> M.Map LongOpt (ArgSpec a)
-  -> Parser a
-longOpt set mp = do
-  (_, lo, maybeArg) <- approxLongOpt set
-  let spec = mp ! lo
-      maybeNextArg = maybe nextWord return maybeArg
-  case spec of
-    NoArg a -> case maybeArg of
-      Nothing -> return a
-      Just _ -> fail $ "option " ++ unLongOpt lo
-                  ++ " does not take argument"
-    ChoiceArg ls -> do
-      s <- maybeNextArg
-      case matchAbbrev ls s of
-        Nothing -> fail $ "option " ++ unLongOpt lo
-                   ++ " requires an argument: "
-                   ++ (concat . intersperse ", " . map fst $ ls)
-        Just g -> return g
-
-    OptionalArg f -> case maybeArg of
-      Nothing -> either (fail . errorMsg (Left lo) []) return
-                 $ f Nothing
-      Just s -> either (fail . errorMsg (Left lo) [s]) return
-                $ f (Just s)
-
-
-    OneArg f -> maybeNextArg >>= g
-      where
-        g a = either (fail . errorMsg (Left lo) [a]) return
-              $ f a
-
-    TwoArg f -> do
-      a1 <- maybeNextArg
-      a2 <- nextWord
-      either (fail . errorMsg (Left lo) [a1, a2]) return
-        $ f a1 a2
-
-    ThreeArg f -> do
-      a1 <- maybeNextArg
-      a2 <- nextWord
-      a3 <- nextWord
-      either (fail . errorMsg (Left lo) [a1, a2, a3]) return
-        $ f a1 a2 a3
-
-    VariableArg f -> do
-      as <- many nonOptionPosArg
-      let args = case maybeArg of
-            Nothing -> as
-            Just a -> a:as
-      either (fail . errorMsg (Left lo) args) return
-        $ f args
-
-
-shortOpt :: OptSpec a -> Maybe (Parser a)
-shortOpt o = mconcat parsers where
-  parsers = map mkParser . shortOpts $ o
-  mkParser c =
-    let opt = unsafeShortOpt c
-    in Just $ nextShort opt *> case argSpec o of
-      NoArg a -> return a
-      ChoiceArg ls -> shortChoiceArg opt ls
-      OptionalArg f -> shortOptionalArg opt f
-      OneArg f -> shortOneArg opt f
-      TwoArg f -> shortTwoArg opt f
-      ThreeArg f -> shortThreeArg opt f
-      VariableArg f -> shortVariableArg opt f
-
--- | Parses a short option without an argument, either pending or
--- non-pending. Fails with a single error message rather than two.
-nextShort :: ShortOpt -> Parser ()
-nextShort o = p <?> ("short option: -" ++ [unShortOpt o])
-  where
-    p = do
-      r1 <- optional $ pendingShortOpt o
-      case r1 of
-        Just () -> return ()
-        Nothing -> nonPendingShortOpt o
-
-
-shortVariableArg
-  :: ShortOpt
-  -> ([String] -> Either InputError a)
-  -> Parser a
-shortVariableArg so f = do
-  maybeSameWordArg <- optional pendingShortOptArg
-  args <- many nonOptionPosArg
-  let as = case maybeSameWordArg of
-        Nothing -> args
-        Just a -> a:args
-  either (fail . errorMsg (Right so) as) return $ f as
-
-
-shortOneArg
-  :: ShortOpt
-  -> (String -> Either InputError a)
-  -> Parser a
-shortOneArg so f = do
-  a <- firstShortArg
-  either (fail . errorMsg (Right so) [a]) return $ f a
-
-firstShortArg :: Parser String
-firstShortArg =
-  optional pendingShortOptArg >>= maybe nextWord return
-
-
-shortChoiceArg :: ShortOpt -> [(String, a)] -> Parser a
-shortChoiceArg opt ls =
-  firstShortArg
-  >>= maybe err return . matchAbbrev ls
-  where
-    err = fail $ "option " ++ [unShortOpt opt] ++ " requires "
-          ++ "one argument: "
-          ++ (concat . intersperse " " . map fst $ ls)
-
-
-shortTwoArg
-  :: ShortOpt
-  -> (String -> String -> Either InputError a)
-  -> Parser a
-shortTwoArg so f = do
-  a1 <- firstShortArg
-  a2 <- nextWord
-  either (fail . errorMsg (Right so) [a1, a2]) return
-    $ f a1 a2
-
-
-shortThreeArg
-  :: ShortOpt
-  -> (String -> String -> String -> Either InputError a)
-  -> Parser a
-shortThreeArg so f = do
-  a1 <- firstShortArg
-  a2 <- nextWord
-  a3 <- nextWord
-  either (fail . errorMsg (Right so) [a1, a2, a3]) return
-    $ f a1 a2 a3
-
-shortOptionalArg
-  :: ShortOpt
-  -> (Maybe String -> Either InputError a)
-  -> Parser a
-shortOptionalArg so f = do
-  maybeSameWordArg <- optional pendingShortOptArg
-  case maybeSameWordArg of
-    Nothing -> do
-      maybeArg <- optional nonOptionPosArg
-      case maybeArg of
-        Nothing -> either (fail . errorMsg (Right so) []) return
-                   $ f Nothing
-        Just a -> either (fail . errorMsg (Right so) [a]) return
-                  $ f (Just a)
-    Just a -> either (fail . errorMsg (Right so) [a]) return
-              $ f (Just a)
-
-
-
--- | Finds the unambiguous short match for a string, if there is
--- one. Returns a string describing the error condition if there is
--- one, or the matching result if successful.
-matchAbbrev :: [(String, a)] -> String -> Maybe a
-matchAbbrev ls s =
-  let ls' = nubBy (\x y -> fst x == fst y) ls
-  in case lookup s ls' of
-    Just a -> return a
-    Nothing ->
-      let pdct (t, _) = s `isPrefixOf` t
-      in case filter pdct ls of
-        (_, a):[] -> return a
-        _ -> Nothing
-
--- | Formats error messages for nice display. Returns a multi-line
--- string (there is no need to append a newline to the end of the
--- string returned).
-formatError
-  :: String
-  -- ^ Pass the name of your program here. Displayed at the beginning
-  -- of the error message.
-
-  -> Error
-  -> String
-formatError p (Error loc ls) =
-  p ++ ": error: could not parse command line.\n"
-  ++ "Error at: " ++ loc ++ "\n"
-  ++ expError
-  ++ genError
-  ++ unk
-  where
-    toExp m = case m of { Expected s -> Just s; _ -> Nothing }
-    expc = unlines . mapMaybe toExp $ ls
-    expError = if null expc then "" else "Expecting:\n" ++ expc
-    toGeneral m = case m of { General s -> Just s; _ -> Nothing }
-    gen = unlines . mapMaybe toGeneral $ ls
-    genError = if null gen
-               then ""
-               else let sep = if null expError
-                              then "" else "\n"
-                        in sep ++ gen
-    unk = if any (== Unknown) ls then "Unknown error\n" else ""
-    
diff --git a/lib/System/Console/MultiArg/CommandLine.hs b/lib/System/Console/MultiArg/CommandLine.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg/CommandLine.hs
+++ /dev/null
@@ -1,536 +0,0 @@
-{-# LANGUAGE ExistentialQuantification #-}
--- | Some pre-built command line parsers. One is a simple command line
--- parser that can parse options that take an optional argument, one
--- or two arguments, or a variable number of arguments. For sample
--- code that uses this parser, see
--- "System.Console.MultiArg.SampleParser".
---
--- Another parser is provided for multi-mode programs that are similar
--- to @git@ or @darcs@.
---
--- Previously there was a bug in System.Environment.getArgs that would
--- not properly encode Unicode command line arguments.  multiarg used
--- to provide its own GetArgs module to deal with this.  This bug was
--- in base 4.3.1.0, which was bundled with ghc 7.0.4.  This bug was
--- fixed in base 4.4.0.0, which came with ghc 7.2.  Since this bug has
--- been fixed for awhile, multiarg no longer has its own GetArgs
--- module.
-module System.Console.MultiArg.CommandLine (
-  -- * Interspersion control
-  Intersperse (Intersperse, StopOptions)
-
-  -- * Types
-  , ProgName
-  , Opts(..)
-  , OptsWithPosArgs(..)
-  , Mode(..)
-
-  -- * Simple parsers
-  , simplePure
-  , simpleIO
-  , simpleHelp
-  , simpleHelpVersion
-
-  -- * Mode parsers
-  , modesPure
-  , modesIO
-
-  -- * Helpers to create various options and modes
-  , optsHelp
-  , optsHelpVersion
-  , modeHelp
-
-  ) where
-
-import qualified System.Console.MultiArg.Combinator as C
-import qualified System.Console.MultiArg.Prim as P
-import System.Environment (getArgs, getProgName)
-import System.Exit (exitFailure, exitSuccess)
-import qualified System.IO as IO
-import Control.Applicative ( many, (<|>), optional,
-                             (<$), (<*>), (<*), (<$>))
-import Data.Bifunctor
-import Data.List (find)
-import Data.Maybe (catMaybes, fromJust)
-import qualified Data.Set as Set
-
-
--- | What to do after encountering the first non-option,
--- non-option-argument word on the command line? In either case, no
--- more options are parsed after a stopper.
-data Intersperse =
-  Intersperse
-  -- ^ Additional options are allowed on the command line after
-  -- encountering the first positional argument. For example, if @a@
-  -- and @b@ are options, in the command line @-a posarg -b@, @b@ will
-  -- be parsed as an option. If @b@ is /not/ an option and the same
-  -- command line is entered, then @-b@ will result in an error
-  -- because @-b@ starts with a hyphen and therefore \"looks like\" an
-  -- option.
-
-  | StopOptions
-    -- ^ No additional options will be parsed after encountering the
-    -- first positional argument. For example, if @a@ and @b@ are
-    -- options, in the command line @-a posarg -b@, @b@ will be parsed
-    -- as a positional argument rather than as an option.
-
-
--- | Specifies a set of options.
-data Opts s a = Opts
-  { oShortcuts :: [C.OptSpec s]
-  -- ^ Shortcut options are commonly options such as @--help@ or
-  -- @--version@. Such options must be specified alone on the command
-  -- line.  The parser looks for one of these options first.  If it
-  -- finds one and it is the only option on the command line, only
-  -- this option is processed and returned.  If the option is not
-  -- alone on the command line, an error occurs.  If no shortcut
-  -- option is found, the parser processes non-shortcut options
-  -- instead.
-
-  , oOptions :: [C.OptSpec a]
-  -- ^ If the user does not specify any shortcut options, she may
-  -- specify any number of these options.
-
-  }
-
-instance Bifunctor Opts where
-  bimap fa fc o = Opts
-    { oShortcuts = map (fmap fa) . oShortcuts $ o
-    , oOptions = map (fmap fc) . oOptions $ o
-    }
-
-instance Functor (Opts a) where
-  fmap f o = o { oOptions = fmap (fmap f) . oOptions $ o }
-
--- | Creates an Opts with a help shortcut option.
-optsHelp
-  :: h
-  -- ^ Whatever type you wish to use for help
-  -> [C.OptSpec a]
-  -> Opts h a
-optsHelp h = Opts [C.OptSpec ["help"] "h" (C.NoArg h)]
-
--- | Creates an Opts with help and version shortcut options.
-optsHelpVersion
-  :: h
-  -- ^ What you wish to use for help
-
-  -> h
-  -- ^ What you wish to use for version
-
-  -> [C.OptSpec a]
-  -> Opts h a
-optsHelpVersion h v = Opts [ C.OptSpec ["help"] "h" (C.NoArg h)
-                            , C.OptSpec ["version"] "v" (C.NoArg v) ]
-
--- | Specification for both options and positional arguments.
-data OptsWithPosArgs s a = OptsWithPosArgs
-  { opOpts :: Opts s a
-  , opIntersperse :: Intersperse
-  , opPosArg :: String -> Either C.InputError a
-  }
-
-instance Bifunctor OptsWithPosArgs where
-  bimap fa fc o = OptsWithPosArgs
-    { opOpts = bimap fa fc . opOpts $ o
-    , opIntersperse = opIntersperse o
-    , opPosArg = fmap (fmap fc) . opPosArg $ o
-    }
-
-instance Functor (OptsWithPosArgs s) where
-  fmap f o = o
-    { opOpts = fmap f . opOpts $ o
-    , opPosArg = fmap (fmap f) . opPosArg $ o
-    }
-
--- | Specifies a mode.
-data Mode s r = forall a. Mode
-  { mModeName :: String
-  -- ^ How the user specifies the mode on the command line.  For @git@
-  -- for example this might be @commit@ or @log@.
-
-  , mGetResult :: [a] -> r
-  -- ^ This function is applied to a list of the results of parsing the
-  -- options that are specific to this mode.  The function returns a
-  -- type of your choosing (though all modes in the same parser will
-  -- have to return the same type.)
-
-  , mOpts :: OptsWithPosArgs s a
-  -- ^ Options and positional arguments that are specific to this
-  -- mode.  For example, in the command line @git commit -a -m 'this
-  -- is a log message'@, @commit@ is the mode name and everything
-  -- after that is specified here as an option or positional argument
-  -- that is specific to this mode.
-  }
-
-instance Bifunctor Mode where
-  bimap fa fc (Mode n r o) = Mode
-    { mModeName = n
-    , mGetResult = fmap fc r
-    , mOpts = first fa o
-    }
-
-instance Functor (Mode s) where
-  fmap f (Mode n gr os) = Mode n (fmap f gr) os
-
--- | Creates a Mode with a help option (help specific to the mode.)
-modeHelp
-  :: String
-  -- ^ Mode name
-
-  -> h
-  -- ^ Whatever you want to use for the help (perhaps a string, or a
-  -- function, or an IO action).  Its type will have to match up with
-  -- the type of the global shortcut options and with the shortcut
-  -- type of the other modes.
-
-  -> ([a] -> r)
-  -- ^ When applied to the the mode options, returns the result.
-
-  -> [C.OptSpec a]
-  -- ^ Options for this mode
-
-  -> Intersperse
-  -- ^ Allow interspersion of mode options and positional arguments?
-
-  -> (String -> Either C.InputError a)
-  -- ^ Parses positional arguments
-
-  -> Mode h r
-
-modeHelp n h getR os i p =
-  Mode n getR (OptsWithPosArgs (Opts ss os) i p)
-  where
-    ss = [C.OptSpec ["help"] "h" (C.NoArg h)]
-
-parseOpts :: Opts s a -> P.Parser (Either s [a])
-parseOpts os = do
-  let specials = oShortcuts os
-  maySpecial <- optional (C.parseOption specials <* P.end)
-  case maySpecial of
-    Nothing -> fmap Right
-      $ P.manyTill (C.parseOption (oOptions os)) endOrNonOpt
-    Just spec -> return . Left $ spec
-
-parseOptsWithPosArgs
-  :: OptsWithPosArgs s a
-  -> P.Parser (Either s [a])
-parseOptsWithPosArgs os = do
-  let specials = oShortcuts . opOpts $ os
-  maySpecial <- optional (C.parseOption specials <* P.end)
-  case maySpecial of
-    Nothing ->
-      let f = case opIntersperse os of
-            Intersperse -> parseIntersperse
-            StopOptions -> parseStopOpts
-          parser = C.parseOption (oOptions . opOpts $ os)
-      in fmap Right $ f parser (opPosArg os)
-    Just spec -> return . Left $ spec
-
-parseModes
-  :: [Mode s r]
-  -> P.Parser (Either s r)
-parseModes ms = do
-  let modeWords = Set.fromList . map mModeName $ ms
-  (_, w) <- P.matchApproxWord modeWords
-  processMode (fromJust . find (\c -> mModeName c == w) $ ms)
-  where
-    processMode (Mode _ gr os) = do
-      eiOpts <- parseOptsWithPosArgs os
-      return $ case eiOpts of
-        Left x -> Left x
-        Right opts -> Right (gr opts)
-
-
--- | A pure (non-IO) parser for simple command lines--that is, command
--- lines that do not have modes.
-simplePure
-  :: OptsWithPosArgs s a
-  -- ^ Specifies allowed regular options, allowed shortcut options,
-  -- and how to parse positional arguments.  Also specifies whether
-  -- the user may intersperse options with positional arguments.
-
-  -> [String]
-  -- ^ The command line arguments to parse
-
-  -> Either P.Error (Either s [a])
-  -- ^ Returns an error if the command line arguments could not be
-  -- parsed. If the parse was successful, returns an Either.  A Left
-  -- indicates that the user selected a shortcut option.  A Right
-  -- indicates that the user did not specify a shortcut option, and
-  -- will contain a list of the options and positional arguments.
-simplePure os ss = P.parse ss (parseOptsWithPosArgs os)
-
--- | A pure (non-IO) parser for command lines that contain modes.
-modesPure
-  :: Opts s g
-  -- ^ Global options.  These are specified before any mode.  For
-  -- instance, in the command @git --no-pager commit -a@, the option
-  -- @--no-pager@ is a global option.  Global options can contain
-  -- shortcut options.  For instance, @git --help@ contains a single
-  -- shortcut option.
-
-  -> ([g] -> Either String (Either r [Mode s r]))
-  -- ^ This function processes the global options.  If there are no
-  -- shortcut options specified in the global options, it is applied
-  -- to the result of processing the global options.  This function
-  -- may return a Left if there is something wrong with the
-  -- global options (a nonsensical combination, perhaps.)  Otherwise,
-  -- it returns a @Right Either@.  Return a Left if there is no need to
-  -- process any modes at all after seeing the global options.
-  -- Otherwise, return a Right with a list of modes.
-
-  -> [String]
-  -- ^ Command line arguments to parse
-
-  -> Either P.Error (Either s r)
-  -- ^ If the command line arguments fail to parse, this will be a
-  -- Left with the error.  If the parser is successful, this
-  -- returns a @Right Either@. A Left indicates that the user entered a
-  -- shortcut option, either in the global options or in one of the
-  -- mode-specific options.  A Right indicates that the user selected
-  -- a mode.
-modesPure os process ss = P.parse ss p
-  where
-    p = do
-      eiGs <- parseOpts os
-      case eiGs of
-        Left spec -> return . Left $ spec
-        Right gs -> case process gs of
-          Left s -> fail s
-          Right eiModes -> case eiModes of
-            Left r -> return (Right r)
-            Right modes -> parseModes modes
-
--- | A parser for simple command lines that do not contain modes.
--- Runs in the IO monad.
-simpleIO
-  :: [C.OptSpec a]
-  -- ^ Options to parse
-
-  -> Intersperse
-  -- ^ Allow interspersion of options and arguments?
-
-  -> (String -> Either C.InputError a)
-  -- ^ How to parse positional arguments
-
-  -> IO [a]
-  -- ^ If there is an error parsing the command line, the program will
-  -- exit with an error message.  If successful the results are
-  -- returned here.
-simpleIO os i getArg = do
-  let optsWithArgs = OptsWithPosArgs (Opts os []) i getArg
-  ss <- getArgs
-  case simplePure optsWithArgs ss of
-    Left e -> errorAct e
-    Right g -> case g of
-      Left _ ->
-        error "simpleIO: should never happen: no shortcut options"
-      Right gs -> return gs
-
-simpleIOCustomError
-  :: (P.Error -> IO ())
-  -> OptsWithPosArgs s a
-  -> IO (Either s [a])
-simpleIOCustomError showErr os = do
-  ss <- getArgs
-  case simplePure os ss of
-    Left e -> showErr e >> exitFailure
-    Right g -> return g
-  
-
--- | A command line parser for multi-mode command lines.  Runs in the
--- IO monad.
-modesIO
-  :: Opts s g
-  -- ^ Specifies global options and global shortcut options
-
-  -> ([g] -> Either String (Either r [Mode s r]))
-  -- ^ This function processes the global options.  If there are no
-  -- shortcut options specified in the global options, it is applied
-  -- to the result of processing the global options.  This function
-  -- may return a Left if there is something wrong with the
-  -- global options (a nonsensical combination, perhaps.)  Otherwise,
-  -- it returns a @Right Either@.  Return a Left if there is no need to
-  -- process any modes at all after seeing the global options.
-  -- Otherwise, return a Right with a list of modes.
-
-  -> IO (Either s r)
-  -- ^ If parsing fails, the program will exit with a failure. If
-  -- successful, the result is returned here.  A Left indicates a
-  -- shortcut option, either from the global options or from the
-  -- mode-specific options; a Right indicates the mode a user
-  -- selected.
-modesIO os ms = do
-  ss <- getArgs
-  case modesPure os ms ss of
-    Left e -> errorAct e
-    Right g -> return g
-
-
--- | The name of the program that was entered on the command line,
--- obtained from System.Environment.getProgName.
-type ProgName = String
-
-displayAct :: (ProgName -> String) -> IO a
-displayAct getHelp = do
-  pn <- getProgName
-  putStr $ getHelp pn
-  exitSuccess
-
-errorAct :: P.Error -> IO a
-errorAct e = do
-  pn <- getProgName
-  IO.hPutStr IO.stderr $ C.formatError pn e
-  exitFailure
-
-errorActDisplayHelp :: P.Error -> IO a
-errorActDisplayHelp e = do
-  pn <- getProgName
-  IO.hPutStr IO.stderr $ C.formatError pn e
-  IO.hPutStrLn IO.stderr $ "enter \"" ++ pn ++ " -h\" for help."
-  exitFailure
-
--- | A parser for simple command lines. Adds a @--help@ option for
--- you.
-simpleHelp
-  :: (ProgName -> String)
-  -- ^ Indicate the help here. This function, when applied to the name
-  -- of the program, returns help.  simpleHelp automatically adds
-  -- options for @--help@ and @-h@ for you.
-
-  -> [C.OptSpec a]
-  -- ^ Options to parse
-
-  -> Intersperse
-  -- ^ Allow interspersion of options and positional arguments?
-
-  -> (String -> Either C.InputError a)
-  -- ^ How to parse positional arguments
-
-  -> IO [a]
-  -- ^ If the parser fails, the program will exit with an error.  If
-  -- the user requested help, it will be displayed and the program
-  -- exits successfully.  Otherwise, the options and positional
-  -- arguments are returned here.
-simpleHelp getHelp os ir getArg = do
-  let shortcuts = [C.OptSpec ["help"] "h" (C.NoArg (displayAct getHelp))]
-      opts = OptsWithPosArgs (Opts shortcuts os) ir getArg
-  ei <- simpleIOCustomError errorActDisplayHelp opts
-  case ei of
-    Left act -> act
-    Right as -> return as
-
--- | A parser for simple command lines without modes.  Adds options
--- for @--help@ and @--version@ for you.
-simpleHelpVersion
-  :: (ProgName -> String)
-  -- ^ Indicate the help here. This function, when applied to the name
-  -- of the program, returns help.  simpleHelpVersion automatically adds
-  -- options for @--help@ and @-h@ for you.
-
-  -> (ProgName -> String)
-  -- ^ Indicate the version here. This function, when applied to the
-  -- name of the program, returns a version string.  simpleHelpVersion
-  -- automatically adds an option for @--version@ for you.
-
-  -> [C.OptSpec a]
-  -- ^ Options to parse
-
-  -> Intersperse
-  -- ^ Allow interspersion of options and positional arguments?
-
-  -> (String -> Either C.InputError a)
-  -- ^ How to parse positional arguments
-
-  -> IO [a]
-  -- ^ If the parser fails, the program will exit with an error.  If
-  -- the user requested help or version information, it will be
-  -- displayed and the program exits successfully.  Otherwise, the
-  -- options and positional arguments are returned here.
-
-simpleHelpVersion getHelp getVer os ir getArg = do
-  let shortcuts = [ C.OptSpec ["help"] "h"
-                      (C.NoArg (displayAct getHelp))
-                  , C.OptSpec ["version"] ""
-                      (C.NoArg (displayAct getVer)) ]
-      opts = OptsWithPosArgs (Opts shortcuts os) ir getArg
-  ei <- simpleIOCustomError errorActDisplayHelp opts
-  case ei of
-    Left act -> act
-    Right as -> return as
-
--- # Helpers
-
--- | Handles positional arguments and errors with them.  The parser for
--- the positional argument must be passed in (this way it can
--- be parsed with nonOptionPosArg or nextWord, as appropriate; when
--- parsing interpsersed command lines, you will want nonOptionPosArg;
--- when parsing non-interspersed command lines, you will need
--- nextWord.)
-parsePosArg
-  :: P.Parser String
-  -- ^ Parser for Word for next positional argument
-  -> (String -> Either C.InputError a)
-  -- ^ Function to handle positional arguments
-  -> P.Parser a
-parsePosArg pa f = do
-  a <- pa
-  case f a of
-    Left e ->
-      let msg = "invalid positional argument: \"" ++ a ++ "\""
-      in case e of
-          C.NoMsg -> fail msg
-          C.ErrorMsg s -> fail $ msg ++ ": " ++ s
-    Right g -> return g
-
--- | Parses options only, where they are not interspersed with
--- positional arguments.  Stops parsing only where it encouters a word
--- that does not begin with a dash.  This way if the user enters a bad
--- option, it shows in the error message as a bad option rather than
--- simply not getting parsed.
-parseOptsNoIntersperse :: P.Parser a -> P.Parser [a]
-parseOptsNoIntersperse p = P.manyTill p e where
-  e = P.end <|> nonOpt
-  nonOpt = P.lookAhead next
-  next = (() <$ P.nonOptionPosArg) <|> P.stopper
-
--- | Parses options and positional arguments where the two are not
--- interspersed. Stops parsing options when a stopper is encountered
--- or at the first word that does not look like an option.
-parseStopOpts
-  :: P.Parser a
-  -> (String -> Either C.InputError a)
-  -> P.Parser [a]
-parseStopOpts optParser p =
-  (++)
-  <$> parseOptsNoIntersperse optParser
-  <* optional P.stopper
-  <*> many (parsePosArg P.nextWord p)
-
-
--- | @parseIntersperse o p@ parses options and positional arguments,
--- where o is a parser that parses options, and p is a function that,
--- when applied to a string, returns the appropriate type.
---
--- If a stopper has not yet been seen, any word that begins with a
--- hyphen will not be parsed as a positional argument.  Therefore, if
--- there is a word before a stopper and it begins with a hyphen, if it
--- is not a valid option then the parse will fail with an error.
-parseIntersperse
-  :: P.Parser a
-  -> (String -> Either C.InputError a)
-  -> P.Parser [a]
-parseIntersperse optParser p =
-  let pa = Just <$> parsePosArg P.nonOptionPosArg p
-      po = Just <$> optParser
-      ps = Nothing <$ P.stopper
-      parser = po <|> ps <|> pa
-  in catMaybes <$> P.manyTill parser P.end
-
--- | Looks at the next word. Succeeds if it is a non-option, or if we
--- are at the end of input. Fails otherwise.
-endOrNonOpt :: P.Parser ()
-endOrNonOpt = (P.lookAhead P.nonOptionPosArg >> return ())
-              <|> P.end
-
diff --git a/lib/System/Console/MultiArg/Option.hs b/lib/System/Console/MultiArg/Option.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg/Option.hs
+++ /dev/null
@@ -1,45 +0,0 @@
--- | These types represent options. Option names cannot have a dash as
--- their first or second character, and long option names cannot have
--- an equals sign anywhere in the name.
-module System.Console.MultiArg.Option (
-  ShortOpt,
-  unShortOpt,
-  makeShortOpt,
-  LongOpt,
-  unLongOpt,
-  makeLongOpt )
-  where
-
--- | Short options. Options that are preceded with a single dash on
--- the command line and consist of a single letter. That single letter
--- cannot be a dash. Any other Unicode character is good (including
--- pathological ones like newlines).
-newtype ShortOpt = ShortOpt { unShortOpt :: Char } deriving (Show, Eq, Ord)
-
--- | Creates a short option. Returns Nothing if the character is not
--- valid for a short option.
-makeShortOpt :: Char -> Maybe ShortOpt
-makeShortOpt c = case c of
-  '-' -> Nothing
-  x -> Just $ ShortOpt x
-
--- | Long options. Options that are preceded with two dashes on the
--- command line and typically consist of an entire mnemonic word, such
--- as @lines@. However, anything that is at least one letter long is
--- fine for a long option name. The name must be at least one
--- character long. It cannot have an equal sign anywhere in its
--- name. Otherwise any Unicode character is good (including
--- pathological ones like newlines).
-data LongOpt = LongOpt { unLongOpt :: String } deriving (Show, Eq, Ord)
-
--- | Makes a long option. Returns Nothing if the string is not a valid
--- long option.
-makeLongOpt :: String -> Maybe LongOpt
-makeLongOpt t =
-  if isValidLongOptText t then Just $ LongOpt t else Nothing
-
-
-isValidLongOptText :: String -> Bool
-isValidLongOptText s = case s of
-  [] -> False
-  xs -> not $ '=' `elem` xs
diff --git a/lib/System/Console/MultiArg/Prim.hs b/lib/System/Console/MultiArg/Prim.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg/Prim.hs
+++ /dev/null
@@ -1,681 +0,0 @@
--- | Parser primitives. These are the only functions that have access
--- to the internals of the parser. Use these functions if you want to
--- build your own parser from scratch. If your needs are simpler, you
--- will want to look at "System.Console.MultiArg.SimpleParser" or
--- "System.Console.MultiArg.Combinator", which do a lot of grunt work
--- for you.
---
--- Internal design, especially the error handling, is based in large
--- part on Parsec, as described in the paper at
--- <http://legacy.cs.uu.nl/daan/pubs.html#parsec>.
-module System.Console.MultiArg.Prim (
-    -- * Parser types
-  Parser,
-
-  -- * Running a parser
-
-  -- | Each parser runner is applied to a list of Strings, which are the
-  -- command line arguments to parse.
-  parse,
-
-  -- * Higher-level parser combinators
-  good,
-  choice,
-  bind,
-  lookAhead,
-
-  -- ** Running parsers multiple times
-  several,
-  several1,
-  manyTill,
-
-  -- ** Failure and errors
-  failString,
-  genericThrow,
-  (<?>),
-  try,
-
-  -- * Parsers
-  -- ** Short options and arguments
-  pendingShortOpt,
-  nonPendingShortOpt,
-  pendingShortOptArg,
-
-  -- ** Long options and arguments
-  exactLongOpt,
-  approxLongOpt,
-
-  -- ** Stoppers
-  stopper,
-  resetStopper,
-
-  -- ** Positional (non-option) arguments
-  nextWord,
-  nextWordIs,
-  nonOptionPosArg,
-  matchApproxWord,
-
-  -- ** Miscellaneous
-  end,
-
-  -- * Errors
-  Description(..),
-  Error(Error),
-  InputDesc
-
-  ) where
-
-
-import System.Console.MultiArg.Option
-  (ShortOpt,
-    unShortOpt,
-    LongOpt,
-    unLongOpt,
-    makeLongOpt )
-import Control.Applicative ( Applicative, Alternative, optional )
-import qualified Control.Applicative as A
-import qualified Data.Set as Set
-import Data.Set ( Set )
-import qualified Control.Monad
-import Control.Monad ( when, MonadPlus(mzero, mplus), guard, liftM )
-import Data.Maybe (mapMaybe)
-import Data.Monoid ( Monoid ( mempty, mappend ) )
-import qualified Data.List as L
-import Data.List (isPrefixOf)
-
--- | Parsers. Internally the parser tracks what input remains to be
--- parsed, whether there are any pending short options, and whether a
--- stopper has been seen. A parser can return a value of any type.
---
--- The parser also includes the notion of failure. Any parser can
--- fail; a failed parser affects the behavior of combinators such as
--- choice.
-newtype Parser a = Parser { runParser :: State -> Consumed a }
-
-instance Monad Parser where
-  (>>=) = bind
-  return = good
-  fail = failString
-
-instance Functor Parser where
-  fmap = liftM
-
-instance Applicative Parser where
-  (<*>) = Control.Monad.ap
-  pure = return
-
-instance Alternative Parser where
-  empty = genericThrow
-  (<|>) = choice
-  some = several1
-  many = several
-
-instance Monoid (Parser a) where
-  mempty = genericThrow
-  mappend = choice
-
-instance MonadPlus Parser where
-  mzero = genericThrow
-  mplus = choice
-
-type PendingShort = String
-type Remaining = [String]
-type SawStopper = Bool
-data State = State PendingShort Remaining SawStopper
-
-type InputDesc = String
-data Description = Unknown | General String | Expected String
-  deriving (Eq, Show, Ord)
-
--- | Error messages. To format error messages for nice display, see
--- 'System.Console.MultiArg.Combinator.formatError'.
-data Error = Error InputDesc [Description]
-  deriving (Eq, Show, Ord)
-
-data Reply a = Ok a State Error
-             | Fail Error
-
-data Consumed a = Consumed (Reply a)
-                | Empty (Reply a)
-
--- | @good a@ always succeeds without consuming any input and has
--- result a. This provides the implementation for
--- 'Control.Monad.Monad.return' and
--- 'Control.Applicative.Applicative.pure'.
-good :: a -> Parser a
-good x = Parser $ \st -> Empty (Ok x st (Error (descLocation st) []))
-
--- | Combines two parsers into a single parser. The second parser can
--- optionally depend upon the result from the first parser.
---
--- This applies the first parser. If the first parser succeeds,
--- combine then takes the result from the first parser, applies the
--- function given to the result from the first parser, and then
--- applies the resulting parser.
---
--- If the first parser fails, combine will not apply the second
--- function but instead will bypass the second parser.
---
--- This provides the implementation for '>>=' in
--- 'Control.Monad.Monad'.
-bind :: Parser a -> (a -> Parser b) -> Parser b
-bind (Parser p) f = Parser $ \s ->
-  case p s of
-    Empty r1 -> case r1 of
-      Ok x s' _ -> runParser (f x) s'
-      Fail m -> Empty (Fail m)
-    Consumed r1 -> Consumed $
-      case r1 of
-        Ok x s' _ -> case runParser (f x) s' of
-          Consumed r -> r
-          Empty r -> r
-        Fail e -> Fail e
-
-descLocation :: State -> InputDesc
-descLocation (State ps rm st) = pending ++ next ++ stop
-  where
-    pending
-      | null ps = ""
-      | otherwise = "short option or short option argument: "
-                  ++ ps ++ " "
-    next = case rm of
-      [] -> "no words remaining"
-      x:_ -> "next word: " ++ x
-    stop = if st then " (stopper already seen)" else ""
-
-
--- | @failString s@ always fails without consuming any input. The
--- failure contains a record of the string passed in by s. This
--- provides the implementation for 'Control.Monad.Monad.fail'.
-failString :: String -> Parser a
-failString str = Parser $ \s ->
-  Empty (Fail (Error (descLocation s) [General str]))
-
-
--- | Fail with an unhelpful error message. Usually 'throwString' is
--- more useful, but this is handy to implement some typeclass
--- instances.
-genericThrow :: Parser a
-genericThrow = Parser $ \s ->
-  Empty (Fail (Error (descLocation s) [Unknown]))
-
--- | Runs the first parser. If it fails without consuming any input,
--- then runs the second parser. If the first parser succeeds, then
--- returns the result of the first parser. If the first parser fails
--- and consumes input, then returns the result of the first
--- parser. This provides the implementation for
--- '<|>' in 'Control.Applicative.Alternative'.
-choice :: Parser a -> Parser a -> Parser a
-choice p q = Parser $ \s ->
-  case runParser p s of
-    Empty (Fail msg1) ->
-      case runParser q s of
-        Empty (Fail msg2) -> mergeError msg1 msg2
-        Empty (Ok x s' msg2) -> mergeOk x s' msg1 msg2
-        c -> c
-    Empty (Ok x s' msg1) ->
-      case runParser q s of
-        Empty (Fail msg2) -> mergeOk x s' msg1 msg2
-        Empty (Ok _ _ msg2) -> mergeOk x s' msg1 msg2
-        c -> c
-    c -> c
-  where
-    mergeOk x s msg1 msg2 = Empty (Ok x s (merge msg1 msg2))
-    mergeError msg1 msg2 = Empty (Fail (merge msg1 msg2))
-    merge (Error loc exp1) (Error _ exp2) =
-      Error loc (exp1 ++ exp2)
-
--- | Applies 'error' if a parser would succeed without consuming any
--- input. Useful for preventing infinite loops on parsers like
--- 'several1'.
-crashOnEmptyOk
-  :: String
-  -- ^ Use this label when applying 'error'
-
-  -> Parser a
-  -> Parser a
-crashOnEmptyOk str p = Parser $ \s ->
-  case runParser p s of
-    Empty r -> case r of
-      Ok _ _ _ ->
-         error $ "multiarg: error: " ++ str
-               ++ " applied to parser that succeeds without "
-               ++ "consuming any input. Aborted to prevent "
-               ++ "an infinite loop."
-      e -> Empty e
-    o -> o
-               
-
--- | Runs a parser one or more times. Runs the parser once and then
--- applies 'several'.
-several1 :: Parser a -> Parser [a]
-several1 p = do
-  r1 <- p
-  rs <- several p
-  return $ r1:rs
-
-
--- | Runs a parser zero or more times. If the last run of the parser
--- fails without consuming any input, this parser succeeds without
--- consuming any input. If the last run of the parser fails while
--- consuming input, this parser fails while consuming input. This
--- provides the implementation for 'many' in Control.Applicative.
-several :: Parser a -> Parser [a]
-several unwrapped =
-  let p = crashOnEmptyOk "several" unwrapped
-  in do
-    maybeA <- optional p
-    case maybeA of
-      Nothing -> return []
-      Just a -> do
-        rest <- several unwrapped
-        return $ a:rest
-  
-
--- | Runs the parser given. If it fails without consuming any input,
--- replaces all Expected messages with the one given. Otherwise,
--- returns the result of the parser unchanged.
-(<?>) :: Parser a -> String -> Parser a
-p <?> str = Parser $ \s ->
-  case runParser p s of
-    Empty (Fail m) -> Empty (Fail (expect m str))
-    Empty (Ok x s' m) -> Empty (Ok x s' (expect m str))
-    x -> x
-  where
-    expect (Error pos ls) s =
-      let ls' = mapMaybe notExpected ls
-          notExpected d = case d of
-            Expected _ -> Nothing
-            x -> Just x
-      in Error pos ((Expected s) : ls')
-
-infix 0 <?>
-
--- | Runs a parser. This is the only way to change a value of type
--- @Parser a@ into a value of type @a@ (that is, it is the only way to
--- \"get out of the Parser monad\" or to \"escape the Parser monad\".)
-parse
-  :: [String]
-  -- ^ Command line arguments to parse. Presumably you got these from
-  -- 'getArgs'. If there is any chance that you will be parsing
-  -- Unicode strings, see the documentation in
-  -- "System.Console.MultiArg.GetArgs" before you use
-  -- 'System.Environment.getArgs'.
-
-  -> Parser a
-  -- ^ Parser to run
-
-  -> Either Error a
-  -- ^ Success or failure. Any parser might fail; for example, the
-  -- command line might not have any values left to parse. Use of the
-  -- 'choice' combinator can lead to a list of failures.
-
-parse ss p =
-  let s = State "" ss False
-      procReply r = case r of
-        Ok x _ _ -> Right x
-        Fail m -> Left m
-  in case runParser p s of
-      Consumed r -> procReply r
-      Empty r -> procReply r
-
--- | Parses only pending short options. Fails without consuming any
--- input if there has already been a stopper or if there are no
--- pending short options. Fails without consuming any input if there
--- is a pending short option, but it does not match the short option
--- given. Succeeds and consumes a pending short option if it matches
--- the short option given.
-pendingShortOpt :: ShortOpt -> Parser ()
-pendingShortOpt so = Parser $ \s@(State pends rm stop) ->
-  let msg = Error (descLocation s)
-        [Expected ("pending short option: -" ++ [unShortOpt so])]
-      gd s' = Consumed (Ok () s' msg)
-      err = Empty (Fail msg)
-  in maybe err gd $ do
-    guard $ not stop
-    (first, rest) <- case pends of
-      [] -> mzero
-      x:xs -> return (x, xs)
-    when (unShortOpt so /= first) mzero
-    return $ State rest rm stop
-
--- | @lookAhead p@ runs parser p. If p succeeds, lookAhead p succeeds
--- without consuming any input. If p fails without consuming any
--- input, so does lookAhead. If p fails and consumes input, lookAhead
--- also fails and consumes input. If this is undesirable, combine with
--- "try".
-lookAhead :: Parser a -> Parser a
-lookAhead p = Parser $ \s ->
-  case runParser p s of
-    Consumed r -> case r of
-      Ok x _ e -> Empty (Ok x s e)
-      e -> Consumed e
-    e -> e
-
-nextW :: Remaining -> Maybe (String, Remaining)
-nextW rm = case rm of
-  [] -> Nothing
-  x:xs -> Just (x, xs)
-
--- | Parses only non-pending short options. Fails without consuming
--- any input if:
---
--- * there are pending short options
---
--- * there has already been a stopper
---
--- * there are no arguments left to parse
---
--- * the next argument is an empty string
---
--- * the next argument does not begin with a dash
---
--- * the next argument is a single dash
---
--- * the next argument is a short option but it does not match
---   the one given
---
--- * the next argument is a stopper
---
--- Otherwise, consumes the next argument, puts any remaining letters
--- from the argument into a pending short, and removes the first word
--- from remaining arguments to be parsed.
-nonPendingShortOpt :: ShortOpt -> Parser ()
-nonPendingShortOpt so = Parser $ \s@(State ps rm stop) ->
-  let dsc = [Expected
-            $ "non pending short option: -" ++ [unShortOpt so]]
-      err = Error (descLocation s) dsc
-      errRet = Empty (Fail err)
-      gd (ps'', rm'') = Consumed (Ok () (State ps'' rm'' stop) err)
-  in maybe errRet gd $ do
-    guard $ null ps
-    guard $ not stop
-    (a, rm') <- nextW rm
-    (maybeDash, word) <- case a of
-      [] -> mzero
-      x:xs -> return (x, xs)
-    guard (maybeDash == '-')
-    (letter, arg) <- case word of
-      [] -> mzero
-      x:xs -> return (x, xs)
-    guard (letter == unShortOpt so)
-    return (arg, rm')
-
-
--- | Parses an exact long option. That is, the text of the
--- command-line option must exactly match the text of the
--- option. Returns any argument that is attached to
--- the same word of the option with an equal sign (for example,
--- @--follow=\/dev\/random@ will return @Just \"\/dev\/random\"@ for the
--- argument.) If there is no equal sign, returns Nothing for the
--- argument. If there is an equal sign but there is nothing after it,
--- returns @Just \"\"@ for the argument.
---
--- If you do not want your long option to have equal signs and
--- GNU-style option arguments, wrap this parser in something that will
--- fail if there is an option argument.
---
--- Fails without consuming any input if:
---
--- * there are pending short options
---
--- * a stopper has been parsed
---
--- * there are no arguments left on the command line
---
--- * the next argument on the command line does not begin with
---   two dashes
---
--- * the next argument on the command line is @--@ (a stopper)
---
--- * the next argument on the command line does begin with two
---   dashes but its text does not match the argument we're looking for
-
-exactLongOpt :: LongOpt -> Parser (Maybe String)
-exactLongOpt lo = Parser $ \s@(State ps rm sp) ->
-  let msg = Error (descLocation s)
-            [Expected ("long option: --" ++ unLongOpt lo)]
-      gd (arg, newRm) = Consumed (Ok arg (State ps newRm sp) msg)
-      err = Empty (Fail msg)
-  in maybe err gd $ do
-    guard $ null ps
-    guard $ not sp
-    (x, rm') <- nextW rm
-    (word, afterEq) <- getLongOption x
-    guard (word == unLongOpt lo)
-    return (afterEq, rm')
-    
-
-getLongOption :: String -> Maybe (String, Maybe String)
-getLongOption str = do
-  guard (str /= "--")
-  let (pre, word, afterEq) = splitLongWord str
-  guard (pre == "--")
-  return (word, afterEq)
-
--- | Takes a single String and returns a tuple, where the first element
--- is the first two letters, the second element is everything from the
--- third letter to the equal sign, and the third element is Nothing if
--- there is no equal sign, or Just String with everything after the
--- equal sign if there is one.
-splitLongWord :: String -> (String, String, Maybe String)
-splitLongWord t = (f, s, r) where
-  (f, rest) = L.splitAt 2 t
-  (s, withEq) = L.break (== '=') rest
-  r = case withEq of
-    [] -> Nothing
-    _:xs -> Just xs
-
-approxLongOptError :: [LongOpt] -> [Description]
-approxLongOptError =
-  map (Expected . ("long option: --" ++) . unLongOpt)
-
-
-assert :: e -> Bool -> Either e ()
-assert e b = if b then Right () else Left e
-
-fromMaybe :: e -> Maybe a -> Either e a
-fromMaybe e = maybe (Left e) Right
-
--- | Examines the next word. If it matches a LongOpt in the set
--- unambiguously, returns a tuple of the word actually found and the
--- matching word in the set and the accompanying text after the equal
--- sign (if any). If the Set is empty, this parser will always fail.
-approxLongOpt ::
-  Set LongOpt
-  -> Parser (String, LongOpt, Maybe String)
-approxLongOpt ts = Parser $ \s@(State ps rm stop) ->
-  let err ls = Error (descLocation s) (approxLongOptError ls)
-      ert ls = Empty (Fail $ err ls)
-      gd (found, opt, arg, rm'') =
-        Consumed (Ok (found, opt, arg) (State ps rm'' stop)
-                     (err allOpts))
-      allOpts = Set.toList ts
-  in either ert gd $ do
-    assert allOpts $ null ps
-    assert allOpts $ not stop
-    (x, rm') <- fromMaybe allOpts $ nextW rm
-    (word, afterEq) <- fromMaybe allOpts $ getLongOption x
-    opt <- fromMaybe allOpts $ makeLongOpt word
-    if Set.member opt ts
-      then return (word, opt, afterEq, rm')
-      else do
-      let p t = word `isPrefixOf` unLongOpt t
-          matches = Set.filter p ts
-      case Set.toList matches of
-        [] -> Left allOpts
-        (m:[]) -> return (word, m, afterEq, rm')
-        ls -> Left ls
-
-
--- | Parses only pending short option arguments. For example, for the
--- @tail@ command, if you enter the option @-c25@, then after parsing
--- the @-c@ option the @25@ becomes a pending short option argument
--- because it was in the same command line argument as the @-c@.
---
--- Fails without consuming any input if:
---
--- * a stopper has already been parsed
---
--- * there are no pending short option arguments
---
--- On success, returns the String of the pending short option argument
--- (this String will never be empty).
-pendingShortOptArg :: Parser String
-pendingShortOptArg = Parser $ \st@(State ps rm sp) ->
-  let msg = [Expected "pending short option argument"]
-      err = Error (descLocation st) msg
-      ert = Empty (Fail err)
-      gd str = Consumed (Ok str (State "" rm sp) err)
-  in maybe ert gd $ do
-     guard $ not sp
-     case ps of
-      [] -> mzero
-      xs -> return xs
-
-
--- | Parses a \"stopper\" - that is, a double dash. Changes the internal
--- state of the parser to reflect that a stopper has been seen.
-stopper :: Parser ()
-stopper = Parser $ \s@(State ps rm sp) ->
-  let err = Error (descLocation s)
-        [Expected "stopper, \"--\""]
-      ert = Empty (Fail err)
-      gd rm'' = Consumed (Ok () (State ps rm'' True) err)
-  in maybe ert gd $ do
-     guard $ not sp
-     guard . null $ ps
-     (x, rm') <- nextW rm
-     guard $ x == "--"
-     return rm'
-
-
--- | If a stopper has already been seen, change the internal state
--- back to indicating that no stopper has been seen.
-resetStopper :: Parser ()
-resetStopper = Parser $ \s@(State ps rm _) ->
-  Empty (Ok () (State ps rm False) (Error (descLocation s) []))
-
-
--- | try p behaves just like p, but if p fails, try p will not consume
--- any input.
-try :: Parser a -> Parser a
-try a = Parser $ \s ->
-  case runParser a s of
-    Consumed r -> case r of
-      Fail e -> Empty (Fail e)
-      o -> Consumed o
-    o -> o
-
-
--- | Returns the next string on the command line as long as there are
--- no pendings. Succeeds even if a stopper is present. Be careful -
--- this will return the next string even if it looks like an option
--- (that is, it starts with a dash.) Consider whether you should be
--- using nonOptionPosArg instead. However this can be useful when
--- parsing command line options after a stopper.
-nextWord :: Parser String
-nextWord = Parser $ \s@(State ps rm sp) ->
-  let err = Error (descLocation s) [dsc]
-      dsc = Expected "next word"
-      ert = Empty (Fail err)
-      gd (str, rm'') = Consumed $ Ok str (State ps rm'' sp) err
-  in maybe ert gd $ do
-      guard $ null ps
-      nextW rm
-      
-
--- | Parses the next word on the command line, but only if it exactly
--- matches the word given. Otherwise, fails without consuming any
--- input. Also fails without consuming any input if there are pending
--- short options or if a stopper has already been parsed. Does not pay
--- any attention to whether a stopper is present.
-nextWordIs :: String -> Parser ()
-nextWordIs str = Parser $ \s@(State ps rm sp) ->
-  let err = Error (descLocation s) [dsc]
-      dsc = Expected $ "next argument \"" ++ str ++ "\""
-      ert = Empty $ Fail err
-      gd rm'' = Consumed $ Ok () (State ps rm'' sp) err
-  in maybe ert gd $ do
-      guard $ null ps
-      (a, rm') <- nextW rm
-      guard (a == str)
-      return rm'
-
-
--- | If there are pending short options, fails without consuming any input.
---
--- Otherwise, if a stopper has NOT already been parsed, then returns
--- the next word if it is either a single dash or any other word that
--- does not begin with a dash. If the next word does not meet these
--- criteria, fails without consuming any input.
---
--- Otherwise, if a stopper has already been parsed, then returns the
--- next word, regardless of whether it begins with a dash or not.
-nonOptionPosArg :: Parser String
-nonOptionPosArg = Parser $ \s@(State ps rm sp) ->
-  let err = Error (descLocation s) [dsc]
-      dsc = Expected "non option positional argument"
-      ert = Empty $ Fail err
-      gd (str, rm'') = Consumed $ Ok str (State ps rm'' sp) err
-  in maybe ert gd $ do
-    guard $ null ps
-    (x, rm') <- nextW rm
-    result <- if sp
-              then return x
-              else case x of
-                [] -> return x
-                '-':[] -> return "-"
-                f:_ -> if f == '-' then mzero else return x
-    return (result, rm')
-
-
--- | Succeeds if there is no more input left.
-end :: Parser ()
-end = Parser $ \s@(State ps rm _) ->
-  let err = Error (descLocation s) [dsc]
-      dsc = Expected "end of input"
-      ert = Empty $ Fail err
-      gd = Empty $ Ok () s err
-  in if null ps && null rm then gd else ert
-
-
--- | Examines the possible words in Set. If there are no pendings,
--- then get the next word and see if it matches one of the words in
--- Set. If so, returns the word actually parsed and the matching word
--- from Set. If there is no match, fails without consuming any
--- input. Pays no attention to whether a stopper has been seen.
-matchApproxWord :: Set String -> Parser (String, String)
-matchApproxWord set = Parser $ \s@(State ps rm sp) ->
-  let err = Error (descLocation s) . lsDsc
-      lsDsc = map (Expected . ("next word: " ++))
-      ert = Empty . Fail . err
-      gd (act, mtch, rm'') =
-        Consumed $ Ok (act, mtch) (State ps rm'' sp) (err allWords)
-      allWords = Set.toList set
-  in either ert gd $ do
-      assert allWords $ null ps
-      (x, rm') <- fromMaybe allWords $ nextW rm
-      let matches = Set.filter p set
-          p t = x `isPrefixOf` t
-      case Set.toList matches of
-        [] -> Left allWords
-        r:[] -> return (x, r, rm')
-        xs -> Left xs
-      
--- | @manyTill p end@ runs parser p zero or more times until parser
--- @end@ succeeds. If @end@ succeeds and consumes input, that input is
--- also consumed. in the result of @manyTill@. If that is a problem,
--- wrap it in @lookAhead@. Also, if @end@ fails and consumes input,
--- @manyTill@ fails and consumes input. If that is a problem, wrap
--- @end@ in @try@.
-manyTill :: Parser a -> Parser end -> Parser [a]
-manyTill p e = do
-  maybeEnd <- optional e
-  case maybeEnd of
-    Just _ -> return []
-    Nothing -> do
-      a <- crashOnEmptyOk "manyTill" p
-      rs <- manyTill p e
-      return $ a:rs
-
diff --git a/lib/System/Console/MultiArg/SampleParser.hs b/lib/System/Console/MultiArg/SampleParser.hs
deleted file mode 100644
--- a/lib/System/Console/MultiArg/SampleParser.hs
+++ /dev/null
@@ -1,70 +0,0 @@
--- | This is sample code using "System.Console.MultiArg". This could
--- be a command-line parser for the version of the Unix command @tail@
--- that is included with GNU coreutils version 8.5. "main" simply gets
--- the command line arguments, parses them, and prints out what was
--- parsed. To test it out, simply compile an executable that looks
--- like this and then feed it different options:
---
--- > import System.Console.MultiArg.SampleParser
--- > main = sampleMain Intersperse
---
--- or:
---
--- > import System.Console.MultiArg.SampleParser
--- > main = sampleMain StopOptions
---
--- The code in the module is the sample code; the sample code is not
--- in the Haddock documentation! If you're reading this in Haddock,
--- you will want to also take a look at the actual source code.
-module System.Console.MultiArg.SampleParser where
-
-import qualified System.Console.MultiArg.Combinator as C
-import qualified System.Console.MultiArg.CommandLine as P
-
-data Flag =
-  Bytes String
-  | Follow (Maybe String)
-  | Retry
-  | Lines String
-  | Stats String
-  | Pid String
-  | Quiet
-  | Sleep String
-  | Verbose
-  | Help
-  | Version
-  | Filename String
-  deriving Show
-
-specs :: [C.OptSpec Flag]
-
-specs =
-  [ C.OptSpec ["bytes"]                     ['c']
-              (C.OneArg (return . Bytes))
-
-  , C.OptSpec ["follow"]                    ['f']
-              (C.OptionalArg (return . Follow))
-
-  , C.OptSpec ["follow-retry"]              ['F']     (C.NoArg Retry)
-
-  , C.OptSpec ["lines"]                     ['n']
-              (C.OneArg (return . Lines))
-
-  , C.OptSpec ["max-unchanged-stats"]       []
-              (C.OneArg (return . Stats))
-
-  , C.OptSpec ["pid"]                       []
-              (C.OneArg (return . Pid))
-  , C.OptSpec ["quiet"]                     ['q']     (C.NoArg Quiet)
-
-  , C.OptSpec ["sleep-interval"]            ['s']
-              (C.OneArg (return . Sleep))
-  , C.OptSpec ["verbose"]                   ['v']     (C.NoArg Verbose)
-  , C.OptSpec ["help"]                      []        (C.NoArg Help)
-  , C.OptSpec ["version"]                   []        (C.NoArg Version)
-  ]
-
-sampleMain :: P.Intersperse -> IO ()
-sampleMain i = do
-  r <- P.simpleIO specs i (return . Filename)
-  print r
diff --git a/multiarg.cabal b/multiarg.cabal
--- a/multiarg.cabal
+++ b/multiarg.cabal
@@ -1,5 +1,5 @@
 Name: multiarg
-Version: 0.26.0.0
+Version: 0.28.0.0
 Cabal-version: >=1.8
 Build-Type: Simple
 License: BSD3
@@ -16,8 +16,6 @@
   minimum-versions.txt, current-versions.txt,
   sunlight-test.hs
 
-tested-with: GHC==7.4.1, GHC==7.6.3
-
 description: multiarg is a parser combinator library to build command
  line parsers. With it you can easily create parsers with options
  that take more than one option argument--for example, I created
@@ -30,7 +28,7 @@
  for many situtations and shields you from the underlying complexity
  if you don't need it.
  .
- See the documentation in the System.Console.MultiArg module for
+ See the documentation in the Multiarg module for
  details.
 
 source-repository head
@@ -46,12 +44,12 @@
   hs-source-dirs: lib
 
   Exposed-modules:
-      System.Console.MultiArg
-    , System.Console.MultiArg.Combinator
-    , System.Console.MultiArg.CommandLine
-    , System.Console.MultiArg.Option
-    , System.Console.MultiArg.Prim
-    , System.Console.MultiArg.SampleParser
+      Multiarg
+    , Multiarg.Combinator
+    , Multiarg.CommandLine
+    , Multiarg.Option
+    , Multiarg.Prim
+    , Multiarg.SampleParser
 
   ghc-options: -Wall
 
