Std.mem.concat or my Slice assignment behaves unexpected

I tried to read a path (but works / fails for any string i tested) from my windows cmd and to concatenate the read path with a given suffix.

But not only does std.mem.concat not care about my ordering of the slices I input, is also seems to ignore the first 6 characters of my input, and I have no Idea why.

(Version 0.13.0)

const std = @import("std");

pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    const allocator = arena.allocator();

    const out_filename_demand = "Line: \n";
    const out_filename = try readLine(allocator, out_filename_demand);

    const end = "\\testname_1234";
    const concat: []const []const u8 = &.{ out_filename, end };
    const out_file_path = std.mem.concat(allocator, u8, concat) catch unreachable;

    std.debug.print("outPath: {s}\n", .{out_file_path});

    arena.deinit();
}

fn readLine(allo: std.mem.Allocator, prompt: []const u8) ![]const u8 {
    var input: [std.os.windows.MAX_PATH]u8 = undefined;

    const stdIn = std.io.getStdIn().reader();
    std.debug.print("{s}", .{prompt});

    const line = try stdIn.readUntilDelimiterOrEof(&input, '\n') orelse return error.NoLine;

    std.debug.print("Read: {s}\n", .{line});

    return allo.dupeZ(u8, line);
}

For example my input of “abcdefghi” results in “\testname_1234fghi” instead of “\testname_1234abcdefghi”.

Trying get some insight, where exactly things go wrong, I tried printing my input, but what resulted confused me even more:

// input len = 10, input is abcdefghi
std.debug.print("input len = {any}, input is {s}\n", .{ out_filename.len, out_filename });
// , testname_1234
std.debug.print("{s}, {s} \n", .{ concat[0], concat[1] });

Is this just a basic beginner slice initialization mistake, or what breaks this code?
I mean after all, the final result of my concatination is still:
“testname_1234efghi” instead of “\testname_1234abcdefghi” or even “abcdefghi\testname_1234”

In windows newlines are “\r\n”.
readUntilDelimiterOrEof actually reads “abcdefghi\r”.
When “\r” is printed in the terminal it moves the cursor at the start of line.
This does not happens at all on linux because newlines are “\n”.

One way to handle it is using std.mem.trimRight or:

var line = try stdIn.readUntilDelimiterOrEof(&input, '\n') orelse return error.NoLine;
const end = line.len -1;
if (line[end] == '\r') {
    line = line[0..end];
}
2 Likes