setenv (empty) → 0.1.0
raw patch · 5 files changed
+155/−0 lines, 5 filesdep +QuickCheckdep +basedep +hspecsetup-changed
Dependencies added: QuickCheck, base, hspec, setenv, unix
Files
- LICENSE +19/−0
- Setup.lhs +3/−0
- setenv.cabal +43/−0
- src/System/SetEnv.hs +89/−0
- test/Spec.hs +1/−0
+ LICENSE view
@@ -0,0 +1,19 @@+Copyright (c) 2012 Simon Hengel <sol@typeful.net>++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in+all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN+THE SOFTWARE.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ setenv.cabal view
@@ -0,0 +1,43 @@+name: setenv+version: 0.1.0+license: MIT+license-file: LICENSE+copyright: (c) 2012 Simon Hengel+author: Simon Hengel <sol@typeful.net>+maintainer: Simon Hengel <sol@typeful.net>+category: System+synopsis: A cross-platform library for setting environment variables+description: A cross-platform library for setting environment variables+build-type: Simple+cabal-version: >= 1.8++source-repository head+ type: git+ location: https://github.com/sol/setenv++library+ ghc-options:+ -Wall+ hs-source-dirs:+ src+ exposed-modules:+ System.SetEnv+ build-depends:+ base == 4.*+ if !os(windows)+ build-depends: unix++test-suite spec+ type:+ exitcode-stdio-1.0+ ghc-options:+ -Wall -Werror+ hs-source-dirs:+ test+ main-is:+ Spec.hs+ build-depends:+ base+ , setenv+ , hspec >= 1.3+ , QuickCheck
+ src/System/SetEnv.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+module System.SetEnv (+ setEnv+, unsetEnv+) where++#ifdef mingw32_HOST_OS+import GHC.Windows+import Foreign.Safe+import Foreign.C+import Control.Monad+#else+import qualified System.Posix.Env as Posix+#endif++#ifdef mingw32_HOST_OS+# if defined(i386_HOST_ARCH)+# define WINDOWS_CCONV stdcall+# elif defined(x86_64_HOST_ARCH)+# define WINDOWS_CCONV ccall+# else+# error Unknown mingw32 arch+# endif++foreign import WINDOWS_CCONV unsafe "windows.h GetLastError"+ c_GetLastError:: IO DWORD++eRROR_ENVVAR_NOT_FOUND :: DWORD+eRROR_ENVVAR_NOT_FOUND = 203++#endif++-- | @setEnv name value@ sets the specified environment variable to @value@.+--+-- If @value@ is the empty string, the specified environment variable is+-- removed from the environment.+--+-- Throws `Control.Exception.IOException` if @name@ is the empty string or+-- contains an equals character.+setEnv :: String -> String -> IO ()+setEnv key value_+ | null value = unsetEnv key+ | otherwise = setEnv_ key value+ where+ -- NOTE: Anything that follows NUL is ignored on both POSIX and Windows.+ -- We still strip it manually so that the null check above succeds if a+ -- value starts with NUL, and `unsetEnv` is called. This is important for+ -- two reasons.+ --+ -- * On POSIX setting an environment variable to the empty string does not+ -- remove it.+ --+ -- * On Windows setting an environment variable to the empty string+ -- removes that environment variable. A subsequent call to+ -- GetEnvironmentVariable will then return 0, but GetLastError will not+ -- be updates, and hence may not return ERROR_ENVVAR_NOT_FOUND. This is+ -- at least true for observed this behavior with Windows XP SP 3.+ value = takeWhile (/= '\NUL') value_++setEnv_ :: String -> String -> IO ()+#ifdef mingw32_HOST_OS+setEnv_ key value = withCWString key $ \k -> withCWString value $ \v -> do+ success <- c_SetEnvironmentVariable k v+ unless success (throwGetLastError "setEnv")++foreign import WINDOWS_CCONV unsafe "windows.h SetEnvironmentVariableW"+ c_SetEnvironmentVariable :: LPTSTR -> LPTSTR -> IO Bool+#else+setEnv_ k v = Posix.setEnv k v True+#endif++-- | @unSet name@ removes the specified environment variable from the+-- environment of the current process.+--+-- Throws `Control.Exception.IOException` if @name@ is the empty string or+-- contains an equals character.+unsetEnv :: String -> IO ()+#ifdef mingw32_HOST_OS+unsetEnv key = withCWString key $ \k -> do+ success <- c_SetEnvironmentVariable k nullPtr+ unless success $ do+ -- We consider unsetting an environment variable that does not exist not as+ -- an error, hence we ignore eRROR_ENVVAR_NOT_FOUND.+ err <- c_GetLastError+ unless (err == eRROR_ENVVAR_NOT_FOUND) $ do+ throwGetLastError "unsetEnv"+#else+unsetEnv = Posix.unsetEnv+#endif
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}