Serenity Operating System
at hosted 542 lines 13 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/Platform.h> 28#include <AK/StdLibExtras.h> 29#include <AK/Types.h> 30#include <assert.h> 31#include <ctype.h> 32#include <errno.h> 33#include <signal.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37 38extern "C" { 39 40void bzero(void* dest, size_t n) 41{ 42 memset(dest, 0, n); 43} 44 45void bcopy(const void* src, void* dest, size_t n) 46{ 47 memmove(dest, src, n); 48} 49 50size_t strspn(const char* s, const char* accept) 51{ 52 const char* p = s; 53cont: 54 char ch = *p++; 55 char ac; 56 for (const char* ap = accept; (ac = *ap++) != '\0';) { 57 if (ac == ch) 58 goto cont; 59 } 60 return p - 1 - s; 61} 62 63size_t strcspn(const char* s, const char* reject) 64{ 65 for (auto* p = s;;) { 66 char c = *p++; 67 auto* rp = reject; 68 char rc; 69 do { 70 if ((rc = *rp++) == c) 71 return p - 1 - s; 72 } while (rc); 73 } 74} 75 76size_t strlen(const char* str) 77{ 78 size_t len = 0; 79 while (*(str++)) 80 ++len; 81 return len; 82} 83 84size_t strnlen(const char* str, size_t maxlen) 85{ 86 size_t len = 0; 87 for (; len < maxlen && *str; str++) 88 len++; 89 return len; 90} 91 92char* strdup(const char* str) 93{ 94 size_t len = strlen(str); 95 char* new_str = (char*)malloc(len + 1); 96 strcpy(new_str, str); 97 return new_str; 98} 99 100char* strndup(const char* str, size_t maxlen) 101{ 102 size_t len = min(strlen(str), maxlen); 103 char* new_str = (char*)malloc(len + 1); 104 memcpy(new_str, str, len); 105 new_str[len] = 0; 106 return new_str; 107} 108 109int strcmp(const char* s1, const char* s2) 110{ 111 while (*s1 == *s2++) 112 if (*s1++ == 0) 113 return 0; 114 return *(const unsigned char*)s1 - *(const unsigned char*)--s2; 115} 116 117int strncmp(const char* s1, const char* s2, size_t n) 118{ 119 if (!n) 120 return 0; 121 do { 122 if (*s1 != *s2++) 123 return *(const unsigned char*)s1 - *(const unsigned char*)--s2; 124 if (*s1++ == 0) 125 break; 126 } while (--n); 127 return 0; 128} 129 130int memcmp(const void* v1, const void* v2, size_t n) 131{ 132 auto* s1 = (const uint8_t*)v1; 133 auto* s2 = (const uint8_t*)v2; 134 while (n-- > 0) { 135 if (*s1++ != *s2++) 136 return s1[-1] < s2[-1] ? -1 : 1; 137 } 138 return 0; 139} 140 141#if ARCH(I386) 142void* mmx_memcpy(void* dest, const void* src, size_t len) 143{ 144 ASSERT(len >= 1024); 145 146 auto* dest_ptr = (u8*)dest; 147 auto* src_ptr = (const u8*)src; 148 149 if ((u32)dest_ptr & 7) { 150 u32 prologue = 8 - ((u32)dest_ptr & 7); 151 len -= prologue; 152 asm volatile( 153 "rep movsb\n" 154 : "=S"(src_ptr), "=D"(dest_ptr), "=c"(prologue) 155 : "0"(src_ptr), "1"(dest_ptr), "2"(prologue) 156 : "memory"); 157 } 158 for (u32 i = len / 64; i; --i) { 159 asm volatile( 160 "movq (%0), %%mm0\n" 161 "movq 8(%0), %%mm1\n" 162 "movq 16(%0), %%mm2\n" 163 "movq 24(%0), %%mm3\n" 164 "movq 32(%0), %%mm4\n" 165 "movq 40(%0), %%mm5\n" 166 "movq 48(%0), %%mm6\n" 167 "movq 56(%0), %%mm7\n" 168 "movq %%mm0, (%1)\n" 169 "movq %%mm1, 8(%1)\n" 170 "movq %%mm2, 16(%1)\n" 171 "movq %%mm3, 24(%1)\n" 172 "movq %%mm4, 32(%1)\n" 173 "movq %%mm5, 40(%1)\n" 174 "movq %%mm6, 48(%1)\n" 175 "movq %%mm7, 56(%1)\n" ::"r"(src_ptr), 176 "r"(dest_ptr) 177 : "memory"); 178 src_ptr += 64; 179 dest_ptr += 64; 180 } 181 asm volatile("emms" :: 182 : "memory"); 183 // Whatever remains we'll have to memcpy. 184 len %= 64; 185 if (len) 186 memcpy(dest_ptr, src_ptr, len); 187 return dest; 188} 189 190void* memcpy(void* dest_ptr, const void* src_ptr, size_t n) 191{ 192 if (n >= 1024) 193 return mmx_memcpy(dest_ptr, src_ptr, n); 194 195 u32 dest = (u32)dest_ptr; 196 u32 src = (u32)src_ptr; 197 // FIXME: Support starting at an unaligned address. 198 if (!(dest & 0x3) && !(src & 0x3) && n >= 12) { 199 size_t u32s = n / sizeof(u32); 200 asm volatile( 201 "rep movsl\n" 202 : "=S"(src), "=D"(dest) 203 : "S"(src), "D"(dest), "c"(u32s) 204 : "memory"); 205 n -= u32s * sizeof(u32); 206 if (n == 0) 207 return dest_ptr; 208 } 209 asm volatile( 210 "rep movsb\n" ::"S"(src), "D"(dest), "c"(n) 211 : "memory"); 212 return dest_ptr; 213} 214 215void* memset(void* dest_ptr, int c, size_t n) 216{ 217 u32 dest = (u32)dest_ptr; 218 // FIXME: Support starting at an unaligned address. 219 if (!(dest & 0x3) && n >= 12) { 220 size_t u32s = n / sizeof(u32); 221 u32 expanded_c = (u8)c; 222 expanded_c |= expanded_c << 8; 223 expanded_c |= expanded_c << 16; 224 asm volatile( 225 "rep stosl\n" 226 : "=D"(dest) 227 : "D"(dest), "c"(u32s), "a"(expanded_c) 228 : "memory"); 229 n -= u32s * sizeof(u32); 230 if (n == 0) 231 return dest_ptr; 232 } 233 asm volatile( 234 "rep stosb\n" 235 : "=D"(dest), "=c"(n) 236 : "0"(dest), "1"(n), "a"(c) 237 : "memory"); 238 return dest_ptr; 239} 240#else 241void* memcpy(void* dest_ptr, const void* src_ptr, size_t n) 242{ 243 auto* dest = (u8*)dest_ptr; 244 auto* src = (const u8*)src_ptr; 245 for (size_t i = 0; i < n; ++i) 246 dest[i] = src[i]; 247 return dest_ptr; 248} 249 250void* memset(void* dest_ptr, int c, size_t n) 251{ 252 auto* dest = (u8*)dest_ptr; 253 for (size_t i = 0; i < n; ++i) 254 dest[i] = (u8)c; 255 return dest_ptr; 256} 257#endif 258 259void* memmove(void* dest, const void* src, size_t n) 260{ 261 if (dest < src) 262 return memcpy(dest, src, n); 263 264 u8* pd = (u8*)dest; 265 const u8* ps = (const u8*)src; 266 for (pd += n, ps += n; n--;) 267 *--pd = *--ps; 268 return dest; 269} 270 271char* strcpy(char* dest, const char* src) 272{ 273 char* originalDest = dest; 274 while ((*dest++ = *src++) != '\0') 275 ; 276 return originalDest; 277} 278 279char* strncpy(char* dest, const char* src, size_t n) 280{ 281 size_t i; 282 for (i = 0; i < n && src[i] != '\0'; ++i) 283 dest[i] = src[i]; 284 for (; i < n; ++i) 285 dest[i] = '\0'; 286 return dest; 287} 288 289char* strchr(const char* str, int c) 290{ 291 char ch = c; 292 for (;; ++str) { 293 if (*str == ch) 294 return const_cast<char*>(str); 295 if (!*str) 296 return nullptr; 297 } 298} 299 300char* strchrnul(const char* str, int c) 301{ 302 char ch = c; 303 for (;; ++str) { 304 if (*str == ch || !*str) 305 return const_cast<char*>(str); 306 } 307} 308 309void* memchr(const void* ptr, int c, size_t size) 310{ 311 char ch = c; 312 auto* cptr = (const char*)ptr; 313 for (size_t i = 0; i < size; ++i) { 314 if (cptr[i] == ch) 315 return const_cast<char*>(cptr + i); 316 } 317 return nullptr; 318} 319 320char* strrchr(const char* str, int ch) 321{ 322 char* last = nullptr; 323 char c; 324 for (; (c = *str); ++str) { 325 if (c == ch) 326 last = const_cast<char*>(str); 327 } 328 return last; 329} 330 331char* strcat(char* dest, const char* src) 332{ 333 size_t dest_length = strlen(dest); 334 size_t i; 335 for (i = 0; src[i] != '\0'; i++) 336 dest[dest_length + i] = src[i]; 337 dest[dest_length + i] = '\0'; 338 return dest; 339} 340 341char* strncat(char* dest, const char* src, size_t n) 342{ 343 size_t dest_length = strlen(dest); 344 size_t i; 345 for (i = 0; i < n && src[i] != '\0'; i++) 346 dest[dest_length + i] = src[i]; 347 dest[dest_length + i] = '\0'; 348 return dest; 349} 350 351const char* const sys_errlist[] = { 352 "Success (not an error)", 353 "Operation not permitted", 354 "No such file or directory", 355 "No such process", 356 "Interrupted syscall", 357 "I/O error", 358 "No such device or address", 359 "Argument list too long", 360 "Exec format error", 361 "Bad fd number", 362 "No child processes", 363 "Try again", 364 "Out of memory", 365 "Permission denied", 366 "Bad address", 367 "Block device required", 368 "Device or resource busy", 369 "File already exists", 370 "Cross-device link", 371 "No such device", 372 "Not a directory", 373 "Is a directory", 374 "Invalid argument", 375 "File table overflow", 376 "Too many open files", 377 "Not a TTY", 378 "Text file busy", 379 "File too large", 380 "No space left on device", 381 "Illegal seek", 382 "Read-only filesystem", 383 "Too many links", 384 "Broken pipe", 385 "Range error", 386 "Name too long", 387 "Too many symlinks", 388 "Overflow", 389 "Operation not supported", 390 "No such syscall", 391 "Not implemented", 392 "Address family not supported", 393 "Not a socket", 394 "Address in use", 395 "Failed without setting an error code (bug!)", 396 "Directory not empty", 397 "Math argument out of domain", 398 "Connection refused", 399 "Address not available", 400 "Already connected", 401 "Connection aborted", 402 "Connection already in progress", 403 "Connection reset", 404 "Desination address required", 405 "Host unreachable", 406 "Illegal byte sequence", 407 "Message size", 408 "Network down", 409 "Network unreachable", 410 "Network reset", 411 "No buffer space", 412 "No lock available", 413 "No message", 414 "No protocol option", 415 "Not connected", 416 "Operation would block", 417 "Protocol not supported", 418 "Resource deadlock would occur", 419 "Timed out", 420 "Wrong protocol type", 421 "Operation in progress", 422 "No such thread", 423 "Protocol error", 424 "Not supported", 425 "The highest errno +1 :^)", 426}; 427 428int sys_nerr = EMAXERRNO; 429 430char* strerror(int errnum) 431{ 432 if (errnum >= EMAXERRNO) { 433 printf("strerror() missing string for errnum=%d\n", errnum); 434 return const_cast<char*>("Unknown error"); 435 } 436 return const_cast<char*>(sys_errlist[errnum]); 437} 438 439char* strsignal(int signum) 440{ 441 if (signum >= NSIG) { 442 printf("strsignal() missing string for signum=%d\n", signum); 443 return const_cast<char*>("Unknown signal"); 444 } 445 return const_cast<char*>(sys_siglist[signum]); 446} 447 448char* strstr(const char* haystack, const char* needle) 449{ 450 char nch; 451 char hch; 452 453 if ((nch = *needle++) != 0) { 454 size_t len = strlen(needle); 455 do { 456 do { 457 if ((hch = *haystack++) == 0) 458 return nullptr; 459 } while (hch != nch); 460 } while (strncmp(haystack, needle, len) != 0); 461 --haystack; 462 } 463 return const_cast<char*>(haystack); 464} 465 466char* strpbrk(const char* s, const char* accept) 467{ 468 while (*s) 469 if (strchr(accept, *s++)) 470 return const_cast<char*>(--s); 471 return nullptr; 472} 473 474char* strtok_r(char* str, const char* delim, char** saved_str) 475{ 476 if (!str) { 477 if (!saved_str) 478 return nullptr; 479 str = *saved_str; 480 } 481 482 size_t token_start = 0; 483 size_t token_end = 0; 484 size_t str_len = strlen(str); 485 size_t delim_len = strlen(delim); 486 487 for (size_t i = 0; i < str_len; ++i) { 488 bool is_proper_delim = false; 489 490 for (size_t j = 0; j < delim_len; ++j) { 491 if (str[i] == delim[j]) { 492 // Skip beginning delimiters 493 if (token_end - token_start == 0) { 494 ++token_start; 495 break; 496 } 497 498 is_proper_delim = true; 499 } 500 } 501 502 ++token_end; 503 if (is_proper_delim && token_end > 0) { 504 --token_end; 505 break; 506 } 507 } 508 509 if (str[token_start] == '\0') 510 return nullptr; 511 512 if (token_end == 0) { 513 *saved_str = nullptr; 514 return &str[token_start]; 515 } 516 517 *saved_str = &str[token_end + 1]; 518 str[token_end] = '\0'; 519 return &str[token_start]; 520} 521 522char* strtok(char* str, const char* delim) 523{ 524 static char* saved_str; 525 return strtok_r(str, delim, &saved_str); 526} 527 528int strcoll(const char* s1, const char* s2) 529{ 530 return strcmp(s1, s2); 531} 532 533size_t strxfrm(char* dest, const char* src, size_t n) 534{ 535 size_t i; 536 for (i = 0; i < n && src[i] != '\0'; ++i) 537 dest[i] = src[i]; 538 for (; i < n; ++i) 539 dest[i] = '\0'; 540 return i; 541} 542}