-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
env.jl
156 lines (133 loc) · 4.89 KB
/
env.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# This file is a part of Julia. License is MIT: http://julialang.org/license
if is_windows()
const ERROR_ENVVAR_NOT_FOUND = UInt32(203)
_getenvlen(var::Vector{UInt16}) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,C_NULL,0)
_hasenv(s::Vector{UInt16}) = _getenvlen(s) != 0 || Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND
_hasenv(s::AbstractString) = _hasenv(cwstring(s))
function access_env(onError::Function, str::AbstractString)
var = cwstring(str)
len = _getenvlen(var)
if len == 0
return Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND ? "" : onError(str)
end
val = zeros(UInt16,len)
ret = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,val,len)
if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0
error(string("getenv: ", str, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage()))
end
pop!(val) # NUL
return transcode(String, val)
end
function _setenv(svar::AbstractString, sval::AbstractString, overwrite::Bool=true)
var = cwstring(svar)
val = cwstring(sval)
if overwrite || !_hasenv(var)
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,val)
systemerror(:setenv, ret == 0)
end
end
function _unsetenv(svar::AbstractString)
var = cwstring(svar)
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL)
systemerror(:setenv, ret == 0)
end
else # !windows
_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var)
_hasenv(s::AbstractString) = _getenv(s) != C_NULL
function access_env(onError::Function, var::AbstractString)
val = _getenv(var)
val == C_NULL ? onError(var) : unsafe_string(val)
end
function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true)
ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite)
systemerror(:setenv, ret != 0)
end
function _unsetenv(var::AbstractString)
ret = ccall(:unsetenv, Int32, (Cstring,), var)
systemerror(:unsetenv, ret != 0)
end
end # os test
## ENV: hash interface ##
type EnvHash <: Associative{String,String}; end
"""
ENV
Reference to the singleton `EnvHash`, providing a dictionary interface to system environment
variables.
"""
const ENV = EnvHash()
similar(::EnvHash) = Dict{String,String}()
getindex(::EnvHash, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
get(::EnvHash, k::AbstractString, def) = access_env(k->def, k)
in(k::AbstractString, ::KeyIterator{EnvHash}) = _hasenv(k)
pop!(::EnvHash, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v)
pop!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def
delete!(::EnvHash, k::AbstractString) = (_unsetenv(k); ENV)
delete!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? delete!(ENV,k) : def
setindex!(::EnvHash, v, k::AbstractString) = _setenv(k,string(v))
push!(::EnvHash, k::AbstractString, v) = setindex!(ENV, v, k)
if is_windows()
start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos))
function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}})
if unsafe_load(block[1]) == 0
ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2])
return true
end
return false
end
function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}})
pos = block[1]
blk = block[2]
len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos)
buf = Array{UInt16}(len)
unsafe_copy!(pointer(buf), pos, len)
env = transcode(String, buf)
m = match(r"^(=?[^=]+)=(.*)$"s, env)
if m === nothing
error("malformed environment entry: $env")
end
return (Pair{String,String}(m.captures[1], m.captures[2]), (pos+len*2, blk))
end
else # !windows
start(::EnvHash) = 0
done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing)
function next(::EnvHash, i)
env = ccall(:jl_environ, Any, (Int32,), i)
if env === nothing
throw(BoundsError())
end
env = env::String
m = match(r"^(.*?)=(.*)$"s, env)
if m === nothing
error("malformed environment entry: $env")
end
return (Pair{String,String}(m.captures[1], m.captures[2]), i+1)
end
end # os-test
#TODO: Make these more efficent
function length(::EnvHash)
i = 0
for (k,v) in ENV
i += 1
end
return i
end
function show(io::IO, ::EnvHash)
for (k,v) = ENV
println(io, "$k=$v")
end
end
# temporarily set and then restore an environment value
function withenv{T<:AbstractString}(f::Function, keyvals::Pair{T}...)
old = Dict{T,Any}()
for (key,val) in keyvals
old[key] = get(ENV,key,nothing)
val !== nothing ? (ENV[key]=val) : delete!(ENV, key)
end
try f()
finally
for (key,val) in old
val !== nothing ? (ENV[key]=val) : delete!(ENV, key)
end
end
end
withenv(f::Function) = f() # handle empty keyvals case; see #10853