| ... | @@ -77,17 +77,31 @@ pub const Environ = struct { | ... | @@ -77,17 +77,31 @@ pub const Environ = struct { |
| 77 | /// memoized based on `block`. | 77 | /// memoized based on `block`. |
| 78 | initialized: bool = false, | 78 | initialized: bool = false, |
| 79 | /// Protected by `mutex`. Memoized based on `block`. Tracks whether the | 79 | /// Protected by `mutex`. Memoized based on `block`. Tracks whether the |
| 80 | /// environment variables are present and non-empty. | 80 | /// environment variables are present, ignoring their value. |
| 81 | exist: struct { | 81 | exist: Exist = .{}, |
| 82 | NO_COLOR: bool = false, | | |
| 83 | CLICOLOR_FORCE: bool = false, | | |
| 84 | } = .{}, | | |
| 85 | /// Protected by `mutex`. Memoized based on `block`. | 82 | /// Protected by `mutex`. Memoized based on `block`. |
| 86 | string: struct { | 83 | string: String = .{}, |
| 87 | PATH: ?[:0]const u8 = null, | 84 | /// Protected by `mutex`. Tracks the problem, if any, that occurred when |
| 88 | } = .{}, | 85 | /// trying to scan environment variables. |
| | 86 | /// |
| | 87 | /// Errors are only possible on WASI. |
| | 88 | err: ?Error = null, |
| | 89 | |
| | 90 | pub const Error = Allocator.Error || Io.UnexpectedError; |
| 89 | | 91 | |
| 90 | pub const Block = []const [*:0]const u8; | 92 | pub const Block = []const [*:0]const u8; |
| | 93 | |
| | 94 | pub const Exist = struct { |
| | 95 | NO_COLOR: bool = false, |
| | 96 | CLICOLOR_FORCE: bool = false, |
| | 97 | }; |
| | 98 | |
| | 99 | pub const String = switch (native_os) { |
| | 100 | .openbsd, .haiku => struct { |
| | 101 | PATH: ?[:0]const u8 = null, |
| | 102 | }, |
| | 103 | else => struct {}, |
| | 104 | }; |
| 91 | }; | 105 | }; |
| 92 | | 106 | |
| 93 | pub const RobustCancel = if (std.Thread.use_pthreads or native_os == .linux) enum { | 107 | pub const RobustCancel = if (std.Thread.use_pthreads or native_os == .linux) enum { |
| ... | @@ -11917,13 +11931,111 @@ fn scanEnviron(t: *Threaded) void { | ... | @@ -11917,13 +11931,111 @@ fn scanEnviron(t: *Threaded) void { |
| 11917 | if (t.environ.initialized) return; | 11931 | if (t.environ.initialized) return; |
| 11918 | t.environ.initialized = true; | 11932 | t.environ.initialized = true; |
| 11919 | | 11933 | |
| 11920 | if (native_os == .wasi) { | 11934 | if (is_windows) { |
| 11921 | @panic("TODO"); | 11935 | const ptr = windows.peb().ProcessParameters.Environment; |
| 11922 | } | | |
| 11923 | | 11936 | |
| 11924 | for (t.environ.block) |kv| { | 11937 | var i: usize = 0; |
| 11925 | _ = kv; | 11938 | while (ptr[i] != 0) { |
| 11926 | @panic("TODO"); | 11939 | const key_start = i; |
| | 11940 | |
| | 11941 | // There are some special environment variables that start with =, |
| | 11942 | // so we need a special case to not treat = as a key/value separator |
| | 11943 | // if it's the first character. |
| | 11944 | // https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133 |
| | 11945 | if (ptr[key_start] == '=') i += 1; |
| | 11946 | |
| | 11947 | while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} |
| | 11948 | const key_w = ptr[key_start..i]; |
| | 11949 | if (std.mem.eql(u16, key_w, &.{ 'N', 'O', '_', 'C', 'O', 'L', 'O', 'R' })) { |
| | 11950 | t.environ.exist.NO_COLOR = true; |
| | 11951 | } else if (std.mem.eql(u16, key_w, &.{ 'C', 'L', 'I', 'C', 'O', 'L', 'O', 'R', '_', 'F', 'O', 'R', 'C', 'E' })) { |
| | 11952 | t.environ.exist.CLICOLOR_FORCE = true; |
| | 11953 | } |
| | 11954 | comptime assert(@sizeOf(Environ.String) == 0); |
| | 11955 | |
| | 11956 | while (ptr[i] != 0) : (i += 1) {} // skip over '=' and value |
| | 11957 | i += 1; // skip over null byte |
| | 11958 | } |
| | 11959 | } else if (native_os == .wasi and !builtin.link_libc) { |
| | 11960 | var environ_count: usize = undefined; |
| | 11961 | var environ_buf_size: usize = undefined; |
| | 11962 | |
| | 11963 | switch (std.os.wasi.environ_sizes_get(&environ_count, &environ_buf_size)) { |
| | 11964 | .SUCCESS => {}, |
| | 11965 | else => |err| { |
| | 11966 | t.environ.err = posix.unexpectedErrno(err); |
| | 11967 | return; |
| | 11968 | }, |
| | 11969 | } |
| | 11970 | if (environ_count == 0) return; |
| | 11971 | |
| | 11972 | const environ = t.allocator.alloc([*:0]u8, environ_count) catch |err| { |
| | 11973 | t.environ.err = err; |
| | 11974 | return; |
| | 11975 | }; |
| | 11976 | defer t.allocator.free(environ); |
| | 11977 | const environ_buf = t.allocator.alloc(u8, environ_buf_size) catch |err| { |
| | 11978 | t.environ.err = err; |
| | 11979 | return; |
| | 11980 | }; |
| | 11981 | defer t.allocator.free(environ_buf); |
| | 11982 | |
| | 11983 | switch (std.os.wasi.environ_get(environ.ptr, environ_buf.ptr)) { |
| | 11984 | .SUCCESS => {}, |
| | 11985 | else => |err| { |
| | 11986 | t.environ.err = posix.unexpectedErrno(err); |
| | 11987 | return; |
| | 11988 | }, |
| | 11989 | } |
| | 11990 | |
| | 11991 | for (environ) |env| { |
| | 11992 | const pair = std.mem.sliceTo(env, 0); |
| | 11993 | var parts = std.mem.splitScalar(u8, pair, '='); |
| | 11994 | const key = parts.first(); |
| | 11995 | if (std.mem.eql(u8, key, "NO_COLOR")) { |
| | 11996 | t.environ.exist.NO_COLOR = true; |
| | 11997 | } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) { |
| | 11998 | t.environ.exist.CLICOLOR_FORCE = true; |
| | 11999 | } |
| | 12000 | comptime assert(@sizeOf(Environ.String) == 0); |
| | 12001 | } |
| | 12002 | } else if (builtin.link_libc) { |
| | 12003 | var ptr = std.c.environ; |
| | 12004 | while (ptr[0]) |line| : (ptr += 1) { |
| | 12005 | var line_i: usize = 0; |
| | 12006 | while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} |
| | 12007 | const key = line[0..line_i]; |
| | 12008 | |
| | 12009 | var end_i: usize = line_i; |
| | 12010 | while (line[end_i] != 0) : (end_i += 1) {} |
| | 12011 | const value = line[line_i + 1 .. end_i]; |
| | 12012 | |
| | 12013 | if (std.mem.eql(u8, key, "NO_COLOR")) { |
| | 12014 | t.environ.exist.NO_COLOR = true; |
| | 12015 | } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) { |
| | 12016 | t.environ.exist.CLICOLOR_FORCE = true; |
| | 12017 | } else if (@hasField(Environ.String, "PATH") and std.mem.eql(u8, key, "PATH")) { |
| | 12018 | t.environ.string.PATH = value; |
| | 12019 | } |
| | 12020 | } |
| | 12021 | } else { |
| | 12022 | for (t.environ.block) |line| { |
| | 12023 | var line_i: usize = 0; |
| | 12024 | while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} |
| | 12025 | const key = line[0..line_i]; |
| | 12026 | |
| | 12027 | var end_i: usize = line_i; |
| | 12028 | while (line[end_i] != 0) : (end_i += 1) {} |
| | 12029 | const value = line[line_i + 1 .. end_i]; |
| | 12030 | |
| | 12031 | if (std.mem.eql(u8, key, "NO_COLOR")) { |
| | 12032 | t.environ.exist.NO_COLOR = true; |
| | 12033 | } else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) { |
| | 12034 | t.environ.exist.CLICOLOR_FORCE = true; |
| | 12035 | } else if (@hasField(Environ.String, "PATH") and std.mem.eql(u8, key, "PATH")) { |
| | 12036 | t.environ.string.PATH = value; |
| | 12037 | } |
| | 12038 | } |
| 11927 | } | 12039 | } |
| 11928 | } | 12040 | } |
| 11929 | | 12041 | |