mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-28 06:47:53 +00:00
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.
This commit is contained in:
parent
6b9a49cd5f
commit
039fc40679
34
src/buffer.c
34
src/buffer.c
@ -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;
|
||||
|
19
src/buffer.h
19
src/buffer.h
@ -90,6 +90,18 @@ void git_buf_rtruncate_at_char(git_buf *path, char separator);
|
||||
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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user