    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Language.C
    -- Copyright   :  (c) 2008 Benedikt Huber
    --                [1995..2007]
    --                   Manuel M. T. Chakravarty
    --                   Duncan Coutts
    --                   Betram Felgenhauer
    -- License     :  BSD-style
    -- Maintainer  : benedikt.huber@gmail.com
    -- Stability   : experimental
    -- Portability : ghc
    --
    -- Library for analysing and generating C code.
    --
    -- See <http://www.sivity.net/projects/language.c>
    -----------------------------------------------------------------------------
    module Language.C (
        parseCFile, parseCFilePre, -- maybe change ?
        module Language.C.Data,
        module Language.C.Syntax,
        module Language.C.Pretty,
        module Language.C.Parser,
    )
    where
    import Language.C.Data
    import Language.C.Syntax
    import Language.C.Pretty
    import Language.C.Parser
    import Language.C.System.Preprocess

    -- | preprocess (if necessary) and parse a C source file
    --
    --   > Synopsis: parseCFile preprocesssor tmp-dir? cpp-opts file
    --   > Example:  parseCFile (newGCC "gcc") Nothing ["-I/usr/include/gtk-2.0"] my-gtk-exts.c
    parseCFile :: (Preprocessor cpp) => cpp -> Maybe FilePath -> [String] -> FilePath -> IO (Either ParseError CTranslUnit)
    parseCFile :: forall cpp.
    Preprocessor cpp =>
    cpp
    -> Maybe FilePath
    -> [FilePath]
    -> FilePath
    -> IO (Either ParseError CTranslUnit)
    parseCFile cpp
    cpp Maybe FilePath
    tmp_dir_opt [FilePath]
    args FilePath
    input_file = do
        input_stream <- if Bool -> Bool
    not (FilePath -> Bool
    isPreprocessed FilePath
    input_file)
                            then  let cpp_args :: CppArgs
    cpp_args = ([FilePath] -> FilePath -> CppArgs
    rawCppArgs [FilePath]
    args FilePath
    input_file) { cppTmpDir = tmp_dir_opt }
                                  in  cpp -> CppArgs -> IO (Either ExitCode InputStream)
    forall cpp.
    Preprocessor cpp =>
    cpp -> CppArgs -> IO (Either ExitCode InputStream)
    runPreprocessor cpp
    cpp CppArgs
    cpp_args IO (Either ExitCode InputStream)
    -> (Either ExitCode InputStream -> IO InputStream)
    -> IO InputStream
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Either ExitCode InputStream -> IO InputStream
    forall {m :: * -> *} {a} {a}.
    (MonadFail m, Show a) =>
    Either a a -> m a
    handleCppError
                            else  FilePath -> IO InputStream
    readInputStream FilePath
    input_file
        return$ parseC input_stream (initPos input_file)
        where
        handleCppError :: Either a a -> m a
    handleCppError (Left a
    exitCode) = FilePath -> m a
    forall a. FilePath -> m a
    forall (m :: * -> *) a. MonadFail m => FilePath -> m a
    fail (FilePath -> m a) -> FilePath -> m a
    forall a b. (a -> b) -> a -> b
    $ FilePath
    "Preprocessor failed with " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ a -> FilePath
    forall a. Show a => a -> FilePath
    show a
    exitCode
        handleCppError (Right a
    ok)      = a -> m a
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    ok

    -- | parse an already preprocessed C file
    --
    --   > Synopsis: parseCFilePre file.i
    parseCFilePre :: FilePath -> IO (Either ParseError CTranslUnit)
    parseCFilePre :: FilePath -> IO (Either ParseError CTranslUnit)
    parseCFilePre FilePath
    file = do
        input_stream <- FilePath -> IO InputStream
    readInputStream FilePath
    file
        return $ parseC input_stream (initPos file)