Skip to content

Commit 707737c

Browse files
committed
Synchronize ByteString and String modules
And fix free-bug in 'putEnv'. Fixes haskell#68
1 parent d2fe3cd commit 707737c

File tree

1 file changed

+33
-5
lines changed

1 file changed

+33
-5
lines changed

System/Posix/Env/ByteString.hsc

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{-# LANGUAGE CApiFFI #-}
2-
{-# LANGUAGE Safe #-}
2+
{-# LANGUAGE Trustworthy #-}
33

44
-----------------------------------------------------------------------------
55
-- |
@@ -21,23 +21,29 @@ module System.Posix.Env.ByteString (
2121
, getEnvDefault
2222
, getEnvironmentPrim
2323
, getEnvironment
24+
, setEnvironment
2425
, putEnv
2526
, setEnv
26-
, unsetEnv
27+
, unsetEnv
28+
, clearEnv
2729

2830
-- * Program arguments
2931
, getArgs
3032
) where
3133

3234
#include "HsUnix.h"
3335

36+
import Control.Monad
3437
import Foreign
3538
import Foreign.C
3639
import Data.Maybe ( fromMaybe )
3740

41+
import System.Posix.Env ( clearEnv )
3842
import qualified Data.ByteString as B
3943
import qualified Data.ByteString.Char8 as BC
4044
import Data.ByteString (ByteString)
45+
import Data.ByteString.Internal (ByteString (PS), memcpy)
46+
import Foreign.ForeignPtr.Unsafe(unsafeForeignPtrToPtr)
4147

4248
-- |'getEnv' looks up a variable in the environment.
4349

@@ -96,6 +102,18 @@ getEnvironment = do
96102
| BC.head y == '=' = (x,B.tail y)
97103
| otherwise = error $ "getEnvironment: insane variable " ++ BC.unpack x
98104

105+
-- |'setEnvironment' resets the entire environment to the given list of
106+
-- @(key,value)@ pairs.
107+
--
108+
-- @since 2.8.0.0
109+
setEnvironment ::
110+
[(ByteString,ByteString)] {- ^ @[(key,value)]@ -} ->
111+
IO ()
112+
setEnvironment env = do
113+
clearEnv
114+
forM_ env $ \(key,value) ->
115+
setEnv key value True {-overwrite-}
116+
99117
-- |The 'unsetEnv' function deletes all instances of the variable name
100118
-- from the environment.
101119

@@ -116,15 +134,25 @@ foreign import capi unsafe "HsUnix.h unsetenv"
116134
c_unsetenv :: CString -> IO ()
117135
# endif
118136
#else
119-
unsetEnv name = putEnv (name ++ "=")
137+
unsetEnv name = putEnv (name <> BC.pack "=")
120138
#endif
121139

122140
-- |'putEnv' function takes an argument of the form @name=value@
123141
-- and is equivalent to @setEnv(key,value,True{-overwrite-})@.
124142

125143
putEnv :: ByteString {- ^ "key=value" -} -> IO ()
126-
putEnv keyvalue = B.useAsCString keyvalue $ \s ->
127-
throwErrnoIfMinus1_ "putenv" (c_putenv s)
144+
putEnv (PS fp _ l) = do
145+
-- https://pubs.opengroup.org/onlinepubs/009696899/functions/putenv.html
146+
--
147+
-- "the string pointed to by string shall become part of the environment,
148+
-- so altering the string shall change the environment. The space used by
149+
-- string is no longer used once a new string which defines name is passed to putenv()."
150+
--
151+
-- hence we must not free the buffer
152+
buf <- mallocBytes (l+1)
153+
memcpy buf (unsafeForeignPtrToPtr fp) l
154+
pokeByteOff buf l (0::Word8)
155+
throwErrnoIfMinus1_ "putenv" (c_putenv (castPtr buf))
128156

129157
foreign import ccall unsafe "putenv"
130158
c_putenv :: CString -> IO CInt

0 commit comments

Comments
 (0)