feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.Environ
pub const Environ = struct
File
Code
pub const Environ = struct {
process_environ: process.Environ,
exist: Exist = .{},
string: String = .{},
zig_progress_file: std.Progress.ParentFileError!File = error.EnvironmentVariableMissing,
err: ?Error = null,
pub const empty: Environ = .{ .process_environ = .empty };
pub const Error = Allocator.Error || Io.UnexpectedError;
pub const Exist = struct {
NO_COLOR: bool = false,
CLICOLOR_FORCE: bool = false,
};
pub const String = switch (native_os) {
.windows, .wasi => struct {},
else => struct {
PATH: ?[:0]const u8 = null,
DEBUGINFOD_CACHE_PATH: ?[:0]const u8 = null,
XDG_CACHE_HOME: ?[:0]const u8 = null,
HOME: ?[:0]const u8 = null,
TERM: ?[:0]const u8 = null,
},
};
pub fn scan(environ: *Environ, allocator: Allocator) void {
if (is_windows) {
// which is outside of this Io implementation's control, so references
// must be short-lived.
const peb = windows.peb();
assert(windows.ntdll.RtlEnterCriticalSection(peb.FastPebLock) == .SUCCESS);
defer assert(windows.ntdll.RtlLeaveCriticalSection(peb.FastPebLock) == .SUCCESS);
const ptr = peb.ProcessParameters.Environment;
var i: usize = 0;
while (ptr[i] != 0) {
// so we need a special case to not treat = as a key/value separator
// if it's the first character.
// https://devblogs.microsoft.com/oldnewthing/20100506-00/?p=14133
const key_start = i;
if (ptr[i] == '=') i += 1;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const key_w = ptr[key_start..i];
const value_start = i + 1;
while (ptr[i] != 0) : (i += 1) {}
const value_w = ptr[value_start..i];
i += 1;
if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'N', 'O', '_', 'C', 'O', 'L', 'O', 'R' })) {
environ.exist.NO_COLOR = true;
} else if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'C', 'L', 'I', 'C', 'O', 'L', 'O', 'R', '_', 'F', 'O', 'R', 'C', 'E' })) {
environ.exist.CLICOLOR_FORCE = true;
} else if (windows.eqlIgnoreCaseWtf16(key_w, &.{ 'Z', 'I', 'G', '_', 'P', 'R', 'O', 'G', 'R', 'E', 'S', 'S' })) {
environ.zig_progress_file = file: {
var value_buf: [std.fmt.count("{d}", .{std.math.maxInt(usize)})]u8 = undefined;
const len = std.unicode.calcWtf8Len(value_w);
if (len > value_buf.len) break :file error.UnrecognizedFormat;
assert(std.unicode.wtf16LeToWtf8(&value_buf, value_w) == len);
break :file .{
.handle = @ptrFromInt(std.fmt.parseInt(usize, value_buf[0..len], 10) catch
break :file error.UnrecognizedFormat),
.flags = .{ .nonblocking = true },
};
};
}
comptime assert(@sizeOf(String) == 0);
}
} else if (native_os == .wasi and !builtin.link_libc) {
var environ_size: usize = undefined;
var environ_buf_size: usize = undefined;
switch (std.os.wasi.environ_sizes_get(&environ_size, &environ_buf_size)) {
.SUCCESS => {},
else => |err| {
environ.err = posix.unexpectedErrno(err);
return;
},
}
if (environ_size == 0) return;
const wasi_environ = allocator.alloc([*:0]u8, environ_size) catch |err| {
environ.err = err;
return;
};
defer allocator.free(wasi_environ);
const wasi_environ_buf = allocator.alloc(u8, environ_buf_size) catch |err| {
environ.err = err;
return;
};
defer allocator.free(wasi_environ_buf);
switch (std.os.wasi.environ_get(wasi_environ.ptr, wasi_environ_buf.ptr)) {
.SUCCESS => {},
else => |err| {
environ.err = posix.unexpectedErrno(err);
return;
},
}
for (wasi_environ) |env| {
const pair = std.mem.sliceTo(env, 0);
var parts = std.mem.splitScalar(u8, pair, '=');
const key = parts.first();
if (std.mem.eql(u8, key, "NO_COLOR")) {
environ.exist.NO_COLOR = true;
} else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) {
environ.exist.CLICOLOR_FORCE = true;
}
comptime assert(@sizeOf(String) == 0);
}
} else {
for (environ.process_environ.block.slice) |opt_entry| {
const entry = opt_entry.?;
var entry_i: usize = 0;
while (entry[entry_i] != 0 and entry[entry_i] != '=') : (entry_i += 1) {}
const key = entry[0..entry_i];
var end_i: usize = entry_i;
while (entry[end_i] != 0) : (end_i += 1) {}
const value = entry[entry_i + 1 .. end_i :0];
if (std.mem.eql(u8, key, "NO_COLOR")) {
environ.exist.NO_COLOR = true;
} else if (std.mem.eql(u8, key, "CLICOLOR_FORCE")) {
environ.exist.CLICOLOR_FORCE = true;
} else if (std.mem.eql(u8, key, "ZIG_PROGRESS")) {
environ.zig_progress_file = file: {
break :file .{
.handle = std.fmt.parseInt(u31, value, 10) catch
break :file error.UnrecognizedFormat,
.flags = .{ .nonblocking = true },
};
};
} else inline for (@typeInfo(String).@"struct".field_names) |field_name| {
if (std.mem.eql(u8, key, field_name)) @field(environ.string, field_name) = value;
}
}
}
}
}