    {-# LINE 1 "libraries/base/System/Environment/Blank.hsc" #-}
    {-# LANGUAGE Safe #-}
    {-# LANGUAGE CPP #-}
    {-# LANGUAGE CApiFFI #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.Environment.Blank
    -- Copyright   :  (c) Habib Alamin 2017
    -- License     :  BSD-style (see the file libraries/base/LICENSE)
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- A setEnv implementation that allows blank environment variables. Mimics
    -- the `System.Posix.Env` module from the @unix@ package, but with support
    -- for Windows too.
    --
    -- The matrix of platforms that:
    --
    --   * support @putenv("FOO")@ to unset environment variables,
    --   * support @putenv("FOO=")@ to unset environment variables or set them
    --     to blank values,
    --   * support @unsetenv@ to unset environment variables,
    --   * support @setenv@ to set environment variables,
    --   * etc.
    --
    -- is very complicated. Some platforms don't support unsetting of environment
    -- variables at all.
    --
    -----------------------------------------------------------------------------

    module System.Environment.Blank
        (
          module System.Environment,
          getEnv,
          getEnvDefault,
          setEnv,
          unsetEnv,
      ) where

    import Foreign.C

    {-# LINE 48 "libraries/base/System/Environment/Blank.hsc" #-}
    import System.Posix.Internals

    {-# LINE 50 "libraries/base/System/Environment/Blank.hsc" #-}
    import GHC.IO.Exception
    import System.IO.Error
    import Control.Exception.Base
    import Data.Maybe

    import System.Environment
        (
          getArgs,
          getProgName,
          getExecutablePath,
          withArgs,
          withProgName,
          getEnvironment
      )

    {-# LINE 65 "libraries/base/System/Environment/Blank.hsc" #-}
    import qualified System.Environment as Environment

    {-# LINE 67 "libraries/base/System/Environment/Blank.hsc" #-}

    -- TODO: include windows_cconv.h when it's merged, instead of duplicating
    -- this C macro block.

    {-# LINE 79 "libraries/base/System/Environment/Blank.hsc" #-}

    throwInvalidArgument :: String -> IO a
    throwInvalidArgument :: forall a. String -> IO a
    throwInvalidArgument String
    from =
      IOError -> IO a
    forall e a. Exception e => e -> IO a
    throwIO (IOErrorType -> String -> Maybe Handle -> Maybe String -> IOError
    mkIOError IOErrorType
    InvalidArgument String
    from Maybe Handle
    forall a. Maybe a
    Nothing Maybe String
    forall a. Maybe a
    Nothing)

    -- | Similar to 'System.Environment.lookupEnv'.
    getEnv :: String -> IO (Maybe String)

    {-# LINE 91 "libraries/base/System/Environment/Blank.hsc" #-}
    getEnv :: String -> IO (Maybe String)
    getEnv = String -> IO (Maybe String)
    Environment.lookupEnv

    {-# LINE 93 "libraries/base/System/Environment/Blank.hsc" #-}

    -- | Get an environment value or a default value.
    getEnvDefault ::
      String    {- ^ variable name                    -} ->
      String    {- ^ fallback value                   -} ->
      IO String {- ^ variable value or fallback value -}
    getEnvDefault :: String -> String -> IO String
    getEnvDefault String
    name String
    fallback = String -> Maybe String -> String
    forall a. a -> Maybe a -> a
    fromMaybe String
    fallback (Maybe String -> String) -> IO (Maybe String) -> IO String
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> String -> IO (Maybe String)
    getEnv String
    name

    -- | Like 'System.Environment.setEnv', but allows blank environment values
    -- and mimics the function signature of 'System.Posix.Env.setEnv' from the
    -- @unix@ package.
    setEnv ::
      String {- ^ variable name  -} ->
      String {- ^ variable value -} ->
      Bool   {- ^ overwrite      -} ->
      IO ()
    setEnv :: String -> String -> Bool -> IO ()
    setEnv String
    key_ String
    value_ Bool
    overwrite
      | String -> Bool
    forall a. [a] -> Bool
    forall (t :: * -> *) a. Foldable t => t a -> Bool
    null String
    key       = String -> IO ()
    forall a. String -> IO a
    throwInvalidArgument String
    "setEnv"
      | Char
    '=' Char -> String -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` String
    key = String -> IO ()
    forall a. String -> IO a
    throwInvalidArgument String
    "setEnv"
      | Bool
    otherwise      =
        if Bool
    overwrite
        then String -> String -> IO ()
    setEnv_ String
    key String
    value
        else do
          Maybe String
    env_var <- String -> IO (Maybe String)
    getEnv String
    key
          case Maybe String
    env_var of
              Just String
    _  -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
              Maybe String
    Nothing -> String -> String -> IO ()
    setEnv_ String
    key String
    value
      where
        key :: String
    key   = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    takeWhile (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Char
    '\NUL') String
    key_
        value :: String
    value = (Char -> Bool) -> String -> String
    forall a. (a -> Bool) -> [a] -> [a]
    takeWhile (Char -> Char -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Char
    '\NUL') String
    value_

    setEnv_ :: String -> String -> IO ()

    {-# LINE 133 "libraries/base/System/Environment/Blank.hsc" #-}
    setEnv_ :: String -> String -> IO ()
    setEnv_ String
    key String
    value =
      String -> (CString -> IO ()) -> IO ()
    forall a. String -> (CString -> IO a) -> IO a
    withFilePath String
    key ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \ CString
    keyP ->
        String -> (CString -> IO ()) -> IO ()
    forall a. String -> (CString -> IO a) -> IO a
    withFilePath String
    value ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \ CString
    valueP ->
          String -> IO CInt -> IO ()
    forall a. (Eq a, Num a) => String -> IO a -> IO ()
    throwErrnoIfMinus1_ String
    "setenv" (IO CInt -> IO ()) -> IO CInt -> IO ()
    forall a b. (a -> b) -> a -> b
    $
            CString -> CString -> CInt -> IO CInt
    c_setenv CString
    keyP CString
    valueP (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Bool -> Int
    forall a. Enum a => a -> Int
    fromEnum Bool
    True))

    foreign import ccall unsafe "setenv"
       c_setenv :: CString -> CString -> CInt -> IO CInt

    {-# LINE 142 "libraries/base/System/Environment/Blank.hsc" #-}

    -- | Like 'System.Environment.unsetEnv', but allows for the removal of
    -- blank environment variables. May throw an exception if the underlying
    -- platform doesn't support unsetting of environment variables.
    unsetEnv :: String -> IO ()

    {-# LINE 163 "libraries/base/System/Environment/Blank.hsc" #-}

    unsetEnv :: String -> IO ()
    {-# LINE 164 "libraries/base/System/Environment/Blank.hsc" #-}
    unsetEnv name = withFilePath name $ \ s ->
      throwErrnoIfMinus1_ "unsetenv" (c_unsetenv s)

    -- POSIX.1-2001 compliant unsetenv(3)
    foreign import capi unsafe "HsBase.h unsetenv"
       c_unsetenv :: CString -> IO CInt

    {-# LINE 177 "libraries/base/System/Environment/Blank.hsc" #-}

    {-# LINE 194 "libraries/base/System/Environment/Blank.hsc" #-}