osenv.nim 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. ## Include file that implements 'getEnv' and friends. Do not import it!
  2. when not declared(ospaths):
  3. {.error: "This is an include file for ospaths.nim!".}
  4. proc c_getenv(env: cstring): cstring {.
  5. importc: "getenv", header: "<stdlib.h>".}
  6. proc c_putenv(env: cstring): cint {.
  7. importc: "putenv", header: "<stdlib.h>".}
  8. # Environment handling cannot be put into RTL, because the ``envPairs``
  9. # iterator depends on ``environment``.
  10. var
  11. envComputed {.threadvar.}: bool
  12. environment {.threadvar.}: seq[string]
  13. when defined(windows) and not defined(nimscript):
  14. # because we support Windows GUI applications, things get really
  15. # messy here...
  16. when useWinUnicode:
  17. when defined(cpp):
  18. proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
  19. importcpp: "(NI16*)wcschr((const wchar_t *)#, #)", header: "<string.h>".}
  20. else:
  21. proc strEnd(cstr: WideCString, c = 0'i32): WideCString {.
  22. importc: "wcschr", header: "<string.h>".}
  23. else:
  24. proc strEnd(cstr: cstring, c = 0'i32): cstring {.
  25. importc: "strchr", header: "<string.h>".}
  26. proc getEnvVarsC() =
  27. if not envComputed:
  28. environment = @[]
  29. when useWinUnicode:
  30. var
  31. env = getEnvironmentStringsW()
  32. e = env
  33. if e == nil: return # an error occurred
  34. while true:
  35. var eend = strEnd(e)
  36. add(environment, $e)
  37. e = cast[WideCString](cast[ByteAddress](eend)+2)
  38. if eend[1].int == 0: break
  39. discard freeEnvironmentStringsW(env)
  40. else:
  41. var
  42. env = getEnvironmentStringsA()
  43. e = env
  44. if e == nil: return # an error occurred
  45. while true:
  46. var eend = strEnd(e)
  47. add(environment, $e)
  48. e = cast[cstring](cast[ByteAddress](eend)+1)
  49. if eend[1] == '\0': break
  50. discard freeEnvironmentStringsA(env)
  51. envComputed = true
  52. else:
  53. const
  54. useNSGetEnviron = (defined(macosx) and not defined(ios)) or defined(nimscript)
  55. when useNSGetEnviron:
  56. # From the manual:
  57. # Shared libraries and bundles don't have direct access to environ,
  58. # which is only available to the loader ld(1) when a complete program
  59. # is being linked.
  60. # The environment routines can still be used, but if direct access to
  61. # environ is needed, the _NSGetEnviron() routine, defined in
  62. # <crt_externs.h>, can be used to retrieve the address of environ
  63. # at runtime.
  64. proc NSGetEnviron(): ptr cstringArray {.
  65. importc: "_NSGetEnviron", header: "<crt_externs.h>".}
  66. else:
  67. var gEnv {.importc: "environ".}: cstringArray
  68. proc getEnvVarsC() =
  69. # retrieves the variables of char** env of C's main proc
  70. if not envComputed:
  71. environment = @[]
  72. when useNSGetEnviron:
  73. var gEnv = NSGetEnviron()[]
  74. var i = 0
  75. while true:
  76. if gEnv[i] == nil: break
  77. add environment, $gEnv[i]
  78. inc(i)
  79. envComputed = true
  80. proc findEnvVar(key: string): int =
  81. getEnvVarsC()
  82. var temp = key & '='
  83. for i in 0..high(environment):
  84. if startsWith(environment[i], temp): return i
  85. return -1
  86. proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} =
  87. ## Returns the value of the `environment variable`:idx: named `key`.
  88. ##
  89. ## If the variable does not exist, "" is returned. To distinguish
  90. ## whether a variable exists or it's value is just "", call
  91. ## `existsEnv(key)`.
  92. when nimvm:
  93. discard "built into the compiler"
  94. else:
  95. var i = findEnvVar(key)
  96. if i >= 0:
  97. return TaintedString(substr(environment[i], find(environment[i], '=')+1))
  98. else:
  99. var env = c_getenv(key)
  100. if env == nil: return TaintedString(default)
  101. result = TaintedString($env)
  102. proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
  103. ## Checks whether the environment variable named `key` exists.
  104. ## Returns true if it exists, false otherwise.
  105. when nimvm:
  106. discard "built into the compiler"
  107. else:
  108. if c_getenv(key) != nil: return true
  109. else: return findEnvVar(key) >= 0
  110. proc putEnv*(key, val: string) {.tags: [WriteEnvEffect].} =
  111. ## Sets the value of the `environment variable`:idx: named `key` to `val`.
  112. ## If an error occurs, `EInvalidEnvVar` is raised.
  113. # Note: by storing the string in the environment sequence,
  114. # we guarantee that we don't free the memory before the program
  115. # ends (this is needed for POSIX compliance). It is also needed so that
  116. # the process itself may access its modified environment variables!
  117. when nimvm:
  118. discard "built into the compiler"
  119. else:
  120. var indx = findEnvVar(key)
  121. if indx >= 0:
  122. environment[indx] = key & '=' & val
  123. else:
  124. add environment, (key & '=' & val)
  125. indx = high(environment)
  126. when defined(windows) and not defined(nimscript):
  127. when useWinUnicode:
  128. var k = newWideCString(key)
  129. var v = newWideCString(val)
  130. if setEnvironmentVariableW(k, v) == 0'i32: raiseOSError(osLastError())
  131. else:
  132. if setEnvironmentVariableA(key, val) == 0'i32: raiseOSError(osLastError())
  133. else:
  134. if c_putenv(environment[indx]) != 0'i32:
  135. raiseOSError(osLastError())
  136. iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} =
  137. ## Iterate over all `environments variables`:idx:. In the first component
  138. ## of the tuple is the name of the current variable stored, in the second
  139. ## its value.
  140. getEnvVarsC()
  141. for i in 0..high(environment):
  142. var p = find(environment[i], '=')
  143. yield (TaintedString(substr(environment[i], 0, p-1)),
  144. TaintedString(substr(environment[i], p+1)))