diff --git a/lib/c.zig b/lib/c.zig index 8581ec4e14..e55b8443d9 100644 --- a/lib/c.zig +++ b/lib/c.zig @@ -153,7 +153,11 @@ test "strncat" { } fn strcmp(s1: [*:0]const u8, s2: [*:0]const u8) callconv(.C) c_int { - return std.cstr.cmp(s1, s2); + return switch (std.mem.orderZ(u8, s1, s2)) { + .lt => -1, + .eq => 0, + .gt => 1, + }; } fn strlen(s: [*:0]const u8) callconv(.C) usize { diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 9f4d75084f..c0aeba00de 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -1,6 +1,5 @@ const std = @import("std.zig"); const builtin = @import("builtin"); -const cstr = std.cstr; const unicode = std.unicode; const io = std.io; const fs = std.fs; diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig index 0888edf10d..83c6c12a87 100644 --- a/lib/std/cstr.zig +++ b/lib/std/cstr.zig @@ -1,100 +1,3 @@ -const std = @import("std.zig"); -const builtin = @import("builtin"); -const debug = std.debug; -const mem = std.mem; -const testing = std.testing; - -pub const line_sep = switch (builtin.os.tag) { - .windows => "\r\n", - else => "\n", -}; - -pub fn cmp(a: [*:0]const u8, b: [*:0]const u8) i8 { - var index: usize = 0; - while (a[index] == b[index] and a[index] != 0) : (index += 1) {} - if (a[index] > b[index]) { - return 1; - } else if (a[index] < b[index]) { - return -1; - } else { - return 0; - } -} - -test "cstr fns" { - try comptime testCStrFnsImpl(); - try testCStrFnsImpl(); -} - -fn testCStrFnsImpl() !void { - try testing.expect(cmp("aoeu", "aoez") == -1); -} - -/// Returns a mutable, null-terminated slice with the same length as `slice`. -/// Caller owns the returned memory. -pub fn addNullByte(allocator: mem.Allocator, slice: []const u8) ![:0]u8 { - const result = try allocator.alloc(u8, slice.len + 1); - @memcpy(result[0..slice.len], slice); - result[slice.len] = 0; - return result[0..slice.len :0]; -} - -test "addNullByte" { - const slice = try addNullByte(std.testing.allocator, "hello"[0..4]); - defer std.testing.allocator.free(slice); - try testing.expect(slice.len == 4); - try testing.expect(slice[4] == 0); -} - -pub const NullTerminated2DArray = struct { - allocator: mem.Allocator, - byte_count: usize, - ptr: ?[*:null]?[*:0]u8, - - /// Takes N lists of strings, concatenates the lists together, and adds a null terminator - /// Caller must deinit result - pub fn fromSlices(allocator: mem.Allocator, slices: []const []const []const u8) !NullTerminated2DArray { - var new_len: usize = 1; // 1 for the list null - var byte_count: usize = 0; - for (slices) |slice| { - new_len += slice.len; - for (slice) |inner| { - byte_count += inner.len; - } - byte_count += slice.len; // for the null terminators of inner - } - - const index_size = @sizeOf(usize) * new_len; // size of the ptrs - byte_count += index_size; - - const buf = try allocator.alignedAlloc(u8, @alignOf(?*u8), byte_count); - errdefer allocator.free(buf); - - var write_index = index_size; - const index_buf = mem.bytesAsSlice(?[*]u8, buf); - - var i: usize = 0; - for (slices) |slice| { - for (slice) |inner| { - index_buf[i] = buf.ptr + write_index; - i += 1; - @memcpy(buf[write_index..][0..inner.len], inner); - write_index += inner.len; - buf[write_index] = 0; - write_index += 1; - } - } - index_buf[i] = null; - - return NullTerminated2DArray{ - .allocator = allocator, - .byte_count = byte_count, - .ptr = @as(?[*:null]?[*:0]u8, @ptrCast(buf.ptr)), - }; - } - - pub fn deinit(self: *NullTerminated2DArray) void { - const buf = @as([*]u8, @ptrCast(self.ptr)); - self.allocator.free(buf[0..self.byte_count]); - } -}; +pub const line_sep = @compileError("deprecated; choose correct end-of-line sequence of characters by yourself instead"); +pub const cmp = @compileError("deprecated; use `std.mem.orderZ` instead"); +pub const addNullByte = @compileError("deprecated; use `allocator.dupeZ(u8, stuff)` instead"); diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 229bc0b63e..36e9813c2a 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -607,12 +607,24 @@ pub fn order(comptime T: type, lhs: []const T, rhs: []const T) math.Order { return math.order(lhs.len, rhs.len); } -test "order" { +/// Compares two many-item pointers with NUL-termination lexicographically. +pub fn orderZ(comptime T: type, lhs: [*:0]const T, rhs: [*:0]const T) math.Order { + var i: usize = 0; + while (lhs[i] == rhs[i] and lhs[i] != 0) : (i += 1) {} + return math.order(lhs[i], rhs[i]); +} + +test "order and orderZ" { try testing.expect(order(u8, "abcd", "bee") == .lt); + try testing.expect(orderZ(u8, "abcd", "bee") == .lt); try testing.expect(order(u8, "abc", "abc") == .eq); + try testing.expect(orderZ(u8, "abc", "abc") == .eq); try testing.expect(order(u8, "abc", "abc0") == .lt); + try testing.expect(orderZ(u8, "abc", "abc0") == .lt); try testing.expect(order(u8, "", "") == .eq); + try testing.expect(orderZ(u8, "", "") == .eq); try testing.expect(order(u8, "", "a") == .lt); + try testing.expect(orderZ(u8, "", "a") == .lt); } /// Returns true if lhs < rhs, false otherwise diff --git a/lib/std/net.zig b/lib/std/net.zig index af291f6414..7a8ca62022 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -783,7 +783,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get errdefer result.deinit(); if (builtin.target.os.tag == .windows) { - const name_c = try std.cstr.addNullByte(allocator, name); + const name_c = try allocator.dupeZ(u8, name); defer allocator.free(name_c); const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port}); @@ -855,7 +855,7 @@ pub fn getAddressList(allocator: mem.Allocator, name: []const u8, port: u16) Get } if (builtin.link_libc) { - const name_c = try std.cstr.addNullByte(allocator, name); + const name_c = try allocator.dupeZ(u8, name); defer allocator.free(name_c); const port_c = try std.fmt.allocPrintZ(allocator, "{}", .{port}); diff --git a/lib/std/zig/c_builtins.zig b/lib/std/zig/c_builtins.zig index 7f0414c96f..46d376a437 100644 --- a/lib/std/zig/c_builtins.zig +++ b/lib/std/zig/c_builtins.zig @@ -126,7 +126,11 @@ pub inline fn __builtin_strlen(s: [*c]const u8) usize { return std.mem.sliceTo(s, 0).len; } pub inline fn __builtin_strcmp(s1: [*c]const u8, s2: [*c]const u8) c_int { - return @as(c_int, std.cstr.cmp(s1, s2)); + return switch (std.mem.orderZ(u8, s1, s2)) { + .lt => -1, + .eq => 0, + .gt => 1, + }; } pub inline fn __builtin_object_size(ptr: ?*const anyopaque, ty: c_int) usize { diff --git a/src/Compilation.zig b/src/Compilation.zig index 902586bf7a..92de342a16 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -5066,7 +5066,7 @@ fn parseLldStderr(comp: *Compilation, comptime prefix: []const u8, stderr: []con defer context_lines.deinit(); var current_err: ?*LldError = null; - var lines = mem.splitSequence(u8, stderr, std.cstr.line_sep); + var lines = mem.splitSequence(u8, stderr, if (builtin.os.tag == .windows) "\r\n" else "\n"); while (lines.next()) |line| { if (mem.startsWith(u8, line, prefix ++ ":")) { if (current_err) |err| { diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index efff2e557c..dbdb65ac29 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const cstr = std.cstr; const mem = std.mem; const Allocator = mem.Allocator; const assert = std.debug.assert; @@ -1025,7 +1024,7 @@ pub const CType = extern union { for (lhs_data, rhs_data) |lhs_field, rhs_field| { if (!ctx.eqlIndex(lhs_field.type, rhs_field.type)) return false; if (lhs_field.alignas.@"align" != rhs_field.alignas.@"align") return false; - if (cstr.cmp(lhs_field.name, rhs_field.name) != 0) return false; + if (std.mem.orderZ(u8, lhs_field.name, rhs_field.name) != .eq) return false; } return true; }, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 87cbb3e242..57a579cfdb 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -647,7 +647,7 @@ test "multiline string literal is null terminated" { \\three ; const s2 = "one\ntwo)\nthree"; - try expect(std.cstr.cmp(s1, s2) == 0); + try expect(std.mem.orderZ(u8, s1, s2) == .eq); } test "string escapes" { diff --git a/test/cbe.zig b/test/cbe.zig index b56202c7e5..7eb212b2fe 100644 --- a/test/cbe.zig +++ b/test/cbe.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Cases = @import("src/Cases.zig"); +const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n"; // These tests should work with all platforms, but we're using linux_x64 for // now for consistency. Will be expanded eventually. @@ -19,7 +20,7 @@ pub fn addCases(ctx: *Cases) !void { \\ _ = puts("hello world!"); \\ return 0; \\} - , "hello world!" ++ std.cstr.line_sep); + , "hello world!" ++ nl); // Now change the message only case.addCompareOutput( @@ -28,7 +29,7 @@ pub fn addCases(ctx: *Cases) !void { \\ _ = puts("yo"); \\ return 0; \\} - , "yo" ++ std.cstr.line_sep); + , "yo" ++ nl); // Add an unused Decl case.addCompareOutput( @@ -38,7 +39,7 @@ pub fn addCases(ctx: *Cases) !void { \\ return 0; \\} \\fn unused() void {} - , "yo!" ++ std.cstr.line_sep); + , "yo!" ++ nl); // Comptime return type and calling convention expected. case.addError( @@ -67,7 +68,7 @@ pub fn addCases(ctx: *Cases) !void { \\ _ = printf("Hello, %s!\n", "world"); \\ return 0; \\} - , "Hello, world!" ++ std.cstr.line_sep); + , "Hello, world!" ++ nl); } { diff --git a/test/compare_output.zig b/test/compare_output.zig index 92dfd76b58..bcdc642a1e 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -15,7 +15,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ _ = c.puts("Hello, world!"); \\ return 0; \\} - , "Hello, world!" ++ std.cstr.line_sep); + , "Hello, world!" ++ if (@import("builtin").os.tag == .windows) "\r\n" else "\n"); cases.add("hello world without libc", \\const io = @import("std").io; diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig index a64a3eb7a4..fe32d376d2 100644 --- a/test/run_translated_c.zig +++ b/test/run_translated_c.zig @@ -1,6 +1,6 @@ const std = @import("std"); const tests = @import("tests.zig"); -const nl = std.cstr.line_sep; +const nl = if (@import("builtin").os.tag == .windows) "\r\n" else "\n"; pub fn addCases(cases: *tests.RunTranslatedCContext) void { cases.add("dereference address of",