{-# 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  :  [email protected]
-- 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. I think AIX is screwed, but we don't support it.
-- The whole situation with setenv(3), unsetenv(3), and putenv(3) is not
-- good. Even mingw32 adds its own crap to the pile, but luckily, we can
-- just use Windows' native environment functions to sidestep the issue.
--
-- #12494
--
-----------------------------------------------------------------------------

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

import Foreign.C

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

{-# LINE 54 "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 69 "libraries/base/System/Environment/Blank.hsc" #-}
import qualified System.Environment as Environment

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

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

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



throwInvalidArgument :: String -> IO a
throwInvalidArgument from =
  throwIO (mkIOError InvalidArgument from Nothing Nothing)

-- | `System.Environment.lookupEnv`.
getEnv :: String -> IO (Maybe String)

{-# LINE 95 "libraries/base/System/Environment/Blank.hsc" #-}
getEnv = Environment.lookupEnv

{-# LINE 97 "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 name fallback = fromMaybe fallback <$> getEnv 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 key_ value_ overwrite
  | null key       = throwInvalidArgument "setEnv"
  | '=' `elem` key = throwInvalidArgument "setEnv"
  | otherwise      =
    if overwrite
    then setEnv_ key value
    else do
      env_var <- getEnv key
      case env_var of
          Just _  -> return ()
          Nothing -> setEnv_ key value
  where
    key   = takeWhile (/= '\NUL') key_
    value = takeWhile (/= '\NUL') value_

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

{-# LINE 137 "libraries/base/System/Environment/Blank.hsc" #-}
setEnv_ key value =
  withFilePath key $ \ keyP ->
    withFilePath value $ \ valueP ->
      throwErrnoIfMinus1_ "setenv" $
        c_setenv keyP valueP (fromIntegral (fromEnum True))

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

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

-- | Like `System.Environment.unsetEnv`, but allows for the removal of
-- blank environment variables.
unsetEnv :: String -> IO ()

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

{-# LINE 167 "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 180 "libraries/base/System/Environment/Blank.hsc" #-}

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