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