MMgr v1.0.0
Zero-heap memory manager in C11. One borrowed buffer, carved by asserted offset.
Loading...
Searching...
No Matches
mmgr_string_shim.h
1/**
2 * @brief Redirects the <string.h> names onto MMgr's bounded implementations.
3 *
4 * @note Defines the usual <string.h> include guards. A later #include <string.h> contributes nothing.
5 * @warning strcmp, strcasecmp, strncmp and strncasecmp report equality only and never order.
6 * @warning Including this header changes the meaning of those names for the whole translation unit.
7 */
8#ifndef MMGR_STRING_SHIM_H
9#define MMGR_STRING_SHIM_H
10
12#include "config/mmgr_config.h"
14
15/**
16 * @brief Read bound applied to the <string.h> names that take no length of their own.
17 *
18 * @note Defaults to MMGR_CARCER_MAX, the largest confinium a string can occupy.
19 * @warning strlen, strstr, strcmp and strchr stop at this many bytes even without a terminator.
20 */
21#ifndef MMGR_STR_MAX
22
23#define MMGR_STR_MAX MMGR_CARCER_MAX
24#endif
25
26/**
27 * @brief Claims the include guards several C libraries use for <string.h>.
28 *
29 * @note A later #include <string.h> then expands to nothing, leaving these macros in place.
30 * @warning A library whose guard is not among these five will still declare the real functions.
31 */
32#ifndef _STRING_H
33#define _STRING_H 1
34#endif
35#ifndef _STRING_H_
36#define _STRING_H_ 1
37#endif
38#ifndef __STRING_H__
39#define __STRING_H__ 1
40#endif
41#ifndef _STRING_H_INCLUDED
42#define _STRING_H_INCLUDED 1
43#endif
44#ifndef _INC_STRING
45#define _INC_STRING 1
46#endif
47
48MMGR_INCIPE_DECLS
49
50/**
51 * @brief Copies bytes from source to dest and returns dest.
52 *
53 * @param[out] dest Destination to write [BORROWS].
54 * @param[in] source Bytes to read [BORROWS].
55 * @param[in] bytes Number of bytes to copy.
56 * @return dest [BORROWS].
57 * @warning The two regions must not overlap; use mmgr_shim_move when they might.
58 */
59MMGR_INLINE void *mmgr_shim_cpy(void *dest, const void *source, size_t bytes)
60{
61 MMGR_CALL(memor.cpy, MemoriaCfg, .dst = dest, .src = source, .bytes = bytes);
62 return dest;
63}
64
65/**
66 * @brief Copies bytes from source to dest, tolerating overlap, and returns dest.
67 *
68 * @param[out] dest Destination to write [BORROWS].
69 * @param[in] source Bytes to read [BORROWS].
70 * @param[in] bytes Number of bytes to copy.
71 * @return dest [BORROWS].
72 * @note Compares the two addresses and walks upwards or downwards so overlapping bytes are read before they are
73 * written.
74 */
75MMGR_INLINE void *mmgr_shim_move(void *dest, const void *source, size_t bytes)
76{
77 if ((const uint8_t *)dest <= (const uint8_t *)source)
78 {
79 MMGR_CALL(memor.move_down, MemoriaCfg, .dst = dest, .src = source, .bytes = bytes);
80 }
81 else
82 {
83 MMGR_CALL(memor.move_up, MemoriaCfg, .dst = dest, .src = source, .bytes = bytes);
84 }
85 return dest;
86}
87
88/**
89 * @brief Fills bytes of dest with the low byte of value and returns dest.
90 *
91 * @param[out] dest Destination to write [BORROWS].
92 * @param[in] value Fill value; only its low eight bits are used.
93 * @param[in] bytes Number of bytes to write.
94 * @return dest [BORROWS].
95 * @note Explicit cast narrows value to uint8_t, matching the byte the fill writes.
96 */
97MMGR_INLINE void *mmgr_shim_set(void *dest, mmgr_iword value, size_t bytes)
98{
99 MMGR_CALL(memor.set, MemoriaCfg, .dst = dest, .val = (uint8_t)value, .bytes = bytes);
100 return dest;
101}
102
103/**
104 * @brief Compares bytes of left against right.
105 *
106 * @param[in] left First region [BORROWS].
107 * @param[in] right Second region [BORROWS].
108 * @param[in] bytes Number of bytes to compare.
109 * @return Difference of the first unequal byte pair, or 0 when all bytes match.
110 * @note Unlike the strcmp shims, this one does order: the sign follows the differing bytes.
111 */
112MMGR_INLINE mmgr_iword mmgr_shim_cmp(const void *left, const void *right, size_t bytes)
113{
114 return MMGR_CALL(memor.cmp, MemoriaCfg, .src = left, .other = right, .bytes = bytes);
115}
116
117/**
118 * @brief Finds the first byte in region equal to the low byte of value.
119 *
120 * @param[in] region Bytes to search [BORROWS].
121 * @param[in] value Byte sought; only its low eight bits are used.
122 * @param[in] bytes Number of bytes to search.
123 * @return Address of the match, or NULL when the byte does not occur [BORROWS].
124 * @note The cast through size_t drops the const the backend returns, matching the memchr signature.
125 */
126MMGR_INLINE void *mmgr_shim_chr(const void *region, mmgr_iword value, size_t bytes)
127{
128 return (void *)(size_t)MMGR_CALL(memor.chr, MemoriaCfg, .src = region, .bytes = bytes, .val = (uint8_t)value);
129}
130
131/**
132 * @brief Replaces memcpy with mmgr_shim_cpy.
133 *
134 * @note Every argument is parenthesized. Any expression may be passed.
135 */
136#define memcpy(dest, source, bytes) mmgr_shim_cpy((dest), (source), (bytes))
137
138/**
139 * @brief Replaces memmove with mmgr_shim_move.
140 */
141#define memmove(dest, source, bytes) mmgr_shim_move((dest), (source), (bytes))
142
143/**
144 * @brief Replaces memset with mmgr_shim_set.
145 */
146#define memset(dest, value, bytes) mmgr_shim_set((dest), (value), (bytes))
147
148/**
149 * @brief Replaces memcmp with mmgr_shim_cmp.
150 *
151 * @note Keeps the ordering the standard requires; the sign follows the first differing byte pair.
152 */
153#define memcmp(left, right, bytes) mmgr_shim_cmp((left), (right), (bytes))
154
155/**
156 * @brief Replaces memchr with mmgr_shim_chr.
157 */
158#define memchr(region, value, bytes) mmgr_shim_chr((region), (value), (bytes))
159
160/**
161 * @brief Replaces strlen with a scan bounded at MMGR_STR_MAX.
162 *
163 * @warning Returns MMGR_STR_MAX when no terminator appears within it, instead of scanning further.
164 */
165#define strlen(text) MMGR_CALL(cellul.len, CatenaFinitaCfg, .src = (text), .cap = MMGR_STR_MAX)
166
167/**
168 * @brief Replaces strnlen with a scan bounded at limit.
169 *
170 * @note Returns limit when no terminator appears within it, as strnlen does.
171 */
172#define strnlen(text, limit) MMGR_CALL(cellul.len, CatenaFinitaCfg, .src = (text), .cap = (limit))
173
174/**
175 * @brief Replaces strstr with a case-sensitive search bounded at MMGR_STR_MAX.
176 *
177 * @note The cast through size_t drops the const the backend returns, matching the strstr signature.
178 * @warning Both operands are read to MMGR_STR_MAX, and both must be terminated within it.
179 */
180#define strstr(haystack, needle) \
181 ((char *)(size_t)MMGR_CALL(cellul.find, CatenaFinitaCfg, .src = (haystack), .cap = MMGR_STR_MAX, \
182 .other = (needle), .other_cap = MMGR_STR_MAX, .ci = MMGR_FALSE))
183
184/**
185 * @brief Replaces strcasestr with a case-folded search bounded at MMGR_STR_MAX.
186 *
187 * @note Differs from the strstr shim only in passing ci as MMGR_TRUE.
188 * @warning Both operands are read to MMGR_STR_MAX, and both must be terminated within it.
189 */
190#define strcasestr(haystack, needle) \
191 ((char *)(size_t)MMGR_CALL(cellul.find, CatenaFinitaCfg, .src = (haystack), .cap = MMGR_STR_MAX, \
192 .other = (needle), .other_cap = MMGR_STR_MAX, .ci = MMGR_TRUE))
193
194/**
195 * @brief Replaces strcmp with an equality test bounded at MMGR_STR_MAX.
196 *
197 * @note Gives 0 when the two agree and 1 when they do not, and so == 0 and ! both test equality.
198 * @warning Never negative and never above 1: it cannot be used to order strings.
199 */
200#define strcmp(left, right) \
201 (!MMGR_CALL(cellul.eq, CatenaFinitaCfg, .src = (left), .other = (right), .cap = MMGR_STR_MAX, .ci = MMGR_FALSE))
202
203/**
204 * @brief Replaces strcasecmp with a case-folded equality test bounded at MMGR_STR_MAX.
205 *
206 * @note Gives 0 when the two agree and 1 when they do not.
207 * @warning Never negative and never above 1: it cannot be used to order strings.
208 */
209#define strcasecmp(left, right) \
210 (!MMGR_CALL(cellul.eq, CatenaFinitaCfg, .src = (left), .other = (right), .cap = MMGR_STR_MAX, .ci = MMGR_TRUE))
211
212/**
213 * @brief Replaces strncmp with an equality test over at most limit bytes.
214 *
215 * @note Gives 0 when the two agree through limit and 1 when they differ before it.
216 * @warning Never negative and never above 1: it cannot be used to order strings.
217 * @warning A terminator does not end the comparison; all limit bytes must be readable in both operands.
218 */
219#define strncmp(left, right, limit) \
220 (MMGR_CALL(cellul.diff, CatenaFinitaCfg, .src = (left), .other = (right), .cap = (limit), .ci = MMGR_FALSE) < \
221 (limit))
222
223/**
224 * @brief Replaces strncasecmp with a case-folded equality test over at most limit bytes.
225 *
226 * @note Gives 0 when the two agree through limit and 1 when they differ before it.
227 * @warning Never negative and never above 1: it cannot be used to order strings.
228 * @warning A terminator does not end the comparison; all limit bytes must be readable in both operands.
229 */
230#define strncasecmp(left, right, limit) \
231 (MMGR_CALL(cellul.diff, CatenaFinitaCfg, .src = (left), .other = (right), .cap = (limit), .ci = MMGR_TRUE) < \
232 (limit))
233
234/**
235 * @brief Replaces strlcpy with a bounded copy that always terminates unless limit is 0.
236 *
237 * @note Returns the bytes copied, the truncated length and not the source length.
238 */
239#define strlcpy(dest, source, limit) \
240 MMGR_CALL(cellul.copy, CatenaFinitaCfg, .dst = (dest), .src = (source), .cap = (limit))
241
242/**
243 * @brief Replaces strchr with a search bounded at MMGR_STR_MAX.
244 *
245 * @note A value of 0 returns the address of the terminator, as strchr does.
246 * @note The cast through size_t drops the const the backend returns, matching the strchr signature.
247 * @warning text is read to MMGR_STR_MAX, and so it must be terminated within it.
248 */
249#define strchr(text, value) \
250 ((char *)(size_t)MMGR_CALL(cellul.chr, CatenaFinitaCfg, .src = (text), .cap = MMGR_STR_MAX, \
251 .byte = (uint8_t)(value)))
252
253MMGR_FINIS_DECLS
254
255#endif
Bounded string work: the three argument types, the calls, and the cellul dispatch table.
Byte-level memory work: its arguments, the calls, and the memor dispatch table.
Arguments for the memor calls.
void *const dst
const void *const src