xref: /haiku/src/libs/compat/freebsd_network/fbsd_subr_sbuf.c (revision dba28784c21beab5d397068303881fe024a76859)
1*dba28784SAugustin Cavalier /*-
2*dba28784SAugustin Cavalier  * Copyright (c) 2000-2008 Poul-Henning Kamp
3*dba28784SAugustin Cavalier  * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav
4*dba28784SAugustin Cavalier  * All rights reserved.
5*dba28784SAugustin Cavalier  *
6*dba28784SAugustin Cavalier  * Redistribution and use in source and binary forms, with or without
7*dba28784SAugustin Cavalier  * modification, are permitted provided that the following conditions
8*dba28784SAugustin Cavalier  * are met:
9*dba28784SAugustin Cavalier  * 1. Redistributions of source code must retain the above copyright
10*dba28784SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer
11*dba28784SAugustin Cavalier  *    in this position and unchanged.
12*dba28784SAugustin Cavalier  * 2. Redistributions in binary form must reproduce the above copyright
13*dba28784SAugustin Cavalier  *    notice, this list of conditions and the following disclaimer in the
14*dba28784SAugustin Cavalier  *    documentation and/or other materials provided with the distribution.
15*dba28784SAugustin Cavalier  *
16*dba28784SAugustin Cavalier  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17*dba28784SAugustin Cavalier  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*dba28784SAugustin Cavalier  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*dba28784SAugustin Cavalier  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20*dba28784SAugustin Cavalier  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21*dba28784SAugustin Cavalier  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22*dba28784SAugustin Cavalier  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23*dba28784SAugustin Cavalier  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24*dba28784SAugustin Cavalier  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25*dba28784SAugustin Cavalier  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26*dba28784SAugustin Cavalier  * SUCH DAMAGE.
27*dba28784SAugustin Cavalier  */
28*dba28784SAugustin Cavalier 
29*dba28784SAugustin Cavalier #include <sys/cdefs.h>
30*dba28784SAugustin Cavalier __FBSDID("$FreeBSD$");
31*dba28784SAugustin Cavalier 
32*dba28784SAugustin Cavalier #include <sys/param.h>
33*dba28784SAugustin Cavalier 
34*dba28784SAugustin Cavalier #ifdef _KERNEL
35*dba28784SAugustin Cavalier #include <sys/ctype.h>
36*dba28784SAugustin Cavalier #include <sys/errno.h>
37*dba28784SAugustin Cavalier #include <sys/kernel.h>
38*dba28784SAugustin Cavalier #include <sys/limits.h>
39*dba28784SAugustin Cavalier #include <sys/malloc.h>
40*dba28784SAugustin Cavalier #include <sys/systm.h>
41*dba28784SAugustin Cavalier #include <sys/uio.h>
42*dba28784SAugustin Cavalier #include <machine/stdarg.h>
43*dba28784SAugustin Cavalier #else /* _KERNEL */
44*dba28784SAugustin Cavalier #include <ctype.h>
45*dba28784SAugustin Cavalier #include <errno.h>
46*dba28784SAugustin Cavalier #include <limits.h>
47*dba28784SAugustin Cavalier #include <stdarg.h>
48*dba28784SAugustin Cavalier #include <stdio.h>
49*dba28784SAugustin Cavalier #include <stdlib.h>
50*dba28784SAugustin Cavalier #include <string.h>
51*dba28784SAugustin Cavalier #endif /* _KERNEL */
52*dba28784SAugustin Cavalier 
53*dba28784SAugustin Cavalier #include <sys/sbuf.h>
54*dba28784SAugustin Cavalier 
55*dba28784SAugustin Cavalier #ifdef _KERNEL
56*dba28784SAugustin Cavalier //static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
57*dba28784SAugustin Cavalier #define	SBMALLOC(size)		malloc(size)
58*dba28784SAugustin Cavalier #define	SBFREE(buf)		free(buf)
59*dba28784SAugustin Cavalier #if __GNUC__ == 2
60*dba28784SAugustin Cavalier #	define va_copy(to, from)	__va_copy(to, from)
61*dba28784SAugustin Cavalier #endif
62*dba28784SAugustin Cavalier #else /* _KERNEL */
63*dba28784SAugustin Cavalier #define	KASSERT(e, m)
64*dba28784SAugustin Cavalier #define	SBMALLOC(size)		calloc(1, size)
65*dba28784SAugustin Cavalier #define	SBFREE(buf)		free(buf)
66*dba28784SAugustin Cavalier #endif /* _KERNEL */
67*dba28784SAugustin Cavalier 
68*dba28784SAugustin Cavalier /*
69*dba28784SAugustin Cavalier  * Predicates
70*dba28784SAugustin Cavalier  */
71*dba28784SAugustin Cavalier #define	SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
72*dba28784SAugustin Cavalier #define	SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
73*dba28784SAugustin Cavalier #define	SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
74*dba28784SAugustin Cavalier #define	SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
75*dba28784SAugustin Cavalier #define	SBUF_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
76*dba28784SAugustin Cavalier #define	SBUF_CANEXTEND(s)	((s)->s_flags & SBUF_AUTOEXTEND)
77*dba28784SAugustin Cavalier #define	SBUF_ISSECTION(s)	((s)->s_flags & SBUF_INSECTION)
78*dba28784SAugustin Cavalier #define	SBUF_NULINCLUDED(s)	((s)->s_flags & SBUF_INCLUDENUL)
79*dba28784SAugustin Cavalier 
80*dba28784SAugustin Cavalier /*
81*dba28784SAugustin Cavalier  * Set / clear flags
82*dba28784SAugustin Cavalier  */
83*dba28784SAugustin Cavalier #define	SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
84*dba28784SAugustin Cavalier #define	SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
85*dba28784SAugustin Cavalier 
86*dba28784SAugustin Cavalier #define	SBUF_MINSIZE		 2		/* Min is 1 byte + nulterm. */
87*dba28784SAugustin Cavalier #define	SBUF_MINEXTENDSIZE	16		/* Should be power of 2. */
88*dba28784SAugustin Cavalier 
89*dba28784SAugustin Cavalier #ifdef PAGE_SIZE
90*dba28784SAugustin Cavalier #define	SBUF_MAXEXTENDSIZE	PAGE_SIZE
91*dba28784SAugustin Cavalier #define	SBUF_MAXEXTENDINCR	PAGE_SIZE
92*dba28784SAugustin Cavalier #else
93*dba28784SAugustin Cavalier #define	SBUF_MAXEXTENDSIZE	4096
94*dba28784SAugustin Cavalier #define	SBUF_MAXEXTENDINCR	4096
95*dba28784SAugustin Cavalier #endif
96*dba28784SAugustin Cavalier 
97*dba28784SAugustin Cavalier /*
98*dba28784SAugustin Cavalier  * Debugging support
99*dba28784SAugustin Cavalier  */
100*dba28784SAugustin Cavalier #if defined(_KERNEL) && defined(INVARIANTS)
101*dba28784SAugustin Cavalier 
102*dba28784SAugustin Cavalier static void
_assert_sbuf_integrity(const char * fun,struct sbuf * s)103*dba28784SAugustin Cavalier _assert_sbuf_integrity(const char *fun, struct sbuf *s)
104*dba28784SAugustin Cavalier {
105*dba28784SAugustin Cavalier 
106*dba28784SAugustin Cavalier 	KASSERT(s != NULL,
107*dba28784SAugustin Cavalier 	    ("%s called with a NULL sbuf pointer", fun));
108*dba28784SAugustin Cavalier 	KASSERT(s->s_buf != NULL,
109*dba28784SAugustin Cavalier 	    ("%s called with uninitialized or corrupt sbuf", fun));
110*dba28784SAugustin Cavalier         if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) {
111*dba28784SAugustin Cavalier 		KASSERT(s->s_len <= s->s_size,
112*dba28784SAugustin Cavalier 		    ("wrote past end of sbuf (%jd >= %jd)",
113*dba28784SAugustin Cavalier 		    (intmax_t)s->s_len, (intmax_t)s->s_size));
114*dba28784SAugustin Cavalier 	} else {
115*dba28784SAugustin Cavalier 		KASSERT(s->s_len < s->s_size,
116*dba28784SAugustin Cavalier 		    ("wrote past end of sbuf (%jd >= %jd)",
117*dba28784SAugustin Cavalier 		    (intmax_t)s->s_len, (intmax_t)s->s_size));
118*dba28784SAugustin Cavalier 	}
119*dba28784SAugustin Cavalier }
120*dba28784SAugustin Cavalier 
121*dba28784SAugustin Cavalier static void
_assert_sbuf_state(const char * fun,struct sbuf * s,int state)122*dba28784SAugustin Cavalier _assert_sbuf_state(const char *fun, struct sbuf *s, int state)
123*dba28784SAugustin Cavalier {
124*dba28784SAugustin Cavalier 
125*dba28784SAugustin Cavalier 	KASSERT((s->s_flags & SBUF_FINISHED) == state,
126*dba28784SAugustin Cavalier 	    ("%s called with %sfinished or corrupt sbuf", fun,
127*dba28784SAugustin Cavalier 	    (state ? "un" : "")));
128*dba28784SAugustin Cavalier }
129*dba28784SAugustin Cavalier 
130*dba28784SAugustin Cavalier #define	assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
131*dba28784SAugustin Cavalier #define	assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
132*dba28784SAugustin Cavalier 
133*dba28784SAugustin Cavalier #else /* _KERNEL && INVARIANTS */
134*dba28784SAugustin Cavalier 
135*dba28784SAugustin Cavalier #define	assert_sbuf_integrity(s) do { } while (0)
136*dba28784SAugustin Cavalier #define	assert_sbuf_state(s, i)	 do { } while (0)
137*dba28784SAugustin Cavalier 
138*dba28784SAugustin Cavalier #endif /* _KERNEL && INVARIANTS */
139*dba28784SAugustin Cavalier 
140*dba28784SAugustin Cavalier #if 0
141*dba28784SAugustin Cavalier CTASSERT(powerof2(SBUF_MAXEXTENDSIZE));
142*dba28784SAugustin Cavalier CTASSERT(powerof2(SBUF_MAXEXTENDINCR));
143*dba28784SAugustin Cavalier #endif
144*dba28784SAugustin Cavalier 
145*dba28784SAugustin Cavalier static int
sbuf_extendsize(int size)146*dba28784SAugustin Cavalier sbuf_extendsize(int size)
147*dba28784SAugustin Cavalier {
148*dba28784SAugustin Cavalier 	int newsize;
149*dba28784SAugustin Cavalier 
150*dba28784SAugustin Cavalier 	if (size < (int)SBUF_MAXEXTENDSIZE) {
151*dba28784SAugustin Cavalier 		newsize = SBUF_MINEXTENDSIZE;
152*dba28784SAugustin Cavalier 		while (newsize < size)
153*dba28784SAugustin Cavalier 			newsize *= 2;
154*dba28784SAugustin Cavalier 	} else {
155*dba28784SAugustin Cavalier 		newsize = roundup2(size, SBUF_MAXEXTENDINCR);
156*dba28784SAugustin Cavalier 	}
157*dba28784SAugustin Cavalier 	KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
158*dba28784SAugustin Cavalier 	return (newsize);
159*dba28784SAugustin Cavalier }
160*dba28784SAugustin Cavalier 
161*dba28784SAugustin Cavalier /*
162*dba28784SAugustin Cavalier  * Extend an sbuf.
163*dba28784SAugustin Cavalier  */
164*dba28784SAugustin Cavalier static int
sbuf_extend(struct sbuf * s,int addlen)165*dba28784SAugustin Cavalier sbuf_extend(struct sbuf *s, int addlen)
166*dba28784SAugustin Cavalier {
167*dba28784SAugustin Cavalier 	char *newbuf;
168*dba28784SAugustin Cavalier 	int newsize;
169*dba28784SAugustin Cavalier 
170*dba28784SAugustin Cavalier 	if (!SBUF_CANEXTEND(s))
171*dba28784SAugustin Cavalier 		return (-1);
172*dba28784SAugustin Cavalier 	newsize = sbuf_extendsize(s->s_size + addlen);
173*dba28784SAugustin Cavalier 	newbuf = SBMALLOC(newsize);
174*dba28784SAugustin Cavalier 	if (newbuf == NULL)
175*dba28784SAugustin Cavalier 		return (-1);
176*dba28784SAugustin Cavalier 	memcpy(newbuf, s->s_buf, s->s_size);
177*dba28784SAugustin Cavalier 	if (SBUF_ISDYNAMIC(s))
178*dba28784SAugustin Cavalier 		SBFREE(s->s_buf);
179*dba28784SAugustin Cavalier 	else
180*dba28784SAugustin Cavalier 		SBUF_SETFLAG(s, SBUF_DYNAMIC);
181*dba28784SAugustin Cavalier 	s->s_buf = newbuf;
182*dba28784SAugustin Cavalier 	s->s_size = newsize;
183*dba28784SAugustin Cavalier 	return (0);
184*dba28784SAugustin Cavalier }
185*dba28784SAugustin Cavalier 
186*dba28784SAugustin Cavalier /*
187*dba28784SAugustin Cavalier  * Initialize the internals of an sbuf.
188*dba28784SAugustin Cavalier  * If buf is non-NULL, it points to a static or already-allocated string
189*dba28784SAugustin Cavalier  * big enough to hold at least length characters.
190*dba28784SAugustin Cavalier  */
191*dba28784SAugustin Cavalier static struct sbuf *
sbuf_newbuf(struct sbuf * s,char * buf,int length,int flags)192*dba28784SAugustin Cavalier sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags)
193*dba28784SAugustin Cavalier {
194*dba28784SAugustin Cavalier 
195*dba28784SAugustin Cavalier 	memset(s, 0, sizeof(*s));
196*dba28784SAugustin Cavalier 	s->s_flags = flags;
197*dba28784SAugustin Cavalier 	s->s_size = length;
198*dba28784SAugustin Cavalier 	s->s_buf = buf;
199*dba28784SAugustin Cavalier 
200*dba28784SAugustin Cavalier 	if ((s->s_flags & SBUF_AUTOEXTEND) == 0) {
201*dba28784SAugustin Cavalier 		KASSERT(s->s_size >= SBUF_MINSIZE,
202*dba28784SAugustin Cavalier 		    ("attempt to create an sbuf smaller than %d bytes",
203*dba28784SAugustin Cavalier 		    SBUF_MINSIZE));
204*dba28784SAugustin Cavalier 	}
205*dba28784SAugustin Cavalier 
206*dba28784SAugustin Cavalier 	if (s->s_buf != NULL)
207*dba28784SAugustin Cavalier 		return (s);
208*dba28784SAugustin Cavalier 
209*dba28784SAugustin Cavalier 	if ((flags & SBUF_AUTOEXTEND) != 0)
210*dba28784SAugustin Cavalier 		s->s_size = sbuf_extendsize(s->s_size);
211*dba28784SAugustin Cavalier 
212*dba28784SAugustin Cavalier 	s->s_buf = SBMALLOC(s->s_size);
213*dba28784SAugustin Cavalier 	if (s->s_buf == NULL)
214*dba28784SAugustin Cavalier 		return (NULL);
215*dba28784SAugustin Cavalier 	SBUF_SETFLAG(s, SBUF_DYNAMIC);
216*dba28784SAugustin Cavalier 	return (s);
217*dba28784SAugustin Cavalier }
218*dba28784SAugustin Cavalier 
219*dba28784SAugustin Cavalier /*
220*dba28784SAugustin Cavalier  * Initialize an sbuf.
221*dba28784SAugustin Cavalier  * If buf is non-NULL, it points to a static or already-allocated string
222*dba28784SAugustin Cavalier  * big enough to hold at least length characters.
223*dba28784SAugustin Cavalier  */
224*dba28784SAugustin Cavalier struct sbuf *
sbuf_new(struct sbuf * s,char * buf,int length,int flags)225*dba28784SAugustin Cavalier sbuf_new(struct sbuf *s, char *buf, int length, int flags)
226*dba28784SAugustin Cavalier {
227*dba28784SAugustin Cavalier 
228*dba28784SAugustin Cavalier 	KASSERT(length >= 0,
229*dba28784SAugustin Cavalier 	    ("attempt to create an sbuf of negative length (%d)", length));
230*dba28784SAugustin Cavalier 	KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
231*dba28784SAugustin Cavalier 	    ("%s called with invalid flags", __func__));
232*dba28784SAugustin Cavalier 
233*dba28784SAugustin Cavalier 	flags &= SBUF_USRFLAGMSK;
234*dba28784SAugustin Cavalier 	if (s != NULL)
235*dba28784SAugustin Cavalier 		return (sbuf_newbuf(s, buf, length, flags));
236*dba28784SAugustin Cavalier 
237*dba28784SAugustin Cavalier 	s = SBMALLOC(sizeof(*s));
238*dba28784SAugustin Cavalier 	if (s == NULL)
239*dba28784SAugustin Cavalier 		return (NULL);
240*dba28784SAugustin Cavalier 	if (sbuf_newbuf(s, buf, length, flags) == NULL) {
241*dba28784SAugustin Cavalier 		SBFREE(s);
242*dba28784SAugustin Cavalier 		return (NULL);
243*dba28784SAugustin Cavalier 	}
244*dba28784SAugustin Cavalier 	SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
245*dba28784SAugustin Cavalier 	return (s);
246*dba28784SAugustin Cavalier }
247*dba28784SAugustin Cavalier 
248*dba28784SAugustin Cavalier #if 0
249*dba28784SAugustin Cavalier /*
250*dba28784SAugustin Cavalier  * Create an sbuf with uio data
251*dba28784SAugustin Cavalier  */
252*dba28784SAugustin Cavalier struct sbuf *
253*dba28784SAugustin Cavalier sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
254*dba28784SAugustin Cavalier {
255*dba28784SAugustin Cavalier 
256*dba28784SAugustin Cavalier 	KASSERT(uio != NULL,
257*dba28784SAugustin Cavalier 	    ("%s called with NULL uio pointer", __func__));
258*dba28784SAugustin Cavalier 	KASSERT(error != NULL,
259*dba28784SAugustin Cavalier 	    ("%s called with NULL error pointer", __func__));
260*dba28784SAugustin Cavalier 
261*dba28784SAugustin Cavalier 	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
262*dba28784SAugustin Cavalier 	if (s == NULL) {
263*dba28784SAugustin Cavalier 		*error = ENOMEM;
264*dba28784SAugustin Cavalier 		return (NULL);
265*dba28784SAugustin Cavalier 	}
266*dba28784SAugustin Cavalier 	*error = uiomove(s->s_buf, uio->uio_resid, uio);
267*dba28784SAugustin Cavalier 	if (*error != 0) {
268*dba28784SAugustin Cavalier 		sbuf_delete(s);
269*dba28784SAugustin Cavalier 		return (NULL);
270*dba28784SAugustin Cavalier 	}
271*dba28784SAugustin Cavalier 	s->s_len = s->s_size - 1;
272*dba28784SAugustin Cavalier 	if (SBUF_ISSECTION(s))
273*dba28784SAugustin Cavalier 		s->s_sect_len = s->s_size - 1;
274*dba28784SAugustin Cavalier 	*error = 0;
275*dba28784SAugustin Cavalier 	return (s);
276*dba28784SAugustin Cavalier }
277*dba28784SAugustin Cavalier #endif
278*dba28784SAugustin Cavalier 
279*dba28784SAugustin Cavalier int
sbuf_get_flags(struct sbuf * s)280*dba28784SAugustin Cavalier sbuf_get_flags(struct sbuf *s)
281*dba28784SAugustin Cavalier {
282*dba28784SAugustin Cavalier 
283*dba28784SAugustin Cavalier 	return (s->s_flags & SBUF_USRFLAGMSK);
284*dba28784SAugustin Cavalier }
285*dba28784SAugustin Cavalier 
286*dba28784SAugustin Cavalier void
sbuf_clear_flags(struct sbuf * s,int flags)287*dba28784SAugustin Cavalier sbuf_clear_flags(struct sbuf *s, int flags)
288*dba28784SAugustin Cavalier {
289*dba28784SAugustin Cavalier 
290*dba28784SAugustin Cavalier 	s->s_flags &= ~(flags & SBUF_USRFLAGMSK);
291*dba28784SAugustin Cavalier }
292*dba28784SAugustin Cavalier 
293*dba28784SAugustin Cavalier void
sbuf_set_flags(struct sbuf * s,int flags)294*dba28784SAugustin Cavalier sbuf_set_flags(struct sbuf *s, int flags)
295*dba28784SAugustin Cavalier {
296*dba28784SAugustin Cavalier 
297*dba28784SAugustin Cavalier 
298*dba28784SAugustin Cavalier 	s->s_flags |= (flags & SBUF_USRFLAGMSK);
299*dba28784SAugustin Cavalier }
300*dba28784SAugustin Cavalier 
301*dba28784SAugustin Cavalier /*
302*dba28784SAugustin Cavalier  * Clear an sbuf and reset its position.
303*dba28784SAugustin Cavalier  */
304*dba28784SAugustin Cavalier void
sbuf_clear(struct sbuf * s)305*dba28784SAugustin Cavalier sbuf_clear(struct sbuf *s)
306*dba28784SAugustin Cavalier {
307*dba28784SAugustin Cavalier 
308*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
309*dba28784SAugustin Cavalier 	/* don't care if it's finished or not */
310*dba28784SAugustin Cavalier 
311*dba28784SAugustin Cavalier 	SBUF_CLEARFLAG(s, SBUF_FINISHED);
312*dba28784SAugustin Cavalier 	s->s_error = 0;
313*dba28784SAugustin Cavalier 	s->s_len = 0;
314*dba28784SAugustin Cavalier 	s->s_sect_len = 0;
315*dba28784SAugustin Cavalier }
316*dba28784SAugustin Cavalier 
317*dba28784SAugustin Cavalier /*
318*dba28784SAugustin Cavalier  * Set the sbuf's end position to an arbitrary value.
319*dba28784SAugustin Cavalier  * Effectively truncates the sbuf at the new position.
320*dba28784SAugustin Cavalier  */
321*dba28784SAugustin Cavalier int
sbuf_setpos(struct sbuf * s,ssize_t pos)322*dba28784SAugustin Cavalier sbuf_setpos(struct sbuf *s, ssize_t pos)
323*dba28784SAugustin Cavalier {
324*dba28784SAugustin Cavalier 
325*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
326*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
327*dba28784SAugustin Cavalier 
328*dba28784SAugustin Cavalier 	KASSERT(pos >= 0,
329*dba28784SAugustin Cavalier 	    ("attempt to seek to a negative position (%jd)", (intmax_t)pos));
330*dba28784SAugustin Cavalier 	KASSERT(pos < s->s_size,
331*dba28784SAugustin Cavalier 	    ("attempt to seek past end of sbuf (%jd >= %jd)",
332*dba28784SAugustin Cavalier 	    (intmax_t)pos, (intmax_t)s->s_size));
333*dba28784SAugustin Cavalier 	KASSERT(!SBUF_ISSECTION(s),
334*dba28784SAugustin Cavalier 	    ("attempt to seek when in a section"));
335*dba28784SAugustin Cavalier 
336*dba28784SAugustin Cavalier 	if (pos < 0 || pos > s->s_len)
337*dba28784SAugustin Cavalier 		return (-1);
338*dba28784SAugustin Cavalier 	s->s_len = pos;
339*dba28784SAugustin Cavalier 	return (0);
340*dba28784SAugustin Cavalier }
341*dba28784SAugustin Cavalier 
342*dba28784SAugustin Cavalier /*
343*dba28784SAugustin Cavalier  * Set up a drain function and argument on an sbuf to flush data to
344*dba28784SAugustin Cavalier  * when the sbuf buffer overflows.
345*dba28784SAugustin Cavalier  */
346*dba28784SAugustin Cavalier void
sbuf_set_drain(struct sbuf * s,sbuf_drain_func * func,void * ctx)347*dba28784SAugustin Cavalier sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx)
348*dba28784SAugustin Cavalier {
349*dba28784SAugustin Cavalier 
350*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
351*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
352*dba28784SAugustin Cavalier 	KASSERT(func == s->s_drain_func || s->s_len == 0,
353*dba28784SAugustin Cavalier 	    ("Cannot change drain to %p on non-empty sbuf %p", func, s));
354*dba28784SAugustin Cavalier 	s->s_drain_func = func;
355*dba28784SAugustin Cavalier 	s->s_drain_arg = ctx;
356*dba28784SAugustin Cavalier }
357*dba28784SAugustin Cavalier 
358*dba28784SAugustin Cavalier /*
359*dba28784SAugustin Cavalier  * Call the drain and process the return.
360*dba28784SAugustin Cavalier  */
361*dba28784SAugustin Cavalier static int
sbuf_drain(struct sbuf * s)362*dba28784SAugustin Cavalier sbuf_drain(struct sbuf *s)
363*dba28784SAugustin Cavalier {
364*dba28784SAugustin Cavalier 	int len;
365*dba28784SAugustin Cavalier 
366*dba28784SAugustin Cavalier 	KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s));
367*dba28784SAugustin Cavalier 	KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s));
368*dba28784SAugustin Cavalier 	len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len);
369*dba28784SAugustin Cavalier 	if (len < 0) {
370*dba28784SAugustin Cavalier 		s->s_error = -len;
371*dba28784SAugustin Cavalier 		return (s->s_error);
372*dba28784SAugustin Cavalier 	}
373*dba28784SAugustin Cavalier 	KASSERT(len > 0 && len <= s->s_len,
374*dba28784SAugustin Cavalier 	    ("Bad drain amount %d for sbuf %p", len, s));
375*dba28784SAugustin Cavalier 	s->s_len -= len;
376*dba28784SAugustin Cavalier 	/*
377*dba28784SAugustin Cavalier 	 * Fast path for the expected case where all the data was
378*dba28784SAugustin Cavalier 	 * drained.
379*dba28784SAugustin Cavalier 	 */
380*dba28784SAugustin Cavalier 	if (s->s_len == 0)
381*dba28784SAugustin Cavalier 		return (0);
382*dba28784SAugustin Cavalier 	/*
383*dba28784SAugustin Cavalier 	 * Move the remaining characters to the beginning of the
384*dba28784SAugustin Cavalier 	 * string.
385*dba28784SAugustin Cavalier 	 */
386*dba28784SAugustin Cavalier 	memmove(s->s_buf, s->s_buf + len, s->s_len);
387*dba28784SAugustin Cavalier 	return (0);
388*dba28784SAugustin Cavalier }
389*dba28784SAugustin Cavalier 
390*dba28784SAugustin Cavalier /*
391*dba28784SAugustin Cavalier  * Append bytes to an sbuf.  This is the core function for appending
392*dba28784SAugustin Cavalier  * to an sbuf and is the main place that deals with extending the
393*dba28784SAugustin Cavalier  * buffer and marking overflow.
394*dba28784SAugustin Cavalier  */
395*dba28784SAugustin Cavalier static void
sbuf_put_bytes(struct sbuf * s,const char * buf,size_t len)396*dba28784SAugustin Cavalier sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len)
397*dba28784SAugustin Cavalier {
398*dba28784SAugustin Cavalier 	size_t n;
399*dba28784SAugustin Cavalier 
400*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
401*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
402*dba28784SAugustin Cavalier 
403*dba28784SAugustin Cavalier 	if (s->s_error != 0)
404*dba28784SAugustin Cavalier 		return;
405*dba28784SAugustin Cavalier 	while (len > 0) {
406*dba28784SAugustin Cavalier 		if (SBUF_FREESPACE(s) <= 0) {
407*dba28784SAugustin Cavalier 			/*
408*dba28784SAugustin Cavalier 			 * If there is a drain, use it, otherwise extend the
409*dba28784SAugustin Cavalier 			 * buffer.
410*dba28784SAugustin Cavalier 			 */
411*dba28784SAugustin Cavalier 			if (s->s_drain_func != NULL)
412*dba28784SAugustin Cavalier 				(void)sbuf_drain(s);
413*dba28784SAugustin Cavalier 			else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len)
414*dba28784SAugustin Cavalier 			    < 0)
415*dba28784SAugustin Cavalier 				s->s_error = ENOMEM;
416*dba28784SAugustin Cavalier 			if (s->s_error != 0)
417*dba28784SAugustin Cavalier 				return;
418*dba28784SAugustin Cavalier 		}
419*dba28784SAugustin Cavalier 		n = SBUF_FREESPACE(s);
420*dba28784SAugustin Cavalier 		if (len < n)
421*dba28784SAugustin Cavalier 			n = len;
422*dba28784SAugustin Cavalier 		memcpy(&s->s_buf[s->s_len], buf, n);
423*dba28784SAugustin Cavalier 		s->s_len += n;
424*dba28784SAugustin Cavalier 		if (SBUF_ISSECTION(s))
425*dba28784SAugustin Cavalier 			s->s_sect_len += n;
426*dba28784SAugustin Cavalier 		len -= n;
427*dba28784SAugustin Cavalier 		buf += n;
428*dba28784SAugustin Cavalier 	}
429*dba28784SAugustin Cavalier }
430*dba28784SAugustin Cavalier 
431*dba28784SAugustin Cavalier static void
sbuf_put_byte(struct sbuf * s,char c)432*dba28784SAugustin Cavalier sbuf_put_byte(struct sbuf *s, char c)
433*dba28784SAugustin Cavalier {
434*dba28784SAugustin Cavalier 
435*dba28784SAugustin Cavalier 	sbuf_put_bytes(s, &c, 1);
436*dba28784SAugustin Cavalier }
437*dba28784SAugustin Cavalier 
438*dba28784SAugustin Cavalier /*
439*dba28784SAugustin Cavalier  * Append a byte string to an sbuf.
440*dba28784SAugustin Cavalier  */
441*dba28784SAugustin Cavalier int
sbuf_bcat(struct sbuf * s,const void * buf,size_t len)442*dba28784SAugustin Cavalier sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
443*dba28784SAugustin Cavalier {
444*dba28784SAugustin Cavalier 
445*dba28784SAugustin Cavalier 	sbuf_put_bytes(s, buf, len);
446*dba28784SAugustin Cavalier 	if (s->s_error != 0)
447*dba28784SAugustin Cavalier 		return (-1);
448*dba28784SAugustin Cavalier 	return (0);
449*dba28784SAugustin Cavalier }
450*dba28784SAugustin Cavalier 
451*dba28784SAugustin Cavalier #ifdef _KERNEL
452*dba28784SAugustin Cavalier /*
453*dba28784SAugustin Cavalier  * Copy a byte string from userland into an sbuf.
454*dba28784SAugustin Cavalier  */
455*dba28784SAugustin Cavalier int
sbuf_bcopyin(struct sbuf * s,const void * uaddr,size_t len)456*dba28784SAugustin Cavalier sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
457*dba28784SAugustin Cavalier {
458*dba28784SAugustin Cavalier 
459*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
460*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
461*dba28784SAugustin Cavalier 	KASSERT(s->s_drain_func == NULL,
462*dba28784SAugustin Cavalier 	    ("Nonsensical copyin to sbuf %p with a drain", s));
463*dba28784SAugustin Cavalier 
464*dba28784SAugustin Cavalier 	if (s->s_error != 0)
465*dba28784SAugustin Cavalier 		return (-1);
466*dba28784SAugustin Cavalier 	if (len == 0)
467*dba28784SAugustin Cavalier 		return (0);
468*dba28784SAugustin Cavalier 	if (len > SBUF_FREESPACE(s)) {
469*dba28784SAugustin Cavalier 		sbuf_extend(s, len - SBUF_FREESPACE(s));
470*dba28784SAugustin Cavalier 		if (SBUF_FREESPACE(s) < len)
471*dba28784SAugustin Cavalier 			len = SBUF_FREESPACE(s);
472*dba28784SAugustin Cavalier 	}
473*dba28784SAugustin Cavalier 	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
474*dba28784SAugustin Cavalier 		return (-1);
475*dba28784SAugustin Cavalier 	s->s_len += len;
476*dba28784SAugustin Cavalier 
477*dba28784SAugustin Cavalier 	return (0);
478*dba28784SAugustin Cavalier }
479*dba28784SAugustin Cavalier #endif
480*dba28784SAugustin Cavalier 
481*dba28784SAugustin Cavalier /*
482*dba28784SAugustin Cavalier  * Copy a byte string into an sbuf.
483*dba28784SAugustin Cavalier  */
484*dba28784SAugustin Cavalier int
sbuf_bcpy(struct sbuf * s,const void * buf,size_t len)485*dba28784SAugustin Cavalier sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
486*dba28784SAugustin Cavalier {
487*dba28784SAugustin Cavalier 
488*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
489*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
490*dba28784SAugustin Cavalier 
491*dba28784SAugustin Cavalier 	sbuf_clear(s);
492*dba28784SAugustin Cavalier 	return (sbuf_bcat(s, buf, len));
493*dba28784SAugustin Cavalier }
494*dba28784SAugustin Cavalier 
495*dba28784SAugustin Cavalier /*
496*dba28784SAugustin Cavalier  * Append a string to an sbuf.
497*dba28784SAugustin Cavalier  */
498*dba28784SAugustin Cavalier int
sbuf_cat(struct sbuf * s,const char * str)499*dba28784SAugustin Cavalier sbuf_cat(struct sbuf *s, const char *str)
500*dba28784SAugustin Cavalier {
501*dba28784SAugustin Cavalier 	size_t n;
502*dba28784SAugustin Cavalier 
503*dba28784SAugustin Cavalier 	n = strlen(str);
504*dba28784SAugustin Cavalier 	sbuf_put_bytes(s, str, n);
505*dba28784SAugustin Cavalier 	if (s->s_error != 0)
506*dba28784SAugustin Cavalier 		return (-1);
507*dba28784SAugustin Cavalier 	return (0);
508*dba28784SAugustin Cavalier }
509*dba28784SAugustin Cavalier 
510*dba28784SAugustin Cavalier #if 0
511*dba28784SAugustin Cavalier /*
512*dba28784SAugustin Cavalier  * Append a string from userland to an sbuf.
513*dba28784SAugustin Cavalier  */
514*dba28784SAugustin Cavalier int
515*dba28784SAugustin Cavalier sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
516*dba28784SAugustin Cavalier {
517*dba28784SAugustin Cavalier 	size_t done;
518*dba28784SAugustin Cavalier 
519*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
520*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
521*dba28784SAugustin Cavalier 	KASSERT(s->s_drain_func == NULL,
522*dba28784SAugustin Cavalier 	    ("Nonsensical copyin to sbuf %p with a drain", s));
523*dba28784SAugustin Cavalier 
524*dba28784SAugustin Cavalier 	if (s->s_error != 0)
525*dba28784SAugustin Cavalier 		return (-1);
526*dba28784SAugustin Cavalier 
527*dba28784SAugustin Cavalier 	if (len == 0)
528*dba28784SAugustin Cavalier 		len = SBUF_FREESPACE(s);	/* XXX return 0? */
529*dba28784SAugustin Cavalier 	if (len > SBUF_FREESPACE(s)) {
530*dba28784SAugustin Cavalier 		sbuf_extend(s, len);
531*dba28784SAugustin Cavalier 		if (SBUF_FREESPACE(s) < len)
532*dba28784SAugustin Cavalier 			len = SBUF_FREESPACE(s);
533*dba28784SAugustin Cavalier 	}
534*dba28784SAugustin Cavalier 	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
535*dba28784SAugustin Cavalier 	case ENAMETOOLONG:
536*dba28784SAugustin Cavalier 		s->s_error = ENOMEM;
537*dba28784SAugustin Cavalier 		/* fall through */
538*dba28784SAugustin Cavalier 	case 0:
539*dba28784SAugustin Cavalier 		s->s_len += done - 1;
540*dba28784SAugustin Cavalier 		if (SBUF_ISSECTION(s))
541*dba28784SAugustin Cavalier 			s->s_sect_len += done - 1;
542*dba28784SAugustin Cavalier 		break;
543*dba28784SAugustin Cavalier 	default:
544*dba28784SAugustin Cavalier 		return (-1);	/* XXX */
545*dba28784SAugustin Cavalier 	}
546*dba28784SAugustin Cavalier 
547*dba28784SAugustin Cavalier 	return (done);
548*dba28784SAugustin Cavalier }
549*dba28784SAugustin Cavalier #endif
550*dba28784SAugustin Cavalier 
551*dba28784SAugustin Cavalier /*
552*dba28784SAugustin Cavalier  * Copy a string into an sbuf.
553*dba28784SAugustin Cavalier  */
554*dba28784SAugustin Cavalier int
sbuf_cpy(struct sbuf * s,const char * str)555*dba28784SAugustin Cavalier sbuf_cpy(struct sbuf *s, const char *str)
556*dba28784SAugustin Cavalier {
557*dba28784SAugustin Cavalier 
558*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
559*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
560*dba28784SAugustin Cavalier 
561*dba28784SAugustin Cavalier 	sbuf_clear(s);
562*dba28784SAugustin Cavalier 	return (sbuf_cat(s, str));
563*dba28784SAugustin Cavalier }
564*dba28784SAugustin Cavalier 
565*dba28784SAugustin Cavalier /*
566*dba28784SAugustin Cavalier  * Format the given argument list and append the resulting string to an sbuf.
567*dba28784SAugustin Cavalier  */
568*dba28784SAugustin Cavalier #if 0
569*dba28784SAugustin Cavalier 
570*dba28784SAugustin Cavalier /*
571*dba28784SAugustin Cavalier  * Append a non-NUL character to an sbuf.  This prototype signature is
572*dba28784SAugustin Cavalier  * suitable for use with kvprintf(9).
573*dba28784SAugustin Cavalier  */
574*dba28784SAugustin Cavalier static void
575*dba28784SAugustin Cavalier sbuf_putc_func(int c, void *arg)
576*dba28784SAugustin Cavalier {
577*dba28784SAugustin Cavalier 
578*dba28784SAugustin Cavalier 	if (c != '\0')
579*dba28784SAugustin Cavalier 		sbuf_put_byte(arg, c);
580*dba28784SAugustin Cavalier }
581*dba28784SAugustin Cavalier 
582*dba28784SAugustin Cavalier int
583*dba28784SAugustin Cavalier sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
584*dba28784SAugustin Cavalier {
585*dba28784SAugustin Cavalier 
586*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
587*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
588*dba28784SAugustin Cavalier 
589*dba28784SAugustin Cavalier 	KASSERT(fmt != NULL,
590*dba28784SAugustin Cavalier 	    ("%s called with a NULL format string", __func__));
591*dba28784SAugustin Cavalier 
592*dba28784SAugustin Cavalier 	(void)kvprintf(fmt, sbuf_putc_func, s, 10, ap);
593*dba28784SAugustin Cavalier 	if (s->s_error != 0)
594*dba28784SAugustin Cavalier 		return (-1);
595*dba28784SAugustin Cavalier 	return (0);
596*dba28784SAugustin Cavalier }
597*dba28784SAugustin Cavalier #else /* !_KERNEL */
598*dba28784SAugustin Cavalier int
sbuf_vprintf(struct sbuf * s,const char * fmt,va_list ap)599*dba28784SAugustin Cavalier sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
600*dba28784SAugustin Cavalier {
601*dba28784SAugustin Cavalier 	va_list ap_copy;
602*dba28784SAugustin Cavalier 	int error, len;
603*dba28784SAugustin Cavalier 
604*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
605*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
606*dba28784SAugustin Cavalier 
607*dba28784SAugustin Cavalier 	KASSERT(fmt != NULL,
608*dba28784SAugustin Cavalier 	    ("%s called with a NULL format string", __func__));
609*dba28784SAugustin Cavalier 
610*dba28784SAugustin Cavalier 	if (s->s_error != 0)
611*dba28784SAugustin Cavalier 		return (-1);
612*dba28784SAugustin Cavalier 
613*dba28784SAugustin Cavalier 	/*
614*dba28784SAugustin Cavalier 	 * For the moment, there is no way to get vsnprintf(3) to hand
615*dba28784SAugustin Cavalier 	 * back a character at a time, to push everything into
616*dba28784SAugustin Cavalier 	 * sbuf_putc_func() as was done for the kernel.
617*dba28784SAugustin Cavalier 	 *
618*dba28784SAugustin Cavalier 	 * In userspace, while drains are useful, there's generally
619*dba28784SAugustin Cavalier 	 * not a problem attempting to malloc(3) on out of space.  So
620*dba28784SAugustin Cavalier 	 * expand a userland sbuf if there is not enough room for the
621*dba28784SAugustin Cavalier 	 * data produced by sbuf_[v]printf(3).
622*dba28784SAugustin Cavalier 	 */
623*dba28784SAugustin Cavalier 
624*dba28784SAugustin Cavalier 	error = 0;
625*dba28784SAugustin Cavalier 	do {
626*dba28784SAugustin Cavalier 		va_copy(ap_copy, ap);
627*dba28784SAugustin Cavalier 		len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
628*dba28784SAugustin Cavalier 		    fmt, ap_copy);
629*dba28784SAugustin Cavalier 		if (len < 0) {
630*dba28784SAugustin Cavalier 			s->s_error = errno;
631*dba28784SAugustin Cavalier 			return (-1);
632*dba28784SAugustin Cavalier 		}
633*dba28784SAugustin Cavalier 		va_end(ap_copy);
634*dba28784SAugustin Cavalier 
635*dba28784SAugustin Cavalier 		if (SBUF_FREESPACE(s) >= len)
636*dba28784SAugustin Cavalier 			break;
637*dba28784SAugustin Cavalier 		/* Cannot print with the current available space. */
638*dba28784SAugustin Cavalier 		if (s->s_drain_func != NULL && s->s_len > 0)
639*dba28784SAugustin Cavalier 			error = sbuf_drain(s);
640*dba28784SAugustin Cavalier 		else
641*dba28784SAugustin Cavalier 			error = sbuf_extend(s, len - SBUF_FREESPACE(s));
642*dba28784SAugustin Cavalier 	} while (error == 0);
643*dba28784SAugustin Cavalier 
644*dba28784SAugustin Cavalier 	/*
645*dba28784SAugustin Cavalier 	 * s->s_len is the length of the string, without the terminating nul.
646*dba28784SAugustin Cavalier 	 * When updating s->s_len, we must subtract 1 from the length that
647*dba28784SAugustin Cavalier 	 * we passed into vsnprintf() because that length includes the
648*dba28784SAugustin Cavalier 	 * terminating nul.
649*dba28784SAugustin Cavalier 	 *
650*dba28784SAugustin Cavalier 	 * vsnprintf() returns the amount that would have been copied,
651*dba28784SAugustin Cavalier 	 * given sufficient space, so don't over-increment s_len.
652*dba28784SAugustin Cavalier 	 */
653*dba28784SAugustin Cavalier 	if (SBUF_FREESPACE(s) < len)
654*dba28784SAugustin Cavalier 		len = SBUF_FREESPACE(s);
655*dba28784SAugustin Cavalier 	s->s_len += len;
656*dba28784SAugustin Cavalier 	if (SBUF_ISSECTION(s))
657*dba28784SAugustin Cavalier 		s->s_sect_len += len;
658*dba28784SAugustin Cavalier 	if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
659*dba28784SAugustin Cavalier 		s->s_error = ENOMEM;
660*dba28784SAugustin Cavalier 
661*dba28784SAugustin Cavalier 	KASSERT(s->s_len < s->s_size,
662*dba28784SAugustin Cavalier 	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
663*dba28784SAugustin Cavalier 
664*dba28784SAugustin Cavalier 	if (s->s_error != 0)
665*dba28784SAugustin Cavalier 		return (-1);
666*dba28784SAugustin Cavalier 	return (0);
667*dba28784SAugustin Cavalier }
668*dba28784SAugustin Cavalier #endif /* _KERNEL */
669*dba28784SAugustin Cavalier 
670*dba28784SAugustin Cavalier /*
671*dba28784SAugustin Cavalier  * Format the given arguments and append the resulting string to an sbuf.
672*dba28784SAugustin Cavalier  */
673*dba28784SAugustin Cavalier int
sbuf_printf(struct sbuf * s,const char * fmt,...)674*dba28784SAugustin Cavalier sbuf_printf(struct sbuf *s, const char *fmt, ...)
675*dba28784SAugustin Cavalier {
676*dba28784SAugustin Cavalier 	va_list ap;
677*dba28784SAugustin Cavalier 	int result;
678*dba28784SAugustin Cavalier 
679*dba28784SAugustin Cavalier 	va_start(ap, fmt);
680*dba28784SAugustin Cavalier 	result = sbuf_vprintf(s, fmt, ap);
681*dba28784SAugustin Cavalier 	va_end(ap);
682*dba28784SAugustin Cavalier 	return (result);
683*dba28784SAugustin Cavalier }
684*dba28784SAugustin Cavalier 
685*dba28784SAugustin Cavalier /*
686*dba28784SAugustin Cavalier  * Append a character to an sbuf.
687*dba28784SAugustin Cavalier  */
688*dba28784SAugustin Cavalier int
sbuf_putc(struct sbuf * s,int c)689*dba28784SAugustin Cavalier sbuf_putc(struct sbuf *s, int c)
690*dba28784SAugustin Cavalier {
691*dba28784SAugustin Cavalier 
692*dba28784SAugustin Cavalier 	sbuf_put_byte(s, c);
693*dba28784SAugustin Cavalier 	if (s->s_error != 0)
694*dba28784SAugustin Cavalier 		return (-1);
695*dba28784SAugustin Cavalier 	return (0);
696*dba28784SAugustin Cavalier }
697*dba28784SAugustin Cavalier 
698*dba28784SAugustin Cavalier /*
699*dba28784SAugustin Cavalier  * Trim whitespace characters from end of an sbuf.
700*dba28784SAugustin Cavalier  */
701*dba28784SAugustin Cavalier #define isspace(c) ((c) == ' ' || (c) == '\t')
702*dba28784SAugustin Cavalier int
sbuf_trim(struct sbuf * s)703*dba28784SAugustin Cavalier sbuf_trim(struct sbuf *s)
704*dba28784SAugustin Cavalier {
705*dba28784SAugustin Cavalier 
706*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
707*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
708*dba28784SAugustin Cavalier 	KASSERT(s->s_drain_func == NULL,
709*dba28784SAugustin Cavalier 	    ("%s makes no sense on sbuf %p with drain", __func__, s));
710*dba28784SAugustin Cavalier 
711*dba28784SAugustin Cavalier 	if (s->s_error != 0)
712*dba28784SAugustin Cavalier 		return (-1);
713*dba28784SAugustin Cavalier 
714*dba28784SAugustin Cavalier 	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) {
715*dba28784SAugustin Cavalier 		--s->s_len;
716*dba28784SAugustin Cavalier 		if (SBUF_ISSECTION(s))
717*dba28784SAugustin Cavalier 			s->s_sect_len--;
718*dba28784SAugustin Cavalier 	}
719*dba28784SAugustin Cavalier 
720*dba28784SAugustin Cavalier 	return (0);
721*dba28784SAugustin Cavalier }
722*dba28784SAugustin Cavalier 
723*dba28784SAugustin Cavalier /*
724*dba28784SAugustin Cavalier  * Check if an sbuf has an error.
725*dba28784SAugustin Cavalier  */
726*dba28784SAugustin Cavalier int
sbuf_error(const struct sbuf * s)727*dba28784SAugustin Cavalier sbuf_error(const struct sbuf *s)
728*dba28784SAugustin Cavalier {
729*dba28784SAugustin Cavalier 
730*dba28784SAugustin Cavalier 	return (s->s_error);
731*dba28784SAugustin Cavalier }
732*dba28784SAugustin Cavalier 
733*dba28784SAugustin Cavalier /*
734*dba28784SAugustin Cavalier  * Finish off an sbuf.
735*dba28784SAugustin Cavalier  */
736*dba28784SAugustin Cavalier int
sbuf_finish(struct sbuf * s)737*dba28784SAugustin Cavalier sbuf_finish(struct sbuf *s)
738*dba28784SAugustin Cavalier {
739*dba28784SAugustin Cavalier 
740*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
741*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
742*dba28784SAugustin Cavalier 
743*dba28784SAugustin Cavalier 	s->s_buf[s->s_len] = '\0';
744*dba28784SAugustin Cavalier 	if (SBUF_NULINCLUDED(s))
745*dba28784SAugustin Cavalier 		s->s_len++;
746*dba28784SAugustin Cavalier 	if (s->s_drain_func != NULL) {
747*dba28784SAugustin Cavalier 		while (s->s_len > 0 && s->s_error == 0)
748*dba28784SAugustin Cavalier 			s->s_error = sbuf_drain(s);
749*dba28784SAugustin Cavalier 	}
750*dba28784SAugustin Cavalier 	SBUF_SETFLAG(s, SBUF_FINISHED);
751*dba28784SAugustin Cavalier #ifdef _KERNEL
752*dba28784SAugustin Cavalier 	return (s->s_error);
753*dba28784SAugustin Cavalier #else
754*dba28784SAugustin Cavalier 	if (s->s_error != 0) {
755*dba28784SAugustin Cavalier 		errno = s->s_error;
756*dba28784SAugustin Cavalier 		return (-1);
757*dba28784SAugustin Cavalier 	}
758*dba28784SAugustin Cavalier 	return (0);
759*dba28784SAugustin Cavalier #endif
760*dba28784SAugustin Cavalier }
761*dba28784SAugustin Cavalier 
762*dba28784SAugustin Cavalier /*
763*dba28784SAugustin Cavalier  * Return a pointer to the sbuf data.
764*dba28784SAugustin Cavalier  */
765*dba28784SAugustin Cavalier char *
sbuf_data(struct sbuf * s)766*dba28784SAugustin Cavalier sbuf_data(struct sbuf *s)
767*dba28784SAugustin Cavalier {
768*dba28784SAugustin Cavalier 
769*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
770*dba28784SAugustin Cavalier 	assert_sbuf_state(s, SBUF_FINISHED);
771*dba28784SAugustin Cavalier 	KASSERT(s->s_drain_func == NULL,
772*dba28784SAugustin Cavalier 	    ("%s makes no sense on sbuf %p with drain", __func__, s));
773*dba28784SAugustin Cavalier 
774*dba28784SAugustin Cavalier 	return (s->s_buf);
775*dba28784SAugustin Cavalier }
776*dba28784SAugustin Cavalier 
777*dba28784SAugustin Cavalier /*
778*dba28784SAugustin Cavalier  * Return the length of the sbuf data.
779*dba28784SAugustin Cavalier  */
780*dba28784SAugustin Cavalier ssize_t
sbuf_len(struct sbuf * s)781*dba28784SAugustin Cavalier sbuf_len(struct sbuf *s)
782*dba28784SAugustin Cavalier {
783*dba28784SAugustin Cavalier 
784*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
785*dba28784SAugustin Cavalier 	/* don't care if it's finished or not */
786*dba28784SAugustin Cavalier 	KASSERT(s->s_drain_func == NULL,
787*dba28784SAugustin Cavalier 	    ("%s makes no sense on sbuf %p with drain", __func__, s));
788*dba28784SAugustin Cavalier 
789*dba28784SAugustin Cavalier 	if (s->s_error != 0)
790*dba28784SAugustin Cavalier 		return (-1);
791*dba28784SAugustin Cavalier 
792*dba28784SAugustin Cavalier 	/* If finished, nulterm is already in len, else add one. */
793*dba28784SAugustin Cavalier 	if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s))
794*dba28784SAugustin Cavalier 		return (s->s_len + 1);
795*dba28784SAugustin Cavalier 	return (s->s_len);
796*dba28784SAugustin Cavalier }
797*dba28784SAugustin Cavalier 
798*dba28784SAugustin Cavalier /*
799*dba28784SAugustin Cavalier  * Clear an sbuf, free its buffer if necessary.
800*dba28784SAugustin Cavalier  */
801*dba28784SAugustin Cavalier void
sbuf_delete(struct sbuf * s)802*dba28784SAugustin Cavalier sbuf_delete(struct sbuf *s)
803*dba28784SAugustin Cavalier {
804*dba28784SAugustin Cavalier 	int isdyn;
805*dba28784SAugustin Cavalier 
806*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
807*dba28784SAugustin Cavalier 	/* don't care if it's finished or not */
808*dba28784SAugustin Cavalier 
809*dba28784SAugustin Cavalier 	if (SBUF_ISDYNAMIC(s))
810*dba28784SAugustin Cavalier 		SBFREE(s->s_buf);
811*dba28784SAugustin Cavalier 	isdyn = SBUF_ISDYNSTRUCT(s);
812*dba28784SAugustin Cavalier 	memset(s, 0, sizeof(*s));
813*dba28784SAugustin Cavalier 	if (isdyn)
814*dba28784SAugustin Cavalier 		SBFREE(s);
815*dba28784SAugustin Cavalier }
816*dba28784SAugustin Cavalier 
817*dba28784SAugustin Cavalier /*
818*dba28784SAugustin Cavalier  * Check if an sbuf has been finished.
819*dba28784SAugustin Cavalier  */
820*dba28784SAugustin Cavalier int
sbuf_done(const struct sbuf * s)821*dba28784SAugustin Cavalier sbuf_done(const struct sbuf *s)
822*dba28784SAugustin Cavalier {
823*dba28784SAugustin Cavalier 
824*dba28784SAugustin Cavalier 	return (SBUF_ISFINISHED(s));
825*dba28784SAugustin Cavalier }
826*dba28784SAugustin Cavalier 
827*dba28784SAugustin Cavalier /*
828*dba28784SAugustin Cavalier  * Start a section.
829*dba28784SAugustin Cavalier  */
830*dba28784SAugustin Cavalier void
sbuf_start_section(struct sbuf * s,ssize_t * old_lenp)831*dba28784SAugustin Cavalier sbuf_start_section(struct sbuf *s, ssize_t *old_lenp)
832*dba28784SAugustin Cavalier {
833*dba28784SAugustin Cavalier 
834*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
835*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
836*dba28784SAugustin Cavalier 
837*dba28784SAugustin Cavalier 	if (!SBUF_ISSECTION(s)) {
838*dba28784SAugustin Cavalier 		KASSERT(s->s_sect_len == 0,
839*dba28784SAugustin Cavalier 		    ("s_sect_len != 0 when starting a section"));
840*dba28784SAugustin Cavalier 		if (old_lenp != NULL)
841*dba28784SAugustin Cavalier 			*old_lenp = -1;
842*dba28784SAugustin Cavalier 		SBUF_SETFLAG(s, SBUF_INSECTION);
843*dba28784SAugustin Cavalier 	} else {
844*dba28784SAugustin Cavalier 		KASSERT(old_lenp != NULL,
845*dba28784SAugustin Cavalier 		    ("s_sect_len should be saved when starting a subsection"));
846*dba28784SAugustin Cavalier 		*old_lenp = s->s_sect_len;
847*dba28784SAugustin Cavalier 		s->s_sect_len = 0;
848*dba28784SAugustin Cavalier 	}
849*dba28784SAugustin Cavalier }
850*dba28784SAugustin Cavalier 
851*dba28784SAugustin Cavalier /*
852*dba28784SAugustin Cavalier  * End the section padding to the specified length with the specified
853*dba28784SAugustin Cavalier  * character.
854*dba28784SAugustin Cavalier  */
855*dba28784SAugustin Cavalier ssize_t
sbuf_end_section(struct sbuf * s,ssize_t old_len,size_t pad,int c)856*dba28784SAugustin Cavalier sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c)
857*dba28784SAugustin Cavalier {
858*dba28784SAugustin Cavalier 	ssize_t len;
859*dba28784SAugustin Cavalier 
860*dba28784SAugustin Cavalier 	assert_sbuf_integrity(s);
861*dba28784SAugustin Cavalier 	assert_sbuf_state(s, 0);
862*dba28784SAugustin Cavalier 	KASSERT(SBUF_ISSECTION(s),
863*dba28784SAugustin Cavalier 	    ("attempt to end a section when not in a section"));
864*dba28784SAugustin Cavalier 
865*dba28784SAugustin Cavalier 	if (pad > 1) {
866*dba28784SAugustin Cavalier 		len = roundup(s->s_sect_len, pad) - s->s_sect_len;
867*dba28784SAugustin Cavalier 		for (; s->s_error == 0 && len > 0; len--)
868*dba28784SAugustin Cavalier 			sbuf_put_byte(s, c);
869*dba28784SAugustin Cavalier 	}
870*dba28784SAugustin Cavalier 	len = s->s_sect_len;
871*dba28784SAugustin Cavalier 	if (old_len == -1) {
872*dba28784SAugustin Cavalier 		s->s_sect_len = 0;
873*dba28784SAugustin Cavalier 		SBUF_CLEARFLAG(s, SBUF_INSECTION);
874*dba28784SAugustin Cavalier 	} else {
875*dba28784SAugustin Cavalier 		s->s_sect_len += old_len;
876*dba28784SAugustin Cavalier 	}
877*dba28784SAugustin Cavalier 	if (s->s_error != 0)
878*dba28784SAugustin Cavalier 		return (-1);
879*dba28784SAugustin Cavalier 	return (len);
880*dba28784SAugustin Cavalier }
881