summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ninep/pane.zig28
1 files changed, 24 insertions, 4 deletions
diff --git a/src/ninep/pane.zig b/src/ninep/pane.zig
index d5f2f20a..d3c1b907 100644
--- a/src/ninep/pane.zig
+++ b/src/ninep/pane.zig
@@ -760,7 +760,7 @@ fn pairOf(text: []const u8) ?State.Range {
const q0 = std.fmt.parseInt(u32, it.next() orelse return null, 10) catch return null;
const q1 = std.fmt.parseInt(u32, it.next() orelse return null, 10) catch return null;
if (it.next() != null) return null;
- return .{ .q0 = q0, .q1 = @max(q0, q1) };
+ return .{ .q0 = q0, .q1 = q1 };
}
pub const e_addr_failed = "no address: the last one written to addr failed";
@@ -779,9 +779,16 @@ fn writeRange(req: Req, pane: *Pane, file: PaneFile) Reply {
if (file == .addr and pf.addr_failed and expr.len > 0 and std.mem.indexOfScalar(u8, ".+-", expr[0]) != null)
return tree.failText(req.tag, E.INVAL, e_addr_failed);
var a: addressing.Addr = .{ .text = text, .lim = pf.limit, .expr = expr };
- var r = if (pairOf(expr)) |pair|
- State.Range{ .q0 = @min(pair.q0, clip(text.len)), .q1 = @min(pair.q1, clip(text.len)) }
- else if (a.address(pf.addr)) |found| (if (a.i < expr.len) null else found) else null;
+ // A pair is refused as the address form refuses it, never clamped: one
+ // past the text is out of range, one ending before it starts out of
+ // order (below).
+ var r = if (pairOf(expr)) |pair| pair: {
+ if (pair.q0 > clip(text.len) or pair.q1 > clip(text.len)) {
+ a.err = addressing.e_range;
+ break :pair null;
+ }
+ break :pair pair;
+ } else if (a.address(pf.addr)) |found| (if (a.i < expr.len) null else found) else null;
// sam's check, which acme leaves out: `#100,#50` names no range.
if (r) |found| if (found.q0 > found.q1) {
a.err = addressing.e_order;
@@ -1395,6 +1402,19 @@ test "a 9P write moves dot only as acme's textinsert does, and scrolls only the
try testing.expectEqualStrings("abYYef\nmore\n", fileOf(pane).?.content);
}
+test "an addr pair out of order or out of range is refused as the address form is, not clamped" {
+ const p = try withFile(testing.allocator, "abcdef\n");
+ defer p.deinit();
+ const serial = serialOf(p);
+ const addr = Node.of(serial, .addr);
+ try testing.expectEqualStrings(addressing.e_order, wr(p, addr, "5 2").reply.ename);
+ try testing.expectEqualStrings(addressing.e_order, wr(p, addr, "#5,#2").reply.ename);
+ try testing.expectEqualStrings(addressing.e_range, wr(p, addr, "2 99").reply.ename);
+ try testing.expectEqualStrings(addressing.e_range, wr(p, addr, "#2,#99").reply.ename);
+ try testing.expectEqual(Status.ok, wr(p, addr, "2 4").reply.status);
+ try testing.expectEqual(State.Range{ .q0 = 2, .q1 = 4 }, p.panes[p.paneBySerial(serial).?].?.fs.addr);
+}
+
test "a write of two lines to name is refused EINVAL, on a held open or not" {
const p = try withFile(testing.allocator, "x\n");
defer p.deinit();