/
githubmirror
/
julia
Обзор
Документация
Войти
/
githubmirror
/
julia
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
base/env.jl
290 строк
10 KB
Shuhei Kadowaki
Base: Remove dead stores and unused bindings flagged by JETLS (#62534)
28 июл 2026, 15:03
Не верифицирован
28 июл 2026, 15:03
8ddf7d8
Код
Авторство
О чём код?
# This file is a part of Julia. License is MIT: https://julialang.org/license if Sys.iswindows() const ERROR_ENVVAR_NOT_FOUND = UInt32(203) const env_dict = Lockable(Dict{String, Vector{Cwchar_t}}()) function memoized_env_lookup(str::AbstractString) # Windows environment variables have a different format from Linux / MacOS, and previously # incurred allocations because we had to convert a String to a Vector{Cwchar_t} each time # an environment variable was looked up. This function memoizes that lookup process, storing # the String => Vector{Cwchar_t} pairs in env_dict @lock env_dict begin var = get(env_dict[], str, nothing) if isnothing(var) var = cwstring(str) env_dict[][str] = var end return var end end _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(memoized_env_lookup(s)) function access_env(onError::Function, str::AbstractString) var = memoized_env_lookup(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) windowserror(:getenv, (ret == 0 && len != 1) || ret != len-1 || val[end] != 0) pop!(val) # NUL return transcode(String, val) end function _setenv(svar::AbstractString, sval::AbstractString, overwrite::Bool=true) var = memoized_env_lookup(svar) val = cwstring(sval) if overwrite || !_hasenv(var) ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,val) windowserror(:setenv, ret == 0) end end function _unsetenv(svar::AbstractString) var = memoized_env_lookup(svar) ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL) windowserror(:setenv, ret == 0 && Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND) end else # !windows _getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) _hasenv(s::AbstractString) = _getenv(s) != C_NULL if Sys.isapple() _environ() = unsafe_load(ccall(:_NSGetEnviron, Ptr{Ptr{Cstring}}, ())) else const _environ_ptr = Base.OncePerProcess{Ptr{Ptr{Cstring}}}() do # Look up `environ` in the main executable, since if Julia is loaded # via RTLD_DEEPBIND this may resolve to NULL in our own namespace. # (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111413) executable_handle = ccall(:jl_dlopen, Ptr{Cvoid}, (Ptr{Cchar}, Cint), C_NULL, Libc.Libdl.RTLD_LAZY) return Ptr{Ptr{Cstring}}(Libc.Libdl.dlsym(executable_handle, :environ)) end _environ() = unsafe_load(_environ_ptr()) end 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 ## """ EnvDict()::EnvDict A singleton of this type provides a hash table interface to environment variables. """ struct EnvDict <: AbstractDict{String,String}; end """ ENV Reference to the singleton `EnvDict`, providing a dictionary interface to system environment variables. (On Windows, system environment variables are case-insensitive, and `ENV` correspondingly converts all keys to uppercase for display, iteration, and copying. Portable code should not rely on the ability to distinguish variables by case, and should beware that setting an ostensibly lowercase variable may result in an uppercase `ENV` key.) !!! warning Mutating the environment is not thread-safe. # Examples ```julia-repl julia> ENV Base.EnvDict with "50" entries: "SECURITYSESSIONID" => "123" "USER" => "username" "MallocNanoZone" => "0" ⋮ => ⋮ julia> ENV["JULIA_EDITOR"] = "vim" "vim" julia> ENV["JULIA_EDITOR"] "vim" ``` See also: [`withenv`](@ref), [`addenv`](@ref). """ const ENV = EnvDict() const get_bool_env_truthy = ( "t", "T", "true", "True", "TRUE", "y", "Y", "yes", "Yes", "YES", "1") const get_bool_env_falsy = ( "f", "F", "false", "False", "FALSE", "n", "N", "no", "No", "NO", "0") """ Base.get_bool_env(name::String, default::Bool; throw=false)::Union{Bool,Nothing} Base.get_bool_env(f_default::Callable, name::String; throw=false)::Union{Bool,Nothing} Evaluate whether the value of environment variable `name` is a truthy or falsy string, and return `nothing` (or throw if `throw=true`) if it is not recognized as either. If the variable is not set, or is set to "", return `default` or the result of executing `f_default()`. Recognized values are the following, and their Capitalized and UPPERCASE forms: truthy: "t", "true", "y", "yes", "1" falsy: "f", "false", "n", "no", "0" """ get_bool_env(name::String, default::Bool; kwargs...) = get_bool_env(Returns(default), name; kwargs...) function get_bool_env(f_default::Callable, name::String; kwargs...) if haskey(ENV, name) val = ENV[name] if !isempty(val) return parse_bool_env(name, val; kwargs...) end end return f_default() end function parse_bool_env(name::String, val::String = ENV[name]; throw::Bool=false) if val in get_bool_env_truthy return true elseif val in get_bool_env_falsy return false elseif throw Base.throw(ArgumentError("Value for environment variable `$name` could not be parsed as Boolean: $(repr(val))")) else return nothing end end getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k) get(::EnvDict, k::AbstractString, def) = access_env(Returns(def), k) get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k) function get!(default::Callable, ::EnvDict, k::AbstractString) haskey(ENV, k) && return ENV[k] ENV[k] = default() end in(k::AbstractString, ::KeySet{String, EnvDict}) = _hasenv(k) pop!(::EnvDict, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v) pop!(::EnvDict, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def delete!(::EnvDict, k::AbstractString) = (_unsetenv(k); ENV) setindex!(::EnvDict, v, k::AbstractString) = _setenv(k,string(v)) push!(::EnvDict, kv::Pair{<:AbstractString}) = setindex!(ENV, kv.second, kv.first) if Sys.iswindows() GESW() = (pos = ccall(:GetEnvironmentStringsW, stdcall, Ptr{UInt16}, ()); (pos, pos)) function winuppercase(s::AbstractString) isempty(s) && return s LOCALE_INVARIANT = 0x0000007f LCMAP_UPPERCASE = 0x00000200 ws = transcode(UInt16, String(s)) result = ccall(:LCMapStringW, stdcall, Cint, (UInt32, UInt32, Ptr{UInt16}, Cint, Ptr{UInt16}, Cint), LOCALE_INVARIANT, LCMAP_UPPERCASE, ws, length(ws), ws, length(ws)) systemerror(:LCMapStringW, iszero(result)) return transcode(String, ws) end function iterate(hash::EnvDict, block::Tuple{Ptr{UInt16},Ptr{UInt16}} = GESW()) while true if unsafe_load(block[1]) == 0 ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2]) return nothing end pos = block[1] blk = block[2] len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos) buf = Vector{UInt16}(undef, len) GC.@preserve buf unsafe_copyto!(pointer(buf), pos, len) env = transcode(String, buf) pos += (len + 1) * 2 if !isempty(env) m = findnext('=', env, nextind(env, firstindex(env))) else m = nothing end if m === nothing @warn "malformed environment entry" env continue end return (Pair{String,String}(winuppercase(env[1:prevind(env, m)]), env[nextind(env, m):end]), (pos, blk)) end end else # !windows function iterate(::EnvDict, i=0) envs = _environ() envs == C_NULL && error("Failed to resolve `environ`.") while true envp = unsafe_load(envs, i + 1) envp == C_NULL && return nothing env = unsafe_string(envp) i += 1 m = findfirst('=', env) if m === nothing @warn "malformed environment entry" env continue end return (Pair{String,String}(env[1:prevind(env, m)], env[nextind(env, m):end]), i) end end end # os-test #TODO: Make these more efficient function length(::EnvDict) i = 0 for _ in ENV i += 1 end return i end function show(io::IO, ::EnvDict) for (k,v) = ENV println(io, "$k=$v") end end """ withenv(f, kv::Pair...) Execute `f` in an environment that is temporarily modified (not replaced as in `setenv`) by zero or more `"var"=>val` arguments `kv`. `withenv` is generally used via the `withenv(kv...) do ... end` syntax. A value of `nothing` can be used to temporarily unset an environment variable (if it is set). When `withenv` returns, the original environment has been restored. !!! warning Changing the environment is not thread-safe. For running external commands with a different environment from the parent process, prefer using [`addenv`](@ref) over `withenv`. """ function withenv(f, keyvals::Pair{T}...) where T<:AbstractString 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) = f() # handle empty keyvals case; see #10853