env_wasi.odin 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. #+private
  2. package os2
  3. import "base:runtime"
  4. import "core:strings"
  5. import "core:sync"
  6. import "core:sys/wasm/wasi"
  7. g_env: map[string]string
  8. g_env_buf: []byte
  9. g_env_mutex: sync.RW_Mutex
  10. g_env_error: Error
  11. g_env_built: bool
  12. build_env :: proc() -> (err: Error) {
  13. if g_env_built || g_env_error != nil {
  14. return g_env_error
  15. }
  16. sync.guard(&g_env_mutex)
  17. if g_env_built || g_env_error != nil {
  18. return g_env_error
  19. }
  20. defer if err != nil {
  21. g_env_error = err
  22. }
  23. num_envs, size_of_envs, _err := wasi.environ_sizes_get()
  24. if _err != nil {
  25. return _get_platform_error(_err)
  26. }
  27. g_env = make(map[string]string, num_envs, file_allocator()) or_return
  28. defer if err != nil { delete(g_env) }
  29. g_env_buf = make([]byte, size_of_envs, file_allocator()) or_return
  30. defer if err != nil { delete(g_env_buf, file_allocator()) }
  31. temp_allocator := TEMP_ALLOCATOR_GUARD({})
  32. envs := make([]cstring, num_envs, temp_allocator) or_return
  33. _err = wasi.environ_get(raw_data(envs), raw_data(g_env_buf))
  34. if _err != nil {
  35. return _get_platform_error(_err)
  36. }
  37. for env in envs {
  38. key, _, value := strings.partition(string(env), "=")
  39. g_env[key] = value
  40. }
  41. g_env_built = true
  42. return
  43. }
  44. delete_string_if_not_original :: proc(str: string) {
  45. start := uintptr(raw_data(g_env_buf))
  46. end := start + uintptr(len(g_env_buf))
  47. ptr := uintptr(raw_data(str))
  48. if ptr < start || ptr > end {
  49. delete(str, file_allocator())
  50. }
  51. }
  52. @(require_results)
  53. _lookup_env_alloc :: proc(key: string, allocator: runtime.Allocator) -> (value: string, found: bool) {
  54. if err := build_env(); err != nil {
  55. return
  56. }
  57. sync.shared_guard(&g_env_mutex)
  58. value = g_env[key] or_return
  59. value, _ = clone_string(value, allocator)
  60. return
  61. }
  62. _lookup_env_buf :: proc(buf: []u8, key: string) -> (value: string, error: Error) {
  63. if key == "" {
  64. return
  65. }
  66. if len(key) + 1 > len(buf) {
  67. return "", .Buffer_Full
  68. } else {
  69. copy(buf, key)
  70. }
  71. sync.shared_guard(&g_env_mutex)
  72. val, ok := g_env[key]
  73. if !ok {
  74. return "", .Env_Var_Not_Found
  75. } else {
  76. if len(val) > len(buf) {
  77. return "", .Buffer_Full
  78. } else {
  79. copy(buf, val)
  80. return string(buf[:len(val)]), nil
  81. }
  82. }
  83. }
  84. _lookup_env :: proc{_lookup_env_alloc, _lookup_env_buf}
  85. @(require_results)
  86. _set_env :: proc(key, value: string) -> (err: Error) {
  87. build_env() or_return
  88. sync.guard(&g_env_mutex)
  89. defer if err != nil {
  90. delete_key(&g_env, key)
  91. }
  92. key_ptr, value_ptr, just_inserted := map_entry(&g_env, key) or_return
  93. if just_inserted {
  94. key_ptr^ = clone_string(key, file_allocator()) or_return
  95. defer if err != nil {
  96. delete(key_ptr^, file_allocator())
  97. }
  98. value_ptr^ = clone_string(value, file_allocator()) or_return
  99. return
  100. }
  101. delete_string_if_not_original(value_ptr^)
  102. value_ptr^ = clone_string(value, file_allocator()) or_return
  103. return
  104. }
  105. @(require_results)
  106. _unset_env :: proc(key: string) -> bool {
  107. if err := build_env(); err != nil {
  108. return false
  109. }
  110. sync.guard(&g_env_mutex)
  111. dkey, dval := delete_key(&g_env, key)
  112. delete_string_if_not_original(dkey)
  113. delete_string_if_not_original(dval)
  114. return true
  115. }
  116. _clear_env :: proc() {
  117. sync.guard(&g_env_mutex)
  118. for k, v in g_env {
  119. delete_string_if_not_original(k)
  120. delete_string_if_not_original(v)
  121. }
  122. delete(g_env_buf, file_allocator())
  123. g_env_buf = {}
  124. clear(&g_env)
  125. g_env_built = true
  126. }
  127. @(require_results)
  128. _environ :: proc(allocator: runtime.Allocator) -> (environ: []string, err: Error) {
  129. build_env() or_return
  130. sync.shared_guard(&g_env_mutex)
  131. envs := make([dynamic]string, 0, len(g_env), allocator) or_return
  132. defer if err != nil {
  133. for env in envs {
  134. delete(env, allocator)
  135. }
  136. delete(envs)
  137. }
  138. for k, v in g_env {
  139. append(&envs, concatenate({k, "=", v}, allocator) or_return)
  140. }
  141. environ = envs[:]
  142. return
  143. }