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