-- | Generate a main action that parses the given command line options
-- (while always adding 'commonOptions').
mainWithOptions :: cfg
                -> [FunOptDescr cfg]
                -> ([String] -> cfg -> Maybe (IO ()))
                -> IO ()
mainWithOptions emptyConfig commandLineOptions f = do
  args <- getArgs
  case getOpt' Permute commandLineOptions' args of
    (opts, nonopts, [], []) ->
      case applyOpts opts of
        Right config
          | Just m <- f nonopts config -> m
          | otherwise                  -> invalid nonopts [] []
        Left m       -> m
    (_, nonopts, unrecs, errs) -> invalid nonopts unrecs errs
  where applyOpts opts = do fs <- sequence opts
                            return $ foldl (.) id (reverse fs) emptyConfig

        invalid nonopts unrecs errs = do usage <- usageStr commandLineOptions'
                                         badOptions usage nonopts errs unrecs

        commandLineOptions' =
          commonOptions commandLineOptions ++ commandLineOptions
mainWithOptions :: cfg
                -> [FunOptDescr cfg]
                -> ([String] -> cfg -> Maybe (IO ()))
                -> IO ()
mainWithOptions emptyConfig commandLineOptions f = do
  args <- getArgs
  case getOpt' Permute commandLineOptions' args of
    (opts, nonopts, [], []) ->
      case applyOpts opts of
        Right config
          | Just m <- f nonopts config -> m
          | otherwise                  -> invalid nonopts [] []
        Left m       -> m
    (_, nonopts, unrecs, errs) -> invalid nonopts unrecs errs
  where applyOpts opts = do fs <- sequence opts
                            return $ foldl (.) id (reverse fs) emptyConfig

        invalid nonopts unrecs errs = do usage <- usageStr commandLineOptions'
                                         badOptions usage nonopts errs unrecs

        commandLineOptions' =
          commonOptions commandLineOptions ++ commandLineOptions
mainWithOptions emptyConfig commandLineOptions f = do
  args <- getArgs
  case getOpt' Permute commandLineOptions' args of
    (opts, nonopts, [], []) ->
      case applyOpts opts of
        Right config
          | Just m <- f nonopts config -> m
          | otherwise                  -> invalid nonopts [] []
        Left m       -> m
    (_, nonopts, unrecs, errs) -> invalid nonopts unrecs errs
  where applyOpts opts = do fs <- sequence opts
                            return $ foldl (.) id (reverse fs) emptyConfig

        invalid nonopts unrecs errs = do usage <- usageStr commandLineOptions'
                                         badOptions usage nonopts errs unrecs

        commandLineOptions' =
          commonOptions commandLineOptions ++ commandLineOptions