1 /*- 2 * Copyright (c) 2000-2008 Poul-Henning Kamp 3 * Copyright (c) 2000-2008 Dag-Erling Coïdan Smørgrav 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer 11 * in this position and unchanged. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 34 #ifdef _KERNEL 35 #include <sys/ctype.h> 36 #include <sys/errno.h> 37 #include <sys/kernel.h> 38 #include <sys/malloc.h> 39 #include <sys/systm.h> 40 #include <sys/uio.h> 41 #include <machine/stdarg.h> 42 #else /* _KERNEL */ 43 #include <ctype.h> 44 #include <errno.h> 45 #include <stdarg.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #endif /* _KERNEL */ 50 51 #include <sys/sbuf.h> 52 53 #ifdef _KERNEL 54 static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); 55 #define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO) 56 #define SBFREE(buf) free(buf, M_SBUF) 57 #else /* _KERNEL */ 58 #define KASSERT(e, m) 59 #define SBMALLOC(size) calloc(1, size) 60 #define SBFREE(buf) free(buf) 61 #endif /* _KERNEL */ 62 63 /* 64 * Predicates 65 */ 66 #define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC) 67 #define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT) 68 #define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED) 69 #define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1) 70 #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) 71 #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) 72 #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) 73 74 /* 75 * Set / clear flags 76 */ 77 #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) 78 #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) 79 80 #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ 81 82 #ifdef PAGE_SIZE 83 #define SBUF_MAXEXTENDSIZE PAGE_SIZE 84 #define SBUF_MAXEXTENDINCR PAGE_SIZE 85 #else 86 #define SBUF_MAXEXTENDSIZE 4096 87 #define SBUF_MAXEXTENDINCR 4096 88 #endif 89 90 /* 91 * Debugging support 92 */ 93 #if defined(_KERNEL) && defined(INVARIANTS) 94 95 static void 96 _assert_sbuf_integrity(const char *fun, struct sbuf *s) 97 { 98 99 KASSERT(s != NULL, 100 ("%s called with a NULL sbuf pointer", fun)); 101 KASSERT(s->s_buf != NULL, 102 ("%s called with uninitialized or corrupt sbuf", fun)); 103 KASSERT(s->s_len < s->s_size, 104 ("wrote past end of sbuf (%jd >= %jd)", 105 (intmax_t)s->s_len, (intmax_t)s->s_size)); 106 } 107 108 static void 109 _assert_sbuf_state(const char *fun, struct sbuf *s, int state) 110 { 111 112 KASSERT((s->s_flags & SBUF_FINISHED) == state, 113 ("%s called with %sfinished or corrupt sbuf", fun, 114 (state ? "un" : ""))); 115 } 116 117 #define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s)) 118 #define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i)) 119 120 #else /* _KERNEL && INVARIANTS */ 121 122 #define assert_sbuf_integrity(s) do { } while (0) 123 #define assert_sbuf_state(s, i) do { } while (0) 124 125 #endif /* _KERNEL && INVARIANTS */ 126 127 #ifdef CTASSERT 128 CTASSERT(powerof2(SBUF_MAXEXTENDSIZE)); 129 CTASSERT(powerof2(SBUF_MAXEXTENDINCR)); 130 #endif 131 132 static int 133 sbuf_extendsize(int size) 134 { 135 int newsize; 136 137 if (size < (int)SBUF_MAXEXTENDSIZE) { 138 newsize = SBUF_MINEXTENDSIZE; 139 while (newsize < size) 140 newsize *= 2; 141 } else { 142 newsize = roundup2(size, SBUF_MAXEXTENDINCR); 143 } 144 KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size)); 145 return (newsize); 146 } 147 148 /* 149 * Extend an sbuf. 150 */ 151 static int 152 sbuf_extend(struct sbuf *s, int addlen) 153 { 154 char *newbuf; 155 size_t newsize; 156 157 if (!SBUF_CANEXTEND(s)) 158 return (-1); 159 newsize = sbuf_extendsize(s->s_size + addlen); 160 if (s->s_buf == s->s_static_buf && newsize <= sizeof(s->s_static_buf)) { 161 s->s_size = sizeof(s->s_static_buf); 162 return (0); 163 } 164 165 newbuf = SBMALLOC(newsize); 166 if (newbuf == NULL) 167 return (-1); 168 memcpy(newbuf, s->s_buf, s->s_size); 169 if (SBUF_ISDYNAMIC(s)) 170 SBFREE(s->s_buf); 171 else 172 SBUF_SETFLAG(s, SBUF_DYNAMIC); 173 s->s_buf = newbuf; 174 s->s_size = newsize; 175 return (0); 176 } 177 178 /* 179 * Initialize the internals of an sbuf. 180 * If buf is non-NULL, it points to a static or already-allocated string 181 * big enough to hold at least length characters. 182 */ 183 static struct sbuf * 184 sbuf_newbuf(struct sbuf *s, char *buf, size_t length, int flags) 185 { 186 187 memset(s, 0, sizeof(*s)); 188 s->s_flags = flags; 189 s->s_size = length; 190 s->s_buf = buf; 191 192 if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { 193 KASSERT(s->s_size >= 0, 194 ("attempt to create a too small sbuf")); 195 } 196 197 if (s->s_buf != NULL) 198 return (s); 199 200 if ((flags & SBUF_AUTOEXTEND) != 0) 201 s->s_size = sbuf_extendsize(s->s_size); 202 203 if (s->s_size <= sizeof(s->s_static_buf)) { 204 s->s_buf = s->s_static_buf; 205 return (s); 206 } 207 208 s->s_buf = SBMALLOC(s->s_size); 209 if (s->s_buf == NULL) 210 return (NULL); 211 SBUF_SETFLAG(s, SBUF_DYNAMIC); 212 return (s); 213 } 214 215 /* 216 * Initialize an sbuf. 217 * If buf is non-NULL, it points to a static or already-allocated string 218 * big enough to hold at least length characters. 219 */ 220 struct sbuf * 221 sbuf_new(struct sbuf *s, char *buf, int length, int flags) 222 { 223 224 KASSERT(length >= 0, 225 ("attempt to create an sbuf of negative length (%d)", length)); 226 KASSERT((flags & ~SBUF_USRFLAGMSK) == 0, 227 ("%s called with invalid flags", __func__)); 228 229 flags &= SBUF_USRFLAGMSK; 230 if (s != NULL) 231 return (sbuf_newbuf(s, buf, length, flags)); 232 233 s = SBMALLOC(sizeof(*s)); 234 if (s == NULL) 235 return (NULL); 236 if (sbuf_newbuf(s, buf, length, flags) == NULL) { 237 SBFREE(s); 238 return (NULL); 239 } 240 SBUF_SETFLAG(s, SBUF_DYNSTRUCT); 241 return (s); 242 } 243 244 #ifdef _KERNEL 245 /* 246 * Create an sbuf with uio data 247 */ 248 struct sbuf * 249 sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) 250 { 251 252 KASSERT(uio != NULL, 253 ("%s called with NULL uio pointer", __func__)); 254 KASSERT(error != NULL, 255 ("%s called with NULL error pointer", __func__)); 256 257 s = sbuf_new(s, NULL, uio->uio_resid + 1, 0); 258 if (s == NULL) { 259 *error = ENOMEM; 260 return (NULL); 261 } 262 *error = uiomove(s->s_buf, uio->uio_resid, uio); 263 if (*error != 0) { 264 sbuf_delete(s); 265 return (NULL); 266 } 267 s->s_len = s->s_size - 1; 268 if (SBUF_ISSECTION(s)) 269 s->s_sect_len = s->s_size - 1; 270 *error = 0; 271 return (s); 272 } 273 #endif 274 275 /* 276 * Clear an sbuf and reset its position. 277 */ 278 void 279 sbuf_clear(struct sbuf *s) 280 { 281 282 assert_sbuf_integrity(s); 283 /* don't care if it's finished or not */ 284 285 SBUF_CLEARFLAG(s, SBUF_FINISHED); 286 s->s_error = 0; 287 s->s_len = 0; 288 s->s_sect_len = 0; 289 } 290 291 /* 292 * Set the sbuf's end position to an arbitrary value. 293 * Effectively truncates the sbuf at the new position. 294 */ 295 int 296 sbuf_setpos(struct sbuf *s, size_t pos) 297 { 298 299 assert_sbuf_integrity(s); 300 assert_sbuf_state(s, 0); 301 302 KASSERT(pos < s->s_size, 303 ("attempt to seek past end of sbuf (%jd >= %jd)", 304 (intmax_t)pos, (intmax_t)s->s_size)); 305 KASSERT(!SBUF_ISSECTION(s), 306 ("attempt to seek when in a section")); 307 308 if (pos > s->s_len) 309 return (-1); 310 s->s_len = pos; 311 return (0); 312 } 313 314 /* 315 * Set up a drain function and argument on an sbuf to flush data to 316 * when the sbuf buffer overflows. 317 */ 318 void 319 sbuf_set_drain(struct sbuf *s, sbuf_drain_func *func, void *ctx) 320 { 321 322 assert_sbuf_state(s, 0); 323 assert_sbuf_integrity(s); 324 KASSERT(func == s->s_drain_func || s->s_len == 0, 325 ("Cannot change drain to %p on non-empty sbuf %p", func, s)); 326 s->s_drain_func = func; 327 s->s_drain_arg = ctx; 328 } 329 330 /* 331 * Call the drain and process the return. 332 */ 333 static int 334 sbuf_drain(struct sbuf *s) 335 { 336 int len; 337 338 KASSERT(s->s_len > 0, ("Shouldn't drain empty sbuf %p", s)); 339 KASSERT(s->s_error == 0, ("Called %s with error on %p", __func__, s)); 340 len = s->s_drain_func(s->s_drain_arg, s->s_buf, s->s_len); 341 if (len < 0) { 342 s->s_error = -len; 343 return (s->s_error); 344 } 345 KASSERT(len > 0 && len <= s->s_len, 346 ("Bad drain amount %d for sbuf %p", len, s)); 347 s->s_len -= len; 348 /* 349 * Fast path for the expected case where all the data was 350 * drained. 351 */ 352 if (s->s_len == 0) 353 return (0); 354 /* 355 * Move the remaining characters to the beginning of the 356 * string. 357 */ 358 memmove(s->s_buf, s->s_buf + len, s->s_len); 359 return (0); 360 } 361 362 /* 363 * Append a byte to an sbuf. This is the core function for appending 364 * to an sbuf and is the main place that deals with extending the 365 * buffer and marking overflow. 366 */ 367 static void 368 sbuf_put_byte(struct sbuf *s, int c) 369 { 370 371 assert_sbuf_integrity(s); 372 assert_sbuf_state(s, 0); 373 374 if (s->s_error != 0) 375 return; 376 if (SBUF_FREESPACE(s) <= 0) { 377 /* 378 * If there is a drain, use it, otherwise extend the 379 * buffer. 380 */ 381 if (s->s_drain_func != NULL) 382 (void)sbuf_drain(s); 383 else if (sbuf_extend(s, 1) < 0) 384 s->s_error = ENOMEM; 385 if (s->s_error != 0) 386 return; 387 } 388 s->s_buf[s->s_len++] = c; 389 if (SBUF_ISSECTION(s)) 390 s->s_sect_len++; 391 } 392 393 /* 394 * Append a byte string to an sbuf. 395 */ 396 int 397 sbuf_bcat(struct sbuf *s, const void *buf, size_t len) 398 { 399 const char *str = buf; 400 const char *end = str + len; 401 402 assert_sbuf_integrity(s); 403 assert_sbuf_state(s, 0); 404 405 if (s->s_error != 0) 406 return (-1); 407 for (; str < end; str++) { 408 sbuf_put_byte(s, *str); 409 if (s->s_error != 0) 410 return (-1); 411 } 412 return (0); 413 } 414 415 #ifdef _KERNEL 416 /* 417 * Copy a byte string from userland into an sbuf. 418 */ 419 int 420 sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len) 421 { 422 423 assert_sbuf_integrity(s); 424 assert_sbuf_state(s, 0); 425 KASSERT(s->s_drain_func == NULL, 426 ("Nonsensical copyin to sbuf %p with a drain", s)); 427 428 if (s->s_error != 0) 429 return (-1); 430 if (len == 0) 431 return (0); 432 if (len > SBUF_FREESPACE(s)) { 433 sbuf_extend(s, len - SBUF_FREESPACE(s)); 434 if (SBUF_FREESPACE(s) < len) 435 len = SBUF_FREESPACE(s); 436 } 437 if (copyin(uaddr, s->s_buf + s->s_len, len) != 0) 438 return (-1); 439 s->s_len += len; 440 441 return (0); 442 } 443 #endif 444 445 /* 446 * Copy a byte string into an sbuf. 447 */ 448 int 449 sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) 450 { 451 452 assert_sbuf_integrity(s); 453 assert_sbuf_state(s, 0); 454 455 sbuf_clear(s); 456 return (sbuf_bcat(s, buf, len)); 457 } 458 459 /* 460 * Append a string to an sbuf. 461 */ 462 int 463 sbuf_cat(struct sbuf *s, const char *str) 464 { 465 466 assert_sbuf_integrity(s); 467 assert_sbuf_state(s, 0); 468 469 if (s->s_error != 0) 470 return (-1); 471 472 while (*str != '\0') { 473 sbuf_put_byte(s, *str++); 474 if (s->s_error != 0) 475 return (-1); 476 } 477 return (0); 478 } 479 480 #ifdef _KERNEL 481 /* 482 * Append a string from userland to an sbuf. 483 */ 484 int 485 sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len) 486 { 487 size_t done; 488 489 assert_sbuf_integrity(s); 490 assert_sbuf_state(s, 0); 491 KASSERT(s->s_drain_func == NULL, 492 ("Nonsensical copyin to sbuf %p with a drain", s)); 493 494 if (s->s_error != 0) 495 return (-1); 496 497 if (len == 0) 498 len = SBUF_FREESPACE(s); /* XXX return 0? */ 499 if (len > SBUF_FREESPACE(s)) { 500 sbuf_extend(s, len); 501 if (SBUF_FREESPACE(s) < len) 502 len = SBUF_FREESPACE(s); 503 } 504 switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) { 505 case ENAMETOOLONG: 506 s->s_error = ENOMEM; 507 /* fall through */ 508 case 0: 509 s->s_len += done - 1; 510 if (SBUF_ISSECTION(s)) 511 s->s_sect_len += done - 1; 512 break; 513 default: 514 return (-1); /* XXX */ 515 } 516 517 return (done); 518 } 519 #endif 520 521 /* 522 * Copy a string into an sbuf. 523 */ 524 int 525 sbuf_cpy(struct sbuf *s, const char *str) 526 { 527 528 assert_sbuf_integrity(s); 529 assert_sbuf_state(s, 0); 530 531 sbuf_clear(s); 532 return (sbuf_cat(s, str)); 533 } 534 535 /* 536 * Format the given argument list and append the resulting string to an sbuf. 537 */ 538 #ifdef _KERNEL 539 540 /* 541 * Append a non-NUL character to an sbuf. This prototype signature is 542 * suitable for use with kvprintf(9). 543 */ 544 static void 545 sbuf_putc_func(int c, void *arg) 546 { 547 548 if (c != '\0') 549 sbuf_put_byte(arg, c); 550 } 551 552 int 553 sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 554 { 555 556 assert_sbuf_integrity(s); 557 assert_sbuf_state(s, 0); 558 559 KASSERT(fmt != NULL, 560 ("%s called with a NULL format string", __func__)); 561 562 (void)kvprintf(fmt, sbuf_putc_func, s, 10, ap); 563 if (s->s_error != 0) 564 return (-1); 565 return (0); 566 } 567 #else /* !_KERNEL */ 568 int 569 sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) 570 { 571 va_list ap_copy; 572 size_t len; 573 int error; 574 575 assert_sbuf_integrity(s); 576 assert_sbuf_state(s, 0); 577 578 KASSERT(fmt != NULL, 579 ("%s called with a NULL format string", __func__)); 580 581 if (s->s_error != 0) 582 return (-1); 583 584 /* 585 * For the moment, there is no way to get vsnprintf(3) to hand 586 * back a character at a time, to push everything into 587 * sbuf_putc_func() as was done for the kernel. 588 * 589 * In userspace, while drains are useful, there's generally 590 * not a problem attempting to malloc(3) on out of space. So 591 * expand a userland sbuf if there is not enough room for the 592 * data produced by sbuf_[v]printf(3). 593 */ 594 595 error = 0; 596 do { 597 va_copy(ap_copy, ap); 598 len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, 599 fmt, ap_copy); 600 va_end(ap_copy); 601 602 if (SBUF_FREESPACE(s) >= len) 603 break; 604 /* Cannot print with the current available space. */ 605 if (s->s_drain_func != NULL && s->s_len > 0) 606 error = sbuf_drain(s); 607 else 608 error = sbuf_extend(s, len - SBUF_FREESPACE(s)); 609 } while (error == 0); 610 611 /* 612 * s->s_len is the length of the string, without the terminating nul. 613 * When updating s->s_len, we must subtract 1 from the length that 614 * we passed into vsnprintf() because that length includes the 615 * terminating nul. 616 * 617 * vsnprintf() returns the amount that would have been copied, 618 * given sufficient space, so don't over-increment s_len. 619 */ 620 if (SBUF_FREESPACE(s) < len) 621 len = SBUF_FREESPACE(s); 622 s->s_len += len; 623 if (SBUF_ISSECTION(s)) 624 s->s_sect_len += len; 625 if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s)) 626 s->s_error = ENOMEM; 627 628 KASSERT(s->s_len < s->s_size, 629 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size)); 630 631 if (s->s_error != 0) 632 return (-1); 633 return (0); 634 } 635 #endif /* _KERNEL */ 636 637 /* 638 * Format the given arguments and append the resulting string to an sbuf. 639 */ 640 int 641 sbuf_printf(struct sbuf *s, const char *fmt, ...) 642 { 643 va_list ap; 644 int result; 645 646 va_start(ap, fmt); 647 result = sbuf_vprintf(s, fmt, ap); 648 va_end(ap); 649 return (result); 650 } 651 652 /* 653 * Append a character to an sbuf. 654 */ 655 int 656 sbuf_putc(struct sbuf *s, int c) 657 { 658 659 sbuf_put_byte(s, c); 660 if (s->s_error != 0) 661 return (-1); 662 return (0); 663 } 664 665 /* 666 * Trim whitespace characters from end of an sbuf. 667 */ 668 int 669 sbuf_trim(struct sbuf *s) 670 { 671 672 assert_sbuf_integrity(s); 673 assert_sbuf_state(s, 0); 674 KASSERT(s->s_drain_func == NULL, 675 ("%s makes no sense on sbuf %p with drain", __func__, s)); 676 677 if (s->s_error != 0) 678 return (-1); 679 680 while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1])) { 681 --s->s_len; 682 if (SBUF_ISSECTION(s)) 683 s->s_sect_len--; 684 } 685 686 return (0); 687 } 688 689 /* 690 * Check if an sbuf has an error. 691 */ 692 int 693 sbuf_error(const struct sbuf *s) 694 { 695 696 return (s->s_error); 697 } 698 699 /* 700 * Finish off an sbuf. 701 */ 702 int 703 sbuf_finish(struct sbuf *s) 704 { 705 706 assert_sbuf_integrity(s); 707 assert_sbuf_state(s, 0); 708 709 if (s->s_drain_func != NULL) { 710 while (s->s_len > 0 && s->s_error == 0) 711 s->s_error = sbuf_drain(s); 712 } 713 s->s_buf[s->s_len] = '\0'; 714 SBUF_SETFLAG(s, SBUF_FINISHED); 715 #ifdef _KERNEL 716 return (s->s_error); 717 #else 718 if (s->s_error != 0) { 719 errno = s->s_error; 720 return (-1); 721 } 722 return (0); 723 #endif 724 } 725 726 /* 727 * Return a pointer to the sbuf data. 728 */ 729 char * 730 sbuf_data(struct sbuf *s) 731 { 732 733 assert_sbuf_integrity(s); 734 assert_sbuf_state(s, SBUF_FINISHED); 735 KASSERT(s->s_drain_func == NULL, 736 ("%s makes no sense on sbuf %p with drain", __func__, s)); 737 738 return (s->s_buf); 739 } 740 741 /* 742 * Return the length of the sbuf data. 743 */ 744 ssize_t 745 sbuf_len(struct sbuf *s) 746 { 747 748 assert_sbuf_integrity(s); 749 /* don't care if it's finished or not */ 750 KASSERT(s->s_drain_func == NULL, 751 ("%s makes no sense on sbuf %p with drain", __func__, s)); 752 753 if (s->s_error != 0) 754 return (-1); 755 return (s->s_len); 756 } 757 758 /* 759 * Clear an sbuf, free its buffer if necessary. 760 */ 761 void 762 sbuf_delete(struct sbuf *s) 763 { 764 int isdyn; 765 766 assert_sbuf_integrity(s); 767 /* don't care if it's finished or not */ 768 769 if (SBUF_ISDYNAMIC(s)) 770 SBFREE(s->s_buf); 771 isdyn = SBUF_ISDYNSTRUCT(s); 772 memset(s, 0, sizeof(*s)); 773 if (isdyn) 774 SBFREE(s); 775 } 776 777 /* 778 * Check if an sbuf has been finished. 779 */ 780 int 781 sbuf_done(const struct sbuf *s) 782 { 783 784 return (SBUF_ISFINISHED(s)); 785 } 786 787 /* 788 * Start a section. 789 */ 790 void 791 sbuf_start_section(struct sbuf *s, ssize_t *old_lenp) 792 { 793 794 assert_sbuf_integrity(s); 795 assert_sbuf_state(s, 0); 796 797 if (!SBUF_ISSECTION(s)) { 798 KASSERT(s->s_sect_len == 0, 799 ("s_sect_len != 0 when starting a section")); 800 if (old_lenp != NULL) 801 *old_lenp = -1; 802 SBUF_SETFLAG(s, SBUF_INSECTION); 803 } else { 804 KASSERT(old_lenp != NULL, 805 ("s_sect_len should be saved when starting a subsection")); 806 *old_lenp = s->s_sect_len; 807 s->s_sect_len = 0; 808 } 809 } 810 811 /* 812 * End the section padding to the specified length with the specified 813 * character. 814 */ 815 ssize_t 816 sbuf_end_section(struct sbuf *s, ssize_t old_len, size_t pad, int c) 817 { 818 ssize_t len; 819 820 assert_sbuf_integrity(s); 821 assert_sbuf_state(s, 0); 822 KASSERT(SBUF_ISSECTION(s), 823 ("attempt to end a section when not in a section")); 824 825 if (pad > 1) { 826 len = roundup(s->s_sect_len, pad) - s->s_sect_len; 827 for (; s->s_error == 0 && len > 0; len--) 828 sbuf_put_byte(s, c); 829 } 830 len = s->s_sect_len; 831 if (old_len == -1) { 832 s->s_sect_len = 0; 833 SBUF_CLEARFLAG(s, SBUF_INSECTION); 834 } else { 835 s->s_sect_len += old_len; 836 } 837 if (s->s_error != 0) 838 return (-1); 839 return (len); 840 } 841