    module GHC.Settings.Utils where

    import Prelude -- See Note [Why do we import Prelude here?]

    import Data.Char (isSpace)
    import Data.Map (Map)
    import qualified Data.Map as Map

    import GHC.BaseDir
    import GHC.Platform.ArchOS
    import System.FilePath

    maybeRead :: Read a => String -> Maybe a
    maybeRead :: forall a. Read a => String -> Maybe a
    maybeRead String
    str = case ReadS a
    forall a. Read a => ReadS a
    reads String
    str of
      [(a
    x, String
    "")] -> a -> Maybe a
    forall a. a -> Maybe a
    Just a
    x
      [(a, String)]
    _ -> Maybe a
    forall a. Maybe a
    Nothing

    maybeReadFuzzy :: Read a => String -> Maybe a
    maybeReadFuzzy :: forall a. Read a => String -> Maybe a
    maybeReadFuzzy String
    str = case ReadS a
    forall a. Read a => ReadS a
    reads String
    str of
      [(a
    x, String
    s)] | (Char -> Bool) -> String -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    all Char -> Bool
    isSpace String
    s -> a -> Maybe a
    forall a. a -> Maybe a
    Just a
    x
      [(a, String)]
    _ -> Maybe a
    forall a. Maybe a
    Nothing

    -- Note [Settings file]
    -- ~~~~~~~~~~~~~~~~~~~~
    --
    -- GHC has a file, `${top_dir}/settings`, which is the main source of run-time
    -- configuration. ghc-pkg needs just a little bit of it: the target platform CPU
    -- arch and OS. It uses that to figure out what subdirectory of `~/.ghc` is
    -- associated with the current version/target platform.
    --
    -- This module has just enough code to read key value pairs from the settings
    -- file, and read the target platform from those pairs.

    type RawSettings = Map String String

    -- | Read target Arch/OS from the settings
    getTargetArchOS
      :: FilePath     -- ^ Settings filepath (for error messages)
      -> RawSettings  -- ^ Raw settings file contents
      -> Either String ArchOS
    getTargetArchOS :: String -> RawSettings -> Either String ArchOS
    getTargetArchOS String
    settingsFile RawSettings
    settings =
      Arch -> OS -> ArchOS
    ArchOS (Arch -> OS -> ArchOS)
    -> Either String Arch -> Either String (OS -> ArchOS)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> RawSettings -> String -> Either String Arch
    forall a.
    (Show a, Read a) =>
    String -> RawSettings -> String -> Either String a
    readRawSetting String
    settingsFile RawSettings
    settings String
    "target arch"
             Either String (OS -> ArchOS)
    -> Either String OS -> Either String ArchOS
    forall a b.
    Either String (a -> b) -> Either String a -> Either String b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> String -> RawSettings -> String -> Either String OS
    forall a.
    (Show a, Read a) =>
    String -> RawSettings -> String -> Either String a
    readRawSetting String
    settingsFile RawSettings
    settings String
    "target os"

    getGlobalPackageDb :: FilePath -> RawSettings -> Either String FilePath
    getGlobalPackageDb :: String -> RawSettings -> Either String String
    getGlobalPackageDb String
    settingsFile RawSettings
    settings = do
      rel_db <- String -> RawSettings -> String -> Either String String
    getRawSetting String
    settingsFile RawSettings
    settings String
    "Relative Global Package DB"
      return (dropFileName settingsFile </> rel_db)

    getRawSetting
      :: FilePath -> RawSettings -> String -> Either String String
    getRawSetting :: String -> RawSettings -> String -> Either String String
    getRawSetting String
    settingsFile RawSettings
    settings String
    key = case String -> RawSettings -> Maybe String
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup String
    key RawSettings
    settings of
      Just String
    xs -> String -> Either String String
    forall a b. b -> Either a b
    Right String
    xs
      Maybe String
    Nothing -> String -> Either String String
    forall a b. a -> Either a b
    Left (String -> Either String String) -> String -> Either String String
    forall a b. (a -> b) -> a -> b
    $ String
    "No entry for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    key String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " in " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    settingsFile

    getRawFilePathSetting
      :: FilePath -> FilePath -> RawSettings -> String -> Either String String
    getRawFilePathSetting :: String -> String -> RawSettings -> String -> Either String String
    getRawFilePathSetting String
    top_dir String
    settingsFile RawSettings
    settings String
    key =
      String -> String -> String
    expandTopDir String
    top_dir (String -> String) -> Either String String -> Either String String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> RawSettings -> String -> Either String String
    getRawSetting String
    settingsFile RawSettings
    settings String
    key

    getRawBooleanSetting
      :: FilePath -> RawSettings -> String -> Either String Bool
    getRawBooleanSetting :: String -> RawSettings -> String -> Either String Bool
    getRawBooleanSetting String
    settingsFile RawSettings
    settings String
    key = do
      rawValue <- String -> RawSettings -> String -> Either String String
    getRawSetting String
    settingsFile RawSettings
    settings String
    key
      case rawValue of
        String
    "YES" -> Bool -> Either String Bool
    forall a b. b -> Either a b
    Right Bool
    True
        String
    "NO" -> Bool -> Either String Bool
    forall a b. b -> Either a b
    Right Bool
    False
        String
    xs -> String -> Either String Bool
    forall a b. a -> Either a b
    Left (String -> Either String Bool) -> String -> Either String Bool
    forall a b. (a -> b) -> a -> b
    $ String
    "Bad value for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    key String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ": " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    xs

    readRawSetting
      :: (Show a, Read a) => FilePath -> RawSettings -> String -> Either String a
    readRawSetting :: forall a.
    (Show a, Read a) =>
    String -> RawSettings -> String -> Either String a
    readRawSetting String
    settingsFile RawSettings
    settings String
    key = case String -> RawSettings -> Maybe String
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup String
    key RawSettings
    settings of
      Just String
    xs -> case String -> Maybe a
    forall a. Read a => String -> Maybe a
    maybeRead String
    xs of
        Just a
    v -> a -> Either String a
    forall a b. b -> Either a b
    Right a
    v
        Maybe a
    Nothing -> String -> Either String a
    forall a b. a -> Either a b
    Left (String -> Either String a) -> String -> Either String a
    forall a b. (a -> b) -> a -> b
    $ String
    "Failed to read " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    key String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " value " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    xs
      Maybe String
    Nothing -> String -> Either String a
    forall a b. a -> Either a b
    Left (String -> Either String a) -> String -> Either String a
    forall a b. (a -> b) -> a -> b
    $ String
    "No entry for " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    key String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    " in " String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String -> String
    forall a. Show a => a -> String
    show String
    settingsFile