subr_sbuf.c revision 89121
1239281Sgonzo/*- 2239281Sgonzo * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Co�dan Sm�rgrav 3239281Sgonzo * All rights reserved. 4239281Sgonzo * 5239281Sgonzo * Redistribution and use in source and binary forms, with or without 6239281Sgonzo * modification, are permitted provided that the following conditions 7239281Sgonzo * are met: 8239281Sgonzo * 1. Redistributions of source code must retain the above copyright 9239281Sgonzo * notice, this list of conditions and the following disclaimer 10239281Sgonzo * in this position and unchanged. 11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12239281Sgonzo * notice, this list of conditions and the following disclaimer in the 13239281Sgonzo * documentation and/or other materials provided with the distribution. 14239281Sgonzo * 3. The name of the author may not be used to endorse or promote products 15239281Sgonzo * derived from this software without specific prior written permission. 16239281Sgonzo * 17239281Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20239281Sgonzo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21239281Sgonzo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22239281Sgonzo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23239281Sgonzo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24239281Sgonzo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25239281Sgonzo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26239281Sgonzo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27239281Sgonzo * 28239281Sgonzo * $FreeBSD: head/sys/kern/subr_sbuf.c 89121 2002-01-09 07:29:28Z kbyanc $ 29239281Sgonzo */ 30239281Sgonzo 31239281Sgonzo#include <sys/param.h> 32239281Sgonzo 33239281Sgonzo#ifdef _KERNEL 34239281Sgonzo#include <sys/ctype.h> 35239281Sgonzo#include <sys/kernel.h> 36239281Sgonzo#include <sys/malloc.h> 37239281Sgonzo#include <sys/systm.h> 38239281Sgonzo#include <sys/uio.h> 39239281Sgonzo#include <machine/stdarg.h> 40239281Sgonzo#else /* _KERNEL */ 41239281Sgonzo#include <ctype.h> 42239281Sgonzo#include <stdarg.h> 43239281Sgonzo#include <stdio.h> 44239281Sgonzo#include <stdlib.h> 45239281Sgonzo#include <string.h> 46239281Sgonzo#endif /* _KERNEL */ 47239281Sgonzo 48239281Sgonzo#include <sys/sbuf.h> 49239281Sgonzo 50239281Sgonzo#ifdef _KERNEL 51239281SgonzoMALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 52239281Sgonzo#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK) 53239281Sgonzo#define SBFREE(buf) free(buf, M_SBUF) 54239281Sgonzo#else /* _KERNEL */ 55239281Sgonzo#define KASSERT(e, m) 56239281Sgonzo#define SBMALLOC(size) malloc(size) 57239281Sgonzo#define SBFREE(buf) free(buf) 58239281Sgonzo#define min(x,y) MIN(x,y) 59239281Sgonzo#endif /* _KERNEL */ 60239281Sgonzo 61239281Sgonzo/* 62239281Sgonzo * Predicates 63239281Sgonzo */ 64239281Sgonzo#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 65239281Sgonzo#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 66239281Sgonzo#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 67239281Sgonzo#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED) 68239281Sgonzo#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 69239281Sgonzo#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1) 70239281Sgonzo#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 71239281Sgonzo 72239281Sgonzo/* 73239281Sgonzo * Set / clear flags 74239281Sgonzo */ 75239281Sgonzo#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 76239281Sgonzo#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 77239281Sgonzo 78239281Sgonzo#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 79239281Sgonzo#define SBUF_MAXEXTENDSIZE PAGE_SIZE 80239281Sgonzo#define SBUF_MAXEXTENDINCR PAGE_SIZE 81239281Sgonzo 82239281Sgonzo/* 83239281Sgonzo * Debugging support 84239281Sgonzo */ 85239281Sgonzo#if defined(_KERNEL) && defined(INVARIANTS) 86239281Sgonzostatic void 87239281Sgonzo_assert_sbuf_integrity(char *fun, struct sbuf *s) 88239281Sgonzo{ 89239281Sgonzo KASSERT(s != NULL, 90239281Sgonzo ("%s called with a NULL sbuf pointer", fun)); 91239281Sgonzo KASSERT(s->s_buf != NULL, 92239281Sgonzo ("%s called with uninitialized or corrupt sbuf", fun)); 93239281Sgonzo KASSERT(s->s_len < s->s_size, 94239281Sgonzo ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 95239281Sgonzo} 96239281Sgonzo 97239281Sgonzostatic void 98239281Sgonzo_assert_sbuf_state(char *fun, struct sbuf *s, int state) 99239281Sgonzo{ 100239281Sgonzo KASSERT((s->s_flags & SBUF_FINISHED) == state, 101239281Sgonzo ("%s called with %sfinished or corrupt sbuf", fun, 102239281Sgonzo (state ? "un" : ""))); 103239281Sgonzo} 104239281Sgonzo#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 105239281Sgonzo#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 106239281Sgonzo#else /* _KERNEL && INVARIANTS */ 107239281Sgonzo#define assert_sbuf_integrity(s) do { } while (0) 108239281Sgonzo#define assert_sbuf_state(s, i) do { } while (0) 109239281Sgonzo#endif /* _KERNEL && INVARIANTS */ 110239281Sgonzo 111239281Sgonzostatic int 112239281Sgonzosbuf_extendsize(int size) 113239281Sgonzo{ 114239281Sgonzo int newsize; 115239281Sgonzo 116239281Sgonzo newsize = SBUF_MINEXTENDSIZE; 117239281Sgonzo while (newsize < size) { 118239281Sgonzo if (newsize < SBUF_MAXEXTENDSIZE) 119239281Sgonzo newsize *= 2; 120239281Sgonzo else 121239281Sgonzo newsize += SBUF_MAXEXTENDINCR; 122239281Sgonzo } 123239281Sgonzo 124239281Sgonzo return (newsize); 125239281Sgonzo} 126239281Sgonzo 127239281Sgonzo 128239281Sgonzo/* 129239281Sgonzo * Extend an sbuf. 130239281Sgonzo */ 131239281Sgonzostatic int 132239281Sgonzosbuf_extend(struct sbuf *s, int addlen) 133239281Sgonzo{ 134239281Sgonzo char *newbuf; 135239281Sgonzo int newsize; 136239281Sgonzo 137239281Sgonzo if (!SBUF_CANEXTEND(s)) 138239281Sgonzo return (-1); 139239281Sgonzo 140239281Sgonzo newsize = sbuf_extendsize(s->s_size + addlen); 141239281Sgonzo newbuf = (char *)SBMALLOC(newsize); 142239281Sgonzo if (newbuf == NULL) 143239281Sgonzo return (-1); 144239281Sgonzo bcopy(s->s_buf, newbuf, s->s_size); 145239281Sgonzo if (SBUF_ISDYNAMIC(s)) 146239281Sgonzo SBFREE(s->s_buf); 147239281Sgonzo else 148239281Sgonzo SBUF_SETFLAG(s, SBUF_DYNAMIC); 149239281Sgonzo s->s_buf = newbuf; 150239281Sgonzo s->s_size = newsize; 151239281Sgonzo return (0); 152239281Sgonzo} 153239281Sgonzo 154239281Sgonzo/* 155239281Sgonzo * Initialize an sbuf. 156239281Sgonzo * If buf is non-NULL, it points to a static or already-allocated string 157245672Skientzle * big enough to hold at least length characters. 158245672Skientzle */ 159239281Sgonzostruct sbuf * 160245672Skientzlesbuf_new(struct sbuf *s, char *buf, int length, int flags) 161239281Sgonzo{ 162239281Sgonzo KASSERT(length >= 0, 163239281Sgonzo ("attempt to create an sbuf of negative length (%d)", length)); 164239281Sgonzo KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 165252229Srpaulo ("%s called with invalid flags", __func__)); 166252229Srpaulo 167252229Srpaulo flags &= SBUF_USRFLAGMSK; 168239281Sgonzo if (s == NULL) { 169239281Sgonzo s = (struct sbuf *)SBMALLOC(sizeof *s); 170239281Sgonzo if (s == NULL) 171239281Sgonzo return (NULL); 172239281Sgonzo bzero(s, sizeof *s); 173239281Sgonzo s->s_flags = flags; 174239281Sgonzo SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 175239281Sgonzo } else { 176239281Sgonzo bzero(s, sizeof *s); 177239281Sgonzo s->s_flags = flags; 178239281Sgonzo } 179239281Sgonzo s->s_size = length; 180239281Sgonzo if (buf) { 181239281Sgonzo s->s_buf = buf; 182239281Sgonzo return (s); 183239281Sgonzo } 184239281Sgonzo if (flags & SBUF_AUTOEXTEND) 185239281Sgonzo s->s_size = sbuf_extendsize(s->s_size); 186239281Sgonzo s->s_buf = (char *)SBMALLOC(s->s_size); 187239281Sgonzo if (s->s_buf == NULL) { 188239281Sgonzo if (SBUF_ISDYNSTRUCT(s)) 189239281Sgonzo SBFREE(s); 190239281Sgonzo return (NULL); 191239281Sgonzo } 192239281Sgonzo SBUF_SETFLAG(s, SBUF_DYNAMIC); 193239281Sgonzo return (s); 194239281Sgonzo} 195239281Sgonzo 196239281Sgonzo#ifdef _KERNEL 197239281Sgonzo/* 198239281Sgonzo * Create an sbuf with uio data 199239281Sgonzo */ 200239281Sgonzostruct sbuf * 201239281Sgonzosbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 202239281Sgonzo{ 203239281Sgonzo KASSERT(uio != NULL, 204239281Sgonzo ("%s called with NULL uio pointer", __func__)); 205239281Sgonzo KASSERT(error != NULL, 206239281Sgonzo ("%s called with NULL error pointer", __func__)); 207239281Sgonzo 208240518Seadler s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 209239281Sgonzo if (s == NULL) { 210239281Sgonzo *error = ENOMEM; 211239281Sgonzo return (NULL); 212239281Sgonzo } 213239281Sgonzo *error = uiomove(s->s_buf, uio->uio_resid, uio); 214239281Sgonzo if (*error != 0) { 215239281Sgonzo sbuf_delete(s); 216239281Sgonzo return (NULL); 217239281Sgonzo } 218239281Sgonzo s->s_len = s->s_size - 1; 219239281Sgonzo *error = 0; 220239281Sgonzo return (s); 221239281Sgonzo} 222239281Sgonzo#endif 223239281Sgonzo 224239281Sgonzo/* 225239281Sgonzo * Clear an sbuf and reset its position. 226239281Sgonzo */ 227239281Sgonzovoid 228239281Sgonzosbuf_clear(struct sbuf *s) 229239281Sgonzo{ 230239281Sgonzo assert_sbuf_integrity(s); 231239281Sgonzo /* don't care if it's finished or not */ 232239281Sgonzo 233239281Sgonzo SBUF_CLEARFLAG(s, SBUF_FINISHED); 234239281Sgonzo SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 235239281Sgonzo s->s_len = 0; 236239281Sgonzo} 237239281Sgonzo 238239281Sgonzo/* 239239281Sgonzo * Set the sbuf's end position to an arbitrary value. 240239281Sgonzo * Effectively truncates the sbuf at the new position. 241239281Sgonzo */ 242239281Sgonzoint 243239281Sgonzosbuf_setpos(struct sbuf *s, int pos) 244239281Sgonzo{ 245239281Sgonzo assert_sbuf_integrity(s); 246239281Sgonzo assert_sbuf_state(s, 0); 247239281Sgonzo 248239281Sgonzo KASSERT(pos >= 0, 249239281Sgonzo ("attempt to seek to a negative position (%d)", pos)); 250239281Sgonzo KASSERT(pos < s->s_size, 251239281Sgonzo ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size)); 252239281Sgonzo 253239281Sgonzo if (pos < 0 || pos > s->s_len) 254239281Sgonzo return (-1); 255239281Sgonzo s->s_len = pos; 256239281Sgonzo return (0); 257239281Sgonzo} 258239281Sgonzo 259239281Sgonzo/* 260239281Sgonzo * Append a byte string to an sbuf. 261239281Sgonzo */ 262239281Sgonzoint 263239281Sgonzosbuf_bcat(struct sbuf *s, const char *str, size_t len) 264239281Sgonzo{ 265239281Sgonzo assert_sbuf_integrity(s); 266239281Sgonzo assert_sbuf_state(s, 0); 267239281Sgonzo 268239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 269239281Sgonzo return (-1); 270239281Sgonzo 271239281Sgonzo while (len--) { 272239281Sgonzo if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0) 273239281Sgonzo break; 274239281Sgonzo s->s_buf[s->s_len++] = *str++; 275239281Sgonzo } 276239281Sgonzo if (len) { 277239281Sgonzo SBUF_SETFLAG(s, SBUF_OVERFLOWED); 278239281Sgonzo return (-1); 279239281Sgonzo } 280239281Sgonzo return (0); 281239281Sgonzo} 282239281Sgonzo 283239281Sgonzo#ifdef _KERNEL 284239281Sgonzo/* 285239281Sgonzo * Copy a byte string from userland into an sbuf. 286239281Sgonzo */ 287239281Sgonzoint 288239281Sgonzosbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 289239281Sgonzo{ 290239281Sgonzo assert_sbuf_integrity(s); 291239281Sgonzo assert_sbuf_state(s, 0); 292239281Sgonzo 293239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 294239281Sgonzo return (-1); 295239281Sgonzo 296239281Sgonzo if (len == 0) 297239281Sgonzo return (0); 298239281Sgonzo if (len > SBUF_FREESPACE(s)) { 299239281Sgonzo sbuf_extend(s, len - SBUF_FREESPACE(s)); 300239281Sgonzo len = min(len, SBUF_FREESPACE(s)); 301239281Sgonzo } 302239281Sgonzo if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 303239281Sgonzo return (-1); 304239281Sgonzo s->s_len += len; 305239281Sgonzo 306239281Sgonzo return (0); 307239281Sgonzo} 308239281Sgonzo#endif 309239281Sgonzo 310239281Sgonzo/* 311239281Sgonzo * Copy a byte string into an sbuf. 312239281Sgonzo */ 313239281Sgonzoint 314239281Sgonzosbuf_bcpy(struct sbuf *s, const char *str, size_t len) 315239281Sgonzo{ 316239281Sgonzo assert_sbuf_integrity(s); 317239281Sgonzo assert_sbuf_state(s, 0); 318239281Sgonzo 319239281Sgonzo sbuf_clear(s); 320239281Sgonzo return (sbuf_bcat(s, str, len)); 321239281Sgonzo} 322239281Sgonzo 323239281Sgonzo/* 324239281Sgonzo * Append a string to an sbuf. 325239281Sgonzo */ 326239281Sgonzoint 327239281Sgonzosbuf_cat(struct sbuf *s, const char *str) 328239281Sgonzo{ 329239281Sgonzo assert_sbuf_integrity(s); 330239281Sgonzo assert_sbuf_state(s, 0); 331239281Sgonzo 332239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 333239281Sgonzo return (-1); 334239281Sgonzo 335239281Sgonzo while (*str) { 336239281Sgonzo if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0) 337239281Sgonzo break; 338239281Sgonzo s->s_buf[s->s_len++] = *str++; 339239281Sgonzo } 340239281Sgonzo if (*str) { 341239281Sgonzo SBUF_SETFLAG(s, SBUF_OVERFLOWED); 342239281Sgonzo return (-1); 343239281Sgonzo } 344239281Sgonzo return (0); 345239281Sgonzo} 346239281Sgonzo 347239281Sgonzo#ifdef _KERNEL 348239281Sgonzo/* 349239281Sgonzo * Append a string from userland to an sbuf. 350239281Sgonzo */ 351239281Sgonzoint 352239281Sgonzosbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 353239281Sgonzo{ 354239281Sgonzo size_t done; 355239281Sgonzo 356239281Sgonzo assert_sbuf_integrity(s); 357239281Sgonzo assert_sbuf_state(s, 0); 358239281Sgonzo 359239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 360239281Sgonzo return (-1); 361239281Sgonzo 362239281Sgonzo if (len == 0) 363239281Sgonzo len = SBUF_FREESPACE(s); /* XXX return 0? */ 364239281Sgonzo if (len > SBUF_FREESPACE(s)) { 365239281Sgonzo sbuf_extend(s, len); 366239281Sgonzo len = min(len, SBUF_FREESPACE(s)); 367239281Sgonzo } 368239281Sgonzo switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 369239281Sgonzo case ENAMETOOLONG: 370239281Sgonzo SBUF_SETFLAG(s, SBUF_OVERFLOWED); 371239281Sgonzo /* fall through */ 372239281Sgonzo case 0: 373239281Sgonzo s->s_len += done - 1; 374239281Sgonzo break; 375239281Sgonzo default: 376239281Sgonzo return (-1); /* XXX */ 377239281Sgonzo } 378239281Sgonzo 379239281Sgonzo return (0); 380239281Sgonzo} 381239281Sgonzo#endif 382239281Sgonzo 383239281Sgonzo/* 384239281Sgonzo * Copy a string into an sbuf. 385239281Sgonzo */ 386239281Sgonzoint 387239281Sgonzosbuf_cpy(struct sbuf *s, const char *str) 388239281Sgonzo{ 389239281Sgonzo assert_sbuf_integrity(s); 390239281Sgonzo assert_sbuf_state(s, 0); 391239281Sgonzo 392239281Sgonzo sbuf_clear(s); 393239281Sgonzo return (sbuf_cat(s, str)); 394239281Sgonzo} 395239281Sgonzo 396239281Sgonzo/* 397245672Skientzle * Format the given argument list and append the resulting string to an sbuf. 398239281Sgonzo */ 399239281Sgonzoint 400239281Sgonzosbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 401239281Sgonzo{ 402245672Skientzle int len; 403245672Skientzle 404245672Skientzle assert_sbuf_integrity(s); 405245672Skientzle assert_sbuf_state(s, 0); 406245672Skientzle 407239281Sgonzo KASSERT(fmt != NULL, 408239281Sgonzo ("%s called with a NULL format string", __func__)); 409239281Sgonzo 410239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 411239281Sgonzo return (-1); 412239281Sgonzo 413239281Sgonzo do { 414239281Sgonzo len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 415239281Sgonzo fmt, ap); 416239281Sgonzo } while (len > SBUF_FREESPACE(s) && 417239281Sgonzo sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0); 418239281Sgonzo 419239281Sgonzo /* 420239281Sgonzo * s->s_len is the length of the string, without the terminating nul. 421266152Sian * When updating s->s_len, we must subtract 1 from the length that 422266152Sian * we passed into vsnprintf() because that length includes the 423266152Sian * terminating nul. 424266152Sian * 425239281Sgonzo * vsnprintf() returns the amount that would have been copied, 426239281Sgonzo * given sufficient space, hence the min() calculation below. 427239281Sgonzo */ 428239281Sgonzo s->s_len += min(len, SBUF_FREESPACE(s)); 429239281Sgonzo if (!SBUF_HASROOM(s)) 430239281Sgonzo SBUF_SETFLAG(s, SBUF_OVERFLOWED); 431239281Sgonzo 432239281Sgonzo KASSERT(s->s_len < s->s_size, 433239281Sgonzo ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 434239281Sgonzo 435239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 436239281Sgonzo return (-1); 437239281Sgonzo return (0); 438239281Sgonzo} 439239281Sgonzo 440239281Sgonzo/* 441239281Sgonzo * Format the given arguments and append the resulting string to an sbuf. 442239281Sgonzo */ 443239281Sgonzoint 444239281Sgonzosbuf_printf(struct sbuf *s, const char *fmt, ...) 445239281Sgonzo{ 446239281Sgonzo va_list ap; 447239281Sgonzo int result; 448239281Sgonzo 449239281Sgonzo va_start(ap, fmt); 450239281Sgonzo result = sbuf_vprintf(s, fmt, ap); 451239281Sgonzo va_end(ap); 452239281Sgonzo return(result); 453239281Sgonzo} 454239281Sgonzo 455239281Sgonzo/* 456239281Sgonzo * Append a character to an sbuf. 457239281Sgonzo */ 458239281Sgonzoint 459239281Sgonzosbuf_putc(struct sbuf *s, int c) 460239281Sgonzo{ 461239281Sgonzo assert_sbuf_integrity(s); 462239281Sgonzo assert_sbuf_state(s, 0); 463239281Sgonzo 464239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 465239281Sgonzo return (-1); 466239281Sgonzo 467239281Sgonzo if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) { 468239281Sgonzo SBUF_SETFLAG(s, SBUF_OVERFLOWED); 469239281Sgonzo return (-1); 470239281Sgonzo } 471239281Sgonzo if (c != '\0') 472239281Sgonzo s->s_buf[s->s_len++] = c; 473239281Sgonzo return (0); 474239281Sgonzo} 475239281Sgonzo 476239281Sgonzo/* 477239281Sgonzo * Trim whitespace characters from end of an sbuf. 478239281Sgonzo */ 479239281Sgonzoint 480239281Sgonzosbuf_trim(struct sbuf *s) 481239281Sgonzo{ 482239281Sgonzo assert_sbuf_integrity(s); 483239281Sgonzo assert_sbuf_state(s, 0); 484239281Sgonzo 485239281Sgonzo if (SBUF_HASOVERFLOWED(s)) 486239281Sgonzo return (-1); 487239281Sgonzo 488239281Sgonzo while (s->s_len && isspace(s->s_buf[s->s_len-1])) 489239281Sgonzo --s->s_len; 490239281Sgonzo 491239281Sgonzo return (0); 492239281Sgonzo} 493239281Sgonzo 494239281Sgonzo/* 495239281Sgonzo * Check if an sbuf overflowed 496239281Sgonzo */ 497239281Sgonzoint 498239281Sgonzosbuf_overflowed(struct sbuf *s) 499239281Sgonzo{ 500239281Sgonzo return SBUF_HASOVERFLOWED(s); 501239281Sgonzo} 502239281Sgonzo 503239281Sgonzo/* 504 * Finish off an sbuf. 505 */ 506void 507sbuf_finish(struct sbuf *s) 508{ 509 assert_sbuf_integrity(s); 510 assert_sbuf_state(s, 0); 511 512 s->s_buf[s->s_len] = '\0'; 513 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED); 514 SBUF_SETFLAG(s, SBUF_FINISHED); 515} 516 517/* 518 * Return a pointer to the sbuf data. 519 */ 520char * 521sbuf_data(struct sbuf *s) 522{ 523 assert_sbuf_integrity(s); 524 assert_sbuf_state(s, SBUF_FINISHED); 525 526 return s->s_buf; 527} 528 529/* 530 * Return the length of the sbuf data. 531 */ 532int 533sbuf_len(struct sbuf *s) 534{ 535 assert_sbuf_integrity(s); 536 /* don't care if it's finished or not */ 537 538 if (SBUF_HASOVERFLOWED(s)) 539 return (-1); 540 return s->s_len; 541} 542 543/* 544 * Clear an sbuf, free its buffer if necessary. 545 */ 546void 547sbuf_delete(struct sbuf *s) 548{ 549 int isdyn; 550 551 assert_sbuf_integrity(s); 552 /* don't care if it's finished or not */ 553 554 if (SBUF_ISDYNAMIC(s)) 555 SBFREE(s->s_buf); 556 isdyn = SBUF_ISDYNSTRUCT(s); 557 bzero(s, sizeof *s); 558 if (isdyn) 559 SBFREE(s); 560} 561