2 * Copyright (c) 2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <kern/kalloc.h>
29 #include <libkern/libkern.h>
31 #include <os/overflow.h>
32 #include <sys/param.h>
36 #if DEBUG || DEVELOPMENT
37 #include <kern/macro_help.h>
38 #include <sys/errno.h>
39 #include <sys/sysctl.h>
40 #endif /* DEBUG || DEVELOPMENT */
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)
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)
52 #define SBUF_MINEXTENDSIZE 16
53 #define SBUF_MAXEXTENDSIZE PAGE_SIZE
54 #define SBUF_MAXEXTENDINCR PAGE_SIZE
57 * @function sbuf_delete
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).
65 * The sbuf to destroy.
68 sbuf_delete(struct sbuf
*s
)
70 if (SBUF_ISDYNAMIC(s
) && s
->s_buf
) {
71 kheap_free(KHEAP_DATA_BUFFERS
, s
->s_buf
, s
->s_size
);
75 if (SBUF_ISDYNSTRUCT(s
)) {
76 kheap_free(KHEAP_DEFAULT
, s
, sizeof(*s
));
81 * @function sbuf_extendsize
84 * Attempts to extend the size of an sbuf to the value pointed to by 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
92 * 0 on success, -1 on failure.
95 sbuf_extendsize(size_t *size
)
97 size_t target_size
= *size
;
100 if (target_size
> INT_MAX
) {
104 if (target_size
< SBUF_MAXEXTENDSIZE
) {
105 new_size
= SBUF_MINEXTENDSIZE
;
106 while (new_size
< target_size
) {
110 /* round up to nearest page: */
111 new_size
= (target_size
+ PAGE_SIZE
- 1) & ~PAGE_MASK
;
114 if (new_size
> INT_MAX
) {
126 * Allocates and/or initializes an sbuf.
129 * An optional existing sbuf to initialize. If NULL, a new one is allocated on
133 * An optional existing backing buffer to assign to the sbuf. If NULL, a new
134 * one is allocated on the heap.
137 * The initial size of the sbuf. The actual size may be greater than this
141 * The flags to set on the sbuf. Accepted values are:
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
149 * The new and/or initialized sbuf on success, or NULL on failure.
152 sbuf_new(struct sbuf
*s
, char *buf
, int length_
, int flags
)
154 size_t length
= (size_t)length_
;
156 if (length
> INT_MAX
|| flags
& ~SBUF_USRFLAGMSK
) {
161 s
= (struct sbuf
*)kheap_alloc(KHEAP_DEFAULT
, sizeof(*s
), Z_WAITOK
);
166 bzero(s
, sizeof(*s
));
168 SBUF_SETFLAG(s
, SBUF_DYNSTRUCT
);
170 bzero(s
, sizeof(*s
));
175 s
->s_size
= (int)length
;
180 if (SBUF_CANEXTEND(s
) && (-1 == sbuf_extendsize(&length
))) {
185 * we always need at least 1 byte for \0, so s_size of 0 will cause an
186 * underflow in sbuf_capacity.
192 s
->s_buf
= (char *)kheap_alloc(KHEAP_DATA_BUFFERS
, length
, Z_WAITOK
);
193 if (NULL
== s
->s_buf
) {
196 bzero(s
->s_buf
, length
);
197 s
->s_size
= (int)length
;
199 SBUF_SETFLAG(s
, SBUF_DYNAMIC
);
208 * @function sbuf_setpos
211 * Set the current position of the sbuf.
214 * The sbuf to modify.
217 * The new position to set. Must be less than or equal to the current position.
220 * 0 on success, -1 on failure.
223 sbuf_setpos(struct sbuf
*s
, int pos
)
225 if (pos
< 0 || pos
> s
->s_len
) {
234 * @function sbuf_clear
237 * Resets the position/length of the sbuf data to zero and clears the finished
238 * and overflow flags.
244 sbuf_clear(struct sbuf
*s
)
246 SBUF_CLEARFLAG(s
, SBUF_FINISHED
);
247 SBUF_CLEARFLAG(s
, SBUF_OVERFLOWED
);
252 * @function sbuf_extend
255 * Attempt to extend the size of an sbuf's backing buffer by @a addlen bytes.
258 * The sbuf to extend.
261 * How many bytes to increase the size by.
264 * 0 on success, -1 on failure.
266 static int OS_WARN_RESULT
267 sbuf_extend(struct sbuf
*s
, size_t addlen
)
276 if (!SBUF_CANEXTEND(s
)) {
280 if (os_add_overflow((size_t)s
->s_size
, addlen
, &new_size
)) {
284 if (-1 == sbuf_extendsize(&new_size
)) {
288 new_buf
= (char *)kheap_alloc(KHEAP_DATA_BUFFERS
, new_size
, Z_WAITOK
);
289 if (NULL
== new_buf
) {
293 bcopy(s
->s_buf
, new_buf
, (size_t)s
->s_size
);
294 if (SBUF_ISDYNAMIC(s
)) {
295 kheap_free(KHEAP_DATA_BUFFERS
, s
->s_buf
, (size_t)s
->s_size
);
297 SBUF_SETFLAG(s
, SBUF_DYNAMIC
);
301 s
->s_size
= (int)new_size
;
306 * @function sbuf_capacity
309 * Get the current capacity of an sbuf: how many more bytes we can append given
310 * the current size and position.
313 * The sbuf to get the capacity of.
316 * The current sbuf capacity.
319 sbuf_capacity(const struct sbuf
*s
)
321 /* 1 byte reserved for \0: */
322 return (size_t)(s
->s_size
- s
->s_len
- 1);
326 * @function sbuf_ensure_capacity
329 * Ensure that an sbuf can accommodate @a add_len bytes, reallocating the
330 * backing buffer if necessary.
336 * The minimum capacity to ensure @a s has.
339 * 0 if the minimum capacity is met by @a s, or -1 on error.
342 sbuf_ensure_capacity(struct sbuf
*s
, size_t wanted
)
346 size
= sbuf_capacity(s
);
347 if (size
>= wanted
) {
351 return sbuf_extend(s
, wanted
- size
);
355 * @function sbuf_bcat
358 * Append data to an sbuf.
364 * The data to append.
367 * The length of the data.
370 * 0 on success, -1 on failure. Will always fail if the sbuf is marked as
374 sbuf_bcat(struct sbuf
*s
, const void *data
, size_t len
)
376 if (SBUF_HASOVERFLOWED(s
)) {
380 if (-1 == sbuf_ensure_capacity(s
, len
)) {
381 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
385 bcopy(data
, s
->s_buf
+ s
->s_len
, len
);
386 s
->s_len
+= (int)len
; /* safe */
392 * @function sbuf_bcpy
395 * Set the entire sbuf data, possibly reallocating the backing buffer to
405 * The length of the data to set.
408 * 0 on success or -1 on failure. Will clear the finished/overflowed flags.
411 sbuf_bcpy(struct sbuf
*s
, const void *data
, size_t len
)
414 return sbuf_bcat(s
, data
, len
);
421 * Append a string to an sbuf, possibly expanding the backing buffer to
428 * The string to append.
431 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
435 sbuf_cat(struct sbuf
*s
, const char *str
)
437 return sbuf_bcat(s
, str
, strlen(str
));
444 * Set the entire sbuf data to the given nul-terminated string, possibly
445 * expanding the backing buffer to accommodate it if necessary.
451 * The string to set the sbuf data to.
454 * 0 on success, -1 on failure. Clears and resets the sbuf first.
457 sbuf_cpy(struct sbuf
*s
, const char *str
)
460 return sbuf_cat(s
, str
);
464 * @function sbuf_vprintf
467 * Formatted-print into an sbuf using a va_list.
476 * The format string argument data.
479 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
483 sbuf_vprintf(struct sbuf
*s
, const char *fmt
, va_list ap
)
490 if (SBUF_HASOVERFLOWED(s
)) {
495 capacity
= sbuf_capacity(s
);
497 va_copy(ap_copy
, ap
);
498 /* +1 for \0. safe because we already accommodate this. */
499 result
= vsnprintf(&s
->s_buf
[s
->s_len
], capacity
+ 1, fmt
, ap_copy
);
506 len
= (size_t)result
;
507 if (len
<= capacity
) {
508 s
->s_len
+= (int)len
;
511 } while (-1 != sbuf_ensure_capacity(s
, len
));
513 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
518 * @function sbuf_printf
521 * Formatted-print into an sbuf using variadic arguments.
530 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
534 sbuf_printf(struct sbuf
*s
, const char *fmt
, ...)
540 result
= sbuf_vprintf(s
, fmt
, ap
);
546 * @function sbuf_putc
549 * Append a single character to an sbuf. Ignores '\0'.
555 * The character to append.
558 * 0 on success, -1 on failure. This function will always fail if the sbuf is
559 * marked as overflowed.
562 sbuf_putc(struct sbuf
*s
, int c_
)
566 if (SBUF_HASOVERFLOWED(s
)) {
570 if (-1 == sbuf_ensure_capacity(s
, 1)) {
571 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
576 s
->s_buf
[s
->s_len
++] = c
;
585 return ch
== ' ' || ch
== '\n' || ch
== '\t';
589 * @function sbuf_trim
592 * Removes whitespace from the end of an sbuf.
598 * 0 on success or -1 if the sbuf is marked as overflowed.
601 sbuf_trim(struct sbuf
*s
)
603 if (SBUF_HASOVERFLOWED(s
)) {
607 while (s
->s_len
> 0 && isspace(s
->s_buf
[s
->s_len
- 1])) {
615 * @function sbuf_overflowed
618 * Indicates whether the sbuf is marked as overflowed.
624 * 1 if the sbuf has overflowed or 0 otherwise.
627 sbuf_overflowed(struct sbuf
*s
)
629 return !!SBUF_HASOVERFLOWED(s
);
633 * @function sbuf_finish
636 * Puts a trailing nul byte onto the sbuf data.
642 sbuf_finish(struct sbuf
*s
)
644 /* safe because we always reserve a byte at the end for \0: */
645 s
->s_buf
[s
->s_len
] = '\0';
646 SBUF_CLEARFLAG(s
, SBUF_OVERFLOWED
);
647 SBUF_SETFLAG(s
, SBUF_FINISHED
);
651 * @function sbuf_data
654 * Gets a pointer to the sbuf backing data.
660 * A pointer to the sbuf data.
663 sbuf_data(struct sbuf
*s
)
672 * Retrieves the current length of the sbuf data.
678 * The length of the sbuf data or -1 if the sbuf is marked as overflowed.
681 sbuf_len(struct sbuf
*s
)
683 if (SBUF_HASOVERFLOWED(s
)) {
691 * @function sbuf_done
694 * Tests if the sbuf is marked as finished.
700 * 1 if the sbuf is marked as finished or 0 if not.
703 sbuf_done(struct sbuf
*s
)
705 return !!SBUF_ISFINISHED(s
);
708 #if DEBUG || DEVELOPMENT
711 * a = assertion string
713 #define SBUF_FAIL(a) \
715 printf("sbuf_tests: failed assertion: %s\n", a); \
716 if (what != NULL && should != NULL) { \
717 printf("sbuf_tests: while testing: %s should %s\n", what, should); \
728 #define SBUF_ASSERT(x) \
737 #define SBUF_ASSERT_NOT(x) \
745 #define SBUF_ASSERT_CMP(e, a, c) \
750 SBUF_FAIL(#a " " #c " " #e); \
754 #define SBUF_ASSERT_EQ(e, a) SBUF_ASSERT_CMP(e, a, ==)
755 #define SBUF_ASSERT_NE(e, a) SBUF_ASSERT_CMP(e, a, !=)
756 #define SBUF_ASSERT_GT(e, a) SBUF_ASSERT_CMP(e, a, >)
757 #define SBUF_ASSERT_GTE(e, a) SBUF_ASSERT_CMP(e, a, >=)
758 #define SBUF_ASSERT_LT(e, a) SBUF_ASSERT_CMP(e, a, <)
759 #define SBUF_ASSERT_LTE(e, a) SBUF_ASSERT_CMP(e, a, <=)
761 #define SBUF_TEST_BEGIN \
763 const char *what = NULL; \
764 const char *should = NULL;
767 * include the trailing semi-colons here intentionally to allow for block-like
770 #define SBUF_TESTING(f) \
775 #define SBUF_SHOULD(s) \
780 #define SBUF_TEST_END \
781 printf("sbuf_tests: %zu assertions passed\n", passed); \
784 return ENOTRECOVERABLE;
787 sysctl_sbuf_tests SYSCTL_HANDLER_ARGS
789 #pragma unused(arg1, arg2)
791 char str
[32] = { 'o', 'k', 0 };
793 rval
= sysctl_handle_string(oidp
, str
, sizeof(str
), req
);
794 if (rval
!= 0 || req
->newptr
== 0 || req
->newlen
< 1) {
800 SBUF_TESTING("sbuf_new")
802 SBUF_SHOULD("fail to allocate >INT_MAX")
804 struct sbuf
*s
= NULL
;
806 s
= sbuf_new(NULL
, NULL
, INT_MAX
+ 1, 0);
807 SBUF_ASSERT_EQ(NULL
, s
);
810 SBUF_SHOULD("fail when claiming a backing buffer >INT_MAX")
812 struct sbuf
*s
= NULL
;
815 s
= sbuf_new(NULL
, buf
, INT_MAX
+ 1, 0);
816 SBUF_ASSERT_EQ(NULL
, s
);
819 SBUF_SHOULD("fail to allocate a zero-length sbuf")
821 struct sbuf
*s
= NULL
;
823 s
= sbuf_new(NULL
, NULL
, 0, 0);
824 SBUF_ASSERT_EQ(NULL
, s
);
827 SBUF_SHOULD("not accept invalid flags")
829 struct sbuf
*s
= NULL
;
831 s
= sbuf_new(NULL
, NULL
, 16, 0x10000);
832 SBUF_ASSERT_EQ(NULL
, s
);
835 SBUF_SHOULD("succeed when passed an existing sbuf")
837 struct sbuf
*s
= NULL
;
838 struct sbuf existing
;
840 memset(&existing
, 0x41, sizeof(existing
));
841 s
= sbuf_new(&existing
, NULL
, 16, SBUF_AUTOEXTEND
);
842 SBUF_ASSERT_EQ(&existing
, s
);
843 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_AUTOEXTEND
));
844 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_DYNAMIC
));
845 SBUF_ASSERT_NE(NULL
, s
->s_buf
);
846 SBUF_ASSERT_NE(0, s
->s_size
);
847 SBUF_ASSERT_EQ(0, s
->s_len
);
852 SBUF_SHOULD("succeed when passed an existing sbuf and buffer")
854 struct sbuf
*s
= NULL
;
855 struct sbuf existing
;
858 memset(&existing
, 0x41, sizeof(existing
));
859 s
= sbuf_new(&existing
, buf
, sizeof(buf
), 0);
860 SBUF_ASSERT_EQ(&existing
, s
);
861 SBUF_ASSERT_EQ(buf
, s
->s_buf
);
862 SBUF_ASSERT_EQ(4, s
->s_size
);
863 SBUF_ASSERT_EQ(0, s
->s_len
);
868 SBUF_SHOULD("succeed without an existing sbuf or buffer")
870 struct sbuf
*s
= NULL
;
872 s
= sbuf_new(NULL
, NULL
, 16, 0);
873 SBUF_ASSERT_NE(NULL
, s
);
874 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_DYNAMIC
));
875 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_DYNSTRUCT
));
876 SBUF_ASSERT_NE(NULL
, s
->s_buf
);
877 SBUF_ASSERT_NE(0, s
->s_size
);
878 SBUF_ASSERT_EQ(0, s
->s_len
);
883 SBUF_SHOULD("succeed without an existing sbuf, but with a buffer")
885 struct sbuf
*s
= NULL
;
888 s
= sbuf_new(NULL
, buf
, sizeof(buf
), 0);
889 SBUF_ASSERT_NE(NULL
, s
);
890 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_DYNSTRUCT
));
891 SBUF_ASSERT_EQ(buf
, s
->s_buf
);
892 SBUF_ASSERT_EQ(4, s
->s_size
);
893 SBUF_ASSERT_EQ(0, s
->s_len
);
898 SBUF_SHOULD("round up the requested size if SBUF_AUTOEXTEND")
900 struct sbuf
*s
= NULL
;
902 s
= sbuf_new(NULL
, NULL
, 1, SBUF_AUTOEXTEND
);
903 SBUF_ASSERT_GT(1, s
->s_size
);
909 SBUF_TESTING("sbuf_clear")
911 SBUF_SHOULD("clear the overflowed and finished flags")
913 struct sbuf
*s
= NULL
;
915 s
= sbuf_new(NULL
, NULL
, 16, 0);
917 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
918 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
919 SBUF_SETFLAG(s
, SBUF_FINISHED
);
920 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_FINISHED
));
922 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
923 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_FINISHED
));
928 SBUF_SHOULD("reset the position to zero")
930 struct sbuf
*s
= NULL
;
932 s
= sbuf_new(NULL
, NULL
, 16, 0);
936 SBUF_ASSERT_EQ(0, s
->s_len
);
942 SBUF_TESTING("sbuf_extend")
944 SBUF_SHOULD("allow zero")
946 struct sbuf
*s
= NULL
;
949 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
950 size_before
= s
->s_size
;
951 SBUF_ASSERT_EQ(0, sbuf_extend(s
, 0));
952 SBUF_ASSERT_EQ(size_before
, s
->s_size
);
957 SBUF_SHOULD("fail for sbuf not marked as SBUF_AUTOEXTEND")
959 struct sbuf
*s
= NULL
;
961 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
962 SBUF_ASSERT_EQ(-1, sbuf_extend(s
, 10));
967 SBUF_SHOULD("accommodate reasonable requests")
969 struct sbuf
*s
= NULL
;
972 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
973 size_before
= s
->s_size
;
975 SBUF_ASSERT_EQ(0, sbuf_extend(s
, 10));
976 SBUF_ASSERT_GTE(10, s
->s_size
- size_before
);
981 SBUF_SHOULD("reject requests that cause overflows")
983 struct sbuf
*s
= NULL
;
985 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
986 SBUF_ASSERT_EQ(-1, sbuf_extend(s
, SIZE_MAX
));
987 SBUF_ASSERT_EQ(-1, sbuf_extend(s
, INT_MAX
));
992 SBUF_SHOULD("transform the sbuf into an SBUF_DYNAMIC one")
994 struct sbuf
*s
= NULL
;
997 s
= sbuf_new(NULL
, buf
, sizeof(buf
), SBUF_AUTOEXTEND
);
998 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_DYNAMIC
));
999 SBUF_ASSERT_EQ(0, sbuf_extend(s
, 10));
1000 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_DYNAMIC
));
1006 SBUF_TESTING("sbuf_capacity")
1008 SBUF_SHOULD("account for the trailing nul byte")
1010 struct sbuf
*s
= NULL
;
1012 s
= sbuf_new(NULL
, NULL
, 16, 0);
1013 SBUF_ASSERT_EQ(s
->s_size
- s
->s_len
- 1, sbuf_capacity(s
));
1019 SBUF_TESTING("sbuf_ensure_capacity")
1021 SBUF_SHOULD("return 0 if the sbuf already has enough capacity")
1023 struct sbuf
*s
= NULL
;
1026 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1027 size_before
= s
->s_size
;
1028 SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s
, 5));
1029 SBUF_ASSERT_EQ(size_before
, s
->s_size
);
1034 SBUF_SHOULD("extend the buffer as needed")
1036 struct sbuf
*s
= NULL
;
1039 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1040 size_before
= s
->s_size
;
1041 SBUF_ASSERT_EQ(0, sbuf_ensure_capacity(s
, 30));
1042 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1048 SBUF_TESTING("sbuf_bcat")
1050 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1052 struct sbuf
*s
= NULL
;
1054 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1055 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1056 SBUF_ASSERT_EQ(-1, sbuf_bcat(s
, "A", 1));
1061 SBUF_SHOULD("fail if len is too big")
1063 struct sbuf
*s
= NULL
;
1065 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1066 SBUF_ASSERT_EQ(-1, sbuf_bcat(s
, "A", INT_MAX
));
1067 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1072 SBUF_SHOULD("succeed for a fixed buf within limits")
1074 struct sbuf
*s
= NULL
;
1076 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1077 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "ABC", 3));
1078 SBUF_ASSERT_EQ(3, s
->s_len
);
1079 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1080 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1081 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1086 SBUF_SHOULD("succeed for binary data, even with nul bytes")
1088 struct sbuf
*s
= NULL
;
1090 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1091 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "A\0C", 3));
1092 SBUF_ASSERT_EQ(3, s
->s_len
);
1093 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1094 SBUF_ASSERT_EQ('\0', s
->s_buf
[1]);
1095 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1100 SBUF_SHOULD("append to existing data")
1102 struct sbuf
*s
= NULL
;
1104 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1105 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "ABC", 3));
1106 SBUF_ASSERT_EQ(3, s
->s_len
);
1107 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1108 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1109 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1111 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "DEF", 3));
1112 SBUF_ASSERT_EQ(6, s
->s_len
);
1113 SBUF_ASSERT_EQ('D', s
->s_buf
[3]);
1114 SBUF_ASSERT_EQ('E', s
->s_buf
[4]);
1115 SBUF_ASSERT_EQ('F', s
->s_buf
[5]);
1120 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1122 struct sbuf
*s
= NULL
;
1124 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1125 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "0123456789abcde", 15));
1126 SBUF_ASSERT_EQ(15, s
->s_len
);
1131 SBUF_SHOULD("fail for a fixed buf if too big")
1133 struct sbuf
*s
= NULL
;
1135 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1136 SBUF_ASSERT_EQ(-1, sbuf_bcat(s
, "0123456789abcdef", 16));
1137 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1142 SBUF_SHOULD("expand the backing buffer as needed")
1144 struct sbuf
*s
= NULL
;
1147 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1148 size_before
= s
->s_size
;
1149 SBUF_ASSERT_EQ(0, sbuf_bcat(s
, "0123456789abcdef", 16));
1150 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1151 SBUF_ASSERT_EQ(16, s
->s_len
);
1157 SBUF_TESTING("sbuf_bcpy")
1159 SBUF_SHOULD("overwrite any existing data")
1161 struct sbuf
*s
= NULL
;
1163 s
= sbuf_new(NULL
, NULL
, 16, 0);
1164 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "ABC", 3));
1165 SBUF_ASSERT_EQ(3, s
->s_len
);
1166 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1167 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1168 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1170 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "XYZ123", 6));
1171 SBUF_ASSERT_EQ(6, s
->s_len
);
1172 SBUF_ASSERT_EQ('X', s
->s_buf
[0]);
1173 SBUF_ASSERT_EQ('Y', s
->s_buf
[1]);
1174 SBUF_ASSERT_EQ('Z', s
->s_buf
[2]);
1175 SBUF_ASSERT_EQ('1', s
->s_buf
[3]);
1176 SBUF_ASSERT_EQ('2', s
->s_buf
[4]);
1177 SBUF_ASSERT_EQ('3', s
->s_buf
[5]);
1182 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1184 struct sbuf
*s
= NULL
;
1186 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1187 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1188 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "A", 1));
1193 SBUF_SHOULD("fail if len is too big")
1195 struct sbuf
*s
= NULL
;
1197 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1198 SBUF_ASSERT_EQ(-1, sbuf_bcpy(s
, "A", INT_MAX
));
1199 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1204 SBUF_SHOULD("succeed for a fixed buf within limits")
1206 struct sbuf
*s
= NULL
;
1208 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1209 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "ABC", 3));
1210 SBUF_ASSERT_EQ(3, s
->s_len
);
1211 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1212 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1213 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1218 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1220 struct sbuf
*s
= NULL
;
1222 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1223 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "0123456789abcde", 15));
1224 SBUF_ASSERT_EQ(15, s
->s_len
);
1229 SBUF_SHOULD("fail for a fixed buf if too big")
1231 struct sbuf
*s
= NULL
;
1233 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1234 SBUF_ASSERT_EQ(-1, sbuf_bcpy(s
, "0123456789abcdef", 16));
1235 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1240 SBUF_SHOULD("expand the backing buffer as needed")
1242 struct sbuf
*s
= NULL
;
1245 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1246 size_before
= s
->s_size
;
1247 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "0123456789abcdef", 16));
1248 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1249 SBUF_ASSERT_EQ(16, s
->s_len
);
1255 SBUF_TESTING("sbuf_cat")
1257 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1259 struct sbuf
*s
= NULL
;
1261 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1262 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1263 SBUF_ASSERT_EQ(-1, sbuf_cat(s
, "A"));
1268 SBUF_SHOULD("succeed for a fixed buf within limits")
1270 struct sbuf
*s
= NULL
;
1272 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1273 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "ABC"));
1274 SBUF_ASSERT_EQ(3, s
->s_len
);
1275 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1276 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1277 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1282 SBUF_SHOULD("only copy up to a nul byte")
1284 struct sbuf
*s
= NULL
;
1286 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1287 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "A\0C"));
1288 SBUF_ASSERT_EQ(1, s
->s_len
);
1289 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1294 SBUF_SHOULD("append to existing data")
1296 struct sbuf
*s
= NULL
;
1298 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1299 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "ABC"));
1300 SBUF_ASSERT_EQ(3, s
->s_len
);
1301 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1302 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1303 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1305 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "DEF"));
1306 SBUF_ASSERT_EQ(6, s
->s_len
);
1307 SBUF_ASSERT_EQ('D', s
->s_buf
[3]);
1308 SBUF_ASSERT_EQ('E', s
->s_buf
[4]);
1309 SBUF_ASSERT_EQ('F', s
->s_buf
[5]);
1314 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1316 struct sbuf
*s
= NULL
;
1318 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1319 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "0123456789abcde"));
1320 SBUF_ASSERT_EQ(15, s
->s_len
);
1325 SBUF_SHOULD("fail for a fixed buf if too big")
1327 struct sbuf
*s
= NULL
;
1329 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1330 SBUF_ASSERT_EQ(-1, sbuf_cat(s
, "0123456789abcdef"));
1331 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1336 SBUF_SHOULD("expand the backing buffer as needed")
1338 struct sbuf
*s
= NULL
;
1341 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1342 size_before
= s
->s_size
;
1343 SBUF_ASSERT_EQ(0, sbuf_cat(s
, "0123456789abcdef"));
1344 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1345 SBUF_ASSERT_EQ(16, s
->s_len
);
1351 SBUF_TESTING("sbuf_cpy")
1353 SBUF_SHOULD("overwrite any existing data")
1355 struct sbuf
*s
= NULL
;
1357 s
= sbuf_new(NULL
, NULL
, 16, 0);
1358 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "ABC"));
1359 SBUF_ASSERT_EQ(3, s
->s_len
);
1360 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1361 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1362 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1364 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "XYZ123"));
1365 SBUF_ASSERT_EQ(6, s
->s_len
);
1366 SBUF_ASSERT_EQ('X', s
->s_buf
[0]);
1367 SBUF_ASSERT_EQ('Y', s
->s_buf
[1]);
1368 SBUF_ASSERT_EQ('Z', s
->s_buf
[2]);
1369 SBUF_ASSERT_EQ('1', s
->s_buf
[3]);
1370 SBUF_ASSERT_EQ('2', s
->s_buf
[4]);
1371 SBUF_ASSERT_EQ('3', s
->s_buf
[5]);
1376 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1378 struct sbuf
*s
= NULL
;
1380 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1381 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1382 SBUF_ASSERT_EQ(0, sbuf_bcpy(s
, "A", 1));
1387 SBUF_SHOULD("succeed for a fixed buf within limits")
1389 struct sbuf
*s
= NULL
;
1391 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1392 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "ABC"));
1393 SBUF_ASSERT_EQ(3, s
->s_len
);
1394 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1395 SBUF_ASSERT_EQ('B', s
->s_buf
[1]);
1396 SBUF_ASSERT_EQ('C', s
->s_buf
[2]);
1401 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1403 struct sbuf
*s
= NULL
;
1405 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1406 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "0123456789abcde"));
1407 SBUF_ASSERT_EQ(15, s
->s_len
);
1412 SBUF_SHOULD("fail for a fixed buf if too big")
1414 struct sbuf
*s
= NULL
;
1416 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1417 SBUF_ASSERT_EQ(-1, sbuf_cpy(s
, "0123456789abcdef"));
1418 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1423 SBUF_SHOULD("expand the backing buffer as needed")
1425 struct sbuf
*s
= NULL
;
1428 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1429 size_before
= s
->s_size
;
1430 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "0123456789abcdef"));
1431 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1432 SBUF_ASSERT_EQ(16, s
->s_len
);
1438 /* also tests sbuf_vprintf: */
1439 SBUF_TESTING("sbuf_printf")
1441 SBUF_SHOULD("support simple printing")
1443 struct sbuf
*s
= NULL
;
1445 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1446 SBUF_ASSERT_EQ(0, sbuf_printf(s
, "hello"));
1447 SBUF_ASSERT_EQ(5, s
->s_len
);
1448 SBUF_ASSERT_EQ('h', s
->s_buf
[0]);
1449 SBUF_ASSERT_EQ('e', s
->s_buf
[1]);
1450 SBUF_ASSERT_EQ('l', s
->s_buf
[2]);
1451 SBUF_ASSERT_EQ('l', s
->s_buf
[3]);
1452 SBUF_ASSERT_EQ('o', s
->s_buf
[4]);
1457 SBUF_SHOULD("support format strings")
1459 struct sbuf
*s
= NULL
;
1462 const char *data3
= "foo";
1464 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1465 SBUF_ASSERT_EQ(0, sbuf_printf(s
, "%c %d %s", data1
, data2
, data3
));
1466 SBUF_ASSERT_EQ(9, s
->s_len
);
1467 SBUF_ASSERT_EQ('A', s
->s_buf
[0]);
1468 SBUF_ASSERT_EQ(' ', s
->s_buf
[1]);
1469 SBUF_ASSERT_EQ('1', s
->s_buf
[2]);
1470 SBUF_ASSERT_EQ('2', s
->s_buf
[3]);
1471 SBUF_ASSERT_EQ('3', s
->s_buf
[4]);
1472 SBUF_ASSERT_EQ(' ', s
->s_buf
[5]);
1473 SBUF_ASSERT_EQ('f', s
->s_buf
[6]);
1474 SBUF_ASSERT_EQ('o', s
->s_buf
[7]);
1475 SBUF_ASSERT_EQ('o', s
->s_buf
[8]);
1480 SBUF_SHOULD("work with the fact we reserve a nul byte at the end")
1482 struct sbuf
*s
= NULL
;
1484 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1485 SBUF_ASSERT_EQ(0, sbuf_printf(s
, "0123456789abcde"));
1486 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1491 SBUF_SHOULD("mark the sbuf as overflowed if we try to write too much")
1493 struct sbuf
*s
= NULL
;
1495 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1496 SBUF_ASSERT_EQ(-1, sbuf_printf(s
, "0123456789abcdef"));
1497 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1502 SBUF_SHOULD("auto-extend as necessary")
1504 struct sbuf
*s
= NULL
;
1505 const char *data
= "0123456789abcdef";
1509 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1510 size_before
= s
->s_size
;
1511 SBUF_ASSERT_EQ(0, sbuf_printf(s
, "%s", data
));
1512 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1514 for (n
= 0; n
< strlen(data
); ++n
) {
1515 SBUF_ASSERT_EQ(data
[n
], s
->s_buf
[n
]);
1521 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1523 struct sbuf
*s
= NULL
;
1525 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1526 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1527 SBUF_ASSERT_EQ(-1, sbuf_printf(s
, "A"));
1533 SBUF_TESTING("sbuf_putc")
1535 SBUF_SHOULD("work where we have capacity")
1537 struct sbuf
*s
= NULL
;
1539 s
= sbuf_new(NULL
, NULL
, 16, 0);
1540 SBUF_ASSERT_EQ(0, sbuf_putc(s
, 'a'));
1541 SBUF_ASSERT_EQ(1, s
->s_len
);
1542 SBUF_ASSERT_EQ('a', s
->s_buf
[0]);
1547 SBUF_SHOULD("fail if we have a full, fixedlen sbuf")
1549 struct sbuf
*s
= NULL
;
1551 s
= sbuf_new(NULL
, NULL
, 16, SBUF_FIXEDLEN
);
1552 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "0123456789abcd"));
1553 SBUF_ASSERT_EQ(0, sbuf_putc(s
, 'e'));
1554 SBUF_ASSERT_EQ(-1, sbuf_putc(s
, 'f'));
1555 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1560 SBUF_SHOULD("ignore nul")
1562 struct sbuf
*s
= NULL
;
1564 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1565 SBUF_ASSERT_EQ(0, sbuf_putc(s
, '\0'));
1566 SBUF_ASSERT_EQ(0, s
->s_len
);
1571 SBUF_SHOULD("auto-extend if necessary")
1573 struct sbuf
*s
= NULL
;
1577 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1578 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "0123456789abcde"));
1579 len_before
= s
->s_len
;
1580 size_before
= s
->s_size
;
1581 SBUF_ASSERT_EQ(0, sbuf_putc(s
, 'f'));
1582 SBUF_ASSERT_EQ(len_before
+ 1, s
->s_len
);
1583 SBUF_ASSERT_GT(size_before
, s
->s_size
);
1584 SBUF_ASSERT_EQ('f', s
->s_buf
[s
->s_len
- 1]);
1589 SBUF_SHOULD("fail if the sbuf is overflowed")
1591 struct sbuf
*s
= NULL
;
1593 s
= sbuf_new(NULL
, NULL
, 16, SBUF_AUTOEXTEND
);
1594 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1595 SBUF_ASSERT_EQ(-1, sbuf_putc(s
, 'a'));
1601 SBUF_TESTING("sbuf_trim")
1603 SBUF_SHOULD("remove trailing spaces, tabs and newlines")
1605 struct sbuf
*s
= NULL
;
1606 const char *test
= "foo \t\t\n\t";
1608 s
= sbuf_new(NULL
, NULL
, 16, 0);
1609 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, test
));
1610 SBUF_ASSERT_EQ(strlen(test
), s
->s_len
);
1611 SBUF_ASSERT_EQ(0, sbuf_trim(s
));
1612 SBUF_ASSERT_EQ(3, s
->s_len
);
1617 SBUF_SHOULD("do nothing if there is no trailing whitespace")
1619 struct sbuf
*s
= NULL
;
1620 const char *test
= "foo";
1622 s
= sbuf_new(NULL
, NULL
, 16, 0);
1623 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, test
));
1624 SBUF_ASSERT_EQ(strlen(test
), s
->s_len
);
1625 SBUF_ASSERT_EQ(0, sbuf_trim(s
));
1626 SBUF_ASSERT_EQ(strlen(test
), s
->s_len
);
1631 SBUF_SHOULD("fail if the sbuf is overflowed")
1633 struct sbuf
*s
= NULL
;
1634 const char *test
= "foo ";
1636 s
= sbuf_new(NULL
, NULL
, 16, 0);
1637 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, test
));
1638 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1639 SBUF_ASSERT_EQ(-1, sbuf_trim(s
));
1640 SBUF_ASSERT_EQ(strlen(test
), s
->s_len
);
1645 SBUF_SHOULD("work on empty strings")
1647 struct sbuf
*s
= NULL
;
1649 s
= sbuf_new(NULL
, NULL
, 16, 0);
1650 SBUF_ASSERT_EQ(0, sbuf_trim(s
));
1651 SBUF_ASSERT_EQ(0, s
->s_len
);
1657 SBUF_TESTING("sbuf_overflowed")
1659 SBUF_SHOULD("return false if it hasn't overflowed")
1661 struct sbuf
*s
= NULL
;
1663 s
= sbuf_new(NULL
, NULL
, 16, 0);
1664 SBUF_ASSERT_NOT(sbuf_overflowed(s
));
1669 SBUF_SHOULD("return true if it has overflowed")
1671 struct sbuf
*s
= NULL
;
1673 s
= sbuf_new(NULL
, NULL
, 16, 0);
1674 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1675 SBUF_ASSERT(sbuf_overflowed(s
));
1681 SBUF_TESTING("sbuf_finish")
1683 SBUF_SHOULD("insert a nul byte, clear the overflowed flag and set the finished flag")
1685 struct sbuf
*s
= NULL
;
1687 s
= sbuf_new(NULL
, NULL
, 16, 0);
1688 SBUF_ASSERT_EQ(0, sbuf_putc(s
, 'A'));
1689 s
->s_buf
[s
->s_len
] = 'x';
1690 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1691 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_FINISHED
));
1695 SBUF_ASSERT_EQ(0, s
->s_buf
[s
->s_len
]);
1696 SBUF_ASSERT_NOT(SBUF_ISSET(s
, SBUF_OVERFLOWED
));
1697 SBUF_ASSERT(SBUF_ISSET(s
, SBUF_FINISHED
));
1703 SBUF_TESTING("sbuf_data")
1705 SBUF_SHOULD("return the s_buf pointer")
1707 struct sbuf
*s
= NULL
;
1709 s
= sbuf_new(NULL
, NULL
, 16, 0);
1710 SBUF_ASSERT_EQ(s
->s_buf
, sbuf_data(s
));
1715 SBUF_SHOULD("return the buffer we gave it")
1717 struct sbuf
*s
= NULL
;
1718 char buf
[4] = { 0 };
1720 s
= sbuf_new(NULL
, buf
, sizeof(buf
), 0);
1721 SBUF_ASSERT_EQ(buf
, sbuf_data(s
));
1727 SBUF_TESTING("sbuf_len")
1729 SBUF_SHOULD("return the length of the sbuf data")
1731 struct sbuf
*s
= NULL
;
1733 s
= sbuf_new(NULL
, NULL
, 16, 0);
1734 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "hello"));
1735 SBUF_ASSERT_EQ(5, sbuf_len(s
));
1740 SBUF_SHOULD("return -1 if the sbuf is overflowed")
1742 struct sbuf
*s
= NULL
;
1744 s
= sbuf_new(NULL
, NULL
, 16, 0);
1745 SBUF_ASSERT_EQ(0, sbuf_cpy(s
, "hello"));
1746 SBUF_ASSERT_EQ(5, sbuf_len(s
));
1747 SBUF_SETFLAG(s
, SBUF_OVERFLOWED
);
1748 SBUF_ASSERT_EQ(-1, sbuf_len(s
));
1754 SBUF_TESTING("sbuf_done")
1756 SBUF_SHOULD("return false if the sbuf isn't finished")
1758 struct sbuf
*s
= NULL
;
1760 s
= sbuf_new(NULL
, NULL
, 16, 0);
1761 SBUF_ASSERT_NOT(sbuf_done(s
));
1766 SBUF_SHOULD("return true if the sbuf has finished")
1768 struct sbuf
*s
= NULL
;
1770 s
= sbuf_new(NULL
, NULL
, 16, 0);
1771 SBUF_ASSERT_NOT(sbuf_done(s
));
1772 SBUF_SETFLAG(s
, SBUF_FINISHED
);
1773 SBUF_ASSERT(sbuf_done(s
));
1779 SBUF_TESTING("sbuf_delete")
1781 SBUF_SHOULD("just free the backing buffer if we supplied an sbuf")
1783 struct sbuf
*s
= NULL
;
1784 struct sbuf existing
= {};
1786 s
= sbuf_new(&existing
, NULL
, 16, 0);
1787 SBUF_ASSERT_NE(NULL
, s
->s_buf
);
1790 SBUF_ASSERT_EQ(NULL
, s
->s_buf
);
1797 SYSCTL_PROC(_kern
, OID_AUTO
, sbuf_test
, CTLTYPE_STRING
| CTLFLAG_RW
| CTLFLAG_KERN
| CTLFLAG_MASKED
, 0, 0, sysctl_sbuf_tests
, "A", "sbuf tests");
1799 #endif /* DEBUG || DEVELOPMENT */