* include/proto/buffers.h
* Buffer management definitions, macros and inline functions.
*
- * Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
+ * Copyright (C) 2000-2010 Willy Tarreau - w@1wt.eu
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len);
int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len);
void buffer_dump(FILE *o, struct buffer *b, int from, int to);
+void buffer_bounce_realign(struct buffer *buf);
+
/* writes the chunk <chunk> to buffer <buf>. Returns -1 in case of success,
/*
* Buffer management functions.
*
- * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
+/* Realigns a possibly non-contiguous buffer by bouncing bytes from source to
+ * destination. It does not use any intermediate buffer and does the move in
+ * place, though it will be slower than a simple memmove() on contiguous data,
+ * so it's desirable to use it only on non-contiguous buffers. No pointers are
+ * changed, the caller is responsible for that.
+ */
+void buffer_bounce_realign(struct buffer *buf)
+{
+ int advance, to_move;
+ char *from, *to;
+
+ advance = buf->data + buf->size - buf->w;
+ if (!advance)
+ return;
+
+ from = buf->w;
+ to_move = buf->l;
+ while (to_move) {
+ char last, save;
+
+ last = *from;
+ to = from + advance;
+ if (to >= buf->data + buf->size)
+ to -= buf->size;
+
+ while (1) {
+ save = *to;
+ *to = last;
+ last = save;
+ to_move--;
+ if (!to_move)
+ break;
+
+ /* check if we went back home after rotating a number of bytes */
+ if (to == from)
+ break;
+
+ /* if we ended up in the empty area, let's walk to next place. The
+ * empty area is either between buf->r and from or before from or
+ * after buf->r.
+ */
+ if (from > buf->r) {
+ if (to >= buf->r && to < from)
+ break;
+ } else if (from < buf->r) {
+ if (to < from || to >= buf->r)
+ break;
+ }
+
+ /* we have overwritten a byte of the original set, let's move it */
+ to += advance;
+ if (to >= buf->data + buf->size)
+ to -= buf->size;
+ }
+
+ from++;
+ if (from >= buf->data + buf->size)
+ from -= buf->size;
+ }
+}
+
+
/*
* Does an snprintf() at the end of chunk <chk>, respecting the limit of
* at most chk->size chars. If the chk->len is over, nothing is added. Returns
* - the buffer is in two blocks, we move it via the trash
*/
if (buf->l) {
- int block1 = buf->l;
- int block2 = 0;
- if (buf->r <= buf->w) {
+ if (buf->r <= buf->w)
/* non-contiguous block */
- block1 = buf->data + buf->size - buf->w;
- block2 = buf->r - buf->data;
- }
- if (block2)
- memcpy(trash, buf->data, block2);
- memmove(buf->data, buf->w, block1);
- if (block2)
- memcpy(buf->data + block1, trash, block2);
+ buffer_bounce_realign(buf);
+ else
+ memmove(buf->data, buf->w, buf->l);
}
/* adjust all known pointers */