dte test coverage


Directory: ./
File: src/util/str-util.h
Date: 2024-12-21 16:03:22
Exec Total Coverage
Lines: 65 65 100.0%
Functions: 13 13 100.0%
Branches: 31 32 96.9%

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 883 static inline size_t copystrn(char *dest, const char *src, size_t len)
16 {
17 883 memcpy(dest, src, len);
18 883 return len;
19 }
20
21 // Like getenv(3), but also returning NULL for empty strings
22 17 static inline const char *xgetenv(const char *name)
23 {
24 17 const char *val = getenv(name);
25
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
17 return (!val || val[0] == '\0') ? NULL : val;
26 }
27
28 PURE NONNULL_ARGS
29 2009 static inline bool str_has_prefix(const char *str, const char *prefix)
30 {
31 2009 return strncmp(str, prefix, strlen(prefix)) == 0;
32 }
33
34 PURE NONNULL_ARGS
35 19 static inline bool str_has_suffix(const char *str, const char *suffix)
36 {
37 19 size_t l1 = strlen(str);
38 19 size_t l2 = strlen(suffix);
39
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 7 times.
19 return (l1 >= l2) && mem_equal(str + l1 - l2, suffix, l2);
40 }
41
42 NONNULL_ARGS
43 73 static inline bool strn_has_strview_prefix(const char *s, size_t n, const StringView *p)
44 {
45
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 3 times.
73 return n >= p->length && mem_equal(s, p->data, p->length);
46 }
47
48 NONNULL_ARGS
49 87 static inline size_t str_common_prefix_length(const char *a, const char *b)
50 {
51 87 size_t n = 0;
52
4/4
✓ Branch 0 taken 1721 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 1685 times.
✓ Branch 3 taken 36 times.
1772 while (a[n] && a[n] == b[n]) {
53 1685 n++;
54 }
55 87 return n;
56 }
57
58 // Replaces all occurrences of a specific byte with a replacement byte
59 // and returns the length of the string (like strlen(str))
60 NONNULL_ARGS
61 1 static inline size_t str_replace_byte(char *str, char byte, char replacement)
62 {
63 1 size_t n = 0;
64
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 1 times.
18 for (char c; (c = str[n]); n++) {
65
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 7 times.
17 if (c == byte) {
66 10 str[n] = replacement;
67 }
68 }
69 1 return n;
70 }
71
72 NONNULL_ARGS
73 5 static inline void strn_replace_byte(char *str, size_t n, char byte, char rep)
74 {
75
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 5 times.
75 for (size_t i = 0; i < n; i++) {
76
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 47 times.
70 if (str[i] == byte) {
77 23 str[i] = rep;
78 }
79 }
80 5 }
81
82 // Extract a substring between `buf + pos` and either the next `delim`
83 // byte (if found) or `buf + size` (the remainder of the string). The
84 // substring is returned as a StringView and the `posp` in-out-param
85 // is set to the offset one byte after the found delimiter (or to the
86 // end of the size-bounded string, if no delimiter was found).
87 NONNULL_ARGS
88 9185 static inline StringView get_delim(const char *buf, size_t *posp, size_t size, int delim)
89 {
90 9185 size_t pos = *posp;
91 9185 BUG_ON(pos >= size);
92 9185 size_t len = size - pos;
93 9185 const char *start = buf + pos;
94 9185 const char *found = memchr(start, delim, len);
95
2/2
✓ Branch 0 taken 8957 times.
✓ Branch 1 taken 228 times.
9185 len = found ? (size_t)(found - start) : len;
96 9185 size_t delim_len = found ? 1 : 0;
97 9185 *posp += len + delim_len;
98 9185 return string_view(start, len);
99 }
100
101 // Similar to get_delim(), but returning a null-terminated substring
102 // instead of a StringView, by mutating the contents of `buf` (i.e.
103 // replacing the delimiter with a NUL byte). Using get_delim() should
104 // be preferred, unless the substring specifically needs to be
105 // null-terminated (e.g. for passing to a library function).
106 NONNULL_ARGS
107 564 static inline char *get_delim_str(char *buf, size_t *posp, size_t size, int delim)
108 {
109 564 size_t pos = *posp;
110 564 BUG_ON(pos >= size);
111 564 size_t len = size - pos;
112 564 char *start = buf + pos;
113 564 char *found = memchr(start, delim, len);
114
2/2
✓ Branch 0 taken 562 times.
✓ Branch 1 taken 2 times.
564 if (found) {
115 562 *found = '\0';
116 562 *posp += (size_t)(found - start) + 1;
117 } else {
118 // If no delimiter is found, write the null-terminator 1 byte
119 // beyond the `size` bound. Callers must ensure this is safe
120 // to do. Thus, when calling this function (perhaps repeatedly)
121 // to consume an entire string, either buf[size-1] must be a
122 // delim byte or buf[size] must be in-bounds, writable memory.
123 2 start[len] = '\0';
124 2 *posp += len;
125 }
126 564 return start;
127 }
128
129 NONNULL_ARGS
130 8391 static inline StringView buf_slice_next_line(const char *buf, size_t *posp, size_t size)
131 {
132 8391 return get_delim(buf, posp, size, '\n');
133 }
134
135 NONNULL_ARGS
136 560 static inline char *buf_next_line(char *buf, size_t *posp, size_t size)
137 {
138 560 return get_delim_str(buf, posp, size, '\n');
139 }
140
141 NONNULL_ARGS
142 588 static inline size_t count_nl(const char *buf, size_t size)
143 {
144 588 const char *end = buf + size;
145 588 size_t nl = 0;
146
2/2
✓ Branch 0 taken 1359 times.
✓ Branch 1 taken 476 times.
1835 while (buf < end) {
147 1359 buf = memchr(buf, '\n', end - buf);
148
2/2
✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 112 times.
1359 if (!buf) {
149 break;
150 }
151 1247 buf++;
152 1247 nl++;
153 }
154 588 return nl;
155 }
156
157 #endif
158