xref: /freebsd/sys/kern/subr_sbuf.c (revision a48740b6c50cfe7030c97caf8254ded1b60bea1e)
160ec4130SDag-Erling Smørgrav /*-
260ec4130SDag-Erling Smørgrav  * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav
360ec4130SDag-Erling Smørgrav  * All rights reserved.
460ec4130SDag-Erling Smørgrav  *
560ec4130SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
660ec4130SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
760ec4130SDag-Erling Smørgrav  * are met:
860ec4130SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
960ec4130SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
1060ec4130SDag-Erling Smørgrav  *    in this position and unchanged.
1160ec4130SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
1260ec4130SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
1360ec4130SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
1460ec4130SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
1560ec4130SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
1660ec4130SDag-Erling Smørgrav  *
1760ec4130SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1860ec4130SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1960ec4130SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2060ec4130SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2160ec4130SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2260ec4130SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2360ec4130SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2460ec4130SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2560ec4130SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2660ec4130SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2760ec4130SDag-Erling Smørgrav  *
2860ec4130SDag-Erling Smørgrav  *      $FreeBSD$
2960ec4130SDag-Erling Smørgrav  */
3060ec4130SDag-Erling Smørgrav 
3160ec4130SDag-Erling Smørgrav #include <sys/param.h>
323393f8daSKenneth D. Merry 
333393f8daSKenneth D. Merry #ifdef _KERNEL
345b6db477SDag-Erling Smørgrav #include <sys/ctype.h>
3560ec4130SDag-Erling Smørgrav #include <sys/kernel.h>
3660ec4130SDag-Erling Smørgrav #include <sys/malloc.h>
3760ec4130SDag-Erling Smørgrav #include <sys/systm.h>
385b6db477SDag-Erling Smørgrav #include <sys/uio.h>
3960ec4130SDag-Erling Smørgrav #include <machine/stdarg.h>
403393f8daSKenneth D. Merry #else /* _KERNEL */
415b6db477SDag-Erling Smørgrav #include <ctype.h>
423393f8daSKenneth D. Merry #include <stdarg.h>
439fa416caSJonathan Lemon #include <stdlib.h>
443393f8daSKenneth D. Merry #endif /* _KERNEL */
4560ec4130SDag-Erling Smørgrav 
465b6db477SDag-Erling Smørgrav #include <sys/sbuf.h>
475b6db477SDag-Erling Smørgrav 
483393f8daSKenneth D. Merry #ifdef _KERNEL
4960ec4130SDag-Erling Smørgrav MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
503393f8daSKenneth D. Merry #define SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK)
513393f8daSKenneth D. Merry #define SBFREE(buf)		free(buf, M_SBUF)
523393f8daSKenneth D. Merry #else /* _KERNEL */
533393f8daSKenneth D. Merry #define KASSERT(e, m)
543393f8daSKenneth D. Merry #define SBMALLOC(size)		malloc(size)
553393f8daSKenneth D. Merry #define SBFREE(buf)		free(buf)
563393f8daSKenneth D. Merry #define min(x,y)		MIN(x,y)
573393f8daSKenneth D. Merry #endif /* _KERNEL */
5860ec4130SDag-Erling Smørgrav 
594dc14139SDag-Erling Smørgrav /*
604dc14139SDag-Erling Smørgrav  * Predicates
614dc14139SDag-Erling Smørgrav  */
624dc14139SDag-Erling Smørgrav #define SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
63d6479358SDag-Erling Smørgrav #define SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
644dc14139SDag-Erling Smørgrav #define SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
654dc14139SDag-Erling Smørgrav #define SBUF_HASOVERFLOWED(s)	((s)->s_flags & SBUF_OVERFLOWED)
664dc14139SDag-Erling Smørgrav #define SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
674dc14139SDag-Erling Smørgrav 
684dc14139SDag-Erling Smørgrav /*
694dc14139SDag-Erling Smørgrav  * Set / clear flags
704dc14139SDag-Erling Smørgrav  */
714dc14139SDag-Erling Smørgrav #define SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
724dc14139SDag-Erling Smørgrav #define SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
734dc14139SDag-Erling Smørgrav 
744dc14139SDag-Erling Smørgrav /*
754dc14139SDag-Erling Smørgrav  * Debugging support
764dc14139SDag-Erling Smørgrav  */
773393f8daSKenneth D. Merry #if defined(_KERNEL) && defined(INVARIANTS)
7860ec4130SDag-Erling Smørgrav static void
79cab5b963SDag-Erling Smørgrav _assert_sbuf_integrity(char *fun, struct sbuf *s)
8060ec4130SDag-Erling Smørgrav {
8160ec4130SDag-Erling Smørgrav 	KASSERT(s != NULL,
82cab5b963SDag-Erling Smørgrav 	    ("%s called with a NULL sbuf pointer", fun));
8360ec4130SDag-Erling Smørgrav 	KASSERT(s->s_buf != NULL,
84cab5b963SDag-Erling Smørgrav 	    ("%s called with unitialized or corrupt sbuf", fun));
8560ec4130SDag-Erling Smørgrav 	KASSERT(s->s_len < s->s_size,
8660ec4130SDag-Erling Smørgrav 	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
8760ec4130SDag-Erling Smørgrav }
8860ec4130SDag-Erling Smørgrav 
8960ec4130SDag-Erling Smørgrav static void
90cab5b963SDag-Erling Smørgrav _assert_sbuf_state(char *fun, struct sbuf *s, int state)
9160ec4130SDag-Erling Smørgrav {
9260ec4130SDag-Erling Smørgrav 	KASSERT((s->s_flags & SBUF_FINISHED) == state,
93cab5b963SDag-Erling Smørgrav 	    ("%s called with %sfinished or corrupt sbuf", fun,
9460ec4130SDag-Erling Smørgrav 	    (state ? "un" : "")));
9560ec4130SDag-Erling Smørgrav }
96a48740b6SDavid E. O'Brien #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
97a48740b6SDavid E. O'Brien #define assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
983393f8daSKenneth D. Merry #else /* _KERNEL && INVARIANTS */
9960ec4130SDag-Erling Smørgrav #define assert_sbuf_integrity(s) do { } while (0)
10060ec4130SDag-Erling Smørgrav #define assert_sbuf_state(s, i)	 do { } while (0)
1013393f8daSKenneth D. Merry #endif /* _KERNEL && INVARIANTS */
10260ec4130SDag-Erling Smørgrav 
10360ec4130SDag-Erling Smørgrav /*
10460ec4130SDag-Erling Smørgrav  * Initialize an sbuf.
10560ec4130SDag-Erling Smørgrav  * If buf is non-NULL, it points to a static or already-allocated string
10660ec4130SDag-Erling Smørgrav  * big enough to hold at least length characters.
10760ec4130SDag-Erling Smørgrav  */
108d6479358SDag-Erling Smørgrav struct sbuf *
1094dc14139SDag-Erling Smørgrav sbuf_new(struct sbuf *s, char *buf, int length, int flags)
11060ec4130SDag-Erling Smørgrav {
1114dc14139SDag-Erling Smørgrav 	KASSERT(length >= 0,
1124dc14139SDag-Erling Smørgrav 	    ("attempt to create an sbuf of negative length (%d)", length));
11360ec4130SDag-Erling Smørgrav 	KASSERT(flags == 0,
114a48740b6SDavid E. O'Brien 	    ("%s called with non-zero flags", __func__));
11560ec4130SDag-Erling Smørgrav 
116d6479358SDag-Erling Smørgrav 	if (s == NULL) {
117d6479358SDag-Erling Smørgrav 		s = (struct sbuf *)SBMALLOC(sizeof *s);
118d6479358SDag-Erling Smørgrav 		if (s == NULL)
119d6479358SDag-Erling Smørgrav 			return (NULL);
12060ec4130SDag-Erling Smørgrav 		bzero(s, sizeof *s);
121d6479358SDag-Erling Smørgrav 		SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
122d6479358SDag-Erling Smørgrav 	} else {
123d6479358SDag-Erling Smørgrav 		bzero(s, sizeof *s);
124d6479358SDag-Erling Smørgrav 	}
12560ec4130SDag-Erling Smørgrav 	s->s_size = length;
12660ec4130SDag-Erling Smørgrav 	if (buf) {
12760ec4130SDag-Erling Smørgrav 		s->s_buf = buf;
128d6479358SDag-Erling Smørgrav 		return (s);
12960ec4130SDag-Erling Smørgrav 	}
1303393f8daSKenneth D. Merry 	s->s_buf = (char *)SBMALLOC(s->s_size);
131d6479358SDag-Erling Smørgrav 	if (s->s_buf == NULL) {
132d6479358SDag-Erling Smørgrav 		if (SBUF_ISDYNSTRUCT(s))
133d6479358SDag-Erling Smørgrav 			SBFREE(s);
134d6479358SDag-Erling Smørgrav 		return (NULL);
135d6479358SDag-Erling Smørgrav 	}
13660ec4130SDag-Erling Smørgrav 	SBUF_SETFLAG(s, SBUF_DYNAMIC);
137d6479358SDag-Erling Smørgrav 	return (s);
13860ec4130SDag-Erling Smørgrav }
13960ec4130SDag-Erling Smørgrav 
1405b6db477SDag-Erling Smørgrav #ifdef _KERNEL
1415b6db477SDag-Erling Smørgrav /*
1425b6db477SDag-Erling Smørgrav  * Create an sbuf with uio data
1435b6db477SDag-Erling Smørgrav  */
1445b6db477SDag-Erling Smørgrav struct sbuf *
1455b6db477SDag-Erling Smørgrav sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
1465b6db477SDag-Erling Smørgrav {
1475b6db477SDag-Erling Smørgrav 	KASSERT(uio != NULL,
148a48740b6SDavid E. O'Brien 	    ("%s called with NULL uio pointer", __func__));
1495b6db477SDag-Erling Smørgrav 	KASSERT(error != NULL,
150a48740b6SDavid E. O'Brien 	    ("%s called with NULL error pointer", __func__));
1515b6db477SDag-Erling Smørgrav 
1525b6db477SDag-Erling Smørgrav 	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
1535b6db477SDag-Erling Smørgrav 	if (s == NULL) {
1545b6db477SDag-Erling Smørgrav 		*error = ENOMEM;
1555b6db477SDag-Erling Smørgrav 		return (NULL);
1565b6db477SDag-Erling Smørgrav 	}
1575b6db477SDag-Erling Smørgrav 	*error = uiomove(s->s_buf, uio->uio_resid, uio);
1585b6db477SDag-Erling Smørgrav 	if (*error != 0) {
1595b6db477SDag-Erling Smørgrav 		sbuf_delete(s);
1605b6db477SDag-Erling Smørgrav 		return (NULL);
1615b6db477SDag-Erling Smørgrav 	}
1625b6db477SDag-Erling Smørgrav 	s->s_len = s->s_size - 1;
1635b6db477SDag-Erling Smørgrav 	*error = 0;
1645b6db477SDag-Erling Smørgrav 	return (s);
1655b6db477SDag-Erling Smørgrav }
1665b6db477SDag-Erling Smørgrav #endif
1675b6db477SDag-Erling Smørgrav 
16860ec4130SDag-Erling Smørgrav /*
1694dc14139SDag-Erling Smørgrav  * Clear an sbuf and reset its position
1704dc14139SDag-Erling Smørgrav  */
1714dc14139SDag-Erling Smørgrav void
1724dc14139SDag-Erling Smørgrav sbuf_clear(struct sbuf *s)
1734dc14139SDag-Erling Smørgrav {
1744dc14139SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
1759fa2ef3dSDag-Erling Smørgrav 	/* don't care if it's finished or not */
1764dc14139SDag-Erling Smørgrav 
1774dc14139SDag-Erling Smørgrav 	SBUF_CLEARFLAG(s, SBUF_FINISHED);
1784dc14139SDag-Erling Smørgrav 	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
1794dc14139SDag-Erling Smørgrav 	s->s_len = 0;
1804dc14139SDag-Erling Smørgrav }
1814dc14139SDag-Erling Smørgrav 
1824dc14139SDag-Erling Smørgrav /*
18360ec4130SDag-Erling Smørgrav  * Set the sbuf's position to an arbitrary value
18460ec4130SDag-Erling Smørgrav  */
18560ec4130SDag-Erling Smørgrav int
1864dc14139SDag-Erling Smørgrav sbuf_setpos(struct sbuf *s, int pos)
18760ec4130SDag-Erling Smørgrav {
18860ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
18960ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
19060ec4130SDag-Erling Smørgrav 
19160ec4130SDag-Erling Smørgrav 	KASSERT(pos >= 0,
19260ec4130SDag-Erling Smørgrav 	    ("attempt to seek to a negative position (%d)", pos));
19360ec4130SDag-Erling Smørgrav 	KASSERT(pos < s->s_size,
19460ec4130SDag-Erling Smørgrav 	    ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size));
19560ec4130SDag-Erling Smørgrav 
19660ec4130SDag-Erling Smørgrav 	if (pos < 0 || pos > s->s_len)
19760ec4130SDag-Erling Smørgrav 		return (-1);
19860ec4130SDag-Erling Smørgrav 	s->s_len = pos;
19960ec4130SDag-Erling Smørgrav 	return (0);
20060ec4130SDag-Erling Smørgrav }
20160ec4130SDag-Erling Smørgrav 
20260ec4130SDag-Erling Smørgrav /*
203b0def2b5SDag-Erling Smørgrav  * Append a byte string to an sbuf.
204b0def2b5SDag-Erling Smørgrav  */
205b0def2b5SDag-Erling Smørgrav int
206b0def2b5SDag-Erling Smørgrav sbuf_bcat(struct sbuf *s, const char *str, size_t len)
207b0def2b5SDag-Erling Smørgrav {
208b0def2b5SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
209b0def2b5SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
210b0def2b5SDag-Erling Smørgrav 
211b0def2b5SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
212b0def2b5SDag-Erling Smørgrav 		return (-1);
213b0def2b5SDag-Erling Smørgrav 
214b0def2b5SDag-Erling Smørgrav 	while (len-- && SBUF_HASROOM(s))
215b0def2b5SDag-Erling Smørgrav 		s->s_buf[s->s_len++] = *str++;
216b0def2b5SDag-Erling Smørgrav 	if (len) {
217b0def2b5SDag-Erling Smørgrav 		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
218b0def2b5SDag-Erling Smørgrav 		return (-1);
219b0def2b5SDag-Erling Smørgrav 	}
220b0def2b5SDag-Erling Smørgrav 	return (0);
221b0def2b5SDag-Erling Smørgrav }
222b0def2b5SDag-Erling Smørgrav 
223b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL
224b0def2b5SDag-Erling Smørgrav /*
225b0def2b5SDag-Erling Smørgrav  * Copy a byte string from userland into an sbuf.
226b0def2b5SDag-Erling Smørgrav  */
227b0def2b5SDag-Erling Smørgrav int
228b0def2b5SDag-Erling Smørgrav sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
229b0def2b5SDag-Erling Smørgrav {
230b0def2b5SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
231b0def2b5SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
232b0def2b5SDag-Erling Smørgrav 
233b0def2b5SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
234b0def2b5SDag-Erling Smørgrav 		return (-1);
235b0def2b5SDag-Erling Smørgrav 
236b0def2b5SDag-Erling Smørgrav 	if (len == 0)
237b0def2b5SDag-Erling Smørgrav 		return (0);
238b0def2b5SDag-Erling Smørgrav 	if (len > (s->s_size - s->s_len - 1))
239b0def2b5SDag-Erling Smørgrav 		len = s->s_size - s->s_len - 1;
240e3b37322SDag-Erling Smørgrav 	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
241e3b37322SDag-Erling Smørgrav 		return (-1);
242fe463496SDag-Erling Smørgrav 	s->s_len += len;
243b0def2b5SDag-Erling Smørgrav 
244b0def2b5SDag-Erling Smørgrav 	return (0);
245b0def2b5SDag-Erling Smørgrav }
246b0def2b5SDag-Erling Smørgrav #endif
247b0def2b5SDag-Erling Smørgrav 
248b0def2b5SDag-Erling Smørgrav /*
249b0def2b5SDag-Erling Smørgrav  * Copy a byte string into an sbuf.
250b0def2b5SDag-Erling Smørgrav  */
251b0def2b5SDag-Erling Smørgrav int
252b0def2b5SDag-Erling Smørgrav sbuf_bcpy(struct sbuf *s, const char *str, size_t len)
253b0def2b5SDag-Erling Smørgrav {
254b0def2b5SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
255b0def2b5SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
256b0def2b5SDag-Erling Smørgrav 
257b0def2b5SDag-Erling Smørgrav 	sbuf_clear(s);
258b0def2b5SDag-Erling Smørgrav 	return (sbuf_bcat(s, str, len));
259b0def2b5SDag-Erling Smørgrav }
260b0def2b5SDag-Erling Smørgrav 
261b0def2b5SDag-Erling Smørgrav /*
26260ec4130SDag-Erling Smørgrav  * Append a string to an sbuf.
26360ec4130SDag-Erling Smørgrav  */
26460ec4130SDag-Erling Smørgrav int
2653393f8daSKenneth D. Merry sbuf_cat(struct sbuf *s, const char *str)
26660ec4130SDag-Erling Smørgrav {
26760ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
26860ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
26960ec4130SDag-Erling Smørgrav 
27060ec4130SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
27160ec4130SDag-Erling Smørgrav 		return (-1);
27260ec4130SDag-Erling Smørgrav 
27360ec4130SDag-Erling Smørgrav 	while (*str && SBUF_HASROOM(s))
27460ec4130SDag-Erling Smørgrav 		s->s_buf[s->s_len++] = *str++;
27560ec4130SDag-Erling Smørgrav 	if (*str) {
27660ec4130SDag-Erling Smørgrav 		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
27760ec4130SDag-Erling Smørgrav 		return (-1);
27860ec4130SDag-Erling Smørgrav 	}
27960ec4130SDag-Erling Smørgrav 	return (0);
28060ec4130SDag-Erling Smørgrav }
28160ec4130SDag-Erling Smørgrav 
282b0def2b5SDag-Erling Smørgrav #ifdef _KERNEL
283b0def2b5SDag-Erling Smørgrav /*
284b0def2b5SDag-Erling Smørgrav  * Copy a string from userland into an sbuf.
285b0def2b5SDag-Erling Smørgrav  */
286b0def2b5SDag-Erling Smørgrav int
287b0def2b5SDag-Erling Smørgrav sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
288b0def2b5SDag-Erling Smørgrav {
289b0def2b5SDag-Erling Smørgrav 	size_t done;
290b0def2b5SDag-Erling Smørgrav 
291b0def2b5SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
292b0def2b5SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
293b0def2b5SDag-Erling Smørgrav 
294b0def2b5SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
295b0def2b5SDag-Erling Smørgrav 		return (-1);
296b0def2b5SDag-Erling Smørgrav 
297b0def2b5SDag-Erling Smørgrav 	if (len == 0 || len > (s->s_size - s->s_len - 1))
298b0def2b5SDag-Erling Smørgrav 		len = s->s_size - s->s_len - 1;
299b0def2b5SDag-Erling Smørgrav 	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
300b0def2b5SDag-Erling Smørgrav 	case ENAMETOOLONG:
301b0def2b5SDag-Erling Smørgrav 		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
302b0def2b5SDag-Erling Smørgrav 		/* fall through */
303b0def2b5SDag-Erling Smørgrav 	case 0:
304b0def2b5SDag-Erling Smørgrav 		s->s_len += done - 1;
305b0def2b5SDag-Erling Smørgrav 		break;
306b0def2b5SDag-Erling Smørgrav 	default:
307b0def2b5SDag-Erling Smørgrav 		return (-1);	/* XXX */
308b0def2b5SDag-Erling Smørgrav 	}
309b0def2b5SDag-Erling Smørgrav 
310b0def2b5SDag-Erling Smørgrav 	return (0);
311b0def2b5SDag-Erling Smørgrav }
312b0def2b5SDag-Erling Smørgrav #endif
313b0def2b5SDag-Erling Smørgrav 
31460ec4130SDag-Erling Smørgrav /*
31560ec4130SDag-Erling Smørgrav  * Copy a string into an sbuf.
31660ec4130SDag-Erling Smørgrav  */
31760ec4130SDag-Erling Smørgrav int
3183393f8daSKenneth D. Merry sbuf_cpy(struct sbuf *s, const char *str)
31960ec4130SDag-Erling Smørgrav {
32060ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
32160ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
32260ec4130SDag-Erling Smørgrav 
3234dc14139SDag-Erling Smørgrav 	sbuf_clear(s);
32460ec4130SDag-Erling Smørgrav 	return (sbuf_cat(s, str));
32560ec4130SDag-Erling Smørgrav }
32660ec4130SDag-Erling Smørgrav 
32760ec4130SDag-Erling Smørgrav /*
32860ec4130SDag-Erling Smørgrav  * Format the given arguments and append the resulting string to an sbuf.
32960ec4130SDag-Erling Smørgrav  */
33060ec4130SDag-Erling Smørgrav int
3312687c874SDag-Erling Smørgrav sbuf_printf(struct sbuf *s, const char *fmt, ...)
33260ec4130SDag-Erling Smørgrav {
33360ec4130SDag-Erling Smørgrav 	va_list ap;
3344dc14139SDag-Erling Smørgrav 	int len;
33560ec4130SDag-Erling Smørgrav 
33660ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
33760ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
33860ec4130SDag-Erling Smørgrav 
33960ec4130SDag-Erling Smørgrav 	KASSERT(fmt != NULL,
340a48740b6SDavid E. O'Brien 	    ("%s called with a NULL format string", __func__));
34160ec4130SDag-Erling Smørgrav 
34260ec4130SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
34360ec4130SDag-Erling Smørgrav 		return (-1);
34460ec4130SDag-Erling Smørgrav 
34560ec4130SDag-Erling Smørgrav 	va_start(ap, fmt);
3463393f8daSKenneth D. Merry 	len = vsnprintf(&s->s_buf[s->s_len], s->s_size - s->s_len, fmt, ap);
34760ec4130SDag-Erling Smørgrav 	va_end(ap);
34860ec4130SDag-Erling Smørgrav 
3493393f8daSKenneth D. Merry 	/*
3503393f8daSKenneth D. Merry 	 * s->s_len is the length of the string, without the terminating nul.
3513393f8daSKenneth D. Merry 	 * When updating s->s_len, we must subtract 1 from the length that
3523393f8daSKenneth D. Merry 	 * we passed into vsnprintf() because that length includes the
3533393f8daSKenneth D. Merry 	 * terminating nul.
3543393f8daSKenneth D. Merry 	 *
3553393f8daSKenneth D. Merry 	 * vsnprintf() returns the amount that would have been copied,
3563393f8daSKenneth D. Merry 	 * given sufficient space, hence the min() calculation below.
3573393f8daSKenneth D. Merry 	 */
3583393f8daSKenneth D. Merry 	s->s_len += min(len, s->s_size - s->s_len - 1);
3593393f8daSKenneth D. Merry 	if (!SBUF_HASROOM(s))
3603393f8daSKenneth D. Merry 		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
3613393f8daSKenneth D. Merry 
36260ec4130SDag-Erling Smørgrav 	KASSERT(s->s_len < s->s_size,
36360ec4130SDag-Erling Smørgrav 	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
36460ec4130SDag-Erling Smørgrav 
36560ec4130SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
36660ec4130SDag-Erling Smørgrav 		return (-1);
36760ec4130SDag-Erling Smørgrav 	return (0);
36860ec4130SDag-Erling Smørgrav }
36960ec4130SDag-Erling Smørgrav 
37060ec4130SDag-Erling Smørgrav /*
37160ec4130SDag-Erling Smørgrav  * Append a character to an sbuf.
37260ec4130SDag-Erling Smørgrav  */
37360ec4130SDag-Erling Smørgrav int
37460ec4130SDag-Erling Smørgrav sbuf_putc(struct sbuf *s, int c)
37560ec4130SDag-Erling Smørgrav {
37660ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
37760ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
37860ec4130SDag-Erling Smørgrav 
37960ec4130SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
38060ec4130SDag-Erling Smørgrav 		return (-1);
38160ec4130SDag-Erling Smørgrav 
38260ec4130SDag-Erling Smørgrav 	if (!SBUF_HASROOM(s)) {
38360ec4130SDag-Erling Smørgrav 		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
38460ec4130SDag-Erling Smørgrav 		return (-1);
38560ec4130SDag-Erling Smørgrav 	}
386cab5b963SDag-Erling Smørgrav 	if (c != '\0')
38760ec4130SDag-Erling Smørgrav 	    s->s_buf[s->s_len++] = c;
38860ec4130SDag-Erling Smørgrav 	return (0);
38960ec4130SDag-Erling Smørgrav }
39060ec4130SDag-Erling Smørgrav 
39160ec4130SDag-Erling Smørgrav /*
3925b6db477SDag-Erling Smørgrav  * Trim whitespace characters from an sbuf.
3935b6db477SDag-Erling Smørgrav  */
3945b6db477SDag-Erling Smørgrav int
3955b6db477SDag-Erling Smørgrav sbuf_trim(struct sbuf *s)
3965b6db477SDag-Erling Smørgrav {
3975b6db477SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
3985b6db477SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
3995b6db477SDag-Erling Smørgrav 
4005b6db477SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
4015b6db477SDag-Erling Smørgrav 		return (-1);
4025b6db477SDag-Erling Smørgrav 
4035b6db477SDag-Erling Smørgrav 	while (s->s_len && isspace(s->s_buf[s->s_len-1]))
4045b6db477SDag-Erling Smørgrav 		--s->s_len;
4055b6db477SDag-Erling Smørgrav 
4065b6db477SDag-Erling Smørgrav 	return (0);
4075b6db477SDag-Erling Smørgrav }
4085b6db477SDag-Erling Smørgrav 
4095b6db477SDag-Erling Smørgrav /*
4104dc14139SDag-Erling Smørgrav  * Check if an sbuf overflowed
41160ec4130SDag-Erling Smørgrav  */
41260ec4130SDag-Erling Smørgrav int
4134dc14139SDag-Erling Smørgrav sbuf_overflowed(struct sbuf *s)
4144dc14139SDag-Erling Smørgrav {
4154dc14139SDag-Erling Smørgrav     return SBUF_HASOVERFLOWED(s);
4164dc14139SDag-Erling Smørgrav }
4174dc14139SDag-Erling Smørgrav 
4184dc14139SDag-Erling Smørgrav /*
4194dc14139SDag-Erling Smørgrav  * Finish off an sbuf.
4204dc14139SDag-Erling Smørgrav  */
4214dc14139SDag-Erling Smørgrav void
42260ec4130SDag-Erling Smørgrav sbuf_finish(struct sbuf *s)
42360ec4130SDag-Erling Smørgrav {
42460ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
42560ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, 0);
42660ec4130SDag-Erling Smørgrav 
427cab5b963SDag-Erling Smørgrav 	s->s_buf[s->s_len] = '\0';
4284dc14139SDag-Erling Smørgrav 	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
42960ec4130SDag-Erling Smørgrav 	SBUF_SETFLAG(s, SBUF_FINISHED);
43060ec4130SDag-Erling Smørgrav }
43160ec4130SDag-Erling Smørgrav 
43260ec4130SDag-Erling Smørgrav /*
43360ec4130SDag-Erling Smørgrav  * Return a pointer to the sbuf data.
43460ec4130SDag-Erling Smørgrav  */
43560ec4130SDag-Erling Smørgrav char *
43660ec4130SDag-Erling Smørgrav sbuf_data(struct sbuf *s)
43760ec4130SDag-Erling Smørgrav {
43860ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
43960ec4130SDag-Erling Smørgrav 	assert_sbuf_state(s, SBUF_FINISHED);
44060ec4130SDag-Erling Smørgrav 
44160ec4130SDag-Erling Smørgrav 	return s->s_buf;
44260ec4130SDag-Erling Smørgrav }
44360ec4130SDag-Erling Smørgrav 
44460ec4130SDag-Erling Smørgrav /*
44560ec4130SDag-Erling Smørgrav  * Return the length of the sbuf data.
44660ec4130SDag-Erling Smørgrav  */
4474dc14139SDag-Erling Smørgrav int
44860ec4130SDag-Erling Smørgrav sbuf_len(struct sbuf *s)
44960ec4130SDag-Erling Smørgrav {
45060ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
4519fa2ef3dSDag-Erling Smørgrav 	/* don't care if it's finished or not */
45260ec4130SDag-Erling Smørgrav 
45360ec4130SDag-Erling Smørgrav 	if (SBUF_HASOVERFLOWED(s))
4544dc14139SDag-Erling Smørgrav 		return (-1);
45560ec4130SDag-Erling Smørgrav 	return s->s_len;
45660ec4130SDag-Erling Smørgrav }
45760ec4130SDag-Erling Smørgrav 
45860ec4130SDag-Erling Smørgrav /*
45960ec4130SDag-Erling Smørgrav  * Clear an sbuf, free its buffer if necessary.
46060ec4130SDag-Erling Smørgrav  */
46160ec4130SDag-Erling Smørgrav void
46260ec4130SDag-Erling Smørgrav sbuf_delete(struct sbuf *s)
46360ec4130SDag-Erling Smørgrav {
46460ec4130SDag-Erling Smørgrav 	assert_sbuf_integrity(s);
46560ec4130SDag-Erling Smørgrav 	/* don't care if it's finished or not */
46660ec4130SDag-Erling Smørgrav 
46760ec4130SDag-Erling Smørgrav 	if (SBUF_ISDYNAMIC(s))
4683393f8daSKenneth D. Merry 		SBFREE(s->s_buf);
46960ec4130SDag-Erling Smørgrav 	bzero(s, sizeof *s);
470d6479358SDag-Erling Smørgrav 	if (SBUF_ISDYNSTRUCT(s))
471d6479358SDag-Erling Smørgrav 		SBFREE(s);
47260ec4130SDag-Erling Smørgrav }
473