Serenity Operating System
at master 487 lines 12 kB view raw
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}