1/*
2 * Copyright (c) 2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#include <kern/kalloc.h>
29#include <libkern/libkern.h>
30#include <os/base.h>
31#include <os/overflow.h>
32#include <sys/param.h>
33#include <sys/sbuf.h>
34#include <sys/uio.h>
35
36#if DEBUG || DEVELOPMENT
37#include <kern/macro_help.h>
38#include <sys/errno.h>
39#include <sys/sysctl.h>
40#endif /* DEBUG || DEVELOPMENT */
41
42#define SBUF_ISSET(s, f) ((s)->s_flags & (f))
43#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0)
44#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0)
45
46#define SBUF_CANEXTEND(s) SBUF_ISSET(s, SBUF_AUTOEXTEND)
47#define SBUF_HASOVERFLOWED(s) SBUF_ISSET(s, SBUF_OVERFLOWED)
48#define SBUF_ISDYNAMIC(s) SBUF_ISSET(s, SBUF_DYNAMIC)
49#define SBUF_ISDYNSTRUCT(s) SBUF_ISSET(s, SBUF_DYNSTRUCT)
50#define SBUF_ISFINISHED(s) SBUF_ISSET(s, SBUF_FINISHED)
51
52#define SBUF_MINEXTENDSIZE 16
53#define SBUF_MAXEXTENDSIZE PAGE_SIZE
54#define SBUF_MAXEXTENDINCR PAGE_SIZE
55
56/*!
57 * @function sbuf_delete
58 *
59 * @brief
60 * Destroys an sbuf. Frees the underlying buffer if it's allocated on the heap
61 * (indicated by SBUF_ISDYNAMIC) and frees the sbuf if it itself is allocated
62 * on the heap (SBUF_ISDYNSTRUCT).
63 *
64 * @param s
65 * The sbuf to destroy.
66 */
67void
68sbuf_delete(struct sbuf *s)
69{
70 if (SBUF_ISDYNAMIC(s) && s->s_buf) {
71 kfree_data(s->s_buf, s->s_size);
72 s->s_buf = NULL;
73 }
74
75 if (SBUF_ISDYNSTRUCT(s)) {
76 kfree_type(struct sbuf, s);
77 }
78}
79
80/*!
81 * @function sbuf_extendsize
82 *
83 * @brief
84 * Attempts to extend the size of an sbuf to the value pointed to by size.
85 *
86 * @param size
87 * Points to a size_t containing the desired size for input and receives the
88 * actual new size on success (which will be greater than or equal to the
89 * requested size).
90 *
91 * @returns
92 * 0 on success, -1 on failure.
93 */
94static int
95sbuf_extendsize(size_t *size)
96{
97 size_t target_size = *size;
98 size_t new_size;
99
100 if (target_size > INT_MAX) {
101 return -1;
102 }
103
104 if (target_size < SBUF_MAXEXTENDSIZE) {
105 new_size = SBUF_MINEXTENDSIZE;
106 while (new_size < target_size) {
107 new_size *= 2;
108 }
109 } else {
110 /* round up to nearest page: */
111 new_size = (target_size + PAGE_SIZE - 1) & ~PAGE_MASK;
112 }
113
114 if (new_size > INT_MAX) {
115 return -1;
116 }
117
118 *size = new_size;
119 return 0;
120}
121
122/*!
123 * @function sbuf_new
124 *
125 * @brief
126 * Allocates and/or initializes an sbuf.
127 *
128 * @param s
129 * An optional existing sbuf to initialize. If NULL, a new one is allocated on
130 * the heap.
131 *
132 * @param buf
133 * An optional existing backing buffer to assign to the sbuf. If NULL, a new
134 * one is allocated on the heap.
135 *
136 * @param length_
137 * The initial size of the sbuf. The actual size may be greater than this
138 * value.
139 *
140 * @param flags
141 * The flags to set on the sbuf. Accepted values are:
142 *
143 * - SBUF_FIXEDLEN: Do not allow the backing buffer to dynamically expand
144 * to accommodate appended data.
145 * - SBUF_AUTOEXPAND: Automatically reallocate the backing buffer using the
146 * heap if required.
147 *
148 * @returns
149 * The new and/or initialized sbuf on success, or NULL on failure.
150 */
151struct sbuf *
152sbuf_new(struct sbuf *s, char *buf, int length_, int flags)
153{
154 size_t length = (size_t)length_;
155
156 if (length > INT_MAX || flags & ~SBUF_USRFLAGMSK) {
157 return NULL;
158 }
159
160 if (s == NULL) {
161 s = (struct sbuf *)kalloc_type(struct sbuf, Z_WAITOK | Z_ZERO);
162 if (NULL == s) {
163 return NULL;
164 }
165
166 s->s_flags = flags;
167 SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
168 } else {
169 bzero(s, n: sizeof(*s));
170 s->s_flags = flags;
171 }
172
173 if (buf) {
174 s->s_size = (int)length;
175 s->s_buf = buf;
176 return s;
177 }
178
179 if (SBUF_CANEXTEND(s) && (-1 == sbuf_extendsize(size: &length))) {
180 goto fail;
181 }
182
183 /*
184 * we always need at least 1 byte for \0, so s_size of 0 will cause an
185 * underflow in sbuf_capacity.
186 */
187 if (length == 0) {
188 goto fail;
189 }
190
191 s->s_buf = kalloc_data(length, Z_WAITOK | Z_ZERO);
192 if (NULL == s->s_buf) {
193 goto fail;
194 }
195 s->s_size = (int)length;
196
197 SBUF_SETFLAG(s, SBUF_DYNAMIC);
198 return s;
199
200fail:
201 sbuf_delete(s);
202 return NULL;
203}
204
205/*!
206 * @function sbuf_setpos
207 *
208 * @brief
209 * Set the current position of the sbuf.
210 *
211 * @param s
212 * The sbuf to modify.
213 *
214 * @param pos
215 * The new position to set. Must be less than or equal to the current position.
216 *
217 * @returns
218 * 0 on success, -1 on failure.
219 */
220int
221sbuf_setpos(struct sbuf *s, int pos)
222{
223 if (pos < 0 || pos > s->s_len) {
224 return -1;
225 }
226
227 s->s_len = pos;
228 return 0;
229}
230
231/*!
232 * @function sbuf_clear
233 *
234 * @brief
235 * Resets the position/length of the sbuf data to zero and clears the finished
236 * and overflow flags.
237 *
238 * @param s
239 * The sbuf to clear.
240 */
241void
242sbuf_clear(struct sbuf *s)
243{
244 SBUF_CLEARFLAG(s, SBUF_FINISHED);
245 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
246 sbuf_setpos(s, pos: 0);
247}
248
249/*!
250 * @function sbuf_extend
251 *
252 * @brief
253 * Attempt to extend the size of an sbuf's backing buffer by @a addlen bytes.
254 *
255 * @param s
256 * The sbuf to extend.
257 *
258 * @param addlen
259 * How many bytes to increase the size by.
260 *
261 * @returns
262 * 0 on success, -1 on failure.
263 */
264static int OS_WARN_RESULT
265sbuf_extend(struct sbuf *s, size_t addlen)
266{
267 char *new_buf;
268 size_t new_size;
269
270 if (addlen == 0) {
271 return 0;
272 }
273
274 if (!SBUF_CANEXTEND(s)) {
275 return -1;
276 }
277
278 if (os_add_overflow((size_t)s->s_size, addlen, &new_size)) {
279 return -1;
280 }
281
282 if (-1 == sbuf_extendsize(size: &new_size)) {
283 return -1;
284 }
285
286 new_buf = (char *) kalloc_data(new_size, Z_WAITOK);
287 if (NULL == new_buf) {
288 return -1;
289 }
290
291 bcopy(src: s->s_buf, dst: new_buf, n: (size_t)s->s_size);
292 if (SBUF_ISDYNAMIC(s)) {
293 kfree_data(s->s_buf, (size_t)s->s_size);
294 } else {
295 SBUF_SETFLAG(s, SBUF_DYNAMIC);
296 }
297
298 s->s_buf = new_buf;
299 s->s_size = (int)new_size;
300 return 0;
301}
302
303/*!
304 * @function sbuf_capacity
305 *
306 * @brief
307 * Get the current capacity of an sbuf: how many more bytes we can append given
308 * the current size and position.
309 *
310 * @param s
311 * The sbuf to get the capacity of.
312 *
313 * @returns
314 * The current sbuf capacity.
315 */
316static size_t
317sbuf_capacity(const struct sbuf *s)
318{
319 /* 1 byte reserved for \0: */
320 return (size_t)(s->s_size - s->s_len - 1);
321}
322
323/*!
324 * @function sbuf_ensure_capacity
325 *
326 * @brief
327 * Ensure that an sbuf can accommodate @a add_len bytes, reallocating the
328 * backing buffer if necessary.
329 *
330 * @param s
331 * The sbuf.
332 *
333 * @param wanted
334 * The minimum capacity to ensure @a s has.
335 *
336 * @returns
337 * 0 if the minimum capacity is met by @a s, or -1 on error.
338 */
339static int
340sbuf_ensure_capacity(struct sbuf *s, size_t wanted)
341{
342 size_t size;
343
344 size = sbuf_capacity(s);
345 if (size >= wanted) {
346 return 0;
347 }
348
349 return sbuf_extend(s, addlen: wanted - size);
350}
351
352/*!
353 * @function sbuf_bcat
354 *
355 * @brief
356 * Append data to an sbuf.
357 *
358 * @param s
359 * The sbuf.
360 *
361 * @param data
362 * The data to append.
363 *
364 * @param len
365 * The length of the data.
366 *
367 * @returns
368 * 0 on success, -1 on failure. Will always fail if the sbuf is marked as
369 * overflowed.
370 */
371int
372sbuf_bcat(struct sbuf *s, const void *data, size_t len)
373{
374 if (SBUF_HASOVERFLOWED(s)) {
375 return -1;
376 }
377
378 if (-1 == sbuf_ensure_capacity(s, wanted: len)) {
379 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
380 return -1;
381 }
382
383 bcopy(src: data, dst: s->s_buf + s->s_len, n: len);
384 s->s_len += (int)len; /* safe */
385
386 return 0;
387}
388
389/*!
390 * @function sbuf_bcpy
391 *
392 * @brief
393 * Set the entire sbuf data, possibly reallocating the backing buffer to
394 * accommodate.
395 *
396 * @param s
397 * The sbuf.
398 *
399 * @param data
400 * The data to set.
401 *
402 * @param len
403 * The length of the data to set.
404 *
405 * @returns
406 * 0 on success or -1 on failure. Will clear the finished/overflowed flags.
407 */
408int
409sbuf_bcpy(struct sbuf *s, const void *data, size_t len)
410{
411 sbuf_clear(s);
412 return sbuf_bcat(s, data, len);
413}
414
415/*!
416 * @function sbuf_cat
417 *
418 * @brief
419 * Append a string to an sbuf, possibly expanding the backing buffer to
420 * accommodate.
421 *
422 * @param s
423 * The sbuf.
424 *
425 * @param str
426 * The string to append.
427 *
428 * @returns
429 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
430 * overflowed.
431 */
432int
433sbuf_cat(struct sbuf *s, const char *str)
434{
435 return sbuf_bcat(s, data: str, len: strlen(s: str));
436}
437
438/*!
439 * @function sbuf_cpy
440 *
441 * @brief
442 * Set the entire sbuf data to the given nul-terminated string, possibly
443 * expanding the backing buffer to accommodate it if necessary.
444 *
445 * @param s
446 * The sbuf.
447 *
448 * @param str
449 * The string to set the sbuf data to.
450 *
451 * @returns
452 * 0 on success, -1 on failure. Clears and resets the sbuf first.
453 */
454int
455sbuf_cpy(struct sbuf *s, const char *str)
456{
457 sbuf_clear(s);
458 return sbuf_cat(s, str);
459}
460
461/*!
462 * @function sbuf_vprintf
463 *
464 * @brief
465 * Formatted-print into an sbuf using a va_list.
466 *
467 * @param s
468 * The sbuf.
469 *
470 * @param fmt
471 * The format string.
472 *
473 * @param ap
474 * The format string argument data.
475 *
476 * @returns
477 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
478 * overflowed.
479 */
480int
481sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
482{
483 va_list ap_copy;
484 int result;
485 size_t capacity;
486 size_t len;
487
488 if (SBUF_HASOVERFLOWED(s)) {
489 return -1;
490 }
491
492 do {
493 capacity = sbuf_capacity(s);
494
495 va_copy(ap_copy, ap);
496 /* +1 for \0. safe because we already accommodate this. */
497 result = vsnprintf(&s->s_buf[s->s_len], capacity + 1, fmt, ap_copy);
498 va_end(ap_copy);
499
500 if (result < 0) {
501 return -1;
502 }
503
504 len = (size_t)result;
505 if (len <= capacity) {
506 s->s_len += (int)len;
507 return 0;
508 }
509 } while (-1 != sbuf_ensure_capacity(s, wanted: len));
510
511 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
512 return -1;
513}
514
515/*!
516 * @function sbuf_printf
517 *
518 * @brief
519 * Formatted-print into an sbuf using variadic arguments.
520 *
521 * @param s
522 * The sbuf.
523 *
524 * @param fmt
525 * The format string.
526 *
527 * @returns
528 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
529 * overflowed.
530 */
531int
532sbuf_printf(struct sbuf *s, const char *fmt, ...)
533{
534 va_list ap;
535 int result;
536
537 va_start(ap, fmt);
538 result = sbuf_vprintf(s, fmt, ap);
539 va_end(ap);
540 return result;
541}
542
543/*!
544 * @function sbuf_putc
545 *
546 * @brief
547 * Append a single character to an sbuf. Ignores '\0'.
548 *
549 * @param s
550 * The sbuf.
551 *
552 * @param c_
553 * The character to append.
554 *
555 * @returns
556 * 0 on success, -1 on failure. This function will always fail if the sbuf is
557 * marked as overflowed.
558 */
559int
560sbuf_putc(struct sbuf *s, int c_)
561{
562 char c = (char)c_;
563
564 if (SBUF_HASOVERFLOWED(s)) {
565 return -1;
566 }
567
568 if (-1 == sbuf_ensure_capacity(s, wanted: 1)) {
569 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
570 return -1;
571 }
572
573 if (c != '\0') {
574 s->s_buf[s->s_len++] = c;
575 }
576
577 return 0;
578}
579
580static inline int
581isspace(char ch)
582{
583 return ch == ' ' || ch == '\n' || ch == '\t';
584}
585
586/*!
587 * @function sbuf_trim
588 *
589 * @brief
590 * Removes whitespace from the end of an sbuf.
591 *
592 * @param s
593 * The sbuf.
594 *
595 * @returns
596 * 0 on success or -1 if the sbuf is marked as overflowed.
597 */
598int
599sbuf_trim(struct sbuf *s)
600{
601 if (SBUF_HASOVERFLOWED(s)) {
602 return -1;
603 }
604
605 while (s->s_len > 0 && isspace(ch: s->s_buf[s->s_len - 1])) {
606 --s->s_len;
607 }
608
609 return 0;
610}
611
612/*!
613 * @function sbuf_overflowed
614 *
615 * @brief
616 * Indicates whether the sbuf is marked as overflowed.
617 *
618 * @param s
619 * The sbuf.
620 *
621 * @returns
622 * 1 if the sbuf has overflowed or 0 otherwise.
623 */
624int
625sbuf_overflowed(struct sbuf *s)
626{
627 return !!SBUF_HASOVERFLOWED(s);
628}
629
630/*!
631 * @function sbuf_finish
632 *
633 * @brief
634 * Puts a trailing nul byte onto the sbuf data.
635 *
636 * @param s
637 * The sbuf.
638 */
639void
640sbuf_finish(struct sbuf *s)
641{
642 /* safe because we always reserve a byte at the end for \0: */
643 s->s_buf[s->s_len] = '\0';
644 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
645 SBUF_SETFLAG(s, SBUF_FINISHED);
646}
647
648/*!
649 * @function sbuf_data
650 *
651 * @brief
652 * Gets a pointer to the sbuf backing data.
653 *
654 * @param s
655 * The sbuf.
656 *
657 * @returns
658 * A pointer to the sbuf data.
659 */
660char *
661sbuf_data(struct sbuf *s)
662{
663 return s->s_buf;
664}
665
666/*!
667 * @function sbuf_len
668 *
669 * @brief
670 * Retrieves the current length of the sbuf data.
671 *
672 * @param s
673 * The sbuf
674 *
675 * @returns
676 * The length of the sbuf data or -1 if the sbuf is marked as overflowed.
677 */
678int
679sbuf_len(struct sbuf *s)
680{
681 if (SBUF_HASOVERFLOWED(s)) {
682 return -1;
683 }
684
685 return s->s_len;
686}
687
688/*!
689 * @function sbuf_done
690 *
691 * @brief
692 * Tests if the sbuf is marked as finished.
693 *
694 * @param s
695 * The sbuf.
696 *
697 * @returns
698 * 1 if the sbuf is marked as finished or 0 if not.
699 */
700int
701sbuf_done(struct sbuf *s)
702{
703 return !!SBUF_ISFINISHED(s);
704}
705
706#if DEBUG || DEVELOPMENT
707
708/*
709 * a = assertion string
710 */
711#define SBUF_FAIL(a) \
712 MACRO_BEGIN \
713 printf("sbuf_tests: failed assertion: %s\n", a); \
714 if (what != NULL && should != NULL) { \
715 printf("sbuf_tests: while testing: %s should %s\n", what, should); \
716 } \
717 goto fail; \
718 MACRO_END
719
720#define SBUF_PASS \
721 ++passed
722
723/*
724 * x = expression
725 */
726#define SBUF_ASSERT(x) \
727 MACRO_BEGIN \
728 if (x) { \
729 SBUF_PASS; \
730 } else { \
731 SBUF_FAIL(#x); \
732 } \
733 MACRO_END
734
735#define SBUF_ASSERT_NOT(x) \
736 SBUF_ASSERT(!(x))
737
738/*
739 * e = expected
740 * a = actual
741 * c = comparator
742 */
743#define SBUF_ASSERT_CMP(e, a, c) \
744 MACRO_BEGIN \
745 if ((a) c (e)) { \
746 SBUF_PASS; \
747 } else { \
748 SBUF_FAIL(#a " " #c " " #e); \
749 } \
750 MACRO_END
751
752#define SBUF_ASSERT_EQ(e, a) SBUF_ASSERT_CMP(e, a, ==)
753#define SBUF_ASSERT_NE(e, a) SBUF_ASSERT_CMP(e, a, !=)
754#define SBUF_ASSERT_GT(e, a) SBUF_ASSERT_CMP(e, a, >)
755#define SBUF_ASSERT_GTE(e, a) SBUF_ASSERT_CMP(e, a, >=)
756#define SBUF_ASSERT_LT(e, a) SBUF_ASSERT_CMP(e, a, <)
757#define SBUF_ASSERT_LTE(e, a) SBUF_ASSERT_CMP(e, a, <=)
758
759#define SBUF_TEST_BEGIN \
760 size_t passed = 0; \
761 const char *what = NULL; \
762 const char *should = NULL;
763
764/*
765 * include the trailing semi-colons here intentionally to allow for block-like
766 * appearance:
767 */
768#define SBUF_TESTING(f) \
769 MACRO_BEGIN \
770 what = (f); \
771 MACRO_END;
772
773#define SBUF_SHOULD(s) \
774 MACRO_BEGIN \
775 should = (s); \
776 MACRO_END;
777
778#define SBUF_TEST_END \
779 printf("sbuf_tests: %zu assertions passed\n", passed); \
780 return 0; \
781fail: \
782 return ENOTRECOVERABLE;
783
784static int
785sysctl_sbuf_tests SYSCTL_HANDLER_ARGS
786{
787#pragma unused(arg1, arg2)
788 int rval = 0;
789 char str[32] = { 'o', 'k', 0 };
790
791 rval = sysctl_handle_string(oidp, str, sizeof(str), req);
792 if (rval != 0 || req->newptr == 0 || req->newlen < 1) {
793 return rval;
794 }
795
796 SBUF_TEST_BEGIN;
797
798 SBUF_TESTING("sbuf_new")
799 {
800 SBUF_SHOULD("fail to allocate >INT_MAX")
801 {
802 struct sbuf *s = NULL;
803
804 s = sbuf_new(NULL, NULL, INT_MIN, 0);
805 SBUF_ASSERT_EQ(NULL, s);
806 }
807
808 SBUF_SHOULD("fail when claiming a backing buffer >INT_MAX")
809 {
810 struct sbuf *s = NULL;
811 char buf[4] = { 0 };
812
813 s = sbuf_new(NULL, buf, INT_MIN, 0);
814 SBUF_ASSERT_EQ(NULL, s);
815 }
816
817 SBUF_SHOULD("fail to allocate a zero-length sbuf")
818 {
819 struct sbuf *s = NULL;
820
821 s = sbuf_new(NULL, NULL, 0, 0);
822 SBUF_ASSERT_EQ(NULL, s);
823 }
824
825 SBUF_SHOULD("not accept invalid flags")
826 {
827 struct sbuf *s = NULL;
828
829 s = sbuf_new(NULL, NULL, 16, 0x10000);
830 SBUF_ASSERT_EQ(NULL, s);
831 }
832
833 SBUF_SHOULD("succeed when passed an existing sbuf")
834 {
835 struct sbuf *s = NULL;
836 struct sbuf existing;
837
838 memset(&existing, 0x41, sizeof(existing));
839 s = sbuf_new(&existing, NULL, 16, SBUF_AUTOEXTEND);
840 SBUF_ASSERT_EQ(&existing, s);
841 SBUF_ASSERT(SBUF_ISSET(s, SBUF_AUTOEXTEND));
842 SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC));
843 SBUF_ASSERT_NE(NULL, s->s_buf);
844 SBUF_ASSERT_NE(0, s->s_size);
845 SBUF_ASSERT_EQ(0, s->s_len);
846
847 sbuf_delete(s);
848 }
849
850 SBUF_SHOULD("succeed when passed an existing sbuf and buffer")
851 {
852 struct sbuf *s = NULL;
853 struct sbuf existing;
854 char buf[4] = { 0 };
855
856 memset(&existing, 0x41, sizeof(existing));
857 s = sbuf_new(&existing, buf, sizeof(buf), 0);
858 SBUF_ASSERT_EQ(&existing, s);
859 SBUF_ASSERT_EQ(buf, s->s_buf);
860 SBUF_ASSERT_EQ(4, s->s_size);
861 SBUF_ASSERT_EQ(0, s->s_len);
862
863 sbuf_delete(s);
864 }
865
866 SBUF_SHOULD("succeed without an existing sbuf or buffer")
867 {
868 struct sbuf *s = NULL;
869
870 s = sbuf_new(NULL, NULL, 16, 0);
871 SBUF_ASSERT_NE(NULL, s);
872 SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC));
873 SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNSTRUCT));
874 SBUF_ASSERT_NE(NULL, s->s_buf);
875 SBUF_ASSERT_NE(0, s->s_size);
876 SBUF_ASSERT_EQ(0, s->s_len);
877
878 sbuf_delete(s);
879 }
880
881 SBUF_SHOULD("succeed without an existing sbuf, but with a buffer")
882 {
883 struct sbuf *s = NULL;
884 char buf[4] = { 0 };
885
886 s = sbuf_new(NULL, buf, sizeof(buf), 0);
887 SBUF_ASSERT_NE(NULL, s);
888 SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNSTRUCT));
889 SBUF_ASSERT_EQ(buf, s->s_buf);
890 SBUF_ASSERT_EQ(4, s->s_size);
891 SBUF_ASSERT_EQ(0, s->s_len);
892
893 sbuf_delete(s);
894 }
895
896 SBUF_SHOULD("round up the requested size if SBUF_AUTOEXTEND")
897 {
898 struct sbuf *s = NULL;
899
900 s = sbuf_new(NULL, NULL, 1, SBUF_AUTOEXTEND);
901 SBUF_ASSERT_GT(1, s->s_size);
902
903 sbuf_delete(s);
904 }
905 }
906
907 SBUF_TESTING("sbuf_clear")
908 {
909 SBUF_SHOULD("clear the overflowed and finished flags")
910 {
911 struct sbuf *s = NULL;
912
913 s = sbuf_new(NULL, NULL, 16, 0);
914
915 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
916 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
917 SBUF_SETFLAG(s, SBUF_FINISHED);
918 SBUF_ASSERT(SBUF_ISSET(s, SBUF_FINISHED));
919 sbuf_clear(s);
920 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED));
921 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_FINISHED));
922
923 sbuf_delete(s);
924 }
925
926 SBUF_SHOULD("reset the position to zero")
927 {
928 struct sbuf *s = NULL;
929
930 s = sbuf_new(NULL, NULL, 16, 0);
931
932 s->s_len = 1;
933 sbuf_clear(s);
934 SBUF_ASSERT_EQ(0, s->s_len);
935
936 sbuf_delete(s);
937 }
938 }
939
940 SBUF_TESTING("sbuf_extend")
941 {
942 SBUF_SHOULD("allow zero")
943 {
944 struct sbuf *s = NULL;
945 int size_before;
946
947 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
948 size_before = s->s_size;
949 SBUF_ASSERT_EQ(0, sbuf_extend(s, 0));
950 SBUF_ASSERT_EQ(size_before, s->s_size);
951
952 sbuf_delete(s);
953 }
954
955 SBUF_SHOULD("fail for sbuf not marked as SBUF_AUTOEXTEND")
956 {
957 struct sbuf *s = NULL;
958
959 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
960 SBUF_ASSERT_EQ(-1, sbuf_extend(s, 10));
961
962 sbuf_delete(s);
963 }
964
965 SBUF_SHOULD("accommodate reasonable requests")
966 {
967 struct sbuf *s = NULL;
968 int size_before;
969
970 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
971 size_before = s->s_size;
972
973 SBUF_ASSERT_EQ(0, sbuf_extend(s, 10));
974 SBUF_ASSERT_GTE(10, s->s_size - size_before);
975
976 sbuf_delete(s);
977 }
978
979 SBUF_SHOULD("reject requests that cause overflows")
980 {
981 struct sbuf *s = NULL;
982
983 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
984 SBUF_ASSERT_EQ(-1, sbuf_extend(s, SIZE_MAX));
985 SBUF_ASSERT_EQ(-1, sbuf_extend(s, INT_MAX));
986
987 sbuf_delete(s);
988 }
989
990 SBUF_SHOULD("transform the sbuf into an SBUF_DYNAMIC one")
991 {
992 struct sbuf *s = NULL;
993 char buf[4] = { 0 };
994
995 s = sbuf_new(NULL, buf, sizeof(buf), SBUF_AUTOEXTEND);
996 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_DYNAMIC));
997 SBUF_ASSERT_EQ(0, sbuf_extend(s, 10));
998 SBUF_ASSERT(SBUF_ISSET(s, SBUF_DYNAMIC));
999
1000 sbuf_delete(s);
1001 }
1002 }
1003
1004 SBUF_TESTING("sbuf_capacity")
1005 {
1006 SBUF_SHOULD("account for the trailing nul byte")
1007 {
1008 struct sbuf *s = NULL;
1009
1010 s = sbuf_new(NULL, NULL, 16, 0);
1011 SBUF_ASSERT_EQ(s->s_size - s->s_len - 1, sbuf_capacity(s));
1012
1013 sbuf_delete(s);
1014 }
1015 }
1016
1017 SBUF_TESTING("sbuf_ensure_capacity")
1018 {
1019 SBUF_SHOULD("return 0 if the sbuf already has enough capacity")
1020 {
1021 struct sbuf *s = NULL;
1022 int size_before;
1023
1024 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1025 size_before = s->s_size;
1026 SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s, 5));
1027 SBUF_ASSERT_EQ(size_before, s->s_size);
1028
1029 sbuf_delete(s);
1030 }
1031
1032 SBUF_SHOULD("extend the buffer as needed")
1033 {
1034 struct sbuf *s = NULL;
1035 int size_before;
1036
1037 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1038 size_before = s->s_size;
1039 SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s, 30));
1040 SBUF_ASSERT_GT(size_before, s->s_size);
1041
1042 sbuf_delete(s);
1043 }
1044 }
1045
1046 SBUF_TESTING("sbuf_bcat")
1047 {
1048 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1049 {
1050 struct sbuf *s = NULL;
1051
1052 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1053 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1054 SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "A", 1));
1055
1056 sbuf_delete(s);
1057 }
1058
1059 SBUF_SHOULD("fail if len is too big")
1060 {
1061 struct sbuf *s = NULL;
1062
1063 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1064 SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "A", INT_MAX));
1065 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1066
1067 sbuf_delete(s);
1068 }
1069
1070 SBUF_SHOULD("succeed for a fixed buf within limits")
1071 {
1072 struct sbuf *s = NULL;
1073
1074 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1075 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "ABC", 3));
1076 SBUF_ASSERT_EQ(3, s->s_len);
1077 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1078 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1079 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1080
1081 sbuf_delete(s);
1082 }
1083
1084 SBUF_SHOULD("succeed for binary data, even with nul bytes")
1085 {
1086 struct sbuf *s = NULL;
1087
1088 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1089 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "A\0C", 3));
1090 SBUF_ASSERT_EQ(3, s->s_len);
1091 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1092 SBUF_ASSERT_EQ('\0', s->s_buf[1]);
1093 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1094
1095 sbuf_delete(s);
1096 }
1097
1098 SBUF_SHOULD("append to existing data")
1099 {
1100 struct sbuf *s = NULL;
1101
1102 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1103 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "ABC", 3));
1104 SBUF_ASSERT_EQ(3, s->s_len);
1105 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1106 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1107 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1108
1109 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "DEF", 3));
1110 SBUF_ASSERT_EQ(6, s->s_len);
1111 SBUF_ASSERT_EQ('D', s->s_buf[3]);
1112 SBUF_ASSERT_EQ('E', s->s_buf[4]);
1113 SBUF_ASSERT_EQ('F', s->s_buf[5]);
1114
1115 sbuf_delete(s);
1116 }
1117
1118 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1119 {
1120 struct sbuf *s = NULL;
1121
1122 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1123 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "0123456789abcde", 15));
1124 SBUF_ASSERT_EQ(15, s->s_len);
1125
1126 sbuf_delete(s);
1127 }
1128
1129 SBUF_SHOULD("fail for a fixed buf if too big")
1130 {
1131 struct sbuf *s = NULL;
1132
1133 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1134 SBUF_ASSERT_EQ(-1, sbuf_bcat(s, "0123456789abcdef", 16));
1135 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1136
1137 sbuf_delete(s);
1138 }
1139
1140 SBUF_SHOULD("expand the backing buffer as needed")
1141 {
1142 struct sbuf *s = NULL;
1143 int size_before;
1144
1145 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1146 size_before = s->s_size;
1147 SBUF_ASSERT_EQ(0, sbuf_bcat(s, "0123456789abcdef", 16));
1148 SBUF_ASSERT_GT(size_before, s->s_size);
1149 SBUF_ASSERT_EQ(16, s->s_len);
1150
1151 sbuf_delete(s);
1152 }
1153 }
1154
1155 SBUF_TESTING("sbuf_bcpy")
1156 {
1157 SBUF_SHOULD("overwrite any existing data")
1158 {
1159 struct sbuf *s = NULL;
1160
1161 s = sbuf_new(NULL, NULL, 16, 0);
1162 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "ABC", 3));
1163 SBUF_ASSERT_EQ(3, s->s_len);
1164 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1165 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1166 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1167
1168 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "XYZ123", 6));
1169 SBUF_ASSERT_EQ(6, s->s_len);
1170 SBUF_ASSERT_EQ('X', s->s_buf[0]);
1171 SBUF_ASSERT_EQ('Y', s->s_buf[1]);
1172 SBUF_ASSERT_EQ('Z', s->s_buf[2]);
1173 SBUF_ASSERT_EQ('1', s->s_buf[3]);
1174 SBUF_ASSERT_EQ('2', s->s_buf[4]);
1175 SBUF_ASSERT_EQ('3', s->s_buf[5]);
1176
1177 sbuf_delete(s);
1178 }
1179
1180 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1181 {
1182 struct sbuf *s = NULL;
1183
1184 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1185 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1186 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "A", 1));
1187
1188 sbuf_delete(s);
1189 }
1190
1191 SBUF_SHOULD("fail if len is too big")
1192 {
1193 struct sbuf *s = NULL;
1194
1195 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1196 SBUF_ASSERT_EQ(-1, sbuf_bcpy(s, "A", INT_MAX));
1197 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1198
1199 sbuf_delete(s);
1200 }
1201
1202 SBUF_SHOULD("succeed for a fixed buf within limits")
1203 {
1204 struct sbuf *s = NULL;
1205
1206 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1207 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "ABC", 3));
1208 SBUF_ASSERT_EQ(3, s->s_len);
1209 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1210 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1211 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1212
1213 sbuf_delete(s);
1214 }
1215
1216 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1217 {
1218 struct sbuf *s = NULL;
1219
1220 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1221 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "0123456789abcde", 15));
1222 SBUF_ASSERT_EQ(15, s->s_len);
1223
1224 sbuf_delete(s);
1225 }
1226
1227 SBUF_SHOULD("fail for a fixed buf if too big")
1228 {
1229 struct sbuf *s = NULL;
1230
1231 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1232 SBUF_ASSERT_EQ(-1, sbuf_bcpy(s, "0123456789abcdef", 16));
1233 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1234
1235 sbuf_delete(s);
1236 }
1237
1238 SBUF_SHOULD("expand the backing buffer as needed")
1239 {
1240 struct sbuf *s = NULL;
1241 int size_before;
1242
1243 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1244 size_before = s->s_size;
1245 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "0123456789abcdef", 16));
1246 SBUF_ASSERT_GT(size_before, s->s_size);
1247 SBUF_ASSERT_EQ(16, s->s_len);
1248
1249 sbuf_delete(s);
1250 }
1251 }
1252
1253 SBUF_TESTING("sbuf_cat")
1254 {
1255 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1256 {
1257 struct sbuf *s = NULL;
1258
1259 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1260 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1261 SBUF_ASSERT_EQ(-1, sbuf_cat(s, "A"));
1262
1263 sbuf_delete(s);
1264 }
1265
1266 SBUF_SHOULD("succeed for a fixed buf within limits")
1267 {
1268 struct sbuf *s = NULL;
1269
1270 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1271 SBUF_ASSERT_EQ(0, sbuf_cat(s, "ABC"));
1272 SBUF_ASSERT_EQ(3, s->s_len);
1273 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1274 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1275 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1276
1277 sbuf_delete(s);
1278 }
1279
1280 SBUF_SHOULD("only copy up to a nul byte")
1281 {
1282 struct sbuf *s = NULL;
1283
1284 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1285 SBUF_ASSERT_EQ(0, sbuf_cat(s, "A\0C"));
1286 SBUF_ASSERT_EQ(1, s->s_len);
1287 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1288
1289 sbuf_delete(s);
1290 }
1291
1292 SBUF_SHOULD("append to existing data")
1293 {
1294 struct sbuf *s = NULL;
1295
1296 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1297 SBUF_ASSERT_EQ(0, sbuf_cat(s, "ABC"));
1298 SBUF_ASSERT_EQ(3, s->s_len);
1299 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1300 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1301 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1302
1303 SBUF_ASSERT_EQ(0, sbuf_cat(s, "DEF"));
1304 SBUF_ASSERT_EQ(6, s->s_len);
1305 SBUF_ASSERT_EQ('D', s->s_buf[3]);
1306 SBUF_ASSERT_EQ('E', s->s_buf[4]);
1307 SBUF_ASSERT_EQ('F', s->s_buf[5]);
1308
1309 sbuf_delete(s);
1310 }
1311
1312 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1313 {
1314 struct sbuf *s = NULL;
1315
1316 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1317 SBUF_ASSERT_EQ(0, sbuf_cat(s, "0123456789abcde"));
1318 SBUF_ASSERT_EQ(15, s->s_len);
1319
1320 sbuf_delete(s);
1321 }
1322
1323 SBUF_SHOULD("fail for a fixed buf if too big")
1324 {
1325 struct sbuf *s = NULL;
1326
1327 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1328 SBUF_ASSERT_EQ(-1, sbuf_cat(s, "0123456789abcdef"));
1329 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1330
1331 sbuf_delete(s);
1332 }
1333
1334 SBUF_SHOULD("expand the backing buffer as needed")
1335 {
1336 struct sbuf *s = NULL;
1337 int size_before;
1338
1339 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1340 size_before = s->s_size;
1341 SBUF_ASSERT_EQ(0, sbuf_cat(s, "0123456789abcdef"));
1342 SBUF_ASSERT_GT(size_before, s->s_size);
1343 SBUF_ASSERT_EQ(16, s->s_len);
1344
1345 sbuf_delete(s);
1346 }
1347 }
1348
1349 SBUF_TESTING("sbuf_cpy")
1350 {
1351 SBUF_SHOULD("overwrite any existing data")
1352 {
1353 struct sbuf *s = NULL;
1354
1355 s = sbuf_new(NULL, NULL, 16, 0);
1356 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "ABC"));
1357 SBUF_ASSERT_EQ(3, s->s_len);
1358 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1359 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1360 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1361
1362 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "XYZ123"));
1363 SBUF_ASSERT_EQ(6, s->s_len);
1364 SBUF_ASSERT_EQ('X', s->s_buf[0]);
1365 SBUF_ASSERT_EQ('Y', s->s_buf[1]);
1366 SBUF_ASSERT_EQ('Z', s->s_buf[2]);
1367 SBUF_ASSERT_EQ('1', s->s_buf[3]);
1368 SBUF_ASSERT_EQ('2', s->s_buf[4]);
1369 SBUF_ASSERT_EQ('3', s->s_buf[5]);
1370
1371 sbuf_delete(s);
1372 }
1373
1374 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1375 {
1376 struct sbuf *s = NULL;
1377
1378 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1379 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1380 SBUF_ASSERT_EQ(0, sbuf_bcpy(s, "A", 1));
1381
1382 sbuf_delete(s);
1383 }
1384
1385 SBUF_SHOULD("succeed for a fixed buf within limits")
1386 {
1387 struct sbuf *s = NULL;
1388
1389 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1390 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "ABC"));
1391 SBUF_ASSERT_EQ(3, s->s_len);
1392 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1393 SBUF_ASSERT_EQ('B', s->s_buf[1]);
1394 SBUF_ASSERT_EQ('C', s->s_buf[2]);
1395
1396 sbuf_delete(s);
1397 }
1398
1399 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1400 {
1401 struct sbuf *s = NULL;
1402
1403 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1404 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
1405 SBUF_ASSERT_EQ(15, s->s_len);
1406
1407 sbuf_delete(s);
1408 }
1409
1410 SBUF_SHOULD("fail for a fixed buf if too big")
1411 {
1412 struct sbuf *s = NULL;
1413
1414 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1415 SBUF_ASSERT_EQ(-1, sbuf_cpy(s, "0123456789abcdef"));
1416 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1417
1418 sbuf_delete(s);
1419 }
1420
1421 SBUF_SHOULD("expand the backing buffer as needed")
1422 {
1423 struct sbuf *s = NULL;
1424 int size_before;
1425
1426 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1427 size_before = s->s_size;
1428 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcdef"));
1429 SBUF_ASSERT_GT(size_before, s->s_size);
1430 SBUF_ASSERT_EQ(16, s->s_len);
1431
1432 sbuf_delete(s);
1433 }
1434 }
1435
1436 /* also tests sbuf_vprintf: */
1437 SBUF_TESTING("sbuf_printf")
1438 {
1439 SBUF_SHOULD("support simple printing")
1440 {
1441 struct sbuf *s = NULL;
1442
1443 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1444 SBUF_ASSERT_EQ(0, sbuf_printf(s, "hello"));
1445 SBUF_ASSERT_EQ(5, s->s_len);
1446 SBUF_ASSERT_EQ('h', s->s_buf[0]);
1447 SBUF_ASSERT_EQ('e', s->s_buf[1]);
1448 SBUF_ASSERT_EQ('l', s->s_buf[2]);
1449 SBUF_ASSERT_EQ('l', s->s_buf[3]);
1450 SBUF_ASSERT_EQ('o', s->s_buf[4]);
1451
1452 sbuf_delete(s);
1453 }
1454
1455 SBUF_SHOULD("support format strings")
1456 {
1457 struct sbuf *s = NULL;
1458 char data1 = 'A';
1459 int data2 = 123;
1460 const char *data3 = "foo";
1461
1462 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1463 SBUF_ASSERT_EQ(0, sbuf_printf(s, "%c %d %s", data1, data2, data3));
1464 SBUF_ASSERT_EQ(9, s->s_len);
1465 SBUF_ASSERT_EQ('A', s->s_buf[0]);
1466 SBUF_ASSERT_EQ(' ', s->s_buf[1]);
1467 SBUF_ASSERT_EQ('1', s->s_buf[2]);
1468 SBUF_ASSERT_EQ('2', s->s_buf[3]);
1469 SBUF_ASSERT_EQ('3', s->s_buf[4]);
1470 SBUF_ASSERT_EQ(' ', s->s_buf[5]);
1471 SBUF_ASSERT_EQ('f', s->s_buf[6]);
1472 SBUF_ASSERT_EQ('o', s->s_buf[7]);
1473 SBUF_ASSERT_EQ('o', s->s_buf[8]);
1474
1475 sbuf_delete(s);
1476 }
1477
1478 SBUF_SHOULD("work with the fact we reserve a nul byte at the end")
1479 {
1480 struct sbuf *s = NULL;
1481
1482 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1483 SBUF_ASSERT_EQ(0, sbuf_printf(s, "0123456789abcde"));
1484 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1485
1486 sbuf_delete(s);
1487 }
1488
1489 SBUF_SHOULD("mark the sbuf as overflowed if we try to write too much")
1490 {
1491 struct sbuf *s = NULL;
1492
1493 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1494 SBUF_ASSERT_EQ(-1, sbuf_printf(s, "0123456789abcdef"));
1495 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1496
1497 sbuf_delete(s);
1498 }
1499
1500 SBUF_SHOULD("auto-extend as necessary")
1501 {
1502 struct sbuf *s = NULL;
1503 const char *data = "0123456789abcdef";
1504 int size_before;
1505 size_t n;
1506
1507 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1508 size_before = s->s_size;
1509 SBUF_ASSERT_EQ(0, sbuf_printf(s, "%s", data));
1510 SBUF_ASSERT_GT(size_before, s->s_size);
1511
1512 for (n = 0; n < strlen(data); ++n) {
1513 SBUF_ASSERT_EQ(data[n], s->s_buf[n]);
1514 }
1515
1516 sbuf_delete(s);
1517 }
1518
1519 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1520 {
1521 struct sbuf *s = NULL;
1522
1523 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1524 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1525 SBUF_ASSERT_EQ(-1, sbuf_printf(s, "A"));
1526
1527 sbuf_delete(s);
1528 }
1529 }
1530
1531 SBUF_TESTING("sbuf_putc")
1532 {
1533 SBUF_SHOULD("work where we have capacity")
1534 {
1535 struct sbuf *s = NULL;
1536
1537 s = sbuf_new(NULL, NULL, 16, 0);
1538 SBUF_ASSERT_EQ(0, sbuf_putc(s, 'a'));
1539 SBUF_ASSERT_EQ(1, s->s_len);
1540 SBUF_ASSERT_EQ('a', s->s_buf[0]);
1541
1542 sbuf_delete(s);
1543 }
1544
1545 SBUF_SHOULD("fail if we have a full, fixedlen sbuf")
1546 {
1547 struct sbuf *s = NULL;
1548
1549 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1550 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcd"));
1551 SBUF_ASSERT_EQ(0, sbuf_putc(s, 'e'));
1552 SBUF_ASSERT_EQ(-1, sbuf_putc(s, 'f'));
1553 SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1554
1555 sbuf_delete(s);
1556 }
1557
1558 SBUF_SHOULD("ignore nul")
1559 {
1560 struct sbuf *s = NULL;
1561
1562 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1563 SBUF_ASSERT_EQ(0, sbuf_putc(s, '\0'));
1564 SBUF_ASSERT_EQ(0, s->s_len);
1565
1566 sbuf_delete(s);
1567 }
1568
1569 SBUF_SHOULD("auto-extend if necessary")
1570 {
1571 struct sbuf *s = NULL;
1572 int len_before;
1573 int size_before;
1574
1575 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1576 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
1577 len_before = s->s_len;
1578 size_before = s->s_size;
1579 SBUF_ASSERT_EQ(0, sbuf_putc(s, 'f'));
1580 SBUF_ASSERT_EQ(len_before + 1, s->s_len);
1581 SBUF_ASSERT_GT(size_before, s->s_size);
1582 SBUF_ASSERT_EQ('f', s->s_buf[s->s_len - 1]);
1583
1584 sbuf_delete(s);
1585 }
1586
1587 SBUF_SHOULD("fail if the sbuf is overflowed")
1588 {
1589 struct sbuf *s = NULL;
1590
1591 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1592 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1593 SBUF_ASSERT_EQ(-1, sbuf_putc(s, 'a'));
1594
1595 sbuf_delete(s);
1596 }
1597 }
1598
1599 SBUF_TESTING("sbuf_trim")
1600 {
1601 SBUF_SHOULD("remove trailing spaces, tabs and newlines")
1602 {
1603 struct sbuf *s = NULL;
1604 const char *test = "foo \t\t\n\t";
1605
1606 s = sbuf_new(NULL, NULL, 16, 0);
1607 SBUF_ASSERT_EQ(0, sbuf_cpy(s, test));
1608 SBUF_ASSERT_EQ(strlen(test), s->s_len);
1609 SBUF_ASSERT_EQ(0, sbuf_trim(s));
1610 SBUF_ASSERT_EQ(3, s->s_len);
1611
1612 sbuf_delete(s);
1613 }
1614
1615 SBUF_SHOULD("do nothing if there is no trailing whitespace")
1616 {
1617 struct sbuf *s = NULL;
1618 const char *test = "foo";
1619
1620 s = sbuf_new(NULL, NULL, 16, 0);
1621 SBUF_ASSERT_EQ(0, sbuf_cpy(s, test));
1622 SBUF_ASSERT_EQ(strlen(test), s->s_len);
1623 SBUF_ASSERT_EQ(0, sbuf_trim(s));
1624 SBUF_ASSERT_EQ(strlen(test), s->s_len);
1625
1626 sbuf_delete(s);
1627 }
1628
1629 SBUF_SHOULD("fail if the sbuf is overflowed")
1630 {
1631 struct sbuf *s = NULL;
1632 const char *test = "foo ";
1633
1634 s = sbuf_new(NULL, NULL, 16, 0);
1635 SBUF_ASSERT_EQ(0, sbuf_cpy(s, test));
1636 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1637 SBUF_ASSERT_EQ(-1, sbuf_trim(s));
1638 SBUF_ASSERT_EQ(strlen(test), s->s_len);
1639
1640 sbuf_delete(s);
1641 }
1642
1643 SBUF_SHOULD("work on empty strings")
1644 {
1645 struct sbuf *s = NULL;
1646
1647 s = sbuf_new(NULL, NULL, 16, 0);
1648 SBUF_ASSERT_EQ(0, sbuf_trim(s));
1649 SBUF_ASSERT_EQ(0, s->s_len);
1650
1651 sbuf_delete(s);
1652 }
1653 }
1654
1655 SBUF_TESTING("sbuf_overflowed")
1656 {
1657 SBUF_SHOULD("return false if it hasn't overflowed")
1658 {
1659 struct sbuf *s = NULL;
1660
1661 s = sbuf_new(NULL, NULL, 16, 0);
1662 SBUF_ASSERT_NOT(sbuf_overflowed(s));
1663
1664 sbuf_delete(s);
1665 }
1666
1667 SBUF_SHOULD("return true if it has overflowed")
1668 {
1669 struct sbuf *s = NULL;
1670
1671 s = sbuf_new(NULL, NULL, 16, 0);
1672 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1673 SBUF_ASSERT(sbuf_overflowed(s));
1674
1675 sbuf_delete(s);
1676 }
1677 }
1678
1679 SBUF_TESTING("sbuf_finish")
1680 {
1681 SBUF_SHOULD("insert a nul byte, clear the overflowed flag and set the finished flag")
1682 {
1683 struct sbuf *s = NULL;
1684
1685 s = sbuf_new(NULL, NULL, 16, 0);
1686 SBUF_ASSERT_EQ(0, sbuf_putc(s, 'A'));
1687 s->s_buf[s->s_len] = 'x';
1688 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1689 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_FINISHED));
1690
1691 sbuf_finish(s);
1692
1693 SBUF_ASSERT_EQ(0, s->s_buf[s->s_len]);
1694 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED));
1695 SBUF_ASSERT(SBUF_ISSET(s, SBUF_FINISHED));
1696
1697 sbuf_delete(s);
1698 }
1699 }
1700
1701 SBUF_TESTING("sbuf_data")
1702 {
1703 SBUF_SHOULD("return the s_buf pointer")
1704 {
1705 struct sbuf *s = NULL;
1706
1707 s = sbuf_new(NULL, NULL, 16, 0);
1708 SBUF_ASSERT_EQ(s->s_buf, sbuf_data(s));
1709
1710 sbuf_delete(s);
1711 }
1712
1713 SBUF_SHOULD("return the buffer we gave it")
1714 {
1715 struct sbuf *s = NULL;
1716 char buf[4] = { 0 };
1717
1718 s = sbuf_new(NULL, buf, sizeof(buf), 0);
1719 SBUF_ASSERT_EQ(buf, sbuf_data(s));
1720
1721 sbuf_delete(s);
1722 }
1723 }
1724
1725 SBUF_TESTING("sbuf_len")
1726 {
1727 SBUF_SHOULD("return the length of the sbuf data")
1728 {
1729 struct sbuf *s = NULL;
1730
1731 s = sbuf_new(NULL, NULL, 16, 0);
1732 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "hello"));
1733 SBUF_ASSERT_EQ(5, sbuf_len(s));
1734
1735 sbuf_delete(s);
1736 }
1737
1738 SBUF_SHOULD("return -1 if the sbuf is overflowed")
1739 {
1740 struct sbuf *s = NULL;
1741
1742 s = sbuf_new(NULL, NULL, 16, 0);
1743 SBUF_ASSERT_EQ(0, sbuf_cpy(s, "hello"));
1744 SBUF_ASSERT_EQ(5, sbuf_len(s));
1745 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1746 SBUF_ASSERT_EQ(-1, sbuf_len(s));
1747
1748 sbuf_delete(s);
1749 }
1750 }
1751
1752 SBUF_TESTING("sbuf_done")
1753 {
1754 SBUF_SHOULD("return false if the sbuf isn't finished")
1755 {
1756 struct sbuf *s = NULL;
1757
1758 s = sbuf_new(NULL, NULL, 16, 0);
1759 SBUF_ASSERT_NOT(sbuf_done(s));
1760
1761 sbuf_delete(s);
1762 }
1763
1764 SBUF_SHOULD("return true if the sbuf has finished")
1765 {
1766 struct sbuf *s = NULL;
1767
1768 s = sbuf_new(NULL, NULL, 16, 0);
1769 SBUF_ASSERT_NOT(sbuf_done(s));
1770 SBUF_SETFLAG(s, SBUF_FINISHED);
1771 SBUF_ASSERT(sbuf_done(s));
1772
1773 sbuf_delete(s);
1774 }
1775 }
1776
1777 SBUF_TESTING("sbuf_delete")
1778 {
1779 SBUF_SHOULD("just free the backing buffer if we supplied an sbuf")
1780 {
1781 struct sbuf *s = NULL;
1782 struct sbuf existing = {};
1783
1784 s = sbuf_new(&existing, NULL, 16, 0);
1785 SBUF_ASSERT_NE(NULL, s->s_buf);
1786
1787 sbuf_delete(s);
1788 SBUF_ASSERT_EQ(NULL, s->s_buf);
1789 }
1790 }
1791
1792 SBUF_TEST_END;
1793}
1794
1795SYSCTL_PROC(_kern, OID_AUTO, sbuf_test, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_MASKED, 0, 0, sysctl_sbuf_tests, "A", "sbuf tests");
1796
1797#endif /* DEBUG || DEVELOPMENT */
1798