169990Sdes/*-
2181462Sdes * Copyright (c) 2000-2008 Poul-Henning Kamp
3181462Sdes * Copyright (c) 2000-2008 Dag-Erling Co��dan Sm��rgrav
469990Sdes * All rights reserved.
569990Sdes *
669990Sdes * Redistribution and use in source and binary forms, with or without
769990Sdes * modification, are permitted provided that the following conditions
869990Sdes * are met:
969990Sdes * 1. Redistributions of source code must retain the above copyright
1069990Sdes *    notice, this list of conditions and the following disclaimer
1169990Sdes *    in this position and unchanged.
1269990Sdes * 2. Redistributions in binary form must reproduce the above copyright
1369990Sdes *    notice, this list of conditions and the following disclaimer in the
1469990Sdes *    documentation and/or other materials provided with the distribution.
1569990Sdes *
16181462Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17181462Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18181462Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19181462Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20181462Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21181462Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22181462Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23181462Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24181462Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25181462Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26181462Sdes * SUCH DAMAGE.
2769990Sdes */
2869990Sdes
29116182Sobrien#include <sys/cdefs.h>
30116182Sobrien__FBSDID("$FreeBSD$");
31116182Sobrien
3269990Sdes#include <sys/param.h>
3374840Sken
3474840Sken#ifdef _KERNEL
3584097Sdes#include <sys/ctype.h>
36212367Smdf#include <sys/errno.h>
3769990Sdes#include <sys/kernel.h>
3869990Sdes#include <sys/malloc.h>
3969990Sdes#include <sys/systm.h>
4084097Sdes#include <sys/uio.h>
4169990Sdes#include <machine/stdarg.h>
4274840Sken#else /* _KERNEL */
4384097Sdes#include <ctype.h>
44212367Smdf#include <errno.h>
4574840Sken#include <stdarg.h>
4688950Skbyanc#include <stdio.h>
4778340Sjlemon#include <stdlib.h>
4888950Skbyanc#include <string.h>
4974840Sken#endif /* _KERNEL */
5069990Sdes
5184097Sdes#include <sys/sbuf.h>
5284097Sdes
5374840Sken#ifdef _KERNEL
54141616Sphkstatic MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
55255805Sdes#define	SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK|M_ZERO)
5689121Skbyanc#define	SBFREE(buf)		free(buf, M_SBUF)
5774840Sken#else /* _KERNEL */
5889121Skbyanc#define	KASSERT(e, m)
59255805Sdes#define	SBMALLOC(size)		calloc(1, size)
6089121Skbyanc#define	SBFREE(buf)		free(buf)
6174840Sken#endif /* _KERNEL */
6269990Sdes
6371721Sdes/*
6471721Sdes * Predicates
6571721Sdes */
6689121Skbyanc#define	SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
6789121Skbyanc#define	SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
6889121Skbyanc#define	SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
6989121Skbyanc#define	SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
70222004Sphk#define	SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
7188950Skbyanc#define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
72249377Strociny#define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
7371721Sdes
7471721Sdes/*
7571721Sdes * Set / clear flags
7671721Sdes */
7789121Skbyanc#define	SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
7889121Skbyanc#define	SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
7971721Sdes
8089121Skbyanc#define	SBUF_MINEXTENDSIZE	16		/* Should be power of 2. */
81222004Sphk
82222004Sphk#ifdef PAGE_SIZE
8389121Skbyanc#define	SBUF_MAXEXTENDSIZE	PAGE_SIZE
8489121Skbyanc#define	SBUF_MAXEXTENDINCR	PAGE_SIZE
85222004Sphk#else
86222004Sphk#define	SBUF_MAXEXTENDSIZE	4096
87222004Sphk#define	SBUF_MAXEXTENDINCR	4096
88222004Sphk#endif
8988950Skbyanc
9071721Sdes/*
9171721Sdes * Debugging support
9271721Sdes */
9374840Sken#if defined(_KERNEL) && defined(INVARIANTS)
94181462Sdes
9569990Sdesstatic void
9692664Speter_assert_sbuf_integrity(const char *fun, struct sbuf *s)
9769990Sdes{
98181462Sdes
9969990Sdes	KASSERT(s != NULL,
10073891Sdes	    ("%s called with a NULL sbuf pointer", fun));
10169990Sdes	KASSERT(s->s_buf != NULL,
10288950Skbyanc	    ("%s called with uninitialized or corrupt sbuf", fun));
10369990Sdes	KASSERT(s->s_len < s->s_size,
104221993Sphk	    ("wrote past end of sbuf (%jd >= %jd)",
105221993Sphk	    (intmax_t)s->s_len, (intmax_t)s->s_size));
10669990Sdes}
10769990Sdes
10869990Sdesstatic void
10992664Speter_assert_sbuf_state(const char *fun, struct sbuf *s, int state)
11069990Sdes{
111181462Sdes
11269990Sdes	KASSERT((s->s_flags & SBUF_FINISHED) == state,
11373891Sdes	    ("%s called with %sfinished or corrupt sbuf", fun,
11469990Sdes	    (state ? "un" : "")));
11569990Sdes}
116181462Sdes
11789121Skbyanc#define	assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
11889121Skbyanc#define	assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
119181462Sdes
12074840Sken#else /* _KERNEL && INVARIANTS */
121181462Sdes
12289121Skbyanc#define	assert_sbuf_integrity(s) do { } while (0)
12389121Skbyanc#define	assert_sbuf_state(s, i)	 do { } while (0)
124181462Sdes
12574840Sken#endif /* _KERNEL && INVARIANTS */
12669990Sdes
127212184Smdf#ifdef CTASSERT
128212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
129212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDINCR));
130212182Smdf#endif
131212180Smdf
13288950Skbyancstatic int
13388950Skbyancsbuf_extendsize(int size)
13488950Skbyanc{
13588950Skbyanc	int newsize;
13688950Skbyanc
137212180Smdf	if (size < (int)SBUF_MAXEXTENDSIZE) {
138212180Smdf		newsize = SBUF_MINEXTENDSIZE;
139212180Smdf		while (newsize < size)
14088950Skbyanc			newsize *= 2;
141212180Smdf	} else {
142212180Smdf		newsize = roundup2(size, SBUF_MAXEXTENDINCR);
14388950Skbyanc	}
144212181Smdf	KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
14588950Skbyanc	return (newsize);
14688950Skbyanc}
14788950Skbyanc
14869990Sdes/*
14988950Skbyanc * Extend an sbuf.
15088950Skbyanc */
15188950Skbyancstatic int
15288950Skbyancsbuf_extend(struct sbuf *s, int addlen)
15388950Skbyanc{
15488950Skbyanc	char *newbuf;
15588950Skbyanc	int newsize;
15688950Skbyanc
15788950Skbyanc	if (!SBUF_CANEXTEND(s))
15888950Skbyanc		return (-1);
15988950Skbyanc	newsize = sbuf_extendsize(s->s_size + addlen);
160181462Sdes	newbuf = SBMALLOC(newsize);
16188950Skbyanc	if (newbuf == NULL)
16288950Skbyanc		return (-1);
163222015Sphk	memcpy(newbuf, s->s_buf, s->s_size);
16488950Skbyanc	if (SBUF_ISDYNAMIC(s))
16588950Skbyanc		SBFREE(s->s_buf);
16688950Skbyanc	else
16788950Skbyanc		SBUF_SETFLAG(s, SBUF_DYNAMIC);
16888950Skbyanc	s->s_buf = newbuf;
16988950Skbyanc	s->s_size = newsize;
17088950Skbyanc	return (0);
17188950Skbyanc}
17288950Skbyanc
17388950Skbyanc/*
174222015Sphk * Initialize the internals of an sbuf.
175222015Sphk * If buf is non-NULL, it points to a static or already-allocated string
176222015Sphk * big enough to hold at least length characters.
177222015Sphk */
178222015Sphkstatic struct sbuf *
179222015Sphksbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
180222015Sphk{
181222015Sphk
182222015Sphk	memset(s, 0, sizeof(*s));
183222015Sphk	s->s_flags = flags;
184222015Sphk	s->s_size = length;
185222015Sphk	s->s_buf = buf;
186222015Sphk
187222015Sphk	if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
188224999Srwatson		KASSERT(s->s_size >= 0,
189222015Sphk		    ("attempt to create a too small sbuf"));
190222015Sphk	}
191222015Sphk
192222015Sphk	if (s->s_buf != NULL)
193222015Sphk		return (s);
194222015Sphk
195222015Sphk	if ((flags & SBUF_AUTOEXTEND) != 0)
196222015Sphk		s->s_size = sbuf_extendsize(s->s_size);
197222015Sphk
198222015Sphk	s->s_buf = SBMALLOC(s->s_size);
199222015Sphk	if (s->s_buf == NULL)
200222015Sphk		return (NULL);
201222015Sphk	SBUF_SETFLAG(s, SBUF_DYNAMIC);
202222015Sphk	return (s);
203222015Sphk}
204222015Sphk
205222015Sphk/*
20669990Sdes * Initialize an sbuf.
20769990Sdes * If buf is non-NULL, it points to a static or already-allocated string
20869990Sdes * big enough to hold at least length characters.
20969990Sdes */
21077989Sdesstruct sbuf *
21171721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags)
21269990Sdes{
213181462Sdes
21471721Sdes	KASSERT(length >= 0,
21571721Sdes	    ("attempt to create an sbuf of negative length (%d)", length));
21688950Skbyanc	KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
21788950Skbyanc	    ("%s called with invalid flags", __func__));
21869990Sdes
21988950Skbyanc	flags &= SBUF_USRFLAGMSK;
220222015Sphk	if (s != NULL)
221222015Sphk		return (sbuf_newbuf(s, buf, length, flags));
222222015Sphk
223222015Sphk	s = SBMALLOC(sizeof(*s));
224222015Sphk	if (s == NULL)
22577989Sdes		return (NULL);
226222015Sphk	if (sbuf_newbuf(s, buf, length, flags) == NULL) {
227222015Sphk		SBFREE(s);
228222015Sphk		return (NULL);
22977989Sdes	}
230222015Sphk	SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
23177989Sdes	return (s);
23269990Sdes}
23369990Sdes
23484097Sdes#ifdef _KERNEL
23569990Sdes/*
23684097Sdes * Create an sbuf with uio data
23784097Sdes */
23884097Sdesstruct sbuf *
23984097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
24084097Sdes{
241181462Sdes
24284097Sdes	KASSERT(uio != NULL,
24387594Sobrien	    ("%s called with NULL uio pointer", __func__));
24484097Sdes	KASSERT(error != NULL,
24587594Sobrien	    ("%s called with NULL error pointer", __func__));
24684097Sdes
24784097Sdes	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
24884097Sdes	if (s == NULL) {
24984097Sdes		*error = ENOMEM;
25084097Sdes		return (NULL);
25184097Sdes	}
25284097Sdes	*error = uiomove(s->s_buf, uio->uio_resid, uio);
25384097Sdes	if (*error != 0) {
25484097Sdes		sbuf_delete(s);
25584097Sdes		return (NULL);
25684097Sdes	}
25784097Sdes	s->s_len = s->s_size - 1;
258249377Strociny	if (SBUF_ISSECTION(s))
259249377Strociny		s->s_sect_len = s->s_size - 1;
26084097Sdes	*error = 0;
26184097Sdes	return (s);
26284097Sdes}
26384097Sdes#endif
26484097Sdes
26584097Sdes/*
26688950Skbyanc * Clear an sbuf and reset its position.
26771721Sdes */
26871721Sdesvoid
26971721Sdessbuf_clear(struct sbuf *s)
27071721Sdes{
271181462Sdes
27271721Sdes	assert_sbuf_integrity(s);
27371724Sdes	/* don't care if it's finished or not */
27471721Sdes
27571721Sdes	SBUF_CLEARFLAG(s, SBUF_FINISHED);
276212367Smdf	s->s_error = 0;
27771721Sdes	s->s_len = 0;
278249377Strociny	s->s_sect_len = 0;
27971721Sdes}
28071721Sdes
28171721Sdes/*
28288950Skbyanc * Set the sbuf's end position to an arbitrary value.
28388950Skbyanc * Effectively truncates the sbuf at the new position.
28469990Sdes */
28569990Sdesint
286221993Sphksbuf_setpos(struct sbuf *s, ssize_t pos)
28769990Sdes{
288181462Sdes
28969990Sdes	assert_sbuf_integrity(s);
29069990Sdes	assert_sbuf_state(s, 0);
291125937Sdes
29269990Sdes	KASSERT(pos >= 0,
293221993Sphk	    ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
29469990Sdes	KASSERT(pos < s->s_size,
295221993Sphk	    ("attempt to seek past end of sbuf (%jd >= %jd)",
296221993Sphk	    (intmax_t)pos, (intmax_t)s->s_size));
297249377Strociny	KASSERT(!SBUF_ISSECTION(s),
298249377Strociny	    ("attempt to seek when in a section"));
299125937Sdes
30069990Sdes	if (pos < 0 || pos > s->s_len)
30169990Sdes		return (-1);
30269990Sdes	s->s_len = pos;
30369990Sdes	return (0);
30469990Sdes}
30569990Sdes
30669990Sdes/*
307212367Smdf * Set up a drain function and argument on an sbuf to flush data to
308212367Smdf * when the sbuf buffer overflows.
309212367Smdf */
310212367Smdfvoid
311212367Smdfsbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
312212367Smdf{
313212367Smdf
314212367Smdf	assert_sbuf_state(s, 0);
315212367Smdf	assert_sbuf_integrity(s);
316212367Smdf	KASSERT(func == s->s_drain_func || s->s_len == 0,
317212367Smdf	    ("Cannot change drain to %p on non-empty sbuf %p", func, s));
318212367Smdf	s->s_drain_func = func;
319212367Smdf	s->s_drain_arg = ctx;
320212367Smdf}
321212367Smdf
322212367Smdf/*
323212367Smdf * Call the drain and process the return.
324212367Smdf */
325212367Smdfstatic int
326212367Smdfsbuf_drain(struct sbuf *s)
327212367Smdf{
328212367Smdf	int len;
329212367Smdf
330212367Smdf	KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s));
331212425Smdf	KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s));
332212367Smdf	len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
333212367Smdf	if (len < 0) {
334212367Smdf		s->s_error = -len;
335212367Smdf		return (s->s_error);
336212367Smdf	}
337212750Smdf	KASSERT(len > 0 && len <= s->s_len,
338212750Smdf	    ("Bad drain amount %d for sbuf %p", len, s));
339212367Smdf	s->s_len -= len;
340212367Smdf	/*
341212367Smdf	 * Fast path for the expected case where all the data was
342212367Smdf	 * drained.
343212367Smdf	 */
344212367Smdf	if (s->s_len == 0)
345212367Smdf		return (0);
346212367Smdf	/*
347212367Smdf	 * Move the remaining characters to the beginning of the
348212367Smdf	 * string.
349212367Smdf	 */
350212367Smdf	memmove(s->s_buf, s->s_buf + len, s->s_len);
351212367Smdf	return (0);
352212367Smdf}
353212367Smdf
354212367Smdf/*
355212365Smdf * Append a byte to an sbuf.  This is the core function for appending
356212365Smdf * to an sbuf and is the main place that deals with extending the
357212365Smdf * buffer and marking overflow.
358212365Smdf */
359212365Smdfstatic void
360222004Sphksbuf_put_byte(struct sbuf *s, int c)
361212365Smdf{
362212365Smdf
363212365Smdf	assert_sbuf_integrity(s);
364212365Smdf	assert_sbuf_state(s, 0);
365212365Smdf
366212425Smdf	if (s->s_error != 0)
367212365Smdf		return;
368212365Smdf	if (SBUF_FREESPACE(s) <= 0) {
369222004Sphk		/*
370212367Smdf		 * If there is a drain, use it, otherwise extend the
371212367Smdf		 * buffer.
372212367Smdf		 */
373212367Smdf		if (s->s_drain_func != NULL)
374212367Smdf			(void)sbuf_drain(s);
375212367Smdf		else if (sbuf_extend(s, 1) < 0)
376212425Smdf			s->s_error = ENOMEM;
377212425Smdf		if (s->s_error != 0)
378212365Smdf			return;
379212365Smdf	}
380212365Smdf	s->s_buf[s->s_len++] = c;
381249377Strociny	if (SBUF_ISSECTION(s))
382249377Strociny		s->s_sect_len++;
383212365Smdf}
384212365Smdf
385212365Smdf/*
38678077Sdes * Append a byte string to an sbuf.
38778077Sdes */
38878077Sdesint
389131869Sdessbuf_bcat(struct sbuf *s, const void *buf, size_t len)
39078077Sdes{
391131869Sdes	const char *str = buf;
392212365Smdf	const char *end = str + len;
393131868Sdes
39478077Sdes	assert_sbuf_integrity(s);
39578077Sdes	assert_sbuf_state(s, 0);
396125937Sdes
397212425Smdf	if (s->s_error != 0)
39878077Sdes		return (-1);
399212365Smdf	for (; str < end; str++) {
400222004Sphk		sbuf_put_byte(s, *str);
401212425Smdf		if (s->s_error != 0)
402212365Smdf			return (-1);
403222004Sphk	}
40478077Sdes	return (0);
40578077Sdes}
40678077Sdes
40778077Sdes#ifdef _KERNEL
40878077Sdes/*
40978077Sdes * Copy a byte string from userland into an sbuf.
41078077Sdes */
41178077Sdesint
41278077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
41378077Sdes{
414181462Sdes
41578077Sdes	assert_sbuf_integrity(s);
41678077Sdes	assert_sbuf_state(s, 0);
417212367Smdf	KASSERT(s->s_drain_func == NULL,
418212367Smdf	    ("Nonsensical copyin to sbuf %p with a drain", s));
41978077Sdes
420212425Smdf	if (s->s_error != 0)
42178077Sdes		return (-1);
42278077Sdes	if (len == 0)
42378077Sdes		return (0);
42488950Skbyanc	if (len > SBUF_FREESPACE(s)) {
42588950Skbyanc		sbuf_extend(s, len - SBUF_FREESPACE(s));
426212183Smdf		if (SBUF_FREESPACE(s) < len)
427212183Smdf			len = SBUF_FREESPACE(s);
42888950Skbyanc	}
42978092Sdes	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
43078092Sdes		return (-1);
43178095Sdes	s->s_len += len;
432125937Sdes
43378077Sdes	return (0);
43478077Sdes}
43578077Sdes#endif
43678077Sdes
43778077Sdes/*
43878077Sdes * Copy a byte string into an sbuf.
43978077Sdes */
44078077Sdesint
441131869Sdessbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
44278077Sdes{
443181462Sdes
44478077Sdes	assert_sbuf_integrity(s);
44578077Sdes	assert_sbuf_state(s, 0);
446125937Sdes
44778077Sdes	sbuf_clear(s);
448131869Sdes	return (sbuf_bcat(s, buf, len));
44978077Sdes}
45078077Sdes
45178077Sdes/*
45269990Sdes * Append a string to an sbuf.
45369990Sdes */
45469990Sdesint
45574840Skensbuf_cat(struct sbuf *s, const char *str)
45669990Sdes{
457181462Sdes
45869990Sdes	assert_sbuf_integrity(s);
45969990Sdes	assert_sbuf_state(s, 0);
460125937Sdes
461212425Smdf	if (s->s_error != 0)
46269990Sdes		return (-1);
463125937Sdes
464212183Smdf	while (*str != '\0') {
465222004Sphk		sbuf_put_byte(s, *str++);
466212425Smdf		if (s->s_error != 0)
467212365Smdf			return (-1);
46888950Skbyanc	}
46969990Sdes	return (0);
47069990Sdes}
47169990Sdes
47278077Sdes#ifdef _KERNEL
47369990Sdes/*
47488950Skbyanc * Append a string from userland to an sbuf.
47578077Sdes */
47678077Sdesint
47778077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
47878077Sdes{
47978077Sdes	size_t done;
480125937Sdes
48178077Sdes	assert_sbuf_integrity(s);
48278077Sdes	assert_sbuf_state(s, 0);
483212367Smdf	KASSERT(s->s_drain_func == NULL,
484212367Smdf	    ("Nonsensical copyin to sbuf %p with a drain", s));
48578077Sdes
486212425Smdf	if (s->s_error != 0)
48778077Sdes		return (-1);
48878077Sdes
48988950Skbyanc	if (len == 0)
49088950Skbyanc		len = SBUF_FREESPACE(s);	/* XXX return 0? */
49188950Skbyanc	if (len > SBUF_FREESPACE(s)) {
49288950Skbyanc		sbuf_extend(s, len);
493212183Smdf		if (SBUF_FREESPACE(s) < len)
494212183Smdf			len = SBUF_FREESPACE(s);
49588950Skbyanc	}
49678077Sdes	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
49778077Sdes	case ENAMETOOLONG:
498212425Smdf		s->s_error = ENOMEM;
49978077Sdes		/* fall through */
50078077Sdes	case 0:
50178077Sdes		s->s_len += done - 1;
502249377Strociny		if (SBUF_ISSECTION(s))
503249377Strociny			s->s_sect_len += done - 1;
50478077Sdes		break;
50578077Sdes	default:
50678077Sdes		return (-1);	/* XXX */
50778077Sdes	}
508125937Sdes
509153678Sphk	return (done);
51078077Sdes}
51178077Sdes#endif
51278077Sdes
51378077Sdes/*
51469990Sdes * Copy a string into an sbuf.
51569990Sdes */
51669990Sdesint
51774840Skensbuf_cpy(struct sbuf *s, const char *str)
51869990Sdes{
519181462Sdes
52069990Sdes	assert_sbuf_integrity(s);
52169990Sdes	assert_sbuf_state(s, 0);
522125937Sdes
52371721Sdes	sbuf_clear(s);
52469990Sdes	return (sbuf_cat(s, str));
52569990Sdes}
52669990Sdes
52769990Sdes/*
52888950Skbyanc * Format the given argument list and append the resulting string to an sbuf.
52969990Sdes */
530212365Smdf#ifdef _KERNEL
531222004Sphk
532222004Sphk/*
533222004Sphk * Append a non-NUL character to an sbuf.  This prototype signature is
534222004Sphk * suitable for use with kvprintf(9).
535222004Sphk */
536222004Sphkstatic void
537222004Sphksbuf_putc_func(int c, void *arg)
538222004Sphk{
539222004Sphk
540222004Sphk	if (c != '\0')
541222004Sphk		sbuf_put_byte(arg, c);
542222004Sphk}
543222004Sphk
54469990Sdesint
54588950Skbyancsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
54669990Sdes{
547212365Smdf
548212365Smdf	assert_sbuf_integrity(s);
549212365Smdf	assert_sbuf_state(s, 0);
550212365Smdf
551212365Smdf	KASSERT(fmt != NULL,
552212365Smdf	    ("%s called with a NULL format string", __func__));
553212365Smdf
554212365Smdf	(void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
555212425Smdf	if (s->s_error != 0)
556212365Smdf		return (-1);
557212365Smdf	return (0);
558212365Smdf}
559212365Smdf#else /* !_KERNEL */
560212365Smdfint
561212365Smdfsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
562212365Smdf{
563115311Speter	va_list ap_copy;
564212367Smdf	int error, len;
56569990Sdes
56669990Sdes	assert_sbuf_integrity(s);
56769990Sdes	assert_sbuf_state(s, 0);
56888950Skbyanc
56969990Sdes	KASSERT(fmt != NULL,
57087594Sobrien	    ("%s called with a NULL format string", __func__));
57188950Skbyanc
572212425Smdf	if (s->s_error != 0)
57369990Sdes		return (-1);
57469990Sdes
575212365Smdf	/*
576212365Smdf	 * For the moment, there is no way to get vsnprintf(3) to hand
577212365Smdf	 * back a character at a time, to push everything into
578212365Smdf	 * sbuf_putc_func() as was done for the kernel.
579212367Smdf	 *
580212367Smdf	 * In userspace, while drains are useful, there's generally
581212367Smdf	 * not a problem attempting to malloc(3) on out of space.  So
582212367Smdf	 * expand a userland sbuf if there is not enough room for the
583212367Smdf	 * data produced by sbuf_[v]printf(3).
584212365Smdf	 */
585212365Smdf
586212367Smdf	error = 0;
58788950Skbyanc	do {
588115311Speter		va_copy(ap_copy, ap);
58988950Skbyanc		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
590115311Speter		    fmt, ap_copy);
591115311Speter		va_end(ap_copy);
59269990Sdes
593212367Smdf		if (SBUF_FREESPACE(s) >= len)
594212367Smdf			break;
595212367Smdf		/* Cannot print with the current available space. */
596212367Smdf		if (s->s_drain_func != NULL && s->s_len > 0)
597212367Smdf			error = sbuf_drain(s);
598212367Smdf		else
599212367Smdf			error = sbuf_extend(s, len - SBUF_FREESPACE(s));
600212367Smdf	} while (error == 0);
601212367Smdf
60274840Sken	/*
60374840Sken	 * s->s_len is the length of the string, without the terminating nul.
60474840Sken	 * When updating s->s_len, we must subtract 1 from the length that
60574840Sken	 * we passed into vsnprintf() because that length includes the
60674840Sken	 * terminating nul.
60774840Sken	 *
60874840Sken	 * vsnprintf() returns the amount that would have been copied,
609212183Smdf	 * given sufficient space, so don't over-increment s_len.
61074840Sken	 */
611212183Smdf	if (SBUF_FREESPACE(s) < len)
612212183Smdf		len = SBUF_FREESPACE(s);
613212183Smdf	s->s_len += len;
614249377Strociny	if (SBUF_ISSECTION(s))
615249377Strociny		s->s_sect_len += len;
61689646Sphk	if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
617212425Smdf		s->s_error = ENOMEM;
61874840Sken
61969990Sdes	KASSERT(s->s_len < s->s_size,
62069990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
62169990Sdes
622212425Smdf	if (s->s_error != 0)
62369990Sdes		return (-1);
62469990Sdes	return (0);
62569990Sdes}
626212365Smdf#endif /* _KERNEL */
62769990Sdes
62869990Sdes/*
62988950Skbyanc * Format the given arguments and append the resulting string to an sbuf.
63088950Skbyanc */
63188950Skbyancint
63288950Skbyancsbuf_printf(struct sbuf *s, const char *fmt, ...)
63388950Skbyanc{
63488950Skbyanc	va_list ap;
63588950Skbyanc	int result;
63688950Skbyanc
63788950Skbyanc	va_start(ap, fmt);
63888950Skbyanc	result = sbuf_vprintf(s, fmt, ap);
63988950Skbyanc	va_end(ap);
640181462Sdes	return (result);
64188950Skbyanc}
64288950Skbyanc
64388950Skbyanc/*
64469990Sdes * Append a character to an sbuf.
64569990Sdes */
64669990Sdesint
64769990Sdessbuf_putc(struct sbuf *s, int c)
64869990Sdes{
649181462Sdes
650222004Sphk	sbuf_put_byte(s, c);
651212425Smdf	if (s->s_error != 0)
65269990Sdes		return (-1);
65369990Sdes	return (0);
65469990Sdes}
65569990Sdes
65669990Sdes/*
65788950Skbyanc * Trim whitespace characters from end of an sbuf.
65884097Sdes */
65984097Sdesint
66084097Sdessbuf_trim(struct sbuf *s)
66184097Sdes{
662181462Sdes
66384097Sdes	assert_sbuf_integrity(s);
66484097Sdes	assert_sbuf_state(s, 0);
665212367Smdf	KASSERT(s->s_drain_func == NULL,
666212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
667125937Sdes
668212425Smdf	if (s->s_error != 0)
66984097Sdes		return (-1);
670125937Sdes
671249377Strociny	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
67284097Sdes		--s->s_len;
673249377Strociny		if (SBUF_ISSECTION(s))
674249377Strociny			s->s_sect_len--;
675249377Strociny	}
67684097Sdes
67784097Sdes	return (0);
67884097Sdes}
67984097Sdes
68084097Sdes/*
681212425Smdf * Check if an sbuf has an error.
68271721Sdes */
68371721Sdesint
684221993Sphksbuf_error(const struct sbuf *s)
68571721Sdes{
686181462Sdes
687212425Smdf	return (s->s_error);
68871721Sdes}
68971721Sdes
69071721Sdes/*
69169990Sdes * Finish off an sbuf.
69269990Sdes */
693212367Smdfint
69469990Sdessbuf_finish(struct sbuf *s)
69569990Sdes{
696181462Sdes
69769990Sdes	assert_sbuf_integrity(s);
69869990Sdes	assert_sbuf_state(s, 0);
699125937Sdes
700212367Smdf	if (s->s_drain_func != NULL) {
701222004Sphk		while (s->s_len > 0 && s->s_error == 0)
702222004Sphk			s->s_error = sbuf_drain(s);
703212425Smdf	}
70473891Sdes	s->s_buf[s->s_len] = '\0';
70569990Sdes	SBUF_SETFLAG(s, SBUF_FINISHED);
706212367Smdf#ifdef _KERNEL
707222004Sphk	return (s->s_error);
708212367Smdf#else
709250706Sjh	if (s->s_error != 0) {
710250706Sjh		errno = s->s_error;
711222004Sphk		return (-1);
712250706Sjh	}
713222004Sphk	return (0);
714212367Smdf#endif
71569990Sdes}
71669990Sdes
71769990Sdes/*
71869990Sdes * Return a pointer to the sbuf data.
71969990Sdes */
72069990Sdeschar *
72169990Sdessbuf_data(struct sbuf *s)
72269990Sdes{
723181462Sdes
72469990Sdes	assert_sbuf_integrity(s);
72569990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
726212367Smdf	KASSERT(s->s_drain_func == NULL,
727212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
728125937Sdes
729181462Sdes	return (s->s_buf);
73069990Sdes}
73169990Sdes
73269990Sdes/*
73369990Sdes * Return the length of the sbuf data.
73469990Sdes */
735221993Sphkssize_t
73669990Sdessbuf_len(struct sbuf *s)
73769990Sdes{
738181462Sdes
73969990Sdes	assert_sbuf_integrity(s);
74071724Sdes	/* don't care if it's finished or not */
741212367Smdf	KASSERT(s->s_drain_func == NULL,
742212367Smdf	    ("%s makes no sense on sbuf %p with drain", __func__, s));
743125937Sdes
744212425Smdf	if (s->s_error != 0)
74571721Sdes		return (-1);
746181462Sdes	return (s->s_len);
74769990Sdes}
74869990Sdes
74969990Sdes/*
75069990Sdes * Clear an sbuf, free its buffer if necessary.
75169990Sdes */
75269990Sdesvoid
75369990Sdessbuf_delete(struct sbuf *s)
75469990Sdes{
75588219Sdillon	int isdyn;
75688219Sdillon
75769990Sdes	assert_sbuf_integrity(s);
75869990Sdes	/* don't care if it's finished or not */
759125937Sdes
76069990Sdes	if (SBUF_ISDYNAMIC(s))
76174840Sken		SBFREE(s->s_buf);
76288219Sdillon	isdyn = SBUF_ISDYNSTRUCT(s);
763222015Sphk	memset(s, 0, sizeof(*s));
76488219Sdillon	if (isdyn)
76577989Sdes		SBFREE(s);
76669990Sdes}
767104449Sphk
768104449Sphk/*
769104449Sphk * Check if an sbuf has been finished.
770104449Sphk */
771104449Sphkint
772221993Sphksbuf_done(const struct sbuf *s)
773104449Sphk{
774104449Sphk
775181462Sdes	return (SBUF_ISFINISHED(s));
776104449Sphk}
777249377Strociny
778249377Strociny/*
779249377Strociny * Start a section.
780249377Strociny */
781249377Strocinyvoid
782249377Strocinysbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
783249377Strociny{
784249377Strociny
785249377Strociny	assert_sbuf_integrity(s);
786249377Strociny	assert_sbuf_state(s, 0);
787249377Strociny
788249377Strociny	if (!SBUF_ISSECTION(s)) {
789249377Strociny		KASSERT(s->s_sect_len == 0,
790249377Strociny		    ("s_sect_len != 0 when starting a section"));
791249377Strociny		if (old_lenp != NULL)
792249377Strociny			*old_lenp = -1;
793249377Strociny		SBUF_SETFLAG(s, SBUF_INSECTION);
794249377Strociny	} else {
795249377Strociny		KASSERT(old_lenp != NULL,
796249377Strociny		    ("s_sect_len should be saved when starting a subsection"));
797249377Strociny		*old_lenp = s->s_sect_len;
798249377Strociny		s->s_sect_len = 0;
799249377Strociny	}
800249377Strociny}
801249377Strociny
802249377Strociny/*
803249377Strociny * End the section padding to the specified length with the specified
804249377Strociny * character.
805249377Strociny */
806249377Strocinyssize_t
807249377Strocinysbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
808249377Strociny{
809249377Strociny	ssize_t len;
810249377Strociny
811249377Strociny	assert_sbuf_integrity(s);
812249377Strociny	assert_sbuf_state(s, 0);
813249377Strociny	KASSERT(SBUF_ISSECTION(s),
814249377Strociny	    ("attempt to end a section when not in a section"));
815249377Strociny
816249377Strociny	if (pad > 1) {
817249377Strociny		len = roundup(s->s_sect_len, pad) - s->s_sect_len;
818249377Strociny		for (; s->s_error == 0 && len > 0; len--)
819249377Strociny			sbuf_put_byte(s, c);
820249377Strociny	}
821249377Strociny	len = s->s_sect_len;
822249377Strociny	if (old_len == -1) {
823249377Strociny		s->s_sect_len = 0;
824249377Strociny		SBUF_CLEARFLAG(s, SBUF_INSECTION);
825249377Strociny	} else {
826249377Strociny		s->s_sect_len += old_len;
827249377Strociny	}
828249377Strociny	if (s->s_error != 0)
829249377Strociny		return (-1);
830249377Strociny	return (len);
831249377Strociny}
832