util.dbuffer: Add read_until() method
authorMatthew Wild <mwild1@gmail.com>
Tue, 29 Jun 2021 13:48:14 +0100
changeset 11640 11e0a0a08da3
parent 11639 1b17b967838e
child 11641 19cddf92fcc2
util.dbuffer: Add read_until() method
spec/util_dbuffer_spec.lua
util/dbuffer.lua
--- a/spec/util_dbuffer_spec.lua	Thu May 27 13:09:18 2021 +0200
+++ b/spec/util_dbuffer_spec.lua	Tue Jun 29 13:48:14 2021 +0100
@@ -36,6 +36,50 @@
 		end);
 	end);
 
+	describe(":read_until", function ()
+		it("works", function ()
+			local b = dbuffer.new();
+			b:write("hello\n");
+			b:write("world");
+			b:write("\n");
+			b:write("\n\n");
+			b:write("stuff");
+			b:write("more\nand more");
+
+			assert.equal(nil, b:read_until("."));
+			assert.equal(nil, b:read_until("%"));
+			assert.equal("hello\n", b:read_until("\n"));
+			assert.equal("world\n", b:read_until("\n"));
+			assert.equal("\n", b:read_until("\n"));
+			assert.equal("\n", b:read_until("\n"));
+			assert.equal("stu", b:read(3));
+			assert.equal("ffmore\n", b:read_until("\n"));
+			assert.equal(nil, b:read_until("\n"));
+			assert.equal("and more", b:read_chunk());
+		end);
+
+		it("works with multi-character sequences", function ()
+			local b = dbuffer.new();
+			b:write("hello\r\n");
+			b:write("world");
+			b:write("\r\n");
+			b:write("\r\n\r\n");
+			b:write("stuff");
+			b:write("more\r\nand more");
+
+			assert.equal(nil, b:read_until("."));
+			assert.equal(nil, b:read_until("%"));
+			assert.equal("hello\r\n", b:read_until("\r\n"));
+			assert.equal("world\r\n", b:read_until("\r\n"));
+			assert.equal("\r\n", b:read_until("\r\n"));
+			assert.equal("\r\n", b:read_until("\r\n"));
+			assert.equal("stu", b:read(3));
+			assert.equal("ffmore\r\n", b:read_until("\r\n"));
+			assert.equal(nil, b:read_until("\r\n"));
+			assert.equal("and more", b:read_chunk());
+		end);
+	end);
+
 	describe(":discard", function ()
 		local b = dbuffer.new();
 		it("works", function ()
--- a/util/dbuffer.lua	Thu May 27 13:09:18 2021 +0200
+++ b/util/dbuffer.lua	Tue Jun 29 13:48:14 2021 +0100
@@ -76,6 +76,20 @@
 	return table.concat(chunks);
 end
 
+-- Read to, and including, the specified character sequence (return nil if not found)
+function dbuffer_methods:read_until(char)
+	local buffer_pos = 0;
+	for i, chunk in self.items:items() do
+		local start = 1 + self.front_consumed;
+		local char_pos = chunk:find(char, start, true);
+		if char_pos then
+			return self:read(buffer_pos + (char_pos - start) + #char);
+		end
+		buffer_pos = buffer_pos + #chunk;
+	end
+	return nil;
+end
+
 function dbuffer_methods:discard(requested_bytes)
 	if requested_bytes > self._length then
 		return nil;