Commit 039fc406 by Russell Belfer

Add a couple of useful git_buf utilities

* `git_buf_rfind` (with tests and tests for `git_buf_rfind_next`)
* `git_buf_puts_escaped` and `git_buf_puts_escaped_regex` (with tests)
  to copy strings into a buffer while injecting an escape sequence
  (e.g. '\') in front of particular characters.
parent 6b9a49cd
......@@ -141,6 +141,40 @@ int git_buf_puts(git_buf *buf, const char *string)
return git_buf_put(buf, string, strlen(string));
}
int git_buf_puts_escaped(
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with)
{
const char *scan = string;
size_t total = 0, esc_with_len = strlen(esc_with);
while (*scan) {
size_t count = strcspn(scan, esc_chars);
total += count + 1 + esc_with_len;
scan += count + 1;
}
ENSURE_SIZE(buf, buf->size + total + 1);
for (scan = string; *scan; ) {
size_t count = strcspn(scan, esc_chars);
memmove(buf->ptr + buf->size, scan, count);
scan += count;
buf->size += count;
if (*scan) {
memmove(buf->ptr + buf->size, esc_with, esc_with_len);
buf->size += esc_with_len;
memmove(buf->ptr + buf->size, scan, 1);
scan += 1;
buf->size += 1;
}
}
return 0;
}
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
{
int len;
......
......@@ -91,6 +91,18 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...);
int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b);
/**
* Copy string into buf prefixing every character that is contained in the
* esc_chars string with the esc_with string.
*/
int git_buf_puts_escaped(
git_buf *buf, const char *string, const char *esc_chars, const char *esc_with);
GIT_INLINE(int) git_buf_puts_escape_regex(git_buf *buf, const char *string)
{
return git_buf_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\");
}
/**
* Join two strings as paths, inserting a slash between as needed.
* @return 0 on success, -1 on failure
*/
......@@ -121,6 +133,13 @@ GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch)
return idx;
}
GIT_INLINE(ssize_t) git_buf_rfind(git_buf *buf, char ch)
{
ssize_t idx = (ssize_t)buf->size - 1;
while (idx >= 0 && buf->ptr[idx] != ch) idx--;
return idx;
}
/* Remove whitespace from the end of the buffer */
void git_buf_rtrim(git_buf *buf);
......
......@@ -611,3 +611,50 @@ void test_core_buffer__11(void)
git_buf_free(&a);
}
void test_core_buffer__rfind_variants(void)
{
git_buf a = GIT_BUF_INIT;
ssize_t len;
cl_git_pass(git_buf_sets(&a, "/this/is/it/"));
len = (ssize_t)git_buf_len(&a);
cl_assert(git_buf_rfind(&a, '/') == len - 1);
cl_assert(git_buf_rfind_next(&a, '/') == len - 4);
cl_assert(git_buf_rfind(&a, 'i') == len - 3);
cl_assert(git_buf_rfind_next(&a, 'i') == len - 3);
cl_assert(git_buf_rfind(&a, 'h') == 2);
cl_assert(git_buf_rfind_next(&a, 'h') == 2);
cl_assert(git_buf_rfind(&a, 'q') == -1);
cl_assert(git_buf_rfind_next(&a, 'q') == -1);
git_buf_clear(&a);
}
void test_core_buffer__puts_escaped(void)
{
git_buf a = GIT_BUF_INIT;
git_buf_clear(&a);
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "", ""));
cl_assert_equal_s("this is a test", a.ptr);
git_buf_clear(&a);
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "t", "\\"));
cl_assert_equal_s("\\this is a \\tes\\t", a.ptr);
git_buf_clear(&a);
cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "i ", "__"));
cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr);
git_buf_clear(&a);
cl_git_pass(git_buf_puts_escape_regex(&a, "^match\\s*[A-Z]+.*"));
cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr);
git_buf_free(&a);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment