Commit 3a14d3e2bca4f1af7de978decda1c7ca74ffd3bf

nulltoken 2012-10-01T11:58:15

buf: introduce git_buf_splice()

diff --git a/src/buffer.c b/src/buffer.c
index b40b16b..e55b0a2 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -549,3 +549,31 @@ void git_buf_unescape(git_buf *buf)
 {
 	buf->size = git__unescape(buf->ptr);
 }
+
+int git_buf_splice(
+	git_buf *buf,
+	size_t where,
+	size_t nb_to_remove,
+	const char *data,
+	size_t nb_to_insert)
+{
+	assert(buf &&
+		where <= git_buf_len(buf) &&
+		where + nb_to_remove <= git_buf_len(buf));
+
+	/* Ported from git.git
+	 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
+	 */
+	if (git_buf_grow(buf, git_buf_len(buf) + nb_to_insert - nb_to_remove) < 0)
+		return -1;
+
+	memmove(buf->ptr + where + nb_to_insert,
+			buf->ptr + where + nb_to_remove,
+			buf->size - where - nb_to_remove);
+
+	memcpy(buf->ptr + where, data, nb_to_insert);
+
+	buf->size = buf->size + nb_to_insert - nb_to_remove;
+	buf->ptr[buf->size] = '\0';
+	return 0;
+}
diff --git a/src/buffer.h b/src/buffer.h
index 2aae06c..a2896d4 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -158,4 +158,29 @@ void git_buf_unescape(git_buf *buf);
 /* Write data as base64 encoded in buffer */
 int git_buf_put_base64(git_buf *buf, const char *data, size_t len);
 
+/*
+ * Insert, remove or replace a portion of the buffer.
+ *
+ * @param buf The buffer to work with
+ *
+ * @param where The location in the buffer where the transformation
+ * should be applied.
+ *
+ * @param nb_to_remove The number of chars to be removed. 0 to not
+ * remove any character in the buffer.
+ *
+ * @param data A pointer to the data which should be inserted.
+ *
+ * @param nb_to_insert The number of chars to be inserted. 0 to not
+ * insert any character from the buffer.
+ *
+ * @return 0 or an error code.
+ */
+int git_buf_splice(
+	git_buf *buf,
+	size_t where,
+	size_t nb_to_remove,
+	const char *data,
+	size_t nb_to_insert);
+
 #endif
diff --git a/tests-clar/buf/splice.c b/tests-clar/buf/splice.c
new file mode 100644
index 0000000..e80c931
--- /dev/null
+++ b/tests-clar/buf/splice.c
@@ -0,0 +1,93 @@
+#include "clar_libgit2.h"
+#include "buffer.h"
+
+static git_buf _buf;
+
+void test_buf_splice__initialize(void) {
+   git_buf_init(&_buf, 16);
+}
+
+void test_buf_splice__cleanup(void) {
+   git_buf_free(&_buf);
+}
+
+void test_buf_splice__preprend(void)
+{
+	git_buf_sets(&_buf, "world!");
+
+	cl_git_pass(git_buf_splice(&_buf, 0, 0, "Hello Dolly", strlen("Hello ")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__append(void)
+{
+	git_buf_sets(&_buf, "Hello");
+
+	cl_git_pass(git_buf_splice(&_buf, git_buf_len(&_buf), 0, " world!", strlen(" world!")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__insert_at(void)
+{
+	git_buf_sets(&_buf, "Hell world!");
+
+	cl_git_pass(git_buf_splice(&_buf, strlen("Hell"), 0, "o", strlen("o")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__remove_at(void)
+{
+	git_buf_sets(&_buf, "Hello world of warcraft!");
+
+	cl_git_pass(git_buf_splice(&_buf, strlen("Hello world"), strlen(" of warcraft"), "", 0));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__replace(void)
+{
+	git_buf_sets(&_buf, "Hell0 w0rld!");
+
+	cl_git_pass(git_buf_splice(&_buf, strlen("Hell"), strlen("0 w0"), "o wo", strlen("o wo")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__replace_with_longer(void)
+{
+	git_buf_sets(&_buf, "Hello you!");
+
+	cl_git_pass(git_buf_splice(&_buf, strlen("Hello "), strlen("you"), "world", strlen("world")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__replace_with_shorter(void)
+{
+	git_buf_sets(&_buf, "Brave new world!");
+
+	cl_git_pass(git_buf_splice(&_buf, 0, strlen("Brave new"), "Hello", strlen("Hello")));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__truncate(void)
+{
+	git_buf_sets(&_buf, "Hello world!!");
+
+	cl_git_pass(git_buf_splice(&_buf, strlen("Hello world!"), strlen("!"), "", 0));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}
+
+void test_buf_splice__dont_do_anything(void)
+{
+	git_buf_sets(&_buf, "Hello world!");
+
+	cl_git_pass(git_buf_splice(&_buf, 3, 0, "Hello", 0));
+
+	cl_assert_equal_s("Hello world!", git_buf_cstr(&_buf));
+}