diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-12-23 17:04:26 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-12-23 17:04:26 -0500 |
| commit | c00216701c64269a2395e84f3ccff99d6fb89ffc (patch) | |
| tree | 9fa071b9e96f9eadc5069b71634b11fc13b00839 /std | |
| parent | c21884e1d64e4193e03be4f3064917a26b34b142 (diff) | |
| parent | 45081c1e9cc28757cb563c77553631f7a92b29d8 (diff) | |
| download | zig-c00216701c64269a2395e84f3ccff99d6fb89ffc.tar.gz zig-c00216701c64269a2395e84f3ccff99d6fb89ffc.zip | |
Merge remote-tracking branch 'origin/master' into llvm8
Diffstat (limited to 'std')
76 files changed, 4695 insertions, 1205 deletions
diff --git a/std/array_list.zig b/std/array_list.zig index 3ee425fe14..ddad9c989c 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" { assert(list.len == 6); assert(list.items[0] == 1); } + +const Item = struct { + integer: i32, + sub_items: ArrayList(Item), +}; + +test "std.ArrayList: ArrayList(T) of struct T" { + var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) }; + try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } ); + assert(root.sub_items.items[0].integer == 42); +} diff --git a/std/atomic/int.zig b/std/atomic/int.zig index 38b85873c0..94985b914f 100644 --- a/std/atomic/int.zig +++ b/std/atomic/int.zig @@ -26,6 +26,10 @@ pub fn Int(comptime T: type) type { return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst); } + pub fn set(self: *Self, new_value: T) void { + _ = self.xchg(new_value); + } + pub fn xchg(self: *Self, new_value: T) T { return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst); } diff --git a/std/buf_map.zig b/std/buf_map.zig index a82d1b731a..6de0d20cdb 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -16,7 +16,7 @@ pub const BufMap = struct { return self; } - pub fn deinit(self: *const BufMap) void { + pub fn deinit(self: *BufMap) void { var it = self.hash_map.iterator(); while (true) { const entry = it.next() orelse break; @@ -27,16 +27,34 @@ pub const BufMap = struct { self.hash_map.deinit(); } + /// Same as `set` but the key and value become owned by the BufMap rather + /// than being copied. + /// If `setMove` fails, the ownership of key and value does not transfer. + pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void { + const get_or_put = try self.hash_map.getOrPut(key); + if (get_or_put.found_existing) { + self.free(get_or_put.kv.key); + get_or_put.kv.key = key; + } + get_or_put.kv.value = value; + } + + /// `key` and `value` are copied into the BufMap. pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void { - self.delete(key); - const key_copy = try self.copy(key); - errdefer self.free(key_copy); const value_copy = try self.copy(value); errdefer self.free(value_copy); - _ = try self.hash_map.put(key_copy, value_copy); + // Avoid copying key if it already exists + const get_or_put = try self.hash_map.getOrPut(key); + if (!get_or_put.found_existing) { + get_or_put.kv.key = self.copy(key) catch |err| { + _ = self.hash_map.remove(key); + return err; + }; + } + get_or_put.kv.value = value_copy; } - pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 { + pub fn get(self: BufMap, key: []const u8) ?[]const u8 { const entry = self.hash_map.get(key) orelse return null; return entry.value; } @@ -47,7 +65,7 @@ pub const BufMap = struct { self.free(entry.value); } - pub fn count(self: *const BufMap) usize { + pub fn count(self: BufMap) usize { return self.hash_map.count(); } @@ -55,11 +73,11 @@ pub const BufMap = struct { return self.hash_map.iterator(); } - fn free(self: *const BufMap, value: []const u8) void { + fn free(self: BufMap, value: []const u8) void { self.hash_map.allocator.free(value); } - fn copy(self: *const BufMap, value: []const u8) ![]const u8 { + fn copy(self: BufMap, value: []const u8) ![]u8 { return mem.dupe(self.hash_map.allocator, u8, value); } }; diff --git a/std/build.zig b/std/build.zig index fe84455cbe..90f5bec656 100644 --- a/std/build.zig +++ b/std/build.zig @@ -150,7 +150,11 @@ pub const Builder = struct { } pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - return LibExeObjStep.createExecutable(self, name, root_src); + return LibExeObjStep.createExecutable(self, name, root_src, false); + } + + pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { + return LibExeObjStep.createExecutable(self, name, root_src, true); } pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { @@ -795,11 +799,23 @@ pub const Target = union(enum) { }; } + pub fn isFreeBSD(self: *const Target) bool { + return switch (self.getOs()) { + builtin.Os.freebsd => true, + else => false, + }; + } + pub fn wantSharedLibSymLinks(self: *const Target) bool { return !self.isWindows(); } }; +const Pkg = struct { + name: []const u8, + path: []const u8, +}; + pub const LibExeObjStep = struct { step: Step, builder: *Builder, @@ -842,11 +858,6 @@ pub const LibExeObjStep = struct { source_files: ArrayList([]const u8), object_src: []const u8, - const Pkg = struct { - name: []const u8, - path: []const u8, - }; - const Kind = enum { Exe, Lib, @@ -884,8 +895,8 @@ pub const LibExeObjStep = struct { return self; } - pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { - const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable; + pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { + const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable; return self; } @@ -1263,6 +1274,9 @@ pub const LibExeObjStep = struct { zig_args.append("--ver-patch") catch unreachable; zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; } + if (self.kind == Kind.Exe and self.static) { + zig_args.append("--static") catch unreachable; + } switch (self.target) { Target.Native => {}, @@ -1653,6 +1667,7 @@ pub const TestStep = struct { exec_cmd_args: ?[]const ?[]const u8, include_dirs: ArrayList([]const u8), lib_paths: ArrayList([]const u8), + packages: ArrayList(Pkg), object_files: ArrayList([]const u8), no_rosegment: bool, output_path: ?[]const u8, @@ -1673,6 +1688,7 @@ pub const TestStep = struct { .exec_cmd_args = null, .include_dirs = ArrayList([]const u8).init(builder.allocator), .lib_paths = ArrayList([]const u8).init(builder.allocator), + .packages = ArrayList(Pkg).init(builder.allocator), .object_files = ArrayList([]const u8).init(builder.allocator), .no_rosegment = false, .output_path = null, @@ -1688,6 +1704,13 @@ pub const TestStep = struct { self.lib_paths.append(path) catch unreachable; } + pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void { + self.packages.append(Pkg{ + .name = name, + .path = pkg_index_path, + }) catch unreachable; + } + pub fn setVerbose(self: *TestStep, value: bool) void { self.verbose = value; } @@ -1864,6 +1887,13 @@ pub const TestStep = struct { try zig_args.append(lib_path); } + for (self.packages.toSliceConst()) |pkg| { + zig_args.append("--pkg-begin") catch unreachable; + zig_args.append(pkg.name) catch unreachable; + zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable; + zig_args.append("--pkg-end") catch unreachable; + } + if (self.no_rosegment) { try zig_args.append("--no-rosegment"); } diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig new file mode 100644 index 0000000000..421e964827 --- /dev/null +++ b/std/c/freebsd.zig @@ -0,0 +1,33 @@ +const timespec = @import("../os/freebsd/index.zig").timespec; + +extern "c" fn __error() *c_int; +pub const _errno = __error; + +pub extern "c" fn kqueue() c_int; +pub extern "c" fn kevent( + kq: c_int, + changelist: [*]const Kevent, + nchanges: c_int, + eventlist: [*]Kevent, + nevents: c_int, + timeout: ?*const timespec, +) c_int; +pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; +pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; +pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; + +/// Renamed from `kevent` to `Kevent` to avoid conflict with function name. +pub const Kevent = extern struct { + ident: usize, + filter: i16, + flags: u16, + fflags: u32, + data: i64, + udata: usize, + // TODO ext +}; + +pub const pthread_attr_t = extern struct { + __size: [56]u8, + __align: c_long, +}; diff --git a/std/c/index.zig b/std/c/index.zig index 6b20d718ef..4aab39d931 100644 --- a/std/c/index.zig +++ b/std/c/index.zig @@ -5,6 +5,7 @@ pub use switch (builtin.os) { Os.linux => @import("linux.zig"), Os.windows => @import("windows.zig"), Os.macosx, Os.ios => @import("darwin.zig"), + Os.freebsd => @import("freebsd.zig"), else => empty_import, }; const empty_import = @import("../empty.zig"); diff --git a/std/coff.zig b/std/coff.zig index 6a1aa34b46..53bd2a4b7a 100644 --- a/std/coff.zig +++ b/std/coff.zig @@ -51,7 +51,7 @@ pub const Coff = struct { // Seek to PE File Header (coff header) try self.in_file.seekTo(pe_pointer_offset); - const pe_magic_offset = try in.readIntLe(u32); + const pe_magic_offset = try in.readIntLittle(u32); try self.in_file.seekTo(pe_magic_offset); var pe_header_magic: [4]u8 = undefined; @@ -60,13 +60,13 @@ pub const Coff = struct { return error.InvalidPEHeader; self.coff_header = CoffHeader{ - .machine = try in.readIntLe(u16), - .number_of_sections = try in.readIntLe(u16), - .timedate_stamp = try in.readIntLe(u32), - .pointer_to_symbol_table = try in.readIntLe(u32), - .number_of_symbols = try in.readIntLe(u32), - .size_of_optional_header = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u16), + .machine = try in.readIntLittle(u16), + .number_of_sections = try in.readIntLittle(u16), + .timedate_stamp = try in.readIntLittle(u32), + .pointer_to_symbol_table = try in.readIntLittle(u32), + .number_of_symbols = try in.readIntLittle(u32), + .size_of_optional_header = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u16), }; switch (self.coff_header.machine) { @@ -79,7 +79,7 @@ pub const Coff = struct { fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void { const in = &file_stream.stream; - self.pe_header.magic = try in.readIntLe(u16); + self.pe_header.magic = try in.readIntLittle(u16); // For now we're only interested in finding the reference to the .pdb, // so we'll skip most of this header, which size is different in 32 // 64 bits by the way. @@ -93,14 +93,14 @@ pub const Coff = struct { try self.in_file.seekForward(skip_size); - const number_of_rva_and_sizes = try in.readIntLe(u32); + const number_of_rva_and_sizes = try in.readIntLittle(u32); if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES) return error.InvalidPEHeader; for (self.pe_header.data_directory) |*data_dir| { data_dir.* = OptionalHeader.DataDirectory{ - .virtual_address = try in.readIntLe(u32), - .size = try in.readIntLe(u32), + .virtual_address = try in.readIntLittle(u32), + .size = try in.readIntLittle(u32), }; } } @@ -124,7 +124,7 @@ pub const Coff = struct { if (!mem.eql(u8, cv_signature, "RSDS")) return error.InvalidPEMagic; try in.readNoEof(self.guid[0..]); - self.age = try in.readIntLe(u32); + self.age = try in.readIntLittle(u32); // Finally read the null-terminated string. var byte = try in.readByte(); @@ -157,15 +157,15 @@ pub const Coff = struct { try self.sections.append(Section{ .header = SectionHeader{ .name = name, - .misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) }, - .virtual_address = try in.readIntLe(u32), - .size_of_raw_data = try in.readIntLe(u32), - .pointer_to_raw_data = try in.readIntLe(u32), - .pointer_to_relocations = try in.readIntLe(u32), - .pointer_to_line_numbers = try in.readIntLe(u32), - .number_of_relocations = try in.readIntLe(u16), - .number_of_line_numbers = try in.readIntLe(u16), - .characteristics = try in.readIntLe(u32), + .misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) }, + .virtual_address = try in.readIntLittle(u32), + .size_of_raw_data = try in.readIntLittle(u32), + .pointer_to_raw_data = try in.readIntLittle(u32), + .pointer_to_relocations = try in.readIntLittle(u32), + .pointer_to_line_numbers = try in.readIntLittle(u32), + .number_of_relocations = try in.readIntLittle(u16), + .number_of_line_numbers = try in.readIntLittle(u16), + .characteristics = try in.readIntLittle(u32), }, }); } diff --git a/std/crypto/blake2.zig b/std/crypto/blake2.zig index dc68d806d2..e3de65916a 100644 --- a/std/crypto/blake2.zig +++ b/std/crypto/blake2.zig @@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } @@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]); + // TODO https://github.com/ziglang/zig/issues/863 + r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); } var k: usize = 0; @@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); } } @@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); } var k: usize = 0; diff --git a/std/crypto/chacha20.zig b/std/crypto/chacha20.zig index 059bc82088..5ec1e79756 100644 --- a/std/crypto/chacha20.zig +++ b/std/crypto/chacha20.zig @@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); } } @@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = []u32{ - mem.readIntLE(u32, c[0..4]), - mem.readIntLE(u32, c[4..8]), - mem.readIntLE(u32, c[8..12]), - mem.readIntLE(u32, c[12..16]), + mem.readIntSliceLittle(u32, c[0..4]), + mem.readIntSliceLittle(u32, c[4..8]), + mem.readIntSliceLittle(u32, c[8..12]), + mem.readIntSliceLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntLE(u32, nonce[0..4]); - c[2] = mem.readIntLE(u32, nonce[4..8]); - c[3] = mem.readIntLE(u32, nonce[8..12]); + c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntLE(u32, key[0..4]); - k[1] = mem.readIntLE(u32, key[4..8]); - k[2] = mem.readIntLE(u32, key[8..12]); - k[3] = mem.readIntLE(u32, key[12..16]); - k[4] = mem.readIntLE(u32, key[16..20]); - k[5] = mem.readIntLE(u32, key[20..24]); - k[6] = mem.readIntLE(u32, key[24..28]); - k[7] = mem.readIntLE(u32, key[28..32]); + k[0] = mem.readIntSliceLittle(u32, key[0..4]); + k[1] = mem.readIntSliceLittle(u32, key[4..8]); + k[2] = mem.readIntSliceLittle(u32, key[8..12]); + k[3] = mem.readIntSliceLittle(u32, key[12..16]); + k[4] = mem.readIntSliceLittle(u32, key[16..20]); + k[5] = mem.readIntSliceLittle(u32, key[20..24]); + k[6] = mem.readIntSliceLittle(u32, key[24..28]); + k[7] = mem.readIntSliceLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntLE(u32, nonce[0..4]); - c[3] = mem.readIntLE(u32, nonce[4..8]); + c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); + c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); const block_size = (1 << 6); const big_block = (block_size << 32); diff --git a/std/crypto/md5.zig b/std/crypto/md5.zig index 8663fa751f..994a7fa25c 100644 --- a/std/crypto/md5.zig +++ b/std/crypto/md5.zig @@ -112,7 +112,8 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/poly1305.zig b/std/crypto/poly1305.zig index a5d9fcdf57..0d7a4d672d 100644 --- a/std/crypto/poly1305.zig +++ b/std/crypto/poly1305.zig @@ -6,8 +6,8 @@ const std = @import("../index.zig"); const builtin = @import("builtin"); const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff; + ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc; + ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little); + ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little); - ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little); - ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little); - ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little); + ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,10 +210,11 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - writeInt(out[0..], @truncate(u32, uu0), Endian.Little); - writeInt(out[4..], @truncate(u32, uu1), Endian.Little); - writeInt(out[8..], @truncate(u32, uu2), Endian.Little); - writeInt(out[12..], @truncate(u32, uu3), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); + writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); + writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); + writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/std/crypto/sha1.zig b/std/crypto/sha1.zig index 1cb0b17434..d5aab8f33f 100644 --- a/std/crypto/sha1.zig +++ b/std/crypto/sha1.zig @@ -109,7 +109,8 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } diff --git a/std/crypto/sha2.zig b/std/crypto/sha2.zig index 7e9749364b..0476a3a25e 100644 --- a/std/crypto/sha2.zig +++ b/std/crypto/sha2.zig @@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); } } @@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); } } diff --git a/std/crypto/sha3.zig b/std/crypto/sha3.zig index 881370e686..e686e1337c 100644 --- a/std/crypto/sha3.zig +++ b/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = []const u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); } comptime var x: usize = 0; @@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void { } for (s) |r, i| { - mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); } } diff --git a/std/crypto/x25519.zig b/std/crypto/x25519.zig index 281813b457..daccb56808 100644 --- a/std/crypto/x25519.zig +++ b/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readInt = std.mem.readInt; -const writeInt = std.mem.writeInt; +const readIntSliceLittle = std.mem.readIntSliceLittle; +const writeIntSliceLittle = std.mem.writeIntSliceLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readInt(s[0..4], u32, Endian.Little); - t[1] = readInt(s[4..7], u32, Endian.Little) << 6; - t[2] = readInt(s[7..10], u32, Endian.Little) << 5; - t[3] = readInt(s[10..13], u32, Endian.Little) << 3; - t[4] = readInt(s[13..16], u32, Endian.Little) << 2; - t[5] = readInt(s[16..20], u32, Endian.Little); - t[6] = readInt(s[20..23], u32, Endian.Little) << 7; - t[7] = readInt(s[23..26], u32, Endian.Little) << 5; - t[8] = readInt(s[26..29], u32, Endian.Little) << 4; - t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2; + t[0] = readIntSliceLittle(u32, s[0..4]); + t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6; + t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5; + t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3; + t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2; + t[5] = readIntSliceLittle(u32, s[16..20]); + t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7; + t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5; + t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4; + t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,14 +544,15 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little); - writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little); - writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little); - writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little); - writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little); - writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little); - writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little); - writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little); + // TODO https://github.com/ziglang/zig/issues/863 + writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/std/debug/index.zig b/std/debug/index.zig index b077bdb3b0..73c6ea7b56 100644 --- a/std/debug/index.zig +++ b/std/debug/index.zig @@ -198,49 +198,44 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, } } -pub inline fn getReturnAddress(frame_count: usize) usize { - var fp = @ptrToInt(@frameAddress()); - var i: usize = 0; - while (fp != 0 and i < frame_count) { - fp = @intToPtr(*const usize, fp).*; - i += 1; +pub const StackIterator = struct { + first_addr: ?usize, + fp: usize, + + pub fn init(first_addr: ?usize) StackIterator { + return StackIterator{ + .first_addr = first_addr, + .fp = @ptrToInt(@frameAddress()), + }; } - return @intToPtr(*const usize, fp + @sizeOf(usize)).*; -} + + fn next(self: *StackIterator) ?usize { + if (self.fp == 0) return null; + self.fp = @intToPtr(*const usize, self.fp).*; + if (self.fp == 0) return null; + + if (self.first_addr) |addr| { + while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) { + const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; + if (addr == return_address) { + self.first_addr = null; + return return_address; + } + } + } + + const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; + return return_address; + } +}; pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { switch (builtin.os) { builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), else => {}, } - const AddressState = union(enum) { - NotLookingForStartAddress, - LookingForStartAddress: usize, - }; - // TODO: I want to express like this: - //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr } - // else AddressState.NotLookingForStartAddress; - var addr_state: AddressState = undefined; - if (start_addr) |addr| { - addr_state = AddressState{ .LookingForStartAddress = addr }; - } else { - addr_state = AddressState.NotLookingForStartAddress; - } - - var fp = @ptrToInt(@frameAddress()); - while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) { - const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*; - - switch (addr_state) { - AddressState.NotLookingForStartAddress => {}, - AddressState.LookingForStartAddress => |addr| { - if (return_address == addr) { - addr_state = AddressState.NotLookingForStartAddress; - } else { - continue; - } - }, - } + var it = StackIterator.init(start_addr); + while (it.next()) |return_address| { try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); } } @@ -282,8 +277,9 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres var coff_section: *coff.Section = undefined; const mod_index = for (di.sect_contribs) |sect_contrib| { - if (sect_contrib.Section >= di.coff.sections.len) continue; - coff_section = &di.coff.sections.toSlice()[sect_contrib.Section]; + if (sect_contrib.Section > di.coff.sections.len) continue; + // Remember that SectionContribEntry.Section is 1-based. + coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1]; const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; const vaddr_end = vaddr_start + sect_contrib.Size; @@ -413,7 +409,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres if (opt_line_info) |line_info| { try out_stream.print("\n"); - if (printLineFromFile(out_stream, line_info)) { + if (printLineFromFileAnyOs(out_stream, line_info)) { if (line_info.column == 0) { try out_stream.write("\n"); } else { @@ -527,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void { const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo; - const signature = try modi.stream.readIntLe(u32); + const signature = try modi.stream.readIntLittle(u32); if (signature != 4) return error.InvalidDebugInfo; @@ -597,7 +593,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt } else "???"; if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { defer line_info.deinit(); - try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); + try printLineInfo( + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_color, + printLineFromFileAnyOs, + ); } else |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => { if (tty_color) { @@ -610,7 +614,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt } } -pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { +/// This function works in freestanding mode. +/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void +pub fn printSourceAtAddressDwarf( + debug_info: *DwarfInfo, + out_stream: var, + address: usize, + tty_color: bool, + comptime printLineFromFile: var, +) !void { const compile_unit = findCompileUnit(debug_info, address) catch { if (tty_color) { try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); @@ -620,10 +632,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres return; }; const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); - if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| { + if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| { defer line_info.deinit(); const symbol_name = "???"; - try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); + try printLineInfo( + out_stream, + line_info, + address, + symbol_name, + compile_unit_name, + tty_color, + printLineFromFile, + ); } else |err| switch (err) { error.MissingDebugInfo, error.InvalidDebugInfo => { if (tty_color) { @@ -636,14 +656,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres } } +pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { + return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs); +} + fn printLineInfo( - debug_info: *DebugInfo, out_stream: var, line_info: LineInfo, address: usize, symbol_name: []const u8, compile_unit_name: []const u8, tty_color: bool, + comptime printLineFromFile: var, ) !void { if (tty_color) { try out_stream.print( @@ -733,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { try di.pdb.openFile(di.coff, path); var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo; - const version = try pdb_stream.stream.readIntLe(u32); - const signature = try pdb_stream.stream.readIntLe(u32); - const age = try pdb_stream.stream.readIntLe(u32); + const version = try pdb_stream.stream.readIntLittle(u32); + const signature = try pdb_stream.stream.readIntLittle(u32); + const age = try pdb_stream.stream.readIntLittle(u32); var guid: [16]u8 = undefined; try pdb_stream.stream.readNoEof(guid[0..]); if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age) @@ -743,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { // We validated the executable and pdb match. const string_table_index = str_tab_index: { - const name_bytes_len = try pdb_stream.stream.readIntLe(u32); + const name_bytes_len = try pdb_stream.stream.readIntLittle(u32); const name_bytes = try allocator.alloc(u8, name_bytes_len); try pdb_stream.stream.readNoEof(name_bytes); @@ -773,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { }; const bucket_list = try allocator.alloc(Bucket, present.len); for (present) |_| { - const name_offset = try pdb_stream.stream.readIntLe(u32); - const name_index = try pdb_stream.stream.readIntLe(u32); + const name_offset = try pdb_stream.stream.readIntLittle(u32); + const name_index = try pdb_stream.stream.readIntLittle(u32); const name = mem.toSlice(u8, name_bytes.ptr + name_offset); if (mem.eql(u8, name, "/names")) { break :str_tab_index name_index; @@ -835,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator); var sect_cont_offset: usize = 0; if (section_contrib_size != 0) { - const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32)); + const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32)); if (ver != pdb.SectionContrSubstreamVersion.Ver60) return error.InvalidDebugInfo; sect_cont_offset += @sizeOf(u32); @@ -855,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { } fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { - const num_words = try stream.readIntLe(u32); + const num_words = try stream.readIntLittle(u32); var word_i: usize = 0; var list = ArrayList(usize).init(allocator); while (word_i != num_words) : (word_i += 1) { - const word = try stream.readIntLe(u32); + const word = try stream.readIntLittle(u32); var bit_i: u5 = 0; while (true) : (bit_i += 1) { if (word & (u32(1) << bit_i) != 0) { @@ -871,55 +895,68 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { return list.toOwnedSlice(); } -fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { - var di = DebugInfo{ - .self_exe_file = undefined, - .elf = undefined, - .debug_info = undefined, - .debug_abbrev = undefined, - .debug_str = undefined, - .debug_line = undefined, - .debug_ranges = null, - .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), - .compile_unit_list = ArrayList(CompileUnit).init(allocator), +fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { + const elf_header = (try elf_file.findSection(name)) orelse return null; + return DwarfInfo.Section{ + .offset = elf_header.offset, + .size = elf_header.size, }; - di.self_exe_file = try os.openSelfExe(); - errdefer di.self_exe_file.close(); - - try di.elf.openFile(allocator, di.self_exe_file); - errdefer di.elf.close(); - - di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; - di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; - di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; - di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; - di.debug_ranges = (try di.elf.findSection(".debug_ranges")); - try scanAllCompileUnits(&di); - return di; } -pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr { - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; - - section_loop: for (elf.section_headers) |*elf_section| { - if (elf_section.sh_type == SHT_NULL) continue; - - const name_offset = elf.string_section.offset + elf_section.name; - try elf.in_file.seekTo(name_offset); - - for (name) |expected_c| { - const target_c = try in.readByte(); - if (target_c == 0 or expected_c != target_c) continue :section_loop; - } +/// Initialize DWARF info. The caller has the responsibility to initialize most +/// the DwarfInfo fields before calling. These fields can be left undefined: +/// * abbrev_table_list +/// * compile_unit_list +pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { + di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); + di.compile_unit_list = ArrayList(CompileUnit).init(allocator); + try scanAllCompileUnits(di); +} - { - const null_byte = try in.readByte(); - if (null_byte == 0) return elf_section; - } - } +pub fn openElfDebugInfo( + allocator: *mem.Allocator, + elf_seekable_stream: *DwarfSeekableStream, + elf_in_stream: *DwarfInStream, +) !DwarfInfo { + var efile: elf.Elf = undefined; + try efile.openStream(allocator, elf_seekable_stream, elf_in_stream); + errdefer efile.close(); + + var di = DwarfInfo{ + .dwarf_seekable_stream = elf_seekable_stream, + .dwarf_in_stream = elf_in_stream, + .endian = efile.endian, + .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo, + .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo, + .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo, + .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo, + .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), + .abbrev_table_list = undefined, + .compile_unit_list = undefined, + }; + try openDwarfDebugInfo(&di, allocator); + return di; +} - return null; +fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo { + const S = struct { + var self_exe_file: os.File = undefined; + var self_exe_seekable_stream: os.File.SeekableStream = undefined; + var self_exe_in_stream: os.File.InStream = undefined; + }; + S.self_exe_file = try os.openSelfExe(); + errdefer S.self_exe_file.close(); + + S.self_exe_seekable_stream = S.self_exe_file.seekableStream(); + S.self_exe_in_stream = S.self_exe_file.inStream(); + + return openElfDebugInfo( + allocator, + // TODO https://github.com/ziglang/zig/issues/764 + @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream), + // TODO https://github.com/ziglang/zig/issues/764 + @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream), + ); } fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { @@ -999,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { }; } -fn printLineFromFile(out_stream: var, line_info: LineInfo) !void { +fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { var f = try os.File.openRead(line_info.file_name); defer f.close(); // TODO fstat and make sure that the file has the correct size @@ -1052,6 +1089,35 @@ const MachOFile = struct { sect_debug_line: ?*const macho.section_64, }; +pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); +pub const DwarfInStream = io.InStream(anyerror); + +pub const DwarfInfo = struct { + dwarf_seekable_stream: *DwarfSeekableStream, + dwarf_in_stream: *DwarfInStream, + endian: builtin.Endian, + debug_info: Section, + debug_abbrev: Section, + debug_str: Section, + debug_line: Section, + debug_ranges: ?Section, + abbrev_table_list: ArrayList(AbbrevTableHeader), + compile_unit_list: ArrayList(CompileUnit), + + pub const Section = struct { + offset: usize, + size: usize, + }; + + pub fn allocator(self: DwarfInfo) *mem.Allocator { + return self.abbrev_table_list.allocator; + } + + pub fn readString(self: *DwarfInfo) ![]u8 { + return readStringRaw(self.allocator(), self.dwarf_in_stream); + } +}; + pub const DebugInfo = switch (builtin.os) { builtin.Os.macosx => struct { symbols: []const MachoSymbol, @@ -1075,32 +1141,8 @@ pub const DebugInfo = switch (builtin.os) { sect_contribs: []pdb.SectionContribEntry, modules: []Module, }, - builtin.Os.linux => struct { - self_exe_file: os.File, - elf: elf.Elf, - debug_info: *elf.SectionHeader, - debug_abbrev: *elf.SectionHeader, - debug_str: *elf.SectionHeader, - debug_line: *elf.SectionHeader, - debug_ranges: ?*elf.SectionHeader, - abbrev_table_list: ArrayList(AbbrevTableHeader), - compile_unit_list: ArrayList(CompileUnit), - - pub fn allocator(self: DebugInfo) *mem.Allocator { - return self.abbrev_table_list.allocator; - } - - pub fn readString(self: *DebugInfo) ![]u8 { - var in_file_stream = self.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - return readStringRaw(self.allocator(), in_stream); - } - - pub fn close(self: *DebugInfo) void { - self.self_exe_file.close(); - self.elf.close(); - } - }, + builtin.Os.linux => DwarfInfo, + builtin.Os.freebsd => struct {}, else => @compileError("Unsupported OS"), }; @@ -1158,7 +1200,7 @@ const Constant = struct { fn asUnsignedLe(self: *const Constant) !u64 { if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo; if (self.signed) return error.InvalidDebugInfo; - return mem.readInt(self.payload, u64, builtin.Endian.Little); + return mem.readVarInt(u64, self.payload, builtin.Endian.Little); } }; @@ -1204,11 +1246,11 @@ const Die = struct { }; } - fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 { + fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 { const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; return switch (form_value.*) { FormValue.String => |value| value, - FormValue.StrPtr => |offset| getString(st, offset), + FormValue.StrPtr => |offset| getString(di, offset), else => error.InvalidDebugInfo, }; } @@ -1221,14 +1263,15 @@ const FileEntry = struct { len_bytes: usize, }; -const LineInfo = struct { +pub const LineInfo = struct { line: usize, column: usize, - file_name: []u8, - allocator: *mem.Allocator, + file_name: []const u8, + allocator: ?*mem.Allocator, - fn deinit(self: *const LineInfo) void { - self.allocator.free(self.file_name); + fn deinit(self: LineInfo) void { + const allocator = self.allocator orelse return; + allocator.free(self.file_name); } }; @@ -1319,10 +1362,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { return buf.toSlice(); } -fn getString(st: *DebugInfo, offset: u64) ![]u8 { - const pos = st.debug_str.offset + offset; - try st.self_exe_file.seekTo(pos); - return st.readString(); +fn getString(di: *DwarfInfo, offset: u64) ![]u8 { + const pos = di.debug_str.offset + offset; + try di.dwarf_seekable_stream.seekTo(pos); + return di.readString(); } fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { @@ -1338,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize } fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { - const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size); + const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size); return parseFormValueBlockLen(allocator, in_stream, block_len); } @@ -1352,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo } fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 { - return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32)); + return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32)); } fn parseFormValueTargetAddrSize(in_stream: var) !u64 { - return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable; + return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable; } fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue { @@ -1365,18 +1408,11 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) } fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue { - const block_len = try in_stream.readIntLe(T); + const block_len = try in_stream.readIntLittle(T); return parseFormValueRefLen(allocator, in_stream, block_len); } -const ParseFormValueError = error{ - EndOfStream, - InvalidDebugInfo, - EndOfFile, - OutOfMemory, -} || std.os.File.ReadError; - -fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue { +fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { return switch (form_id) { DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), @@ -1414,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }, DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, - DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) }, + DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) }, DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) }, DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) }, @@ -1426,25 +1462,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 }; } -fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { - const in_file = st.self_exe_file; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - var result = AbbrevTable.init(st.allocator()); +fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { + var result = AbbrevTable.init(di.allocator()); while (true) { - const abbrev_code = try readULeb128(in_stream); + const abbrev_code = try readULeb128(di.dwarf_in_stream); if (abbrev_code == 0) return result; try result.append(AbbrevTableEntry{ .abbrev_code = abbrev_code, - .tag_id = try readULeb128(in_stream), - .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes, - .attrs = ArrayList(AbbrevAttr).init(st.allocator()), + .tag_id = try readULeb128(di.dwarf_in_stream), + .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes, + .attrs = ArrayList(AbbrevAttr).init(di.allocator()), }); const attrs = &result.items[result.len - 1].attrs; while (true) { - const attr_id = try readULeb128(in_stream); - const form_id = try readULeb128(in_stream); + const attr_id = try readULeb128(di.dwarf_in_stream); + const form_id = try readULeb128(di.dwarf_in_stream); if (attr_id == 0 and form_id == 0) break; try attrs.append(AbbrevAttr{ .attr_id = attr_id, @@ -1456,18 +1489,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, /// seeks in the stream and parses it. -fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { - for (st.abbrev_table_list.toSlice()) |*header| { +fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { + for (di.abbrev_table_list.toSlice()) |*header| { if (header.offset == abbrev_offset) { return &header.table; } } - try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset); - try st.abbrev_table_list.append(AbbrevTableHeader{ + try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset); + try di.abbrev_table_list.append(AbbrevTableHeader{ .offset = abbrev_offset, - .table = try parseAbbrevTable(st), + .table = try parseAbbrevTable(di), }); - return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table; + return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table; } fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { @@ -1477,23 +1510,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con return null; } -fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { - const in_file = st.self_exe_file; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - const abbrev_code = try readULeb128(in_stream); +fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { + const abbrev_code = try readULeb128(di.dwarf_in_stream); const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; var result = Die{ .tag_id = table_entry.tag_id, .has_children = table_entry.has_children, - .attrs = ArrayList(Die.Attr).init(st.allocator()), + .attrs = ArrayList(Die.Attr).init(di.allocator()), }; try result.attrs.resize(table_entry.attrs.len); for (table_entry.attrs.toSliceConst()) |attr, i| { result.attrs.items[i] = Die.Attr{ .id = attr.attr_id, - .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64), + .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), }; } return result; @@ -1697,22 +1727,18 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u return error.MissingDebugInfo; } -fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { +fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); - const in_file = di.self_exe_file; const debug_line_end = di.debug_line.offset + di.debug_line.size; var this_offset = di.debug_line.offset; var this_index: usize = 0; - var in_file_stream = in_file.inStream(); - const in_stream = &in_file_stream.stream; - while (this_offset < debug_line_end) : (this_index += 1) { - try in_file.seekTo(this_offset); + try di.dwarf_seekable_stream.seekTo(this_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); if (unit_length == 0) return error.MissingDebugInfo; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); @@ -1721,35 +1747,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ continue; } - const version = try in_stream.readInt(di.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); // TODO support 3 and 5 if (version != 2 and version != 4) return error.InvalidDebugInfo; - const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32); - const prog_start_offset = (try in_file.getPos()) + prologue_length; + const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); + const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; - const minimum_instruction_length = try in_stream.readByte(); + const minimum_instruction_length = try di.dwarf_in_stream.readByte(); if (minimum_instruction_length == 0) return error.InvalidDebugInfo; if (version >= 4) { // maximum_operations_per_instruction - _ = try in_stream.readByte(); + _ = try di.dwarf_in_stream.readByte(); } - const default_is_stmt = (try in_stream.readByte()) != 0; - const line_base = try in_stream.readByteSigned(); + const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; + const line_base = try di.dwarf_in_stream.readByteSigned(); - const line_range = try in_stream.readByte(); + const line_range = try di.dwarf_in_stream.readByte(); if (line_range == 0) return error.InvalidDebugInfo; - const opcode_base = try in_stream.readByte(); + const opcode_base = try di.dwarf_in_stream.readByte(); const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); { var i: usize = 0; while (i < opcode_base - 1) : (i += 1) { - standard_opcode_lengths[i] = try in_stream.readByte(); + standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); } } @@ -1767,9 +1793,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ while (true) { const file_name = try di.readString(); if (file_name.len == 0) break; - const dir_index = try readULeb128(in_stream); - const mtime = try readULeb128(in_stream); - const len_bytes = try readULeb128(in_stream); + const dir_index = try readULeb128(di.dwarf_in_stream); + const mtime = try readULeb128(di.dwarf_in_stream); + const len_bytes = try readULeb128(di.dwarf_in_stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1778,15 +1804,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ }); } - try in_file.seekTo(prog_start_offset); + try di.dwarf_seekable_stream.seekTo(prog_start_offset); while (true) { - const opcode = try in_stream.readByte(); + const opcode = try di.dwarf_in_stream.readByte(); if (opcode == DW.LNS_extended_op) { - const op_size = try readULeb128(in_stream); + const op_size = try readULeb128(di.dwarf_in_stream); if (op_size < 1) return error.InvalidDebugInfo; - var sub_op = try in_stream.readByte(); + var sub_op = try di.dwarf_in_stream.readByte(); switch (sub_op) { DW.LNE_end_sequence => { prog.end_sequence = true; @@ -1794,14 +1820,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ return error.MissingDebugInfo; }, DW.LNE_set_address => { - const addr = try in_stream.readInt(di.elf.endian, usize); + const addr = try di.dwarf_in_stream.readInt(usize, di.endian); prog.address = addr; }, DW.LNE_define_file => { const file_name = try di.readString(); - const dir_index = try readULeb128(in_stream); - const mtime = try readULeb128(in_stream); - const len_bytes = try readULeb128(in_stream); + const dir_index = try readULeb128(di.dwarf_in_stream); + const mtime = try readULeb128(di.dwarf_in_stream); + const len_bytes = try readULeb128(di.dwarf_in_stream); try file_entries.append(FileEntry{ .file_name = file_name, .dir_index = dir_index, @@ -1811,7 +1837,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ }, else => { const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; - try in_file.seekForward(fwd_amt); + try di.dwarf_seekable_stream.seekForward(fwd_amt); }, } } else if (opcode >= opcode_base) { @@ -1830,19 +1856,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ prog.basic_block = false; }, DW.LNS_advance_pc => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.address += arg * minimum_instruction_length; }, DW.LNS_advance_line => { - const arg = try readILeb128(in_stream); + const arg = try readILeb128(di.dwarf_in_stream); prog.line += arg; }, DW.LNS_set_file => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.file = arg; }, DW.LNS_set_column => { - const arg = try readULeb128(in_stream); + const arg = try readULeb128(di.dwarf_in_stream); prog.column = arg; }, DW.LNS_negate_stmt => { @@ -1856,14 +1882,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ prog.address += inc_addr; }, DW.LNS_fixed_advance_pc => { - const arg = try in_stream.readInt(di.elf.endian, u16); + const arg = try di.dwarf_in_stream.readInt(u16, di.endian); prog.address += arg; }, DW.LNS_set_prologue_end => {}, else => { if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; const len_bytes = standard_opcode_lengths[opcode - 1]; - try in_file.seekForward(len_bytes); + try di.dwarf_seekable_stream.seekForward(len_bytes); }, } } @@ -1875,36 +1901,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ return error.MissingDebugInfo; } -fn scanAllCompileUnits(st: *DebugInfo) !void { - const debug_info_end = st.debug_info.offset + st.debug_info.size; - var this_unit_offset = st.debug_info.offset; +fn scanAllCompileUnits(di: *DwarfInfo) !void { + const debug_info_end = di.debug_info.offset + di.debug_info.size; + var this_unit_offset = di.debug_info.offset; var cu_index: usize = 0; - var in_file_stream = st.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - while (this_unit_offset < debug_info_end) { - try st.self_exe_file.seekTo(this_unit_offset); + try di.dwarf_seekable_stream.seekTo(this_unit_offset); var is_64: bool = undefined; - const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); + const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); if (unit_length == 0) return; const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); - const version = try in_stream.readInt(st.elf.endian, u16); + const version = try di.dwarf_in_stream.readInt(u16, di.endian); if (version < 2 or version > 5) return error.InvalidDebugInfo; - const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32); + const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian); - const address_size = try in_stream.readByte(); + const address_size = try di.dwarf_in_stream.readByte(); if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; - const compile_unit_pos = try st.self_exe_file.getPos(); - const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset); + const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); + const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset); - try st.self_exe_file.seekTo(compile_unit_pos); + try di.dwarf_seekable_stream.seekTo(compile_unit_pos); - const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64)); + const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64)); if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; @@ -1932,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { } }; - try st.compile_unit_list.append(CompileUnit{ + try di.compile_unit_list.append(CompileUnit{ .version = version, .is_64 = is_64, .pc_range = pc_range, @@ -1945,20 +1968,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { } } -fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { - var in_file_stream = st.self_exe_file.inStream(); - const in_stream = &in_file_stream.stream; - for (st.compile_unit_list.toSlice()) |*compile_unit| { +fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { + for (di.compile_unit_list.toSlice()) |*compile_unit| { if (compile_unit.pc_range) |range| { if (target_address >= range.start and target_address < range.end) return compile_unit; } if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { var base_address: usize = 0; - if (st.debug_ranges) |debug_ranges| { - try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset); + if (di.debug_ranges) |debug_ranges| { + try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); while (true) { - const begin_addr = try in_stream.readIntLe(usize); - const end_addr = try in_stream.readIntLe(usize); + const begin_addr = try di.dwarf_in_stream.readIntLittle(usize); + const end_addr = try di.dwarf_in_stream.readIntLittle(usize); if (begin_addr == 0 and end_addr == 0) { break; } @@ -1980,7 +2001,8 @@ fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { } fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T { - const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian); + // TODO https://github.com/ziglang/zig/issues/863 + const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian); ptr.* += @sizeOf(T); return result; } @@ -1996,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 { } fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { - const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]); + // TODO this code can be improved with https://github.com/ziglang/zig/issues/863 + const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { ptr.* += 4; - const result = mem.readIntLE(u64, ptr.*[0..8]); + const result = mem.readIntSliceLittle(u64, ptr.*[0..8]); ptr.* += 8; return result; } else { @@ -2063,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 { } fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 { - const first_32_bits = try in_stream.readIntLe(u32); + const first_32_bits = try in_stream.readIntLittle(u32); is_64.* = (first_32_bits == 0xffffffff); if (is_64.*) { - return in_stream.readIntLe(u64); + return in_stream.readIntLittle(u64); } else { if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo; return u64(first_32_bits); diff --git a/std/dynamic_library.zig b/std/dynamic_library.zig index 49f217bc8e..4d19951318 100644 --- a/std/dynamic_library.zig +++ b/std/dynamic_library.zig @@ -19,7 +19,6 @@ pub const DynLib = switch (builtin.os) { }; pub const LinuxDynLib = struct { - allocator: *mem.Allocator, elf_lib: ElfLib, fd: i32, map_addr: usize, @@ -27,7 +26,7 @@ pub const LinuxDynLib = struct { /// Trusts the file pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib { - const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC); + const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC); errdefer std.os.close(fd); const size = @intCast(usize, (try std.os.posixFStat(fd)).size); @@ -45,7 +44,6 @@ pub const LinuxDynLib = struct { const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size]; return DynLib{ - .allocator = allocator, .elf_lib = try ElfLib.init(bytes), .fd = fd, .map_addr = addr, diff --git a/std/elf.zig b/std/elf.zig index e95222744d..6a564c3283 100644 --- a/std/elf.zig +++ b/std/elf.zig @@ -353,7 +353,8 @@ pub const SectionHeader = struct { }; pub const Elf = struct { - in_file: os.File, + seekable_stream: *io.SeekableStream(anyerror, anyerror), + in_stream: *io.InStream(anyerror), auto_close_stream: bool, is_64: bool, endian: builtin.Endian, @@ -370,19 +371,24 @@ pub const Elf = struct { /// Call close when done. pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void { - try elf.prealloc_file.open(path); - try elf.openFile(allocator, *elf.prealloc_file); - elf.auto_close_stream = true; + @compileError("TODO implement"); } /// Call close when done. pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void { - elf.allocator = allocator; - elf.in_file = file; - elf.auto_close_stream = false; + @compileError("TODO implement"); + } - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; + pub fn openStream( + elf: *Elf, + allocator: *mem.Allocator, + seekable_stream: *io.SeekableStream(anyerror, anyerror), + in: *io.InStream(anyerror), + ) !void { + elf.auto_close_stream = false; + elf.allocator = allocator; + elf.seekable_stream = seekable_stream; + elf.in_stream = in; var magic: [4]u8 = undefined; try in.readNoEof(magic[0..]); @@ -404,9 +410,9 @@ pub const Elf = struct { if (version_byte != 1) return error.InvalidFormat; // skip over padding - try elf.in_file.seekForward(9); + try seekable_stream.seekForward(9); - elf.file_type = switch (try in.readInt(elf.endian, u16)) { + elf.file_type = switch (try in.readInt(u16, elf.endian)) { 1 => FileType.Relocatable, 2 => FileType.Executable, 3 => FileType.Shared, @@ -414,7 +420,7 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - elf.arch = switch (try in.readInt(elf.endian, u16)) { + elf.arch = switch (try in.readInt(u16, elf.endian)) { 0x02 => Arch.Sparc, 0x03 => Arch.x86, 0x08 => Arch.Mips, @@ -427,32 +433,32 @@ pub const Elf = struct { else => return error.InvalidFormat, }; - const elf_version = try in.readInt(elf.endian, u32); + const elf_version = try in.readInt(u32, elf.endian); if (elf_version != 1) return error.InvalidFormat; if (elf.is_64) { - elf.entry_addr = try in.readInt(elf.endian, u64); - elf.program_header_offset = try in.readInt(elf.endian, u64); - elf.section_header_offset = try in.readInt(elf.endian, u64); + elf.entry_addr = try in.readInt(u64, elf.endian); + elf.program_header_offset = try in.readInt(u64, elf.endian); + elf.section_header_offset = try in.readInt(u64, elf.endian); } else { - elf.entry_addr = u64(try in.readInt(elf.endian, u32)); - elf.program_header_offset = u64(try in.readInt(elf.endian, u32)); - elf.section_header_offset = u64(try in.readInt(elf.endian, u32)); + elf.entry_addr = u64(try in.readInt(u32, elf.endian)); + elf.program_header_offset = u64(try in.readInt(u32, elf.endian)); + elf.section_header_offset = u64(try in.readInt(u32, elf.endian)); } // skip over flags - try elf.in_file.seekForward(4); + try seekable_stream.seekForward(4); - const header_size = try in.readInt(elf.endian, u16); + const header_size = try in.readInt(u16, elf.endian); if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { return error.InvalidFormat; } - const ph_entry_size = try in.readInt(elf.endian, u16); - const ph_entry_count = try in.readInt(elf.endian, u16); - const sh_entry_size = try in.readInt(elf.endian, u16); - const sh_entry_count = try in.readInt(elf.endian, u16); - elf.string_section_index = u64(try in.readInt(elf.endian, u16)); + const ph_entry_size = try in.readInt(u16, elf.endian); + const ph_entry_count = try in.readInt(u16, elf.endian); + const sh_entry_size = try in.readInt(u16, elf.endian); + const sh_entry_count = try in.readInt(u16, elf.endian); + elf.string_section_index = u64(try in.readInt(u16, elf.endian)); if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; @@ -461,12 +467,12 @@ pub const Elf = struct { const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count); const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); - const stream_end = try elf.in_file.getEndPos(); + const stream_end = try seekable_stream.getEndPos(); if (stream_end < end_sh or stream_end < end_ph) { return error.InvalidFormat; } - try elf.in_file.seekTo(elf.section_header_offset); + try seekable_stream.seekTo(elf.section_header_offset); elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); errdefer elf.allocator.free(elf.section_headers); @@ -475,32 +481,32 @@ pub const Elf = struct { if (sh_entry_size != 64) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = try in.readInt(elf.endian, u64); - elf_section.addr = try in.readInt(elf.endian, u64); - elf_section.offset = try in.readInt(elf.endian, u64); - elf_section.size = try in.readInt(elf.endian, u64); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = try in.readInt(elf.endian, u64); - elf_section.ent_size = try in.readInt(elf.endian, u64); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = try in.readInt(u64, elf.endian); + elf_section.addr = try in.readInt(u64, elf.endian); + elf_section.offset = try in.readInt(u64, elf.endian); + elf_section.size = try in.readInt(u64, elf.endian); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = try in.readInt(u64, elf.endian); + elf_section.ent_size = try in.readInt(u64, elf.endian); } } else { if (sh_entry_size != 40) return error.InvalidFormat; for (elf.section_headers) |*elf_section| { // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.name = try in.readInt(elf.endian, u32); - elf_section.sh_type = try in.readInt(elf.endian, u32); - elf_section.flags = u64(try in.readInt(elf.endian, u32)); - elf_section.addr = u64(try in.readInt(elf.endian, u32)); - elf_section.offset = u64(try in.readInt(elf.endian, u32)); - elf_section.size = u64(try in.readInt(elf.endian, u32)); - elf_section.link = try in.readInt(elf.endian, u32); - elf_section.info = try in.readInt(elf.endian, u32); - elf_section.addr_align = u64(try in.readInt(elf.endian, u32)); - elf_section.ent_size = u64(try in.readInt(elf.endian, u32)); + elf_section.name = try in.readInt(u32, elf.endian); + elf_section.sh_type = try in.readInt(u32, elf.endian); + elf_section.flags = u64(try in.readInt(u32, elf.endian)); + elf_section.addr = u64(try in.readInt(u32, elf.endian)); + elf_section.offset = u64(try in.readInt(u32, elf.endian)); + elf_section.size = u64(try in.readInt(u32, elf.endian)); + elf_section.link = try in.readInt(u32, elf.endian); + elf_section.info = try in.readInt(u32, elf.endian); + elf_section.addr_align = u64(try in.readInt(u32, elf.endian)); + elf_section.ent_size = u64(try in.readInt(u32, elf.endian)); } } @@ -521,26 +527,23 @@ pub const Elf = struct { pub fn close(elf: *Elf) void { elf.allocator.free(elf.section_headers); - if (elf.auto_close_stream) elf.in_file.close(); + if (elf.auto_close_stream) elf.prealloc_file.close(); } pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { - var file_stream = elf.in_file.inStream(); - const in = &file_stream.stream; - section_loop: for (elf.section_headers) |*elf_section| { if (elf_section.sh_type == SHT_NULL) continue; const name_offset = elf.string_section.offset + elf_section.name; - try elf.in_file.seekTo(name_offset); + try elf.seekable_stream.seekTo(name_offset); for (name) |expected_c| { - const target_c = try in.readByte(); + const target_c = try elf.in_stream.readByte(); if (target_c == 0 or expected_c != target_c) continue :section_loop; } { - const null_byte = try in.readByte(); + const null_byte = try elf.in_stream.readByte(); if (null_byte == 0) return elf_section; } } @@ -549,7 +552,7 @@ pub const Elf = struct { } pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { - try elf.in_file.seekTo(elf_section.offset); + try elf.seekable_stream.seekTo(elf_section.offset); } }; diff --git a/std/event/fs.zig b/std/event/fs.zig index 2ce3014178..1b8e1aa5dc 100644 --- a/std/event/fs.zig +++ b/std/event/fs.zig @@ -83,6 +83,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len); defer loop.allocator.free(iovecs); @@ -219,6 +220,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset: switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len); defer loop.allocator.free(iovecs); @@ -399,7 +401,7 @@ pub async fn openPosix( pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle { switch (builtin.os) { - builtin.Os.macosx, builtin.Os.linux => { + builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC; return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); }, @@ -427,6 +429,7 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os switch (builtin.os) { builtin.Os.macosx, builtin.Os.linux, + builtin.Os.freebsd, => { const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC; return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable); @@ -449,7 +452,7 @@ pub async fn openReadWrite( mode: os.File.Mode, ) os.File.OpenError!os.FileHandle { switch (builtin.os) { - builtin.Os.macosx, builtin.Os.linux => { + builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => { const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC; return await (async openPosix(loop, path, flags, mode) catch unreachable); }, @@ -477,7 +480,7 @@ pub const CloseOperation = struct { os_data: OsData, const OsData = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => OsDataPosix, + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => OsDataPosix, builtin.Os.windows => struct { handle: ?os.FileHandle, @@ -496,7 +499,7 @@ pub const CloseOperation = struct { self.* = CloseOperation{ .loop = loop, .os_data = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => initOsDataPosix(self), + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => initOsDataPosix(self), builtin.Os.windows => OsData{ .handle = null }, else => @compileError("Unsupported OS"), }, @@ -525,6 +528,7 @@ pub const CloseOperation = struct { switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { if (self.os_data.have_fd) { self.loop.posixFsRequest(&self.os_data.close_req_node); @@ -546,6 +550,7 @@ pub const CloseOperation = struct { switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { self.os_data.close_req_node.data.msg.Close.fd = handle; self.os_data.have_fd = true; @@ -562,6 +567,7 @@ pub const CloseOperation = struct { switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { self.os_data.have_fd = false; }, @@ -576,6 +582,7 @@ pub const CloseOperation = struct { switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => { assert(self.os_data.have_fd); return self.os_data.close_req_node.data.msg.Close.fd; @@ -599,6 +606,7 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable), builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable), else => @compileError("Unsupported OS"), @@ -704,7 +712,7 @@ pub fn Watch(comptime V: type) type { os_data: OsData, const OsData = switch (builtin.os) { - builtin.Os.macosx => struct { + builtin.Os.macosx, builtin.Os.freebsd => struct { file_table: FileTable, table_lock: event.Lock, @@ -793,7 +801,7 @@ pub fn Watch(comptime V: type) type { return self; }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const self = try loop.allocator.createOne(Self); errdefer loop.allocator.destroy(self); @@ -813,7 +821,7 @@ pub fn Watch(comptime V: type) type { /// All addFile calls and removeFile calls must have completed. pub fn destroy(self: *Self) void { switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { // TODO we need to cancel the coroutines before destroying the lock self.os_data.table_lock.deinit(); var it = self.os_data.file_table.iterator(); @@ -855,14 +863,14 @@ pub fn Watch(comptime V: type) type { pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V { switch (builtin.os) { - builtin.Os.macosx => return await (async addFileMacosx(self, file_path, value) catch unreachable), + builtin.Os.macosx, builtin.Os.freebsd => return await (async addFileKEvent(self, file_path, value) catch unreachable), builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable), builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable), else => @compileError("Unsupported OS"), } } - async fn addFileMacosx(self: *Self, file_path: []const u8, value: V) !?V { + async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V { const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path); var resolved_path_consumed = false; defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path); @@ -871,7 +879,10 @@ pub fn Watch(comptime V: type) type { var close_op_consumed = false; defer if (!close_op_consumed) close_op.finish(); - const flags = posix.O_SYMLINK | posix.O_EVTONLY; + const flags = switch (builtin.os) { + builtin.Os.macosx => posix.O_SYMLINK | posix.O_EVTONLY, + else => 0, + }; const mode = 0; const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable); close_op.setHandle(fd); diff --git a/std/event/io.zig b/std/event/io.zig index bb377a3b68..b11550f7aa 100644 --- a/std/event/io.zig +++ b/std/event/io.zig @@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type { if (amt_read < buf.len) return error.EndOfStream; } - pub async fn readIntLe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Little, T) catch unreachable); + pub async fn readIntLittle(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readIntLittle(T, &bytes); } pub async fn readIntBe(self: *Self, comptime T: type) !T { - return await (async self.readInt(builtin.Endian.Big, T) catch unreachable); + var bytes: [@sizeOf(T)]u8 = undefined; + try await (async self.readNoEof(bytes[0..]) catch unreachable); + return mem.readIntBig(T, &bytes); } - pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { + pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { var bytes: [@sizeOf(T)]u8 = undefined; try await (async self.readNoEof(bytes[0..]) catch unreachable); - return mem.readInt(bytes, T, endian); + return mem.readInt(T, &bytes, endian); } pub async fn readStruct(self: *Self, comptime T: type) !T { diff --git a/std/event/loop.zig b/std/event/loop.zig index fb47a9f253..43965e8293 100644 --- a/std/event/loop.zig +++ b/std/event/loop.zig @@ -49,7 +49,7 @@ pub const Loop = struct { }; pub const EventFd = switch (builtin.os) { - builtin.Os.macosx => MacOsEventFd, + builtin.Os.macosx, builtin.Os.freebsd => KEventFd, builtin.Os.linux => struct { base: ResumeNode, epoll_op: u32, @@ -62,13 +62,13 @@ pub const Loop = struct { else => @compileError("unsupported OS"), }; - const MacOsEventFd = struct { + const KEventFd = struct { base: ResumeNode, kevent: posix.Kevent, }; pub const Basic = switch (builtin.os) { - builtin.Os.macosx => MacOsBasic, + builtin.Os.macosx, builtin.Os.freebsd => KEventBasic, builtin.Os.linux => struct { base: ResumeNode, }, @@ -78,7 +78,7 @@ pub const Loop = struct { else => @compileError("unsupported OS"), }; - const MacOsBasic = struct { + const KEventBasic = struct { base: ResumeNode, kev: posix.Kevent, }; @@ -214,7 +214,7 @@ pub const Loop = struct { self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun); } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { self.os_data.kqfd = try os.bsdKQueue(); errdefer os.close(self.os_data.kqfd); @@ -369,7 +369,7 @@ pub const Loop = struct { os.close(self.os_data.epollfd); self.allocator.free(self.eventfd_resume_nodes); }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { os.close(self.os_data.kqfd); os.close(self.os_data.fs_kqfd); }, @@ -484,7 +484,7 @@ pub const Loop = struct { const eventfd_node = &resume_stack_node.data; eventfd_node.base.handle = next_tick_node.data; switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; _ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch { @@ -546,6 +546,7 @@ pub const Loop = struct { switch (builtin.os) { builtin.Os.linux, builtin.Os.macosx, + builtin.Os.freebsd, => self.os_data.fs_thread.wait(), else => {}, } @@ -610,7 +611,7 @@ pub const Loop = struct { os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable; return; }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { self.posixFsRequest(&self.os_data.fs_end_request); const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; @@ -668,7 +669,7 @@ pub const Loop = struct { } } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { var eventlist: [1]posix.Kevent = undefined; const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable; @@ -731,7 +732,7 @@ pub const Loop = struct { self.beginOneEvent(); // finished in posixFsRun after processing the msg self.os_data.fs_queue.put(request_node); switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake); const empty_kevs = ([*]posix.Kevent)(undefined)[0..0]; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable; @@ -801,7 +802,7 @@ pub const Loop = struct { else => unreachable, } }, - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait); var out_kevs: [1]posix.Kevent = undefined; _ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable; @@ -813,7 +814,7 @@ pub const Loop = struct { const OsData = switch (builtin.os) { builtin.Os.linux => LinuxOsData, - builtin.Os.macosx => MacOsData, + builtin.Os.macosx, builtin.Os.freebsd => KEventData, builtin.Os.windows => struct { io_port: windows.HANDLE, extra_thread_count: usize, @@ -821,7 +822,7 @@ pub const Loop = struct { else => struct {}, }; - const MacOsData = struct { + const KEventData = struct { kqfd: i32, final_kevent: posix.Kevent, fs_kevent_wake: posix.Kevent, diff --git a/std/fmt/index.zig b/std/fmt/index.zig index b4b2fdb010..b010072273 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -2,6 +2,7 @@ const std = @import("../index.zig"); const math = std.math; const debug = std.debug; const assert = debug.assert; +const assertError = debug.assertError; const mem = std.mem; const builtin = @import("builtin"); const errol = @import("errol/index.zig"); @@ -116,7 +117,7 @@ pub fn formatType( return output(context, @errorName(value)); } switch (@typeInfo(T)) { - builtin.TypeId.Int, builtin.TypeId.Float => { + builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => { return formatValue(value, fmt, context, Errors, output); }, builtin.TypeId.Void => { @@ -242,6 +243,9 @@ pub fn formatType( } return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value)); }, + builtin.TypeId.Fn => { + return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value)); + }, else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"), } } @@ -267,11 +271,15 @@ fn formatValue( } } - comptime var T = @typeOf(value); + const T = @typeOf(value); switch (@typeId(T)) { builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output), builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output), - else => unreachable, + builtin.TypeId.ComptimeInt => { + const Int = math.IntFittingRange(value, value); + return formatIntValue(Int(value), fmt, context, Errors, output); + }, + else => comptime unreachable, } } @@ -288,9 +296,10 @@ pub fn formatIntValue( if (fmt.len > 0) { switch (fmt[0]) { 'c' => { - if (@typeOf(value) == u8) { - if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]}); - return formatAsciiChar(value, context, Errors, output); + if (@typeOf(value).bit_count <= 8) { + if (fmt.len > 1) + @compileError("Unknown format character: " ++ []u8{fmt[1]}); + return formatAsciiChar(u8(value), context, Errors, output); } }, 'b' => { @@ -811,13 +820,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned for (buf) |c| { const digit = try charToDigit(c, radix); - x = try math.mul(T, x, radix); - x = try math.add(T, x, digit); + + if (x != 0) x = try math.mul(T, x, try math.cast(T, radix)); + x = try math.add(T, x, try math.cast(T, digit)); } return x; } +test "parseUnsigned" { + assert((try parseUnsigned(u16, "050124", 10)) == 50124); + assert((try parseUnsigned(u16, "65535", 10)) == 65535); + assertError(parseUnsigned(u16, "65536", 10), error.Overflow); + + assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); + assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow); + + assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); + + assert((try parseUnsigned(u7, "1", 10)) == 1); + assert((try parseUnsigned(u7, "1000", 2)) == 8); + + assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter); + assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter); + + assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); + + // these numbers should fit even though the radix itself doesn't fit in the destination type + assert((try parseUnsigned(u1, "0", 10)) == 0); + assert((try parseUnsigned(u1, "1", 10)) == 1); + assertError(parseUnsigned(u1, "2", 10), error.Overflow); + assert((try parseUnsigned(u1, "001", 16)) == 1); + assert((try parseUnsigned(u2, "3", 16)) == 3); + assertError(parseUnsigned(u2, "4", 16), error.Overflow); +} + pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { const value = switch (c) { '0'...'9' => c - '0', @@ -936,6 +973,25 @@ test "fmt.format" { try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value); } { + var buf1: [32]u8 = undefined; + var context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite); + var res = buf1[0 .. buf1.len - context.remaining.len]; + assert(mem.eql(u8, res, "1234")); + + context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite); + res = buf1[0 .. buf1.len - context.remaining.len]; + debug.warn("{}\n", res); + assert(mem.eql(u8, res, "a")); + + context = BufPrintContext{ .remaining = buf1[0..] }; + try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite); + res = buf1[0 .. buf1.len - context.remaining.len]; + debug.warn("{}\n", res); + assert(mem.eql(u8, res, "1100")); + } + { const value: [3]u8 = "abc"; try testFmt("array: abc\n", "array: {}\n", value); try testFmt("array: abc\n", "array: {}\n", &value); @@ -956,6 +1012,14 @@ test "fmt.format" { try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value); try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value); } + { + const value = @intToPtr(fn () void, 0xdeadbeef); + try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); + } + { + const value = @intToPtr(fn () void, 0xdeadbeef); + try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value); + } try testFmt("buf: Test \n", "buf: {s5}\n", "Test"); try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test"); try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C"); diff --git a/std/hash/siphash.zig b/std/hash/siphash.zig index 0fe958c38b..ee26950272 100644 --- a/std/hash/siphash.zig +++ b/std/hash/siphash.zig @@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) pub fn init(key: []const u8) Self { debug.assert(key.len >= 16); - const k0 = mem.readInt(key[0..8], u64, Endian.Little); - const k1 = mem.readInt(key[8..16], u64, Endian.Little); + const k0 = mem.readIntSliceLittle(u64, key[0..8]); + const k1 = mem.readIntSliceLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) fn round(d: *Self, b: []const u8) void { debug.assert(b.len == 8); - const m = mem.readInt(b[0..], u64, Endian.Little); + const m = mem.readIntSliceLittle(u64, b[0..]); d.v3 ^= m; comptime var i: usize = 0; @@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"; test "siphash64-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][8]u8{ "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc @@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u64, Endian.Little); + const expected = mem.readIntLittle(u64, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } test "siphash128-2-4 sanity" { - const vectors = [][]const u8{ + const vectors = [][16]u8{ "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", @@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" { for (vectors) |vector, i| { buffer[i] = @intCast(u8, i); - const expected = mem.readInt(vector, u128, Endian.Little); + const expected = mem.readIntLittle(u128, &vector); debug.assert(siphash.hash(test_key, buffer[0..i]) == expected); } } diff --git a/std/hash_map.zig b/std/hash_map.zig index 1b299eff78..99237047e0 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 }; } + pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV { + const res = try self.getOrPut(key); + if (!res.found_existing) + res.kv.value = value; + + return res.kv; + } + fn ensureCapacity(self: *Self) !void { if (self.entries.len == 0) { return self.initCapacity(16); @@ -354,6 +362,12 @@ test "basic hash map usage" { gop2.kv.value = 42; assert(map.get(99).?.value == 42); + const gop3 = try map.getOrPutValue(5, 5); + assert(gop3.value == 77); + + const gop4 = try map.getOrPutValue(100, 41); + assert(gop4.value == 41); + assert(map.contains(2)); assert(map.get(2).?.value == 22); _ = map.remove(2); diff --git a/std/heap.zig b/std/heap.zig index 9dbae4b8e0..46b247fa7e 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -66,11 +66,11 @@ pub const DirectAllocator = struct { } } - fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 { + fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const p = os.posix; const alloc_size = if (alignment <= os.page_size) n else n + alignment; const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0); @@ -121,7 +121,7 @@ pub const DirectAllocator = struct { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { if (new_size <= old_mem.len) { const base_addr = @ptrToInt(old_mem.ptr); const old_addr_end = base_addr + old_mem.len; @@ -166,7 +166,7 @@ pub const DirectAllocator = struct { const self = @fieldParentPtr(DirectAllocator, "allocator", allocator); switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { _ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len); }, Os.windows => { diff --git a/std/index.zig b/std/index.zig index 55ad016bb1..33eec14b0e 100644 --- a/std/index.zig +++ b/std/index.zig @@ -57,7 +57,8 @@ test "std" { _ = @import("mutex.zig"); _ = @import("segmented_list.zig"); _ = @import("spinlock.zig"); - + + _ = @import("dynamic_library.zig"); _ = @import("base64.zig"); _ = @import("build.zig"); _ = @import("c/index.zig"); diff --git a/std/io.zig b/std/io.zig index 6473d993c4..428d95725d 100644 --- a/std/io.zig +++ b/std/io.zig @@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File { return File.openHandle(handle); } +pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; + pub fn InStream(comptime ReadError: type) type { return struct { const Self = @This(); @@ -150,35 +152,43 @@ pub fn InStream(comptime ReadError: type) type { } /// Reads a native-endian integer - pub fn readIntNe(self: *Self, comptime T: type) !T { - return self.readInt(builtin.endian, T); + pub fn readIntNative(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntNative(T, &bytes); + } + + /// Reads a foreign-endian integer + pub fn readIntForeign(self: *Self, comptime T: type) !T { + var bytes: [@sizeOf(T)]u8 = undefined; + try self.readNoEof(bytes[0..]); + return mem.readIntForeign(T, &bytes); } - pub fn readIntLe(self: *Self, comptime T: type) !T { + pub fn readIntLittle(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntLE(T, bytes); + return mem.readIntLittle(T, &bytes); } - pub fn readIntBe(self: *Self, comptime T: type) !T { + pub fn readIntBig(self: *Self, comptime T: type) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readIntBE(T, bytes); + return mem.readIntBig(T, &bytes); } - pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T { + pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T { var bytes: [@sizeOf(T)]u8 = undefined; try self.readNoEof(bytes[0..]); - return mem.readInt(bytes, T, endian); + return mem.readInt(T, &bytes, endian); } - pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T { - assert(size <= @sizeOf(T)); - assert(size <= 8); - var input_buf: [8]u8 = undefined; - const input_slice = input_buf[0..size]; - try self.readNoEof(input_slice); - return mem.readInt(input_slice, T, endian); + pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType { + assert(size <= @sizeOf(ReturnType)); + var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined; + const bytes = bytes_buf[0..size]; + try self.readNoEof(bytes); + return mem.readVarInt(ReturnType, bytes, endian); } pub fn skipBytes(self: *Self, num_bytes: usize) !void { @@ -227,25 +237,34 @@ pub fn OutStream(comptime WriteError: type) type { } /// Write a native-endian integer. - pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void { - return self.writeInt(builtin.endian, T, value); + pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeIntNative(T, &bytes, value); + return self.writeFn(self, bytes); + } + + /// Write a foreign-endian integer. + pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void { + var bytes: [@sizeOf(T)]u8 = undefined; + mem.writeIntForeign(T, &bytes, value); + return self.writeFn(self, bytes); } - pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void { + pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntLE(T, &bytes, value); + mem.writeIntLittle(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void { + pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeIntBE(T, &bytes, value); + mem.writeIntBig(T, &bytes, value); return self.writeFn(self, bytes); } - pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void { + pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void { var bytes: [@sizeOf(T)]u8 = undefined; - mem.writeInt(bytes[0..], value, endian); + mem.writeInt(T, &bytes, value, endian); return self.writeFn(self, bytes); } }; @@ -683,25 +702,73 @@ test "import io tests" { } } -pub fn readLine(buf: []u8) !usize { - var stdin = getStdIn() catch return error.StdInUnavailable; - var adapter = stdin.inStream(); - var stream = &adapter.stream; - var index: usize = 0; +pub fn readLine(buf: *std.Buffer) ![]u8 { + var stdin = try getStdIn(); + var stdin_stream = stdin.inStream(); + return readLineFrom(&stdin_stream.stream, buf); +} + +/// Reads all characters until the next newline into buf, and returns +/// a slice of the characters read (excluding the newline character(s)). +pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 { + const start = buf.len(); while (true) { - const byte = stream.readByte() catch return error.EndOfFile; + const byte = try stream.readByte(); switch (byte) { '\r' => { // trash the following \n - _ = stream.readByte() catch return error.EndOfFile; - return index; - }, - '\n' => return index, - else => { - if (index == buf.len) return error.InputTooLong; - buf[index] = byte; - index += 1; + _ = try stream.readByte(); + return buf.toSlice()[start..]; }, + '\n' => return buf.toSlice()[start..], + else => try buf.appendByte(byte), } } } + +test "io.readLineFrom" { + var bytes: [128]u8 = undefined; + const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; + + var buf = try std.Buffer.initSize(allocator, 0); + var mem_stream = SliceInStream.init( + \\Line 1 + \\Line 22 + \\Line 333 + ); + const stream = &mem_stream.stream; + + debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); + debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); + debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); + debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); +} + +pub fn readLineSlice(slice: []u8) ![]u8 { + var stdin = try getStdIn(); + var stdin_stream = stdin.inStream(); + return readLineSliceFrom(&stdin_stream.stream, slice); +} + +/// Reads all characters until the next newline into slice, and returns +/// a slice of the characters read (excluding the newline character(s)). +pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { + // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte + // after taking ownership, which would always require an allocation. + var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) }; + try buf.resize(0); + return try readLineFrom(stream, &buf); +} + +test "io.readLineSliceFrom" { + var buf: [7]u8 = undefined; + var mem_stream = SliceInStream.init( + \\Line 1 + \\Line 22 + \\Line 333 + ); + const stream = &mem_stream.stream; + + debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); + debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); +} diff --git a/std/io/seekable_stream.zig b/std/io/seekable_stream.zig new file mode 100644 index 0000000000..a766f4fb89 --- /dev/null +++ b/std/io/seekable_stream.zig @@ -0,0 +1,32 @@ +const std = @import("../index.zig"); +const InStream = std.io.InStream; + +pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type { + return struct { + const Self = @This(); + pub const SeekError = SeekErrorType; + pub const GetSeekPosError = GetSeekPosErrorType; + + seekToFn: fn (self: *Self, pos: usize) SeekError!void, + seekForwardFn: fn (self: *Self, pos: isize) SeekError!void, + + getPosFn: fn (self: *Self) GetSeekPosError!usize, + getEndPosFn: fn (self: *Self) GetSeekPosError!usize, + + pub fn seekTo(self: *Self, pos: usize) SeekError!void { + return self.seekToFn(self, pos); + } + + pub fn seekForward(self: *Self, amt: isize) SeekError!void { + return self.seekForwardFn(self, amt); + } + + pub fn getEndPos(self: *Self) GetSeekPosError!usize { + return self.getEndPosFn(self); + } + + pub fn getPos(self: *Self) GetSeekPosError!usize { + return self.getPosFn(self); + } + }; +} diff --git a/std/json.zig b/std/json.zig index 23573b6d72..4d07d7b89d 100644 --- a/std/json.zig +++ b/std/json.zig @@ -910,7 +910,7 @@ fn checkNext(p: *TokenStream, id: Token.Id) void { debug.assert(token.id == id); } -test "token" { +test "json.token" { const s = \\{ \\ "Image": { @@ -980,7 +980,7 @@ pub fn validate(s: []const u8) bool { return p.complete; } -test "json validate" { +test "json.validate" { debug.assert(validate("{}")); } @@ -1188,7 +1188,7 @@ pub const Parser = struct { } var value = p.stack.pop(); - try p.pushToParent(value); + try p.pushToParent(&value); }, Token.Id.String => { try p.stack.append(try p.parseString(allocator, token, input, i)); @@ -1251,7 +1251,7 @@ pub const Parser = struct { } var value = p.stack.pop(); - try p.pushToParent(value); + try p.pushToParent(&value); }, Token.Id.ObjectBegin => { try p.stack.append(Value{ .Object = ObjectMap.init(allocator) }); @@ -1312,19 +1312,19 @@ pub const Parser = struct { } } - fn pushToParent(p: *Parser, value: Value) !void { - switch (p.stack.at(p.stack.len - 1)) { + fn pushToParent(p: *Parser, value: *const Value) !void { + switch (p.stack.toSlice()[p.stack.len - 1]) { // Object Parent -> [ ..., object, <key>, value ] Value.String => |key| { _ = p.stack.pop(); var object = &p.stack.items[p.stack.len - 1].Object; - _ = try object.put(key, value); + _ = try object.put(key, value.*); p.state = State.ObjectKey; }, // Array Parent -> [ ..., <array>, value ] Value.Array => |*array| { - try array.append(value); + try array.append(value.*); p.state = State.ArrayValue; }, else => { @@ -1348,7 +1348,7 @@ pub const Parser = struct { } }; -test "json parser dynamic" { +test "json.parser.dynamic" { var p = Parser.init(debug.global_allocator, false); defer p.deinit(); @@ -1364,7 +1364,8 @@ test "json parser dynamic" { \\ "Width": 100 \\ }, \\ "Animated" : false, - \\ "IDs": [116, 943, 234, 38793] + \\ "IDs": [116, 943, 234, 38793], + \\ "ArrayOfObject": [{"n": "m"}] \\ } \\} ; @@ -1387,4 +1388,10 @@ test "json parser dynamic" { const animated = image.Object.get("Animated").?.value; debug.assert(animated.Bool == false); + + const array_of_object = image.Object.get("ArrayOfObject").?.value; + debug.assert(array_of_object.Array.len == 1); + + const obj0 = array_of_object.Array.at(0).Object.get("n").?.value; + debug.assert(mem.eql(u8, obj0.String, "m")); } diff --git a/std/json_test.zig b/std/json_test.zig index 8c8862441a..9e19ec592a 100644 --- a/std/json_test.zig +++ b/std/json_test.zig @@ -21,7 +21,7 @@ fn any(comptime s: []const u8) void { // // Additional tests not part of test JSONTestSuite. -test "y_trailing_comma_after_empty" { +test "json.test.y_trailing_comma_after_empty" { ok( \\{"1":[],"2":{},"3":"4"} ); @@ -29,252 +29,252 @@ test "y_trailing_comma_after_empty" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "y_array_arraysWithSpaces" { +test "json.test.y_array_arraysWithSpaces" { ok( \\[[] ] ); } -test "y_array_empty" { +test "json.test.y_array_empty" { ok( \\[] ); } -test "y_array_empty-string" { +test "json.test.y_array_empty-string" { ok( \\[""] ); } -test "y_array_ending_with_newline" { +test "json.test.y_array_ending_with_newline" { ok( \\["a"] ); } -test "y_array_false" { +test "json.test.y_array_false" { ok( \\[false] ); } -test "y_array_heterogeneous" { +test "json.test.y_array_heterogeneous" { ok( \\[null, 1, "1", {}] ); } -test "y_array_null" { +test "json.test.y_array_null" { ok( \\[null] ); } -test "y_array_with_1_and_newline" { +test "json.test.y_array_with_1_and_newline" { ok( \\[1 \\] ); } -test "y_array_with_leading_space" { +test "json.test.y_array_with_leading_space" { ok( \\ [1] ); } -test "y_array_with_several_null" { +test "json.test.y_array_with_several_null" { ok( \\[1,null,null,null,2] ); } -test "y_array_with_trailing_space" { +test "json.test.y_array_with_trailing_space" { ok("[2] "); } -test "y_number_0e+1" { +test "json.test.y_number_0e+1" { ok( \\[0e+1] ); } -test "y_number_0e1" { +test "json.test.y_number_0e1" { ok( \\[0e1] ); } -test "y_number_after_space" { +test "json.test.y_number_after_space" { ok( \\[ 4] ); } -test "y_number_double_close_to_zero" { +test "json.test.y_number_double_close_to_zero" { ok( \\[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001] ); } -test "y_number_int_with_exp" { +test "json.test.y_number_int_with_exp" { ok( \\[20e1] ); } -test "y_number" { +test "json.test.y_number" { ok( \\[123e65] ); } -test "y_number_minus_zero" { +test "json.test.y_number_minus_zero" { ok( \\[-0] ); } -test "y_number_negative_int" { +test "json.test.y_number_negative_int" { ok( \\[-123] ); } -test "y_number_negative_one" { +test "json.test.y_number_negative_one" { ok( \\[-1] ); } -test "y_number_negative_zero" { +test "json.test.y_number_negative_zero" { ok( \\[-0] ); } -test "y_number_real_capital_e" { +test "json.test.y_number_real_capital_e" { ok( \\[1E22] ); } -test "y_number_real_capital_e_neg_exp" { +test "json.test.y_number_real_capital_e_neg_exp" { ok( \\[1E-2] ); } -test "y_number_real_capital_e_pos_exp" { +test "json.test.y_number_real_capital_e_pos_exp" { ok( \\[1E+2] ); } -test "y_number_real_exponent" { +test "json.test.y_number_real_exponent" { ok( \\[123e45] ); } -test "y_number_real_fraction_exponent" { +test "json.test.y_number_real_fraction_exponent" { ok( \\[123.456e78] ); } -test "y_number_real_neg_exp" { +test "json.test.y_number_real_neg_exp" { ok( \\[1e-2] ); } -test "y_number_real_pos_exponent" { +test "json.test.y_number_real_pos_exponent" { ok( \\[1e+2] ); } -test "y_number_simple_int" { +test "json.test.y_number_simple_int" { ok( \\[123] ); } -test "y_number_simple_real" { +test "json.test.y_number_simple_real" { ok( \\[123.456789] ); } -test "y_object_basic" { +test "json.test.y_object_basic" { ok( \\{"asd":"sdf"} ); } -test "y_object_duplicated_key_and_value" { +test "json.test.y_object_duplicated_key_and_value" { ok( \\{"a":"b","a":"b"} ); } -test "y_object_duplicated_key" { +test "json.test.y_object_duplicated_key" { ok( \\{"a":"b","a":"c"} ); } -test "y_object_empty" { +test "json.test.y_object_empty" { ok( \\{} ); } -test "y_object_empty_key" { +test "json.test.y_object_empty_key" { ok( \\{"":0} ); } -test "y_object_escaped_null_in_key" { +test "json.test.y_object_escaped_null_in_key" { ok( \\{"foo\u0000bar": 42} ); } -test "y_object_extreme_numbers" { +test "json.test.y_object_extreme_numbers" { ok( \\{ "min": -1.0e+28, "max": 1.0e+28 } ); } -test "y_object" { +test "json.test.y_object" { ok( \\{"asd":"sdf", "dfg":"fgh"} ); } -test "y_object_long_strings" { +test "json.test.y_object_long_strings" { ok( \\{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"} ); } -test "y_object_simple" { +test "json.test.y_object_simple" { ok( \\{"a":[]} ); } -test "y_object_string_unicode" { +test "json.test.y_object_string_unicode" { ok( \\{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" } ); } -test "y_object_with_newlines" { +test "json.test.y_object_with_newlines" { ok( \\{ \\"a": "b" @@ -282,419 +282,419 @@ test "y_object_with_newlines" { ); } -test "y_string_1_2_3_bytes_UTF-8_sequences" { +test "json.test.y_string_1_2_3_bytes_UTF-8_sequences" { ok( \\["\u0060\u012a\u12AB"] ); } -test "y_string_accepted_surrogate_pair" { +test "json.test.y_string_accepted_surrogate_pair" { ok( \\["\uD801\udc37"] ); } -test "y_string_accepted_surrogate_pairs" { +test "json.test.y_string_accepted_surrogate_pairs" { ok( \\["\ud83d\ude39\ud83d\udc8d"] ); } -test "y_string_allowed_escapes" { +test "json.test.y_string_allowed_escapes" { ok( \\["\"\\\/\b\f\n\r\t"] ); } -test "y_string_backslash_and_u_escaped_zero" { +test "json.test.y_string_backslash_and_u_escaped_zero" { ok( \\["\\u0000"] ); } -test "y_string_backslash_doublequotes" { +test "json.test.y_string_backslash_doublequotes" { ok( \\["\""] ); } -test "y_string_comments" { +test "json.test.y_string_comments" { ok( \\["a/*b*/c/*d//e"] ); } -test "y_string_double_escape_a" { +test "json.test.y_string_double_escape_a" { ok( \\["\\a"] ); } -test "y_string_double_escape_n" { +test "json.test.y_string_double_escape_n" { ok( \\["\\n"] ); } -test "y_string_escaped_control_character" { +test "json.test.y_string_escaped_control_character" { ok( \\["\u0012"] ); } -test "y_string_escaped_noncharacter" { +test "json.test.y_string_escaped_noncharacter" { ok( \\["\uFFFF"] ); } -test "y_string_in_array" { +test "json.test.y_string_in_array" { ok( \\["asd"] ); } -test "y_string_in_array_with_leading_space" { +test "json.test.y_string_in_array_with_leading_space" { ok( \\[ "asd"] ); } -test "y_string_last_surrogates_1_and_2" { +test "json.test.y_string_last_surrogates_1_and_2" { ok( \\["\uDBFF\uDFFF"] ); } -test "y_string_nbsp_uescaped" { +test "json.test.y_string_nbsp_uescaped" { ok( \\["new\u00A0line"] ); } -test "y_string_nonCharacterInUTF-8_U+10FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+10FFFF" { ok( \\[""] ); } -test "y_string_nonCharacterInUTF-8_U+FFFF" { +test "json.test.y_string_nonCharacterInUTF-8_U+FFFF" { ok( \\[""] ); } -test "y_string_null_escape" { +test "json.test.y_string_null_escape" { ok( \\["\u0000"] ); } -test "y_string_one-byte-utf-8" { +test "json.test.y_string_one-byte-utf-8" { ok( \\["\u002c"] ); } -test "y_string_pi" { +test "json.test.y_string_pi" { ok( \\["π"] ); } -test "y_string_reservedCharacterInUTF-8_U+1BFFF" { +test "json.test.y_string_reservedCharacterInUTF-8_U+1BFFF" { ok( \\[""] ); } -test "y_string_simple_ascii" { +test "json.test.y_string_simple_ascii" { ok( \\["asd "] ); } -test "y_string_space" { +test "json.test.y_string_space" { ok( \\" " ); } -test "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { +test "json.test.y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF" { ok( \\["\uD834\uDd1e"] ); } -test "y_string_three-byte-utf-8" { +test "json.test.y_string_three-byte-utf-8" { ok( \\["\u0821"] ); } -test "y_string_two-byte-utf-8" { +test "json.test.y_string_two-byte-utf-8" { ok( \\["\u0123"] ); } -test "y_string_u+2028_line_sep" { +test "json.test.y_string_u+2028_line_sep" { ok("[\"\xe2\x80\xa8\"]"); } -test "y_string_u+2029_par_sep" { +test "json.test.y_string_u+2029_par_sep" { ok("[\"\xe2\x80\xa9\"]"); } -test "y_string_uescaped_newline" { +test "json.test.y_string_uescaped_newline" { ok( \\["new\u000Aline"] ); } -test "y_string_uEscape" { +test "json.test.y_string_uEscape" { ok( \\["\u0061\u30af\u30EA\u30b9"] ); } -test "y_string_unescaped_char_delete" { +test "json.test.y_string_unescaped_char_delete" { ok("[\"\x7f\"]"); } -test "y_string_unicode_2" { +test "json.test.y_string_unicode_2" { ok( \\["⍂㈴⍂"] ); } -test "y_string_unicodeEscapedBackslash" { +test "json.test.y_string_unicodeEscapedBackslash" { ok( \\["\u005C"] ); } -test "y_string_unicode_escaped_double_quote" { +test "json.test.y_string_unicode_escaped_double_quote" { ok( \\["\u0022"] ); } -test "y_string_unicode" { +test "json.test.y_string_unicode" { ok( \\["\uA66D"] ); } -test "y_string_unicode_U+10FFFE_nonchar" { +test "json.test.y_string_unicode_U+10FFFE_nonchar" { ok( \\["\uDBFF\uDFFE"] ); } -test "y_string_unicode_U+1FFFE_nonchar" { +test "json.test.y_string_unicode_U+1FFFE_nonchar" { ok( \\["\uD83F\uDFFE"] ); } -test "y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { +test "json.test.y_string_unicode_U+200B_ZERO_WIDTH_SPACE" { ok( \\["\u200B"] ); } -test "y_string_unicode_U+2064_invisible_plus" { +test "json.test.y_string_unicode_U+2064_invisible_plus" { ok( \\["\u2064"] ); } -test "y_string_unicode_U+FDD0_nonchar" { +test "json.test.y_string_unicode_U+FDD0_nonchar" { ok( \\["\uFDD0"] ); } -test "y_string_unicode_U+FFFE_nonchar" { +test "json.test.y_string_unicode_U+FFFE_nonchar" { ok( \\["\uFFFE"] ); } -test "y_string_utf8" { +test "json.test.y_string_utf8" { ok( \\["€𝄞"] ); } -test "y_string_with_del_character" { +test "json.test.y_string_with_del_character" { ok("[\"a\x7fa\"]"); } -test "y_structure_lonely_false" { +test "json.test.y_structure_lonely_false" { ok( \\false ); } -test "y_structure_lonely_int" { +test "json.test.y_structure_lonely_int" { ok( \\42 ); } -test "y_structure_lonely_negative_real" { +test "json.test.y_structure_lonely_negative_real" { ok( \\-0.1 ); } -test "y_structure_lonely_null" { +test "json.test.y_structure_lonely_null" { ok( \\null ); } -test "y_structure_lonely_string" { +test "json.test.y_structure_lonely_string" { ok( \\"asd" ); } -test "y_structure_lonely_true" { +test "json.test.y_structure_lonely_true" { ok( \\true ); } -test "y_structure_string_empty" { +test "json.test.y_structure_string_empty" { ok( \\"" ); } -test "y_structure_trailing_newline" { +test "json.test.y_structure_trailing_newline" { ok( \\["a"] ); } -test "y_structure_true_in_array" { +test "json.test.y_structure_true_in_array" { ok( \\[true] ); } -test "y_structure_whitespace_array" { +test "json.test.y_structure_whitespace_array" { ok(" [] "); } //////////////////////////////////////////////////////////////////////////////////////////////////// -test "n_array_1_true_without_comma" { +test "json.test.n_array_1_true_without_comma" { err( \\[1 true] ); } -test "n_array_a_invalid_utf8" { +test "json.test.n_array_a_invalid_utf8" { err( \\[aå] ); } -test "n_array_colon_instead_of_comma" { +test "json.test.n_array_colon_instead_of_comma" { err( \\["": 1] ); } -test "n_array_comma_after_close" { +test "json.test.n_array_comma_after_close" { //err( // \\[""], //); } -test "n_array_comma_and_number" { +test "json.test.n_array_comma_and_number" { err( \\[,1] ); } -test "n_array_double_comma" { +test "json.test.n_array_double_comma" { err( \\[1,,2] ); } -test "n_array_double_extra_comma" { +test "json.test.n_array_double_extra_comma" { err( \\["x",,] ); } -test "n_array_extra_close" { +test "json.test.n_array_extra_close" { err( \\["x"]] ); } -test "n_array_extra_comma" { +test "json.test.n_array_extra_comma" { //err( // \\["",] //); } -test "n_array_incomplete_invalid_value" { +test "json.test.n_array_incomplete_invalid_value" { err( \\[x ); } -test "n_array_incomplete" { +test "json.test.n_array_incomplete" { err( \\["x" ); } -test "n_array_inner_array_no_comma" { +test "json.test.n_array_inner_array_no_comma" { err( \\[3[4]] ); } -test "n_array_invalid_utf8" { +test "json.test.n_array_invalid_utf8" { err( \\[ÿ] ); } -test "n_array_items_separated_by_semicolon" { +test "json.test.n_array_items_separated_by_semicolon" { err( \\[1:2] ); } -test "n_array_just_comma" { +test "json.test.n_array_just_comma" { err( \\[,] ); } -test "n_array_just_minus" { +test "json.test.n_array_just_minus" { err( \\[-] ); } -test "n_array_missing_value" { +test "json.test.n_array_missing_value" { err( \\[ , ""] ); } -test "n_array_newlines_unclosed" { +test "json.test.n_array_newlines_unclosed" { err( \\["a", \\4 @@ -702,41 +702,41 @@ test "n_array_newlines_unclosed" { ); } -test "n_array_number_and_comma" { +test "json.test.n_array_number_and_comma" { err( \\[1,] ); } -test "n_array_number_and_several_commas" { +test "json.test.n_array_number_and_several_commas" { err( \\[1,,] ); } -test "n_array_spaces_vertical_tab_formfeed" { +test "json.test.n_array_spaces_vertical_tab_formfeed" { err("[\"\x0aa\"\\f]"); } -test "n_array_star_inside" { +test "json.test.n_array_star_inside" { err( \\[*] ); } -test "n_array_unclosed" { +test "json.test.n_array_unclosed" { err( \\["" ); } -test "n_array_unclosed_trailing_comma" { +test "json.test.n_array_unclosed_trailing_comma" { err( \\[1, ); } -test "n_array_unclosed_with_new_lines" { +test "json.test.n_array_unclosed_with_new_lines" { err( \\[1, \\1 @@ -744,956 +744,956 @@ test "n_array_unclosed_with_new_lines" { ); } -test "n_array_unclosed_with_object_inside" { +test "json.test.n_array_unclosed_with_object_inside" { err( \\[{} ); } -test "n_incomplete_false" { +test "json.test.n_incomplete_false" { err( \\[fals] ); } -test "n_incomplete_null" { +test "json.test.n_incomplete_null" { err( \\[nul] ); } -test "n_incomplete_true" { +test "json.test.n_incomplete_true" { err( \\[tru] ); } -test "n_multidigit_number_then_00" { +test "json.test.n_multidigit_number_then_00" { err("123\x00"); } -test "n_number_0.1.2" { +test "json.test.n_number_0.1.2" { err( \\[0.1.2] ); } -test "n_number_-01" { +test "json.test.n_number_-01" { err( \\[-01] ); } -test "n_number_0.3e" { +test "json.test.n_number_0.3e" { err( \\[0.3e] ); } -test "n_number_0.3e+" { +test "json.test.n_number_0.3e+" { err( \\[0.3e+] ); } -test "n_number_0_capital_E" { +test "json.test.n_number_0_capital_E" { err( \\[0E] ); } -test "n_number_0_capital_E+" { +test "json.test.n_number_0_capital_E+" { err( \\[0E+] ); } -test "n_number_0.e1" { +test "json.test.n_number_0.e1" { err( \\[0.e1] ); } -test "n_number_0e" { +test "json.test.n_number_0e" { err( \\[0e] ); } -test "n_number_0e+" { +test "json.test.n_number_0e+" { err( \\[0e+] ); } -test "n_number_1_000" { +test "json.test.n_number_1_000" { err( \\[1 000.0] ); } -test "n_number_1.0e-" { +test "json.test.n_number_1.0e-" { err( \\[1.0e-] ); } -test "n_number_1.0e" { +test "json.test.n_number_1.0e" { err( \\[1.0e] ); } -test "n_number_1.0e+" { +test "json.test.n_number_1.0e+" { err( \\[1.0e+] ); } -test "n_number_-1.0." { +test "json.test.n_number_-1.0." { err( \\[-1.0.] ); } -test "n_number_1eE2" { +test "json.test.n_number_1eE2" { err( \\[1eE2] ); } -test "n_number_.-1" { +test "json.test.n_number_.-1" { err( \\[.-1] ); } -test "n_number_+1" { +test "json.test.n_number_+1" { err( \\[+1] ); } -test "n_number_.2e-3" { +test "json.test.n_number_.2e-3" { err( \\[.2e-3] ); } -test "n_number_2.e-3" { +test "json.test.n_number_2.e-3" { err( \\[2.e-3] ); } -test "n_number_2.e+3" { +test "json.test.n_number_2.e+3" { err( \\[2.e+3] ); } -test "n_number_2.e3" { +test "json.test.n_number_2.e3" { err( \\[2.e3] ); } -test "n_number_-2." { +test "json.test.n_number_-2." { err( \\[-2.] ); } -test "n_number_9.e+" { +test "json.test.n_number_9.e+" { err( \\[9.e+] ); } -test "n_number_expression" { +test "json.test.n_number_expression" { err( \\[1+2] ); } -test "n_number_hex_1_digit" { +test "json.test.n_number_hex_1_digit" { err( \\[0x1] ); } -test "n_number_hex_2_digits" { +test "json.test.n_number_hex_2_digits" { err( \\[0x42] ); } -test "n_number_infinity" { +test "json.test.n_number_infinity" { err( \\[Infinity] ); } -test "n_number_+Inf" { +test "json.test.n_number_+Inf" { err( \\[+Inf] ); } -test "n_number_Inf" { +test "json.test.n_number_Inf" { err( \\[Inf] ); } -test "n_number_invalid+-" { +test "json.test.n_number_invalid+-" { err( \\[0e+-1] ); } -test "n_number_invalid-negative-real" { +test "json.test.n_number_invalid-negative-real" { err( \\[-123.123foo] ); } -test "n_number_invalid-utf-8-in-bigger-int" { +test "json.test.n_number_invalid-utf-8-in-bigger-int" { err( \\[123å] ); } -test "n_number_invalid-utf-8-in-exponent" { +test "json.test.n_number_invalid-utf-8-in-exponent" { err( \\[1e1å] ); } -test "n_number_invalid-utf-8-in-int" { +test "json.test.n_number_invalid-utf-8-in-int" { err( \\[0å] ); } -test "n_number_++" { +test "json.test.n_number_++" { err( \\[++1234] ); } -test "n_number_minus_infinity" { +test "json.test.n_number_minus_infinity" { err( \\[-Infinity] ); } -test "n_number_minus_sign_with_trailing_garbage" { +test "json.test.n_number_minus_sign_with_trailing_garbage" { err( \\[-foo] ); } -test "n_number_minus_space_1" { +test "json.test.n_number_minus_space_1" { err( \\[- 1] ); } -test "n_number_-NaN" { +test "json.test.n_number_-NaN" { err( \\[-NaN] ); } -test "n_number_NaN" { +test "json.test.n_number_NaN" { err( \\[NaN] ); } -test "n_number_neg_int_starting_with_zero" { +test "json.test.n_number_neg_int_starting_with_zero" { err( \\[-012] ); } -test "n_number_neg_real_without_int_part" { +test "json.test.n_number_neg_real_without_int_part" { err( \\[-.123] ); } -test "n_number_neg_with_garbage_at_end" { +test "json.test.n_number_neg_with_garbage_at_end" { err( \\[-1x] ); } -test "n_number_real_garbage_after_e" { +test "json.test.n_number_real_garbage_after_e" { err( \\[1ea] ); } -test "n_number_real_with_invalid_utf8_after_e" { +test "json.test.n_number_real_with_invalid_utf8_after_e" { err( \\[1eå] ); } -test "n_number_real_without_fractional_part" { +test "json.test.n_number_real_without_fractional_part" { err( \\[1.] ); } -test "n_number_starting_with_dot" { +test "json.test.n_number_starting_with_dot" { err( \\[.123] ); } -test "n_number_U+FF11_fullwidth_digit_one" { +test "json.test.n_number_U+FF11_fullwidth_digit_one" { err( \\[ï¼] ); } -test "n_number_with_alpha_char" { +test "json.test.n_number_with_alpha_char" { err( \\[1.8011670033376514H-308] ); } -test "n_number_with_alpha" { +test "json.test.n_number_with_alpha" { err( \\[1.2a-3] ); } -test "n_number_with_leading_zero" { +test "json.test.n_number_with_leading_zero" { err( \\[012] ); } -test "n_object_bad_value" { +test "json.test.n_object_bad_value" { err( \\["x", truth] ); } -test "n_object_bracket_key" { +test "json.test.n_object_bracket_key" { err( \\{[: "x"} ); } -test "n_object_comma_instead_of_colon" { +test "json.test.n_object_comma_instead_of_colon" { err( \\{"x", null} ); } -test "n_object_double_colon" { +test "json.test.n_object_double_colon" { err( \\{"x"::"b"} ); } -test "n_object_emoji" { +test "json.test.n_object_emoji" { err( \\{ð¨ð} ); } -test "n_object_garbage_at_end" { +test "json.test.n_object_garbage_at_end" { err( \\{"a":"a" 123} ); } -test "n_object_key_with_single_quotes" { +test "json.test.n_object_key_with_single_quotes" { err( \\{key: 'value'} ); } -test "n_object_lone_continuation_byte_in_key_and_trailing_comma" { +test "json.test.n_object_lone_continuation_byte_in_key_and_trailing_comma" { err( \\{"¹":"0",} ); } -test "n_object_missing_colon" { +test "json.test.n_object_missing_colon" { err( \\{"a" b} ); } -test "n_object_missing_key" { +test "json.test.n_object_missing_key" { err( \\{:"b"} ); } -test "n_object_missing_semicolon" { +test "json.test.n_object_missing_semicolon" { err( \\{"a" "b"} ); } -test "n_object_missing_value" { +test "json.test.n_object_missing_value" { err( \\{"a": ); } -test "n_object_no-colon" { +test "json.test.n_object_no-colon" { err( \\{"a" ); } -test "n_object_non_string_key_but_huge_number_instead" { +test "json.test.n_object_non_string_key_but_huge_number_instead" { err( \\{9999E9999:1} ); } -test "n_object_non_string_key" { +test "json.test.n_object_non_string_key" { err( \\{1:1} ); } -test "n_object_repeated_null_null" { +test "json.test.n_object_repeated_null_null" { err( \\{null:null,null:null} ); } -test "n_object_several_trailing_commas" { +test "json.test.n_object_several_trailing_commas" { err( \\{"id":0,,,,,} ); } -test "n_object_single_quote" { +test "json.test.n_object_single_quote" { err( \\{'a':0} ); } -test "n_object_trailing_comma" { +test "json.test.n_object_trailing_comma" { err( \\{"id":0,} ); } -test "n_object_trailing_comment" { +test "json.test.n_object_trailing_comment" { err( \\{"a":"b"}/**/ ); } -test "n_object_trailing_comment_open" { +test "json.test.n_object_trailing_comment_open" { err( \\{"a":"b"}/**// ); } -test "n_object_trailing_comment_slash_open_incomplete" { +test "json.test.n_object_trailing_comment_slash_open_incomplete" { err( \\{"a":"b"}/ ); } -test "n_object_trailing_comment_slash_open" { +test "json.test.n_object_trailing_comment_slash_open" { err( \\{"a":"b"}// ); } -test "n_object_two_commas_in_a_row" { +test "json.test.n_object_two_commas_in_a_row" { err( \\{"a":"b",,"c":"d"} ); } -test "n_object_unquoted_key" { +test "json.test.n_object_unquoted_key" { err( \\{a: "b"} ); } -test "n_object_unterminated-value" { +test "json.test.n_object_unterminated-value" { err( \\{"a":"a ); } -test "n_object_with_single_string" { +test "json.test.n_object_with_single_string" { err( \\{ "foo" : "bar", "a" } ); } -test "n_object_with_trailing_garbage" { +test "json.test.n_object_with_trailing_garbage" { err( \\{"a":"b"}# ); } -test "n_single_space" { +test "json.test.n_single_space" { err(" "); } -test "n_string_1_surrogate_then_escape" { +test "json.test.n_string_1_surrogate_then_escape" { err( \\["\uD800\"] ); } -test "n_string_1_surrogate_then_escape_u1" { +test "json.test.n_string_1_surrogate_then_escape_u1" { err( \\["\uD800\u1"] ); } -test "n_string_1_surrogate_then_escape_u1x" { +test "json.test.n_string_1_surrogate_then_escape_u1x" { err( \\["\uD800\u1x"] ); } -test "n_string_1_surrogate_then_escape_u" { +test "json.test.n_string_1_surrogate_then_escape_u" { err( \\["\uD800\u"] ); } -test "n_string_accentuated_char_no_quotes" { +test "json.test.n_string_accentuated_char_no_quotes" { err( \\[é] ); } -test "n_string_backslash_00" { +test "json.test.n_string_backslash_00" { err("[\"\x00\"]"); } -test "n_string_escaped_backslash_bad" { +test "json.test.n_string_escaped_backslash_bad" { err( \\["\\\"] ); } -test "n_string_escaped_ctrl_char_tab" { +test "json.test.n_string_escaped_ctrl_char_tab" { err("\x5b\x22\x5c\x09\x22\x5d"); } -test "n_string_escaped_emoji" { +test "json.test.n_string_escaped_emoji" { err("[\"\x5c\xc3\xb0\xc2\x9f\xc2\x8c\xc2\x80\"]"); } -test "n_string_escape_x" { +test "json.test.n_string_escape_x" { err( \\["\x00"] ); } -test "n_string_incomplete_escaped_character" { +test "json.test.n_string_incomplete_escaped_character" { err( \\["\u00A"] ); } -test "n_string_incomplete_escape" { +test "json.test.n_string_incomplete_escape" { err( \\["\"] ); } -test "n_string_incomplete_surrogate_escape_invalid" { +test "json.test.n_string_incomplete_surrogate_escape_invalid" { err( \\["\uD800\uD800\x"] ); } -test "n_string_incomplete_surrogate" { +test "json.test.n_string_incomplete_surrogate" { err( \\["\uD834\uDd"] ); } -test "n_string_invalid_backslash_esc" { +test "json.test.n_string_invalid_backslash_esc" { err( \\["\a"] ); } -test "n_string_invalid_unicode_escape" { +test "json.test.n_string_invalid_unicode_escape" { err( \\["\uqqqq"] ); } -test "n_string_invalid_utf8_after_escape" { +test "json.test.n_string_invalid_utf8_after_escape" { err("[\"\\\x75\xc3\xa5\"]"); } -test "n_string_invalid-utf-8-in-escape" { +test "json.test.n_string_invalid-utf-8-in-escape" { err( \\["\uå"] ); } -test "n_string_leading_uescaped_thinspace" { +test "json.test.n_string_leading_uescaped_thinspace" { err( \\[\u0020"asd"] ); } -test "n_string_no_quotes_with_bad_escape" { +test "json.test.n_string_no_quotes_with_bad_escape" { err( \\[\n] ); } -test "n_string_single_doublequote" { +test "json.test.n_string_single_doublequote" { err( \\" ); } -test "n_string_single_quote" { +test "json.test.n_string_single_quote" { err( \\['single quote'] ); } -test "n_string_single_string_no_double_quotes" { +test "json.test.n_string_single_string_no_double_quotes" { err( \\abc ); } -test "n_string_start_escape_unclosed" { +test "json.test.n_string_start_escape_unclosed" { err( \\["\ ); } -test "n_string_unescaped_crtl_char" { +test "json.test.n_string_unescaped_crtl_char" { err("[\"a\x00a\"]"); } -test "n_string_unescaped_newline" { +test "json.test.n_string_unescaped_newline" { err( \\["new \\line"] ); } -test "n_string_unescaped_tab" { +test "json.test.n_string_unescaped_tab" { err("[\"\t\"]"); } -test "n_string_unicode_CapitalU" { +test "json.test.n_string_unicode_CapitalU" { err( \\"\UA66D" ); } -test "n_string_with_trailing_garbage" { +test "json.test.n_string_with_trailing_garbage" { err( \\""x ); } -test "n_structure_100000_opening_arrays" { +test "json.test.n_structure_100000_opening_arrays" { err("[" ** 100000); } -test "n_structure_angle_bracket_." { +test "json.test.n_structure_angle_bracket_." { err( \\<.> ); } -test "n_structure_angle_bracket_null" { +test "json.test.n_structure_angle_bracket_null" { err( \\[<null>] ); } -test "n_structure_array_trailing_garbage" { +test "json.test.n_structure_array_trailing_garbage" { err( \\[1]x ); } -test "n_structure_array_with_extra_array_close" { +test "json.test.n_structure_array_with_extra_array_close" { err( \\[1]] ); } -test "n_structure_array_with_unclosed_string" { +test "json.test.n_structure_array_with_unclosed_string" { err( \\["asd] ); } -test "n_structure_ascii-unicode-identifier" { +test "json.test.n_structure_ascii-unicode-identifier" { err( \\aÃ¥ ); } -test "n_structure_capitalized_True" { +test "json.test.n_structure_capitalized_True" { err( \\[True] ); } -test "n_structure_close_unopened_array" { +test "json.test.n_structure_close_unopened_array" { err( \\1] ); } -test "n_structure_comma_instead_of_closing_brace" { +test "json.test.n_structure_comma_instead_of_closing_brace" { err( \\{"x": true, ); } -test "n_structure_double_array" { +test "json.test.n_structure_double_array" { err( \\[][] ); } -test "n_structure_end_array" { +test "json.test.n_structure_end_array" { err( \\] ); } -test "n_structure_incomplete_UTF8_BOM" { +test "json.test.n_structure_incomplete_UTF8_BOM" { err( \\ï»{} ); } -test "n_structure_lone-invalid-utf-8" { +test "json.test.n_structure_lone-invalid-utf-8" { err( \\å ); } -test "n_structure_lone-open-bracket" { +test "json.test.n_structure_lone-open-bracket" { err( \\[ ); } -test "n_structure_no_data" { +test "json.test.n_structure_no_data" { err( \\ ); } -test "n_structure_null-byte-outside-string" { +test "json.test.n_structure_null-byte-outside-string" { err("[\x00]"); } -test "n_structure_number_with_trailing_garbage" { +test "json.test.n_structure_number_with_trailing_garbage" { err( \\2@ ); } -test "n_structure_object_followed_by_closing_object" { +test "json.test.n_structure_object_followed_by_closing_object" { err( \\{}} ); } -test "n_structure_object_unclosed_no_value" { +test "json.test.n_structure_object_unclosed_no_value" { err( \\{"": ); } -test "n_structure_object_with_comment" { +test "json.test.n_structure_object_with_comment" { err( \\{"a":/*comment*/"b"} ); } -test "n_structure_object_with_trailing_garbage" { +test "json.test.n_structure_object_with_trailing_garbage" { err( \\{"a": true} "x" ); } -test "n_structure_open_array_apostrophe" { +test "json.test.n_structure_open_array_apostrophe" { err( \\[' ); } -test "n_structure_open_array_comma" { +test "json.test.n_structure_open_array_comma" { err( \\[, ); } -test "n_structure_open_array_object" { +test "json.test.n_structure_open_array_object" { err("[{\"\":" ** 50000); } -test "n_structure_open_array_open_object" { +test "json.test.n_structure_open_array_open_object" { err( \\[{ ); } -test "n_structure_open_array_open_string" { +test "json.test.n_structure_open_array_open_string" { err( \\["a ); } -test "n_structure_open_array_string" { +test "json.test.n_structure_open_array_string" { err( \\["a" ); } -test "n_structure_open_object_close_array" { +test "json.test.n_structure_open_object_close_array" { err( \\{] ); } -test "n_structure_open_object_comma" { +test "json.test.n_structure_open_object_comma" { err( \\{, ); } -test "n_structure_open_object" { +test "json.test.n_structure_open_object" { err( \\{ ); } -test "n_structure_open_object_open_array" { +test "json.test.n_structure_open_object_open_array" { err( \\{[ ); } -test "n_structure_open_object_open_string" { +test "json.test.n_structure_open_object_open_string" { err( \\{"a ); } -test "n_structure_open_object_string_with_apostrophes" { +test "json.test.n_structure_open_object_string_with_apostrophes" { err( \\{'a' ); } -test "n_structure_open_open" { +test "json.test.n_structure_open_open" { err( \\["\{["\{["\{["\{ ); } -test "n_structure_single_eacute" { +test "json.test.n_structure_single_eacute" { err( \\é ); } -test "n_structure_single_star" { +test "json.test.n_structure_single_star" { err( \\* ); } -test "n_structure_trailing_#" { +test "json.test.n_structure_trailing_#" { err( \\{"a":"b"}#{} ); } -test "n_structure_U+2060_word_joined" { +test "json.test.n_structure_U+2060_word_joined" { err( \\[â ] ); } -test "n_structure_uescaped_LF_before_string" { +test "json.test.n_structure_uescaped_LF_before_string" { err( \\[\u000A""] ); } -test "n_structure_unclosed_array" { +test "json.test.n_structure_unclosed_array" { err( \\[1 ); } -test "n_structure_unclosed_array_partial_null" { +test "json.test.n_structure_unclosed_array_partial_null" { err( \\[ false, nul ); } -test "n_structure_unclosed_array_unfinished_false" { +test "json.test.n_structure_unclosed_array_unfinished_false" { err( \\[ true, fals ); } -test "n_structure_unclosed_array_unfinished_true" { +test "json.test.n_structure_unclosed_array_unfinished_true" { err( \\[ false, tru ); } -test "n_structure_unclosed_object" { +test "json.test.n_structure_unclosed_object" { err( \\{"asd":"asd" ); } -test "n_structure_unicode-identifier" { +test "json.test.n_structure_unicode-identifier" { err( \\Ã¥ ); } -test "n_structure_UTF8_BOM_no_data" { +test "json.test.n_structure_UTF8_BOM_no_data" { err( \\ ); } -test "n_structure_whitespace_formfeed" { +test "json.test.n_structure_whitespace_formfeed" { err("[\x0c]"); } -test "n_structure_whitespace_U+2060_word_joiner" { +test "json.test.n_structure_whitespace_U+2060_word_joiner" { err( \\[â ] ); @@ -1701,203 +1701,203 @@ test "n_structure_whitespace_U+2060_word_joiner" { //////////////////////////////////////////////////////////////////////////////////////////////////// -test "i_number_double_huge_neg_exp" { +test "json.test.i_number_double_huge_neg_exp" { any( \\[123.456e-789] ); } -test "i_number_huge_exp" { +test "json.test.i_number_huge_exp" { any( \\[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006] ); } -test "i_number_neg_int_huge_exp" { +test "json.test.i_number_neg_int_huge_exp" { any( \\[-1e+9999] ); } -test "i_number_pos_double_huge_exp" { +test "json.test.i_number_pos_double_huge_exp" { any( \\[1.5e+9999] ); } -test "i_number_real_neg_overflow" { +test "json.test.i_number_real_neg_overflow" { any( \\[-123123e100000] ); } -test "i_number_real_pos_overflow" { +test "json.test.i_number_real_pos_overflow" { any( \\[123123e100000] ); } -test "i_number_real_underflow" { +test "json.test.i_number_real_underflow" { any( \\[123e-10000000] ); } -test "i_number_too_big_neg_int" { +test "json.test.i_number_too_big_neg_int" { any( \\[-123123123123123123123123123123] ); } -test "i_number_too_big_pos_int" { +test "json.test.i_number_too_big_pos_int" { any( \\[100000000000000000000] ); } -test "i_number_very_big_negative_int" { +test "json.test.i_number_very_big_negative_int" { any( \\[-237462374673276894279832749832423479823246327846] ); } -test "i_object_key_lone_2nd_surrogate" { +test "json.test.i_object_key_lone_2nd_surrogate" { any( \\{"\uDFAA":0} ); } -test "i_string_1st_surrogate_but_2nd_missing" { +test "json.test.i_string_1st_surrogate_but_2nd_missing" { any( \\["\uDADA"] ); } -test "i_string_1st_valid_surrogate_2nd_invalid" { +test "json.test.i_string_1st_valid_surrogate_2nd_invalid" { any( \\["\uD888\u1234"] ); } -test "i_string_incomplete_surrogate_and_escape_valid" { +test "json.test.i_string_incomplete_surrogate_and_escape_valid" { any( \\["\uD800\n"] ); } -test "i_string_incomplete_surrogate_pair" { +test "json.test.i_string_incomplete_surrogate_pair" { any( \\["\uDd1ea"] ); } -test "i_string_incomplete_surrogates_escape_valid" { +test "json.test.i_string_incomplete_surrogates_escape_valid" { any( \\["\uD800\uD800\n"] ); } -test "i_string_invalid_lonely_surrogate" { +test "json.test.i_string_invalid_lonely_surrogate" { any( \\["\ud800"] ); } -test "i_string_invalid_surrogate" { +test "json.test.i_string_invalid_surrogate" { any( \\["\ud800abc"] ); } -test "i_string_invalid_utf-8" { +test "json.test.i_string_invalid_utf-8" { any( \\["ÿ"] ); } -test "i_string_inverted_surrogates_U+1D11E" { +test "json.test.i_string_inverted_surrogates_U+1D11E" { any( \\["\uDd1e\uD834"] ); } -test "i_string_iso_latin_1" { +test "json.test.i_string_iso_latin_1" { any( \\["é"] ); } -test "i_string_lone_second_surrogate" { +test "json.test.i_string_lone_second_surrogate" { any( \\["\uDFAA"] ); } -test "i_string_lone_utf8_continuation_byte" { +test "json.test.i_string_lone_utf8_continuation_byte" { any( \\[""] ); } -test "i_string_not_in_unicode_range" { +test "json.test.i_string_not_in_unicode_range" { any( \\["ô¿¿¿"] ); } -test "i_string_overlong_sequence_2_bytes" { +test "json.test.i_string_overlong_sequence_2_bytes" { any( \\["À¯"] ); } -test "i_string_overlong_sequence_6_bytes" { +test "json.test.i_string_overlong_sequence_6_bytes" { any( \\["ü¿¿¿¿"] ); } -test "i_string_overlong_sequence_6_bytes_null" { +test "json.test.i_string_overlong_sequence_6_bytes_null" { any( \\["ü"] ); } -test "i_string_truncated-utf-8" { +test "json.test.i_string_truncated-utf-8" { any( \\["àÿ"] ); } -test "i_string_utf16BE_no_BOM" { +test "json.test.i_string_utf16BE_no_BOM" { any("\x00\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d"); } -test "i_string_utf16LE_no_BOM" { +test "json.test.i_string_utf16LE_no_BOM" { any("\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-16LE_with_BOM" { +test "json.test.i_string_UTF-16LE_with_BOM" { any("\xc3\xbf\xc3\xbe\x5b\x00\x22\x00\xc3\xa9\x00\x22\x00\x5d\x00"); } -test "i_string_UTF-8_invalid_sequence" { +test "json.test.i_string_UTF-8_invalid_sequence" { any( \\["æ¥Ñú"] ); } -test "i_string_UTF8_surrogate_U+D800" { +test "json.test.i_string_UTF8_surrogate_U+D800" { any( \\["í "] ); } -test "i_structure_500_nested_arrays" { +test "json.test.i_structure_500_nested_arrays" { any(("[" ** 500) ++ ("]" ** 500)); } -test "i_structure_UTF-8_BOM_empty_object" { +test "json.test.i_structure_UTF-8_BOM_empty_object" { any( \\{} ); diff --git a/std/linked_list.zig b/std/linked_list.zig index 46cbeb03c4..c3db55b5a6 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { list.len += 1; } + /// Concatenate list2 onto the end of list1, removing all entries from the former. + /// + /// Arguments: + /// list1: the list to concatenate onto + /// list2: the list to be concatenated + pub fn concatByMoving(list1: *Self, list2: *Self) void { + const l2_first = list2.first orelse return; + if (list1.last) |l1_last| { + l1_last.next = list2.first; + l2_first.prev = list1.last; + list1.len += list2.len; + } else { + // list1 was empty + list1.first = list2.first; + list1.len = list2.len; + } + list1.last = list2.last; + list2.first = null; + list2.last = null; + list2.len = 0; + } + /// Insert a new node at the end of the list. /// /// Arguments: @@ -247,3 +269,77 @@ test "basic linked list test" { assert(list.last.?.data == 4); assert(list.len == 2); } + +test "linked list concatenation" { + const allocator = debug.global_allocator; + var list1 = LinkedList(u32).init(); + var list2 = LinkedList(u32).init(); + + var one = try list1.createNode(1, allocator); + defer list1.destroyNode(one, allocator); + var two = try list1.createNode(2, allocator); + defer list1.destroyNode(two, allocator); + var three = try list1.createNode(3, allocator); + defer list1.destroyNode(three, allocator); + var four = try list1.createNode(4, allocator); + defer list1.destroyNode(four, allocator); + var five = try list1.createNode(5, allocator); + defer list1.destroyNode(five, allocator); + + list1.append(one); + list1.append(two); + list2.append(three); + list2.append(four); + list2.append(five); + + list1.concatByMoving(&list2); + + assert(list1.last == five); + assert(list1.len == 5); + assert(list2.first == null); + assert(list2.last == null); + assert(list2.len == 0); + + // Traverse forwards. + { + var it = list1.first; + var index: u32 = 1; + while (it) |node| : (it = node.next) { + assert(node.data == index); + index += 1; + } + } + + // Traverse backwards. + { + var it = list1.last; + var index: u32 = 1; + while (it) |node| : (it = node.prev) { + assert(node.data == (6 - index)); + index += 1; + } + } + + // Swap them back, this verifies that concating to an empty list works. + list2.concatByMoving(&list1); + + // Traverse forwards. + { + var it = list2.first; + var index: u32 = 1; + while (it) |node| : (it = node.next) { + assert(node.data == index); + index += 1; + } + } + + // Traverse backwards. + { + var it = list2.last; + var index: u32 = 1; + while (it) |node| : (it = node.prev) { + assert(node.data == (6 - index)); + index += 1; + } + } +} diff --git a/std/math/index.zig b/std/math/index.zig index de09a6e944..f37de2505b 100644 --- a/std/math/index.zig +++ b/std/math/index.zig @@ -6,6 +6,13 @@ const assert = std.debug.assert; pub const e = 2.71828182845904523536028747135266249775724709369995; pub const pi = 3.14159265358979323846264338327950288419716939937510; +// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128) +pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001)); +pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000)); +pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); +pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000)); +pub const f128_toint = 1.0 / f128_epsilon; + // float.h details pub const f64_true_min = 4.94065645841246544177e-324; pub const f64_min = 2.2250738585072014e-308; @@ -365,6 +372,69 @@ pub fn Log2Int(comptime T: type) type { return @IntType(false, count); } +pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type { + assert(from <= to); + if (from == 0 and to == 0) { + return u0; + } + const is_signed = from < 0; + const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement + const base = log2(largest_positive_integer); + const upper = (1 << base) - 1; + var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1; + if (is_signed) { + magnitude_bits += 1; + } + return @IntType(is_signed, magnitude_bits); +} + +test "math.IntFittingRange" { + assert(IntFittingRange(0, 0) == u0); + assert(IntFittingRange(0, 1) == u1); + assert(IntFittingRange(0, 2) == u2); + assert(IntFittingRange(0, 3) == u2); + assert(IntFittingRange(0, 4) == u3); + assert(IntFittingRange(0, 7) == u3); + assert(IntFittingRange(0, 8) == u4); + assert(IntFittingRange(0, 9) == u4); + assert(IntFittingRange(0, 15) == u4); + assert(IntFittingRange(0, 16) == u5); + assert(IntFittingRange(0, 17) == u5); + assert(IntFittingRange(0, 4095) == u12); + assert(IntFittingRange(2000, 4095) == u12); + assert(IntFittingRange(0, 4096) == u13); + assert(IntFittingRange(2000, 4096) == u13); + assert(IntFittingRange(0, 4097) == u13); + assert(IntFittingRange(2000, 4097) == u13); + assert(IntFittingRange(0, 123456789123456798123456789) == u87); + assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177); + + assert(IntFittingRange(-1, -1) == i1); + assert(IntFittingRange(-1, 0) == i1); + assert(IntFittingRange(-1, 1) == i2); + assert(IntFittingRange(-2, -2) == i2); + assert(IntFittingRange(-2, -1) == i2); + assert(IntFittingRange(-2, 0) == i2); + assert(IntFittingRange(-2, 1) == i2); + assert(IntFittingRange(-2, 2) == i3); + assert(IntFittingRange(-1, 2) == i3); + assert(IntFittingRange(-1, 3) == i3); + assert(IntFittingRange(-1, 4) == i4); + assert(IntFittingRange(-1, 7) == i4); + assert(IntFittingRange(-1, 8) == i5); + assert(IntFittingRange(-1, 9) == i5); + assert(IntFittingRange(-1, 15) == i5); + assert(IntFittingRange(-1, 16) == i6); + assert(IntFittingRange(-1, 17) == i6); + assert(IntFittingRange(-1, 4095) == i13); + assert(IntFittingRange(-4096, 4095) == i13); + assert(IntFittingRange(-1, 4096) == i14); + assert(IntFittingRange(-4097, 4095) == i14); + assert(IntFittingRange(-1, 4097) == i14); + assert(IntFittingRange(-1, 123456789123456798123456789) == i88); + assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178); +} + test "math overflow functions" { testOverflow(); comptime testOverflow(); diff --git a/std/mem.zig b/std/mem.zig index 6b37dfe401..fb5f6fd5da 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -410,12 +410,8 @@ test "mem.indexOf" { /// Reads an integer from memory with size equal to bytes.len. /// T specifies the return type, which must be large enough to store /// the result. -/// See also ::readIntBE or ::readIntLE. -pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T { - if (T.bit_count == 8) { - return bytes[0]; - } - var result: T = 0; +pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType { + var result: ReturnType = 0; switch (endian) { builtin.Endian.Big => { for (bytes) |b| { @@ -423,172 +419,270 @@ pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T { } }, builtin.Endian.Little => { - const ShiftType = math.Log2Int(T); + const ShiftType = math.Log2Int(ReturnType); for (bytes) |b, index| { - result = result | (T(b) << @intCast(ShiftType, index * 8)); + result = result | (ReturnType(b) << @intCast(ShiftType, index * 8)); } }, } return result; } -/// Reads a big-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntBE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes)); - } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result = (result << 8) | T(bytes[i]); - } +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + comptime assert(T.bit_count % 8 == 0); + return @ptrCast(*align(1) const T, bytes).*; +} + +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T { + return @bswap(T, readIntNative(T, bytes)); +} + +pub const readIntLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntNative, + builtin.Endian.Big => readIntForeign, +}; + +pub const readIntBig = switch (builtin.endian) { + builtin.Endian.Little => readIntForeign, + builtin.Endian.Big => readIntNative, +}; + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is native. This means the function can +/// simply pointer cast memory. +pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr)); +} + +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Assumes the endianness of memory is foreign, so it must byte-swap. +pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T { + return @bswap(T, readIntSliceNative(T, bytes)); +} + +pub const readIntSliceLittle = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceNative, + builtin.Endian.Big => readIntSliceForeign, +}; + +pub const readIntSliceBig = switch (builtin.endian) { + builtin.Endian.Little => readIntSliceForeign, + builtin.Endian.Big => readIntSliceNative, +}; + +/// Reads an integer from memory with bit count specified by T. +/// The bit count of T must be evenly divisible by 8. +/// This function cannot fail and cannot cause undefined behavior. +pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T { + if (endian == builtin.endian) { + return readIntNative(T, bytes); + } else { + return readIntForeign(T, bytes); } - return result; } -/// Reads a little-endian int of type T from bytes. -/// bytes.len must be exactly @sizeOf(T). -pub fn readIntLE(comptime T: type, bytes: []const u8) T { - if (T.is_signed) { - return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes)); +/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0 +/// and ignores extra bytes. +/// Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { + assert(@sizeOf(u24) == 3); + assert(bytes.len >= @sizeOf(T)); + // TODO https://github.com/ziglang/zig/issues/863 + return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian); +} + +test "comptime read/write int" { + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntLittle(u16, &bytes, 0x1234); + const result = std.mem.readIntBig(u16, &bytes); + std.debug.assert(result == 0x3412); } - assert(bytes.len == @sizeOf(T)); - if (T == u8) return bytes[0]; - var result: T = 0; - { - comptime var i = 0; - inline while (i < @sizeOf(T)) : (i += 1) { - result |= T(bytes[i]) << i * 8; - } + comptime { + var bytes: [2]u8 = undefined; + std.mem.writeIntBig(u16, &bytes, 0x1234); + const result = std.mem.readIntLittle(u16, &bytes); + std.debug.assert(result == 0x3412); } - return result; } -test "readIntBE/LE" { - assert(readIntBE(u0, []u8{}) == 0x0); - assert(readIntLE(u0, []u8{}) == 0x0); +test "readIntBig and readIntLittle" { + assert(readIntSliceBig(u0, []u8{}) == 0x0); + assert(readIntSliceLittle(u0, []u8{}) == 0x0); - assert(readIntBE(u8, []u8{0x32}) == 0x32); - assert(readIntLE(u8, []u8{0x12}) == 0x12); + assert(readIntSliceBig(u8, []u8{0x32}) == 0x32); + assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12); - assert(readIntBE(u16, []u8{0x12, 0x34}) == 0x1234); - assert(readIntLE(u16, []u8{0x12, 0x34}) == 0x3412); + assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234); + assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412); - assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); - assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); + assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024); + assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec); - assert(readIntBE(i8, []u8{0xff}) == -1); - assert(readIntLE(i8, []u8{0xfe}) == -2); + assert(readIntSliceBig(i8, []u8{0xff}) == -1); + assert(readIntSliceLittle(i8, []u8{0xfe}) == -2); - assert(readIntBE(i16, []u8{0xff, 0xfd}) == -3); - assert(readIntLE(i16, []u8{0xfc, 0xff}) == -4); + assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3); + assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4); } -/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes -/// to fill the entire buffer provided. -/// value must be an integer. -pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void { - const uint = @IntType(false, @typeOf(value).bit_count); - var bits = @truncate(uint, value); - switch (endian) { - builtin.Endian.Big => { - var index: usize = buf.len; - while (index != 0) { - index -= 1; +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, and +/// accepts any integer bit width. +/// This function stores in native endian, which means it is implemented as a simple +/// memory store. +pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + @ptrCast(*align(1) T, buf).* = value; +} - buf[index] = @truncate(u8, bits); - bits >>= 8; - } - }, - builtin.Endian.Little => { - for (buf) |*b| { - b.* = @truncate(u8, bits); - bits >>= 8; - } - }, +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +/// This function stores in foreign endian, which means it does a @bswap first. +pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { + writeIntNative(T, buf, @bswap(T, value)); +} + +pub const writeIntLittle = switch (builtin.endian) { + builtin.Endian.Little => writeIntNative, + builtin.Endian.Big => writeIntForeign, +}; + +pub const writeIntBig = switch (builtin.endian) { + builtin.Endian.Little => writeIntForeign, + builtin.Endian.Big => writeIntNative, +}; + +/// Writes an integer to memory, storing it in twos-complement. +/// This function always succeeds, has defined behavior for all inputs, but +/// the integer bit width must be divisible by 8. +pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + if (endian == builtin.endian) { + return writeIntNative(T, buffer, value); + } else { + return writeIntForeign(T, buffer, value); } - assert(bits == 0); } -pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); +/// Writes a twos-complement little-endian integer to memory. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer after writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntLittle +/// instead. +pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; + var bits = @truncate(uint, value); + for (buffer) |*b| { + b.* = @truncate(u8, bits); + bits >>= 8; } - var index: usize = buf.len; +} + +/// Writes a twos-complement big-endian integer to memory. +/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be divisible by 8. +/// Any extra bytes in buffer before writing the integer are set to zero. To +/// avoid the branch to check for extra buffer bytes, use writeIntBig instead. +pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void { + comptime assert(@sizeOf(u24) == 3); + comptime assert(T.bit_count % 8 == 0); + assert(buffer.len >= @sizeOf(T)); + + // TODO I want to call writeIntBig here but comptime eval facilities aren't good enough + const uint = @IntType(false, T.bit_count); + var bits = @truncate(uint, value); + var index: usize = buffer.len; while (index != 0) { index -= 1; - - buf[index] = @truncate(u8, bits); + buffer[index] = @truncate(u8, bits); bits >>= 8; } - assert(bits == 0); } -pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void { - assert(T.bit_count % 8 == 0); - const uint = @IntType(false, T.bit_count); - if (uint == u0) { - return; - } - var bits = @bitCast(uint, value); - if (uint == u8) { - buf[0] = bits; - return; - } - // FIXME: this should just be for (buf). - // See https://github.com/ziglang/zig/issues/1663 - for (buf.*) |*b| { - b.* = @truncate(u8, bits); - bits >>= 8; +pub const writeIntSliceNative = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceLittle, + builtin.Endian.Big => writeIntSliceBig, +}; + +pub const writeIntSliceForeign = switch (builtin.endian) { + builtin.Endian.Little => writeIntSliceBig, + builtin.Endian.Big => writeIntSliceLittle, +}; + +/// Writes a twos-complement integer to memory, with the specified endianness. +/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3. +/// The bit count of T must be evenly divisible by 8. +/// Any extra bytes in buffer not part of the integer are set to zero, with +/// respect to endianness. To avoid the branch to check for extra buffer bytes, +/// use writeInt instead. +pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void { + comptime assert(T.bit_count % 8 == 0); + switch (endian) { + builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value), + builtin.Endian.Big => return writeIntSliceBig(T, buffer, value), } - assert(bits == 0); } -test "writeIntBE/LE" { +test "writeIntBig and writeIntLittle" { var buf0: [0]u8 = undefined; var buf1: [1]u8 = undefined; var buf2: [2]u8 = undefined; var buf9: [9]u8 = undefined; - writeIntBE(u0, &buf0, 0x0); + writeIntBig(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntLE(u0, &buf0, 0x0); + writeIntLittle(u0, &buf0, 0x0); assert(eql_slice_u8(buf0[0..], []u8{})); - writeIntBE(u8, &buf1, 0x12); + writeIntBig(u8, &buf1, 0x12); assert(eql_slice_u8(buf1[0..], []u8{0x12})); - writeIntLE(u8, &buf1, 0x34); + writeIntLittle(u8, &buf1, 0x34); assert(eql_slice_u8(buf1[0..], []u8{0x34})); - writeIntBE(u16, &buf2, 0x1234); + writeIntBig(u16, &buf2, 0x1234); assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 })); - writeIntLE(u16, &buf2, 0x5678); + writeIntLittle(u16, &buf2, 0x5678); assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 })); - writeIntBE(u72, &buf9, 0x123456789abcdef024); + writeIntBig(u72, &buf9, 0x123456789abcdef024); assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 })); - writeIntLE(u72, &buf9, 0xfedcba9876543210ec); + writeIntLittle(u72, &buf9, 0xfedcba9876543210ec); assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe })); - writeIntBE(i8, &buf1, -1); + writeIntBig(i8, &buf1, -1); assert(eql_slice_u8(buf1[0..], []u8{0xff})); - writeIntLE(i8, &buf1, -2); + writeIntLittle(i8, &buf1, -2); assert(eql_slice_u8(buf1[0..], []u8{0xfe})); - writeIntBE(i16, &buf2, -3); + writeIntBig(i16, &buf2, -3); assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd })); - writeIntLE(i16, &buf2, -4); + writeIntLittle(i16, &buf2, -4); assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff })); } @@ -737,12 +831,12 @@ fn testReadIntImpl() void { 0x56, 0x78, }; - assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); - assert(readIntBE(u32, bytes) == 0x12345678); - assert(readIntBE(i32, bytes) == 0x12345678); - assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); - assert(readIntLE(u32, bytes) == 0x78563412); - assert(readIntLE(i32, bytes) == 0x78563412); + assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678); + assert(readIntBig(u32, &bytes) == 0x12345678); + assert(readIntBig(i32, &bytes) == 0x12345678); + assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412); + assert(readIntLittle(u32, &bytes) == 0x78563412); + assert(readIntLittle(i32, &bytes) == 0x78563412); } { const buf = []u8{ @@ -751,7 +845,7 @@ fn testReadIntImpl() void { 0x12, 0x34, }; - const answer = readInt(buf, u64, builtin.Endian.Big); + const answer = readInt(u32, &buf, builtin.Endian.Big); assert(answer == 0x00001234); } { @@ -761,7 +855,7 @@ fn testReadIntImpl() void { 0x00, 0x00, }; - const answer = readInt(buf, u64, builtin.Endian.Little); + const answer = readInt(u32, &buf, builtin.Endian.Little); assert(answer == 0x00003412); } { @@ -769,21 +863,33 @@ fn testReadIntImpl() void { 0xff, 0xfe, }; - assert(readIntBE(u16, bytes) == 0xfffe); - assert(readIntBE(i16, bytes) == -0x0002); - assert(readIntLE(u16, bytes) == 0xfeff); - assert(readIntLE(i16, bytes) == -0x0101); + assert(readIntBig(u16, &bytes) == 0xfffe); + assert(readIntBig(i16, &bytes) == -0x0002); + assert(readIntLittle(u16, &bytes) == 0xfeff); + assert(readIntLittle(i16, &bytes) == -0x0101); } } -test "testWriteInt" { +test "std.mem.writeIntSlice" { testWriteIntImpl(); comptime testWriteIntImpl(); } fn testWriteIntImpl() void { var bytes: [8]u8 = undefined; - writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big); + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little); + assert(eql(u8, bytes, []u8{ + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + })); + + writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -795,7 +901,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little); + writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -807,7 +913,7 @@ fn testWriteIntImpl() void { 0xBE, })); - writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); + writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -819,7 +925,7 @@ fn testWriteIntImpl() void { 0x78, })); - writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); + writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x12, 0x34, @@ -831,7 +937,7 @@ fn testWriteIntImpl() void { 0x00, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big); assert(eql(u8, bytes, []u8{ 0x00, 0x00, @@ -843,7 +949,7 @@ fn testWriteIntImpl() void { 0x34, })); - writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); + writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little); assert(eql(u8, bytes, []u8{ 0x34, 0x12, @@ -941,29 +1047,52 @@ test "std.mem.rotate" { })); } -// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by -// endian-casting the pointer and then dereferencing +/// Converts a little-endian integer to host endianness. +pub fn littleToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; +} -pub fn endianSwapIfLe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Little, T, x); +/// Converts a big-endian integer to host endianness. +pub fn bigToNative(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } -pub fn endianSwapIfBe(comptime T: type, x: T) T { - return endianSwapIf(builtin.Endian.Big, T, x); +/// Converts an integer from specified endianness to host endianness. +pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T { + return switch (endianness_of_x) { + builtin.Endian.Little => littleToNative(T, x), + builtin.Endian.Big => bigToNative(T, x), + }; } -pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T { - return if (builtin.endian == endian) endianSwap(T, x) else x; +/// Converts an integer which has host endianness to the desired endianness. +pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T { + return switch (desired_endianness) { + builtin.Endian.Little => nativeToLittle(T, x), + builtin.Endian.Big => nativeToBig(T, x), + }; } -pub fn endianSwap(comptime T: type, x: T) T { - var buf: [@sizeOf(T)]u8 = undefined; - mem.writeInt(buf[0..], x, builtin.Endian.Little); - return mem.readInt(buf, T, builtin.Endian.Big); +/// Converts an integer which has host endianness to little endian. +pub fn nativeToLittle(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => x, + builtin.Endian.Big => @bswap(T, x), + }; } -test "std.mem.endianSwap" { - assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE); +/// Converts an integer which has host endianness to big endian. +pub fn nativeToBig(comptime T: type, x: T) T { + return switch (builtin.endian) { + builtin.Endian.Little => @bswap(T, x), + builtin.Endian.Big => x, + }; } fn AsBytesReturnType(comptime P: type) type { diff --git a/std/meta/index.zig b/std/meta/index.zig index 20e66fbe3d..69a3097288 100644 --- a/std/meta/index.zig +++ b/std/meta/index.zig @@ -76,6 +76,25 @@ test "std.meta.tagName" { debug.assert(mem.eql(u8, tagName(u2b), "D")); } +pub fn stringToEnum(comptime T: type, str: []const u8) ?T { + inline for (@typeInfo(T).Enum.fields) |enumField| { + if (std.mem.eql(u8, str, enumField.name)) { + return @field(T, enumField.name); + } + } + return null; +} + +test "std.meta.stringToEnum" { + const E1 = enum { + A, + B, + }; + debug.assert(E1.A == stringToEnum(E1, "A").?); + debug.assert(E1.B == stringToEnum(E1, "B").?); + debug.assert(null == stringToEnum(E1, "C")); +} + pub fn bitCount(comptime T: type) u32 { return switch (@typeInfo(T)) { TypeId.Int => |info| info.bits, @@ -483,3 +502,32 @@ test "std.meta.eql" { debug.assert(eql(EU.tst(false), EU.tst(false))); debug.assert(!eql(EU.tst(false), EU.tst(true))); } + +test "intToEnum with error return" { + const E1 = enum { + A, + }; + const E2 = enum { + A, + B, + }; + + var zero: u8 = 0; + var one: u16 = 1; + debug.assert(intToEnum(E1, zero) catch unreachable == E1.A); + debug.assert(intToEnum(E2, one) catch unreachable == E2.B); + debug.assertError(intToEnum(E1, one), error.InvalidEnumTag); +} + +pub const IntToEnumError = error{InvalidEnumTag}; + +pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag { + comptime var i = 0; + inline while (i != @memberCount(Tag)) : (i += 1) { + const this_tag_value = @field(Tag, @memberName(Tag, i)); + if (tag_int == @enumToInt(this_tag_value)) { + return this_tag_value; + } + } + return error.InvalidEnumTag; +} diff --git a/std/net.zig b/std/net.zig index 006a9d4ac5..968c1f019f 100644 --- a/std/net.zig +++ b/std/net.zig @@ -23,7 +23,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in = posix.sockaddr_in{ .family = posix.AF_INET, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .addr = ip4, .zero = []u8{0} ** 8, }, @@ -37,7 +37,7 @@ pub const Address = struct { .os_addr = posix.sockaddr{ .in6 = posix.sockaddr_in6{ .family = posix.AF_INET6, - .port = std.mem.endianSwapIfLe(u16, _port), + .port = mem.nativeToBig(u16, _port), .flowinfo = 0, .addr = ip6.addr, .scope_id = ip6.scope_id, @@ -47,7 +47,7 @@ pub const Address = struct { } pub fn port(self: Address) u16 { - return std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + return mem.bigToNative(u16, self.os_addr.in.port); } pub fn initPosix(addr: posix.sockaddr) Address { @@ -57,12 +57,12 @@ pub const Address = struct { pub fn format(self: *const Address, out_stream: var) !void { switch (self.os_addr.in.family) { posix.AF_INET => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port); const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]); try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port); }, posix.AF_INET6 => { - const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port); + const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port); try out_stream.print("[TODO render ip6 address]:{}", native_endian_port); }, else => try out_stream.write("(unrecognized address family)"), @@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr { } test "std.net.parseIp4" { - assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001)); + assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001)); testParseIp4Fail("256.0.0.1", error.Overflow); testParseIp4Fail("x.0.0.1", error.InvalidCharacter); diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 9361d78829..0aa896ff1b 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -390,6 +390,19 @@ pub const ChildProcess = struct { setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err); setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err); + if (self.stdin_behavior == StdIo.Pipe) { + os.close(stdin_pipe[0]); + os.close(stdin_pipe[1]); + } + if (self.stdout_behavior == StdIo.Pipe) { + os.close(stdout_pipe[0]); + os.close(stdout_pipe[1]); + } + if (self.stderr_behavior == StdIo.Pipe) { + os.close(stderr_pipe[0]); + os.close(stderr_pipe[1]); + } + if (self.cwd) |cwd| { os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err); } @@ -794,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8); fn writeIntFd(fd: i32, value: ErrInt) !void { const stream = &os.File.openHandle(fd).outStream().stream; - stream.writeIntNe(ErrInt, value) catch return error.SystemResources; + stream.writeIntNative(ErrInt, value) catch return error.SystemResources; } fn readIntFd(fd: i32) !ErrInt { const stream = &os.File.openHandle(fd).inStream().stream; - return stream.readIntNe(ErrInt) catch return error.SystemResources; + return stream.readIntNative(ErrInt) catch return error.SystemResources; } diff --git a/std/os/file.zig b/std/os/file.zig index 962428d4ca..2ae547c694 100644 --- a/std/os/file.zig +++ b/std/os/file.zig @@ -228,9 +228,16 @@ pub const File = struct { return os.isTty(self.handle); } - pub fn seekForward(self: File, amount: isize) !void { + pub const SeekError = error{ + /// TODO make this error impossible to get + Overflow, + Unseekable, + Unexpected, + }; + + pub fn seekForward(self: File, amount: isize) SeekError!void { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); const err = posix.getErrno(result); if (err > 0) { @@ -259,9 +266,9 @@ pub const File = struct { } } - pub fn seekTo(self: File, pos: usize) !void { + pub fn seekTo(self: File, pos: usize) SeekError!void { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const ipos = try math.cast(isize, pos); const result = posix.lseek(self.handle, ipos, posix.SEEK_SET); const err = posix.getErrno(result); @@ -293,9 +300,16 @@ pub const File = struct { } } - pub fn getPos(self: File) !usize { + pub const GetSeekPosError = error{ + Overflow, + SystemResources, + Unseekable, + Unexpected, + }; + + pub fn getPos(self: File) GetSeekPosError!usize { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); const err = posix.getErrno(result); if (err > 0) { @@ -323,13 +337,13 @@ pub const File = struct { } assert(pos >= 0); - return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange; + return math.cast(usize, pos); }, else => @compileError("unsupported OS"), } } - pub fn getEndPos(self: File) !usize { + pub fn getEndPos(self: File) GetSeekPosError!usize { if (is_posix) { const stat = try os.posixFStat(self.handle); return @intCast(usize, stat.size); @@ -431,6 +445,18 @@ pub const File = struct { }; } + pub fn seekableStream(file: File) SeekableStream { + return SeekableStream{ + .file = file, + .stream = SeekableStream.Stream{ + .seekToFn = SeekableStream.seekToFn, + .seekForwardFn = SeekableStream.seekForwardFn, + .getPosFn = SeekableStream.getPosFn, + .getEndPosFn = SeekableStream.getEndPosFn, + }, + }; + } + /// Implementation of io.InStream trait for File pub const InStream = struct { file: File, @@ -458,4 +484,32 @@ pub const File = struct { return self.file.write(bytes); } }; + + /// Implementation of io.SeekableStream trait for File + pub const SeekableStream = struct { + file: File, + stream: Stream, + + pub const Stream = io.SeekableStream(SeekError, GetSeekPosError); + + pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.seekTo(pos); + } + + pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.seekForward(amt); + } + + pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.getEndPos(); + } + + pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize { + const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); + return self.file.getPos(); + } + }; }; diff --git a/std/os/freebsd/errno.zig b/std/os/freebsd/errno.zig new file mode 100644 index 0000000000..0a0d825f5a --- /dev/null +++ b/std/os/freebsd/errno.zig @@ -0,0 +1,121 @@ +pub const EPERM = 1; // Operation not permitted +pub const ENOENT = 2; // No such file or directory +pub const ESRCH = 3; // No such process +pub const EINTR = 4; // Interrupted system call +pub const EIO = 5; // Input/output error +pub const ENXIO = 6; // Device not configured +pub const E2BIG = 7; // Argument list too long +pub const ENOEXEC = 8; // Exec format error +pub const EBADF = 9; // Bad file descriptor +pub const ECHILD = 10; // No child processes +pub const EDEADLK = 11; // Resource deadlock avoided +// 11 was EAGAIN +pub const ENOMEM = 12; // Cannot allocate memory +pub const EACCES = 13; // Permission denied +pub const EFAULT = 14; // Bad address +pub const ENOTBLK = 15; // Block device required +pub const EBUSY = 16; // Device busy +pub const EEXIST = 17; // File exists +pub const EXDEV = 18; // Cross-device link +pub const ENODEV = 19; // Operation not supported by device +pub const ENOTDIR = 20; // Not a directory +pub const EISDIR = 21; // Is a directory +pub const EINVAL = 22; // Invalid argument +pub const ENFILE = 23; // Too many open files in system +pub const EMFILE = 24; // Too many open files +pub const ENOTTY = 25; // Inappropriate ioctl for device +pub const ETXTBSY = 26; // Text file busy +pub const EFBIG = 27; // File too large +pub const ENOSPC = 28; // No space left on device +pub const ESPIPE = 29; // Illegal seek +pub const EROFS = 30; // Read-only filesystem +pub const EMLINK = 31; // Too many links +pub const EPIPE = 32; // Broken pipe + +// math software +pub const EDOM = 33; // Numerical argument out of domain +pub const ERANGE = 34; // Result too large + +// non-blocking and interrupt i/o +pub const EAGAIN = 35; // Resource temporarily unavailable +pub const EWOULDBLOCK = EAGAIN; // Operation would block +pub const EINPROGRESS = 36; // Operation now in progress +pub const EALREADY = 37; // Operation already in progress + +// ipc/network software -- argument errors +pub const ENOTSOCK = 38; // Socket operation on non-socket +pub const EDESTADDRREQ = 39; // Destination address required +pub const EMSGSIZE = 40; // Message too long +pub const EPROTOTYPE = 41; // Protocol wrong type for socket +pub const ENOPROTOOPT = 42; // Protocol not available +pub const EPROTONOSUPPORT = 43; // Protocol not supported +pub const ESOCKTNOSUPPORT = 44; // Socket type not supported +pub const EOPNOTSUPP = 45; // Operation not supported +pub const ENOTSUP = EOPNOTSUPP; // Operation not supported +pub const EPFNOSUPPORT = 46; // Protocol family not supported +pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family +pub const EADDRINUSE = 48; // Address already in use +pub const EADDRNOTAVAIL = 49; // Can't assign requested address + +// ipc/network software -- operational errors +pub const ENETDOWN = 50; // Network is down +pub const ENETUNREACH = 51; // Network is unreachable +pub const ENETRESET = 52; // Network dropped connection on reset +pub const ECONNABORTED = 53; // Software caused connection abort +pub const ECONNRESET = 54; // Connection reset by peer +pub const ENOBUFS = 55; // No buffer space available +pub const EISCONN = 56; // Socket is already connected +pub const ENOTCONN = 57; // Socket is not connected +pub const ESHUTDOWN = 58; // Can't send after socket shutdown +pub const ETOOMANYREFS = 59; // Too many references: can't splice +pub const ETIMEDOUT = 60; // Operation timed out +pub const ECONNREFUSED = 61; // Connection refused + +pub const ELOOP = 62; // Too many levels of symbolic links +pub const ENAMETOOLONG = 63; // File name too long + +// should be rearranged +pub const EHOSTDOWN = 64; // Host is down +pub const EHOSTUNREACH = 65; // No route to host +pub const ENOTEMPTY = 66; // Directory not empty + +// quotas & mush +pub const EPROCLIM = 67; // Too many processes +pub const EUSERS = 68; // Too many users +pub const EDQUOT = 69; // Disc quota exceeded + +// Network File System +pub const ESTALE = 70; // Stale NFS file handle +pub const EREMOTE = 71; // Too many levels of remote in path +pub const EBADRPC = 72; // RPC struct is bad +pub const ERPCMISMATCH = 73; // RPC version wrong +pub const EPROGUNAVAIL = 74; // RPC prog. not avail +pub const EPROGMISMATCH = 75; // Program version wrong +pub const EPROCUNAVAIL = 76; // Bad procedure for program + +pub const ENOLCK = 77; // No locks available +pub const ENOSYS = 78; // Function not implemented + +pub const EFTYPE = 79; // Inappropriate file type or format +pub const EAUTH = 80; // Authentication error +pub const ENEEDAUTH = 81; // Need authenticator +pub const EIDRM = 82; // Identifier removed +pub const ENOMSG = 83; // No message of desired type +pub const EOVERFLOW = 84; // Value too large to be stored in data type +pub const ECANCELED = 85; // Operation canceled +pub const EILSEQ = 86; // Illegal byte sequence +pub const ENOATTR = 87; // Attribute not found + +pub const EDOOFUS = 88; // Programming error + +pub const EBADMSG = 89; // Bad message +pub const EMULTIHOP = 90; // Multihop attempted +pub const ENOLINK = 91; // Link has been severed +pub const EPROTO = 92; // Protocol error + +pub const ENOTCAPABLE = 93; // Capabilities insufficient +pub const ECAPMODE = 94; // Not permitted in capability mode +pub const ENOTRECOVERABLE = 95; // State not recoverable +pub const EOWNERDEAD = 96; // Previous owner died + +pub const ELAST = 96; // Must be equal largest errno diff --git a/std/os/freebsd/index.zig b/std/os/freebsd/index.zig new file mode 100644 index 0000000000..34a3414a48 --- /dev/null +++ b/std/os/freebsd/index.zig @@ -0,0 +1,801 @@ +const assert = @import("../debug.zig").assert; +const builtin = @import("builtin"); +const arch = switch (builtin.arch) { + builtin.Arch.x86_64 => @import("x86_64.zig"), + else => @compileError("unsupported arch"), +}; +pub use @import("syscall.zig"); +pub use @import("errno.zig"); + +const std = @import("../../index.zig"); +const c = std.c; +const maxInt = std.math.maxInt; +pub const Kevent = c.Kevent; + +pub const PATH_MAX = 1024; + +pub const STDIN_FILENO = 0; +pub const STDOUT_FILENO = 1; +pub const STDERR_FILENO = 2; + +pub const PROT_NONE = 0; +pub const PROT_READ = 1; +pub const PROT_WRITE = 2; +pub const PROT_EXEC = 4; + +pub const MAP_FAILED = maxInt(usize); +pub const MAP_SHARED = 0x0001; +pub const MAP_PRIVATE = 0x0002; +pub const MAP_FIXED = 0x0010; +pub const MAP_STACK = 0x0400; +pub const MAP_NOSYNC = 0x0800; +pub const MAP_ANON = 0x1000; +pub const MAP_ANONYMOUS = MAP_ANON; +pub const MAP_FILE = 0; +pub const MAP_NORESERVE = 0; + +pub const MAP_GUARD = 0x00002000; +pub const MAP_EXCL = 0x00004000; +pub const MAP_NOCORE = 0x00020000; +pub const MAP_PREFAULT_READ = 0x00040000; +pub const MAP_32BIT = 0x00080000; + +pub const WNOHANG = 1; +pub const WUNTRACED = 2; +pub const WSTOPPED = WUNTRACED; +pub const WCONTINUED = 4; +pub const WNOWAIT = 8; +pub const WEXITED = 16; +pub const WTRAPPED = 32; + +pub const SA_ONSTACK = 0x0001; +pub const SA_RESTART = 0x0002; +pub const SA_RESETHAND = 0x0004; +pub const SA_NOCLDSTOP = 0x0008; +pub const SA_NODEFER = 0x0010; +pub const SA_NOCLDWAIT = 0x0020; +pub const SA_SIGINFO = 0x0040; + +pub const SIGHUP = 1; +pub const SIGINT = 2; +pub const SIGQUIT = 3; +pub const SIGILL = 4; +pub const SIGTRAP = 5; +pub const SIGABRT = 6; +pub const SIGIOT = SIGABRT; +pub const SIGEMT = 7; +pub const SIGFPE = 8; +pub const SIGKILL = 9; +pub const SIGBUS = 10; +pub const SIGSEGV = 11; +pub const SIGSYS = 12; +pub const SIGPIPE = 13; +pub const SIGALRM = 14; +pub const SIGTERM = 15; +pub const SIGURG = 16; +pub const SIGSTOP = 17; +pub const SIGTSTP = 18; +pub const SIGCONT = 19; +pub const SIGCHLD = 20; +pub const SIGTTIN = 21; +pub const SIGTTOU = 22; +pub const SIGIO = 23; +pub const SIGXCPU = 24; +pub const SIGXFSZ = 25; +pub const SIGVTALRM = 26; +pub const SIGPROF = 27; +pub const SIGWINCH = 28; +pub const SIGINFO = 29; +pub const SIGUSR1 = 30; +pub const SIGUSR2 = 31; +pub const SIGTHR = 32; +pub const SIGLWP = SIGTHR; +pub const SIGLIBRT = 33; + +pub const SIGRTMIN = 65; +pub const SIGRTMAX = 126; + +pub const O_RDONLY = 0o0; +pub const O_WRONLY = 0o1; +pub const O_RDWR = 0o2; +pub const O_ACCMODE = 0o3; + +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o200000; +pub const O_NOFOLLOW = 0o400000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o40000; +pub const O_LARGEFILE = 0; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +pub const SEEK_SET = 0; +pub const SEEK_CUR = 1; +pub const SEEK_END = 2; + +pub const SIG_BLOCK = 1; +pub const SIG_UNBLOCK = 2; +pub const SIG_SETMASK = 3; + +pub const SOCK_STREAM = 1; +pub const SOCK_DGRAM = 2; +pub const SOCK_RAW = 3; +pub const SOCK_RDM = 4; +pub const SOCK_SEQPACKET = 5; + +pub const SOCK_CLOEXEC = 0x10000000; +pub const SOCK_NONBLOCK = 0x20000000; + +pub const PROTO_ip = 0o000; +pub const PROTO_icmp = 0o001; +pub const PROTO_igmp = 0o002; +pub const PROTO_ggp = 0o003; +pub const PROTO_ipencap = 0o004; +pub const PROTO_st = 0o005; +pub const PROTO_tcp = 0o006; +pub const PROTO_egp = 0o010; +pub const PROTO_pup = 0o014; +pub const PROTO_udp = 0o021; +pub const PROTO_hmp = 0o024; +pub const PROTO_xns_idp = 0o026; +pub const PROTO_rdp = 0o033; +pub const PROTO_iso_tp4 = 0o035; +pub const PROTO_xtp = 0o044; +pub const PROTO_ddp = 0o045; +pub const PROTO_idpr_cmtp = 0o046; +pub const PROTO_ipv6 = 0o051; +pub const PROTO_ipv6_route = 0o053; +pub const PROTO_ipv6_frag = 0o054; +pub const PROTO_idrp = 0o055; +pub const PROTO_rsvp = 0o056; +pub const PROTO_gre = 0o057; +pub const PROTO_esp = 0o062; +pub const PROTO_ah = 0o063; +pub const PROTO_skip = 0o071; +pub const PROTO_ipv6_icmp = 0o072; +pub const PROTO_ipv6_nonxt = 0o073; +pub const PROTO_ipv6_opts = 0o074; +pub const PROTO_rspf = 0o111; +pub const PROTO_vmtp = 0o121; +pub const PROTO_ospf = 0o131; +pub const PROTO_ipip = 0o136; +pub const PROTO_encap = 0o142; +pub const PROTO_pim = 0o147; +pub const PROTO_raw = 0o377; + +pub const PF_UNSPEC = 0; +pub const PF_LOCAL = 1; +pub const PF_UNIX = PF_LOCAL; +pub const PF_FILE = PF_LOCAL; +pub const PF_INET = 2; +pub const PF_AX25 = 3; +pub const PF_IPX = 4; +pub const PF_APPLETALK = 5; +pub const PF_NETROM = 6; +pub const PF_BRIDGE = 7; +pub const PF_ATMPVC = 8; +pub const PF_X25 = 9; +pub const PF_INET6 = 10; +pub const PF_ROSE = 11; +pub const PF_DECnet = 12; +pub const PF_NETBEUI = 13; +pub const PF_SECURITY = 14; +pub const PF_KEY = 15; +pub const PF_NETLINK = 16; +pub const PF_ROUTE = PF_NETLINK; +pub const PF_PACKET = 17; +pub const PF_ASH = 18; +pub const PF_ECONET = 19; +pub const PF_ATMSVC = 20; +pub const PF_RDS = 21; +pub const PF_SNA = 22; +pub const PF_IRDA = 23; +pub const PF_PPPOX = 24; +pub const PF_WANPIPE = 25; +pub const PF_LLC = 26; +pub const PF_IB = 27; +pub const PF_MPLS = 28; +pub const PF_CAN = 29; +pub const PF_TIPC = 30; +pub const PF_BLUETOOTH = 31; +pub const PF_IUCV = 32; +pub const PF_RXRPC = 33; +pub const PF_ISDN = 34; +pub const PF_PHONET = 35; +pub const PF_IEEE802154 = 36; +pub const PF_CAIF = 37; +pub const PF_ALG = 38; +pub const PF_NFC = 39; +pub const PF_VSOCK = 40; +pub const PF_MAX = 41; + +pub const AF_UNSPEC = PF_UNSPEC; +pub const AF_LOCAL = PF_LOCAL; +pub const AF_UNIX = AF_LOCAL; +pub const AF_FILE = AF_LOCAL; +pub const AF_INET = PF_INET; +pub const AF_AX25 = PF_AX25; +pub const AF_IPX = PF_IPX; +pub const AF_APPLETALK = PF_APPLETALK; +pub const AF_NETROM = PF_NETROM; +pub const AF_BRIDGE = PF_BRIDGE; +pub const AF_ATMPVC = PF_ATMPVC; +pub const AF_X25 = PF_X25; +pub const AF_INET6 = PF_INET6; +pub const AF_ROSE = PF_ROSE; +pub const AF_DECnet = PF_DECnet; +pub const AF_NETBEUI = PF_NETBEUI; +pub const AF_SECURITY = PF_SECURITY; +pub const AF_KEY = PF_KEY; +pub const AF_NETLINK = PF_NETLINK; +pub const AF_ROUTE = PF_ROUTE; +pub const AF_PACKET = PF_PACKET; +pub const AF_ASH = PF_ASH; +pub const AF_ECONET = PF_ECONET; +pub const AF_ATMSVC = PF_ATMSVC; +pub const AF_RDS = PF_RDS; +pub const AF_SNA = PF_SNA; +pub const AF_IRDA = PF_IRDA; +pub const AF_PPPOX = PF_PPPOX; +pub const AF_WANPIPE = PF_WANPIPE; +pub const AF_LLC = PF_LLC; +pub const AF_IB = PF_IB; +pub const AF_MPLS = PF_MPLS; +pub const AF_CAN = PF_CAN; +pub const AF_TIPC = PF_TIPC; +pub const AF_BLUETOOTH = PF_BLUETOOTH; +pub const AF_IUCV = PF_IUCV; +pub const AF_RXRPC = PF_RXRPC; +pub const AF_ISDN = PF_ISDN; +pub const AF_PHONET = PF_PHONET; +pub const AF_IEEE802154 = PF_IEEE802154; +pub const AF_CAIF = PF_CAIF; +pub const AF_ALG = PF_ALG; +pub const AF_NFC = PF_NFC; +pub const AF_VSOCK = PF_VSOCK; +pub const AF_MAX = PF_MAX; + +pub const DT_UNKNOWN = 0; +pub const DT_FIFO = 1; +pub const DT_CHR = 2; +pub const DT_DIR = 4; +pub const DT_BLK = 6; +pub const DT_REG = 8; +pub const DT_LNK = 10; +pub const DT_SOCK = 12; +pub const DT_WHT = 14; + +/// add event to kq (implies enable) +pub const EV_ADD = 0x0001; + +/// delete event from kq +pub const EV_DELETE = 0x0002; + +/// enable event +pub const EV_ENABLE = 0x0004; + +/// disable event (not reported) +pub const EV_DISABLE = 0x0008; + +/// only report one occurrence +pub const EV_ONESHOT = 0x0010; + +/// clear event state after reporting +pub const EV_CLEAR = 0x0020; + +/// force immediate event output +/// ... with or without EV_ERROR +/// ... use KEVENT_FLAG_ERROR_EVENTS +/// on syscalls supporting flags +pub const EV_RECEIPT = 0x0040; + +/// disable event after reporting +pub const EV_DISPATCH = 0x0080; + +pub const EVFILT_READ = -1; +pub const EVFILT_WRITE = -2; + +/// attached to aio requests +pub const EVFILT_AIO = -3; + +/// attached to vnodes +pub const EVFILT_VNODE = -4; + +/// attached to struct proc +pub const EVFILT_PROC = -5; + +/// attached to struct proc +pub const EVFILT_SIGNAL = -6; + +/// timers +pub const EVFILT_TIMER = -7; + +/// Process descriptors +pub const EVFILT_PROCDESC = -8; + +/// Filesystem events +pub const EVFILT_FS = -9; + +pub const EVFILT_LIO = -10; + +/// User events +pub const EVFILT_USER = -11; + +/// Sendfile events +pub const EVFILT_SENDFILE = -12; + +pub const EVFILT_EMPTY = -13; + +/// On input, NOTE_TRIGGER causes the event to be triggered for output. +pub const NOTE_TRIGGER = 0x01000000; + +/// ignore input fflags +pub const NOTE_FFNOP = 0x00000000; + +/// and fflags +pub const NOTE_FFAND = 0x40000000; + +/// or fflags +pub const NOTE_FFOR = 0x80000000; + +/// copy fflags +pub const NOTE_FFCOPY = 0xc0000000; + +/// mask for operations +pub const NOTE_FFCTRLMASK = 0xc0000000; +pub const NOTE_FFLAGSMASK = 0x00ffffff; + +/// low water mark +pub const NOTE_LOWAT = 0x00000001; + +/// behave like poll() +pub const NOTE_FILE_POLL = 0x00000002; + +/// vnode was removed +pub const NOTE_DELETE = 0x00000001; + +/// data contents changed +pub const NOTE_WRITE = 0x00000002; + +/// size increased +pub const NOTE_EXTEND = 0x00000004; + +/// attributes changed +pub const NOTE_ATTRIB = 0x00000008; + +/// link count changed +pub const NOTE_LINK = 0x00000010; + +/// vnode was renamed +pub const NOTE_RENAME = 0x00000020; + +/// vnode access was revoked +pub const NOTE_REVOKE = 0x00000040; + +/// vnode was opened +pub const NOTE_OPEN = 0x00000080; + +/// file closed, fd did not allow write +pub const NOTE_CLOSE = 0x00000100; + +/// file closed, fd did allow write +pub const NOTE_CLOSE_WRITE = 0x00000200; + +/// file was read +pub const NOTE_READ = 0x00000400; + +/// process exited +pub const NOTE_EXIT = 0x80000000; + +/// process forked +pub const NOTE_FORK = 0x40000000; + +/// process exec'd +pub const NOTE_EXEC = 0x20000000; + +/// mask for signal & exit status +pub const NOTE_PDATAMASK = 0x000fffff; +pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); + +/// data is seconds +pub const NOTE_SECONDS = 0x00000001; + +/// data is milliseconds +pub const NOTE_MSECONDS = 0x00000002; + +/// data is microseconds +pub const NOTE_USECONDS = 0x00000004; + +/// data is nanoseconds +pub const NOTE_NSECONDS = 0x00000008; + +/// timeout is absolute +pub const NOTE_ABSTIME = 0x00000010; + +pub const TCGETS = 0x5401; +pub const TCSETS = 0x5402; +pub const TCSETSW = 0x5403; +pub const TCSETSF = 0x5404; +pub const TCGETA = 0x5405; +pub const TCSETA = 0x5406; +pub const TCSETAW = 0x5407; +pub const TCSETAF = 0x5408; +pub const TCSBRK = 0x5409; +pub const TCXONC = 0x540A; +pub const TCFLSH = 0x540B; +pub const TIOCEXCL = 0x540C; +pub const TIOCNXCL = 0x540D; +pub const TIOCSCTTY = 0x540E; +pub const TIOCGPGRP = 0x540F; +pub const TIOCSPGRP = 0x5410; +pub const TIOCOUTQ = 0x5411; +pub const TIOCSTI = 0x5412; +pub const TIOCGWINSZ = 0x5413; +pub const TIOCSWINSZ = 0x5414; +pub const TIOCMGET = 0x5415; +pub const TIOCMBIS = 0x5416; +pub const TIOCMBIC = 0x5417; +pub const TIOCMSET = 0x5418; +pub const TIOCGSOFTCAR = 0x5419; +pub const TIOCSSOFTCAR = 0x541A; +pub const FIONREAD = 0x541B; +pub const TIOCINQ = FIONREAD; +pub const TIOCLINUX = 0x541C; +pub const TIOCCONS = 0x541D; +pub const TIOCGSERIAL = 0x541E; +pub const TIOCSSERIAL = 0x541F; +pub const TIOCPKT = 0x5420; +pub const FIONBIO = 0x5421; +pub const TIOCNOTTY = 0x5422; +pub const TIOCSETD = 0x5423; +pub const TIOCGETD = 0x5424; +pub const TCSBRKP = 0x5425; +pub const TIOCSBRK = 0x5427; +pub const TIOCCBRK = 0x5428; +pub const TIOCGSID = 0x5429; +pub const TIOCGRS485 = 0x542E; +pub const TIOCSRS485 = 0x542F; +pub const TIOCGPTN = 0x80045430; +pub const TIOCSPTLCK = 0x40045431; +pub const TIOCGDEV = 0x80045432; +pub const TCGETX = 0x5432; +pub const TCSETX = 0x5433; +pub const TCSETXF = 0x5434; +pub const TCSETXW = 0x5435; +pub const TIOCSIG = 0x40045436; +pub const TIOCVHANGUP = 0x5437; +pub const TIOCGPKT = 0x80045438; +pub const TIOCGPTLCK = 0x80045439; +pub const TIOCGEXCL = 0x80045440; + +fn unsigned(s: i32) u32 { + return @bitCast(u32, s); +} +fn signed(s: u32) i32 { + return @bitCast(i32, s); +} +pub fn WEXITSTATUS(s: i32) i32 { + return signed((unsigned(s) & 0xff00) >> 8); +} +pub fn WTERMSIG(s: i32) i32 { + return signed(unsigned(s) & 0x7f); +} +pub fn WSTOPSIG(s: i32) i32 { + return WEXITSTATUS(s); +} +pub fn WIFEXITED(s: i32) bool { + return WTERMSIG(s) == 0; +} +pub fn WIFSTOPPED(s: i32) bool { + return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00; +} +pub fn WIFSIGNALED(s: i32) bool { + return (unsigned(s) & 0xffff) -% 1 < 0xff; +} + +pub const winsize = extern struct { + ws_row: u16, + ws_col: u16, + ws_xpixel: u16, + ws_ypixel: u16, +}; + +/// Get the errno from a syscall return value, or 0 for no error. +pub fn getErrno(r: usize) usize { + const signed_r = @bitCast(isize, r); + return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0; +} + +pub fn dup2(old: i32, new: i32) usize { + return arch.syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new))); +} + +pub fn chdir(path: [*]const u8) usize { + return arch.syscall1(SYS_chdir, @ptrToInt(path)); +} + +pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize { + return arch.syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp)); +} + +pub fn fork() usize { + return arch.syscall0(SYS_fork); +} + +pub fn getcwd(buf: [*]u8, size: usize) usize { + return arch.syscall2(SYS___getcwd, @ptrToInt(buf), size); +} + +pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize { + return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); +} + +pub fn isatty(fd: i32) bool { + var wsz: winsize = undefined; + return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; +} + +pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { + return arch.syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); +} + +pub fn mkdir(path: [*]const u8, mode: u32) usize { + return arch.syscall2(SYS_mkdir, @ptrToInt(path), mode); +} + +pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize { + return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); +} + +pub fn munmap(address: usize, length: usize) usize { + return arch.syscall2(SYS_munmap, address, length); +} + +pub fn read(fd: i32, buf: [*]u8, count: usize) usize { + return arch.syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); +} + +pub fn rmdir(path: [*]const u8) usize { + return arch.syscall1(SYS_rmdir, @ptrToInt(path)); +} + +pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { + return arch.syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new)); +} + +pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { + return arch.syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); +} + +pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize { + return arch.syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); +} + +pub fn pipe(fd: *[2]i32) usize { + return pipe2(fd, 0); +} + +pub fn pipe2(fd: *[2]i32, flags: usize) usize { + return arch.syscall2(SYS_pipe2, @ptrToInt(fd), flags); +} + +pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { + return arch.syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); +} + +pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { + return arch.syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); +} + +pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize { + return arch.syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); +} + +pub fn rename(old: [*]const u8, new: [*]const u8) usize { + return arch.syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new)); +} + +pub fn open(path: [*]const u8, flags: u32, perm: usize) usize { + return arch.syscall3(SYS_open, @ptrToInt(path), flags, perm); +} + +pub fn create(path: [*]const u8, perm: usize) usize { + return arch.syscall2(SYS_creat, @ptrToInt(path), perm); +} + +pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize { + return arch.syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); +} + +pub fn close(fd: i32) usize { + return arch.syscall1(SYS_close, @bitCast(usize, isize(fd))); +} + +pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { + return arch.syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); +} + +pub fn exit(status: i32) noreturn { + _ = arch.syscall1(SYS_exit, @bitCast(usize, isize(status))); + unreachable; +} + +pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { + return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags)); +} + +pub fn kill(pid: i32, sig: i32) usize { + return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); +} + +pub fn unlink(path: [*]const u8) usize { + return arch.syscall1(SYS_unlink, @ptrToInt(path)); +} + +pub fn waitpid(pid: i32, status: *i32, options: i32) usize { + return arch.syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0); +} + +pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize { + return arch.syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem)); +} + +pub fn setuid(uid: u32) usize { + return arch.syscall1(SYS_setuid, uid); +} + +pub fn setgid(gid: u32) usize { + return arch.syscall1(SYS_setgid, gid); +} + +pub fn setreuid(ruid: u32, euid: u32) usize { + return arch.syscall2(SYS_setreuid, ruid, euid); +} + +pub fn setregid(rgid: u32, egid: u32) usize { + return arch.syscall2(SYS_setregid, rgid, egid); +} + +const NSIG = 32; + +pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize)); +pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0); +pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1); + +/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall. +pub const Sigaction = extern struct { + /// signal handler + __sigaction_u: extern union { + __sa_handler: extern fn (i32) void, + __sa_sigaction: extern fn (i32, *__siginfo, usize) void, + }, + + /// see signal options + sa_flags: u32, + + /// signal mask to apply + sa_mask: sigset_t, +}; + +pub const _SIG_WORDS = 4; +pub const _SIG_MAXSIG = 128; + +pub inline fn _SIG_IDX(sig: usize) usize { + return sig - 1; +} +pub inline fn _SIG_WORD(sig: usize) usize { + return_SIG_IDX(sig) >> 5; +} +pub inline fn _SIG_BIT(sig: usize) usize { + return 1 << (_SIG_IDX(sig) & 31); +} +pub inline fn _SIG_VALID(sig: usize) usize { + return sig <= _SIG_MAXSIG and sig > 0; +} + +pub const sigset_t = extern struct { + __bits: [_SIG_WORDS]u32, +}; + +pub fn raise(sig: i32) usize { + // TODO have a chat with the freebsd folks and make sure there's no bug in + // their libc. musl-libc blocks signals in between these calls because + // if a signal handler runs and forks between the gettid and sending the + // signal, the parent will get 2 signals, one from itself and one from the child + // if the protection does not belong here, then it belongs in abort(), + // like it does in freebsd's libc. + var id: usize = undefined; + const rc = arch.syscall1(SYS_thr_self, @ptrToInt(&id)); + if (getErrno(rc) != 0) return rc; + return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig))); +} + +pub const Stat = arch.Stat; +pub const timespec = arch.timespec; + +pub fn fstat(fd: i32, stat_buf: *Stat) usize { + return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); +} + +pub const iovec = extern struct { + iov_base: [*]u8, + iov_len: usize, +}; + +pub const iovec_const = extern struct { + iov_base: [*]const u8, + iov_len: usize, +}; + +// TODO avoid libc dependency +pub fn kqueue() usize { + return errnoWrap(c.kqueue()); +} + +// TODO avoid libc dependency +pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize { + return errnoWrap(c.kevent( + kq, + changelist.ptr, + @intCast(c_int, changelist.len), + eventlist.ptr, + @intCast(c_int, eventlist.len), + timeout, + )); +} + +// TODO avoid libc dependency +pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { + return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen)); +} + +// TODO avoid libc dependency +pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize { + return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen)); +} + +// TODO avoid libc dependency +pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize { + return errnoWrap(c.sysctlnametomib(name, wibp, sizep)); +} + +// TODO avoid libc dependency + +/// Takes the return value from a syscall and formats it back in the way +/// that the kernel represents it to libc. Errno was a mistake, let's make +/// it go away forever. +fn errnoWrap(value: isize) usize { + return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value); +} diff --git a/std/os/freebsd/syscall.zig b/std/os/freebsd/syscall.zig new file mode 100644 index 0000000000..6cdd71de3b --- /dev/null +++ b/std/os/freebsd/syscall.zig @@ -0,0 +1,493 @@ +pub const SYS_syscall = 0; +pub const SYS_exit = 1; +pub const SYS_fork = 2; +pub const SYS_read = 3; +pub const SYS_write = 4; +pub const SYS_open = 5; +pub const SYS_close = 6; +pub const SYS_wait4 = 7; +// 8 is old creat +pub const SYS_link = 9; +pub const SYS_unlink = 10; +// 11 is obsolete execv +pub const SYS_chdir = 12; +pub const SYS_fchdir = 13; +pub const SYS_freebsd11_mknod = 14; +pub const SYS_chmod = 15; +pub const SYS_chown = 16; +pub const SYS_break = 17; +// 18 is freebsd4 getfsstat +// 19 is old lseek +pub const SYS_getpid = 20; +pub const SYS_mount = 21; +pub const SYS_unmount = 22; +pub const SYS_setuid = 23; +pub const SYS_getuid = 24; +pub const SYS_geteuid = 25; +pub const SYS_ptrace = 26; +pub const SYS_recvmsg = 27; +pub const SYS_sendmsg = 28; +pub const SYS_recvfrom = 29; +pub const SYS_accept = 30; +pub const SYS_getpeername = 31; +pub const SYS_getsockname = 32; +pub const SYS_access = 33; +pub const SYS_chflags = 34; +pub const SYS_fchflags = 35; +pub const SYS_sync = 36; +pub const SYS_kill = 37; +// 38 is old stat +pub const SYS_getppid = 39; +// 40 is old lstat +pub const SYS_dup = 41; +pub const SYS_freebsd10_pipe = 42; +pub const SYS_getegid = 43; +pub const SYS_profil = 44; +pub const SYS_ktrace = 45; +// 46 is old sigaction +pub const SYS_getgid = 47; +// 48 is old sigprocmask +pub const SYS_getlogin = 49; +pub const SYS_setlogin = 50; +pub const SYS_acct = 51; +// 52 is old sigpending +pub const SYS_sigaltstack = 53; +pub const SYS_ioctl = 54; +pub const SYS_reboot = 55; +pub const SYS_revoke = 56; +pub const SYS_symlink = 57; +pub const SYS_readlink = 58; +pub const SYS_execve = 59; +pub const SYS_umask = 60; +pub const SYS_chroot = 61; +// 62 is old fstat +// 63 is old getkerninfo +// 64 is old getpagesize +pub const SYS_msync = 65; +pub const SYS_vfork = 66; +// 67 is obsolete vread +// 68 is obsolete vwrite +// 69 is obsolete sbrk (still present on some platforms) +pub const SYS_sstk = 70; +// 71 is old mmap +pub const SYS_vadvise = 72; +pub const SYS_munmap = 73; +pub const SYS_mprotect = 74; +pub const SYS_madvise = 75; +// 76 is obsolete vhangup +// 77 is obsolete vlimit +pub const SYS_mincore = 78; +pub const SYS_getgroups = 79; +pub const SYS_setgroups = 80; +pub const SYS_getpgrp = 81; +pub const SYS_setpgid = 82; +pub const SYS_setitimer = 83; +// 84 is old wait +pub const SYS_swapon = 85; +pub const SYS_getitimer = 86; +// 87 is old gethostname +// 88 is old sethostname +pub const SYS_getdtablesize = 89; +pub const SYS_dup2 = 90; +pub const SYS_fcntl = 92; +pub const SYS_select = 93; +pub const SYS_fsync = 95; +pub const SYS_setpriority = 96; +pub const SYS_socket = 97; +pub const SYS_connect = 98; +// 99 is old accept +pub const SYS_getpriority = 100; +// 101 is old send +// 102 is old recv +// 103 is old sigreturn +pub const SYS_bind = 104; +pub const SYS_setsockopt = 105; +pub const SYS_listen = 106; +// 107 is obsolete vtimes +// 108 is old sigvec +// 109 is old sigblock +// 110 is old sigsetmask +// 111 is old sigsuspend +// 112 is old sigstack +// 113 is old recvmsg +// 114 is old sendmsg +// 115 is obsolete vtrace +pub const SYS_gettimeofday = 116; +pub const SYS_getrusage = 117; +pub const SYS_getsockopt = 118; +pub const SYS_readv = 120; +pub const SYS_writev = 121; +pub const SYS_settimeofday = 122; +pub const SYS_fchown = 123; +pub const SYS_fchmod = 124; +// 125 is old recvfrom +pub const SYS_setreuid = 126; +pub const SYS_setregid = 127; +pub const SYS_rename = 128; +// 129 is old truncate +// 130 is old ftruncate +pub const SYS_flock = 131; +pub const SYS_mkfifo = 132; +pub const SYS_sendto = 133; +pub const SYS_shutdown = 134; +pub const SYS_socketpair = 135; +pub const SYS_mkdir = 136; +pub const SYS_rmdir = 137; +pub const SYS_utimes = 138; +// 139 is obsolete 4.2 sigreturn +pub const SYS_adjtime = 140; +// 141 is old getpeername +// 142 is old gethostid +// 143 is old sethostid +// 144 is old getrlimit +// 145 is old setrlimit +// 146 is old killpg +pub const SYS_setsid = 147; +pub const SYS_quotactl = 148; +// 149 is old quota +// 150 is old getsockname +pub const SYS_nlm_syscall = 154; +pub const SYS_nfssvc = 155; +// 156 is old getdirentries +// 157 is freebsd4 statfs +// 158 is freebsd4 fstatfs +pub const SYS_lgetfh = 160; +pub const SYS_getfh = 161; +// 162 is freebsd4 getdomainname +// 163 is freebsd4 setdomainname +// 164 is freebsd4 uname +pub const SYS_sysarch = 165; +pub const SYS_rtprio = 166; +pub const SYS_semsys = 169; +pub const SYS_msgsys = 170; +pub const SYS_shmsys = 171; +// 173 is freebsd6 pread +// 174 is freebsd6 pwrite +pub const SYS_setfib = 175; +pub const SYS_ntp_adjtime = 176; +pub const SYS_setgid = 181; +pub const SYS_setegid = 182; +pub const SYS_seteuid = 183; +// 184 is obsolete lfs_bmapv +// 185 is obsolete lfs_markv +// 186 is obsolete lfs_segclean +// 187 is obsolete lfs_segwait +pub const SYS_freebsd11_stat = 188; +pub const SYS_freebsd11_fstat = 189; +pub const SYS_freebsd11_lstat = 190; +pub const SYS_pathconf = 191; +pub const SYS_fpathconf = 192; +pub const SYS_getrlimit = 194; +pub const SYS_setrlimit = 195; +pub const SYS_freebsd11_getdirentries = 196; +// 197 is freebsd6 mmap +pub const SYS___syscall = 198; +// 199 is freebsd6 lseek +// 200 is freebsd6 truncate +// 201 is freebsd6 ftruncate +pub const SYS___sysctl = 202; +pub const SYS_mlock = 203; +pub const SYS_munlock = 204; +pub const SYS_undelete = 205; +pub const SYS_futimes = 206; +pub const SYS_getpgid = 207; +pub const SYS_poll = 209; +pub const SYS_freebsd7___semctl = 220; +pub const SYS_semget = 221; +pub const SYS_semop = 222; +pub const SYS_freebsd7_msgctl = 224; +pub const SYS_msgget = 225; +pub const SYS_msgsnd = 226; +pub const SYS_msgrcv = 227; +pub const SYS_shmat = 228; +pub const SYS_freebsd7_shmctl = 229; +pub const SYS_shmdt = 230; +pub const SYS_shmget = 231; +pub const SYS_clock_gettime = 232; +pub const SYS_clock_settime = 233; +pub const SYS_clock_getres = 234; +pub const SYS_ktimer_create = 235; +pub const SYS_ktimer_delete = 236; +pub const SYS_ktimer_settime = 237; +pub const SYS_ktimer_gettime = 238; +pub const SYS_ktimer_getoverrun = 239; +pub const SYS_nanosleep = 240; +pub const SYS_ffclock_getcounter = 241; +pub const SYS_ffclock_setestimate = 242; +pub const SYS_ffclock_getestimate = 243; +pub const SYS_clock_nanosleep = 244; +pub const SYS_clock_getcpuclockid2 = 247; +pub const SYS_ntp_gettime = 248; +pub const SYS_minherit = 250; +pub const SYS_rfork = 251; +// 252 is obsolete openbsd_poll +pub const SYS_issetugid = 253; +pub const SYS_lchown = 254; +pub const SYS_aio_read = 255; +pub const SYS_aio_write = 256; +pub const SYS_lio_listio = 257; +pub const SYS_freebsd11_getdents = 272; +pub const SYS_lchmod = 274; +// 275 is obsolete netbsd_lchown +pub const SYS_lutimes = 276; +// 277 is obsolete netbsd_msync +pub const SYS_freebsd11_nstat = 278; +pub const SYS_freebsd11_nfstat = 279; +pub const SYS_freebsd11_nlstat = 280; +pub const SYS_preadv = 289; +pub const SYS_pwritev = 290; +// 297 is freebsd4 fhstatfs +pub const SYS_fhopen = 298; +pub const SYS_freebsd11_fhstat = 299; +pub const SYS_modnext = 300; +pub const SYS_modstat = 301; +pub const SYS_modfnext = 302; +pub const SYS_modfind = 303; +pub const SYS_kldload = 304; +pub const SYS_kldunload = 305; +pub const SYS_kldfind = 306; +pub const SYS_kldnext = 307; +pub const SYS_kldstat = 308; +pub const SYS_kldfirstmod = 309; +pub const SYS_getsid = 310; +pub const SYS_setresuid = 311; +pub const SYS_setresgid = 312; +// 313 is obsolete signanosleep +pub const SYS_aio_return = 314; +pub const SYS_aio_suspend = 315; +pub const SYS_aio_cancel = 316; +pub const SYS_aio_error = 317; +// 318 is freebsd6 aio_read +// 319 is freebsd6 aio_write +// 320 is freebsd6 lio_listio +pub const SYS_yield = 321; +// 322 is obsolete thr_sleep +// 323 is obsolete thr_wakeup +pub const SYS_mlockall = 324; +pub const SYS_munlockall = 325; +pub const SYS___getcwd = 326; +pub const SYS_sched_setparam = 327; +pub const SYS_sched_getparam = 328; +pub const SYS_sched_setscheduler = 329; +pub const SYS_sched_getscheduler = 330; +pub const SYS_sched_yield = 331; +pub const SYS_sched_get_priority_max = 332; +pub const SYS_sched_get_priority_min = 333; +pub const SYS_sched_rr_get_interval = 334; +pub const SYS_utrace = 335; +// 336 is freebsd4 sendfile +pub const SYS_kldsym = 337; +pub const SYS_jail = 338; +pub const SYS_nnpfs_syscall = 339; +pub const SYS_sigprocmask = 340; +pub const SYS_sigsuspend = 341; +// 342 is freebsd4 sigaction +pub const SYS_sigpending = 343; +// 344 is freebsd4 sigreturn +pub const SYS_sigtimedwait = 345; +pub const SYS_sigwaitinfo = 346; +pub const SYS___acl_get_file = 347; +pub const SYS___acl_set_file = 348; +pub const SYS___acl_get_fd = 349; +pub const SYS___acl_set_fd = 350; +pub const SYS___acl_delete_file = 351; +pub const SYS___acl_delete_fd = 352; +pub const SYS___acl_aclcheck_file = 353; +pub const SYS___acl_aclcheck_fd = 354; +pub const SYS_extattrctl = 355; +pub const SYS_extattr_set_file = 356; +pub const SYS_extattr_get_file = 357; +pub const SYS_extattr_delete_file = 358; +pub const SYS_aio_waitcomplete = 359; +pub const SYS_getresuid = 360; +pub const SYS_getresgid = 361; +pub const SYS_kqueue = 362; +pub const SYS_freebsd11_kevent = 363; +// 364 is obsolete __cap_get_proc +// 365 is obsolete __cap_set_proc +// 366 is obsolete __cap_get_fd +// 367 is obsolete __cap_get_file +// 368 is obsolete __cap_set_fd +// 369 is obsolete __cap_set_file +pub const SYS_extattr_set_fd = 371; +pub const SYS_extattr_get_fd = 372; +pub const SYS_extattr_delete_fd = 373; +pub const SYS___setugid = 374; +pub const SYS_eaccess = 376; +pub const SYS_afs3_syscall = 377; +pub const SYS_nmount = 378; +// 379 is obsolete kse_exit +// 380 is obsolete kse_wakeup +// 381 is obsolete kse_create +// 382 is obsolete kse_thr_interrupt +// 383 is obsolete kse_release +pub const SYS___mac_get_proc = 384; +pub const SYS___mac_set_proc = 385; +pub const SYS___mac_get_fd = 386; +pub const SYS___mac_get_file = 387; +pub const SYS___mac_set_fd = 388; +pub const SYS___mac_set_file = 389; +pub const SYS_kenv = 390; +pub const SYS_lchflags = 391; +pub const SYS_uuidgen = 392; +pub const SYS_sendfile = 393; +pub const SYS_mac_syscall = 394; +pub const SYS_freebsd11_getfsstat = 395; +pub const SYS_freebsd11_statfs = 396; +pub const SYS_freebsd11_fstatfs = 397; +pub const SYS_freebsd11_fhstatfs = 398; +pub const SYS_ksem_close = 400; +pub const SYS_ksem_post = 401; +pub const SYS_ksem_wait = 402; +pub const SYS_ksem_trywait = 403; +pub const SYS_ksem_init = 404; +pub const SYS_ksem_open = 405; +pub const SYS_ksem_unlink = 406; +pub const SYS_ksem_getvalue = 407; +pub const SYS_ksem_destroy = 408; +pub const SYS___mac_get_pid = 409; +pub const SYS___mac_get_link = 410; +pub const SYS___mac_set_link = 411; +pub const SYS_extattr_set_link = 412; +pub const SYS_extattr_get_link = 413; +pub const SYS_extattr_delete_link = 414; +pub const SYS___mac_execve = 415; +pub const SYS_sigaction = 416; +pub const SYS_sigreturn = 417; +pub const SYS_getcontext = 421; +pub const SYS_setcontext = 422; +pub const SYS_swapcontext = 423; +pub const SYS_swapoff = 424; +pub const SYS___acl_get_link = 425; +pub const SYS___acl_set_link = 426; +pub const SYS___acl_delete_link = 427; +pub const SYS___acl_aclcheck_link = 428; +pub const SYS_sigwait = 429; +pub const SYS_thr_create = 430; +pub const SYS_thr_exit = 431; +pub const SYS_thr_self = 432; +pub const SYS_thr_kill = 433; +pub const SYS_jail_attach = 436; +pub const SYS_extattr_list_fd = 437; +pub const SYS_extattr_list_file = 438; +pub const SYS_extattr_list_link = 439; +// 440 is obsolete kse_switchin +pub const SYS_ksem_timedwait = 441; +pub const SYS_thr_suspend = 442; +pub const SYS_thr_wake = 443; +pub const SYS_kldunloadf = 444; +pub const SYS_audit = 445; +pub const SYS_auditon = 446; +pub const SYS_getauid = 447; +pub const SYS_setauid = 448; +pub const SYS_getaudit = 449; +pub const SYS_setaudit = 450; +pub const SYS_getaudit_addr = 451; +pub const SYS_setaudit_addr = 452; +pub const SYS_auditctl = 453; +pub const SYS__umtx_op = 454; +pub const SYS_thr_new = 455; +pub const SYS_sigqueue = 456; +pub const SYS_kmq_open = 457; +pub const SYS_kmq_setattr = 458; +pub const SYS_kmq_timedreceive = 459; +pub const SYS_kmq_timedsend = 460; +pub const SYS_kmq_notify = 461; +pub const SYS_kmq_unlink = 462; +pub const SYS_abort2 = 463; +pub const SYS_thr_set_name = 464; +pub const SYS_aio_fsync = 465; +pub const SYS_rtprio_thread = 466; +pub const SYS_sctp_peeloff = 471; +pub const SYS_sctp_generic_sendmsg = 472; +pub const SYS_sctp_generic_sendmsg_iov = 473; +pub const SYS_sctp_generic_recvmsg = 474; +pub const SYS_pread = 475; +pub const SYS_pwrite = 476; +pub const SYS_mmap = 477; +pub const SYS_lseek = 478; +pub const SYS_truncate = 479; +pub const SYS_ftruncate = 480; +pub const SYS_thr_kill2 = 481; +pub const SYS_shm_open = 482; +pub const SYS_shm_unlink = 483; +pub const SYS_cpuset = 484; +pub const SYS_cpuset_setid = 485; +pub const SYS_cpuset_getid = 486; +pub const SYS_cpuset_getaffinity = 487; +pub const SYS_cpuset_setaffinity = 488; +pub const SYS_faccessat = 489; +pub const SYS_fchmodat = 490; +pub const SYS_fchownat = 491; +pub const SYS_fexecve = 492; +pub const SYS_freebsd11_fstatat = 493; +pub const SYS_futimesat = 494; +pub const SYS_linkat = 495; +pub const SYS_mkdirat = 496; +pub const SYS_mkfifoat = 497; +pub const SYS_freebsd11_mknodat = 498; +pub const SYS_openat = 499; +pub const SYS_readlinkat = 500; +pub const SYS_renameat = 501; +pub const SYS_symlinkat = 502; +pub const SYS_unlinkat = 503; +pub const SYS_posix_openpt = 504; +pub const SYS_gssd_syscall = 505; +pub const SYS_jail_get = 506; +pub const SYS_jail_set = 507; +pub const SYS_jail_remove = 508; +pub const SYS_closefrom = 509; +pub const SYS___semctl = 510; +pub const SYS_msgctl = 511; +pub const SYS_shmctl = 512; +pub const SYS_lpathconf = 513; +// 514 is obsolete cap_new +pub const SYS___cap_rights_get = 515; +pub const SYS_cap_enter = 516; +pub const SYS_cap_getmode = 517; +pub const SYS_pdfork = 518; +pub const SYS_pdkill = 519; +pub const SYS_pdgetpid = 520; +pub const SYS_pselect = 522; +pub const SYS_getloginclass = 523; +pub const SYS_setloginclass = 524; +pub const SYS_rctl_get_racct = 525; +pub const SYS_rctl_get_rules = 526; +pub const SYS_rctl_get_limits = 527; +pub const SYS_rctl_add_rule = 528; +pub const SYS_rctl_remove_rule = 529; +pub const SYS_posix_fallocate = 530; +pub const SYS_posix_fadvise = 531; +pub const SYS_wait6 = 532; +pub const SYS_cap_rights_limit = 533; +pub const SYS_cap_ioctls_limit = 534; +pub const SYS_cap_ioctls_get = 535; +pub const SYS_cap_fcntls_limit = 536; +pub const SYS_cap_fcntls_get = 537; +pub const SYS_bindat = 538; +pub const SYS_connectat = 539; +pub const SYS_chflagsat = 540; +pub const SYS_accept4 = 541; +pub const SYS_pipe2 = 542; +pub const SYS_aio_mlock = 543; +pub const SYS_procctl = 544; +pub const SYS_ppoll = 545; +pub const SYS_futimens = 546; +pub const SYS_utimensat = 547; +// 548 is obsolete numa_getaffinity +// 549 is obsolete numa_setaffinity +pub const SYS_fdatasync = 550; +pub const SYS_fstat = 551; +pub const SYS_fstatat = 552; +pub const SYS_fhstat = 553; +pub const SYS_getdirentries = 554; +pub const SYS_statfs = 555; +pub const SYS_fstatfs = 556; +pub const SYS_getfsstat = 557; +pub const SYS_fhstatfs = 558; +pub const SYS_mknodat = 559; +pub const SYS_kevent = 560; +pub const SYS_cpuset_getdomain = 561; +pub const SYS_cpuset_setdomain = 562; +pub const SYS_getrandom = 563; +pub const SYS_MAXSYSCALL = 564; diff --git a/std/os/freebsd/x86_64.zig b/std/os/freebsd/x86_64.zig new file mode 100644 index 0000000000..509075386f --- /dev/null +++ b/std/os/freebsd/x86_64.zig @@ -0,0 +1,136 @@ +const freebsd = @import("index.zig"); +const socklen_t = freebsd.socklen_t; +const iovec = freebsd.iovec; + +pub const SYS_sbrk = 69; + +pub fn syscall0(number: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number) + : "rcx", "r11" + ); +} + +pub fn syscall1(number: usize, arg1: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1) + : "rcx", "r11" + ); +} + +pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2) + : "rcx", "r11" + ); +} + +pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3) + : "rcx", "r11" + ); +} + +pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4) + : "rcx", "r11" + ); +} + +pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5) + : "rcx", "r11" + ); +} + +pub fn syscall6( + number: usize, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ("syscall" + : [ret] "={rax}" (-> usize) + : [number] "{rax}" (number), + [arg1] "{rdi}" (arg1), + [arg2] "{rsi}" (arg2), + [arg3] "{rdx}" (arg3), + [arg4] "{r10}" (arg4), + [arg5] "{r8}" (arg5), + [arg6] "{r9}" (arg6) + : "rcx", "r11" + ); +} + +pub nakedcc fn restore_rt() void { + asm volatile ("syscall" + : + : [number] "{rax}" (usize(SYS_rt_sigreturn)) + : "rcx", "r11" + ); +} + +pub const msghdr = extern struct { + msg_name: *u8, + msg_namelen: socklen_t, + msg_iov: *iovec, + msg_iovlen: i32, + __pad1: i32, + msg_control: *u8, + msg_controllen: socklen_t, + __pad2: socklen_t, + msg_flags: i32, +}; + +/// Renamed to Stat to not conflict with the stat function. +pub const Stat = extern struct { + dev: u64, + ino: u64, + nlink: usize, + + mode: u32, + uid: u32, + gid: u32, + __pad0: u32, + rdev: u64, + size: i64, + blksize: isize, + blocks: i64, + + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]isize, +}; + +pub const timespec = extern struct { + tv_sec: isize, + tv_nsec: isize, +}; diff --git a/std/os/get_app_data_dir.zig b/std/os/get_app_data_dir.zig index da9c6c3cb4..ae133bb4b1 100644 --- a/std/os/get_app_data_dir.zig +++ b/std/os/get_app_data_dir.zig @@ -43,7 +43,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD }; return os.path.join(allocator, home_dir, "Library", "Application Support", appname); }, - builtin.Os.linux => { + builtin.Os.linux, builtin.Os.freebsd => { const home_dir = os.getEnvPosix("HOME") orelse { // TODO look in /etc/passwd return error.AppDataDirUnavailable; diff --git a/std/os/get_user_id.zig b/std/os/get_user_id.zig index c0c1b1cc4b..9a4d1ab275 100644 --- a/std/os/get_user_id.zig +++ b/std/os/get_user_id.zig @@ -11,7 +11,7 @@ pub const UserInfo = struct { /// POSIX function which gets a uid from username. pub fn getUserInfo(name: []const u8) !UserInfo { return switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name), + Os.linux, Os.macosx, Os.ios, Os.freebsd => posixGetUserInfo(name), else => @compileError("Unsupported OS"), }; } diff --git a/std/os/index.zig b/std/os/index.zig index e1915a2012..b19679c969 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -3,7 +3,7 @@ const builtin = @import("builtin"); const Os = builtin.Os; const is_windows = builtin.os == Os.windows; const is_posix = switch (builtin.os) { - builtin.Os.linux, builtin.Os.macosx => true, + builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => true, else => false, }; const os = @This(); @@ -24,10 +24,12 @@ test "std.os" { pub const windows = @import("windows/index.zig"); pub const darwin = @import("darwin.zig"); pub const linux = @import("linux/index.zig"); +pub const freebsd = @import("freebsd/index.zig"); pub const zen = @import("zen.zig"); pub const posix = switch (builtin.os) { Os.linux => linux, Os.macosx, Os.ios => darwin, + Os.freebsd => freebsd, Os.zen => zen, else => @compileError("Unsupported OS"), }; @@ -40,7 +42,7 @@ pub const time = @import("time.zig"); pub const page_size = 4 * 1024; pub const MAX_PATH_BYTES = switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => posix.PATH_MAX, + Os.linux, Os.macosx, Os.ios, Os.freebsd => posix.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. // If it would require 4 UTF-8 bytes, then there would be a surrogate // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. @@ -101,7 +103,7 @@ const math = std.math; /// library implementation. pub fn getRandomBytes(buf: []u8) !void { switch (builtin.os) { - Os.linux => while (true) { + Os.linux, Os.freebsd => while (true) { // TODO check libc version and potentially call c.getrandom. // See #397 const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0)); @@ -174,7 +176,7 @@ pub fn abort() noreturn { c.abort(); } switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { _ = posix.raise(posix.SIGABRT); _ = posix.raise(posix.SIGKILL); while (true) {} @@ -196,7 +198,7 @@ pub fn exit(status: u8) noreturn { c.exit(status); } switch (builtin.os) { - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { posix.exit(status); }, Os.windows => { @@ -419,7 +421,7 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off } } }, - builtin.Os.linux => while (true) { + builtin.Os.linux, builtin.Os.freebsd => while (true) { const rc = posix.pwritev(fd, iov, count, offset); const err = posix.getErrno(rc); switch (err) { @@ -457,6 +459,7 @@ pub const PosixOpenError = error{ NoSpaceLeft, NotDir, PathAlreadyExists, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, @@ -495,6 +498,7 @@ pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 { posix.ENOTDIR => return PosixOpenError.NotDir, posix.EPERM => return PosixOpenError.AccessDenied, posix.EEXIST => return PosixOpenError.PathAlreadyExists, + posix.EBUSY => return PosixOpenError.DeviceBusy, else => return unexpectedErrorPosix(err), } } @@ -687,7 +691,7 @@ pub fn getBaseAddress() usize { }; return phdr - @sizeOf(ElfHeader); }, - builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header), + builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header), builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)), else => @compileError("Unsupported OS"), } @@ -700,8 +704,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { errdefer result.deinit(); if (is_windows) { - const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory; - defer assert(windows.FreeEnvironmentStringsA(ptr) != 0); + const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory; + defer assert(windows.FreeEnvironmentStringsW(ptr) != 0); var i: usize = 0; while (true) { @@ -710,17 +714,21 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { const key_start = i; while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {} - const key = ptr[key_start..i]; + const key_w = ptr[key_start..i]; + const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w); + errdefer allocator.free(key); if (ptr[i] == '=') i += 1; const value_start = i; while (ptr[i] != 0) : (i += 1) {} - const value = ptr[value_start..i]; + const value_w = ptr[value_start..i]; + const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w); + errdefer allocator.free(value); i += 1; // skip over null byte - try result.set(key, value); + try result.setMove(key, value); } } else { for (posix_environ_raw) |ptr| { @@ -738,6 +746,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { } } +test "os.getEnvMap" { + var env = try getEnvMap(std.debug.global_allocator); + defer env.deinit(); +} + /// TODO make this go through libc when we have it pub fn getEnvPosix(key: []const u8) ?[]const u8 { for (posix_environ_raw) |ptr| { @@ -758,21 +771,24 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 { pub const GetEnvVarOwnedError = error{ OutOfMemory, EnvironmentVariableNotFound, + + /// See https://github.com/ziglang/zig/issues/1774 + InvalidUtf8, }; /// Caller must free returned memory. /// TODO make this go through libc when we have it pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 { if (is_windows) { - const key_with_null = try cstr.addNullByte(allocator, key); + const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key); defer allocator.free(key_with_null); - var buf = try allocator.alloc(u8, 256); - errdefer allocator.free(buf); + var buf = try allocator.alloc(u16, 256); + defer allocator.free(buf); while (true) { const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory; - const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len); + const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len); if (result == 0) { const err = windows.GetLastError(); @@ -786,11 +802,16 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } if (result > buf.len) { - buf = try allocator.realloc(u8, buf, result); + buf = try allocator.realloc(u16, buf, result); continue; } - return allocator.shrink(u8, buf, result); + return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) { + error.DanglingSurrogateHalf => return error.InvalidUtf8, + error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8, + error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8, + error.OutOfMemory => return error.OutOfMemory, + }; } } else { const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound; @@ -798,6 +819,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned } } +test "os.getEnvVarOwned" { + var ga = debug.global_allocator; + debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound); +} + /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; @@ -1305,7 +1331,7 @@ pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void { const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path); return deleteDirW(&dir_path_w); }, - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const err = posix.getErrno(posix.rmdir(dir_path)); switch (err) { 0 => return, @@ -1348,7 +1374,7 @@ pub fn deleteDir(dir_path: []const u8) DeleteDirError!void { const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path); return deleteDirW(&dir_path_w); }, - Os.linux, Os.macosx, Os.ios => { + Os.linux, Os.macosx, Os.ios, Os.freebsd => { const dir_path_c = try toPosixPath(dir_path); return deleteDirC(&dir_path_c); }, @@ -1378,6 +1404,7 @@ const DeleteTreeError = error{ FileSystem, FileBusy, DirNotEmpty, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -1439,6 +1466,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError! error.Unexpected, error.InvalidUtf8, error.BadPathName, + error.DeviceBusy, => return err, }; defer dir.close(); @@ -1465,7 +1493,7 @@ pub const Dir = struct { allocator: *Allocator, pub const Handle = switch (builtin.os) { - Os.macosx, Os.ios => struct { + Os.macosx, Os.ios, Os.freebsd => struct { fd: i32, seek: i64, buf: []u8, @@ -1521,6 +1549,7 @@ pub const Dir = struct { OutOfMemory, InvalidUtf8, BadPathName, + DeviceBusy, /// See https://github.com/ziglang/zig/issues/1396 Unexpected, @@ -1541,7 +1570,7 @@ pub const Dir = struct { .name_data = undefined, }; }, - Os.macosx, Os.ios => Handle{ + Os.macosx, Os.ios, Os.freebsd => Handle{ .fd = try posixOpen( dir_path, posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC, @@ -1572,7 +1601,7 @@ pub const Dir = struct { Os.windows => { _ = windows.FindClose(self.handle.handle); }, - Os.macosx, Os.ios, Os.linux => { + Os.macosx, Os.ios, Os.linux, Os.freebsd => { self.allocator.free(self.handle.buf); os.close(self.handle.fd); }, @@ -1587,6 +1616,7 @@ pub const Dir = struct { Os.linux => return self.nextLinux(), Os.macosx, Os.ios => return self.nextDarwin(), Os.windows => return self.nextWindows(), + Os.freebsd => return self.nextFreebsd(), else => @compileError("unimplemented"), } } @@ -1726,6 +1756,11 @@ pub const Dir = struct { }; } } + + fn nextFreebsd(self: *Dir) !?Entry { + //self.handle.buf = try self.allocator.alloc(u8, page_size); + @compileError("TODO implement dirs for FreeBSD"); + } }; pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void { @@ -2164,7 +2199,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError { pub fn openSelfExe() !os.File { switch (builtin.os) { Os.linux => return os.File.openReadC(c"/proc/self/exe"), - Os.macosx, Os.ios => { + Os.macosx, Os.ios, Os.freebsd => { var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; @@ -2181,7 +2216,7 @@ pub fn openSelfExe() !os.File { test "openSelfExe" { switch (builtin.os) { - Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(), + Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(), else => return error.SkipZigTest, // Unsupported OS. } } @@ -2212,6 +2247,7 @@ pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 { pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 { switch (builtin.os) { Os.linux => return readLink(out_buffer, "/proc/self/exe"), + Os.freebsd => return readLink(out_buffer, "/proc/curproc/file"), Os.windows => { var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined; const utf16le_slice = try selfExePathW(&utf16le_buf); @@ -2250,7 +2286,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 { // will not return null. return path.dirname(full_exe_path).?; }, - Os.windows, Os.macosx, Os.ios => { + Os.windows, Os.macosx, Os.ios, Os.freebsd => { const self_exe_path = try selfExePath(out_buffer); // Assume that the OS APIs return absolute paths, and therefore dirname // will not return null. @@ -3095,10 +3131,13 @@ pub const CpuCountError = error{ pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize { switch (builtin.os) { - builtin.Os.macosx => { + builtin.Os.macosx, builtin.Os.freebsd => { var count: c_int = undefined; var count_len: usize = @sizeOf(c_int); - const rc = posix.sysctlbyname(c"hw.logicalcpu", @ptrCast(*c_void, &count), &count_len, null, 0); + const rc = posix.sysctlbyname(switch (builtin.os) { + builtin.Os.macosx => c"hw.logicalcpu", + else => c"hw.ncpu", + }, @ptrCast(*c_void, &count), &count_len, null, 0); const err = posix.getErrno(rc); switch (err) { 0 => return @intCast(usize, count), diff --git a/std/os/linux/index.zig b/std/os/linux/index.zig index c401eb3dc8..ec90755164 100644 --- a/std/os/linux/index.zig +++ b/std/os/linux/index.zig @@ -703,7 +703,7 @@ pub fn dup2(old: i32, new: i32) usize { } pub fn dup3(old: i32, new: i32, flags: u32) usize { - return syscall3(SYS_dup3, @intCast(usize, old), @intCast(usize, new), flags); + return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -747,7 +747,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize { } pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize { - return syscall3(SYS_getdents64, @intCast(usize, fd), @ptrToInt(dirp), count); + return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count); } pub fn inotify_init1(flags: u32) usize { @@ -755,16 +755,16 @@ pub fn inotify_init1(flags: u32) usize { } pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize { - return syscall3(SYS_inotify_add_watch, @intCast(usize, fd), @ptrToInt(pathname), mask); + return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask); } pub fn inotify_rm_watch(fd: i32, wd: i32) usize { - return syscall2(SYS_inotify_rm_watch, @intCast(usize, fd), @intCast(usize, wd)); + return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd))); } pub fn isatty(fd: i32) bool { var wsz: winsize = undefined; - return syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; + return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0; } // TODO https://github.com/ziglang/zig/issues/265 @@ -774,7 +774,7 @@ pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usiz // TODO https://github.com/ziglang/zig/issues/265 pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize { - return syscall4(SYS_readlinkat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); + return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len); } // TODO https://github.com/ziglang/zig/issues/265 @@ -784,7 +784,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize { - return syscall3(SYS_mkdirat, @intCast(usize, dirfd), @ptrToInt(path), mode); + return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); } // TODO https://github.com/ziglang/zig/issues/265 @@ -803,7 +803,7 @@ pub fn umount2(special: [*]const u8, flags: u32) usize { } pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize { - return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset)); + return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset)); } pub fn munmap(address: usize, length: usize) usize { @@ -811,23 +811,23 @@ pub fn munmap(address: usize, length: usize) usize { } pub fn read(fd: i32, buf: [*]u8, count: usize) usize { - return syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count); + return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize { - return syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize { - return syscall3(SYS_readv, @intCast(usize, fd), @ptrToInt(iov), count); + return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); } pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize { - return syscall3(SYS_writev, @intCast(usize, fd), @ptrToInt(iov), count); + return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count); } pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize { - return syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset); + return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -842,12 +842,12 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize { - return syscall3(SYS_symlinkat, @ptrToInt(existing), @intCast(usize, newfd), @ptrToInt(newpath)); + return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath)); } // TODO https://github.com/ziglang/zig/issues/265 pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize { - return syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -856,7 +856,7 @@ pub fn access(path: [*]const u8, mode: u32) usize { } pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize { - return syscall3(SYS_faccessat, @intCast(usize, dirfd), @ptrToInt(path), mode); + return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode); } pub fn pipe(fd: *[2]i32) usize { @@ -868,11 +868,11 @@ pub fn pipe2(fd: *[2]i32, flags: u32) usize { } pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { - return syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count); + return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count); } pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize { - return syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset); + return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset); } // TODO https://github.com/ziglang/zig/issues/265 @@ -882,7 +882,7 @@ pub fn rename(old: [*]const u8, new: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize { - return syscall5(SYS_renameat2, @intCast(usize, oldfd), @ptrToInt(oldpath), @intCast(usize, newfd), @ptrToInt(newpath), flags); + return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -897,7 +897,8 @@ pub fn create(path: [*]const u8, perm: usize) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize { - return syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode); + // dirfd could be negative, for example AT_FDCWD is -100 + return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode); } /// See also `clone` (from the arch-specific include) @@ -911,11 +912,11 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize { } pub fn close(fd: i32) usize { - return syscall1(SYS_close, @intCast(usize, fd)); + return syscall1(SYS_close, @bitCast(usize, isize(fd))); } pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize { - return syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos); + return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos); } pub fn exit(status: i32) noreturn { @@ -933,7 +934,7 @@ pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize { } pub fn kill(pid: i32, sig: i32) usize { - return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @intCast(usize, sig)); + return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig))); } // TODO https://github.com/ziglang/zig/issues/265 @@ -943,7 +944,7 @@ pub fn unlink(path: [*]const u8) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize { - return syscall3(SYS_unlinkat, @intCast(usize, dirfd), @ptrToInt(path), flags); + return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags); } pub fn waitpid(pid: i32, status: *i32, options: i32) usize { @@ -1120,8 +1121,8 @@ pub const empty_sigset = []usize{0} ** sigset_t.len; pub fn raise(sig: i32) usize { var set: sigset_t = undefined; blockAppSignals(&set); - const tid = @intCast(i32, syscall0(SYS_gettid)); - const ret = syscall2(SYS_tkill, @intCast(usize, tid), @intCast(usize, sig)); + const tid = syscall0(SYS_gettid); + const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig))); restoreSignals(&set); return ret; } @@ -1189,11 +1190,11 @@ pub const iovec_const = extern struct { }; pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { - return syscall3(SYS_getsockname, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len)); + return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); } pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { - return syscall3(SYS_getpeername, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len)); + return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len)); } pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { @@ -1201,47 +1202,47 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize { } pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize { - return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @intCast(usize, optval), @ptrToInt(optlen)); + return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen)); } pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize { - return syscall5(SYS_getsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); + return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen)); } pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize { - return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags); + return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); } pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize { - return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len); + return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len); } pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize { - return syscall3(SYS_recvmsg, @intCast(usize, fd), @ptrToInt(msg), flags); + return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags); } pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize { - return syscall6(SYS_recvfrom, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); + return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen)); } pub fn shutdown(fd: i32, how: i32) usize { - return syscall2(SYS_shutdown, @intCast(usize, fd), @intCast(usize, how)); + return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how))); } pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize { - return syscall3(SYS_bind, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len)); + return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len)); } pub fn listen(fd: i32, backlog: u32) usize { - return syscall2(SYS_listen, @intCast(usize, fd), backlog); + return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog); } pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize { - return syscall6(SYS_sendto, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); + return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen)); } pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize { - return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(*fd[0])); + return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0])); } pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { @@ -1249,11 +1250,11 @@ pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize { } pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize { - return syscall4(SYS_accept4, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len), flags); + return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags); } pub fn fstat(fd: i32, stat_buf: *Stat) usize { - return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf)); + return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf)); } // TODO https://github.com/ziglang/zig/issues/265 @@ -1268,7 +1269,7 @@ pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize { // TODO https://github.com/ziglang/zig/issues/265 pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize { - return syscall4(SYS_fstatat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(stat_buf), flags); + return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags); } // TODO https://github.com/ziglang/zig/issues/265 @@ -1355,7 +1356,7 @@ pub fn epoll_create1(flags: usize) usize { } pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize { - return syscall4(SYS_epoll_ctl, @intCast(usize, epoll_fd), @intCast(usize, op), @intCast(usize, fd), @ptrToInt(ev)); + return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev)); } pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize { @@ -1363,7 +1364,15 @@ pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout } pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize { - return syscall6(SYS_epoll_pwait, @intCast(usize, epoll_fd), @ptrToInt(events), @intCast(usize, maxevents), @intCast(usize, timeout), @ptrToInt(sigmask), @sizeOf(sigset_t)); + return syscall6( + SYS_epoll_pwait, + @bitCast(usize, isize(epoll_fd)), + @ptrToInt(events), + @intCast(usize, maxevents), + @bitCast(usize, isize(timeout)), + @ptrToInt(sigmask), + @sizeOf(sigset_t), + ); } pub fn eventfd(count: u32, flags: u32) usize { @@ -1371,7 +1380,7 @@ pub fn eventfd(count: u32, flags: u32) usize { } pub fn timerfd_create(clockid: i32, flags: u32) usize { - return syscall2(SYS_timerfd_create, @intCast(usize, clockid), flags); + return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags); } pub const itimerspec = extern struct { @@ -1380,11 +1389,11 @@ pub const itimerspec = extern struct { }; pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize { - return syscall2(SYS_timerfd_gettime, @intCast(usize, fd), @ptrToInt(curr_value)); + return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value)); } pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize { - return syscall4(SYS_timerfd_settime, @intCast(usize, fd), flags, @ptrToInt(new_value), @ptrToInt(old_value)); + return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value)); } pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330; diff --git a/std/os/path.zig b/std/os/path.zig index b3cfec1a3a..e61a0f84bc 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -1093,6 +1093,7 @@ pub const RealError = error{ NoSpaceLeft, FileSystem, BadPathName, + DeviceBusy, /// On Windows, file paths must be valid Unicode. InvalidUtf8, @@ -1183,11 +1184,20 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); defer os.close(fd); - var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined; + var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable; return os.readLinkC(out_buffer, proc_path.ptr); }, + Os.freebsd => { // XXX requires fdescfs + const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0); + defer os.close(fd); + + var buf: ["/dev/fd/-2147483648\x00".len]u8 = undefined; + const proc_path = fmt.bufPrint(buf[0..], "/dev/fd/{}\x00", fd) catch unreachable; + + return os.readLinkC(out_buffer, proc_path.ptr); + }, else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)), } } @@ -1202,7 +1212,7 @@ pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError! const pathname_w = try windows_util.sliceToPrefixedFileW(pathname); return realW(out_buffer, &pathname_w); }, - Os.macosx, Os.ios, Os.linux => { + Os.macosx, Os.ios, Os.linux, Os.freebsd => { const pathname_c = try os.toPosixPath(pathname); return realC(out_buffer, &pathname_c); }, diff --git a/std/os/windows/kernel32.zig b/std/os/windows/kernel32.zig index 7eec5faba9..202b8bffeb 100644 --- a/std/os/windows/kernel32.zig +++ b/std/os/windows/kernel32.zig @@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL; pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL; -pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL; +pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL; pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR; @@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE; pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD; -pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8; +pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16; -pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD; +pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD; pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL; diff --git a/std/os/zen.zig b/std/os/zen.zig index 6ac480b890..76c4df9d62 100644 --- a/std/os/zen.zig +++ b/std/os/zen.zig @@ -12,20 +12,20 @@ pub const Message = struct { args: [5]usize, payload: ?[]const u8, - pub fn from(mailbox_id: *const MailboxId) Message { + pub fn from(mailbox_id: MailboxId) Message { return Message{ .sender = MailboxId.Undefined, - .receiver = mailbox_id.*, + .receiver = mailbox_id, .code = undefined, .args = undefined, .payload = null, }; } - pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message { + pub fn to(mailbox_id: MailboxId, msg_code: usize, args: ...) Message { var message = Message{ .sender = MailboxId.This, - .receiver = mailbox_id.*, + .receiver = mailbox_id, .code = msg_code, .args = undefined, .payload = null, @@ -40,14 +40,14 @@ pub const Message = struct { return message; } - pub fn as(self: *const Message, sender: *const MailboxId) Message { - var message = self.*; - message.sender = sender.*; + pub fn as(self: Message, sender: MailboxId) Message { + var message = self; + message.sender = sender; return message; } - pub fn withPayload(self: *const Message, payload: []const u8) Message { - var message = self.*; + pub fn withPayload(self: Message, payload: []const u8) Message { + var message = self; message.payload = payload; return message; } @@ -93,7 +93,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize { STDIN_FILENO => { var i: usize = 0; while (i < count) : (i += 1) { - send(Message.to(Server.Keyboard, 0)); + send(&Message.to(Server.Keyboard, 0)); // FIXME: we should be certain that we are receiving from Keyboard. var message = Message.from(MailboxId.This); @@ -111,7 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize { pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { switch (fd) { STDOUT_FILENO, STDERR_FILENO => { - send(Message.to(Server.Terminal, 1).withPayload(buf[0..count])); + send(&Message.to(Server.Terminal, 1).withPayload(buf[0..count])); }, else => unreachable, } diff --git a/std/pdb.zig b/std/pdb.zig index 17275ab2a5..0cfc6a6cda 100644 --- a/std/pdb.zig +++ b/std/pdb.zig @@ -34,6 +34,7 @@ pub const DbiStreamHeader = packed struct { }; pub const SectionContribEntry = packed struct { + /// COFF Section index, 1-based Section: u16, Padding1: [2]u8, Offset: u32, @@ -507,11 +508,11 @@ const Msf = struct { allocator, ); - const stream_count = try self.directory.stream.readIntLe(u32); + const stream_count = try self.directory.stream.readIntLittle(u32); const stream_sizes = try allocator.alloc(u32, stream_count); for (stream_sizes) |*s| { - const size = try self.directory.stream.readIntLe(u32); + const size = try self.directory.stream.readIntLittle(u32); s.* = blockCountFromSize(size, superblock.BlockSize); } @@ -602,7 +603,7 @@ const MsfStream = struct { var i: u32 = 0; while (i < block_count) : (i += 1) { - stream.blocks[i] = try in.readIntLe(u32); + stream.blocks[i] = try in.readIntLittle(u32); } return stream; diff --git a/std/rand/index.zig b/std/rand/index.zig index bb607a067e..c335063e64 100644 --- a/std/rand/index.zig +++ b/std/rand/index.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.os.getRandomBytes(buf[0..]); -// const seed = mem.readIntLE(u64, buf[0..8]); +// const seed = mem.readIntSliceLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // @@ -52,11 +52,24 @@ pub const Random = struct { // use LE instead of native endian for better portability maybe? // TODO: endian portability is pointless if the underlying prng isn't endian portable. // TODO: document the endian portability of this library. - const byte_aligned_result = mem.readIntLE(ByteAlignedT, rand_bytes); + const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes); const unsigned_result = @truncate(UnsignedT, byte_aligned_result); return @bitCast(T, unsigned_result); } + /// Constant-time implementation off ::uintLessThan. + /// The results of this function may be biased. + pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T { + comptime assert(T.is_signed == false); + comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! + assert(0 < less_than); + if (T.bit_count <= 32) { + return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than)); + } else { + return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than)); + } + } + /// Returns an evenly distributed random unsigned integer `0 <= i < less_than`. /// This function assumes that the underlying ::fillFn produces evenly distributed values. /// Within this assumption, the runtime of this function is exponentially distributed. @@ -64,27 +77,52 @@ pub const Random = struct { /// the runtime of this function would technically be unbounded. /// However, if ::fillFn is backed by any evenly distributed pseudo random number generator, /// this function is guaranteed to return. - /// If you need deterministic runtime bounds, consider instead using `r.int(T) % less_than`, - /// which will usually be biased toward smaller values. + /// If you need deterministic runtime bounds, use `::uintLessThanBiased`. pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T { - assert(T.is_signed == false); + comptime assert(T.is_signed == false); + comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation! assert(0 < less_than); - - const last_group_size_minus_one: T = maxInt(T) % less_than; - if (last_group_size_minus_one == less_than - 1) { - // less_than is a power of two. - assert(math.floorPowerOfTwo(T, less_than) == less_than); - // There is no retry zone. The optimal retry_zone_start would be maxInt(T) + 1. - return r.int(T) % less_than; + // Small is typically u32 + const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32); + // Large is typically u64 + const Large = @IntType(false, Small.bit_count * 2); + + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Lemire's (with an extra tweak from me)" + var x: Small = r.int(Small); + var m: Large = Large(x) * Large(less_than); + var l: Small = @truncate(Small, m); + if (l < less_than) { + // TODO: workaround for https://github.com/ziglang/zig/issues/1770 + // should be: + // var t: Small = -%less_than; + var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than))); + + if (t >= less_than) { + t -= less_than; + if (t >= less_than) { + t %= less_than; + } + } + while (l < t) { + x = r.int(Small); + m = Large(x) * Large(less_than); + l = @truncate(Small, m); + } } - const retry_zone_start = maxInt(T) - last_group_size_minus_one; + return @intCast(T, m >> Small.bit_count); + } - while (true) { - const rand_val = r.int(T); - if (rand_val < retry_zone_start) { - return rand_val % less_than; - } + /// Constant-time implementation off ::uintAtMost. + /// The results of this function may be biased. + pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T { + assert(T.is_signed == false); + if (at_most == maxInt(T)) { + // have the full range + return r.int(T); } + return r.uintLessThanBiased(T, at_most + 1); } /// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`. @@ -99,6 +137,23 @@ pub const Random = struct { return r.uintLessThan(T, at_most + 1); } + /// Constant-time implementation off ::intRangeLessThan. + /// The results of this function may be biased. + pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T { + assert(at_least < less_than); + if (T.is_signed) { + // Two's complement makes this math pretty easy. + const UnsignedT = @IntType(false, T.bit_count); + const lo = @bitCast(UnsignedT, at_least); + const hi = @bitCast(UnsignedT, less_than); + const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo); + return @bitCast(T, result); + } else { + // The signed implementation would work fine, but we can use stricter arithmetic operators here. + return at_least + r.uintLessThanBiased(T, less_than - at_least); + } + } + /// Returns an evenly distributed random integer `at_least <= i < less_than`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -117,6 +172,23 @@ pub const Random = struct { } } + /// Constant-time implementation off ::intRangeAtMostBiased. + /// The results of this function may be biased. + pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T { + assert(at_least <= at_most); + if (T.is_signed) { + // Two's complement makes this math pretty easy. + const UnsignedT = @IntType(false, T.bit_count); + const lo = @bitCast(UnsignedT, at_least); + const hi = @bitCast(UnsignedT, at_most); + const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo); + return @bitCast(T, result); + } else { + // The signed implementation would work fine, but we can use stricter arithmetic operators here. + return at_least + r.uintAtMostBiased(T, at_most - at_least); + } + } + /// Returns an evenly distributed random integer `at_least <= i <= at_most`. /// See ::uintLessThan, which this function uses in most cases, /// for commentary on the runtime of this function. @@ -135,15 +207,11 @@ pub const Random = struct { } } - /// Return a random integer/boolean type. /// TODO: deprecated. use ::boolean or ::int instead. pub fn scalar(r: *Random, comptime T: type) T { - if (T == bool) return r.boolean(); - return r.int(T); + return if (T == bool) r.boolean() else r.int(T); } - /// Return a random integer with even distribution between `start` - /// inclusive and `end` exclusive. `start` must be less than `end`. /// TODO: deprecated. renamed to ::intRangeLessThan pub fn range(r: *Random, comptime T: type, start: T, end: T) T { return r.intRangeLessThan(T, start, end); @@ -206,6 +274,20 @@ pub const Random = struct { } }; +/// Convert a random integer 0 <= random_int <= maxValue(T), +/// into an integer 0 <= result < less_than. +/// This function introduces a minor bias. +pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T { + comptime assert(T.is_signed == false); + const T2 = @IntType(false, T.bit_count * 2); + + // adapted from: + // http://www.pcg-random.org/posts/bounded-rands.html + // "Integer Multiplication (Biased)" + var m: T2 = T2(random_int) * T2(less_than); + return @intCast(T, m >> T.bit_count); +} + const SequentialPrng = struct { const Self = @This(); random: Random, @@ -294,10 +376,19 @@ fn testRandomIntLessThan() void { var r = SequentialPrng.init(); r.next_value = 0xff; assert(r.random.uintLessThan(u8, 4) == 3); - r.next_value = 0xff; - assert(r.random.uintLessThan(u8, 3) == 0); + assert(r.next_value == 0); + assert(r.random.uintLessThan(u8, 4) == 0); assert(r.next_value == 1); + r.next_value = 0; + assert(r.random.uintLessThan(u64, 32) == 0); + + // trigger the bias rejection code path + r.next_value = 0; + assert(r.random.uintLessThan(u8, 3) == 0); + // verify we incremented twice + assert(r.next_value == 2); + r.next_value = 0xff; assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f); r.next_value = 0xff; @@ -311,16 +402,9 @@ fn testRandomIntLessThan() void { assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1); r.next_value = 0xff; - assert(r.random.intRangeLessThan(i64, -0x8000000000000000, 0) == -1); - r.next_value = 0xff; assert(r.random.intRangeLessThan(i3, -4, 0) == -1); r.next_value = 0xff; assert(r.random.intRangeLessThan(i3, -2, 2) == 1); - - // test retrying and eventually getting a good value - // start just out of bounds - r.next_value = 0x81; - assert(r.random.uintLessThan(u8, 0x81) == 0); } test "Random intAtMost" { @@ -332,9 +416,14 @@ fn testRandomIntAtMost() void { var r = SequentialPrng.init(); r.next_value = 0xff; assert(r.random.uintAtMost(u8, 3) == 3); - r.next_value = 0xff; + assert(r.next_value == 0); + assert(r.random.uintAtMost(u8, 3) == 0); + + // trigger the bias rejection code path + r.next_value = 0; assert(r.random.uintAtMost(u8, 2) == 0); - assert(r.next_value == 1); + // verify we incremented twice + assert(r.next_value == 2); r.next_value = 0xff; assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f); @@ -349,16 +438,42 @@ fn testRandomIntAtMost() void { assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1); r.next_value = 0xff; - assert(r.random.intRangeAtMost(i64, -0x8000000000000000, -1) == -1); - r.next_value = 0xff; assert(r.random.intRangeAtMost(i3, -4, -1) == -1); r.next_value = 0xff; assert(r.random.intRangeAtMost(i3, -2, 1) == 1); - // test retrying and eventually getting a good value - // start just out of bounds - r.next_value = 0x81; - assert(r.random.uintAtMost(u8, 0x80) == 0); + assert(r.random.uintAtMost(u0, 0) == 0); +} + +test "Random Biased" { + var r = DefaultPrng.init(0); + // Not thoroughly checking the logic here. + // Just want to execute all the paths with different types. + + assert(r.random.uintLessThanBiased(u1, 1) == 0); + assert(r.random.uintLessThanBiased(u32, 10) < 10); + assert(r.random.uintLessThanBiased(u64, 20) < 20); + + assert(r.random.uintAtMostBiased(u0, 0) == 0); + assert(r.random.uintAtMostBiased(u1, 0) <= 0); + assert(r.random.uintAtMostBiased(u32, 10) <= 10); + assert(r.random.uintAtMostBiased(u64, 20) <= 20); + + assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0); + assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1); + assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10); + assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10); + assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20); + assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20); + + // uncomment for broken module error: + //assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0); + assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0); + assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1); + assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10); + assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10); + assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20); + assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20); } // Generator to extend 64-bit seed values into longer sequences. @@ -870,12 +985,16 @@ test "Random range" { } fn testRange(r: *Random, start: i8, end: i8) void { + testRangeBias(r, start, end, true); + testRangeBias(r, start, end, false); +} +fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void { const count = @intCast(usize, i32(end) - i32(start)); var values_buffer = []bool{false} ** 0x100; const values = values_buffer[0..count]; var i: usize = 0; while (i < count) { - const value: i32 = r.intRangeLessThan(i8, start, end); + const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end); const index = @intCast(usize, value - start); if (!values[index]) { i += 1; diff --git a/std/rand/ziggurat.zig b/std/rand/ziggurat.zig index f7a1359f17..0636a5bfc4 100644 --- a/std/rand/ziggurat.zig +++ b/std/rand/ziggurat.zig @@ -12,7 +12,7 @@ const std = @import("../index.zig"); const math = std.math; const Random = std.rand.Random; -pub fn next_f64(random: *Random, comptime tables: *const ZigTable) f64 { +pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 { while (true) { // We manually construct a float from parts as we can avoid an extra random lookup here by // using the unused exponent for the lookup table entry. diff --git a/std/segmented_list.zig b/std/segmented_list.zig index c7c39651c9..d786e0becd 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -201,6 +201,11 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type self.dynamic_segments = self.allocator.shrink([*]T, self.dynamic_segments, new_cap_shelf_count); } + pub fn shrink(self: *Self, new_len: usize) void { + assert(new_len <= self.len); + self.len = new_len; + } + pub fn uncheckedAt(self: var, index: usize) AtType(@typeOf(self)) { if (index < prealloc_item_count) { return &self.prealloc_segment[index]; diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 53c646abdc..a15be317ab 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -20,10 +20,17 @@ comptime { nakedcc fn _start() noreturn { switch (builtin.arch) { - builtin.Arch.x86_64 => { - argc_ptr = asm ("lea (%%rsp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); + builtin.Arch.x86_64 => switch (builtin.os) { + builtin.Os.freebsd => { + argc_ptr = asm ("lea (%%rdi), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + else => { + argc_ptr = asm ("lea (%%rsp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, }, builtin.Arch.i386 => { argc_ptr = asm ("lea (%%esp), %[argc]" @@ -50,6 +57,9 @@ extern fn WinMainCRTStartup() noreturn { // TODO https://github.com/ziglang/zig/issues/265 fn posixCallMainAndExit() noreturn { + if (builtin.os == builtin.Os.freebsd) { + @setAlignStack(16); + } const argc = argc_ptr[0]; const argv = @ptrCast([*][*]u8, argc_ptr + 1); diff --git a/std/special/build_runner.zig b/std/special/build_runner.zig index 15e3534380..ff3b53619d 100644 --- a/std/special/build_runner.zig +++ b/std/special/build_runner.zig @@ -164,7 +164,6 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void { \\ \\General Options: \\ --help Print this help and exit - \\ --init Generate a build.zig template \\ --verbose Print commands before executing them \\ --prefix [path] Override default install prefix \\ --search-prefix [path] Add a path to look for binaries, libraries, headers diff --git a/std/special/compiler_rt/fixdfdi.zig b/std/special/compiler_rt/fixdfdi.zig new file mode 100644 index 0000000000..c108fd15aa --- /dev/null +++ b/std/special/compiler_rt/fixdfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfdi(a: f64) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i64, a); +} + +test "import fixdfdi" { + _ = @import("fixdfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfdi_test.zig b/std/special/compiler_rt/fixdfdi_test.zig new file mode 100644 index 0000000000..72bcf452d2 --- /dev/null +++ b/std/special/compiler_rt/fixdfdi_test.zig @@ -0,0 +1,66 @@ +const __fixdfdi = @import("fixdfdi.zig").__fixdfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfdi(a: f64, expected: i64) void { + const x = __fixdfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixdfdi" { + //warn("\n"); + + test__fixdfdi(-math.f64_max, math.minInt(i64)); + + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfdi(-2.01, -2); + test__fixdfdi(-2.0, -2); + test__fixdfdi(-1.99, -1); + test__fixdfdi(-1.0, -1); + test__fixdfdi(-0.99, 0); + test__fixdfdi(-0.5, 0); + test__fixdfdi(-math.f64_min, 0); + test__fixdfdi(0.0, 0); + test__fixdfdi(math.f64_min, 0); + test__fixdfdi(0.5, 0); + test__fixdfdi(0.99, 0); + test__fixdfdi(1.0, 1); + test__fixdfdi(1.5, 1); + test__fixdfdi(1.99, 1); + test__fixdfdi(2.0, 2); + test__fixdfdi(2.01, 2); + + test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixdfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixdfsi.zig b/std/special/compiler_rt/fixdfsi.zig new file mode 100644 index 0000000000..83a17b2b0d --- /dev/null +++ b/std/special/compiler_rt/fixdfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfsi(a: f64) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i32, a); +} + +test "import fixdfsi" { + _ = @import("fixdfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfsi_test.zig b/std/special/compiler_rt/fixdfsi_test.zig new file mode 100644 index 0000000000..147f46534a --- /dev/null +++ b/std/special/compiler_rt/fixdfsi_test.zig @@ -0,0 +1,74 @@ +const __fixdfsi = @import("fixdfsi.zig").__fixdfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfsi(a: f64, expected: i32) void { + const x = __fixdfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixdfsi" { + //warn("\n"); + + test__fixdfsi(-math.f64_max, math.minInt(i32)); + + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixdfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixdfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixdfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixdfsi(-0x1.000000p+31, -0x80000000); + test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + + test__fixdfsi(-2.01, -2); + test__fixdfsi(-2.0, -2); + test__fixdfsi(-1.99, -1); + test__fixdfsi(-1.0, -1); + test__fixdfsi(-0.99, 0); + test__fixdfsi(-0.5, 0); + test__fixdfsi(-math.f64_min, 0); + test__fixdfsi(0.0, 0); + test__fixdfsi(math.f64_min, 0); + test__fixdfsi(0.5, 0); + test__fixdfsi(0.99, 0); + test__fixdfsi(1.0, 1); + test__fixdfsi(1.5, 1); + test__fixdfsi(1.99, 1); + test__fixdfsi(2.0, 2); + test__fixdfsi(2.01, 2); + + test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixdfsi(math.f64_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixdfti.zig b/std/special/compiler_rt/fixdfti.zig new file mode 100644 index 0000000000..e30f885cf6 --- /dev/null +++ b/std/special/compiler_rt/fixdfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixdfti(a: f64) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f64, i128, a); +} + +test "import fixdfti" { + _ = @import("fixdfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixdfti_test.zig b/std/special/compiler_rt/fixdfti_test.zig new file mode 100644 index 0000000000..5bb3a31a3f --- /dev/null +++ b/std/special/compiler_rt/fixdfti_test.zig @@ -0,0 +1,66 @@ +const __fixdfti = @import("fixdfti.zig").__fixdfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixdfti(a: f64, expected: i128) void { + const x = __fixdfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixdfti" { + //warn("\n"); + + test__fixdfti(-math.f64_max, math.minInt(i128)); + + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixdfti(-2.01, -2); + test__fixdfti(-2.0, -2); + test__fixdfti(-1.99, -1); + test__fixdfti(-1.0, -1); + test__fixdfti(-0.99, 0); + test__fixdfti(-0.5, 0); + test__fixdfti(-math.f64_min, 0); + test__fixdfti(0.0, 0); + test__fixdfti(math.f64_min, 0); + test__fixdfti(0.5, 0); + test__fixdfti(0.99, 0); + test__fixdfti(1.0, 1); + test__fixdfti(1.5, 1); + test__fixdfti(1.99, 1); + test__fixdfti(2.0, 2); + test__fixdfti(2.01, 2); + + test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixdfti(math.f64_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixint.zig b/std/special/compiler_rt/fixint.zig new file mode 100644 index 0000000000..fd31798cc2 --- /dev/null +++ b/std/special/compiler_rt/fixint.zig @@ -0,0 +1,74 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const Log2Int = std.math.Log2Int; +const maxInt = std.math.maxInt; +const minInt = std.math.minInt; + +const DBG = false; + +pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t { + @setRuntimeSafety(is_test); + + const rep_t = switch (fp_t) { + f32 => u32, + f64 => u64, + f128 => u128, + else => unreachable, + }; + const significandBits = switch (fp_t) { + f32 => 23, + f64 => 52, + f128 => 112, + else => unreachable, + }; + + const typeWidth = rep_t.bit_count; + const exponentBits = (typeWidth - significandBits - 1); + const signBit = (rep_t(1) << (significandBits + exponentBits)); + const maxExponent = ((1 << exponentBits) - 1); + const exponentBias = (maxExponent >> 1); + + const implicitBit = (rep_t(1) << significandBits); + const significandMask = (implicitBit - 1); + + // Break a into sign, exponent, significand + const aRep: rep_t = @bitCast(rep_t, a); + const absMask = signBit - 1; + const aAbs: rep_t = aRep & absMask; + + const negative = (aRep & signBit) != 0; + const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias; + const significand: rep_t = (aAbs & significandMask) | implicitBit; + + // If exponent is negative, the uint_result is zero. + if (exponent < 0) return 0; + + // The unsigned result needs to be large enough to handle an fixint_t or rep_t + const fixuint_t = @IntType(false, fixint_t.bit_count); + const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t; + var uint_result: UintResultType = undefined; + + // If the value is too large for the integer type, saturate. + if (@intCast(usize, exponent) >= fixint_t.bit_count) { + return if (negative) fixint_t(minInt(fixint_t)) else fixint_t(maxInt(fixint_t)); + } + + // If 0 <= exponent < significandBits, right shift else left shift + if (exponent < significandBits) { + uint_result = @intCast(UintResultType, significand) >> @intCast(Log2Int(UintResultType), significandBits - exponent); + } else { + uint_result = @intCast(UintResultType, significand) << @intCast(Log2Int(UintResultType), exponent - significandBits); + } + + // Cast to final signed result + if (negative) { + return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result); + } else { + return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result); + } +} + +test "import fixint" { + _ = @import("fixint_test.zig"); +} diff --git a/std/special/compiler_rt/fixint_test.zig b/std/special/compiler_rt/fixint_test.zig new file mode 100644 index 0000000000..6676bddbee --- /dev/null +++ b/std/special/compiler_rt/fixint_test.zig @@ -0,0 +1,152 @@ +const is_test = @import("builtin").is_test; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +const fixint = @import("fixint.zig").fixint; + +fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void { + const x = fixint(fp_t, fixint_t, a); + //warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected); + assert(x == expected); +} + +test "fixint.i1" { + test__fixint(f32, i1, -math.inf_f32, -1); + test__fixint(f32, i1, -math.f32_max, -1); + test__fixint(f32, i1, -2.0, -1); + test__fixint(f32, i1, -1.1, -1); + test__fixint(f32, i1, -1.0, -1); + test__fixint(f32, i1, -0.9, 0); + test__fixint(f32, i1, -0.1, 0); + test__fixint(f32, i1, -math.f32_min, 0); + test__fixint(f32, i1, -0.0, 0); + test__fixint(f32, i1, 0.0, 0); + test__fixint(f32, i1, math.f32_min, 0); + test__fixint(f32, i1, 0.1, 0); + test__fixint(f32, i1, 0.9, 0); + test__fixint(f32, i1, 1.0, 0); + test__fixint(f32, i1, 2.0, 0); + test__fixint(f32, i1, math.f32_max, 0); + test__fixint(f32, i1, math.inf_f32, 0); +} + +test "fixint.i2" { + test__fixint(f32, i2, -math.inf_f32, -2); + test__fixint(f32, i2, -math.f32_max, -2); + test__fixint(f32, i2, -2.0, -2); + test__fixint(f32, i2, -1.9, -1); + test__fixint(f32, i2, -1.1, -1); + test__fixint(f32, i2, -1.0, -1); + test__fixint(f32, i2, -0.9, 0); + test__fixint(f32, i2, -0.1, 0); + test__fixint(f32, i2, -math.f32_min, 0); + test__fixint(f32, i2, -0.0, 0); + test__fixint(f32, i2, 0.0, 0); + test__fixint(f32, i2, math.f32_min, 0); + test__fixint(f32, i2, 0.1, 0); + test__fixint(f32, i2, 0.9, 0); + test__fixint(f32, i2, 1.0, 1); + test__fixint(f32, i2, 2.0, 1); + test__fixint(f32, i2, math.f32_max, 1); + test__fixint(f32, i2, math.inf_f32, 1); +} + +test "fixint.i3" { + test__fixint(f32, i3, -math.inf_f32, -4); + test__fixint(f32, i3, -math.f32_max, -4); + test__fixint(f32, i3, -4.0, -4); + test__fixint(f32, i3, -3.0, -3); + test__fixint(f32, i3, -2.0, -2); + test__fixint(f32, i3, -1.9, -1); + test__fixint(f32, i3, -1.1, -1); + test__fixint(f32, i3, -1.0, -1); + test__fixint(f32, i3, -0.9, 0); + test__fixint(f32, i3, -0.1, 0); + test__fixint(f32, i3, -math.f32_min, 0); + test__fixint(f32, i3, -0.0, 0); + test__fixint(f32, i3, 0.0, 0); + test__fixint(f32, i3, math.f32_min, 0); + test__fixint(f32, i3, 0.1, 0); + test__fixint(f32, i3, 0.9, 0); + test__fixint(f32, i3, 1.0, 1); + test__fixint(f32, i3, 2.0, 2); + test__fixint(f32, i3, 3.0, 3); + test__fixint(f32, i3, 4.0, 3); + test__fixint(f32, i3, math.f32_max, 3); + test__fixint(f32, i3, math.inf_f32, 3); +} + +test "fixint.i32" { + test__fixint(f64, i32, -math.inf_f64, math.minInt(i32)); + test__fixint(f64, i32, -math.f64_max, math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32)), math.minInt(i32)); + test__fixint(f64, i32, f64(math.minInt(i32))+1, math.minInt(i32)+1); + test__fixint(f64, i32, -2.0, -2); + test__fixint(f64, i32, -1.9, -1); + test__fixint(f64, i32, -1.1, -1); + test__fixint(f64, i32, -1.0, -1); + test__fixint(f64, i32, -0.9, 0); + test__fixint(f64, i32, -0.1, 0); + test__fixint(f64, i32, -math.f32_min, 0); + test__fixint(f64, i32, -0.0, 0); + test__fixint(f64, i32, 0.0, 0); + test__fixint(f64, i32, math.f32_min, 0); + test__fixint(f64, i32, 0.1, 0); + test__fixint(f64, i32, 0.9, 0); + test__fixint(f64, i32, 1.0, 1); + test__fixint(f64, i32, f64(math.maxInt(i32))-1, math.maxInt(i32)-1); + test__fixint(f64, i32, f64(math.maxInt(i32)), math.maxInt(i32)); + test__fixint(f64, i32, math.f64_max, math.maxInt(i32)); + test__fixint(f64, i32, math.inf_f64, math.maxInt(i32)); +} + +test "fixint.i64" { + test__fixint(f64, i64, -math.inf_f64, math.minInt(i64)); + test__fixint(f64, i64, -math.f64_max, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)), math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64))+1, math.minInt(i64)); + test__fixint(f64, i64, f64(math.minInt(i64)/2), math.minInt(i64)/2); + test__fixint(f64, i64, -2.0, -2); + test__fixint(f64, i64, -1.9, -1); + test__fixint(f64, i64, -1.1, -1); + test__fixint(f64, i64, -1.0, -1); + test__fixint(f64, i64, -0.9, 0); + test__fixint(f64, i64, -0.1, 0); + test__fixint(f64, i64, -math.f32_min, 0); + test__fixint(f64, i64, -0.0, 0); + test__fixint(f64, i64, 0.0, 0); + test__fixint(f64, i64, math.f32_min, 0); + test__fixint(f64, i64, 0.1, 0); + test__fixint(f64, i64, 0.9, 0); + test__fixint(f64, i64, 1.0, 1); + test__fixint(f64, i64, f64(math.maxInt(i64))-1, math.maxInt(i64)); + test__fixint(f64, i64, f64(math.maxInt(i64)), math.maxInt(i64)); + test__fixint(f64, i64, math.f64_max, math.maxInt(i64)); + test__fixint(f64, i64, math.inf_f64, math.maxInt(i64)); +} + +test "fixint.i128" { + test__fixint(f64, i128, -math.inf_f64, math.minInt(i128)); + test__fixint(f64, i128, -math.f64_max, math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128)), math.minInt(i128)); + test__fixint(f64, i128, f64(math.minInt(i128))+1, math.minInt(i128)); + test__fixint(f64, i128, -2.0, -2); + test__fixint(f64, i128, -1.9, -1); + test__fixint(f64, i128, -1.1, -1); + test__fixint(f64, i128, -1.0, -1); + test__fixint(f64, i128, -0.9, 0); + test__fixint(f64, i128, -0.1, 0); + test__fixint(f64, i128, -math.f32_min, 0); + test__fixint(f64, i128, -0.0, 0); + test__fixint(f64, i128, 0.0, 0); + test__fixint(f64, i128, math.f32_min, 0); + test__fixint(f64, i128, 0.1, 0); + test__fixint(f64, i128, 0.9, 0); + test__fixint(f64, i128, 1.0, 1); + test__fixint(f64, i128, f64(math.maxInt(i128))-1, math.maxInt(i128)); + test__fixint(f64, i128, f64(math.maxInt(i128)), math.maxInt(i128)); + test__fixint(f64, i128, math.f64_max, math.maxInt(i128)); + test__fixint(f64, i128, math.inf_f64, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixsfdi.zig b/std/special/compiler_rt/fixsfdi.zig new file mode 100644 index 0000000000..ffa81d13ab --- /dev/null +++ b/std/special/compiler_rt/fixsfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfdi(a: f32) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i64, a); +} + +test "import fixsfdi" { + _ = @import("fixsfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfdi_test.zig b/std/special/compiler_rt/fixsfdi_test.zig new file mode 100644 index 0000000000..ef8e50e38e --- /dev/null +++ b/std/special/compiler_rt/fixsfdi_test.zig @@ -0,0 +1,68 @@ +const __fixsfdi = @import("fixsfdi.zig").__fixsfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfdi(a: f32, expected: i64) void { + const x = __fixsfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixsfdi" { + //warn("\n"); + + test__fixsfdi(-math.f32_max, math.minInt(i64)); + + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixsfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfdi(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfdi(-2.01, -2); + test__fixsfdi(-2.0, -2); + test__fixsfdi(-1.99, -1); + test__fixsfdi(-1.0, -1); + test__fixsfdi(-0.99, 0); + test__fixsfdi(-0.5, 0); + test__fixsfdi(-math.f32_min, 0); + test__fixsfdi(0.0, 0); + test__fixsfdi(math.f32_min, 0); + test__fixsfdi(0.5, 0); + test__fixsfdi(0.99, 0); + test__fixsfdi(1.0, 1); + test__fixsfdi(1.5, 1); + test__fixsfdi(1.99, 1); + test__fixsfdi(2.0, 2); + test__fixsfdi(2.01, 2); + + test__fixsfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfdi(0x1.FFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixsfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixsfdi(math.f64_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixsfsi.zig b/std/special/compiler_rt/fixsfsi.zig new file mode 100644 index 0000000000..9a94b4395b --- /dev/null +++ b/std/special/compiler_rt/fixsfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfsi(a: f32) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i32, a); +} + +test "import fixsfsi" { + _ = @import("fixsfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfsi_test.zig b/std/special/compiler_rt/fixsfsi_test.zig new file mode 100644 index 0000000000..d5c0ba5c2a --- /dev/null +++ b/std/special/compiler_rt/fixsfsi_test.zig @@ -0,0 +1,76 @@ +const __fixsfsi = @import("fixsfsi.zig").__fixsfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfsi(a: f32, expected: i32) void { + const x = __fixsfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixsfsi" { + //warn("\n"); + + test__fixsfsi(-math.f32_max, math.minInt(i32)); + + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixsfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixsfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixsfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixsfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixsfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixsfsi(-0x1.000000p+31, -0x80000000); + test__fixsfsi(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfsi(-2.01, -2); + test__fixsfsi(-2.0, -2); + test__fixsfsi(-1.99, -1); + test__fixsfsi(-1.0, -1); + test__fixsfsi(-0.99, 0); + test__fixsfsi(-0.5, 0); + test__fixsfsi(-math.f32_min, 0); + test__fixsfsi(0.0, 0); + test__fixsfsi(math.f32_min, 0); + test__fixsfsi(0.5, 0); + test__fixsfsi(0.99, 0); + test__fixsfsi(1.0, 1); + test__fixsfsi(1.5, 1); + test__fixsfsi(1.99, 1); + test__fixsfsi(2.0, 2); + test__fixsfsi(2.01, 2); + + test__fixsfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfsi(0x1.FFFFFFp+30, 0x7FFFFFFF); + test__fixsfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixsfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixsfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixsfsi(math.f32_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixsfti.zig b/std/special/compiler_rt/fixsfti.zig new file mode 100644 index 0000000000..806a1678aa --- /dev/null +++ b/std/special/compiler_rt/fixsfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixsfti(a: f32) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f32, i128, a); +} + +test "import fixsfti" { + _ = @import("fixsfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixsfti_test.zig b/std/special/compiler_rt/fixsfti_test.zig new file mode 100644 index 0000000000..d693143b18 --- /dev/null +++ b/std/special/compiler_rt/fixsfti_test.zig @@ -0,0 +1,84 @@ +const __fixsfti = @import("fixsfti.zig").__fixsfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixsfti(a: f32, expected: i128) void { + const x = __fixsfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u32, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixsfti" { + //warn("\n"); + + test__fixsfti(-math.f32_max, math.minInt(i128)); + + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixsfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFF0000000p+126, -0x80000000000000000000000000000000); + test__fixsfti(-0x1.FFFFFE0000000p+126, -0x7FFFFF80000000000000000000000000); + test__fixsfti(-0x1.FFFFFC0000000p+126, -0x7FFFFF00000000000000000000000000); + + test__fixsfti(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixsfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFFFFFFFFEp+62, -0x8000000000000000); + + test__fixsfti(-0x1.FFFFFFp+62, -0x8000000000000000); + test__fixsfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixsfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixsfti(-0x1.000000p+31, -0x80000000); + test__fixsfti(-0x1.FFFFFFp+30, -0x80000000); + test__fixsfti(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixsfti(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixsfti(-2.01, -2); + test__fixsfti(-2.0, -2); + test__fixsfti(-1.99, -1); + test__fixsfti(-1.0, -1); + test__fixsfti(-0.99, 0); + test__fixsfti(-0.5, 0); + test__fixsfti(-math.f32_min, 0); + test__fixsfti(0.0, 0); + test__fixsfti(math.f32_min, 0); + test__fixsfti(0.5, 0); + test__fixsfti(0.99, 0); + test__fixsfti(1.0, 1); + test__fixsfti(1.5, 1); + test__fixsfti(1.99, 1); + test__fixsfti(2.0, 2); + test__fixsfti(2.01, 2); + + test__fixsfti(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixsfti(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixsfti(0x1.FFFFFFp+30, 0x80000000); + test__fixsfti(0x1.000000p+31, 0x80000000); + + test__fixsfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixsfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + test__fixsfti(0x1.FFFFFFp+62, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFFFFFFFFEp+62, 0x8000000000000000); + test__fixsfti(0x1.FFFFFFFFFFFFFp+62, 0x8000000000000000); + test__fixsfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixsfti(0x1.0000000000001p+63, 0x8000000000000000); + + test__fixsfti(0x1.FFFFFC0000000p+126, 0x7FFFFF00000000000000000000000000); + test__fixsfti(0x1.FFFFFE0000000p+126, 0x7FFFFF80000000000000000000000000); + test__fixsfti(0x1.FFFFFF0000000p+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixsfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixsfti(math.f32_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/fixtfdi.zig b/std/special/compiler_rt/fixtfdi.zig new file mode 100644 index 0000000000..8d99231b74 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfdi(a: f128) i64 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i64, a); +} + +test "import fixtfdi" { + _ = @import("fixtfdi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfdi_test.zig b/std/special/compiler_rt/fixtfdi_test.zig new file mode 100644 index 0000000000..58ccbc5832 --- /dev/null +++ b/std/special/compiler_rt/fixtfdi_test.zig @@ -0,0 +1,76 @@ +const __fixtfdi = @import("fixtfdi.zig").__fixtfdi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfdi(a: f128, expected: i64) void { + const x = __fixtfdi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u64, expected)); + assert(x == expected); +} + +test "fixtfdi" { + //warn("\n"); + + test__fixtfdi(-math.f128_max, math.minInt(i64)); + + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64)); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000000p+127, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000); + + test__fixtfdi(-0x1.0000000000001p+63, -0x8000000000000000); + test__fixtfdi(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfdi(-0x1.FFFFFEp+62, -0x7FFFFF8000000000); + test__fixtfdi(-0x1.FFFFFCp+62, -0x7FFFFF0000000000); + + test__fixtfdi(-0x1.000000p+31, -0x80000000); + test__fixtfdi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfdi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfdi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfdi(-2.01, -2); + test__fixtfdi(-2.0, -2); + test__fixtfdi(-1.99, -1); + test__fixtfdi(-1.0, -1); + test__fixtfdi(-0.99, 0); + test__fixtfdi(-0.5, 0); + test__fixtfdi(-math.f64_min, 0); + test__fixtfdi(0.0, 0); + test__fixtfdi(math.f64_min, 0); + test__fixtfdi(0.5, 0); + test__fixtfdi(0.99, 0); + test__fixtfdi(1.0, 1); + test__fixtfdi(1.5, 1); + test__fixtfdi(1.99, 1); + test__fixtfdi(2.0, 2); + test__fixtfdi(2.01, 2); + + test__fixtfdi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfdi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfdi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfdi(0x1.000000p+31, 0x80000000); + + test__fixtfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF); + + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF); + test__fixtfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64)); + + test__fixtfdi(math.f128_max, math.maxInt(i64)); +} diff --git a/std/special/compiler_rt/fixtfsi.zig b/std/special/compiler_rt/fixtfsi.zig new file mode 100644 index 0000000000..f3f83634b2 --- /dev/null +++ b/std/special/compiler_rt/fixtfsi.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfsi(a: f128) i32 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i32, a); +} + +test "import fixtfsi" { + _ = @import("fixtfsi_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfsi_test.zig b/std/special/compiler_rt/fixtfsi_test.zig new file mode 100644 index 0000000000..7a3cc7f46c --- /dev/null +++ b/std/special/compiler_rt/fixtfsi_test.zig @@ -0,0 +1,76 @@ +const __fixtfsi = @import("fixtfsi.zig").__fixtfsi; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfsi(a: f128, expected: i32) void { + const x = __fixtfsi(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u32({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u32, expected)); + assert(x == expected); +} + +test "fixtfsi" { + //warn("\n"); + + test__fixtfsi(-math.f128_max, math.minInt(i32)); + + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32)); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000); + + test__fixtfsi(-0x1.0000000000000p+127, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000); + + test__fixtfsi(-0x1.0000000000001p+63, -0x80000000); + test__fixtfsi(-0x1.0000000000000p+63, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000); + + test__fixtfsi(-0x1.FFFFFEp+62, -0x80000000); + test__fixtfsi(-0x1.FFFFFCp+62, -0x80000000); + + test__fixtfsi(-0x1.000000p+31, -0x80000000); + test__fixtfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0); + test__fixtfsi(-0x1.FFFFFEp+30, -0x7FFFFF80); + test__fixtfsi(-0x1.FFFFFCp+30, -0x7FFFFF00); + + test__fixtfsi(-2.01, -2); + test__fixtfsi(-2.0, -2); + test__fixtfsi(-1.99, -1); + test__fixtfsi(-1.0, -1); + test__fixtfsi(-0.99, 0); + test__fixtfsi(-0.5, 0); + test__fixtfsi(-math.f32_min, 0); + test__fixtfsi(0.0, 0); + test__fixtfsi(math.f32_min, 0); + test__fixtfsi(0.5, 0); + test__fixtfsi(0.99, 0); + test__fixtfsi(1.0, 1); + test__fixtfsi(1.5, 1); + test__fixtfsi(1.99, 1); + test__fixtfsi(2.0, 2); + test__fixtfsi(2.01, 2); + + test__fixtfsi(0x1.FFFFFCp+30, 0x7FFFFF00); + test__fixtfsi(0x1.FFFFFEp+30, 0x7FFFFF80); + test__fixtfsi(0x1.FFFFFFp+30, 0x7FFFFFC0); + test__fixtfsi(0x1.000000p+31, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFCp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFEp+62, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+63, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000001p+63, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF); + test__fixtfsi(0x1.0000000000000p+127, 0x7FFFFFFF); + + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF); + test__fixtfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32)); + + test__fixtfsi(math.f128_max, math.maxInt(i32)); +} diff --git a/std/special/compiler_rt/fixtfti.zig b/std/special/compiler_rt/fixtfti.zig new file mode 100644 index 0000000000..07d38f2c3b --- /dev/null +++ b/std/special/compiler_rt/fixtfti.zig @@ -0,0 +1,11 @@ +const fixint = @import("fixint.zig").fixint; +const builtin = @import("builtin"); + +pub extern fn __fixtfti(a: f128) i128 { + @setRuntimeSafety(builtin.is_test); + return fixint(f128, i128, a); +} + +test "import fixtfti" { + _ = @import("fixtfti_test.zig"); +} diff --git a/std/special/compiler_rt/fixtfti_test.zig b/std/special/compiler_rt/fixtfti_test.zig new file mode 100644 index 0000000000..520009486a --- /dev/null +++ b/std/special/compiler_rt/fixtfti_test.zig @@ -0,0 +1,66 @@ +const __fixtfti = @import("fixtfti.zig").__fixtfti; +const std = @import("std"); +const math = std.math; +const assert = std.debug.assert; +const warn = std.debug.warn; + +fn test__fixtfti(a: f128, expected: i128) void { + const x = __fixtfti(a); + //warn("a={}:{x} x={}:{x} expected={}:{x}:u128({x})\n", a, @bitCast(u128, a), x, x, expected, expected, @bitCast(u128, expected)); + assert(x == expected); +} + +test "fixtfti" { + //warn("\n"); + + test__fixtfti(-math.f128_max, math.minInt(i128)); + + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128)); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000); + + test__fixtfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000); + + test__fixtfti(-0x1.0000000000001p+63, -0x8000000000000800); + test__fixtfti(-0x1.0000000000000p+63, -0x8000000000000000); + test__fixtfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00); + test__fixtfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800); + + test__fixtfti(-0x1.FFFFFEp+62, -0x7fffff8000000000); + test__fixtfti(-0x1.FFFFFCp+62, -0x7fffff0000000000); + + test__fixtfti(-2.01, -2); + test__fixtfti(-2.0, -2); + test__fixtfti(-1.99, -1); + test__fixtfti(-1.0, -1); + test__fixtfti(-0.99, 0); + test__fixtfti(-0.5, 0); + test__fixtfti(-math.f128_min, 0); + test__fixtfti(0.0, 0); + test__fixtfti(math.f128_min, 0); + test__fixtfti(0.5, 0); + test__fixtfti(0.99, 0); + test__fixtfti(1.0, 1); + test__fixtfti(1.5, 1); + test__fixtfti(1.99, 1); + test__fixtfti(2.0, 2); + test__fixtfti(2.01, 2); + + test__fixtfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000); + test__fixtfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800); + test__fixtfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00); + test__fixtfti(0x1.0000000000000p+63, 0x8000000000000000); + test__fixtfti(0x1.0000000000001p+63, 0x8000000000000800); + + test__fixtfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000); + test__fixtfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000); + test__fixtfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + test__fixtfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128)); + + test__fixtfti(math.f128_max, math.maxInt(i128)); +} diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index c826af83bc..4bbfc2b290 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -52,6 +52,16 @@ comptime { @export("__fixunstfdi", @import("fixunstfdi.zig").__fixunstfdi, linkage); @export("__fixunstfti", @import("fixunstfti.zig").__fixunstfti, linkage); + @export("__fixdfdi", @import("fixdfdi.zig").__fixdfdi, linkage); + @export("__fixdfsi", @import("fixdfsi.zig").__fixdfsi, linkage); + @export("__fixdfti", @import("fixdfti.zig").__fixdfti, linkage); + @export("__fixsfdi", @import("fixsfdi.zig").__fixsfdi, linkage); + @export("__fixsfsi", @import("fixsfsi.zig").__fixsfsi, linkage); + @export("__fixsfti", @import("fixsfti.zig").__fixsfti, linkage); + @export("__fixtfdi", @import("fixtfdi.zig").__fixtfdi, linkage); + @export("__fixtfsi", @import("fixtfsi.zig").__fixtfsi, linkage); + @export("__fixtfti", @import("fixtfti.zig").__fixtfti, linkage); + @export("__udivmoddi4", @import("udivmoddi4.zig").__udivmoddi4, linkage); @export("__udivsi3", __udivsi3, linkage); @@ -59,7 +69,7 @@ comptime { @export("__umoddi3", __umoddi3, linkage); @export("__udivmodsi4", __udivmodsi4, linkage); - if (isArmArch()) { + if (is_arm_arch and !is_arm_64) { @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); @export("__aeabi_uidiv", __udivsi3, linkage); @@ -149,68 +159,85 @@ extern fn __aeabi_uldivmod(numerator: u64, denominator: u64) AeabiUlDivModResult return result; } -fn isArmArch() bool { - return switch (builtin.arch) { - builtin.Arch.armv8_3a, - builtin.Arch.armv8_2a, - builtin.Arch.armv8_1a, - builtin.Arch.armv8, - builtin.Arch.armv8r, - builtin.Arch.armv8m_baseline, - builtin.Arch.armv8m_mainline, - builtin.Arch.armv7, - builtin.Arch.armv7em, - builtin.Arch.armv7m, - builtin.Arch.armv7s, - builtin.Arch.armv7k, - builtin.Arch.armv7ve, - builtin.Arch.armv6, - builtin.Arch.armv6m, - builtin.Arch.armv6k, - builtin.Arch.armv6t2, - builtin.Arch.armv5, - builtin.Arch.armv5te, - builtin.Arch.armv4t, - builtin.Arch.armebv8_3a, - builtin.Arch.armebv8_2a, - builtin.Arch.armebv8_1a, - builtin.Arch.armebv8, - builtin.Arch.armebv8r, - builtin.Arch.armebv8m_baseline, - builtin.Arch.armebv8m_mainline, - builtin.Arch.armebv7, - builtin.Arch.armebv7em, - builtin.Arch.armebv7m, - builtin.Arch.armebv7s, - builtin.Arch.armebv7k, - builtin.Arch.armebv7ve, - builtin.Arch.armebv6, - builtin.Arch.armebv6m, - builtin.Arch.armebv6k, - builtin.Arch.armebv6t2, - builtin.Arch.armebv5, - builtin.Arch.armebv5te, - builtin.Arch.armebv4t, - builtin.Arch.aarch64v8_3a, - builtin.Arch.aarch64v8_2a, - builtin.Arch.aarch64v8_1a, - builtin.Arch.aarch64v8, - builtin.Arch.aarch64v8r, - builtin.Arch.aarch64v8m_baseline, - builtin.Arch.aarch64v8m_mainline, - builtin.Arch.aarch64_bev8_3a, - builtin.Arch.aarch64_bev8_2a, - builtin.Arch.aarch64_bev8_1a, - builtin.Arch.aarch64_bev8, - builtin.Arch.aarch64_bev8r, - builtin.Arch.aarch64_bev8m_baseline, - builtin.Arch.aarch64_bev8m_mainline, - builtin.Arch.thumb, - builtin.Arch.thumbeb, - => true, - else => false, - }; -} +const is_arm_64 = switch (builtin.arch) { + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + => true, + else => false, +}; + +const is_arm_arch = switch (builtin.arch) { + builtin.Arch.armv8_3a, + builtin.Arch.armv8_2a, + builtin.Arch.armv8_1a, + builtin.Arch.armv8, + builtin.Arch.armv8r, + builtin.Arch.armv8m_baseline, + builtin.Arch.armv8m_mainline, + builtin.Arch.armv7, + builtin.Arch.armv7em, + builtin.Arch.armv7m, + builtin.Arch.armv7s, + builtin.Arch.armv7k, + builtin.Arch.armv7ve, + builtin.Arch.armv6, + builtin.Arch.armv6m, + builtin.Arch.armv6k, + builtin.Arch.armv6t2, + builtin.Arch.armv5, + builtin.Arch.armv5te, + builtin.Arch.armv4t, + builtin.Arch.armebv8_3a, + builtin.Arch.armebv8_2a, + builtin.Arch.armebv8_1a, + builtin.Arch.armebv8, + builtin.Arch.armebv8r, + builtin.Arch.armebv8m_baseline, + builtin.Arch.armebv8m_mainline, + builtin.Arch.armebv7, + builtin.Arch.armebv7em, + builtin.Arch.armebv7m, + builtin.Arch.armebv7s, + builtin.Arch.armebv7k, + builtin.Arch.armebv7ve, + builtin.Arch.armebv6, + builtin.Arch.armebv6m, + builtin.Arch.armebv6k, + builtin.Arch.armebv6t2, + builtin.Arch.armebv5, + builtin.Arch.armebv5te, + builtin.Arch.armebv4t, + builtin.Arch.aarch64v8_3a, + builtin.Arch.aarch64v8_2a, + builtin.Arch.aarch64v8_1a, + builtin.Arch.aarch64v8, + builtin.Arch.aarch64v8r, + builtin.Arch.aarch64v8m_baseline, + builtin.Arch.aarch64v8m_mainline, + builtin.Arch.aarch64_bev8_3a, + builtin.Arch.aarch64_bev8_2a, + builtin.Arch.aarch64_bev8_1a, + builtin.Arch.aarch64_bev8, + builtin.Arch.aarch64_bev8r, + builtin.Arch.aarch64_bev8m_baseline, + builtin.Arch.aarch64_bev8m_mainline, + builtin.Arch.thumb, + builtin.Arch.thumbeb, + => true, + else => false, +}; nakedcc fn __aeabi_uidivmod() void { @setRuntimeSafety(false); diff --git a/std/unicode.zig b/std/unicode.zig index 559a2e739a..2e542bcb19 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -208,7 +208,7 @@ pub const Utf8View = struct { } }; -const Utf8Iterator = struct { +pub const Utf8Iterator = struct { bytes: []const u8, i: usize, @@ -249,12 +249,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u32 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c0: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c0 & ~u32(0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u32 = mem.readIntLE(u16, it.bytes[it.i .. it.i + 2]); + const c1: u32 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); if (c1 & ~u32(0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -510,46 +510,46 @@ test "utf16leToUtf8" { const utf16le_as_bytes = @sliceToBytes(utf16le[0..]); { - mem.writeInt(utf16le_as_bytes[0..], u16('A'), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16('a'), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 'A'); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 'a'); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "Aa")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0x80), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xffff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0x80); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xffff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xc2\x80" ++ "\xef\xbf\xbf")); } { // the values just outside the surrogate half range - mem.writeInt(utf16le_as_bytes[0..], u16(0xd7ff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xe000), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd7ff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xe000); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xed\x9f\xbf" ++ "\xee\x80\x80")); } { // smallest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xd800), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xd800); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf0\x90\x80\x80")); } { // largest surrogate pair - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdfff), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdfff); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xbf\xbf")); } { - mem.writeInt(utf16le_as_bytes[0..], u16(0xdbff), builtin.Endian.Little); - mem.writeInt(utf16le_as_bytes[2..], u16(0xdc00), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[0..], 0xdbff); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[2..], 0xdc00); const utf8 = try utf16leToUtf8Alloc(std.debug.global_allocator, utf16le); assert(mem.eql(u8, utf8, "\xf4\x8f\xb0\x80")); } @@ -583,7 +583,7 @@ pub fn utf8ToUtf16Le(utf16le: []u16, utf8: []const u8) !usize { while (it.nextCodepoint()) |codepoint| { if (end_index == utf16le_as_bytes.len) return (end_index / 2) + 1; // TODO surrogate pairs - mem.writeInt(utf16le_as_bytes[end_index..], @intCast(u16, codepoint), builtin.Endian.Little); + mem.writeIntSliceLittle(u16, utf16le_as_bytes[end_index..], @intCast(u16, codepoint)); end_index += 2; } return end_index / 2; |
