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