diff --git a/src/buffer.c b/src/buffer.c index 3c7f6ccb4..b083768e3 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -136,30 +136,39 @@ int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len) return delta; } -/* This function realigns input data in a possibly wrapping buffer so that it - * becomes contiguous and starts at the beginning of the buffer area. The - * function may only be used when the buffer's output is empty. +/* This function realigns a possibly wrapping buffer so that the input part is + * contiguous and starts at the beginning of the buffer and the output part + * ends at the end of the buffer. This provides the best conditions since it + * allows the largest inputs to be processed at once and ensures that once the + * output data leaves, the whole buffer is available at once. */ void buffer_slow_realign(struct buffer *buf) { - /* two possible cases : - * - the buffer is in one contiguous block, we move it in-place - * - the buffer is in two blocks, we move it via the swap_buffer - */ - if (buf->i) { - int block1 = buf->i; - int block2 = 0; - if (buf->p + buf->i > buf->data + buf->size) { - /* non-contiguous block */ - block1 = buf->data + buf->size - buf->p; - block2 = buf->p + buf->i - (buf->data + buf->size); - } - if (block2) - memcpy(swap_buffer, buf->data, block2); - memmove(buf->data, buf->p, block1); - if (block2) - memcpy(buf->data + block1, swap_buffer, block2); + int block1 = buf->o; + int block2 = 0; + + /* process output data in two steps to cover wrapping */ + if (block1 > buf->p - buf->data) { + block2 = buf->p - buf->data; + block1 -= block2; } + memcpy(swap_buffer + buf->size - buf->o, bo_ptr(buf), block1); + memcpy(swap_buffer + buf->size - block2, buf->data, block2); + + /* process input data in two steps to cover wrapping */ + block1 = buf->i; + block2 = 0; + + if (block1 > buf->data + buf->size - buf->p) { + block1 = buf->data + buf->size - buf->p; + block2 = buf->i - block1; + } + memcpy(swap_buffer, bi_ptr(buf), block1); + memcpy(swap_buffer + block1, buf->data, block2); + + /* reinject changes into the buffer */ + memcpy(buf->data, swap_buffer, buf->i); + memcpy(buf->data + buf->size - buf->o, swap_buffer + buf->size - buf->o, buf->o); buf->p = buf->data; }