module Distribution.Simple.Program.Builtin (
    
    builtinPrograms,
    
    ghcProgram,
    ghcPkgProgram,
    ghcjsProgram,
    ghcjsPkgProgram,
    lhcProgram,
    lhcPkgProgram,
    hmakeProgram,
    jhcProgram,
    haskellSuiteProgram,
    haskellSuitePkgProgram,
    uhcProgram,
    gccProgram,
    arProgram,
    stripProgram,
    happyProgram,
    alexProgram,
    hsc2hsProgram,
    c2hsProgram,
    cpphsProgram,
    hscolourProgram,
    haddockProgram,
    greencardProgram,
    ldProgram,
    tarProgram,
    cppProgram,
    pkgConfigProgram,
    hpcProgram,
  ) where
import Distribution.Simple.Program.Find
         ( findProgramOnSearchPath )
import Distribution.Simple.Program.Run
         ( getProgramInvocationOutput, programInvocation )
import Distribution.Simple.Program.Types
         ( Program(..), ConfiguredProgram(..), simpleProgram )
import Distribution.Simple.Utils
         ( findProgramVersion )
import Distribution.Compat.Exception
         ( catchIO )
import Distribution.Verbosity
         ( lessVerbose )
import Distribution.Version
         ( Version(..), withinRange, earlierVersion, laterVersion
         , intersectVersionRanges )
import Data.Char
         ( isDigit )
import Data.List
         ( isInfixOf )
import qualified Data.Map as Map
builtinPrograms :: [Program]
builtinPrograms =
    [
    
      ghcProgram
    , ghcPkgProgram
    , ghcjsProgram
    , ghcjsPkgProgram
    , haskellSuiteProgram
    , haskellSuitePkgProgram
    , hmakeProgram
    , jhcProgram
    , lhcProgram
    , lhcPkgProgram
    , uhcProgram
    , hpcProgram
    
    , hscolourProgram
    , haddockProgram
    , happyProgram
    , alexProgram
    , hsc2hsProgram
    , c2hsProgram
    , cpphsProgram
    , greencardProgram
    
    , gccProgram
    , arProgram
    , stripProgram
    , ldProgram
    , tarProgram
    
    , pkgConfigProgram
    ]
ghcProgram :: Program
ghcProgram = (simpleProgram "ghc") {
    programFindVersion = findProgramVersion "--numeric-version" id,
    
    
    programPostConf    = \_verbosity ghcProg ->
    do let ghcProg' = ghcProg {
             programOverrideEnv = ("LANGUAGE", Just "en")
                                  : programOverrideEnv ghcProg
             }
           
           affectedVersionRange = intersectVersionRanges
                                  (laterVersion   $ Version [7,8,0] [])
                                  (earlierVersion $ Version [7,8,4] [])
       return $ maybe ghcProg
         (\v -> if withinRange v affectedVersionRange
                then ghcProg' else ghcProg)
         (programVersion ghcProg)
  }
ghcPkgProgram :: Program
ghcPkgProgram = (simpleProgram "ghc-pkg") {
    programFindVersion = findProgramVersion "--version" $ \str ->
      
      
      case words str of
        (_:_:_:_:ver:_) -> ver
        _               -> ""
  }
ghcjsProgram :: Program
ghcjsProgram = (simpleProgram "ghcjs") {
    programFindVersion = findProgramVersion "--numeric-ghcjs-version" id
  }
ghcjsPkgProgram :: Program
ghcjsPkgProgram = (simpleProgram "ghcjs-pkg") {
    programFindVersion = findProgramVersion "--version" $ \str ->
      
      
      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 ->
      
      
      case words str of
        (_:_:_:_:ver:_) -> ver
        _               -> ""
  }
hmakeProgram :: Program
hmakeProgram = (simpleProgram "hmake") {
    programFindVersion = findProgramVersion "--version" $ \str ->
    
    
      case words str of
        (_:ver:_) -> ver
        _         -> ""
  }
jhcProgram :: Program
jhcProgram = (simpleProgram "jhc") {
    programFindVersion = findProgramVersion "--version" $ \str ->
    
    
    
      case words str of
        (_:ver:_) -> ver
        _         -> ""
  }
uhcProgram :: Program
uhcProgram = (simpleProgram "uhc") {
    programFindVersion = findProgramVersion "--version-dotted" id
  }
hpcProgram :: Program
hpcProgram = (simpleProgram "hpc")
    {
        programFindVersion = findProgramVersion "version" $ \str ->
            case words str of
                (_ : _ : _ : ver : _) -> ver
                _ -> ""
    }
haskellSuiteProgram :: Program
haskellSuiteProgram = (simpleProgram "haskell-suite") {
    
    
    programFindLocation =
      \_verbosity _searchPath -> return $ Just "haskell-suite-dummy-location"
  }
haskellSuitePkgProgram :: Program
haskellSuitePkgProgram = (simpleProgram "haskell-suite-pkg") {
    programFindLocation =
      \_verbosity _searchPath -> return $ Just "haskell-suite-pkg-dummy-location"
  }
happyProgram :: Program
happyProgram = (simpleProgram "happy") {
    programFindVersion = findProgramVersion "--version" $ \str ->
      
      
      case words str of
        (_:_:ver:_) -> ver
        _           -> ""
  }
alexProgram :: Program
alexProgram = (simpleProgram "alex") {
    programFindVersion = findProgramVersion "--version" $ \str ->
      
      
      case words str of
        (_:_:ver:_) -> takeWhile (\x -> isDigit x || x == '.') ver
        _           -> ""
  }
gccProgram :: Program
gccProgram = (simpleProgram "gcc") {
    programFindVersion = findProgramVersion "-dumpversion" id
  }
arProgram :: Program
arProgram = simpleProgram "ar"
stripProgram :: Program
stripProgram = (simpleProgram "strip") {
    programFindVersion = \verbosity ->
      findProgramVersion "--version" selectVersion (lessVerbose verbosity)
  }
  where
    selectVersion str =
      
      
      
      
      let numeric ""    = False
          numeric (x:_) = isDigit x
      in case dropWhile (not . numeric) (words str) of
        (ver:_) ->
          
          let isDot         = (== '.')
              (major, rest) = break isDot ver
              minor         = takeWhile (not . isDot) (dropWhile isDot rest)
          in major ++ "." ++ minor
        _ -> ""
hsc2hsProgram :: Program
hsc2hsProgram = (simpleProgram "hsc2hs") {
    programFindVersion =
      findProgramVersion "--version" $ \str ->
        
        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 ->
      
      case words str of
        (_:ver:_) -> ver
        _         -> ""
  }
hscolourProgram :: Program
hscolourProgram = (simpleProgram "hscolour") {
    programFindLocation = \v p -> findProgramOnSearchPath v p "HsColour",
    programFindVersion  = findProgramVersion "-version" $ \str ->
      
      case words str of
        (_:ver:_) -> ver
        _         -> ""
  }
haddockProgram :: Program
haddockProgram = (simpleProgram "haddock") {
    programFindVersion = findProgramVersion "--version" $ \str ->
      
      
      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") {
  
  
  programPostConf = \verbosity tarProg -> do
     tarHelpOutput <- getProgramInvocationOutput
                      verbosity (programInvocation tarProg ["--help"])
                      
                      `catchIO` (\_ -> return "")
     let k = "Supports --format"
         v = if ("--format" `isInfixOf` tarHelpOutput) then "YES" else "NO"
         m = Map.insert k v (programProperties tarProg)
     return $ tarProg { programProperties = m }
  }
cppProgram :: Program
cppProgram = simpleProgram "cpp"
pkgConfigProgram :: Program
pkgConfigProgram = (simpleProgram "pkg-config") {
    programFindVersion = findProgramVersion "--version" id
  }