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$"); 31116182Sobrien 3269990Sdes#include <sys/param.h> 3374840Sken 3474840Sken#ifdef _KERNEL 3584097Sdes#include <sys/ctype.h> 36212367Smdf#include <sys/errno.h> 3769990Sdes#include <sys/kernel.h> 3869990Sdes#include <sys/malloc.h> 3969990Sdes#include <sys/systm.h> 4084097Sdes#include <sys/uio.h> 4169990Sdes#include <machine/stdarg.h> 4274840Sken#else /* _KERNEL */ 4384097Sdes#include <ctype.h> 44212367Smdf#include <errno.h> 4574840Sken#include <stdarg.h> 4688950Skbyanc#include <stdio.h> 4778340Sjlemon#include <stdlib.h> 4888950Skbyanc#include <string.h> 4974840Sken#endif /* _KERNEL */ 5069990Sdes 5184097Sdes#include <sys/sbuf.h> 5284097Sdes 5374840Sken#ifdef _KERNEL 54141616Sphkstatic MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 55255805Sdes#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO) 5689121Skbyanc#define SBFREE(buf) free(buf, M_SBUF) 5774840Sken#else /* _KERNEL */ 5889121Skbyanc#define KASSERT(e, m) 59255805Sdes#define SBMALLOC(size) calloc(1, size) 6089121Skbyanc#define SBFREE(buf) free(buf) 6174840Sken#endif /* _KERNEL */ 6269990Sdes 6371721Sdes/* 6471721Sdes * Predicates 6571721Sdes */ 6689121Skbyanc#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 6789121Skbyanc#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 6889121Skbyanc#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 6989121Skbyanc#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 70222004Sphk#define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) 7188950Skbyanc#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 72249377Strociny#define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) 7371721Sdes 7471721Sdes/* 7571721Sdes * Set / clear flags 7671721Sdes */ 7789121Skbyanc#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 7889121Skbyanc#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 7971721Sdes 8089121Skbyanc#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 81222004Sphk 82222004Sphk#ifdef PAGE_SIZE 8389121Skbyanc#define SBUF_MAXEXTENDSIZE PAGE_SIZE 8489121Skbyanc#define SBUF_MAXEXTENDINCR PAGE_SIZE 85222004Sphk#else 86222004Sphk#define SBUF_MAXEXTENDSIZE 4096 87222004Sphk#define SBUF_MAXEXTENDINCR 4096 88222004Sphk#endif 8988950Skbyanc 9071721Sdes/* 9171721Sdes * Debugging support 9271721Sdes */ 9374840Sken#if defined(_KERNEL) && defined(INVARIANTS) 94181462Sdes 9569990Sdesstatic void 9692664Speter_assert_sbuf_integrity(const char *fun, struct sbuf *s) 9769990Sdes{ 98181462Sdes 9969990Sdes KASSERT(s != NULL, 10073891Sdes ("%s called with a NULL sbuf pointer", fun)); 10169990Sdes KASSERT(s->s_buf != NULL, 10288950Skbyanc ("%s called with uninitialized or corrupt sbuf", fun)); 10369990Sdes KASSERT(s->s_len < s->s_size, 104221993Sphk ("wrote past end of sbuf (%jd >= %jd)", 105221993Sphk (intmax_t)s->s_len, (intmax_t)s->s_size)); 10669990Sdes} 10769990Sdes 10869990Sdesstatic void 10992664Speter_assert_sbuf_state(const char *fun, struct sbuf *s, int state) 11069990Sdes{ 111181462Sdes 11269990Sdes KASSERT((s->s_flags & SBUF_FINISHED) == state, 11373891Sdes ("%s called with %sfinished or corrupt sbuf", fun, 11469990Sdes (state ? "un" : ""))); 11569990Sdes} 116181462Sdes 11789121Skbyanc#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 11889121Skbyanc#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 119181462Sdes 12074840Sken#else /* _KERNEL && INVARIANTS */ 121181462Sdes 12289121Skbyanc#define assert_sbuf_integrity(s) do { } while (0) 12389121Skbyanc#define assert_sbuf_state(s, i) do { } while (0) 124181462Sdes 12574840Sken#endif /* _KERNEL && INVARIANTS */ 12669990Sdes 127212184Smdf#ifdef CTASSERT 128212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 129212180SmdfCTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 130212182Smdf#endif 131212180Smdf 13288950Skbyancstatic int 13388950Skbyancsbuf_extendsize(int size) 13488950Skbyanc{ 13588950Skbyanc int newsize; 13688950Skbyanc 137212180Smdf if (size < (int)SBUF_MAXEXTENDSIZE) { 138212180Smdf newsize = SBUF_MINEXTENDSIZE; 139212180Smdf while (newsize < size) 14088950Skbyanc newsize *= 2; 141212180Smdf } else { 142212180Smdf newsize = roundup2(size, SBUF_MAXEXTENDINCR); 14388950Skbyanc } 144212181Smdf KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 14588950Skbyanc return (newsize); 14688950Skbyanc} 14788950Skbyanc 14869990Sdes/* 14988950Skbyanc * Extend an sbuf. 15088950Skbyanc */ 15188950Skbyancstatic int 15288950Skbyancsbuf_extend(struct sbuf *s, int addlen) 15388950Skbyanc{ 15488950Skbyanc char *newbuf; 15588950Skbyanc int newsize; 15688950Skbyanc 15788950Skbyanc if (!SBUF_CANEXTEND(s)) 15888950Skbyanc return (-1); 15988950Skbyanc newsize = sbuf_extendsize(s->s_size + addlen); 160181462Sdes newbuf = SBMALLOC(newsize); 16188950Skbyanc if (newbuf == NULL) 16288950Skbyanc return (-1); 163222015Sphk memcpy(newbuf, s->s_buf, s->s_size); 16488950Skbyanc if (SBUF_ISDYNAMIC(s)) 16588950Skbyanc SBFREE(s->s_buf); 16688950Skbyanc else 16788950Skbyanc SBUF_SETFLAG(s, SBUF_DYNAMIC); 16888950Skbyanc s->s_buf = newbuf; 16988950Skbyanc s->s_size = newsize; 17088950Skbyanc return (0); 17188950Skbyanc} 17288950Skbyanc 17388950Skbyanc/* 174222015Sphk * Initialize the internals of an sbuf. 175222015Sphk * If buf is non-NULL, it points to a static or already-allocated string 176222015Sphk * big enough to hold at least length characters. 177222015Sphk */ 178222015Sphkstatic struct sbuf * 179222015Sphksbuf_newbuf(struct sbuf *s, char *buf, int length, int flags) 180222015Sphk{ 181222015Sphk 182222015Sphk memset(s, 0, sizeof(*s)); 183222015Sphk s->s_flags = flags; 184222015Sphk s->s_size = length; 185222015Sphk s->s_buf = buf; 186222015Sphk 187222015Sphk if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { 188224999Srwatson KASSERT(s->s_size >= 0, 189222015Sphk ("attempt to create a too small sbuf")); 190222015Sphk } 191222015Sphk 192222015Sphk if (s->s_buf != NULL) 193222015Sphk return (s); 194222015Sphk 195222015Sphk if ((flags & SBUF_AUTOEXTEND) != 0) 196222015Sphk s->s_size = sbuf_extendsize(s->s_size); 197222015Sphk 198222015Sphk s->s_buf = SBMALLOC(s->s_size); 199222015Sphk if (s->s_buf == NULL) 200222015Sphk return (NULL); 201222015Sphk SBUF_SETFLAG(s, SBUF_DYNAMIC); 202222015Sphk return (s); 203222015Sphk} 204222015Sphk 205222015Sphk/* 20669990Sdes * Initialize an sbuf. 20769990Sdes * If buf is non-NULL, it points to a static or already-allocated string 20869990Sdes * big enough to hold at least length characters. 20969990Sdes */ 21077989Sdesstruct sbuf * 21171721Sdessbuf_new(struct sbuf *s, char *buf, int length, int flags) 21269990Sdes{ 213181462Sdes 21471721Sdes KASSERT(length >= 0, 21571721Sdes ("attempt to create an sbuf of negative length (%d)", length)); 21688950Skbyanc KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 21788950Skbyanc ("%s called with invalid flags", __func__)); 21869990Sdes 21988950Skbyanc flags &= SBUF_USRFLAGMSK; 220222015Sphk if (s != NULL) 221222015Sphk return (sbuf_newbuf(s, buf, length, flags)); 222222015Sphk 223222015Sphk s = SBMALLOC(sizeof(*s)); 224222015Sphk if (s == NULL) 22577989Sdes return (NULL); 226222015Sphk if (sbuf_newbuf(s, buf, length, flags) == NULL) { 227222015Sphk SBFREE(s); 228222015Sphk return (NULL); 22977989Sdes } 230222015Sphk SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 23177989Sdes return (s); 23269990Sdes} 23369990Sdes 23484097Sdes#ifdef _KERNEL 23569990Sdes/* 23684097Sdes * Create an sbuf with uio data 23784097Sdes */ 23884097Sdesstruct sbuf * 23984097Sdessbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 24084097Sdes{ 241181462Sdes 24284097Sdes KASSERT(uio != NULL, 24387594Sobrien ("%s called with NULL uio pointer", __func__)); 24484097Sdes KASSERT(error != NULL, 24587594Sobrien ("%s called with NULL error pointer", __func__)); 24684097Sdes 24784097Sdes s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 24884097Sdes if (s == NULL) { 24984097Sdes *error = ENOMEM; 25084097Sdes return (NULL); 25184097Sdes } 25284097Sdes *error = uiomove(s->s_buf, uio->uio_resid, uio); 25384097Sdes if (*error != 0) { 25484097Sdes sbuf_delete(s); 25584097Sdes return (NULL); 25684097Sdes } 25784097Sdes s->s_len = s->s_size - 1; 258249377Strociny if (SBUF_ISSECTION(s)) 259249377Strociny s->s_sect_len = s->s_size - 1; 26084097Sdes *error = 0; 26184097Sdes return (s); 26284097Sdes} 26384097Sdes#endif 26484097Sdes 26584097Sdes/* 26688950Skbyanc * Clear an sbuf and reset its position. 26771721Sdes */ 26871721Sdesvoid 26971721Sdessbuf_clear(struct sbuf *s) 27071721Sdes{ 271181462Sdes 27271721Sdes assert_sbuf_integrity(s); 27371724Sdes /* don't care if it's finished or not */ 27471721Sdes 27571721Sdes SBUF_CLEARFLAG(s, SBUF_FINISHED); 276212367Smdf s->s_error = 0; 27771721Sdes s->s_len = 0; 278249377Strociny s->s_sect_len = 0; 27971721Sdes} 28071721Sdes 28171721Sdes/* 28288950Skbyanc * Set the sbuf's end position to an arbitrary value. 28388950Skbyanc * Effectively truncates the sbuf at the new position. 28469990Sdes */ 28569990Sdesint 286221993Sphksbuf_setpos(struct sbuf *s, ssize_t pos) 28769990Sdes{ 288181462Sdes 28969990Sdes assert_sbuf_integrity(s); 29069990Sdes assert_sbuf_state(s, 0); 291125937Sdes 29269990Sdes KASSERT(pos >= 0, 293221993Sphk ("attempt to seek to a negative position (%jd)", (intmax_t)pos)); 29469990Sdes KASSERT(pos < s->s_size, 295221993Sphk ("attempt to seek past end of sbuf (%jd >= %jd)", 296221993Sphk (intmax_t)pos, (intmax_t)s->s_size)); 297249377Strociny KASSERT(!SBUF_ISSECTION(s), 298249377Strociny ("attempt to seek when in a section")); 299125937Sdes 30069990Sdes if (pos < 0 || pos > s->s_len) 30169990Sdes return (-1); 30269990Sdes s->s_len = pos; 30369990Sdes return (0); 30469990Sdes} 30569990Sdes 30669990Sdes/* 307212367Smdf * Set up a drain function and argument on an sbuf to flush data to 308212367Smdf * when the sbuf buffer overflows. 309212367Smdf */ 310212367Smdfvoid 311212367Smdfsbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx) 312212367Smdf{ 313212367Smdf 314212367Smdf assert_sbuf_state(s, 0); 315212367Smdf assert_sbuf_integrity(s); 316212367Smdf KASSERT(func == s->s_drain_func || s->s_len == 0, 317212367Smdf ("Cannot change drain to %p on non-empty sbuf %p", func, s)); 318212367Smdf s->s_drain_func = func; 319212367Smdf s->s_drain_arg = ctx; 320212367Smdf} 321212367Smdf 322212367Smdf/* 323212367Smdf * Call the drain and process the return. 324212367Smdf */ 325212367Smdfstatic int 326212367Smdfsbuf_drain(struct sbuf *s) 327212367Smdf{ 328212367Smdf int len; 329212367Smdf 330212367Smdf KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); 331212425Smdf KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); 332212367Smdf len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len); 333212367Smdf if (len < 0) { 334212367Smdf s->s_error = -len; 335212367Smdf return (s->s_error); 336212367Smdf } 337212750Smdf KASSERT(len > 0 && len <= s->s_len, 338212750Smdf ("Bad drain amount %d for sbuf %p", len, s)); 339212367Smdf s->s_len -= len; 340212367Smdf /* 341212367Smdf * Fast path for the expected case where all the data was 342212367Smdf * drained. 343212367Smdf */ 344212367Smdf if (s->s_len == 0) 345212367Smdf return (0); 346212367Smdf /* 347212367Smdf * Move the remaining characters to the beginning of the 348212367Smdf * string. 349212367Smdf */ 350212367Smdf memmove(s->s_buf, s->s_buf + len, s->s_len); 351212367Smdf return (0); 352212367Smdf} 353212367Smdf 354212367Smdf/* 355212365Smdf * Append a byte to an sbuf. This is the core function for appending 356212365Smdf * to an sbuf and is the main place that deals with extending the 357212365Smdf * buffer and marking overflow. 358212365Smdf */ 359212365Smdfstatic void 360222004Sphksbuf_put_byte(struct sbuf *s, int c) 361212365Smdf{ 362212365Smdf 363212365Smdf assert_sbuf_integrity(s); 364212365Smdf assert_sbuf_state(s, 0); 365212365Smdf 366212425Smdf if (s->s_error != 0) 367212365Smdf return; 368212365Smdf if (SBUF_FREESPACE(s) <= 0) { 369222004Sphk /* 370212367Smdf * If there is a drain, use it, otherwise extend the 371212367Smdf * buffer. 372212367Smdf */ 373212367Smdf if (s->s_drain_func != NULL) 374212367Smdf (void)sbuf_drain(s); 375212367Smdf else if (sbuf_extend(s, 1) < 0) 376212425Smdf s->s_error = ENOMEM; 377212425Smdf if (s->s_error != 0) 378212365Smdf return; 379212365Smdf } 380212365Smdf s->s_buf[s->s_len++] = c; 381249377Strociny if (SBUF_ISSECTION(s)) 382249377Strociny s->s_sect_len++; 383212365Smdf} 384212365Smdf 385212365Smdf/* 38678077Sdes * Append a byte string to an sbuf. 38778077Sdes */ 38878077Sdesint 389131869Sdessbuf_bcat(struct sbuf *s, const void *buf, size_t len) 39078077Sdes{ 391131869Sdes const char *str = buf; 392212365Smdf const char *end = str + len; 393131868Sdes 39478077Sdes assert_sbuf_integrity(s); 39578077Sdes assert_sbuf_state(s, 0); 396125937Sdes 397212425Smdf if (s->s_error != 0) 39878077Sdes return (-1); 399212365Smdf for (; str < end; str++) { 400222004Sphk sbuf_put_byte(s, *str); 401212425Smdf if (s->s_error != 0) 402212365Smdf return (-1); 403222004Sphk } 40478077Sdes return (0); 40578077Sdes} 40678077Sdes 40778077Sdes#ifdef _KERNEL 40878077Sdes/* 40978077Sdes * Copy a byte string from userland into an sbuf. 41078077Sdes */ 41178077Sdesint 41278077Sdessbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 41378077Sdes{ 414181462Sdes 41578077Sdes assert_sbuf_integrity(s); 41678077Sdes assert_sbuf_state(s, 0); 417212367Smdf KASSERT(s->s_drain_func == NULL, 418212367Smdf ("Nonsensical copyin to sbuf %p with a drain", s)); 41978077Sdes 420212425Smdf if (s->s_error != 0) 42178077Sdes return (-1); 42278077Sdes if (len == 0) 42378077Sdes return (0); 42488950Skbyanc if (len > SBUF_FREESPACE(s)) { 42588950Skbyanc sbuf_extend(s, len - SBUF_FREESPACE(s)); 426212183Smdf if (SBUF_FREESPACE(s) < len) 427212183Smdf len = SBUF_FREESPACE(s); 42888950Skbyanc } 42978092Sdes if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 43078092Sdes return (-1); 43178095Sdes s->s_len += len; 432125937Sdes 43378077Sdes return (0); 43478077Sdes} 43578077Sdes#endif 43678077Sdes 43778077Sdes/* 43878077Sdes * Copy a byte string into an sbuf. 43978077Sdes */ 44078077Sdesint 441131869Sdessbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 44278077Sdes{ 443181462Sdes 44478077Sdes assert_sbuf_integrity(s); 44578077Sdes assert_sbuf_state(s, 0); 446125937Sdes 44778077Sdes sbuf_clear(s); 448131869Sdes return (sbuf_bcat(s, buf, len)); 44978077Sdes} 45078077Sdes 45178077Sdes/* 45269990Sdes * Append a string to an sbuf. 45369990Sdes */ 45469990Sdesint 45574840Skensbuf_cat(struct sbuf *s, const char *str) 45669990Sdes{ 457181462Sdes 45869990Sdes assert_sbuf_integrity(s); 45969990Sdes assert_sbuf_state(s, 0); 460125937Sdes 461212425Smdf if (s->s_error != 0) 46269990Sdes return (-1); 463125937Sdes 464212183Smdf while (*str != '\0') { 465222004Sphk sbuf_put_byte(s, *str++); 466212425Smdf if (s->s_error != 0) 467212365Smdf return (-1); 46888950Skbyanc } 46969990Sdes return (0); 47069990Sdes} 47169990Sdes 47278077Sdes#ifdef _KERNEL 47369990Sdes/* 47488950Skbyanc * Append a string from userland to an sbuf. 47578077Sdes */ 47678077Sdesint 47778077Sdessbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 47878077Sdes{ 47978077Sdes size_t done; 480125937Sdes 48178077Sdes assert_sbuf_integrity(s); 48278077Sdes assert_sbuf_state(s, 0); 483212367Smdf KASSERT(s->s_drain_func == NULL, 484212367Smdf ("Nonsensical copyin to sbuf %p with a drain", s)); 48578077Sdes 486212425Smdf if (s->s_error != 0) 48778077Sdes return (-1); 48878077Sdes 48988950Skbyanc if (len == 0) 49088950Skbyanc len = SBUF_FREESPACE(s); /* XXX return 0? */ 49188950Skbyanc if (len > SBUF_FREESPACE(s)) { 49288950Skbyanc sbuf_extend(s, len); 493212183Smdf if (SBUF_FREESPACE(s) < len) 494212183Smdf len = SBUF_FREESPACE(s); 49588950Skbyanc } 49678077Sdes switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 49778077Sdes case ENAMETOOLONG: 498212425Smdf s->s_error = ENOMEM; 49978077Sdes /* fall through */ 50078077Sdes case 0: 50178077Sdes s->s_len += done - 1; 502249377Strociny if (SBUF_ISSECTION(s)) 503249377Strociny s->s_sect_len += done - 1; 50478077Sdes break; 50578077Sdes default: 50678077Sdes return (-1); /* XXX */ 50778077Sdes } 508125937Sdes 509153678Sphk return (done); 51078077Sdes} 51178077Sdes#endif 51278077Sdes 51378077Sdes/* 51469990Sdes * Copy a string into an sbuf. 51569990Sdes */ 51669990Sdesint 51774840Skensbuf_cpy(struct sbuf *s, const char *str) 51869990Sdes{ 519181462Sdes 52069990Sdes assert_sbuf_integrity(s); 52169990Sdes assert_sbuf_state(s, 0); 522125937Sdes 52371721Sdes sbuf_clear(s); 52469990Sdes return (sbuf_cat(s, str)); 52569990Sdes} 52669990Sdes 52769990Sdes/* 52888950Skbyanc * Format the given argument list and append the resulting string to an sbuf. 52969990Sdes */ 530212365Smdf#ifdef _KERNEL 531222004Sphk 532222004Sphk/* 533222004Sphk * Append a non-NUL character to an sbuf. This prototype signature is 534222004Sphk * suitable for use with kvprintf(9). 535222004Sphk */ 536222004Sphkstatic void 537222004Sphksbuf_putc_func(int c, void *arg) 538222004Sphk{ 539222004Sphk 540222004Sphk if (c != '\0') 541222004Sphk sbuf_put_byte(arg, c); 542222004Sphk} 543222004Sphk 54469990Sdesint 54588950Skbyancsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 54669990Sdes{ 547212365Smdf 548212365Smdf assert_sbuf_integrity(s); 549212365Smdf assert_sbuf_state(s, 0); 550212365Smdf 551212365Smdf KASSERT(fmt != NULL, 552212365Smdf ("%s called with a NULL format string", __func__)); 553212365Smdf 554212365Smdf (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap); 555212425Smdf if (s->s_error != 0) 556212365Smdf return (-1); 557212365Smdf return (0); 558212365Smdf} 559212365Smdf#else /* !_KERNEL */ 560212365Smdfint 561212365Smdfsbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 562212365Smdf{ 563115311Speter va_list ap_copy; 564212367Smdf int error, len; 56569990Sdes 56669990Sdes assert_sbuf_integrity(s); 56769990Sdes assert_sbuf_state(s, 0); 56888950Skbyanc 56969990Sdes KASSERT(fmt != NULL, 57087594Sobrien ("%s called with a NULL format string", __func__)); 57188950Skbyanc 572212425Smdf if (s->s_error != 0) 57369990Sdes return (-1); 57469990Sdes 575212365Smdf /* 576212365Smdf * For the moment, there is no way to get vsnprintf(3) to hand 577212365Smdf * back a character at a time, to push everything into 578212365Smdf * sbuf_putc_func() as was done for the kernel. 579212367Smdf * 580212367Smdf * In userspace, while drains are useful, there's generally 581212367Smdf * not a problem attempting to malloc(3) on out of space. So 582212367Smdf * expand a userland sbuf if there is not enough room for the 583212367Smdf * data produced by sbuf_[v]printf(3). 584212365Smdf */ 585212365Smdf 586212367Smdf error = 0; 58788950Skbyanc do { 588115311Speter va_copy(ap_copy, ap); 58988950Skbyanc len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 590115311Speter fmt, ap_copy); 591115311Speter va_end(ap_copy); 59269990Sdes 593212367Smdf if (SBUF_FREESPACE(s) >= len) 594212367Smdf break; 595212367Smdf /* Cannot print with the current available space. */ 596212367Smdf if (s->s_drain_func != NULL && s->s_len > 0) 597212367Smdf error = sbuf_drain(s); 598212367Smdf else 599212367Smdf error = sbuf_extend(s, len - SBUF_FREESPACE(s)); 600212367Smdf } while (error == 0); 601212367Smdf 60274840Sken /* 60374840Sken * s->s_len is the length of the string, without the terminating nul. 60474840Sken * When updating s->s_len, we must subtract 1 from the length that 60574840Sken * we passed into vsnprintf() because that length includes the 60674840Sken * terminating nul. 60774840Sken * 60874840Sken * vsnprintf() returns the amount that would have been copied, 609212183Smdf * given sufficient space, so don't over-increment s_len. 61074840Sken */ 611212183Smdf if (SBUF_FREESPACE(s) < len) 612212183Smdf len = SBUF_FREESPACE(s); 613212183Smdf s->s_len += len; 614249377Strociny if (SBUF_ISSECTION(s)) 615249377Strociny s->s_sect_len += len; 61689646Sphk if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 617212425Smdf s->s_error = ENOMEM; 61874840Sken 61969990Sdes KASSERT(s->s_len < s->s_size, 62069990Sdes ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 62169990Sdes 622212425Smdf if (s->s_error != 0) 62369990Sdes return (-1); 62469990Sdes return (0); 62569990Sdes} 626212365Smdf#endif /* _KERNEL */ 62769990Sdes 62869990Sdes/* 62988950Skbyanc * Format the given arguments and append the resulting string to an sbuf. 63088950Skbyanc */ 63188950Skbyancint 63288950Skbyancsbuf_printf(struct sbuf *s, const char *fmt, ...) 63388950Skbyanc{ 63488950Skbyanc va_list ap; 63588950Skbyanc int result; 63688950Skbyanc 63788950Skbyanc va_start(ap, fmt); 63888950Skbyanc result = sbuf_vprintf(s, fmt, ap); 63988950Skbyanc va_end(ap); 640181462Sdes return (result); 64188950Skbyanc} 64288950Skbyanc 64388950Skbyanc/* 64469990Sdes * Append a character to an sbuf. 64569990Sdes */ 64669990Sdesint 64769990Sdessbuf_putc(struct sbuf *s, int c) 64869990Sdes{ 649181462Sdes 650222004Sphk sbuf_put_byte(s, c); 651212425Smdf if (s->s_error != 0) 65269990Sdes return (-1); 65369990Sdes return (0); 65469990Sdes} 65569990Sdes 65669990Sdes/* 65788950Skbyanc * Trim whitespace characters from end of an sbuf. 65884097Sdes */ 65984097Sdesint 66084097Sdessbuf_trim(struct sbuf *s) 66184097Sdes{ 662181462Sdes 66384097Sdes assert_sbuf_integrity(s); 66484097Sdes assert_sbuf_state(s, 0); 665212367Smdf KASSERT(s->s_drain_func == NULL, 666212367Smdf ("%s makes no sense on sbuf %p with drain", __func__, s)); 667125937Sdes 668212425Smdf if (s->s_error != 0) 66984097Sdes return (-1); 670125937Sdes 671249377Strociny while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) { 67284097Sdes --s->s_len; 673249377Strociny if (SBUF_ISSECTION(s)) 674249377Strociny s->s_sect_len--; 675249377Strociny } 67684097Sdes 67784097Sdes return (0); 67884097Sdes} 67984097Sdes 68084097Sdes/* 681212425Smdf * Check if an sbuf has an error. 68271721Sdes */ 68371721Sdesint 684221993Sphksbuf_error(const struct sbuf *s) 68571721Sdes{ 686181462Sdes 687212425Smdf return (s->s_error); 68871721Sdes} 68971721Sdes 69071721Sdes/* 69169990Sdes * Finish off an sbuf. 69269990Sdes */ 693212367Smdfint 69469990Sdessbuf_finish(struct sbuf *s) 69569990Sdes{ 696181462Sdes 69769990Sdes assert_sbuf_integrity(s); 69869990Sdes assert_sbuf_state(s, 0); 699125937Sdes 700212367Smdf if (s->s_drain_func != NULL) { 701222004Sphk while (s->s_len > 0 && s->s_error == 0) 702222004Sphk s->s_error = sbuf_drain(s); 703212425Smdf } 70473891Sdes s->s_buf[s->s_len] = '\0'; 70569990Sdes SBUF_SETFLAG(s, SBUF_FINISHED); 706212367Smdf#ifdef _KERNEL 707222004Sphk return (s->s_error); 708212367Smdf#else 709250706Sjh if (s->s_error != 0) { 710250706Sjh errno = s->s_error; 711222004Sphk return (-1); 712250706Sjh } 713222004Sphk return (0); 714212367Smdf#endif 71569990Sdes} 71669990Sdes 71769990Sdes/* 71869990Sdes * Return a pointer to the sbuf data. 71969990Sdes */ 72069990Sdeschar * 72169990Sdessbuf_data(struct sbuf *s) 72269990Sdes{ 723181462Sdes 72469990Sdes assert_sbuf_integrity(s); 72569990Sdes assert_sbuf_state(s, SBUF_FINISHED); 726212367Smdf KASSERT(s->s_drain_func == NULL, 727212367Smdf ("%s makes no sense on sbuf %p with drain", __func__, s)); 728125937Sdes 729181462Sdes return (s->s_buf); 73069990Sdes} 73169990Sdes 73269990Sdes/* 73369990Sdes * Return the length of the sbuf data. 73469990Sdes */ 735221993Sphkssize_t 73669990Sdessbuf_len(struct sbuf *s) 73769990Sdes{ 738181462Sdes 73969990Sdes assert_sbuf_integrity(s); 74071724Sdes /* don't care if it's finished or not */ 741212367Smdf KASSERT(s->s_drain_func == NULL, 742212367Smdf ("%s makes no sense on sbuf %p with drain", __func__, s)); 743125937Sdes 744212425Smdf if (s->s_error != 0) 74571721Sdes return (-1); 746181462Sdes return (s->s_len); 74769990Sdes} 74869990Sdes 74969990Sdes/* 75069990Sdes * Clear an sbuf, free its buffer if necessary. 75169990Sdes */ 75269990Sdesvoid 75369990Sdessbuf_delete(struct sbuf *s) 75469990Sdes{ 75588219Sdillon int isdyn; 75688219Sdillon 75769990Sdes assert_sbuf_integrity(s); 75869990Sdes /* don't care if it's finished or not */ 759125937Sdes 76069990Sdes if (SBUF_ISDYNAMIC(s)) 76174840Sken SBFREE(s->s_buf); 76288219Sdillon isdyn = SBUF_ISDYNSTRUCT(s); 763222015Sphk memset(s, 0, sizeof(*s)); 76488219Sdillon if (isdyn) 76577989Sdes SBFREE(s); 76669990Sdes} 767104449Sphk 768104449Sphk/* 769104449Sphk * Check if an sbuf has been finished. 770104449Sphk */ 771104449Sphkint 772221993Sphksbuf_done(const struct sbuf *s) 773104449Sphk{ 774104449Sphk 775181462Sdes return (SBUF_ISFINISHED(s)); 776104449Sphk} 777249377Strociny 778249377Strociny/* 779249377Strociny * Start a section. 780249377Strociny */ 781249377Strocinyvoid 782249377Strocinysbuf_start_section(struct sbuf *s, ssize_t *old_lenp) 783249377Strociny{ 784249377Strociny 785249377Strociny assert_sbuf_integrity(s); 786249377Strociny assert_sbuf_state(s, 0); 787249377Strociny 788249377Strociny if (!SBUF_ISSECTION(s)) { 789249377Strociny KASSERT(s->s_sect_len == 0, 790249377Strociny ("s_sect_len != 0 when starting a section")); 791249377Strociny if (old_lenp != NULL) 792249377Strociny *old_lenp = -1; 793249377Strociny SBUF_SETFLAG(s, SBUF_INSECTION); 794249377Strociny } else { 795249377Strociny KASSERT(old_lenp != NULL, 796249377Strociny ("s_sect_len should be saved when starting a subsection")); 797249377Strociny *old_lenp = s->s_sect_len; 798249377Strociny s->s_sect_len = 0; 799249377Strociny } 800249377Strociny} 801249377Strociny 802249377Strociny/* 803249377Strociny * End the section padding to the specified length with the specified 804249377Strociny * character. 805249377Strociny */ 806249377Strocinyssize_t 807249377Strocinysbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c) 808249377Strociny{ 809249377Strociny ssize_t len; 810249377Strociny 811249377Strociny assert_sbuf_integrity(s); 812249377Strociny assert_sbuf_state(s, 0); 813249377Strociny KASSERT(SBUF_ISSECTION(s), 814249377Strociny ("attempt to end a section when not in a section")); 815249377Strociny 816249377Strociny if (pad > 1) { 817249377Strociny len = roundup(s->s_sect_len, pad) - s->s_sect_len; 818249377Strociny for (; s->s_error == 0 && len > 0; len--) 819249377Strociny sbuf_put_byte(s, c); 820249377Strociny } 821249377Strociny len = s->s_sect_len; 822249377Strociny if (old_len == -1) { 823249377Strociny s->s_sect_len = 0; 824249377Strociny SBUF_CLEARFLAG(s, SBUF_INSECTION); 825249377Strociny } else { 826249377Strociny s->s_sect_len += old_len; 827249377Strociny } 828249377Strociny if (s->s_error != 0) 829249377Strociny return (-1); 830249377Strociny return (len); 831249377Strociny} 832