dte test coverage


Directory: ./
File: src/util/str-util.h
Date: 2025-09-07 23:01:39
Exec Total Coverage
Lines: 58 58 100.0%
Functions: 13 13 100.0%
Branches: 29 30 96.7%

Line Branch Exec Source
1 #ifndef UTIL_STR_UTIL_H
2 #define UTIL_STR_UTIL_H
3
4 #include <stdbool.h>
5 #include <stddef.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include "debug.h"
9 #include "macros.h"
10 #include "string-view.h"
11 #include "xstring.h"
12
13 #define copyliteral(dest, lit) copystrn(dest, lit, STRLEN(lit))
14
15 1326 static inline size_t copystrn(char *dest, const char *src, size_t len)
16 {
17 1326 memcpy(dest, src, len);
18 1326 return len;
19 }
20
21 // Like getenv(3), but also returning NULL for empty strings
22 29 static inline const char *xgetenv(const char *name)
23 {
24 29 const char *val = getenv(name);
25
3/4
✓ Branch 0 (3→4) taken 10 times.
✓ Branch 1 (3→5) taken 19 times.
✗ Branch 2 (4→5) not taken.
✓ Branch 3 (4→6) taken 10 times.
29 return (!val || val[0] == '\0') ? NULL : val;
26 }
27
28 PURE NONNULL_ARGS
29 1829 static inline bool str_has_strn_prefix(const char *str, const char *prefix, size_t plen)
30 {
31 // Note that `prefix` must be a null-terminated string and `plen`
32 // should be equal to strlen(prefix). The explicit length parameter
33 // is simply for the sake of efficiency, e.g. to allow strlen() to
34 // be hoisted out of loops when `prefix` is loop-invariant.
35
4/4
✓ Branch 0 (2→3) taken 1255 times.
✓ Branch 1 (2→5) taken 574 times.
✓ Branch 2 (3→4) taken 1155 times.
✓ Branch 3 (3→5) taken 100 times.
1829 return plen == 0 || strncmp(str, prefix, plen) == 0;
36 }
37
38 PURE NONNULL_ARGS
39 218 static inline bool str_has_prefix(const char *str, const char *prefix)
40 {
41 218 return str_has_strn_prefix(str, prefix, strlen(prefix));
42 }
43
44 PURE NONNULL_ARGS
45 15 static inline bool str_has_suffix(const char *str, const char *suffix)
46 {
47 15 size_t l1 = strlen(str);
48 15 size_t l2 = strlen(suffix);
49
4/4
✓ Branch 0 (2→3) taken 11 times.
✓ Branch 1 (2→6) taken 4 times.
✓ Branch 2 (4→5) taken 3 times.
✓ Branch 3 (4→6) taken 8 times.
15 return (l1 >= l2) && mem_equal(str + l1 - l2, suffix, l2);
50 }
51
52 NONNULL_ARGS
53 142 static inline size_t str_common_prefix_length(const char *a, const char *b)
54 {
55 142 size_t n = 0;
56
4/4
✓ Branch 0 (4→5) taken 3044 times.
✓ Branch 1 (4→6) taken 82 times.
✓ Branch 2 (5→3) taken 2984 times.
✓ Branch 3 (5→6) taken 60 times.
3126 while (a[n] && a[n] == b[n]) {
57 2984 n++;
58 }
59 142 return n;
60 }
61
62 // Replaces all occurrences of a specific byte with a replacement byte
63 // and returns the length of the string (like strlen(str))
64 NONNULL_ARGS
65 1 static inline size_t str_replace_byte(char *str, char byte, char replacement)
66 {
67 1 size_t n = 0;
68
2/2
✓ Branch 0 (6→3) taken 17 times.
✓ Branch 1 (6→7) taken 1 times.
18 for (char c; (c = str[n]); n++) {
69
2/2
✓ Branch 0 (3→4) taken 10 times.
✓ Branch 1 (3→5) taken 7 times.
17 if (c == byte) {
70 10 str[n] = replacement;
71 }
72 }
73 1 return n;
74 }
75
76 NONNULL_ARGS
77 5 static inline void strn_replace_byte(char *str, size_t n, char byte, char rep)
78 {
79
2/2
✓ Branch 0 (6→3) taken 70 times.
✓ Branch 1 (6→7) taken 5 times.
75 for (size_t i = 0; i < n; i++) {
80
2/2
✓ Branch 0 (3→4) taken 23 times.
✓ Branch 1 (3→5) taken 47 times.
70 if (str[i] == byte) {
81 23 str[i] = rep;
82 }
83 }
84 5 }
85
86 // Extract a substring between `buf + pos` and either the next `delim`
87 // byte (if found) or `buf + size` (the remainder of the string). The
88 // substring is returned as a StringView and the `posp` in-out param
89 // is set to the offset one byte after the found delimiter (or to the
90 // end of the size-bounded string, if no delimiter was found).
91 NONNULL_ARGS READONLY(1, 3) READWRITE(2)
92 12349 static inline StringView get_delim(const char *buf, size_t *posp, size_t size, int delim)
93 {
94 12349 size_t pos = *posp;
95 12349 BUG_ON(pos >= size);
96 12349 size_t len = size - pos;
97 12349 const char *start = buf + pos;
98 12349 const char *found = memchr(start, delim, len);
99
2/2
✓ Branch 0 (4→5) taken 12013 times.
✓ Branch 1 (4→6) taken 336 times.
12349 len = found ? (size_t)(found - start) : len;
100 12349 size_t delim_len = found ? 1 : 0;
101 12349 *posp += len + delim_len;
102 12349 return string_view(start, len);
103 }
104
105 // Similar to get_delim(), but returning a null-terminated substring
106 // instead of a StringView, by mutating the contents of `buf` (i.e.
107 // replacing the delimiter with a NUL byte). Using get_delim() should
108 // be preferred, unless the substring specifically needs to be
109 // null-terminated (e.g. for passing to a library function).
110 NONNULL_ARGS
111 1136 static inline char *get_delim_str(char *buf, size_t *posp, size_t size, int delim)
112 {
113 1136 char *substr = buf + *posp;
114 1136 StringView sv = get_delim(buf, posp, size, delim);
115
116 // If no delimiter was found, this writes the null-terminator 1 byte
117 // beyond the `size` bound. Callers must ensure this is safe to do.
118 // Thus, when calling this function (perhaps repeatedly) to consume
119 // an entire string, either buf[size-1] must be a delim byte or
120 // buf[size] must be in-bounds, writable memory.
121 1136 substr[sv.length] = '\0';
122 1136 return substr;
123 }
124
125 NONNULL_ARGS
126 10134 static inline StringView buf_slice_next_line(const char *buf, size_t *posp, size_t size)
127 {
128 10134 return get_delim(buf, posp, size, '\n');
129 }
130
131 NONNULL_ARGS
132 1103 static inline char *buf_next_line(char *buf, size_t *posp, size_t size)
133 {
134 1103 return get_delim_str(buf, posp, size, '\n');
135 }
136
137 NONNULL_ARGS
138 919 static inline size_t count_nl(const char *buf, size_t size)
139 {
140 919 const char *end = buf + size;
141 919 size_t nl = 0;
142
2/2
✓ Branch 0 (5→3) taken 3168 times.
✓ Branch 1 (5→6) taken 715 times.
3883 while (buf < end) {
143 3168 buf = memchr(buf, '\n', end - buf);
144
2/2
✓ Branch 0 (3→4) taken 2964 times.
✓ Branch 1 (3→6) taken 204 times.
3168 if (!buf) {
145 break;
146 }
147 2964 buf++;
148 2964 nl++;
149 }
150 919 return nl;
151 }
152
153 #endif
154