subr_sbuf.c revision 212181
169990Sdes/*- 2181462Sdes * Copyright (c) 2000-2008 Poul-Henning Kamp 3181462Sdes * Copyright (c) 2000-2008 Dag-Erling Co��dan Sm��rgrav 469990Sdes * All rights reserved. 569990Sdes * 669990Sdes * Redistribution and use in source and binary forms, with or without 769990Sdes * modification, are permitted provided that the following conditions 869990Sdes * are met: 969990Sdes * 1. Redistributions of source code must retain the above copyright 1069990Sdes * notice, this list of conditions and the following disclaimer 1169990Sdes * in this position and unchanged. 1269990Sdes * 2. Redistributions in binary form must reproduce the above copyright 1369990Sdes * notice, this list of conditions and the following disclaimer in the 1469990Sdes * documentation and/or other materials provided with the distribution. 1569990Sdes * 16181462Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17181462Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18181462Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19181462Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20181462Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21181462Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22181462Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23181462Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24181462Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25181462Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26181462Sdes * SUCH DAMAGE. 2769990Sdes */ 2869990Sdes 29116182Sobrien#include <sys/cdefs.h> 30116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/subr_sbuf.c 212181 2010-09-03 16:12:39Z mdf $"); 31116182Sobrien 3269990Sdes#include <sys/param.h> 3374840Sken 3474840Sken#ifdef _KERNEL 3584097Sdes#include <sys/ctype.h> 3669990Sdes#include <sys/kernel.h> 3769990Sdes#include <sys/malloc.h> 3869990Sdes#include <sys/systm.h> 3984097Sdes#include <sys/uio.h> 4069990Sdes#include <machine/stdarg.h> 4174840Sken#else /* _KERNEL */ 4284097Sdes#include <ctype.h> 4374840Sken#include <stdarg.h> 4488950Skbyanc#include <stdio.h> 4578340Sjlemon#include <stdlib.h> 4688950Skbyanc#include <string.h> 4774840Sken#endif /* _KERNEL */ 4869990Sdes 4984097Sdes#include <sys/sbuf.h> 5084097Sdes 5174840Sken#ifdef _KERNEL 52141616Sphkstatic MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 53111119Simp#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK) 5489121Skbyanc#define SBFREE(buf) free(buf, M_SBUF) 5574840Sken#else /* _KERNEL */ 5689121Skbyanc#define KASSERT(e, m) 5789121Skbyanc#define SBMALLOC(size) malloc(size) 5889121Skbyanc#define SBFREE(buf) free(buf) 5989121Skbyanc#define min(x,y) MIN(x,y) 6074840Sken#endif /* _KERNEL */ 6169990Sdes 6271721Sdes/* 6371721Sdes * Predicates 6471721Sdes */ 6589121Skbyanc#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 6689121Skbyanc#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 6789121Skbyanc#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 6889121Skbyanc#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) 6989121Skbyanc#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 7088950Skbyanc#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) 7188950Skbyanc#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 7271721Sdes 7371721Sdes/* 7471721Sdes * Set / clear flags 7571721Sdes */ 7689121Skbyanc#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 7789121Skbyanc#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 7871721Sdes 7989121Skbyanc#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 8089121Skbyanc#define SBUF_MAXEXTENDSIZE PAGE_SIZE 8189121Skbyanc#define SBUF_MAXEXTENDINCR PAGE_SIZE 8288950Skbyanc 8371721Sdes/* 8471721Sdes * Debugging support 8571721Sdes */ 8674840Sken#if defined(_KERNEL) && defined(INVARIANTS) 87181462Sdes 8869990Sdesstatic void 8992664Speter_assert_sbuf_integrity(const char *fun, struct sbuf *s) 9069990Sdes{ 91181462Sdes 9269990Sdes KASSERT(s != NULL, 9373891Sdes ("%s called with a NULL sbuf pointer", fun)); 9469990Sdes KASSERT(s->s_buf != NULL, 9588950Skbyanc ("%s called with uninitialized or corrupt sbuf", fun)); 9669990Sdes KASSERT(s->s_len < s->s_size, 9769990Sdes ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 9869990Sdes} 9969990Sdes 10069990Sdesstatic void 10192664Speter_assert_sbuf_state(const char *fun, struct sbuf *s, int state) 10269990Sdes{ 103181462Sdes 10469990Sdes KASSERT((s->s_flags & SBUF_FINISHED) == state, 10573891Sdes ("%s called with %sfinished or corrupt sbuf", fun, 10669990Sdes (state ? "un" : ""))); 10769990Sdes} 108181462Sdes 10989121Skbyanc#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 11089121Skbyanc#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 111181462Sdes 11274840Sken#else /* _KERNEL && INVARIANTS */ 113181462Sdes 11489121Skbyanc#define assert_sbuf_integrity(s) do { } while (0) 11589121Skbyanc#define assert_sbuf_state(s, i) do { } while (0) 116181462Sdes 11774840Sken#endif /* _KERNEL && INVARIANTS */ 11869990Sdes 119212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 120212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 121212180Smdf 12288950Skbyancstatic int 12388950Skbyancsbuf_extendsize(int size) 12488950Skbyanc{ 12588950Skbyanc int newsize; 12688950Skbyanc 127212180Smdf if (size < (int)SBUF_MAXEXTENDSIZE) { 128212180Smdf newsize = SBUF_MINEXTENDSIZE; 129212180Smdf while (newsize < size) 13088950Skbyanc newsize *= 2; 131212180Smdf } else { 132212180Smdf newsize = roundup2(size, SBUF_MAXEXTENDINCR); 13388950Skbyanc } 134212181Smdf KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 13588950Skbyanc return (newsize); 13688950Skbyanc} 13788950Skbyanc 13888950Skbyanc 13969990Sdes/* 14088950Skbyanc * Extend an sbuf. 14188950Skbyanc */ 14288950Skbyancstatic int 14388950Skbyancsbuf_extend(struct sbuf *s, int addlen) 14488950Skbyanc{ 14588950Skbyanc char *newbuf; 14688950Skbyanc int newsize; 14788950Skbyanc 14888950Skbyanc if (!SBUF_CANEXTEND(s)) 14988950Skbyanc return (-1); 15088950Skbyanc newsize = sbuf_extendsize(s->s_size + addlen); 151181462Sdes newbuf = SBMALLOC(newsize); 15288950Skbyanc if (newbuf == NULL) 15388950Skbyanc return (-1); 15488950Skbyanc bcopy(s->s_buf, newbuf, s->s_size); 15588950Skbyanc if (SBUF_ISDYNAMIC(s)) 15688950Skbyanc SBFREE(s->s_buf); 15788950Skbyanc else 15888950Skbyanc SBUF_SETFLAG(s, SBUF_DYNAMIC); 15988950Skbyanc s->s_buf = newbuf; 16088950Skbyanc s->s_size = newsize; 16188950Skbyanc return (0); 16288950Skbyanc} 16388950Skbyanc 16488950Skbyanc/* 16569990Sdes * Initialize an sbuf. 16669990Sdes * If buf is non-NULL, it points to a static or already-allocated string 16769990Sdes * big enough to hold at least length characters. 16869990Sdes */ 16977989Sdesstruct sbuf * 17071721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags) 17169990Sdes{ 172181462Sdes 17371721Sdes KASSERT(length >= 0, 17471721Sdes ("attempt to create an sbuf of negative length (%d)", length)); 17588950Skbyanc KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 17688950Skbyanc ("%s called with invalid flags", __func__)); 17769990Sdes 17888950Skbyanc flags &= SBUF_USRFLAGMSK; 17977989Sdes if (s == NULL) { 180181462Sdes s = SBMALLOC(sizeof(*s)); 18177989Sdes if (s == NULL) 18277989Sdes return (NULL); 183181462Sdes bzero(s, sizeof(*s)); 18488950Skbyanc s->s_flags = flags; 18577989Sdes SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 18677989Sdes } else { 187181462Sdes bzero(s, sizeof(*s)); 18888950Skbyanc s->s_flags = flags; 18977989Sdes } 19069990Sdes s->s_size = length; 19169990Sdes if (buf) { 19269990Sdes s->s_buf = buf; 19377989Sdes return (s); 19469990Sdes } 19588950Skbyanc if (flags & SBUF_AUTOEXTEND) 19688950Skbyanc s->s_size = sbuf_extendsize(s->s_size); 197181462Sdes s->s_buf = SBMALLOC(s->s_size); 19877989Sdes if (s->s_buf == NULL) { 19977989Sdes if (SBUF_ISDYNSTRUCT(s)) 20077989Sdes SBFREE(s); 20177989Sdes return (NULL); 20277989Sdes } 20369990Sdes SBUF_SETFLAG(s, SBUF_DYNAMIC); 20477989Sdes return (s); 20569990Sdes} 20669990Sdes 20784097Sdes#ifdef _KERNEL 20869990Sdes/* 20984097Sdes * Create an sbuf with uio data 21084097Sdes */ 21184097Sdesstruct sbuf * 21284097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 21384097Sdes{ 214181462Sdes 21584097Sdes KASSERT(uio != NULL, 21687594Sobrien ("%s called with NULL uio pointer", __func__)); 21784097Sdes KASSERT(error != NULL, 21887594Sobrien ("%s called with NULL error pointer", __func__)); 21984097Sdes 22084097Sdes s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 22184097Sdes if (s == NULL) { 22284097Sdes *error = ENOMEM; 22384097Sdes return (NULL); 22484097Sdes } 22584097Sdes *error = uiomove(s->s_buf, uio->uio_resid, uio); 22684097Sdes if (*error != 0) { 22784097Sdes sbuf_delete(s); 22884097Sdes return (NULL); 22984097Sdes } 23084097Sdes s->s_len = s->s_size - 1; 23184097Sdes *error = 0; 23284097Sdes return (s); 23384097Sdes} 23484097Sdes#endif 23584097Sdes 23684097Sdes/* 23788950Skbyanc * Clear an sbuf and reset its position. 23871721Sdes */ 23971721Sdesvoid 24071721Sdessbuf_clear(struct sbuf *s) 24171721Sdes{ 242181462Sdes 24371721Sdes assert_sbuf_integrity(s); 24471724Sdes /* don't care if it's finished or not */ 24571721Sdes 24671721Sdes SBUF_CLEARFLAG(s, SBUF_FINISHED); 24771721Sdes SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 24871721Sdes s->s_len = 0; 24971721Sdes} 25071721Sdes 25171721Sdes/* 25288950Skbyanc * Set the sbuf's end position to an arbitrary value. 25388950Skbyanc * Effectively truncates the sbuf at the new position. 25469990Sdes */ 25569990Sdesint 25671721Sdessbuf_setpos(struct sbuf *s, int pos) 25769990Sdes{ 258181462Sdes 25969990Sdes assert_sbuf_integrity(s); 26069990Sdes assert_sbuf_state(s, 0); 261125937Sdes 26269990Sdes KASSERT(pos >= 0, 26369990Sdes ("attempt to seek to a negative position (%d)", pos)); 26469990Sdes KASSERT(pos < s->s_size, 26569990Sdes ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 266125937Sdes 26769990Sdes if (pos < 0 || pos > s->s_len) 26869990Sdes return (-1); 26969990Sdes s->s_len = pos; 27069990Sdes return (0); 27169990Sdes} 27269990Sdes 27369990Sdes/* 27478077Sdes * Append a byte string to an sbuf. 27578077Sdes */ 27678077Sdesint 277131869Sdessbuf_bcat(struct sbuf *s, const void *buf, size_t len) 27878077Sdes{ 279131869Sdes const char *str = buf; 280131868Sdes 28178077Sdes assert_sbuf_integrity(s); 28278077Sdes assert_sbuf_state(s, 0); 283125937Sdes 28478077Sdes if (SBUF_HASOVERFLOWED(s)) 28578077Sdes return (-1); 28689765Sphk for (; len; len--) { 28788950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) 28888950Skbyanc break; 28978077Sdes s->s_buf[s->s_len++] = *str++; 29088950Skbyanc } 29178077Sdes if (len) { 29278077Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 29378077Sdes return (-1); 29478077Sdes } 29578077Sdes return (0); 29678077Sdes} 29778077Sdes 29878077Sdes#ifdef _KERNEL 29978077Sdes/* 30078077Sdes * Copy a byte string from userland into an sbuf. 30178077Sdes */ 30278077Sdesint 30378077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 30478077Sdes{ 305181462Sdes 30678077Sdes assert_sbuf_integrity(s); 30778077Sdes assert_sbuf_state(s, 0); 30878077Sdes 30978077Sdes if (SBUF_HASOVERFLOWED(s)) 31078077Sdes return (-1); 31178077Sdes if (len == 0) 31278077Sdes return (0); 31388950Skbyanc if (len > SBUF_FREESPACE(s)) { 31488950Skbyanc sbuf_extend(s, len - SBUF_FREESPACE(s)); 31588950Skbyanc len = min(len, SBUF_FREESPACE(s)); 31688950Skbyanc } 31778092Sdes if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 31878092Sdes return (-1); 31978095Sdes s->s_len += len; 320125937Sdes 32178077Sdes return (0); 32278077Sdes} 32378077Sdes#endif 32478077Sdes 32578077Sdes/* 32678077Sdes * Copy a byte string into an sbuf. 32778077Sdes */ 32878077Sdesint 329131869Sdessbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 33078077Sdes{ 331181462Sdes 33278077Sdes assert_sbuf_integrity(s); 33378077Sdes assert_sbuf_state(s, 0); 334125937Sdes 33578077Sdes sbuf_clear(s); 336131869Sdes return (sbuf_bcat(s, buf, len)); 33778077Sdes} 33878077Sdes 33978077Sdes/* 34069990Sdes * Append a string to an sbuf. 34169990Sdes */ 34269990Sdesint 34374840Skensbuf_cat(struct sbuf *s, const char *str) 34469990Sdes{ 345181462Sdes 34669990Sdes assert_sbuf_integrity(s); 34769990Sdes assert_sbuf_state(s, 0); 348125937Sdes 34969990Sdes if (SBUF_HASOVERFLOWED(s)) 35069990Sdes return (-1); 351125937Sdes 35288950Skbyanc while (*str) { 35388950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) 35488950Skbyanc break; 35569990Sdes s->s_buf[s->s_len++] = *str++; 35688950Skbyanc } 35769990Sdes if (*str) { 35869990Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 35969990Sdes return (-1); 36069990Sdes } 36169990Sdes return (0); 36269990Sdes} 36369990Sdes 36478077Sdes#ifdef _KERNEL 36569990Sdes/* 36688950Skbyanc * Append a string from userland to an sbuf. 36778077Sdes */ 36878077Sdesint 36978077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 37078077Sdes{ 37178077Sdes size_t done; 372125937Sdes 37378077Sdes assert_sbuf_integrity(s); 37478077Sdes assert_sbuf_state(s, 0); 37578077Sdes 37678077Sdes if (SBUF_HASOVERFLOWED(s)) 37778077Sdes return (-1); 37878077Sdes 37988950Skbyanc if (len == 0) 38088950Skbyanc len = SBUF_FREESPACE(s); /* XXX return 0? */ 38188950Skbyanc if (len > SBUF_FREESPACE(s)) { 38288950Skbyanc sbuf_extend(s, len); 38388950Skbyanc len = min(len, SBUF_FREESPACE(s)); 38488950Skbyanc } 38578077Sdes switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 38678077Sdes case ENAMETOOLONG: 38778077Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 38878077Sdes /* fall through */ 38978077Sdes case 0: 39078077Sdes s->s_len += done - 1; 39178077Sdes break; 39278077Sdes default: 39378077Sdes return (-1); /* XXX */ 39478077Sdes } 395125937Sdes 396153678Sphk return (done); 39778077Sdes} 39878077Sdes#endif 39978077Sdes 40078077Sdes/* 40169990Sdes * Copy a string into an sbuf. 40269990Sdes */ 40369990Sdesint 40474840Skensbuf_cpy(struct sbuf *s, const char *str) 40569990Sdes{ 406181462Sdes 40769990Sdes assert_sbuf_integrity(s); 40869990Sdes assert_sbuf_state(s, 0); 409125937Sdes 41071721Sdes sbuf_clear(s); 41169990Sdes return (sbuf_cat(s, str)); 41269990Sdes} 41369990Sdes 41469990Sdes/* 41588950Skbyanc * Format the given argument list and append the resulting string to an sbuf. 41669990Sdes */ 41769990Sdesint 41888950Skbyancsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 41969990Sdes{ 420115311Speter va_list ap_copy; 42171721Sdes int len; 42269990Sdes 42369990Sdes assert_sbuf_integrity(s); 42469990Sdes assert_sbuf_state(s, 0); 42588950Skbyanc 42669990Sdes KASSERT(fmt != NULL, 42787594Sobrien ("%s called with a NULL format string", __func__)); 42888950Skbyanc 42969990Sdes if (SBUF_HASOVERFLOWED(s)) 43069990Sdes return (-1); 43169990Sdes 43288950Skbyanc do { 433115311Speter va_copy(ap_copy, ap); 43488950Skbyanc len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 435115311Speter fmt, ap_copy); 436115311Speter va_end(ap_copy); 43788950Skbyanc } while (len > SBUF_FREESPACE(s) && 43888950Skbyanc sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); 43969990Sdes 44074840Sken /* 44174840Sken * s->s_len is the length of the string, without the terminating nul. 44274840Sken * When updating s->s_len, we must subtract 1 from the length that 44374840Sken * we passed into vsnprintf() because that length includes the 44474840Sken * terminating nul. 44574840Sken * 44674840Sken * vsnprintf() returns the amount that would have been copied, 44774840Sken * given sufficient space, hence the min() calculation below. 44874840Sken */ 44988950Skbyanc s->s_len += min(len, SBUF_FREESPACE(s)); 45089646Sphk if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 45174840Sken SBUF_SETFLAG(s, SBUF_OVERFLOWED); 45274840Sken 45369990Sdes KASSERT(s->s_len < s->s_size, 45469990Sdes ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 45569990Sdes 45669990Sdes if (SBUF_HASOVERFLOWED(s)) 45769990Sdes return (-1); 45869990Sdes return (0); 45969990Sdes} 46069990Sdes 46169990Sdes/* 46288950Skbyanc * Format the given arguments and append the resulting string to an sbuf. 46388950Skbyanc */ 46488950Skbyancint 46588950Skbyancsbuf_printf(struct sbuf *s, const char *fmt, ...) 46688950Skbyanc{ 46788950Skbyanc va_list ap; 46888950Skbyanc int result; 46988950Skbyanc 47088950Skbyanc va_start(ap, fmt); 47188950Skbyanc result = sbuf_vprintf(s, fmt, ap); 47288950Skbyanc va_end(ap); 473181462Sdes return (result); 47488950Skbyanc} 47588950Skbyanc 47688950Skbyanc/* 47769990Sdes * Append a character to an sbuf. 47869990Sdes */ 47969990Sdesint 48069990Sdessbuf_putc(struct sbuf *s, int c) 48169990Sdes{ 482181462Sdes 48369990Sdes assert_sbuf_integrity(s); 48469990Sdes assert_sbuf_state(s, 0); 485125937Sdes 48669990Sdes if (SBUF_HASOVERFLOWED(s)) 48769990Sdes return (-1); 48888950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { 48969990Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 49069990Sdes return (-1); 49169990Sdes } 49273891Sdes if (c != '\0') 49373891Sdes s->s_buf[s->s_len++] = c; 49469990Sdes return (0); 49569990Sdes} 49669990Sdes 49769990Sdes/* 49888950Skbyanc * Trim whitespace characters from end of an sbuf. 49984097Sdes */ 50084097Sdesint 50184097Sdessbuf_trim(struct sbuf *s) 50284097Sdes{ 503181462Sdes 50484097Sdes assert_sbuf_integrity(s); 50584097Sdes assert_sbuf_state(s, 0); 506125937Sdes 50784097Sdes if (SBUF_HASOVERFLOWED(s)) 50884097Sdes return (-1); 509125937Sdes 51084097Sdes while (s->s_len && isspace(s->s_buf[s->s_len-1])) 51184097Sdes --s->s_len; 51284097Sdes 51384097Sdes return (0); 51484097Sdes} 51584097Sdes 51684097Sdes/* 51771721Sdes * Check if an sbuf overflowed 51871721Sdes */ 51971721Sdesint 52071721Sdessbuf_overflowed(struct sbuf *s) 52171721Sdes{ 522181462Sdes 523181462Sdes return (SBUF_HASOVERFLOWED(s)); 52471721Sdes} 52571721Sdes 52671721Sdes/* 52769990Sdes * Finish off an sbuf. 52869990Sdes */ 52971721Sdesvoid 53069990Sdessbuf_finish(struct sbuf *s) 53169990Sdes{ 532181462Sdes 53369990Sdes assert_sbuf_integrity(s); 53469990Sdes assert_sbuf_state(s, 0); 535125937Sdes 53673891Sdes s->s_buf[s->s_len] = '\0'; 53771721Sdes SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 53869990Sdes SBUF_SETFLAG(s, SBUF_FINISHED); 53969990Sdes} 54069990Sdes 54169990Sdes/* 54269990Sdes * Return a pointer to the sbuf data. 54369990Sdes */ 54469990Sdeschar * 54569990Sdessbuf_data(struct sbuf *s) 54669990Sdes{ 547181462Sdes 54869990Sdes assert_sbuf_integrity(s); 54969990Sdes assert_sbuf_state(s, SBUF_FINISHED); 550125937Sdes 551181462Sdes return (s->s_buf); 55269990Sdes} 55369990Sdes 55469990Sdes/* 55569990Sdes * Return the length of the sbuf data. 55669990Sdes */ 55771721Sdesint 55869990Sdessbuf_len(struct sbuf *s) 55969990Sdes{ 560181462Sdes 56169990Sdes assert_sbuf_integrity(s); 56271724Sdes /* don't care if it's finished or not */ 563125937Sdes 56469990Sdes if (SBUF_HASOVERFLOWED(s)) 56571721Sdes return (-1); 566181462Sdes return (s->s_len); 56769990Sdes} 56869990Sdes 56969990Sdes/* 57069990Sdes * Clear an sbuf, free its buffer if necessary. 57169990Sdes */ 57269990Sdesvoid 57369990Sdessbuf_delete(struct sbuf *s) 57469990Sdes{ 57588219Sdillon int isdyn; 57688219Sdillon 57769990Sdes assert_sbuf_integrity(s); 57869990Sdes /* don't care if it's finished or not */ 579125937Sdes 58069990Sdes if (SBUF_ISDYNAMIC(s)) 58174840Sken SBFREE(s->s_buf); 58288219Sdillon isdyn = SBUF_ISDYNSTRUCT(s); 583181462Sdes bzero(s, sizeof(*s)); 58488219Sdillon if (isdyn) 58577989Sdes SBFREE(s); 58669990Sdes} 587104449Sphk 588104449Sphk/* 589104449Sphk * Check if an sbuf has been finished. 590104449Sphk */ 591104449Sphkint 592104449Sphksbuf_done(struct sbuf *s) 593104449Sphk{ 594104449Sphk 595181462Sdes return (SBUF_ISFINISHED(s)); 596104449Sphk} 597