summaryrefslogtreecommitdiff
path: root/src/ninep/ctl.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/ninep/ctl.zig')
-rw-r--r--src/ninep/ctl.zig39
1 files changed, 28 insertions, 11 deletions
diff --git a/src/ninep/ctl.zig b/src/ninep/ctl.zig
index 82001f32..a4979f7d 100644
--- a/src/ninep/ctl.zig
+++ b/src/ninep/ctl.zig
@@ -422,7 +422,11 @@ const Builtin = builtins.registry.Builtin();
/// Refuses a control message, quoting it the way Plan 9's cmderror does
/// (kernel/misc/parse.c:82): `unknown control message "Bogus 3"`.
fn refuse(p: *Pardes, req: Req, why: []const u8, line: []const u8) Reply {
- const word = firstWord(line);
+ return refuseQuoting(p, req, why, firstWord(line));
+}
+
+/// `refuse` quoting `word` as given: a setting's bad value, blanks and all.
+fn refuseQuoting(p: *Pardes, req: Req, why: []const u8, word: []const u8) Reply {
// A word too long to quote whole gives up its middle (fitErr), so the
// refusal keeps both its ends.
var shown: [4096]u8 = undefined;
@@ -507,7 +511,7 @@ fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ?
var near: [128]u8 = undefined;
const room = @import("cloud9").fs.errmax -| (head.len + tail.len + line.len + 3);
var why: [256]u8 = undefined;
- return refuse(p, req, std.fmt.bufPrint(&why, head ++ "{s}" ++ tail, .{pardes.colors.themesNear(near[0..@min(room, near.len)], arg)}) catch "bad value in control message", line);
+ return refuse(p, req, std.fmt.bufPrint(&why, head ++ "{s}" ++ tail, .{pardes.colors.themesNear(near[0..@min(room, near.len)], arg)}) catch "bad value in control message", arg);
},
.font => config.Runtime.FontSpec.parse(arg) != null,
else => probe: {
@@ -517,10 +521,12 @@ fn checkBuiltin(p: *Pardes, req: Req, line: []const u8, scope: builtins.Scope) ?
};
if (takes) return null;
var why: [160]u8 = undefined;
- return refuse(p, req, if (config.Runtime.takes(setting.action)) |values|
+ // The offending word is the value: quoted, so two bad values read,
+ // and log, as two.
+ return refuseQuoting(p, req, if (config.Runtime.takes(setting.action)) |values|
std.fmt.bufPrint(&why, "bad value in control message; takes {s}", .{values}) catch "bad value in control message"
else
- "bad value in control message", line);
+ "bad value in control message", arg);
}
/// Runs a checked control message at pane `id`, as a click on its word
@@ -1295,16 +1301,16 @@ test "the root ctl reads the settings as a write takes them, and takes the sessi
try testing.expectEqualStrings("not a session control message \"Del\": write it to pane/<n>/ctl", wr(p, root_ctl, "Del").reply.ename);
try testing.expectEqualStrings("unknown control message \"Nonsense\"", wr(p, root_ctl, "Nonsense 1").reply.ename);
- try testing.expectEqualStrings("bad value in control message; takes on, off \"Verbose\"", wr(p, root_ctl, "Verbose maybe").reply.ename);
- try testing.expectEqualStrings("bad value in control message; takes acme, pardes \"Placement\"", wr(p, root_ctl, "Placement east").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes on, off \"maybe\"", wr(p, root_ctl, "Verbose maybe").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes acme, pardes \"east\"", wr(p, root_ctl, "Placement east").reply.ename);
// A number's refusal names its range, a path's what it takes.
- try testing.expectEqualStrings("bad value in control message; takes 0-100 (a percentage) \"InactiveDim\"", wr(p, root_ctl, "InactiveDim 200").reply.ename);
- try testing.expectEqualStrings("bad value in control message; takes 0-60000 (milliseconds) \"MessageLinger\"", wr(p, root_ctl, "MessageLinger x").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes 0-100 (a percentage) \"200\"", wr(p, root_ctl, "InactiveDim 200").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes 0-60000 (milliseconds) \"x\"", wr(p, root_ctl, "MessageLinger x").reply.ename);
for (config.Runtime.settings) |setting| if (setting.action != .theme)
try testing.expect(config.Runtime.takes(setting.action) != null);
const no_theme = wr(p, root_ctl, "Theme no-such-theme").reply.ename;
try testing.expectStringStartsWith(no_theme, "bad value in control message; like it: n");
- try testing.expect(std.mem.endsWith(u8, no_theme, "; Themes lists all \"Theme\""));
+ try testing.expect(std.mem.endsWith(u8, no_theme, "; Themes lists all \"no-such-theme\""));
try testing.expectEqualStrings("wrong #args in control message \"Newcol\"", wr(p, root_ctl, "Newcol 2").reply.ename);
try testing.expectEqualStrings("wrong #args in control message \"Theme\"", wr(p, root_ctl, "Theme").reply.ename);
// A bare required word fails the check, so the line before never runs.
@@ -1832,7 +1838,18 @@ test "Pager is a setting of the root ctl: pardes by default, off taken, anything
try testing.expectEqual(Status.ok, wr(p, root_ctl, "Pager off\n").reply.status);
try testing.expectEqual(config.Runtime.Pager.off, p.settings.pager);
try testing.expect(std.mem.indexOf(u8, rd(p, root_ctl, 0, 1 << 16).bytes, "Pager off\n") != null);
- try testing.expectEqualStrings("bad value in control message; takes pardes, off \"Pager\"", wr(p, root_ctl, "Pager less\n").reply.ename);
+ try testing.expectEqualStrings("bad value in control message; takes pardes, off \"less\"", wr(p, root_ctl, "Pager less\n").reply.ename);
+}
+
+test "a bad setting value is quoted, so two different bad values log as two records, never one counted twice" {
+ const p = try withFile(testing.allocator, "x\n");
+ defer p.deinit();
+ const root_ctl = @intFromEnum(tree.TopFile.ctl);
+ _ = wr(p, root_ctl, "Verbose maybe\n");
+ _ = wr(p, root_ctl, "Verbose nope\n");
+ try testing.expect(th.logHas(p, "takes on, off \"maybe\"\n"));
+ try testing.expect(th.logHas(p, "takes on, off \"nope\"\n"));
+ try testing.expect(!th.logHas(p, "(x2)"));
}
test "a bare :N or :N:M look addresses the pane itself, from its look, the root's and event write-back" {
@@ -2064,7 +2081,7 @@ test "Joincol with no column to the right and Theme with no such theme say so" {
try testing.expectEqual(E.INVAL, themed.errno());
try testing.expectStringStartsWith(themed.reply.ename, "bad value in control message; like it: ");
try testing.expect(std.mem.indexOf(u8, themed.reply.ename, ": dr") != null);
- try testing.expect(std.mem.endsWith(u8, themed.reply.ename, "\"Theme\""));
+ try testing.expect(std.mem.endsWith(u8, themed.reply.ename, "\"drak\""));
// A click on the word says it on the message row.
_ = wr(p, Node.of(serialOf(p), .exec), "Theme drak\n");
const pane = p.panes[p.active].?;