subr_sbuf.c revision 88219
169990Sdes/*-
269990Sdes * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav
369990Sdes * All rights reserved.
469990Sdes *
569990Sdes * Redistribution and use in source and binary forms, with or without
669990Sdes * modification, are permitted provided that the following conditions
769990Sdes * are met:
869990Sdes * 1. Redistributions of source code must retain the above copyright
969990Sdes *    notice, this list of conditions and the following disclaimer
1069990Sdes *    in this position and unchanged.
1169990Sdes * 2. Redistributions in binary form must reproduce the above copyright
1269990Sdes *    notice, this list of conditions and the following disclaimer in the
1369990Sdes *    documentation and/or other materials provided with the distribution.
1469990Sdes * 3. The name of the author may not be used to endorse or promote products
1569990Sdes *    derived from this software without specific prior written permission.
1669990Sdes *
1769990Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1869990Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1969990Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2069990Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2169990Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2269990Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2369990Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2469990Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2569990Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2669990Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2769990Sdes *
2869990Sdes *      $FreeBSD: head/sys/kern/subr_sbuf.c 88219 2001-12-19 19:04:57Z dillon $
2969990Sdes */
3069990Sdes
3169990Sdes#include <sys/param.h>
3274840Sken
3374840Sken#ifdef _KERNEL
3484097Sdes#include <sys/ctype.h>
3569990Sdes#include <sys/kernel.h>
3669990Sdes#include <sys/malloc.h>
3769990Sdes#include <sys/systm.h>
3884097Sdes#include <sys/uio.h>
3969990Sdes#include <machine/stdarg.h>
4074840Sken#else /* _KERNEL */
4184097Sdes#include <ctype.h>
4274840Sken#include <stdarg.h>
4378340Sjlemon#include <stdlib.h>
4474840Sken#endif /* _KERNEL */
4569990Sdes
4684097Sdes#include <sys/sbuf.h>
4784097Sdes
4874840Sken#ifdef _KERNEL
4969990SdesMALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
5074840Sken#define SBMALLOC(size)		malloc(size, M_SBUF, M_WAITOK)
5174840Sken#define SBFREE(buf)		free(buf, M_SBUF)
5274840Sken#else /* _KERNEL */
5374840Sken#define KASSERT(e, m)
5474840Sken#define SBMALLOC(size)		malloc(size)
5574840Sken#define SBFREE(buf)		free(buf)
5674840Sken#define min(x,y)		MIN(x,y)
5774840Sken#endif /* _KERNEL */
5869990Sdes
5971721Sdes/*
6071721Sdes * Predicates
6171721Sdes */
6271721Sdes#define SBUF_ISDYNAMIC(s)	((s)->s_flags & SBUF_DYNAMIC)
6377989Sdes#define SBUF_ISDYNSTRUCT(s)	((s)->s_flags & SBUF_DYNSTRUCT)
6471721Sdes#define SBUF_ISFINISHED(s)	((s)->s_flags & SBUF_FINISHED)
6571721Sdes#define SBUF_HASOVERFLOWED(s)	((s)->s_flags & SBUF_OVERFLOWED)
6671721Sdes#define SBUF_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
6771721Sdes
6871721Sdes/*
6971721Sdes * Set / clear flags
7071721Sdes */
7171721Sdes#define SBUF_SETFLAG(s, f)	do { (s)->s_flags |= (f); } while (0)
7271721Sdes#define SBUF_CLEARFLAG(s, f)	do { (s)->s_flags &= ~(f); } while (0)
7371721Sdes
7471721Sdes/*
7571721Sdes * Debugging support
7671721Sdes */
7774840Sken#if defined(_KERNEL) && defined(INVARIANTS)
7869990Sdesstatic void
7973891Sdes_assert_sbuf_integrity(char *fun, struct sbuf *s)
8069990Sdes{
8169990Sdes	KASSERT(s != NULL,
8273891Sdes	    ("%s called with a NULL sbuf pointer", fun));
8369990Sdes	KASSERT(s->s_buf != NULL,
8473891Sdes	    ("%s called with unitialized or corrupt sbuf", fun));
8569990Sdes	KASSERT(s->s_len < s->s_size,
8669990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
8769990Sdes}
8869990Sdes
8969990Sdesstatic void
9073891Sdes_assert_sbuf_state(char *fun, struct sbuf *s, int state)
9169990Sdes{
9269990Sdes	KASSERT((s->s_flags & SBUF_FINISHED) == state,
9373891Sdes	    ("%s called with %sfinished or corrupt sbuf", fun,
9469990Sdes	    (state ? "un" : "")));
9569990Sdes}
9687594Sobrien#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
9787594Sobrien#define assert_sbuf_state(s, i)	 _assert_sbuf_state(__func__, (s), (i))
9874840Sken#else /* _KERNEL && INVARIANTS */
9969990Sdes#define assert_sbuf_integrity(s) do { } while (0)
10069990Sdes#define assert_sbuf_state(s, i)	 do { } while (0)
10174840Sken#endif /* _KERNEL && INVARIANTS */
10269990Sdes
10369990Sdes/*
10469990Sdes * Initialize an sbuf.
10569990Sdes * If buf is non-NULL, it points to a static or already-allocated string
10669990Sdes * big enough to hold at least length characters.
10769990Sdes */
10877989Sdesstruct sbuf *
10971721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags)
11069990Sdes{
11171721Sdes	KASSERT(length >= 0,
11271721Sdes	    ("attempt to create an sbuf of negative length (%d)", length));
11369990Sdes	KASSERT(flags == 0,
11487594Sobrien	    ("%s called with non-zero flags", __func__));
11569990Sdes
11677989Sdes	if (s == NULL) {
11777989Sdes		s = (struct sbuf *)SBMALLOC(sizeof *s);
11877989Sdes		if (s == NULL)
11977989Sdes			return (NULL);
12077989Sdes		bzero(s, sizeof *s);
12177989Sdes		SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
12277989Sdes	} else {
12377989Sdes		bzero(s, sizeof *s);
12477989Sdes	}
12569990Sdes	s->s_size = length;
12669990Sdes	if (buf) {
12769990Sdes		s->s_buf = buf;
12877989Sdes		return (s);
12969990Sdes	}
13074840Sken	s->s_buf = (char *)SBMALLOC(s->s_size);
13177989Sdes	if (s->s_buf == NULL) {
13277989Sdes		if (SBUF_ISDYNSTRUCT(s))
13377989Sdes			SBFREE(s);
13477989Sdes		return (NULL);
13577989Sdes	}
13669990Sdes	SBUF_SETFLAG(s, SBUF_DYNAMIC);
13777989Sdes	return (s);
13869990Sdes}
13969990Sdes
14084097Sdes#ifdef _KERNEL
14169990Sdes/*
14284097Sdes * Create an sbuf with uio data
14384097Sdes */
14484097Sdesstruct sbuf *
14584097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
14684097Sdes{
14784097Sdes	KASSERT(uio != NULL,
14887594Sobrien	    ("%s called with NULL uio pointer", __func__));
14984097Sdes	KASSERT(error != NULL,
15087594Sobrien	    ("%s called with NULL error pointer", __func__));
15184097Sdes
15284097Sdes	s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
15384097Sdes	if (s == NULL) {
15484097Sdes		*error = ENOMEM;
15584097Sdes		return (NULL);
15684097Sdes	}
15784097Sdes	*error = uiomove(s->s_buf, uio->uio_resid, uio);
15884097Sdes	if (*error != 0) {
15984097Sdes		sbuf_delete(s);
16084097Sdes		return (NULL);
16184097Sdes	}
16284097Sdes	s->s_len = s->s_size - 1;
16384097Sdes	*error = 0;
16484097Sdes	return (s);
16584097Sdes}
16684097Sdes#endif
16784097Sdes
16884097Sdes/*
16971721Sdes * Clear an sbuf and reset its position
17071721Sdes */
17171721Sdesvoid
17271721Sdessbuf_clear(struct sbuf *s)
17371721Sdes{
17471721Sdes	assert_sbuf_integrity(s);
17571724Sdes	/* don't care if it's finished or not */
17671721Sdes
17771721Sdes	SBUF_CLEARFLAG(s, SBUF_FINISHED);
17871721Sdes	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
17971721Sdes	s->s_len = 0;
18071721Sdes}
18171721Sdes
18271721Sdes/*
18369990Sdes * Set the sbuf's position to an arbitrary value
18469990Sdes */
18569990Sdesint
18671721Sdessbuf_setpos(struct sbuf *s, int pos)
18769990Sdes{
18869990Sdes	assert_sbuf_integrity(s);
18969990Sdes	assert_sbuf_state(s, 0);
19069990Sdes
19169990Sdes	KASSERT(pos >= 0,
19269990Sdes	    ("attempt to seek to a negative position (%d)", pos));
19369990Sdes	KASSERT(pos < s->s_size,
19469990Sdes	    ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size));
19569990Sdes
19669990Sdes	if (pos < 0 || pos > s->s_len)
19769990Sdes		return (-1);
19869990Sdes	s->s_len = pos;
19969990Sdes	return (0);
20069990Sdes}
20169990Sdes
20269990Sdes/*
20378077Sdes * Append a byte string to an sbuf.
20478077Sdes */
20578077Sdesint
20678077Sdessbuf_bcat(struct sbuf *s, const char *str, size_t len)
20778077Sdes{
20878077Sdes	assert_sbuf_integrity(s);
20978077Sdes	assert_sbuf_state(s, 0);
21078077Sdes
21178077Sdes	if (SBUF_HASOVERFLOWED(s))
21278077Sdes		return (-1);
21378077Sdes
21478077Sdes	while (len-- && SBUF_HASROOM(s))
21578077Sdes		s->s_buf[s->s_len++] = *str++;
21678077Sdes	if (len) {
21778077Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
21878077Sdes		return (-1);
21978077Sdes	}
22078077Sdes	return (0);
22178077Sdes}
22278077Sdes
22378077Sdes#ifdef _KERNEL
22478077Sdes/*
22578077Sdes * Copy a byte string from userland into an sbuf.
22678077Sdes */
22778077Sdesint
22878077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
22978077Sdes{
23078077Sdes	assert_sbuf_integrity(s);
23178077Sdes	assert_sbuf_state(s, 0);
23278077Sdes
23378077Sdes	if (SBUF_HASOVERFLOWED(s))
23478077Sdes		return (-1);
23578077Sdes
23678077Sdes	if (len == 0)
23778077Sdes		return (0);
23878077Sdes	if (len > (s->s_size - s->s_len - 1))
23978077Sdes		len = s->s_size - s->s_len - 1;
24078092Sdes	if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
24178092Sdes		return (-1);
24278095Sdes	s->s_len += len;
24378077Sdes
24478077Sdes	return (0);
24578077Sdes}
24678077Sdes#endif
24778077Sdes
24878077Sdes/*
24978077Sdes * Copy a byte string into an sbuf.
25078077Sdes */
25178077Sdesint
25278077Sdessbuf_bcpy(struct sbuf *s, const char *str, size_t len)
25378077Sdes{
25478077Sdes	assert_sbuf_integrity(s);
25578077Sdes	assert_sbuf_state(s, 0);
25678077Sdes
25778077Sdes	sbuf_clear(s);
25878077Sdes	return (sbuf_bcat(s, str, len));
25978077Sdes}
26078077Sdes
26178077Sdes/*
26269990Sdes * Append a string to an sbuf.
26369990Sdes */
26469990Sdesint
26574840Skensbuf_cat(struct sbuf *s, const char *str)
26669990Sdes{
26769990Sdes	assert_sbuf_integrity(s);
26869990Sdes	assert_sbuf_state(s, 0);
26969990Sdes
27069990Sdes	if (SBUF_HASOVERFLOWED(s))
27169990Sdes		return (-1);
27269990Sdes
27369990Sdes	while (*str && SBUF_HASROOM(s))
27469990Sdes		s->s_buf[s->s_len++] = *str++;
27569990Sdes	if (*str) {
27669990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
27769990Sdes		return (-1);
27869990Sdes	}
27969990Sdes	return (0);
28069990Sdes}
28169990Sdes
28278077Sdes#ifdef _KERNEL
28369990Sdes/*
28478077Sdes * Copy a string from userland into an sbuf.
28578077Sdes */
28678077Sdesint
28778077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
28878077Sdes{
28978077Sdes	size_t done;
29078077Sdes
29178077Sdes	assert_sbuf_integrity(s);
29278077Sdes	assert_sbuf_state(s, 0);
29378077Sdes
29478077Sdes	if (SBUF_HASOVERFLOWED(s))
29578077Sdes		return (-1);
29678077Sdes
29778077Sdes	if (len == 0 || len > (s->s_size - s->s_len - 1))
29878077Sdes		len = s->s_size - s->s_len - 1;
29978077Sdes	switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
30078077Sdes	case ENAMETOOLONG:
30178077Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
30278077Sdes		/* fall through */
30378077Sdes	case 0:
30478077Sdes		s->s_len += done - 1;
30578077Sdes		break;
30678077Sdes	default:
30778077Sdes		return (-1);	/* XXX */
30878077Sdes	}
30978077Sdes
31078077Sdes	return (0);
31178077Sdes}
31278077Sdes#endif
31378077Sdes
31478077Sdes/*
31569990Sdes * Copy a string into an sbuf.
31669990Sdes */
31769990Sdesint
31874840Skensbuf_cpy(struct sbuf *s, const char *str)
31969990Sdes{
32069990Sdes	assert_sbuf_integrity(s);
32169990Sdes	assert_sbuf_state(s, 0);
32269990Sdes
32371721Sdes	sbuf_clear(s);
32469990Sdes	return (sbuf_cat(s, str));
32569990Sdes}
32669990Sdes
32769990Sdes/*
32869990Sdes * Format the given arguments and append the resulting string to an sbuf.
32969990Sdes */
33069990Sdesint
33179162Sdessbuf_printf(struct sbuf *s, const char *fmt, ...)
33269990Sdes{
33369990Sdes	va_list ap;
33471721Sdes	int len;
33569990Sdes
33669990Sdes	assert_sbuf_integrity(s);
33769990Sdes	assert_sbuf_state(s, 0);
33869990Sdes
33969990Sdes	KASSERT(fmt != NULL,
34087594Sobrien	    ("%s called with a NULL format string", __func__));
34169990Sdes
34269990Sdes	if (SBUF_HASOVERFLOWED(s))
34369990Sdes		return (-1);
34469990Sdes
34569990Sdes	va_start(ap, fmt);
34674840Sken	len = vsnprintf(&s->s_buf[s->s_len], s->s_size - s->s_len, fmt, ap);
34769990Sdes	va_end(ap);
34869990Sdes
34974840Sken	/*
35074840Sken	 * s->s_len is the length of the string, without the terminating nul.
35174840Sken	 * When updating s->s_len, we must subtract 1 from the length that
35274840Sken	 * we passed into vsnprintf() because that length includes the
35374840Sken	 * terminating nul.
35474840Sken	 *
35574840Sken	 * vsnprintf() returns the amount that would have been copied,
35674840Sken	 * given sufficient space, hence the min() calculation below.
35774840Sken	 */
35874840Sken	s->s_len += min(len, s->s_size - s->s_len - 1);
35974840Sken	if (!SBUF_HASROOM(s))
36074840Sken		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
36174840Sken
36269990Sdes	KASSERT(s->s_len < s->s_size,
36369990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
36469990Sdes
36569990Sdes	if (SBUF_HASOVERFLOWED(s))
36669990Sdes		return (-1);
36769990Sdes	return (0);
36869990Sdes}
36969990Sdes
37069990Sdes/*
37169990Sdes * Append a character to an sbuf.
37269990Sdes */
37369990Sdesint
37469990Sdessbuf_putc(struct sbuf *s, int c)
37569990Sdes{
37669990Sdes	assert_sbuf_integrity(s);
37769990Sdes	assert_sbuf_state(s, 0);
37869990Sdes
37969990Sdes	if (SBUF_HASOVERFLOWED(s))
38069990Sdes		return (-1);
38169990Sdes
38269990Sdes	if (!SBUF_HASROOM(s)) {
38369990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
38469990Sdes		return (-1);
38569990Sdes	}
38673891Sdes	if (c != '\0')
38773891Sdes	    s->s_buf[s->s_len++] = c;
38869990Sdes	return (0);
38969990Sdes}
39069990Sdes
39169990Sdes/*
39284097Sdes * Trim whitespace characters from an sbuf.
39384097Sdes */
39484097Sdesint
39584097Sdessbuf_trim(struct sbuf *s)
39684097Sdes{
39784097Sdes	assert_sbuf_integrity(s);
39884097Sdes	assert_sbuf_state(s, 0);
39984097Sdes
40084097Sdes	if (SBUF_HASOVERFLOWED(s))
40184097Sdes		return (-1);
40284097Sdes
40384097Sdes	while (s->s_len && isspace(s->s_buf[s->s_len-1]))
40484097Sdes		--s->s_len;
40584097Sdes
40684097Sdes	return (0);
40784097Sdes}
40884097Sdes
40984097Sdes/*
41071721Sdes * Check if an sbuf overflowed
41171721Sdes */
41271721Sdesint
41371721Sdessbuf_overflowed(struct sbuf *s)
41471721Sdes{
41571721Sdes    return SBUF_HASOVERFLOWED(s);
41671721Sdes}
41771721Sdes
41871721Sdes/*
41969990Sdes * Finish off an sbuf.
42069990Sdes */
42171721Sdesvoid
42269990Sdessbuf_finish(struct sbuf *s)
42369990Sdes{
42469990Sdes	assert_sbuf_integrity(s);
42569990Sdes	assert_sbuf_state(s, 0);
42669990Sdes
42773891Sdes	s->s_buf[s->s_len] = '\0';
42871721Sdes	SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
42969990Sdes	SBUF_SETFLAG(s, SBUF_FINISHED);
43069990Sdes}
43169990Sdes
43269990Sdes/*
43369990Sdes * Return a pointer to the sbuf data.
43469990Sdes */
43569990Sdeschar *
43669990Sdessbuf_data(struct sbuf *s)
43769990Sdes{
43869990Sdes	assert_sbuf_integrity(s);
43969990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
44069990Sdes
44169990Sdes	return s->s_buf;
44269990Sdes}
44369990Sdes
44469990Sdes/*
44569990Sdes * Return the length of the sbuf data.
44669990Sdes */
44771721Sdesint
44869990Sdessbuf_len(struct sbuf *s)
44969990Sdes{
45069990Sdes	assert_sbuf_integrity(s);
45171724Sdes	/* don't care if it's finished or not */
45269990Sdes
45369990Sdes	if (SBUF_HASOVERFLOWED(s))
45471721Sdes		return (-1);
45569990Sdes	return s->s_len;
45669990Sdes}
45769990Sdes
45869990Sdes/*
45969990Sdes * Clear an sbuf, free its buffer if necessary.
46069990Sdes */
46169990Sdesvoid
46269990Sdessbuf_delete(struct sbuf *s)
46369990Sdes{
46488219Sdillon	int isdyn;
46588219Sdillon
46669990Sdes	assert_sbuf_integrity(s);
46769990Sdes	/* don't care if it's finished or not */
46869990Sdes
46969990Sdes	if (SBUF_ISDYNAMIC(s))
47074840Sken		SBFREE(s->s_buf);
47188219Sdillon	isdyn = SBUF_ISDYNSTRUCT(s);
47269990Sdes	bzero(s, sizeof *s);
47388219Sdillon	if (isdyn)
47477989Sdes		SBFREE(s);
47569990Sdes}
476