From f48919aafb3b1bb9120dce4d16c269dde530176f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 22 Dec 2018 19:19:50 +0100 Subject: [PATCH] MINOR: buffers: add a new b_move() function This function will be used to move parts of a buffer to another place in the same buffer, even if the parts overlap. In order to keep things under reasonable control, it only uses a length and absolute offsets for the source and destination, and doesn't consider head nor data. --- doc/internals/buffer-api.txt | 5 ++++ include/common/buf.h | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/doc/internals/buffer-api.txt b/doc/internals/buffer-api.txt index 7938f4c9a..13881f7eb 100644 --- a/doc/internals/buffer-api.txt +++ b/doc/internals/buffer-api.txt @@ -443,6 +443,11 @@ b_putblk() | buffer *buf | tries to append block at the end | | available. It returns the number of | | bytes really copied --------------------+------------------+--------------------------------------- +b_move() | buffer *buf | moves block (src,len) left or right + | size_t src | by bytes, supporting wrapping + | size_t len | and overlapping. + | size_t shift | +--------------------+------------------+--------------------------------------- b_rep_blk() | buffer *buf | writes the block at position | char *pos | which must be in buffer , and | char *end | moves the part between and the diff --git a/include/common/buf.h b/include/common/buf.h index cc670bf38..d495a19cf 100644 --- a/include/common/buf.h +++ b/include/common/buf.h @@ -564,6 +564,63 @@ static inline size_t b_xfer(struct buffer *dst, struct buffer *src, size_t count return ret; } +/* Moves bytes from absolute position of buffer by + * bytes, while supporting wrapping of both the source and the destination. + * The position is relative to the buffer's origin and may overlap with the + * target position. The 's absolute value must be strictly lower than + * the buffer's size. The main purpose is to aggregate data block during + * parsing while removing unused delimiters. The buffer's length is not + * modified, and the caller must take care of size adjustments and holes by + * itself. + */ +static inline void b_move(const struct buffer *b, size_t src, size_t len, ssize_t shift) +{ + char *orig = b_orig(b); + size_t size = b_size(b); + size_t dst = src + size + shift; + size_t cnt; + + if (dst >= size) + dst -= size; + + if (shift < 0) { + /* copy from left to right */ + for (; (cnt = len); len -= cnt) { + if (cnt > size - src) + cnt = size - src; + if (cnt > size - dst) + cnt = size - dst; + + memmove(orig + dst, orig + src, cnt); + dst += cnt; + src += cnt; + if (dst >= size) + dst -= size; + if (src >= size) + src -= size; + } + } + else if (shift > 0) { + /* copy from right to left */ + for (; (cnt = len); len -= cnt) { + size_t src_end = src + len; + size_t dst_end = dst + len; + + if (dst_end > size) + dst_end -= size; + if (src_end > size) + src_end -= size; + + if (cnt > dst_end) + cnt = dst_end; + if (cnt > src_end) + cnt = src_end; + + memmove(orig + dst_end - cnt, orig + src_end - cnt, cnt); + } + } +} + /* b_rep_blk() : writes the block at position which must be in * buffer , and moves the part between and the buffer's tail just * after the end of the copy of . This effectively replaces the part