From afc72ac3db0840d8571dcfb8e2e182a241bdecaf Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Mon, 28 Sep 2026 18:20:33 -0300 Subject: A shell's > on addr no longer resets it, so echo /re/ > addr searches on Truncating addr reset it to #0, so a shell's find-and-replace loop matched the first hit for ever, .+#1 read 1 1 each time, and foo x foo y foo became foobarbarbar... acme resets addr on the first open (xfid.c:105-108), for clients that hold the fid; a shell cannot. Here neither an open nor a truncation resets it: the address written is evaluated from the last one, and 0 or , starts over. Documented as a departure from acme. Co-Authored-By: Claude Opus 5.5 --- src/ninep/addr.zig | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'src/ninep/addr.zig') diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig index 0537c17a..ccb08924 100644 --- a/src/ninep/addr.zig +++ b/src/ninep/addr.zig @@ -340,13 +340,34 @@ test "a failed address leaves none, so data refuses rather than act at the last try testing.expectEqualStrings(pane_files.e_addr_failed, th.rd(p, addr, 0, 64).reply.ename); try testing.expectEqual(E.INVAL, th.call(p, .{ .tag = 1, .op = .setattr, .node = Node.of(serial, .xdata), .truncate = true }).errno()); try testing.expectEqualStrings("one\ntwo\n", p.panes[0].?.file.?.content); - // A good address, or a truncated addr, gives it one again. + // A good address gives it one again; truncating addr does not. _ = th.wr(p, addr, "#0,#3"); try testing.expectEqual(Status.ok, th.wr(p, data, "ONE").reply.status); try testing.expectEqualStrings("ONE\ntwo\n", p.panes[0].?.file.?.content); _ = th.wr(p, addr, "99"); _ = th.call(p, .{ .tag = 1, .op = .setattr, .node = addr, .truncate = true }); - try testing.expectEqual(Status.ok, th.wr(p, data, "0").reply.status); + try testing.expectEqualStrings(pane_files.e_addr_failed, th.wr(p, data, "0").reply.ename); +} + +test "a shell's > on addr searches on from the last address, and 0 starts over" { + const p = try th.withFile(testing.allocator, "foo x foo y foo\n"); + defer p.deinit(); + const serial = th.serialOf(p); + const addr = Node.of(serial, .addr); + const data = Node.of(serial, .data); + // echo /foo/ > addr; printf foobar > data -- twice over, as a loop does. + for (0..3) |_| { + _ = th.call(p, .{ .tag = 1, .op = .setattr, .node = addr, .truncate = true }); + try testing.expectEqual(Status.ok, th.wr(p, addr, "/foo/").reply.status); + _ = th.call(p, .{ .tag = 1, .op = .setattr, .node = data, .truncate = true }); + try testing.expectEqual(Status.ok, th.wr(p, data, "foobar").reply.status); + } + try testing.expectEqualStrings("foobar x foobar y foobar\n", p.panes[0].?.file.?.content); + // .+#1 moves on from where the last write left the address. + _ = th.wr(p, addr, "0"); + _ = th.call(p, .{ .tag = 1, .op = .setattr, .node = addr, .truncate = true }); + try testing.expectEqual(Status.ok, th.wr(p, addr, ".+#1").reply.status); + try testing.expectEqualStrings(" 1 1 ", th.rd(p, addr, 0, 64).bytes); } test "the address language, form by form" { -- cgit v1.3