subr_sbuf.c revision 212184
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 212184 2010-09-03 17:42:17Z 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) 5974840Sken#endif /* _KERNEL */ 6069990Sdes 6171721Sdes/* 6271721Sdes * Predicates 6371721Sdes */ 6489121Skbyanc#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 6589121Skbyanc#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 6689121Skbyanc#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 6789121Skbyanc#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) 6889121Skbyanc#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 6988950Skbyanc#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) 7088950Skbyanc#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 7171721Sdes 7271721Sdes/* 7371721Sdes * Set / clear flags 7471721Sdes */ 7589121Skbyanc#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 7689121Skbyanc#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 7771721Sdes 7889121Skbyanc#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 7989121Skbyanc#define SBUF_MAXEXTENDSIZE PAGE_SIZE 8089121Skbyanc#define SBUF_MAXEXTENDINCR PAGE_SIZE 8188950Skbyanc 8271721Sdes/* 8371721Sdes * Debugging support 8471721Sdes */ 8574840Sken#if defined(_KERNEL) && defined(INVARIANTS) 86181462Sdes 8769990Sdesstatic void 8892664Speter_assert_sbuf_integrity(const char *fun, struct sbuf *s) 8969990Sdes{ 90181462Sdes 9169990Sdes KASSERT(s != NULL, 9273891Sdes ("%s called with a NULL sbuf pointer", fun)); 9369990Sdes KASSERT(s->s_buf != NULL, 9488950Skbyanc ("%s called with uninitialized or corrupt sbuf", fun)); 9569990Sdes KASSERT(s->s_len < s->s_size, 9669990Sdes ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 9769990Sdes} 9869990Sdes 9969990Sdesstatic void 10092664Speter_assert_sbuf_state(const char *fun, struct sbuf *s, int state) 10169990Sdes{ 102181462Sdes 10369990Sdes KASSERT((s->s_flags & SBUF_FINISHED) == state, 10473891Sdes ("%s called with %sfinished or corrupt sbuf", fun, 10569990Sdes (state ? "un" : ""))); 10669990Sdes} 107181462Sdes 10889121Skbyanc#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 10989121Skbyanc#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 110181462Sdes 11174840Sken#else /* _KERNEL && INVARIANTS */ 112181462Sdes 11389121Skbyanc#define assert_sbuf_integrity(s) do { } while (0) 11489121Skbyanc#define assert_sbuf_state(s, i) do { } while (0) 115181462Sdes 11674840Sken#endif /* _KERNEL && INVARIANTS */ 11769990Sdes 118212184Smdf#ifdef CTASSERT 119212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 120212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 121212182Smdf#endif 122212180Smdf 12388950Skbyancstatic int 12488950Skbyancsbuf_extendsize(int size) 12588950Skbyanc{ 12688950Skbyanc int newsize; 12788950Skbyanc 128212180Smdf if (size < (int)SBUF_MAXEXTENDSIZE) { 129212180Smdf newsize = SBUF_MINEXTENDSIZE; 130212180Smdf while (newsize < size) 13188950Skbyanc newsize *= 2; 132212180Smdf } else { 133212180Smdf newsize = roundup2(size, SBUF_MAXEXTENDINCR); 13488950Skbyanc } 135212181Smdf KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 13688950Skbyanc return (newsize); 13788950Skbyanc} 13888950Skbyanc 13988950Skbyanc 14069990Sdes/* 14188950Skbyanc * Extend an sbuf. 14288950Skbyanc */ 14388950Skbyancstatic int 14488950Skbyancsbuf_extend(struct sbuf *s, int addlen) 14588950Skbyanc{ 14688950Skbyanc char *newbuf; 14788950Skbyanc int newsize; 14888950Skbyanc 14988950Skbyanc if (!SBUF_CANEXTEND(s)) 15088950Skbyanc return (-1); 15188950Skbyanc newsize = sbuf_extendsize(s->s_size + addlen); 152181462Sdes newbuf = SBMALLOC(newsize); 15388950Skbyanc if (newbuf == NULL) 15488950Skbyanc return (-1); 15588950Skbyanc bcopy(s->s_buf, newbuf, s->s_size); 15688950Skbyanc if (SBUF_ISDYNAMIC(s)) 15788950Skbyanc SBFREE(s->s_buf); 15888950Skbyanc else 15988950Skbyanc SBUF_SETFLAG(s, SBUF_DYNAMIC); 16088950Skbyanc s->s_buf = newbuf; 16188950Skbyanc s->s_size = newsize; 16288950Skbyanc return (0); 16388950Skbyanc} 16488950Skbyanc 16588950Skbyanc/* 16669990Sdes * Initialize an sbuf. 16769990Sdes * If buf is non-NULL, it points to a static or already-allocated string 16869990Sdes * big enough to hold at least length characters. 16969990Sdes */ 17077989Sdesstruct sbuf * 17171721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags) 17269990Sdes{ 173181462Sdes 17471721Sdes KASSERT(length >= 0, 17571721Sdes ("attempt to create an sbuf of negative length (%d)", length)); 17688950Skbyanc KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 17788950Skbyanc ("%s called with invalid flags", __func__)); 17869990Sdes 17988950Skbyanc flags &= SBUF_USRFLAGMSK; 18077989Sdes if (s == NULL) { 181181462Sdes s = SBMALLOC(sizeof(*s)); 18277989Sdes if (s == NULL) 18377989Sdes return (NULL); 184181462Sdes bzero(s, sizeof(*s)); 18588950Skbyanc s->s_flags = flags; 18677989Sdes SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 18777989Sdes } else { 188181462Sdes bzero(s, sizeof(*s)); 18988950Skbyanc s->s_flags = flags; 19077989Sdes } 19169990Sdes s->s_size = length; 192212183Smdf if (buf != NULL) { 19369990Sdes s->s_buf = buf; 19477989Sdes return (s); 19569990Sdes } 196212183Smdf if ((flags & SBUF_AUTOEXTEND) != 0) 19788950Skbyanc s->s_size = sbuf_extendsize(s->s_size); 198181462Sdes s->s_buf = SBMALLOC(s->s_size); 19977989Sdes if (s->s_buf == NULL) { 20077989Sdes if (SBUF_ISDYNSTRUCT(s)) 20177989Sdes SBFREE(s); 20277989Sdes return (NULL); 20377989Sdes } 20469990Sdes SBUF_SETFLAG(s, SBUF_DYNAMIC); 20577989Sdes return (s); 20669990Sdes} 20769990Sdes 20884097Sdes#ifdef _KERNEL 20969990Sdes/* 21084097Sdes * Create an sbuf with uio data 21184097Sdes */ 21284097Sdesstruct sbuf * 21384097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 21484097Sdes{ 215181462Sdes 21684097Sdes KASSERT(uio != NULL, 21787594Sobrien ("%s called with NULL uio pointer", __func__)); 21884097Sdes KASSERT(error != NULL, 21987594Sobrien ("%s called with NULL error pointer", __func__)); 22084097Sdes 22184097Sdes s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 22284097Sdes if (s == NULL) { 22384097Sdes *error = ENOMEM; 22484097Sdes return (NULL); 22584097Sdes } 22684097Sdes *error = uiomove(s->s_buf, uio->uio_resid, uio); 22784097Sdes if (*error != 0) { 22884097Sdes sbuf_delete(s); 22984097Sdes return (NULL); 23084097Sdes } 23184097Sdes s->s_len = s->s_size - 1; 23284097Sdes *error = 0; 23384097Sdes return (s); 23484097Sdes} 23584097Sdes#endif 23684097Sdes 23784097Sdes/* 23888950Skbyanc * Clear an sbuf and reset its position. 23971721Sdes */ 24071721Sdesvoid 24171721Sdessbuf_clear(struct sbuf *s) 24271721Sdes{ 243181462Sdes 24471721Sdes assert_sbuf_integrity(s); 24571724Sdes /* don't care if it's finished or not */ 24671721Sdes 24771721Sdes SBUF_CLEARFLAG(s, SBUF_FINISHED); 24871721Sdes SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 24971721Sdes s->s_len = 0; 25071721Sdes} 25171721Sdes 25271721Sdes/* 25388950Skbyanc * Set the sbuf's end position to an arbitrary value. 25488950Skbyanc * Effectively truncates the sbuf at the new position. 25569990Sdes */ 25669990Sdesint 25771721Sdessbuf_setpos(struct sbuf *s, int pos) 25869990Sdes{ 259181462Sdes 26069990Sdes assert_sbuf_integrity(s); 26169990Sdes assert_sbuf_state(s, 0); 262125937Sdes 26369990Sdes KASSERT(pos >= 0, 26469990Sdes ("attempt to seek to a negative position (%d)", pos)); 26569990Sdes KASSERT(pos < s->s_size, 26669990Sdes ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 267125937Sdes 26869990Sdes if (pos < 0 || pos > s->s_len) 26969990Sdes return (-1); 27069990Sdes s->s_len = pos; 27169990Sdes return (0); 27269990Sdes} 27369990Sdes 27469990Sdes/* 27578077Sdes * Append a byte string to an sbuf. 27678077Sdes */ 27778077Sdesint 278131869Sdessbuf_bcat(struct sbuf *s, const void *buf, size_t len) 27978077Sdes{ 280131869Sdes const char *str = buf; 281131868Sdes 28278077Sdes assert_sbuf_integrity(s); 28378077Sdes assert_sbuf_state(s, 0); 284125937Sdes 28578077Sdes if (SBUF_HASOVERFLOWED(s)) 28678077Sdes return (-1); 28789765Sphk for (; len; len--) { 28888950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) 28988950Skbyanc break; 29078077Sdes s->s_buf[s->s_len++] = *str++; 29188950Skbyanc } 292212183Smdf if (len > 0) { 29378077Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 29478077Sdes return (-1); 29578077Sdes } 29678077Sdes return (0); 29778077Sdes} 29878077Sdes 29978077Sdes#ifdef _KERNEL 30078077Sdes/* 30178077Sdes * Copy a byte string from userland into an sbuf. 30278077Sdes */ 30378077Sdesint 30478077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 30578077Sdes{ 306181462Sdes 30778077Sdes assert_sbuf_integrity(s); 30878077Sdes assert_sbuf_state(s, 0); 30978077Sdes 31078077Sdes if (SBUF_HASOVERFLOWED(s)) 31178077Sdes return (-1); 31278077Sdes if (len == 0) 31378077Sdes return (0); 31488950Skbyanc if (len > SBUF_FREESPACE(s)) { 31588950Skbyanc sbuf_extend(s, len - SBUF_FREESPACE(s)); 316212183Smdf if (SBUF_FREESPACE(s) < len) 317212183Smdf len = SBUF_FREESPACE(s); 31888950Skbyanc } 31978092Sdes if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 32078092Sdes return (-1); 32178095Sdes s->s_len += len; 322125937Sdes 32378077Sdes return (0); 32478077Sdes} 32578077Sdes#endif 32678077Sdes 32778077Sdes/* 32878077Sdes * Copy a byte string into an sbuf. 32978077Sdes */ 33078077Sdesint 331131869Sdessbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 33278077Sdes{ 333181462Sdes 33478077Sdes assert_sbuf_integrity(s); 33578077Sdes assert_sbuf_state(s, 0); 336125937Sdes 33778077Sdes sbuf_clear(s); 338131869Sdes return (sbuf_bcat(s, buf, len)); 33978077Sdes} 34078077Sdes 34178077Sdes/* 34269990Sdes * Append a string to an sbuf. 34369990Sdes */ 34469990Sdesint 34574840Skensbuf_cat(struct sbuf *s, const char *str) 34669990Sdes{ 347181462Sdes 34869990Sdes assert_sbuf_integrity(s); 34969990Sdes assert_sbuf_state(s, 0); 350125937Sdes 35169990Sdes if (SBUF_HASOVERFLOWED(s)) 35269990Sdes return (-1); 353125937Sdes 354212183Smdf while (*str != '\0') { 35588950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) 35688950Skbyanc break; 35769990Sdes s->s_buf[s->s_len++] = *str++; 35888950Skbyanc } 359212183Smdf if (*str != '\0') { 36069990Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 36169990Sdes return (-1); 36269990Sdes } 36369990Sdes return (0); 36469990Sdes} 36569990Sdes 36678077Sdes#ifdef _KERNEL 36769990Sdes/* 36888950Skbyanc * Append a string from userland to an sbuf. 36978077Sdes */ 37078077Sdesint 37178077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 37278077Sdes{ 37378077Sdes size_t done; 374125937Sdes 37578077Sdes assert_sbuf_integrity(s); 37678077Sdes assert_sbuf_state(s, 0); 37778077Sdes 37878077Sdes if (SBUF_HASOVERFLOWED(s)) 37978077Sdes return (-1); 38078077Sdes 38188950Skbyanc if (len == 0) 38288950Skbyanc len = SBUF_FREESPACE(s); /* XXX return 0? */ 38388950Skbyanc if (len > SBUF_FREESPACE(s)) { 38488950Skbyanc sbuf_extend(s, len); 385212183Smdf if (SBUF_FREESPACE(s) < len) 386212183Smdf len = SBUF_FREESPACE(s); 38788950Skbyanc } 38878077Sdes switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 38978077Sdes case ENAMETOOLONG: 39078077Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 39178077Sdes /* fall through */ 39278077Sdes case 0: 39378077Sdes s->s_len += done - 1; 39478077Sdes break; 39578077Sdes default: 39678077Sdes return (-1); /* XXX */ 39778077Sdes } 398125937Sdes 399153678Sphk return (done); 40078077Sdes} 40178077Sdes#endif 40278077Sdes 40378077Sdes/* 40469990Sdes * Copy a string into an sbuf. 40569990Sdes */ 40669990Sdesint 40774840Skensbuf_cpy(struct sbuf *s, const char *str) 40869990Sdes{ 409181462Sdes 41069990Sdes assert_sbuf_integrity(s); 41169990Sdes assert_sbuf_state(s, 0); 412125937Sdes 41371721Sdes sbuf_clear(s); 41469990Sdes return (sbuf_cat(s, str)); 41569990Sdes} 41669990Sdes 41769990Sdes/* 41888950Skbyanc * Format the given argument list and append the resulting string to an sbuf. 41969990Sdes */ 42069990Sdesint 42188950Skbyancsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 42269990Sdes{ 423115311Speter va_list ap_copy; 42471721Sdes int len; 42569990Sdes 42669990Sdes assert_sbuf_integrity(s); 42769990Sdes assert_sbuf_state(s, 0); 42888950Skbyanc 42969990Sdes KASSERT(fmt != NULL, 43087594Sobrien ("%s called with a NULL format string", __func__)); 43188950Skbyanc 43269990Sdes if (SBUF_HASOVERFLOWED(s)) 43369990Sdes return (-1); 43469990Sdes 43588950Skbyanc do { 436115311Speter va_copy(ap_copy, ap); 43788950Skbyanc len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 438115311Speter fmt, ap_copy); 439115311Speter va_end(ap_copy); 44088950Skbyanc } while (len > SBUF_FREESPACE(s) && 44188950Skbyanc sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); 44269990Sdes 44374840Sken /* 44474840Sken * s->s_len is the length of the string, without the terminating nul. 44574840Sken * When updating s->s_len, we must subtract 1 from the length that 44674840Sken * we passed into vsnprintf() because that length includes the 44774840Sken * terminating nul. 44874840Sken * 44974840Sken * vsnprintf() returns the amount that would have been copied, 450212183Smdf * given sufficient space, so don't over-increment s_len. 45174840Sken */ 452212183Smdf if (SBUF_FREESPACE(s) < len) 453212183Smdf len = SBUF_FREESPACE(s); 454212183Smdf s->s_len += len; 45589646Sphk if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 45674840Sken SBUF_SETFLAG(s, SBUF_OVERFLOWED); 45774840Sken 45869990Sdes KASSERT(s->s_len < s->s_size, 45969990Sdes ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 46069990Sdes 46169990Sdes if (SBUF_HASOVERFLOWED(s)) 46269990Sdes return (-1); 46369990Sdes return (0); 46469990Sdes} 46569990Sdes 46669990Sdes/* 46788950Skbyanc * Format the given arguments and append the resulting string to an sbuf. 46888950Skbyanc */ 46988950Skbyancint 47088950Skbyancsbuf_printf(struct sbuf *s, const char *fmt, ...) 47188950Skbyanc{ 47288950Skbyanc va_list ap; 47388950Skbyanc int result; 47488950Skbyanc 47588950Skbyanc va_start(ap, fmt); 47688950Skbyanc result = sbuf_vprintf(s, fmt, ap); 47788950Skbyanc va_end(ap); 478181462Sdes return (result); 47988950Skbyanc} 48088950Skbyanc 48188950Skbyanc/* 48269990Sdes * Append a character to an sbuf. 48369990Sdes */ 48469990Sdesint 48569990Sdessbuf_putc(struct sbuf *s, int c) 48669990Sdes{ 487181462Sdes 48869990Sdes assert_sbuf_integrity(s); 48969990Sdes assert_sbuf_state(s, 0); 490125937Sdes 49169990Sdes if (SBUF_HASOVERFLOWED(s)) 49269990Sdes return (-1); 49388950Skbyanc if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { 49469990Sdes SBUF_SETFLAG(s, SBUF_OVERFLOWED); 49569990Sdes return (-1); 49669990Sdes } 49773891Sdes if (c != '\0') 498212183Smdf s->s_buf[s->s_len++] = c; 49969990Sdes return (0); 50069990Sdes} 50169990Sdes 50269990Sdes/* 50388950Skbyanc * Trim whitespace characters from end of an sbuf. 50484097Sdes */ 50584097Sdesint 50684097Sdessbuf_trim(struct sbuf *s) 50784097Sdes{ 508181462Sdes 50984097Sdes assert_sbuf_integrity(s); 51084097Sdes assert_sbuf_state(s, 0); 511125937Sdes 51284097Sdes if (SBUF_HASOVERFLOWED(s)) 51384097Sdes return (-1); 514125937Sdes 515212183Smdf while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) 51684097Sdes --s->s_len; 51784097Sdes 51884097Sdes return (0); 51984097Sdes} 52084097Sdes 52184097Sdes/* 52271721Sdes * Check if an sbuf overflowed 52371721Sdes */ 52471721Sdesint 52571721Sdessbuf_overflowed(struct sbuf *s) 52671721Sdes{ 527181462Sdes 528181462Sdes return (SBUF_HASOVERFLOWED(s)); 52971721Sdes} 53071721Sdes 53171721Sdes/* 53269990Sdes * Finish off an sbuf. 53369990Sdes */ 53471721Sdesvoid 53569990Sdessbuf_finish(struct sbuf *s) 53669990Sdes{ 537181462Sdes 53869990Sdes assert_sbuf_integrity(s); 53969990Sdes assert_sbuf_state(s, 0); 540125937Sdes 54173891Sdes s->s_buf[s->s_len] = '\0'; 54271721Sdes SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 54369990Sdes SBUF_SETFLAG(s, SBUF_FINISHED); 54469990Sdes} 54569990Sdes 54669990Sdes/* 54769990Sdes * Return a pointer to the sbuf data. 54869990Sdes */ 54969990Sdeschar * 55069990Sdessbuf_data(struct sbuf *s) 55169990Sdes{ 552181462Sdes 55369990Sdes assert_sbuf_integrity(s); 55469990Sdes assert_sbuf_state(s, SBUF_FINISHED); 555125937Sdes 556181462Sdes return (s->s_buf); 55769990Sdes} 55869990Sdes 55969990Sdes/* 56069990Sdes * Return the length of the sbuf data. 56169990Sdes */ 56271721Sdesint 56369990Sdessbuf_len(struct sbuf *s) 56469990Sdes{ 565181462Sdes 56669990Sdes assert_sbuf_integrity(s); 56771724Sdes /* don't care if it's finished or not */ 568125937Sdes 56969990Sdes if (SBUF_HASOVERFLOWED(s)) 57071721Sdes return (-1); 571181462Sdes return (s->s_len); 57269990Sdes} 57369990Sdes 57469990Sdes/* 57569990Sdes * Clear an sbuf, free its buffer if necessary. 57669990Sdes */ 57769990Sdesvoid 57869990Sdessbuf_delete(struct sbuf *s) 57969990Sdes{ 58088219Sdillon int isdyn; 58188219Sdillon 58269990Sdes assert_sbuf_integrity(s); 58369990Sdes /* don't care if it's finished or not */ 584125937Sdes 58569990Sdes if (SBUF_ISDYNAMIC(s)) 58674840Sken SBFREE(s->s_buf); 58788219Sdillon isdyn = SBUF_ISDYNSTRUCT(s); 588181462Sdes bzero(s, sizeof(*s)); 58988219Sdillon if (isdyn) 59077989Sdes SBFREE(s); 59169990Sdes} 592104449Sphk 593104449Sphk/* 594104449Sphk * Check if an sbuf has been finished. 595104449Sphk */ 596104449Sphkint 597104449Sphksbuf_done(struct sbuf *s) 598104449Sphk{ 599104449Sphk 600181462Sdes return (SBUF_ISFINISHED(s)); 601104449Sphk} 602