    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Distribution.Simple.Program.Builtin
    -- Copyright   :  Isaac Jones 2006, Duncan Coutts 2007-2009
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- The module defines all the known built-in 'Program's.
    --
    -- Where possible we try to find their version numbers.
    --
    module Distribution.Simple.Program.Builtin (

        -- * The collection of unconfigured and configured progams
        builtinPrograms,

        -- * Programs that Cabal knows about
        ghcProgram,
        ghcPkgProgram,
        lhcProgram,
        lhcPkgProgram,
        nhcProgram,
        hmakeProgram,
        jhcProgram,
        hugsProgram,
        ffihugsProgram,
        uhcProgram,
        gccProgram,
        ranlibProgram,
        arProgram,
        stripProgram,
        happyProgram,
        alexProgram,
        hsc2hsProgram,
        c2hsProgram,
        cpphsProgram,
        hscolourProgram,
        haddockProgram,
        greencardProgram,
        ldProgram,
        tarProgram,
        cppProgram,
        pkgConfigProgram,
      ) where

    import Distribution.Simple.Program.Types
             ( Program(..), simpleProgram )
    import Distribution.Simple.Utils
             ( findProgramLocation, findProgramVersion )

    -- ------------------------------------------------------------
    -- * Known programs
    -- ------------------------------------------------------------

    -- | The default list of programs.
    -- These programs are typically used internally to Cabal.
    builtinPrograms :: [Program]
    builtinPrograms =
        [
        -- compilers and related progs
          ghcProgram
        , ghcPkgProgram
        , hugsProgram
        , ffihugsProgram
        , nhcProgram
        , hmakeProgram
        , jhcProgram
        , lhcProgram
        , lhcPkgProgram
        , uhcProgram
        -- preprocessors
        , hscolourProgram
        , haddockProgram
        , happyProgram
        , alexProgram
        , hsc2hsProgram
        , c2hsProgram
        , cpphsProgram
        , greencardProgram
        -- platform toolchain
        , gccProgram
        , ranlibProgram
        , arProgram
        , stripProgram
        , ldProgram
        , tarProgram
        -- configuration tools
        , pkgConfigProgram
        ]

    ghcProgram :: Program
    ghcProgram = (simpleProgram "ghc") {
        programFindVersion = findProgramVersion "--numeric-version" id
      }

    ghcPkgProgram :: Program
    ghcPkgProgram = (simpleProgram "ghc-pkg") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "ghc-pkg --version" gives a string like
          -- "GHC package manager version 6.4.1"
          case words str of
            (_:_:_:_:ver:_) -> ver
            _               -> ""
      }

    lhcProgram :: Program
    lhcProgram = (simpleProgram "lhc") {
        programFindVersion = findProgramVersion "--numeric-version" id
      }

    lhcPkgProgram :: Program
    lhcPkgProgram = (simpleProgram "lhc-pkg") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "lhc-pkg --version" gives a string like
          -- "LHC package manager version 0.7"
          case words str of
            (_:_:_:_:ver:_) -> ver
            _               -> ""
      }

    nhcProgram :: Program
    nhcProgram = (simpleProgram "nhc98") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "nhc98 --version" gives a string like
          -- "/usr/local/bin/nhc98: v1.20 (2007-11-22)"
          case words str of
            (_:('v':ver):_) -> ver
            _               -> ""
      }

    hmakeProgram :: Program
    hmakeProgram = (simpleProgram "hmake") {
        programFindVersion = findProgramVersion "--version" $ \str ->
        -- Invoking "hmake --version" gives a string line
        -- "/usr/local/bin/hmake: 3.13 (2006-11-01)"
          case words str of
            (_:ver:_) -> ver
            _         -> ""
      }

    jhcProgram :: Program
    jhcProgram = (simpleProgram "jhc") {
        programFindVersion = findProgramVersion "--version" $ \str ->
        -- invoking "jhc --version" gives a string like
        -- "jhc 0.3.20080208 (wubgipkamcep-2)
        -- compiled by ghc-6.8 on a x86_64 running linux"
          case words str of
            (_:ver:_) -> ver
            _         -> ""
      }

    uhcProgram :: Program
    uhcProgram = (simpleProgram "uhc") {
        programFindVersion = findProgramVersion "--version-dotted" id
      }

    -- AArgh! Finding the version of hugs or ffihugs is almost impossible.
    hugsProgram :: Program
    hugsProgram = simpleProgram "hugs"

    ffihugsProgram :: Program
    ffihugsProgram = simpleProgram "ffihugs"

    happyProgram :: Program
    happyProgram = (simpleProgram "happy") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "happy --version" gives a string like
          -- "Happy Version 1.16 Copyright (c) ...."
          case words str of
            (_:_:ver:_) -> ver
            _           -> ""
      }

    alexProgram :: Program
    alexProgram = (simpleProgram "alex") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "alex --version" gives a string like
          -- "Alex version 2.1.0, (c) 2003 Chris Dornan and Simon Marlow"
          case words str of
            (_:_:ver:_) -> takeWhile (`elem` ('.':['0'..'9'])) ver
            _           -> ""
      }

    gccProgram :: Program
    gccProgram = (simpleProgram "gcc") {
        programFindVersion = findProgramVersion "-dumpversion" id
      }

    ranlibProgram :: Program
    ranlibProgram = simpleProgram "ranlib"

    arProgram :: Program
    arProgram = simpleProgram "ar"

    stripProgram :: Program
    stripProgram = simpleProgram "strip"

    hsc2hsProgram :: Program
    hsc2hsProgram = (simpleProgram "hsc2hs") {
        programFindVersion =
          findProgramVersion "--version" $ \str ->
            -- Invoking "hsc2hs --version" gives a string like "hsc2hs version 0.66"
            case words str of
              (_:_:ver:_) -> ver
              _           -> ""
      }

    c2hsProgram :: Program
    c2hsProgram = (simpleProgram "c2hs") {
        programFindVersion = findProgramVersion "--numeric-version" id
      }

    cpphsProgram :: Program
    cpphsProgram = (simpleProgram "cpphs") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "cpphs --version" gives a string like "cpphs 1.3"
          case words str of
            (_:ver:_) -> ver
            _         -> ""
      }

    hscolourProgram :: Program
    hscolourProgram = (simpleProgram "hscolour") {
        programFindLocation = \v -> findProgramLocation v "HsColour",
        programFindVersion  = findProgramVersion "-version" $ \str ->
          -- Invoking "HsColour -version" gives a string like "HsColour 1.7"
          case words str of
            (_:ver:_) -> ver
            _         -> ""
      }

    haddockProgram :: Program
    haddockProgram = (simpleProgram "haddock") {
        programFindVersion = findProgramVersion "--version" $ \str ->
          -- Invoking "haddock --version" gives a string like
          -- "Haddock version 0.8, (c) Simon Marlow 2006"
          case words str of
            (_:_:ver:_) -> takeWhile (`elem` ('.':['0'..'9'])) ver
            _           -> ""
      }

    greencardProgram :: Program
    greencardProgram = simpleProgram "greencard"

    ldProgram :: Program
    ldProgram = simpleProgram "ld"

    tarProgram :: Program
    tarProgram = simpleProgram "tar"

    cppProgram :: Program
    cppProgram = simpleProgram "cpp"

    pkgConfigProgram :: Program
    pkgConfigProgram = (simpleProgram "pkg-config") {
        programFindVersion = findProgramVersion "--version" id
      }