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