subr_sbuf.c revision 69990
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 69990 2000-12-13 19:51:07Z des $
2969990Sdes */
3069990Sdes
3169990Sdes#include <sys/param.h>
3269990Sdes#include <sys/kernel.h>
3369990Sdes#include <sys/malloc.h>
3469990Sdes#include <sys/sbuf.h>
3569990Sdes#include <sys/systm.h>
3669990Sdes
3769990Sdes#include <machine/stdarg.h>
3869990Sdes
3969990SdesMALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
4069990Sdes
4169990Sdes#ifdef INVARIANTS
4269990Sdesstatic void
4369990Sdesassert_sbuf_integrity(struct sbuf *s)
4469990Sdes{
4569990Sdes	KASSERT(s != NULL,
4669990Sdes	    (__FUNCTION__ " called with a NULL sbuf pointer"));
4769990Sdes	KASSERT(s->s_buf != NULL,
4869990Sdes	    (__FUNCTION__ " called with unitialized or corrupt sbuf"));
4969990Sdes	KASSERT(s->s_len < s->s_size,
5069990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
5169990Sdes}
5269990Sdes
5369990Sdesstatic void
5469990Sdesassert_sbuf_state(struct sbuf *s, int state)
5569990Sdes{
5669990Sdes	KASSERT((s->s_flags & SBUF_FINISHED) == state,
5769990Sdes	    (__FUNCTION__ " called with %sfinished or corrupt sbuf",
5869990Sdes	    (state ? "un" : "")));
5969990Sdes}
6069990Sdes#else
6169990Sdes#define assert_sbuf_integrity(s) do { } while (0)
6269990Sdes#define assert_sbuf_state(s, i)	 do { } while (0)
6369990Sdes#endif
6469990Sdes
6569990Sdes/*
6669990Sdes * Initialize an sbuf.
6769990Sdes * If buf is non-NULL, it points to a static or already-allocated string
6869990Sdes * big enough to hold at least length characters.
6969990Sdes */
7069990Sdesint
7169990Sdessbuf_new(struct sbuf *s, char *buf, size_t length, int flags)
7269990Sdes{
7369990Sdes	KASSERT(flags == 0,
7469990Sdes	    (__FUNCTION__ " called with non-zero flags"));
7569990Sdes	KASSERT(s != NULL,
7669990Sdes	    (__FUNCTION__ " called with a NULL sbuf pointer"));
7769990Sdes
7869990Sdes	bzero(s, sizeof *s);
7969990Sdes	s->s_size = length;
8069990Sdes	if (buf) {
8169990Sdes		s->s_buf = buf;
8269990Sdes		return (0);
8369990Sdes	}
8469990Sdes	s->s_buf = malloc(s->s_size, M_SBUF, M_WAITOK);
8569990Sdes	if (s->s_buf == NULL)
8669990Sdes		return (-1);
8769990Sdes	SBUF_SETFLAG(s, SBUF_DYNAMIC);
8869990Sdes	return (0);
8969990Sdes}
9069990Sdes
9169990Sdes/*
9269990Sdes * Set the sbuf's position to an arbitrary value
9369990Sdes */
9469990Sdesint
9569990Sdessbuf_setpos(struct sbuf *s, size_t pos)
9669990Sdes{
9769990Sdes	assert_sbuf_integrity(s);
9869990Sdes	assert_sbuf_state(s, 0);
9969990Sdes
10069990Sdes	KASSERT(pos >= 0,
10169990Sdes	    ("attempt to seek to a negative position (%d)", pos));
10269990Sdes	KASSERT(pos < s->s_size,
10369990Sdes	    ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size));
10469990Sdes
10569990Sdes	if (pos < 0 || pos > s->s_len)
10669990Sdes		return (-1);
10769990Sdes	s->s_len = pos;
10869990Sdes	return (0);
10969990Sdes}
11069990Sdes
11169990Sdes/*
11269990Sdes * Append a string to an sbuf.
11369990Sdes */
11469990Sdesint
11569990Sdessbuf_cat(struct sbuf *s, char *str)
11669990Sdes{
11769990Sdes	assert_sbuf_integrity(s);
11869990Sdes	assert_sbuf_state(s, 0);
11969990Sdes
12069990Sdes	if (SBUF_HASOVERFLOWED(s))
12169990Sdes		return (-1);
12269990Sdes
12369990Sdes	while (*str && SBUF_HASROOM(s))
12469990Sdes		s->s_buf[s->s_len++] = *str++;
12569990Sdes	if (*str) {
12669990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
12769990Sdes		return (-1);
12869990Sdes	}
12969990Sdes	return (0);
13069990Sdes}
13169990Sdes
13269990Sdes/*
13369990Sdes * Copy a string into an sbuf.
13469990Sdes */
13569990Sdesint
13669990Sdessbuf_cpy(struct sbuf *s, char *str)
13769990Sdes{
13869990Sdes	assert_sbuf_integrity(s);
13969990Sdes	assert_sbuf_state(s, 0);
14069990Sdes
14169990Sdes	s->s_len = 0;
14269990Sdes	return (sbuf_cat(s, str));
14369990Sdes}
14469990Sdes
14569990Sdes/*
14669990Sdes * PCHAR function for sbuf_printf()
14769990Sdes */
14869990Sdesstatic void
14969990Sdes_sbuf_pchar(int c, void *v)
15069990Sdes{
15169990Sdes	struct sbuf *s = (struct sbuf *)v;
15269990Sdes
15369990Sdes	assert_sbuf_integrity(s);
15469990Sdes	assert_sbuf_state(s, 0);
15569990Sdes
15669990Sdes	if (SBUF_HASOVERFLOWED(s))
15769990Sdes		return;
15869990Sdes	if (SBUF_HASROOM(s))
15969990Sdes		s->s_buf[s->s_len++] = c;
16069990Sdes	else
16169990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
16269990Sdes}
16369990Sdes
16469990Sdes/*
16569990Sdes * Format the given arguments and append the resulting string to an sbuf.
16669990Sdes */
16769990Sdesint
16869990Sdessbuf_printf(struct sbuf *s, char *fmt, ...)
16969990Sdes{
17069990Sdes	va_list ap;
17169990Sdes	size_t len;
17269990Sdes
17369990Sdes	assert_sbuf_integrity(s);
17469990Sdes	assert_sbuf_state(s, 0);
17569990Sdes
17669990Sdes	KASSERT(fmt != NULL,
17769990Sdes	    (__FUNCTION__ " called with a NULL format string"));
17869990Sdes
17969990Sdes	if (SBUF_HASOVERFLOWED(s))
18069990Sdes		return (-1);
18169990Sdes
18269990Sdes	va_start(ap, fmt);
18369990Sdes	len = kvprintf(fmt, _sbuf_pchar, s, 10, ap);
18469990Sdes	va_end(ap);
18569990Sdes
18669990Sdes	KASSERT(s->s_len < s->s_size,
18769990Sdes	    ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
18869990Sdes
18969990Sdes	if (SBUF_HASOVERFLOWED(s))
19069990Sdes		return (-1);
19169990Sdes	return (0);
19269990Sdes}
19369990Sdes
19469990Sdes/*
19569990Sdes * Append a character to an sbuf.
19669990Sdes */
19769990Sdesint
19869990Sdessbuf_putc(struct sbuf *s, int c)
19969990Sdes{
20069990Sdes	assert_sbuf_integrity(s);
20169990Sdes	assert_sbuf_state(s, 0);
20269990Sdes
20369990Sdes	if (SBUF_HASOVERFLOWED(s))
20469990Sdes		return (-1);
20569990Sdes
20669990Sdes	if (!SBUF_HASROOM(s)) {
20769990Sdes		SBUF_SETFLAG(s, SBUF_OVERFLOWED);
20869990Sdes		return (-1);
20969990Sdes	}
21069990Sdes	s->s_buf[s->s_len++] = c;
21169990Sdes	return (0);
21269990Sdes}
21369990Sdes
21469990Sdes/*
21569990Sdes * Finish off an sbuf.
21669990Sdes */
21769990Sdesint
21869990Sdessbuf_finish(struct sbuf *s)
21969990Sdes{
22069990Sdes	assert_sbuf_integrity(s);
22169990Sdes	assert_sbuf_state(s, 0);
22269990Sdes
22369990Sdes	if (SBUF_HASOVERFLOWED(s))
22469990Sdes		return (-1);
22569990Sdes
22669990Sdes	s->s_buf[s->s_len++] = '\0';
22769990Sdes	SBUF_SETFLAG(s, SBUF_FINISHED);
22869990Sdes	return (0);
22969990Sdes}
23069990Sdes
23169990Sdes/*
23269990Sdes * Return a pointer to the sbuf data.
23369990Sdes */
23469990Sdeschar *
23569990Sdessbuf_data(struct sbuf *s)
23669990Sdes{
23769990Sdes	assert_sbuf_integrity(s);
23869990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
23969990Sdes
24069990Sdes	if (SBUF_HASOVERFLOWED(s))
24169990Sdes		return (NULL);
24269990Sdes	return s->s_buf;
24369990Sdes}
24469990Sdes
24569990Sdes/*
24669990Sdes * Return the length of the sbuf data.
24769990Sdes */
24869990Sdessize_t
24969990Sdessbuf_len(struct sbuf *s)
25069990Sdes{
25169990Sdes	assert_sbuf_integrity(s);
25269990Sdes	assert_sbuf_state(s, SBUF_FINISHED);
25369990Sdes
25469990Sdes	if (SBUF_HASOVERFLOWED(s))
25569990Sdes		return (0);
25669990Sdes	return s->s_len;
25769990Sdes}
25869990Sdes
25969990Sdes/*
26069990Sdes * Clear an sbuf, free its buffer if necessary.
26169990Sdes */
26269990Sdesvoid
26369990Sdessbuf_delete(struct sbuf *s)
26469990Sdes{
26569990Sdes	assert_sbuf_integrity(s);
26669990Sdes	/* don't care if it's finished or not */
26769990Sdes
26869990Sdes	if (SBUF_ISDYNAMIC(s))
26969990Sdes		free(s->s_buf, M_SBUF);
27069990Sdes	bzero(s, sizeof *s);
27169990Sdes}
272