Warning: This file is not a C or C++ file. It does not have highlighting.
1 | /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ |
---|---|
2 | /* |
3 | * string function definitions for NOLIBC |
4 | * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> |
5 | */ |
6 | |
7 | #ifndef _NOLIBC_STRING_H |
8 | #define _NOLIBC_STRING_H |
9 | |
10 | #include "std.h" |
11 | |
12 | static void *malloc(size_t len); |
13 | |
14 | /* |
15 | * As much as possible, please keep functions alphabetically sorted. |
16 | */ |
17 | |
18 | static __attribute__((unused)) |
19 | int memcmp(const void *s1, const void *s2, size_t n) |
20 | { |
21 | size_t ofs = 0; |
22 | int c1 = 0; |
23 | |
24 | while (ofs < n && !(c1 = ((unsigned char *)s1)[ofs] - ((unsigned char *)s2)[ofs])) { |
25 | ofs++; |
26 | } |
27 | return c1; |
28 | } |
29 | |
30 | #ifndef NOLIBC_ARCH_HAS_MEMMOVE |
31 | /* might be ignored by the compiler without -ffreestanding, then found as |
32 | * missing. |
33 | */ |
34 | __attribute__((weak,unused,section(".text.nolibc_memmove"))) |
35 | void *memmove(void *dst, const void *src, size_t len) |
36 | { |
37 | size_t dir, pos; |
38 | |
39 | pos = len; |
40 | dir = -1; |
41 | |
42 | if (dst < src) { |
43 | pos = -1; |
44 | dir = 1; |
45 | } |
46 | |
47 | while (len) { |
48 | pos += dir; |
49 | ((char *)dst)[pos] = ((const char *)src)[pos]; |
50 | len--; |
51 | } |
52 | return dst; |
53 | } |
54 | #endif /* #ifndef NOLIBC_ARCH_HAS_MEMMOVE */ |
55 | |
56 | #ifndef NOLIBC_ARCH_HAS_MEMCPY |
57 | /* must be exported, as it's used by libgcc on ARM */ |
58 | __attribute__((weak,unused,section(".text.nolibc_memcpy"))) |
59 | void *memcpy(void *dst, const void *src, size_t len) |
60 | { |
61 | size_t pos = 0; |
62 | |
63 | while (pos < len) { |
64 | ((char *)dst)[pos] = ((const char *)src)[pos]; |
65 | pos++; |
66 | } |
67 | return dst; |
68 | } |
69 | #endif /* #ifndef NOLIBC_ARCH_HAS_MEMCPY */ |
70 | |
71 | #ifndef NOLIBC_ARCH_HAS_MEMSET |
72 | /* might be ignored by the compiler without -ffreestanding, then found as |
73 | * missing. |
74 | */ |
75 | __attribute__((weak,unused,section(".text.nolibc_memset"))) |
76 | void *memset(void *dst, int b, size_t len) |
77 | { |
78 | char *p = dst; |
79 | |
80 | while (len--) { |
81 | /* prevent gcc from recognizing memset() here */ |
82 | __asm__ volatile(""); |
83 | *(p++) = b; |
84 | } |
85 | return dst; |
86 | } |
87 | #endif /* #ifndef NOLIBC_ARCH_HAS_MEMSET */ |
88 | |
89 | static __attribute__((unused)) |
90 | char *strchr(const char *s, int c) |
91 | { |
92 | while (*s) { |
93 | if (*s == (char)c) |
94 | return (char *)s; |
95 | s++; |
96 | } |
97 | return NULL; |
98 | } |
99 | |
100 | static __attribute__((unused)) |
101 | int strcmp(const char *a, const char *b) |
102 | { |
103 | unsigned int c; |
104 | int diff; |
105 | |
106 | while (!(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) |
107 | ; |
108 | return diff; |
109 | } |
110 | |
111 | static __attribute__((unused)) |
112 | char *strcpy(char *dst, const char *src) |
113 | { |
114 | char *ret = dst; |
115 | |
116 | while ((*dst++ = *src++)); |
117 | return ret; |
118 | } |
119 | |
120 | /* this function is only used with arguments that are not constants or when |
121 | * it's not known because optimizations are disabled. Note that gcc 12 |
122 | * recognizes an strlen() pattern and replaces it with a jump to strlen(), |
123 | * thus itself, hence the asm() statement below that's meant to disable this |
124 | * confusing practice. |
125 | */ |
126 | static __attribute__((unused)) |
127 | size_t strlen(const char *str) |
128 | { |
129 | size_t len; |
130 | |
131 | for (len = 0; str[len]; len++) |
132 | __asm__(""); |
133 | return len; |
134 | } |
135 | |
136 | /* do not trust __builtin_constant_p() at -O0, as clang will emit a test and |
137 | * the two branches, then will rely on an external definition of strlen(). |
138 | */ |
139 | #if defined(__OPTIMIZE__) |
140 | #define nolibc_strlen(x) strlen(x) |
141 | #define strlen(str) ({ \ |
142 | __builtin_constant_p((str)) ? \ |
143 | __builtin_strlen((str)) : \ |
144 | nolibc_strlen((str)); \ |
145 | }) |
146 | #endif |
147 | |
148 | static __attribute__((unused)) |
149 | size_t strnlen(const char *str, size_t maxlen) |
150 | { |
151 | size_t len; |
152 | |
153 | for (len = 0; (len < maxlen) && str[len]; len++); |
154 | return len; |
155 | } |
156 | |
157 | static __attribute__((unused)) |
158 | char *strdup(const char *str) |
159 | { |
160 | size_t len; |
161 | char *ret; |
162 | |
163 | len = strlen(str); |
164 | ret = malloc(len + 1); |
165 | if (__builtin_expect(ret != NULL, 1)) |
166 | memcpy(ret, str, len + 1); |
167 | |
168 | return ret; |
169 | } |
170 | |
171 | static __attribute__((unused)) |
172 | char *strndup(const char *str, size_t maxlen) |
173 | { |
174 | size_t len; |
175 | char *ret; |
176 | |
177 | len = strnlen(str, maxlen); |
178 | ret = malloc(len + 1); |
179 | if (__builtin_expect(ret != NULL, 1)) { |
180 | memcpy(ret, str, len); |
181 | ret[len] = '\0'; |
182 | } |
183 | |
184 | return ret; |
185 | } |
186 | |
187 | static __attribute__((unused)) |
188 | size_t strlcat(char *dst, const char *src, size_t size) |
189 | { |
190 | size_t len; |
191 | char c; |
192 | |
193 | for (len = 0; dst[len]; len++) |
194 | ; |
195 | |
196 | for (;;) { |
197 | c = *src; |
198 | if (len < size) |
199 | dst[len] = c; |
200 | if (!c) |
201 | break; |
202 | len++; |
203 | src++; |
204 | } |
205 | |
206 | return len; |
207 | } |
208 | |
209 | static __attribute__((unused)) |
210 | size_t strlcpy(char *dst, const char *src, size_t size) |
211 | { |
212 | size_t len; |
213 | char c; |
214 | |
215 | for (len = 0;;) { |
216 | c = src[len]; |
217 | if (len < size) |
218 | dst[len] = c; |
219 | if (!c) |
220 | break; |
221 | len++; |
222 | } |
223 | return len; |
224 | } |
225 | |
226 | static __attribute__((unused)) |
227 | char *strncat(char *dst, const char *src, size_t size) |
228 | { |
229 | char *orig = dst; |
230 | |
231 | while (*dst) |
232 | dst++; |
233 | |
234 | while (size && (*dst = *src)) { |
235 | src++; |
236 | dst++; |
237 | size--; |
238 | } |
239 | |
240 | *dst = 0; |
241 | return orig; |
242 | } |
243 | |
244 | static __attribute__((unused)) |
245 | int strncmp(const char *a, const char *b, size_t size) |
246 | { |
247 | unsigned int c; |
248 | int diff = 0; |
249 | |
250 | while (size-- && |
251 | !(diff = (unsigned char)*a++ - (c = (unsigned char)*b++)) && c) |
252 | ; |
253 | |
254 | return diff; |
255 | } |
256 | |
257 | static __attribute__((unused)) |
258 | char *strncpy(char *dst, const char *src, size_t size) |
259 | { |
260 | size_t len; |
261 | |
262 | for (len = 0; len < size; len++) |
263 | if ((dst[len] = *src)) |
264 | src++; |
265 | return dst; |
266 | } |
267 | |
268 | static __attribute__((unused)) |
269 | char *strrchr(const char *s, int c) |
270 | { |
271 | const char *ret = NULL; |
272 | |
273 | while (*s) { |
274 | if (*s == (char)c) |
275 | ret = s; |
276 | s++; |
277 | } |
278 | return (char *)ret; |
279 | } |
280 | |
281 | /* make sure to include all global symbols */ |
282 | #include "nolibc.h" |
283 | |
284 | #endif /* _NOLIBC_STRING_H */ |
285 |
Warning: This file is not a C or C++ file. It does not have highlighting.