summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_sbuf.c
diff options
context:
space:
mode:
authormdf <mdf@FreeBSD.org>2010-09-09 16:51:52 +0000
committermdf <mdf@FreeBSD.org>2010-09-09 16:51:52 +0000
commit3b526ad3fb59f17156ad8e0e70b1bdc98ef32b8b (patch)
tree0712985ef52044b26cd0f333a3a12f6f398b095c /sys/kern/subr_sbuf.c
parent667f651319c270e11737f5cb30c1a20b94db849b (diff)
downloadFreeBSD-src-3b526ad3fb59f17156ad8e0e70b1bdc98ef32b8b.zip
FreeBSD-src-3b526ad3fb59f17156ad8e0e70b1bdc98ef32b8b.tar.gz
Refactor sbuf code so that most uses of sbuf_extend() are in a new
sbuf_put_byte(). This makes it easier to add drain functionality when a buffer would overflow as there are fewer code points. Reviewed by: phk
Diffstat (limited to 'sys/kern/subr_sbuf.c')
-rw-r--r--sys/kern/subr_sbuf.c94
1 files changed, 69 insertions, 25 deletions
diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c
index f460d88..bca8705 100644
--- a/sys/kern/subr_sbuf.c
+++ b/sys/kern/subr_sbuf.c
@@ -272,27 +272,59 @@ sbuf_setpos(struct sbuf *s, int pos)
}
/*
+ * Append a byte to an sbuf. This is the core function for appending
+ * to an sbuf and is the main place that deals with extending the
+ * buffer and marking overflow.
+ */
+static void
+sbuf_put_byte(int c, struct sbuf *s)
+{
+
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ if (SBUF_HASOVERFLOWED(s))
+ return;
+ if (SBUF_FREESPACE(s) <= 0) {
+ if (sbuf_extend(s, 1) < 0) {
+ SBUF_SETFLAG(s, SBUF_OVERFLOWED);
+ return;
+ }
+ }
+ s->s_buf[s->s_len++] = c;
+}
+
+/*
+ * Append a non-NUL character to an sbuf. This prototype signature is
+ * suitable for use with kvprintf(9).
+ */
+static void
+sbuf_putc_func(int c, void *arg)
+{
+
+ if (c != '\0')
+ sbuf_put_byte(c, arg);
+}
+
+/*
* Append a byte string to an sbuf.
*/
int
sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
{
const char *str = buf;
+ const char *end = str + len;
assert_sbuf_integrity(s);
assert_sbuf_state(s, 0);
if (SBUF_HASOVERFLOWED(s))
return (-1);
- for (; len; len--) {
- if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0)
- break;
- s->s_buf[s->s_len++] = *str++;
- }
- if (len > 0) {
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- return (-1);
- }
+ for (; str < end; str++) {
+ sbuf_put_byte(*str, s);
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
+ }
return (0);
}
@@ -352,13 +384,9 @@ sbuf_cat(struct sbuf *s, const char *str)
return (-1);
while (*str != '\0') {
- if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0)
- break;
- s->s_buf[s->s_len++] = *str++;
- }
- if (*str != '\0') {
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- return (-1);
+ sbuf_put_byte(*str, s);
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
}
return (0);
}
@@ -417,6 +445,23 @@ sbuf_cpy(struct sbuf *s, const char *str)
/*
* Format the given argument list and append the resulting string to an sbuf.
*/
+#ifdef _KERNEL
+int
+sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
+{
+
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ KASSERT(fmt != NULL,
+ ("%s called with a NULL format string", __func__));
+
+ (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
+ return (0);
+}
+#else /* !_KERNEL */
int
sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
{
@@ -432,6 +477,12 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
if (SBUF_HASOVERFLOWED(s))
return (-1);
+ /*
+ * For the moment, there is no way to get vsnprintf(3) to hand
+ * back a character at a time, to push everything into
+ * sbuf_putc_func() as was done for the kernel.
+ */
+
do {
va_copy(ap_copy, ap);
len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
@@ -462,6 +513,7 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
return (-1);
return (0);
}
+#endif /* _KERNEL */
/*
* Format the given arguments and append the resulting string to an sbuf.
@@ -485,17 +537,9 @@ int
sbuf_putc(struct sbuf *s, int c)
{
- assert_sbuf_integrity(s);
- assert_sbuf_state(s, 0);
-
+ sbuf_putc_func(c, s);
if (SBUF_HASOVERFLOWED(s))
return (-1);
- if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) {
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- return (-1);
- }
- if (c != '\0')
- s->s_buf[s->s_len++] = c;
return (0);
}
OpenPOWER on IntegriCloud