Commit 2811421b authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Move much closer to FreeBSD current sbuf implementation.

parent 86312952
...@@ -37,14 +37,14 @@ ...@@ -37,14 +37,14 @@
struct vsb { struct vsb {
unsigned s_magic; unsigned s_magic;
char *s_buf; /* storage buffer */ char *s_buf; /* storage buffer */
size_t s_size; /* size of storage buffer */ ssize_t s_size; /* size of storage buffer */
size_t s_len; /* current length of string */ ssize_t s_len; /* current length of string */
int s_error; /* current error code */
#define VSB_FIXEDLEN 0x00000000 /* fixed length buffer (default) */ #define VSB_FIXEDLEN 0x00000000 /* fixed length buffer (default) */
#define VSB_AUTOEXTEND 0x00000001 /* automatically extend buffer */ #define VSB_AUTOEXTEND 0x00000001 /* automatically extend buffer */
#define VSB_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */ #define VSB_USRFLAGMSK 0x0000ffff /* mask of flags the user may specify */
#define VSB_DYNAMIC 0x00010000 /* s_buf must be freed */ #define VSB_DYNAMIC 0x00010000 /* s_buf must be freed */
#define VSB_FINISHED 0x00020000 /* set by vsb_finish() */ #define VSB_FINISHED 0x00020000 /* set by vsb_finish() */
#define VSB_OVERFLOWED 0x00040000 /* vsb overflowed */
#define VSB_DYNSTRUCT 0x00080000 /* vsb must be freed */ #define VSB_DYNSTRUCT 0x00080000 /* vsb must be freed */
int s_flags; /* flags */ int s_flags; /* flags */
}; };
......
...@@ -46,6 +46,9 @@ SVNID("$Id$") ...@@ -46,6 +46,9 @@ SVNID("$Id$")
#define SBFREE(buf) free(buf) #define SBFREE(buf) free(buf)
#define min(x,y) (x < y ? x : y) #define min(x,y) (x < y ? x : y)
// #define bzero(x,y) memset(x,0,y)
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
#define VSB_MAGIC 0x4a82dd8a #define VSB_MAGIC 0x4a82dd8a
/* /*
* Predicates * Predicates
...@@ -53,7 +56,6 @@ SVNID("$Id$") ...@@ -53,7 +56,6 @@ SVNID("$Id$")
#define VSB_ISDYNAMIC(s) ((s)->s_flags & VSB_DYNAMIC) #define VSB_ISDYNAMIC(s) ((s)->s_flags & VSB_DYNAMIC)
#define VSB_ISDYNSTRUCT(s) ((s)->s_flags & VSB_DYNSTRUCT) #define VSB_ISDYNSTRUCT(s) ((s)->s_flags & VSB_DYNSTRUCT)
#define VSB_ISFINISHED(s) ((s)->s_flags & VSB_FINISHED) #define VSB_ISFINISHED(s) ((s)->s_flags & VSB_FINISHED)
#define VSB_HASOVERFLOWED(s) ((s)->s_flags & VSB_OVERFLOWED)
#define VSB_HASROOM(s) ((s)->s_len < (s)->s_size - 1) #define VSB_HASROOM(s) ((s)->s_len < (s)->s_size - 1)
#define VSB_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) #define VSB_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1))
#define VSB_CANEXTEND(s) ((s)->s_flags & VSB_AUTOEXTEND) #define VSB_CANEXTEND(s) ((s)->s_flags & VSB_AUTOEXTEND)
...@@ -111,13 +113,14 @@ vsb_extendsize(int size) ...@@ -111,13 +113,14 @@ vsb_extendsize(int size)
{ {
int newsize; int newsize;
newsize = VSB_MINEXTENDSIZE; if (size < (int)VSB_MAXEXTENDSIZE) {
while (newsize < size) { newsize = VSB_MINEXTENDSIZE;
if (newsize < (int)VSB_MAXEXTENDSIZE) while (newsize < size)
newsize *= 2; newsize *= 2;
else } else {
newsize += VSB_MAXEXTENDINCR; newsize = roundup2(size, VSB_MAXEXTENDINCR);
} }
KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
return (newsize); return (newsize);
} }
...@@ -166,17 +169,21 @@ vsb_new(struct vsb *s, char *buf, int length, int flags) ...@@ -166,17 +169,21 @@ vsb_new(struct vsb *s, char *buf, int length, int flags)
s = SBMALLOC(sizeof(*s)); s = SBMALLOC(sizeof(*s));
if (s == NULL) if (s == NULL)
return (NULL); return (NULL);
flags |= VSB_DYNSTRUCT; bzero(s, sizeof(*s));
s->s_flags = flags;
VSB_SETFLAG(s, VSB_DYNSTRUCT);
} else {
bzero(s, sizeof(*s));
s->s_flags = flags;
} }
memset(s, 0, sizeof *s);
s->s_flags = flags;
s->s_magic = VSB_MAGIC; s->s_magic = VSB_MAGIC;
s->s_size = length; s->s_size = length;
if (buf) { if (buf != NULL) {
s->s_buf = buf; s->s_buf = buf;
return (s); return (s);
} }
if (flags & VSB_AUTOEXTEND) if ((flags & VSB_AUTOEXTEND) != 0)
s->s_size = vsb_extendsize(s->s_size); s->s_size = vsb_extendsize(s->s_size);
s->s_buf = SBMALLOC(s->s_size); s->s_buf = SBMALLOC(s->s_size);
if (s->s_buf == NULL) { if (s->s_buf == NULL) {
...@@ -199,7 +206,7 @@ vsb_clear(struct vsb *s) ...@@ -199,7 +206,7 @@ vsb_clear(struct vsb *s)
/* don't care if it's finished or not */ /* don't care if it's finished or not */
VSB_CLEARFLAG(s, VSB_FINISHED); VSB_CLEARFLAG(s, VSB_FINISHED);
VSB_CLEARFLAG(s, VSB_OVERFLOWED); s->s_error = 0;
s->s_len = 0; s->s_len = 0;
} }
...@@ -225,6 +232,30 @@ vsb_setpos(struct vsb *s, int pos) ...@@ -225,6 +232,30 @@ vsb_setpos(struct vsb *s, int pos)
return (0); return (0);
} }
/*
* Append a byte to an vsb. This is the core function for appending
* to an vsb and is the main place that deals with extending the
* buffer and marking overflow.
*/
static void
vsb_put_byte(int c, struct vsb *s)
{
assert_vsb_integrity(s);
assert_vsb_state(s, 0);
if (s->s_error != 0)
return;
if (VSB_FREESPACE(s) <= 0) {
if (vsb_extend(s, 1) < 0)
s->s_error = ENOMEM;
if (s->s_error != 0)
return;
}
s->s_buf[s->s_len++] = c;
}
/* /*
* Append a byte string to an vsb. * Append a byte string to an vsb.
*/ */
...@@ -232,20 +263,17 @@ int ...@@ -232,20 +263,17 @@ int
vsb_bcat(struct vsb *s, const void *buf, size_t len) vsb_bcat(struct vsb *s, const void *buf, size_t len)
{ {
const char *str = buf; const char *str = buf;
const char *end = str + len;
assert_vsb_integrity(s); assert_vsb_integrity(s);
assert_vsb_state(s, 0); assert_vsb_state(s, 0);
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1);
for (; len; len--) {
if (!VSB_HASROOM(s) && vsb_extend(s, len) < 0)
break;
s->s_buf[s->s_len++] = *str++;
}
if (len) {
VSB_SETFLAG(s, VSB_OVERFLOWED);
return (-1); return (-1);
for (; str < end; str++) {
vsb_put_byte(*str, s);
if (s->s_error != 0)
return (-1);
} }
return (0); return (0);
} }
...@@ -274,17 +302,13 @@ vsb_cat(struct vsb *s, const char *str) ...@@ -274,17 +302,13 @@ vsb_cat(struct vsb *s, const char *str)
assert_vsb_integrity(s); assert_vsb_integrity(s);
assert_vsb_state(s, 0); assert_vsb_state(s, 0);
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1); return (-1);
while (*str) { while (*str != '\0') {
if (!VSB_HASROOM(s) && vsb_extend(s, strlen(str)) < 0) vsb_put_byte(*str++, s);
break; if (s->s_error != 0)
s->s_buf[s->s_len++] = *str++; return (-1);
}
if (*str) {
VSB_SETFLAG(s, VSB_OVERFLOWED);
return (-1);
} }
return (0); return (0);
} }
...@@ -318,7 +342,7 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap) ...@@ -318,7 +342,7 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap)
KASSERT(fmt != NULL, KASSERT(fmt != NULL,
("%s called with a NULL format string", __func__)); ("%s called with a NULL format string", __func__));
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1); return (-1);
do { do {
...@@ -336,16 +360,18 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap) ...@@ -336,16 +360,18 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap)
* terminating nul. * terminating nul.
* *
* vsnprintf() returns the amount that would have been copied, * vsnprintf() returns the amount that would have been copied,
* given sufficient space, hence the min() calculation below. * given sufficient space, so don't over-increment s_len.
*/ */
s->s_len += min(len, VSB_FREESPACE(s)); if (VSB_FREESPACE(s) < len)
len = VSB_FREESPACE(s);
s->s_len += len;
if (!VSB_HASROOM(s) && !VSB_CANEXTEND(s)) if (!VSB_HASROOM(s) && !VSB_CANEXTEND(s))
VSB_SETFLAG(s, VSB_OVERFLOWED); s->s_error = ENOMEM;
KASSERT(s->s_len < s->s_size, KASSERT(s->s_len < s->s_size,
("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size)); ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1); return (-1);
return (0); return (0);
} }
...@@ -362,7 +388,7 @@ vsb_printf(struct vsb *s, const char *fmt, ...) ...@@ -362,7 +388,7 @@ vsb_printf(struct vsb *s, const char *fmt, ...)
va_start(ap, fmt); va_start(ap, fmt);
result = vsb_vprintf(s, fmt, ap); result = vsb_vprintf(s, fmt, ap);
va_end(ap); va_end(ap);
return(result); return (result);
} }
/* /*
...@@ -372,17 +398,9 @@ int ...@@ -372,17 +398,9 @@ int
vsb_putc(struct vsb *s, int c) vsb_putc(struct vsb *s, int c)
{ {
assert_vsb_integrity(s); vsb_put_byte(c, s);
assert_vsb_state(s, 0); if (s->s_error != 0)
if (VSB_HASOVERFLOWED(s))
return (-1); return (-1);
if (!VSB_HASROOM(s) && vsb_extend(s, 1) < 0) {
VSB_SETFLAG(s, VSB_OVERFLOWED);
return (-1);
}
if (c != '\0')
s->s_buf[s->s_len++] = (char)c;
return (0); return (0);
} }
...@@ -396,23 +414,23 @@ vsb_trim(struct vsb *s) ...@@ -396,23 +414,23 @@ vsb_trim(struct vsb *s)
assert_vsb_integrity(s); assert_vsb_integrity(s);
assert_vsb_state(s, 0); assert_vsb_state(s, 0);
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1); return (-1);
while (s->s_len && isspace(s->s_buf[s->s_len-1])) while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1]))
--s->s_len; --s->s_len;
return (0); return (0);
} }
/* /*
* Check if an vsb overflowed * Check if an vsb has an error.
*/ */
int int
vsb_error(const struct vsb *s) vsb_error(const struct vsb *s)
{ {
return (VSB_HASOVERFLOWED(s)); return (s->s_error);
} }
/* /*
...@@ -426,8 +444,10 @@ vsb_finish(struct vsb *s) ...@@ -426,8 +444,10 @@ vsb_finish(struct vsb *s)
assert_vsb_state(s, 0); assert_vsb_state(s, 0);
s->s_buf[s->s_len] = '\0'; s->s_buf[s->s_len] = '\0';
VSB_CLEARFLAG(s, VSB_OVERFLOWED);
VSB_SETFLAG(s, VSB_FINISHED); VSB_SETFLAG(s, VSB_FINISHED);
errno = s->s_error;
if (s->s_error)
return (-1);
return (0); return (0);
} }
...@@ -454,7 +474,7 @@ vsb_len(struct vsb *s) ...@@ -454,7 +474,7 @@ vsb_len(struct vsb *s)
assert_vsb_integrity(s); assert_vsb_integrity(s);
/* don't care if it's finished or not */ /* don't care if it's finished or not */
if (VSB_HASOVERFLOWED(s)) if (s->s_error != 0)
return (-1); return (-1);
return (s->s_len); return (s->s_len);
} }
...@@ -473,7 +493,7 @@ vsb_delete(struct vsb *s) ...@@ -473,7 +493,7 @@ vsb_delete(struct vsb *s)
if (VSB_ISDYNAMIC(s)) if (VSB_ISDYNAMIC(s))
SBFREE(s->s_buf); SBFREE(s->s_buf);
isdyn = VSB_ISDYNSTRUCT(s); isdyn = VSB_ISDYNSTRUCT(s);
memset(s, 0, sizeof *s); bzero(s, sizeof(*s));
if (isdyn) if (isdyn)
SBFREE(s); SBFREE(s);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment