123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- # Include file that implements 'getEnv' and friends. Do not import it!
- when not declared(os) and not declared(ospaths):
- {.error: "This is an include file for os.nim!".}
- from parseutils import skipIgnoreCase
- proc c_getenv(env: cstring): cstring {.
- importc: "getenv", header: "<stdlib.h>".}
- proc c_putenv(env: cstring): cint {.
- importc: "putenv", header: "<stdlib.h>".}
- proc c_unsetenv(env: cstring): cint {.
- importc: "unsetenv", header: "<stdlib.h>".}
- # Environment handling cannot be put into RTL, because the ``envPairs``
- # iterator depends on ``environment``.
- var
- envComputed {.threadvar.}: bool
- environment {.threadvar.}: seq[string]
- when defined(nimV2):
- proc unpairedEnvAllocs*(): int =
- result = environment.len
- if result > 0: inc result
- when defined(windows) and not defined(nimscript):
- # because we support Windows GUI applications, things get really
- # messy here...
- when useWinUnicode:
- when defined(cpp):
- proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
- importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
- else:
- proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
- importc: "wcschr", header: "<string.h>".}
- else:
- proc strEnd(cstr: cstring, c = 0'i32): cstring {.
- importc: "strchr", header: "<string.h>".}
- proc getEnvVarsC() =
- if not envComputed:
- environment = @[]
- when useWinUnicode:
- var
- env = getEnvironmentStringsW()
- e = env
- if e == nil: return # an error occurred
- while true:
- var eend = strEnd(e)
- add(environment, $e)
- e = cast[WideCString](cast[ByteAddress](eend)+2)
- if eend[1].int == 0: break
- discard freeEnvironmentStringsW(env)
- else:
- var
- env = getEnvironmentStringsA()
- e = env
- if e == nil: return # an error occurred
- while true:
- var eend = strEnd(e)
- add(environment, $e)
- e = cast[cstring](cast[ByteAddress](eend)+1)
- if eend[1] == '\0': break
- discard freeEnvironmentStringsA(env)
- envComputed = true
- else:
- const
- useNSGetEnviron = (defined(macosx) and not defined(ios)) or defined(nimscript)
- when useNSGetEnviron:
- # From the manual:
- # Shared libraries and bundles don't have direct access to environ,
- # which is only available to the loader ld(1) when a complete program
- # is being linked.
- # The environment routines can still be used, but if direct access to
- # environ is needed, the _NSGetEnviron() routine, defined in
- # <crt_externs.h>, can be used to retrieve the address of environ
- # at runtime.
- proc NSGetEnviron(): ptr cstringArray {.
- importc: "_NSGetEnviron", header: "<crt_externs.h>".}
- else:
- var gEnv {.importc: "environ".}: cstringArray
- proc getEnvVarsC() =
- # retrieves the variables of char** env of C's main proc
- if not envComputed:
- environment = @[]
- when useNSGetEnviron:
- var gEnv = NSGetEnviron()[]
- var i = 0
- while true:
- if gEnv[i] == nil: break
- add environment, $gEnv[i]
- inc(i)
- envComputed = true
- proc findEnvVar(key: string): int =
- getEnvVarsC()
- var temp = key & '='
- for i in 0..high(environment):
- when defined(windows):
- if skipIgnoreCase(environment[i], temp) == len(temp): return i
- else:
- if startsWith(environment[i], temp): return i
- return -1
- proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} =
- ## Returns the value of the `environment variable`:idx: named `key`.
- ##
- ## If the variable does not exist, `""` is returned. To distinguish
- ## whether a variable exists or it's value is just `""`, call
- ## `existsEnv(key) proc <#existsEnv,string>`_.
- ##
- ## See also:
- ## * `existsEnv proc <#existsEnv,string>`_
- ## * `putEnv proc <#putEnv,string,string>`_
- ## * `delEnv proc <#delEnv,string>`_
- ## * `envPairs iterator <#envPairs.i>`_
- runnableExamples:
- assert getEnv("unknownEnv") == ""
- assert getEnv("unknownEnv", "doesn't exist") == "doesn't exist"
- when nimvm:
- discard "built into the compiler"
- else:
- var i = findEnvVar(key)
- if i >= 0:
- return TaintedString(substr(environment[i], find(environment[i], '=')+1))
- else:
- var env = c_getenv(key)
- if env == nil: return TaintedString(default)
- result = TaintedString($env)
- proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
- ## Checks whether the environment variable named `key` exists.
- ## Returns true if it exists, false otherwise.
- ##
- ## See also:
- ## * `getEnv proc <#getEnv,string,string>`_
- ## * `putEnv proc <#putEnv,string,string>`_
- ## * `delEnv proc <#delEnv,string>`_
- ## * `envPairs iterator <#envPairs.i>`_
- runnableExamples:
- assert not existsEnv("unknownEnv")
- when nimvm:
- discard "built into the compiler"
- else:
- if c_getenv(key) != nil: return true
- else: return findEnvVar(key) >= 0
- proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
- ## Sets the value of the `environment variable`:idx: named `key` to `val`.
- ## If an error occurs, `OSError` is raised.
- ##
- ## See also:
- ## * `getEnv proc <#getEnv,string,string>`_
- ## * `existsEnv proc <#existsEnv,string>`_
- ## * `delEnv proc <#delEnv,string>`_
- ## * `envPairs iterator <#envPairs.i>`_
- # Note: by storing the string in the environment sequence,
- # we guarantee that we don't free the memory before the program
- # ends (this is needed for POSIX compliance). It is also needed so that
- # the process itself may access its modified environment variables!
- when nimvm:
- discard "built into the compiler"
- else:
- var indx = findEnvVar(key)
- if indx >= 0:
- environment[indx] = key & '=' & val
- else:
- add environment, (key & '=' & val)
- indx = high(environment)
- when defined(windows) and not defined(nimscript):
- when useWinUnicode:
- var k = newWideCString(key)
- var v = newWideCString(val)
- if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError())
- else:
- if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError())
- else:
- if c_putenv(environment[indx]) != 0'i32:
- raiseOSError(osLastError())
- proc delEnv*(key: string) {.tags: [WriteEnvEffect].} =
- ## Deletes the `environment variable`:idx: named `key`.
- ## If an error occurs, `OSError` is raised.
- ##
- ## See also:ven
- ## * `getEnv proc <#getEnv,string,string>`_
- ## * `existsEnv proc <#existsEnv,string>`_
- ## * `putEnv proc <#putEnv,string,string>`_
- ## * `envPairs iterator <#envPairs.i>`_
- when nimvm:
- discard "built into the compiler"
- else:
- var indx = findEnvVar(key)
- if indx < 0: return # Do nothing if the env var is not already set
- when defined(windows) and not defined(nimscript):
- when useWinUnicode:
- var k = newWideCString(key)
- if setEnvironmentVariableW(k, nil) == 0'i32: raiseOSError(osLastError())
- else:
- if setEnvironmentVariableA(key, nil) == 0'i32: raiseOSError(osLastError())
- else:
- if c_unsetenv(key) != 0'i32:
- raiseOSError(osLastError())
- environment.delete(indx)
- iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} =
- ## Iterate over all `environments variables`:idx:.
- ##
- ## In the first component of the tuple is the name of the current variable stored,
- ## in the second its value.
- ##
- ## See also:
- ## * `getEnv proc <#getEnv,string,string>`_
- ## * `existsEnv proc <#existsEnv,string>`_
- ## * `putEnv proc <#putEnv,string,string>`_
- ## * `delEnv proc <#delEnv,string>`_
- getEnvVarsC()
- for i in 0..high(environment):
- var p = find(environment[i], '=')
- yield (TaintedString(substr(environment[i], 0, p-1)),
- TaintedString(substr(environment[i], p+1)))
|