summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fs-help.txt2
-rw-r--r--src/ninep/addr.zig4
-rw-r--r--src/ninep/ctl.zig25
3 files changed, 29 insertions, 2 deletions
diff --git a/src/fs-help.txt b/src/fs-help.txt
index 689d8839..4633d91c 100644
--- a/src/fs-help.txt
+++ b/src/fs-help.txt
@@ -40,6 +40,6 @@ Pitfalls, one each:
tag reads the path, then the tag's own text; writes append to that text; truncating clears it.
A terminal's body is a history snapshot frozen per open; pty/data is the live stream.
exec: a word no builtin knows is typed into a terminal in the pane's directory, and not an error.
- A refused write reads as EINVAL through a mount: the log's err record says why.
+ Through a mount a malformed write is EINVAL, a well-formed one that fails EIO: log's err says why.
lock/unlock on a pane's ctl need a held fd (exec 3>ctl); a lock someone holds fails: retry.
Closing a column's last pane leaves a +New in its place; Delcol closes the column.
diff --git a/src/ninep/addr.zig b/src/ninep/addr.zig
index 6656c786..3b29f622 100644
--- a/src/ninep/addr.zig
+++ b/src/ninep/addr.zig
@@ -14,7 +14,9 @@ fn clip(n: usize) u32 {
pub const e_no_match = "no match for regexp";
pub const e_range = "address out of range";
pub const e_regexp = "bad regular expression";
-pub const e_slow = "regular expression search took too long";
+/// Not "took too long": 9ns reads errors by their words, and that would be
+/// ENAMETOOLONG.
+pub const e_slow = "regular expression search gave up, backtracking past its step budget";
pub const e_syntax = "bad address syntax";
pub const e_order = "addresses out of order";
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 382cc0e7..386fd9a9 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -926,3 +926,28 @@ test "look and exec read back what the last command touched, a ctl write's too"
try testing.expectEqual(tree.Status.ok, wr(p, @intFromEnum(tree.TopFile.ctl), "Verbose off\n").reply.status);
try testing.expectEqualStrings(try std.fmt.bufPrint(&want, "{d}\n", .{made}), rd(p, root_exec, 0, 64).bytes);
}
+
+test "an error's words give the errno a mount reads: EINVAL for what is malformed, EIO for what failed" {
+ // 9ns (cloud9's 9ns/src/nine.zig) maps an error to an errno by its
+ // words, and EIO when none of them match: these words must not.
+ const addressing = @import("addr.zig");
+ const einval = [_][]const u8{ "control message", "invalid", "bad " };
+ const other = [_][]const u8{ "interrupt", "shut down", "not exist", "not found", "no such", "exists", "not empty", "not a dir", "is a dir", "permission", "denied", "read-only", "read only", "no space", "not allowed", "not permitted", "cannot", "fid", "busy", "in use", "too long", "not supported", "unsupported" };
+ const Case = struct { text: []const u8, malformed: bool };
+ for ([_]Case{
+ .{ .text = addressing.e_syntax, .malformed = true },
+ .{ .text = addressing.e_regexp, .malformed = true },
+ .{ .text = e_prompt, .malformed = true },
+ .{ .text = addressing.e_no_match, .malformed = false },
+ .{ .text = addressing.e_range, .malformed = false },
+ .{ .text = addressing.e_order, .malformed = false },
+ .{ .text = addressing.e_slow, .malformed = false },
+ .{ .text = "/tmp/x.txt: Modified (Exit again to discard)", .malformed = false },
+ }) |c| {
+ const says_einval = for (einval) |w| {
+ if (std.ascii.findIgnoreCase(c.text, w) != null) break true;
+ } else false;
+ try testing.expectEqual(c.malformed, says_einval);
+ for (other) |w| try testing.expect(std.ascii.findIgnoreCase(c.text, w) == null);
+ }
+}