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