/* * Copy and nul-terminate a ringbuffer to a string. */ ssize_t ringbuf_to_string(char *buf, size_t len, struct ringbuf *rb) { size_t copy_len, n; if (buf == NULL || rb == NULL || len == 0) return (-1); copy_len = MINIMUM(len - 1, ringbuf_used(rb)); if (copy_len == 0) return (copy_len); if (rb->start < rb->end) memcpy(buf, rb->buf + rb->start, copy_len); else { /* If the buffer is wrapped, copy each hunk separately */ n = rb->len - rb->start; memcpy(buf, rb->buf + rb->start, MINIMUM(n, copy_len)); if (copy_len > n) memcpy(buf + n, rb->buf, MINIMUM(rb->end, copy_len - n)); } buf[copy_len] = '\0'; return (ringbuf_used(rb)); }
/* * Append a line to a ring buffer, will delete lines from start * of buffer as necessary */ int ringbuf_append_line(struct ringbuf *rb, char *line) { size_t llen, used, copy_len; int overflow = 0; if (rb == NULL || line == NULL) return (-1); llen = strlen(line); if (llen == 0) return (-1); if (line[llen - 1] != '\n') llen++; /* one extra for appended '\n' */ if (llen >= rb->len) return (-1); /* * If necessary, advance start pointer to make room for appended * string. Ensure that start pointer is at the beginning of a line * once we are done (i.e move to after '\n'). */ used = ringbuf_used(rb); if (used + llen >= rb->len) { rb->start = (rb->start + used + llen - rb->len) % rb->len; /* Find next '\n' */ while (rb->buf[rb->start] != '\n') rb->start = (rb->start + 1) % rb->len; /* Skip it */ rb->start = (rb->start + 1) % rb->len; overflow = 1; } /* * Now append string, starting from last pointer and wrapping if * necessary */ if (rb->end + llen > rb->len) { copy_len = rb->len - rb->end; memcpy(rb->buf + rb->end, line, copy_len); memcpy(rb->buf, line + copy_len, llen - copy_len - 1); rb->buf[llen - copy_len - 1] = '\n'; } else { memcpy(rb->buf + rb->end, line, llen - 1); rb->buf[rb->end + llen - 1] = '\n'; } rb->end = (rb->end + llen) % rb->len; return (overflow); }
ssize_t ringbuf_read(ringbuf_t *rb, char *target, size_t len) { size_t used, tail_len; if (!rb || !target) { return -1; } used = ringbuf_used(rb); len = MIN(len, used); tail_len = rb->len - rb->start + 1; tail_len = MIN(len, tail_len); memcpy(target, rb->buf + rb->start, tail_len); if (len - tail_len > 0) { memcpy(target + tail_len, rb->buf, len - tail_len); } rb->start = (rb->start + len) % rb->len; return len; }