]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/subr_sbuf.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / subr_sbuf.c
CommitLineData
f427ee49
A
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@
2d21ac55 27 */
f427ee49
A
28#include <kern/kalloc.h>
29#include <libkern/libkern.h>
30#include <os/base.h>
31#include <os/overflow.h>
2d21ac55 32#include <sys/param.h>
2d21ac55 33#include <sys/sbuf.h>
f427ee49 34#include <sys/uio.h>
2d21ac55 35
f427ee49
A
36#if DEBUG || DEVELOPMENT
37#include <kern/macro_help.h>
38#include <sys/errno.h>
39#include <sys/sysctl.h>
40#endif /* DEBUG || DEVELOPMENT */
2d21ac55 41
f427ee49 42#define SBUF_ISSET(s, f) ((s)->s_flags & (f))
0a7de745
A
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)
2d21ac55 45
f427ee49
A
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
0a7de745
A
53#define SBUF_MAXEXTENDSIZE PAGE_SIZE
54#define SBUF_MAXEXTENDINCR PAGE_SIZE
2d21ac55 55
f427ee49
A
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.
2d21ac55 66 */
f427ee49
A
67void
68sbuf_delete(struct sbuf *s)
2d21ac55 69{
f427ee49
A
70 if (SBUF_ISDYNAMIC(s) && s->s_buf) {
71 kheap_free(KHEAP_DATA_BUFFERS, s->s_buf, s->s_size);
72 s->s_buf = NULL;
2d21ac55
A
73 }
74
f427ee49
A
75 if (SBUF_ISDYNSTRUCT(s)) {
76 kheap_free(KHEAP_DEFAULT, s, sizeof(*s));
77 }
2d21ac55
A
78}
79
f427ee49
A
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.
2d21ac55
A
93 */
94static int
f427ee49 95sbuf_extendsize(size_t *size)
2d21ac55 96{
f427ee49
A
97 size_t target_size = *size;
98 size_t new_size;
2d21ac55 99
f427ee49 100 if (target_size > INT_MAX) {
0a7de745
A
101 return -1;
102 }
2d21ac55 103
f427ee49
A
104 if (target_size < SBUF_MAXEXTENDSIZE) {
105 new_size = SBUF_MINEXTENDSIZE;
106 while (new_size < target_size) {
107 new_size *= 2;
108 }
0a7de745 109 } else {
f427ee49
A
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;
0a7de745 116 }
f427ee49
A
117
118 *size = new_size;
0a7de745 119 return 0;
2d21ac55
A
120}
121
f427ee49
A
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.
2d21ac55
A
150 */
151struct sbuf *
f427ee49 152sbuf_new(struct sbuf *s, char *buf, int length_, int flags)
2d21ac55 153{
f427ee49
A
154 size_t length = (size_t)length_;
155
156 if (length > INT_MAX || flags & ~SBUF_USRFLAGMSK) {
157 return NULL;
158 }
2d21ac55 159
2d21ac55 160 if (s == NULL) {
f427ee49
A
161 s = (struct sbuf *)kheap_alloc(KHEAP_DEFAULT, sizeof(*s), Z_WAITOK);
162 if (NULL == s) {
0a7de745
A
163 return NULL;
164 }
f427ee49
A
165
166 bzero(s, sizeof(*s));
2d21ac55
A
167 s->s_flags = flags;
168 SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
169 } else {
f427ee49 170 bzero(s, sizeof(*s));
2d21ac55
A
171 s->s_flags = flags;
172 }
f427ee49 173
2d21ac55 174 if (buf) {
f427ee49 175 s->s_size = (int)length;
2d21ac55 176 s->s_buf = buf;
0a7de745 177 return s;
2d21ac55 178 }
f427ee49
A
179
180 if (SBUF_CANEXTEND(s) && (-1 == sbuf_extendsize(&length))) {
181 goto fail;
0a7de745 182 }
f427ee49
A
183
184 /*
185 * we always need at least 1 byte for \0, so s_size of 0 will cause an
186 * underflow in sbuf_capacity.
187 */
188 if (length == 0) {
189 goto fail;
2d21ac55 190 }
f427ee49
A
191
192 s->s_buf = (char *)kheap_alloc(KHEAP_DATA_BUFFERS, length, Z_WAITOK);
193 if (NULL == s->s_buf) {
194 goto fail;
195 }
196 bzero(s->s_buf, length);
197 s->s_size = (int)length;
198
2d21ac55 199 SBUF_SETFLAG(s, SBUF_DYNAMIC);
0a7de745 200 return s;
f427ee49
A
201
202fail:
203 sbuf_delete(s);
204 return NULL;
2d21ac55
A
205}
206
f427ee49
A
207/*!
208 * @function sbuf_setpos
209 *
210 * @brief
211 * Set the current position of the sbuf.
212 *
213 * @param s
214 * The sbuf to modify.
215 *
216 * @param pos
217 * The new position to set. Must be less than or equal to the current position.
218 *
219 * @returns
220 * 0 on success, -1 on failure.
2d21ac55 221 */
f427ee49
A
222int
223sbuf_setpos(struct sbuf *s, int pos)
2d21ac55 224{
f427ee49
A
225 if (pos < 0 || pos > s->s_len) {
226 return -1;
2d21ac55 227 }
f427ee49
A
228
229 s->s_len = pos;
230 return 0;
2d21ac55 231}
2d21ac55 232
f427ee49
A
233/*!
234 * @function sbuf_clear
235 *
236 * @brief
237 * Resets the position/length of the sbuf data to zero and clears the finished
238 * and overflow flags.
239 *
240 * @param s
241 * The sbuf to clear.
2d21ac55
A
242 */
243void
244sbuf_clear(struct sbuf *s)
245{
2d21ac55
A
246 SBUF_CLEARFLAG(s, SBUF_FINISHED);
247 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
f427ee49 248 sbuf_setpos(s, 0);
2d21ac55
A
249}
250
f427ee49
A
251/*!
252 * @function sbuf_extend
253 *
254 * @brief
255 * Attempt to extend the size of an sbuf's backing buffer by @a addlen bytes.
256 *
257 * @param s
258 * The sbuf to extend.
259 *
260 * @param addlen
261 * How many bytes to increase the size by.
262 *
263 * @returns
264 * 0 on success, -1 on failure.
2d21ac55 265 */
f427ee49
A
266static int OS_WARN_RESULT
267sbuf_extend(struct sbuf *s, size_t addlen)
2d21ac55 268{
f427ee49
A
269 char *new_buf;
270 size_t new_size;
2d21ac55 271
f427ee49
A
272 if (addlen == 0) {
273 return 0;
274 }
2d21ac55 275
f427ee49 276 if (!SBUF_CANEXTEND(s)) {
0a7de745
A
277 return -1;
278 }
2d21ac55 279
f427ee49 280 if (os_add_overflow((size_t)s->s_size, addlen, &new_size)) {
0a7de745
A
281 return -1;
282 }
2d21ac55 283
f427ee49 284 if (-1 == sbuf_extendsize(&new_size)) {
0a7de745 285 return -1;
2d21ac55 286 }
2d21ac55 287
f427ee49
A
288 new_buf = (char *)kheap_alloc(KHEAP_DATA_BUFFERS, new_size, Z_WAITOK);
289 if (NULL == new_buf) {
0a7de745
A
290 return -1;
291 }
2d21ac55 292
f427ee49
A
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);
296 } else {
297 SBUF_SETFLAG(s, SBUF_DYNAMIC);
0a7de745 298 }
2d21ac55 299
f427ee49
A
300 s->s_buf = new_buf;
301 s->s_size = (int)new_size;
0a7de745 302 return 0;
2d21ac55 303}
2d21ac55 304
f427ee49
A
305/*!
306 * @function sbuf_capacity
307 *
308 * @brief
309 * Get the current capacity of an sbuf: how many more bytes we can append given
310 * the current size and position.
311 *
312 * @param s
313 * The sbuf to get the capacity of.
314 *
315 * @returns
316 * The current sbuf capacity.
2d21ac55 317 */
f427ee49
A
318static size_t
319sbuf_capacity(const struct sbuf *s)
2d21ac55 320{
f427ee49
A
321 /* 1 byte reserved for \0: */
322 return (size_t)(s->s_size - s->s_len - 1);
323}
2d21ac55 324
f427ee49
A
325/*!
326 * @function sbuf_ensure_capacity
327 *
328 * @brief
329 * Ensure that an sbuf can accommodate @a add_len bytes, reallocating the
330 * backing buffer if necessary.
331 *
332 * @param s
333 * The sbuf.
334 *
335 * @param wanted
336 * The minimum capacity to ensure @a s has.
337 *
338 * @returns
339 * 0 if the minimum capacity is met by @a s, or -1 on error.
340 */
341static int
342sbuf_ensure_capacity(struct sbuf *s, size_t wanted)
343{
344 size_t size;
345
346 size = sbuf_capacity(s);
347 if (size >= wanted) {
348 return 0;
349 }
350
351 return sbuf_extend(s, wanted - size);
2d21ac55
A
352}
353
f427ee49
A
354/*!
355 * @function sbuf_bcat
356 *
357 * @brief
358 * Append data to an sbuf.
359 *
360 * @param s
361 * The sbuf.
362 *
363 * @param data
364 * The data to append.
365 *
366 * @param len
367 * The length of the data.
368 *
369 * @returns
370 * 0 on success, -1 on failure. Will always fail if the sbuf is marked as
371 * overflowed.
2d21ac55
A
372 */
373int
f427ee49 374sbuf_bcat(struct sbuf *s, const void *data, size_t len)
2d21ac55 375{
0a7de745
A
376 if (SBUF_HASOVERFLOWED(s)) {
377 return -1;
378 }
2d21ac55 379
f427ee49 380 if (-1 == sbuf_ensure_capacity(s, len)) {
2d21ac55 381 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
0a7de745 382 return -1;
2d21ac55 383 }
f427ee49
A
384
385 bcopy(data, s->s_buf + s->s_len, len);
386 s->s_len += (int)len; /* safe */
387
0a7de745 388 return 0;
2d21ac55
A
389}
390
f427ee49
A
391/*!
392 * @function sbuf_bcpy
393 *
394 * @brief
395 * Set the entire sbuf data, possibly reallocating the backing buffer to
396 * accommodate.
397 *
398 * @param s
399 * The sbuf.
400 *
401 * @param data
402 * The data to set.
403 *
404 * @param len
405 * The length of the data to set.
406 *
407 * @returns
408 * 0 on success or -1 on failure. Will clear the finished/overflowed flags.
2d21ac55
A
409 */
410int
f427ee49 411sbuf_bcpy(struct sbuf *s, const void *data, size_t len)
2d21ac55 412{
f427ee49
A
413 sbuf_clear(s);
414 return sbuf_bcat(s, data, len);
415}
2d21ac55 416
f427ee49
A
417/*!
418 * @function sbuf_cat
419 *
420 * @brief
421 * Append a string to an sbuf, possibly expanding the backing buffer to
422 * accommodate.
423 *
424 * @param s
425 * The sbuf.
426 *
427 * @param str
428 * The string to append.
429 *
430 * @returns
431 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
432 * overflowed.
433 */
434int
435sbuf_cat(struct sbuf *s, const char *str)
436{
437 return sbuf_bcat(s, str, strlen(str));
2d21ac55 438}
2d21ac55 439
f427ee49
A
440/*!
441 * @function sbuf_cpy
442 *
443 * @brief
444 * Set the entire sbuf data to the given nul-terminated string, possibly
445 * expanding the backing buffer to accommodate it if necessary.
446 *
447 * @param s
448 * The sbuf.
449 *
450 * @param str
451 * The string to set the sbuf data to.
452 *
453 * @returns
454 * 0 on success, -1 on failure. Clears and resets the sbuf first.
2d21ac55
A
455 */
456int
457sbuf_cpy(struct sbuf *s, const char *str)
458{
2d21ac55 459 sbuf_clear(s);
0a7de745 460 return sbuf_cat(s, str);
2d21ac55
A
461}
462
f427ee49
A
463/*!
464 * @function sbuf_vprintf
465 *
466 * @brief
467 * Formatted-print into an sbuf using a va_list.
468 *
469 * @param s
470 * The sbuf.
471 *
472 * @param fmt
473 * The format string.
474 *
475 * @param ap
476 * The format string argument data.
477 *
478 * @returns
479 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
480 * overflowed.
2d21ac55
A
481 */
482int
483sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
484{
f427ee49
A
485 va_list ap_copy;
486 int result;
487 size_t capacity;
488 size_t len;
2d21ac55 489
0a7de745
A
490 if (SBUF_HASOVERFLOWED(s)) {
491 return -1;
492 }
2d21ac55
A
493
494 do {
f427ee49
A
495 capacity = sbuf_capacity(s);
496
2d21ac55 497 va_copy(ap_copy, ap);
f427ee49
A
498 /* +1 for \0. safe because we already accommodate this. */
499 result = vsnprintf(&s->s_buf[s->s_len], capacity + 1, fmt, ap_copy);
2d21ac55 500 va_end(ap_copy);
2d21ac55 501
f427ee49
A
502 if (result < 0) {
503 return -1;
504 }
2d21ac55 505
f427ee49
A
506 len = (size_t)result;
507 if (len <= capacity) {
508 s->s_len += (int)len;
509 return 0;
510 }
511 } while (-1 != sbuf_ensure_capacity(s, len));
2d21ac55 512
f427ee49
A
513 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
514 return -1;
2d21ac55
A
515}
516
f427ee49
A
517/*!
518 * @function sbuf_printf
519 *
520 * @brief
521 * Formatted-print into an sbuf using variadic arguments.
522 *
523 * @param s
524 * The sbuf.
525 *
526 * @param fmt
527 * The format string.
528 *
529 * @returns
530 * 0 on success, -1 on failure. Always fails if the sbuf is marked as
531 * overflowed.
2d21ac55
A
532 */
533int
534sbuf_printf(struct sbuf *s, const char *fmt, ...)
535{
536 va_list ap;
537 int result;
538
539 va_start(ap, fmt);
540 result = sbuf_vprintf(s, fmt, ap);
541 va_end(ap);
0a7de745 542 return result;
2d21ac55
A
543}
544
f427ee49
A
545/*!
546 * @function sbuf_putc
547 *
548 * @brief
549 * Append a single character to an sbuf. Ignores '\0'.
550 *
551 * @param s
552 * The sbuf.
553 *
554 * @param c_
555 * The character to append.
556 *
557 * @returns
558 * 0 on success, -1 on failure. This function will always fail if the sbuf is
559 * marked as overflowed.
2d21ac55
A
560 */
561int
f427ee49 562sbuf_putc(struct sbuf *s, int c_)
2d21ac55 563{
f427ee49 564 char c = (char)c_;
2d21ac55 565
0a7de745
A
566 if (SBUF_HASOVERFLOWED(s)) {
567 return -1;
568 }
2d21ac55 569
f427ee49 570 if (-1 == sbuf_ensure_capacity(s, 1)) {
2d21ac55 571 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
0a7de745
A
572 return -1;
573 }
f427ee49 574
0a7de745
A
575 if (c != '\0') {
576 s->s_buf[s->s_len++] = c;
2d21ac55 577 }
f427ee49 578
0a7de745 579 return 0;
2d21ac55
A
580}
581
582static inline int
583isspace(char ch)
584{
0a7de745 585 return ch == ' ' || ch == '\n' || ch == '\t';
2d21ac55
A
586}
587
f427ee49
A
588/*!
589 * @function sbuf_trim
590 *
591 * @brief
592 * Removes whitespace from the end of an sbuf.
593 *
594 * @param s
595 * The sbuf.
596 *
597 * @returns
598 * 0 on success or -1 if the sbuf is marked as overflowed.
2d21ac55
A
599 */
600int
601sbuf_trim(struct sbuf *s)
602{
0a7de745
A
603 if (SBUF_HASOVERFLOWED(s)) {
604 return -1;
605 }
2d21ac55 606
f427ee49 607 while (s->s_len > 0 && isspace(s->s_buf[s->s_len - 1])) {
2d21ac55 608 --s->s_len;
0a7de745 609 }
2d21ac55 610
0a7de745 611 return 0;
2d21ac55
A
612}
613
f427ee49
A
614/*!
615 * @function sbuf_overflowed
616 *
617 * @brief
618 * Indicates whether the sbuf is marked as overflowed.
619 *
620 * @param s
621 * The sbuf.
622 *
623 * @returns
624 * 1 if the sbuf has overflowed or 0 otherwise.
2d21ac55
A
625 */
626int
627sbuf_overflowed(struct sbuf *s)
628{
f427ee49 629 return !!SBUF_HASOVERFLOWED(s);
2d21ac55
A
630}
631
f427ee49
A
632/*!
633 * @function sbuf_finish
634 *
635 * @brief
636 * Puts a trailing nul byte onto the sbuf data.
637 *
638 * @param s
639 * The sbuf.
2d21ac55
A
640 */
641void
642sbuf_finish(struct sbuf *s)
643{
f427ee49 644 /* safe because we always reserve a byte at the end for \0: */
2d21ac55
A
645 s->s_buf[s->s_len] = '\0';
646 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
647 SBUF_SETFLAG(s, SBUF_FINISHED);
648}
649
f427ee49
A
650/*!
651 * @function sbuf_data
652 *
653 * @brief
654 * Gets a pointer to the sbuf backing data.
655 *
656 * @param s
657 * The sbuf.
658 *
659 * @returns
660 * A pointer to the sbuf data.
2d21ac55
A
661 */
662char *
663sbuf_data(struct sbuf *s)
664{
2d21ac55
A
665 return s->s_buf;
666}
667
f427ee49
A
668/*!
669 * @function sbuf_len
670 *
671 * @brief
672 * Retrieves the current length of the sbuf data.
673 *
674 * @param s
675 * The sbuf
676 *
677 * @returns
678 * The length of the sbuf data or -1 if the sbuf is marked as overflowed.
2d21ac55
A
679 */
680int
681sbuf_len(struct sbuf *s)
682{
0a7de745
A
683 if (SBUF_HASOVERFLOWED(s)) {
684 return -1;
685 }
f427ee49 686
2d21ac55
A
687 return s->s_len;
688}
689
f427ee49
A
690/*!
691 * @function sbuf_done
692 *
693 * @brief
694 * Tests if the sbuf is marked as finished.
695 *
696 * @param s
697 * The sbuf.
698 *
699 * @returns
700 * 1 if the sbuf is marked as finished or 0 if not.
2d21ac55 701 */
f427ee49
A
702int
703sbuf_done(struct sbuf *s)
2d21ac55 704{
f427ee49
A
705 return !!SBUF_ISFINISHED(s);
706}
2d21ac55 707
f427ee49
A
708#if DEBUG || DEVELOPMENT
709
710/*
711 * a = assertion string
712 */
713#define SBUF_FAIL(a) \
714 MACRO_BEGIN \
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); \
718 } \
719 goto fail; \
720 MACRO_END
721
722#define SBUF_PASS \
723 ++passed
724
725/*
726 * x = expression
727 */
728#define SBUF_ASSERT(x) \
729 MACRO_BEGIN \
730 if (x) { \
731 SBUF_PASS; \
732 } else { \
733 SBUF_FAIL(#x); \
734 } \
735 MACRO_END
736
737#define SBUF_ASSERT_NOT(x) \
738 SBUF_ASSERT(!(x))
739
740/*
741 * e = expected
742 * a = actual
743 * c = comparator
744 */
745#define SBUF_ASSERT_CMP(e, a, c) \
746 MACRO_BEGIN \
747 if ((a) c (e)) { \
748 SBUF_PASS; \
749 } else { \
750 SBUF_FAIL(#a " " #c " " #e); \
751 } \
752 MACRO_END
753
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, <=)
760
761#define SBUF_TEST_BEGIN \
762 size_t passed = 0; \
763 const char *what = NULL; \
764 const char *should = NULL;
765
766/*
767 * include the trailing semi-colons here intentionally to allow for block-like
768 * appearance:
769 */
770#define SBUF_TESTING(f) \
771 MACRO_BEGIN \
772 what = (f); \
773 MACRO_END;
774
775#define SBUF_SHOULD(s) \
776 MACRO_BEGIN \
777 should = (s); \
778 MACRO_END;
779
780#define SBUF_TEST_END \
781 printf("sbuf_tests: %zu assertions passed\n", passed); \
782 return 0; \
783fail: \
784 return ENOTRECOVERABLE;
785
786static int
787sysctl_sbuf_tests SYSCTL_HANDLER_ARGS
788{
789#pragma unused(arg1, arg2)
790 int rval = 0;
791 char str[32] = { 'o', 'k', 0 };
792
793 rval = sysctl_handle_string(oidp, str, sizeof(str), req);
794 if (rval != 0 || req->newptr == 0 || req->newlen < 1) {
795 return rval;
796 }
797
798 SBUF_TEST_BEGIN;
799
800 SBUF_TESTING("sbuf_new")
801 {
802 SBUF_SHOULD("fail to allocate >INT_MAX")
803 {
804 struct sbuf *s = NULL;
805
806 s = sbuf_new(NULL, NULL, INT_MAX + 1, 0);
807 SBUF_ASSERT_EQ(NULL, s);
808 }
809
810 SBUF_SHOULD("fail when claiming a backing buffer >INT_MAX")
811 {
812 struct sbuf *s = NULL;
813 char buf[4] = { 0 };
814
815 s = sbuf_new(NULL, buf, INT_MAX + 1, 0);
816 SBUF_ASSERT_EQ(NULL, s);
817 }
818
819 SBUF_SHOULD("fail to allocate a zero-length sbuf")
820 {
821 struct sbuf *s = NULL;
822
823 s = sbuf_new(NULL, NULL, 0, 0);
824 SBUF_ASSERT_EQ(NULL, s);
825 }
826
827 SBUF_SHOULD("not accept invalid flags")
828 {
829 struct sbuf *s = NULL;
830
831 s = sbuf_new(NULL, NULL, 16, 0x10000);
832 SBUF_ASSERT_EQ(NULL, s);
833 }
834
835 SBUF_SHOULD("succeed when passed an existing sbuf")
836 {
837 struct sbuf *s = NULL;
838 struct sbuf existing;
839
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);
848
849 sbuf_delete(s);
850 }
851
852 SBUF_SHOULD("succeed when passed an existing sbuf and buffer")
853 {
854 struct sbuf *s = NULL;
855 struct sbuf existing;
856 char buf[4] = { 0 };
857
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);
864
865 sbuf_delete(s);
866 }
867
868 SBUF_SHOULD("succeed without an existing sbuf or buffer")
869 {
870 struct sbuf *s = NULL;
871
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);
879
880 sbuf_delete(s);
881 }
882
883 SBUF_SHOULD("succeed without an existing sbuf, but with a buffer")
884 {
885 struct sbuf *s = NULL;
886 char buf[4] = { 0 };
887
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);
894
895 sbuf_delete(s);
896 }
897
898 SBUF_SHOULD("round up the requested size if SBUF_AUTOEXTEND")
899 {
900 struct sbuf *s = NULL;
901
902 s = sbuf_new(NULL, NULL, 1, SBUF_AUTOEXTEND);
903 SBUF_ASSERT_GT(1, s->s_size);
904
905 sbuf_delete(s);
906 }
907 }
908
909 SBUF_TESTING("sbuf_clear")
910 {
911 SBUF_SHOULD("clear the overflowed and finished flags")
912 {
913 struct sbuf *s = NULL;
914
915 s = sbuf_new(NULL, NULL, 16, 0);
916
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));
921 sbuf_clear(s);
922 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED));
923 SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_FINISHED));
924
925 sbuf_delete(s);
926 }
927
928 SBUF_SHOULD("reset the position to zero")
929 {
930 struct sbuf *s = NULL;
931
932 s = sbuf_new(NULL, NULL, 16, 0);
933
934 s->s_len = 1;
935 sbuf_clear(s);
936 SBUF_ASSERT_EQ(0, s->s_len);
937
938 sbuf_delete(s);
939 }
940 }
941
942 SBUF_TESTING("sbuf_extend")
943 {
944 SBUF_SHOULD("allow zero")
945 {
946 struct sbuf *s = NULL;
947 int size_before;
948
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);
953
954 sbuf_delete(s);
955 }
956
957 SBUF_SHOULD("fail for sbuf not marked as SBUF_AUTOEXTEND")
958 {
959 struct sbuf *s = NULL;
960
961 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
962 SBUF_ASSERT_EQ(-1, sbuf_extend(s, 10));
963
964 sbuf_delete(s);
965 }
966
967 SBUF_SHOULD("accommodate reasonable requests")
968 {
969 struct sbuf *s = NULL;
970 int size_before;
971
972 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
973 size_before = s->s_size;
974
975 SBUF_ASSERT_EQ(0, sbuf_extend(s, 10));
976 SBUF_ASSERT_GTE(10, s->s_size - size_before);
977
978 sbuf_delete(s);
979 }
980
981 SBUF_SHOULD("reject requests that cause overflows")
982 {
983 struct sbuf *s = NULL;
984
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));
988
989 sbuf_delete(s);
990 }
991
992 SBUF_SHOULD("transform the sbuf into an SBUF_DYNAMIC one")
993 {
994 struct sbuf *s = NULL;
995 char buf[4] = { 0 };
996
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));
1001
1002 sbuf_delete(s);
1003 }
1004 }
1005
1006 SBUF_TESTING("sbuf_capacity")
1007 {
1008 SBUF_SHOULD("account for the trailing nul byte")
1009 {
1010 struct sbuf *s = NULL;
1011
1012 s = sbuf_new(NULL, NULL, 16, 0);
1013 SBUF_ASSERT_EQ(s->s_size - s->s_len - 1, sbuf_capacity(s));
1014
1015 sbuf_delete(s);
1016 }
1017 }
1018
1019 SBUF_TESTING("sbuf_ensure_capacity")
1020 {
1021 SBUF_SHOULD("return 0 if the sbuf already has enough capacity")
1022 {
1023 struct sbuf *s = NULL;
1024 int size_before;
1025
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);
1030
1031 sbuf_delete(s);
1032 }
1033
1034 SBUF_SHOULD("extend the buffer as needed")
1035 {
1036 struct sbuf *s = NULL;
1037 int size_before;
1038
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);
1043
1044 sbuf_delete(s);
1045 }
1046 }
1047
1048 SBUF_TESTING("sbuf_bcat")
1049 {
1050 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1051 {
1052 struct sbuf *s = NULL;
1053
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));
1057
1058 sbuf_delete(s);
1059 }
1060
1061 SBUF_SHOULD("fail if len is too big")
1062 {
1063 struct sbuf *s = NULL;
1064
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));
1068
1069 sbuf_delete(s);
1070 }
1071
1072 SBUF_SHOULD("succeed for a fixed buf within limits")
1073 {
1074 struct sbuf *s = NULL;
1075
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]);
1082
1083 sbuf_delete(s);
1084 }
1085
1086 SBUF_SHOULD("succeed for binary data, even with nul bytes")
1087 {
1088 struct sbuf *s = NULL;
1089
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]);
1096
1097 sbuf_delete(s);
1098 }
1099
1100 SBUF_SHOULD("append to existing data")
1101 {
1102 struct sbuf *s = NULL;
1103
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]);
1110
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]);
1116
1117 sbuf_delete(s);
1118 }
1119
1120 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1121 {
1122 struct sbuf *s = NULL;
1123
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);
1127
1128 sbuf_delete(s);
1129 }
1130
1131 SBUF_SHOULD("fail for a fixed buf if too big")
1132 {
1133 struct sbuf *s = NULL;
1134
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));
1138
1139 sbuf_delete(s);
1140 }
1141
1142 SBUF_SHOULD("expand the backing buffer as needed")
1143 {
1144 struct sbuf *s = NULL;
1145 int size_before;
1146
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);
1152
1153 sbuf_delete(s);
1154 }
1155 }
1156
1157 SBUF_TESTING("sbuf_bcpy")
1158 {
1159 SBUF_SHOULD("overwrite any existing data")
1160 {
1161 struct sbuf *s = NULL;
1162
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]);
1169
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]);
1178
1179 sbuf_delete(s);
1180 }
1181
1182 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1183 {
1184 struct sbuf *s = NULL;
1185
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));
1189
1190 sbuf_delete(s);
1191 }
1192
1193 SBUF_SHOULD("fail if len is too big")
1194 {
1195 struct sbuf *s = NULL;
1196
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));
1200
1201 sbuf_delete(s);
1202 }
1203
1204 SBUF_SHOULD("succeed for a fixed buf within limits")
1205 {
1206 struct sbuf *s = NULL;
1207
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]);
1214
1215 sbuf_delete(s);
1216 }
1217
1218 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1219 {
1220 struct sbuf *s = NULL;
1221
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);
1225
1226 sbuf_delete(s);
1227 }
1228
1229 SBUF_SHOULD("fail for a fixed buf if too big")
1230 {
1231 struct sbuf *s = NULL;
1232
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));
1236
1237 sbuf_delete(s);
1238 }
1239
1240 SBUF_SHOULD("expand the backing buffer as needed")
1241 {
1242 struct sbuf *s = NULL;
1243 int size_before;
1244
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);
1250
1251 sbuf_delete(s);
1252 }
1253 }
1254
1255 SBUF_TESTING("sbuf_cat")
1256 {
1257 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1258 {
1259 struct sbuf *s = NULL;
1260
1261 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1262 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1263 SBUF_ASSERT_EQ(-1, sbuf_cat(s, "A"));
1264
1265 sbuf_delete(s);
1266 }
1267
1268 SBUF_SHOULD("succeed for a fixed buf within limits")
1269 {
1270 struct sbuf *s = NULL;
1271
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]);
1278
1279 sbuf_delete(s);
1280 }
1281
1282 SBUF_SHOULD("only copy up to a nul byte")
1283 {
1284 struct sbuf *s = NULL;
1285
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]);
1290
1291 sbuf_delete(s);
1292 }
1293
1294 SBUF_SHOULD("append to existing data")
1295 {
1296 struct sbuf *s = NULL;
1297
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]);
1304
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]);
1310
1311 sbuf_delete(s);
1312 }
1313
1314 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1315 {
1316 struct sbuf *s = NULL;
1317
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);
1321
1322 sbuf_delete(s);
1323 }
1324
1325 SBUF_SHOULD("fail for a fixed buf if too big")
1326 {
1327 struct sbuf *s = NULL;
1328
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));
1332
1333 sbuf_delete(s);
1334 }
1335
1336 SBUF_SHOULD("expand the backing buffer as needed")
1337 {
1338 struct sbuf *s = NULL;
1339 int size_before;
1340
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);
1346
1347 sbuf_delete(s);
1348 }
1349 }
1350
1351 SBUF_TESTING("sbuf_cpy")
1352 {
1353 SBUF_SHOULD("overwrite any existing data")
1354 {
1355 struct sbuf *s = NULL;
1356
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]);
1363
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]);
1372
1373 sbuf_delete(s);
1374 }
1375
1376 SBUF_SHOULD("succeed if the sbuf is marked as overflowed, but there is space")
1377 {
1378 struct sbuf *s = NULL;
1379
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));
1383
1384 sbuf_delete(s);
1385 }
1386
1387 SBUF_SHOULD("succeed for a fixed buf within limits")
1388 {
1389 struct sbuf *s = NULL;
1390
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]);
1397
1398 sbuf_delete(s);
1399 }
1400
1401 SBUF_SHOULD("succeed for a fixed buf right up to the limit")
1402 {
1403 struct sbuf *s = NULL;
1404
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);
1408
1409 sbuf_delete(s);
1410 }
1411
1412 SBUF_SHOULD("fail for a fixed buf if too big")
1413 {
1414 struct sbuf *s = NULL;
1415
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));
1419
1420 sbuf_delete(s);
1421 }
1422
1423 SBUF_SHOULD("expand the backing buffer as needed")
1424 {
1425 struct sbuf *s = NULL;
1426 int size_before;
1427
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);
1433
1434 sbuf_delete(s);
1435 }
1436 }
1437
1438 /* also tests sbuf_vprintf: */
1439 SBUF_TESTING("sbuf_printf")
1440 {
1441 SBUF_SHOULD("support simple printing")
1442 {
1443 struct sbuf *s = NULL;
1444
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]);
1453
1454 sbuf_delete(s);
1455 }
1456
1457 SBUF_SHOULD("support format strings")
1458 {
1459 struct sbuf *s = NULL;
1460 char data1 = 'A';
1461 int data2 = 123;
1462 const char *data3 = "foo";
1463
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]);
1476
1477 sbuf_delete(s);
1478 }
1479
1480 SBUF_SHOULD("work with the fact we reserve a nul byte at the end")
1481 {
1482 struct sbuf *s = NULL;
1483
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));
1487
1488 sbuf_delete(s);
1489 }
1490
1491 SBUF_SHOULD("mark the sbuf as overflowed if we try to write too much")
1492 {
1493 struct sbuf *s = NULL;
1494
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));
1498
1499 sbuf_delete(s);
1500 }
1501
1502 SBUF_SHOULD("auto-extend as necessary")
1503 {
1504 struct sbuf *s = NULL;
1505 const char *data = "0123456789abcdef";
1506 int size_before;
1507 size_t n;
1508
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);
1513
1514 for (n = 0; n < strlen(data); ++n) {
1515 SBUF_ASSERT_EQ(data[n], s->s_buf[n]);
1516 }
1517
1518 sbuf_delete(s);
1519 }
1520
1521 SBUF_SHOULD("fail if the sbuf is marked as overflowed")
1522 {
1523 struct sbuf *s = NULL;
1524
1525 s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
1526 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1527 SBUF_ASSERT_EQ(-1, sbuf_printf(s, "A"));
1528
1529 sbuf_delete(s);
1530 }
1531 }
1532
1533 SBUF_TESTING("sbuf_putc")
1534 {
1535 SBUF_SHOULD("work where we have capacity")
1536 {
1537 struct sbuf *s = NULL;
1538
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]);
1543
1544 sbuf_delete(s);
1545 }
1546
1547 SBUF_SHOULD("fail if we have a full, fixedlen sbuf")
1548 {
1549 struct sbuf *s = NULL;
1550
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));
1556
1557 sbuf_delete(s);
1558 }
1559
1560 SBUF_SHOULD("ignore nul")
1561 {
1562 struct sbuf *s = NULL;
1563
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);
1567
1568 sbuf_delete(s);
1569 }
1570
1571 SBUF_SHOULD("auto-extend if necessary")
1572 {
1573 struct sbuf *s = NULL;
1574 int len_before;
1575 int size_before;
1576
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]);
1585
1586 sbuf_delete(s);
1587 }
1588
1589 SBUF_SHOULD("fail if the sbuf is overflowed")
1590 {
1591 struct sbuf *s = NULL;
1592
1593 s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
1594 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1595 SBUF_ASSERT_EQ(-1, sbuf_putc(s, 'a'));
1596
1597 sbuf_delete(s);
1598 }
1599 }
1600
1601 SBUF_TESTING("sbuf_trim")
1602 {
1603 SBUF_SHOULD("remove trailing spaces, tabs and newlines")
1604 {
1605 struct sbuf *s = NULL;
1606 const char *test = "foo \t\t\n\t";
1607
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);
1613
1614 sbuf_delete(s);
1615 }
1616
1617 SBUF_SHOULD("do nothing if there is no trailing whitespace")
1618 {
1619 struct sbuf *s = NULL;
1620 const char *test = "foo";
1621
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);
1627
1628 sbuf_delete(s);
1629 }
1630
1631 SBUF_SHOULD("fail if the sbuf is overflowed")
1632 {
1633 struct sbuf *s = NULL;
1634 const char *test = "foo ";
1635
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);
1641
1642 sbuf_delete(s);
1643 }
1644
1645 SBUF_SHOULD("work on empty strings")
1646 {
1647 struct sbuf *s = NULL;
1648
1649 s = sbuf_new(NULL, NULL, 16, 0);
1650 SBUF_ASSERT_EQ(0, sbuf_trim(s));
1651 SBUF_ASSERT_EQ(0, s->s_len);
1652
1653 sbuf_delete(s);
1654 }
1655 }
1656
1657 SBUF_TESTING("sbuf_overflowed")
1658 {
1659 SBUF_SHOULD("return false if it hasn't overflowed")
1660 {
1661 struct sbuf *s = NULL;
1662
1663 s = sbuf_new(NULL, NULL, 16, 0);
1664 SBUF_ASSERT_NOT(sbuf_overflowed(s));
1665
1666 sbuf_delete(s);
1667 }
1668
1669 SBUF_SHOULD("return true if it has overflowed")
1670 {
1671 struct sbuf *s = NULL;
1672
1673 s = sbuf_new(NULL, NULL, 16, 0);
1674 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
1675 SBUF_ASSERT(sbuf_overflowed(s));
1676
1677 sbuf_delete(s);
1678 }
1679 }
1680
1681 SBUF_TESTING("sbuf_finish")
1682 {
1683 SBUF_SHOULD("insert a nul byte, clear the overflowed flag and set the finished flag")
1684 {
1685 struct sbuf *s = NULL;
1686
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));
1692
1693 sbuf_finish(s);
1694
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));
1698
1699 sbuf_delete(s);
1700 }
1701 }
1702
1703 SBUF_TESTING("sbuf_data")
1704 {
1705 SBUF_SHOULD("return the s_buf pointer")
1706 {
1707 struct sbuf *s = NULL;
1708
1709 s = sbuf_new(NULL, NULL, 16, 0);
1710 SBUF_ASSERT_EQ(s->s_buf, sbuf_data(s));
1711
1712 sbuf_delete(s);
1713 }
1714
1715 SBUF_SHOULD("return the buffer we gave it")
1716 {
1717 struct sbuf *s = NULL;
1718 char buf[4] = { 0 };
1719
1720 s = sbuf_new(NULL, buf, sizeof(buf), 0);
1721 SBUF_ASSERT_EQ(buf, sbuf_data(s));
1722
1723 sbuf_delete(s);
1724 }
1725 }
1726
1727 SBUF_TESTING("sbuf_len")
1728 {
1729 SBUF_SHOULD("return the length of the sbuf data")
1730 {
1731 struct sbuf *s = NULL;
1732
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));
1736
1737 sbuf_delete(s);
1738 }
1739
1740 SBUF_SHOULD("return -1 if the sbuf is overflowed")
1741 {
1742 struct sbuf *s = NULL;
1743
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));
1749
1750 sbuf_delete(s);
1751 }
1752 }
1753
1754 SBUF_TESTING("sbuf_done")
1755 {
1756 SBUF_SHOULD("return false if the sbuf isn't finished")
1757 {
1758 struct sbuf *s = NULL;
1759
1760 s = sbuf_new(NULL, NULL, 16, 0);
1761 SBUF_ASSERT_NOT(sbuf_done(s));
1762
1763 sbuf_delete(s);
1764 }
1765
1766 SBUF_SHOULD("return true if the sbuf has finished")
1767 {
1768 struct sbuf *s = NULL;
1769
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));
1774
1775 sbuf_delete(s);
1776 }
1777 }
1778
1779 SBUF_TESTING("sbuf_delete")
1780 {
1781 SBUF_SHOULD("just free the backing buffer if we supplied an sbuf")
1782 {
1783 struct sbuf *s = NULL;
1784 struct sbuf existing = {};
1785
1786 s = sbuf_new(&existing, NULL, 16, 0);
1787 SBUF_ASSERT_NE(NULL, s->s_buf);
1788
1789 sbuf_delete(s);
1790 SBUF_ASSERT_EQ(NULL, s->s_buf);
1791 }
1792 }
1793
f427ee49 1794 SBUF_TEST_END;
2d21ac55 1795}
f427ee49
A
1796
1797SYSCTL_PROC(_kern, OID_AUTO, sbuf_test, CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_KERN | CTLFLAG_MASKED, 0, 0, sysctl_sbuf_tests, "A", "sbuf tests");
1798
1799#endif /* DEBUG || DEVELOPMENT */