{-# LINE 1 "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 "System/Environment/Blank.hsc" #-}
import System.Posix.Internals

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

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

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

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



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

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

{-# LINE 91 "System/Environment/Blank.hsc" #-}
getEnv = Environment.lookupEnv

{-# LINE 93 "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 133 "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 142 "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 "System/Environment/Blank.hsc" #-}

{-# LINE 164 "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 "System/Environment/Blank.hsc" #-}

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