Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021-2022, Brian Gianforcaro <bgianf@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/Format.h>
9#include <AK/MemMem.h>
10#include <AK/Memory.h>
11#include <AK/Platform.h>
12#include <AK/StdLibExtras.h>
13#include <AK/Types.h>
14#include <assert.h>
15#include <ctype.h>
16#include <errno.h>
17#include <signal.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22extern "C" {
23
24// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strspn.html
25size_t strspn(char const* s, char const* accept)
26{
27 char const* p = s;
28cont:
29 char ch = *p++;
30 char ac;
31 for (char const* ap = accept; (ac = *ap++) != '\0';) {
32 if (ac == ch)
33 goto cont;
34 }
35 return p - 1 - s;
36}
37
38// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcspn.html
39size_t strcspn(char const* s, char const* reject)
40{
41 for (auto* p = s;;) {
42 char c = *p++;
43 auto* rp = reject;
44 char rc;
45 do {
46 if ((rc = *rp++) == c)
47 return p - 1 - s;
48 } while (rc);
49 }
50}
51
52// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html
53size_t strlen(char const* str)
54{
55 size_t len = 0;
56 while (*(str++))
57 ++len;
58 return len;
59}
60
61// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strnlen.html
62size_t strnlen(char const* str, size_t maxlen)
63{
64 size_t len = 0;
65 for (; len < maxlen && *str; str++)
66 len++;
67 return len;
68}
69
70// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html
71char* strdup(char const* str)
72{
73 size_t len = strlen(str);
74 char* new_str = (char*)malloc(len + 1);
75 memcpy(new_str, str, len);
76 new_str[len] = '\0';
77 return new_str;
78}
79
80// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strndup.html
81char* strndup(char const* str, size_t maxlen)
82{
83 size_t len = strnlen(str, maxlen);
84 char* new_str = (char*)malloc(len + 1);
85 memcpy(new_str, str, len);
86 new_str[len] = 0;
87 return new_str;
88}
89
90// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcmp.html
91int strcmp(char const* s1, char const* s2)
92{
93 while (*s1 == *s2++)
94 if (*s1++ == 0)
95 return 0;
96 return *(unsigned char const*)s1 - *(unsigned char const*)--s2;
97}
98
99// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strncmp.html
100int strncmp(char const* s1, char const* s2, size_t n)
101{
102 if (!n)
103 return 0;
104 do {
105 if (*s1 != *s2++)
106 return *(unsigned char const*)s1 - *(unsigned char const*)--s2;
107 if (*s1++ == 0)
108 break;
109 } while (--n);
110 return 0;
111}
112
113// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memcmp.html
114int memcmp(void const* v1, void const* v2, size_t n)
115{
116 auto* s1 = (uint8_t const*)v1;
117 auto* s2 = (uint8_t const*)v2;
118 while (n-- > 0) {
119 if (*s1++ != *s2++)
120 return s1[-1] < s2[-1] ? -1 : 1;
121 }
122 return 0;
123}
124
125int timingsafe_memcmp(void const* b1, void const* b2, size_t len)
126{
127 return AK::timing_safe_compare(b1, b2, len) ? 1 : 0;
128}
129
130// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memcpy.html
131void* memcpy(void* dest_ptr, void const* src_ptr, size_t n)
132{
133#if ARCH(X86_64)
134 void* original_dest = dest_ptr;
135 asm volatile(
136 "rep movsb"
137 : "+D"(dest_ptr), "+S"(src_ptr), "+c"(n)::"memory");
138 return original_dest;
139#else
140 u8* pd = (u8*)dest_ptr;
141 u8 const* ps = (u8 const*)src_ptr;
142 for (; n--;)
143 *pd++ = *ps++;
144 return dest_ptr;
145#endif
146}
147
148// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memset.html
149// For x86-64, an optimized ASM implementation is found in ./arch/x86_64/memset.S
150#if ARCH(X86_64)
151#else
152void* memset(void* dest_ptr, int c, size_t n)
153{
154 u8* pd = (u8*)dest_ptr;
155 for (; n--;)
156 *pd++ = c;
157 return dest_ptr;
158}
159#endif
160
161// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memmove.html
162void* memmove(void* dest, void const* src, size_t n)
163{
164 if (((FlatPtr)dest - (FlatPtr)src) >= n)
165 return memcpy(dest, src, n);
166
167 u8* pd = (u8*)dest;
168 u8 const* ps = (u8 const*)src;
169 for (pd += n, ps += n; n--;)
170 *--pd = *--ps;
171 return dest;
172}
173
174void const* memmem(void const* haystack, size_t haystack_length, void const* needle, size_t needle_length)
175{
176 return AK::memmem(haystack, haystack_length, needle, needle_length);
177}
178
179// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcpy.html
180char* strcpy(char* dest, char const* src)
181{
182 char* original_dest = dest;
183 while ((*dest++ = *src++) != '\0')
184 ;
185 return original_dest;
186}
187
188// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strncpy.html
189char* strncpy(char* dest, char const* src, size_t n)
190{
191 size_t i;
192 for (i = 0; i < n && src[i] != '\0'; ++i)
193 dest[i] = src[i];
194 for (; i < n; ++i)
195 dest[i] = '\0';
196 return dest;
197}
198
199size_t strlcpy(char* dest, char const* src, size_t n)
200{
201 size_t i;
202 // Would like to test i < n - 1 here, but n might be 0.
203 for (i = 0; i + 1 < n && src[i] != '\0'; ++i)
204 dest[i] = src[i];
205 if (n)
206 dest[i] = '\0';
207 for (; src[i] != '\0'; ++i)
208 ; // Determine the length of src, don't copy.
209 return i;
210}
211
212// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strchr.html
213char* strchr(char const* str, int c)
214{
215 char ch = c;
216 for (;; ++str) {
217 if (*str == ch)
218 return const_cast<char*>(str);
219 if (!*str)
220 return nullptr;
221 }
222}
223
224// https://pubs.opengroup.org/onlinepubs/9699959399/functions/index.html
225char* index(char const* str, int c)
226{
227 return strchr(str, c);
228}
229
230char* strchrnul(char const* str, int c)
231{
232 char ch = c;
233 for (;; ++str) {
234 if (*str == ch || !*str)
235 return const_cast<char*>(str);
236 }
237}
238
239// https://pubs.opengroup.org/onlinepubs/9699919799/functions/memchr.html
240void* memchr(void const* ptr, int c, size_t size)
241{
242 char ch = c;
243 auto* cptr = (char const*)ptr;
244 for (size_t i = 0; i < size; ++i) {
245 if (cptr[i] == ch)
246 return const_cast<char*>(cptr + i);
247 }
248 return nullptr;
249}
250
251// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strrchr.html
252char* strrchr(char const* str, int ch)
253{
254 char* last = nullptr;
255 char c;
256 for (; (c = *str); ++str) {
257 if (c == ch)
258 last = const_cast<char*>(str);
259 }
260 return last;
261}
262
263// https://pubs.opengroup.org/onlinepubs/9699959399/functions/rindex.html
264char* rindex(char const* str, int ch)
265{
266 return strrchr(str, ch);
267}
268
269// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcat.html
270char* strcat(char* dest, char const* src)
271{
272 size_t dest_length = strlen(dest);
273 size_t i;
274 for (i = 0; src[i] != '\0'; i++)
275 dest[dest_length + i] = src[i];
276 dest[dest_length + i] = '\0';
277 return dest;
278}
279
280// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strncat.html
281char* strncat(char* dest, char const* src, size_t n)
282{
283 size_t dest_length = strlen(dest);
284 size_t i;
285 for (i = 0; i < n && src[i] != '\0'; i++)
286 dest[dest_length + i] = src[i];
287 dest[dest_length + i] = '\0';
288 return dest;
289}
290
291char const* const sys_errlist[] = {
292#define __ENUMERATE_ERRNO_CODE(c, s) s,
293 ENUMERATE_ERRNO_CODES(__ENUMERATE_ERRNO_CODE)
294#undef __ENUMERATE_ERRNO_CODE
295};
296static_assert(array_size(sys_errlist) == (EMAXERRNO + 1));
297
298int sys_nerr = EMAXERRNO;
299
300// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror_r.html
301int strerror_r(int errnum, char* buf, size_t buflen)
302{
303 auto saved_errno = errno;
304 if (errnum < 0 || errnum >= EMAXERRNO) {
305 auto rc = strlcpy(buf, "unknown error", buflen);
306 if (rc >= buflen)
307 dbgln("strerror_r(): Invalid error number '{}' specified and the output buffer is too small.", errnum);
308 errno = saved_errno;
309 return EINVAL;
310 }
311 auto text = strerror(errnum);
312 auto rc = strlcpy(buf, text, buflen);
313 if (rc >= buflen) {
314 errno = saved_errno;
315 return ERANGE;
316 }
317 errno = saved_errno;
318 return 0;
319}
320
321// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html
322char* strerror(int errnum)
323{
324 if (errnum < 0 || errnum >= EMAXERRNO) {
325 return const_cast<char*>("Unknown error");
326 }
327 return const_cast<char*>(sys_errlist[errnum]);
328}
329
330// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strsignal.html
331char* strsignal(int signum)
332{
333 if (signum >= NSIG) {
334 dbgln("strsignal() missing string for signum={}", signum);
335 return const_cast<char*>("Unknown signal");
336 }
337 return const_cast<char*>(sys_siglist[signum]);
338}
339
340// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strstr.html
341char* strstr(char const* haystack, char const* needle)
342{
343 char nch;
344 char hch;
345
346 if ((nch = *needle++) != 0) {
347 size_t len = strlen(needle);
348 do {
349 do {
350 if ((hch = *haystack++) == 0)
351 return nullptr;
352 } while (hch != nch);
353 } while (strncmp(haystack, needle, len) != 0);
354 --haystack;
355 }
356 return const_cast<char*>(haystack);
357}
358
359// https://linux.die.net/man/3/strcasestr
360char* strcasestr(char const* haystack, char const* needle)
361{
362 char nch;
363 char hch;
364
365 if ((nch = *needle++) != 0) {
366 size_t len = strlen(needle);
367 do {
368 do {
369 if ((hch = *haystack++) == 0)
370 return nullptr;
371 } while (toupper(hch) != toupper(nch));
372 } while (strncasecmp(haystack, needle, len) != 0);
373 --haystack;
374 }
375 return const_cast<char*>(haystack);
376}
377
378// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strpbrk.html
379char* strpbrk(char const* s, char const* accept)
380{
381 while (*s)
382 if (strchr(accept, *s++))
383 return const_cast<char*>(--s);
384 return nullptr;
385}
386
387// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok_r.html
388char* strtok_r(char* str, char const* delim, char** saved_str)
389{
390 if (!str) {
391 if (!saved_str || *saved_str == nullptr)
392 return nullptr;
393 str = *saved_str;
394 }
395
396 size_t token_start = 0;
397 size_t token_end = 0;
398 size_t str_len = strlen(str);
399 size_t delim_len = strlen(delim);
400
401 for (size_t i = 0; i < str_len; ++i) {
402 bool is_proper_delim = false;
403
404 for (size_t j = 0; j < delim_len; ++j) {
405 if (str[i] == delim[j]) {
406 // Skip beginning delimiters
407 if (token_end - token_start == 0) {
408 ++token_start;
409 break;
410 }
411
412 is_proper_delim = true;
413 }
414 }
415
416 ++token_end;
417 if (is_proper_delim && token_end > 0) {
418 --token_end;
419 break;
420 }
421 }
422
423 if (str[token_start] == '\0') {
424 *saved_str = nullptr;
425 return nullptr;
426 }
427
428 if (token_end == 0) {
429 *saved_str = nullptr;
430 return &str[token_start];
431 }
432
433 if (str[token_end] == '\0')
434 *saved_str = &str[token_end];
435 else
436 *saved_str = &str[token_end + 1];
437
438 str[token_end] = '\0';
439 return &str[token_start];
440}
441
442// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strtok.html
443char* strtok(char* str, char const* delim)
444{
445 static char* saved_str;
446 return strtok_r(str, delim, &saved_str);
447}
448
449// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcoll.html
450int strcoll(char const* s1, char const* s2)
451{
452 return strcmp(s1, s2);
453}
454
455// https://pubs.opengroup.org/onlinepubs/9699919799/functions/strxfrm.html
456size_t strxfrm(char* dest, char const* src, size_t n)
457{
458 size_t i;
459 for (i = 0; i < n && src[i] != '\0'; ++i)
460 dest[i] = src[i];
461 for (; i < n; ++i)
462 dest[i] = '\0';
463 return i;
464}
465
466// Not in POSIX, originated in BSD but also supported on Linux.
467// https://man.openbsd.org/strsep.3
468char* strsep(char** str, char const* delim)
469{
470 if (*str == nullptr)
471 return nullptr;
472 auto* begin = *str;
473 auto* end = begin + strcspn(begin, delim);
474 if (*end) {
475 *end = '\0';
476 *str = ++end;
477 } else {
478 *str = nullptr;
479 }
480 return begin;
481}
482
483void explicit_bzero(void* ptr, size_t size)
484{
485 secure_zero(ptr, size);
486}
487}