123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423 |
- #include <AK/AKString.h>
- #include <AK/Assertions.h>
- #include <AK/HashMap.h>
- #include <AK/StdLibExtras.h>
- #include <AK/Types.h>
- #include <Kernel/Syscall.h>
- #include <alloca.h>
- #include <assert.h>
- #include <ctype.h>
- #include <errno.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/mman.h>
- #include <sys/wait.h>
- #include <unistd.h>
- extern "C" {
- typedef void (*__atexit_handler)();
- static int __atexit_handler_count = 0;
- static __atexit_handler __atexit_handlers[32];
- void exit(int status)
- {
- for (int i = 0; i < __atexit_handler_count; ++i)
- __atexit_handlers[i]();
- extern void _fini();
- _fini();
- fflush(stdout);
- fflush(stderr);
- _exit(status);
- ASSERT_NOT_REACHED();
- }
- int atexit(void (*handler)())
- {
- ASSERT(__atexit_handler_count < 32);
- __atexit_handlers[__atexit_handler_count++] = handler;
- return 0;
- }
- void abort()
- {
- raise(SIGABRT);
- ASSERT_NOT_REACHED();
- }
- static HashTable<const char*> s_malloced_environment_variables;
- static void free_environment_variable_if_needed(const char* var)
- {
- if (!s_malloced_environment_variables.contains(var))
- return;
- free(const_cast<char*>(var));
- s_malloced_environment_variables.remove(var);
- }
- char* getenv(const char* name)
- {
- size_t vl = strlen(name);
- for (size_t i = 0; environ[i]; ++i) {
- const char* decl = environ[i];
- char* eq = strchr(decl, '=');
- if (!eq)
- continue;
- size_t varLength = eq - decl;
- if (vl != varLength)
- continue;
- if (strncmp(decl, name, varLength) == 0) {
- return eq + 1;
- }
- }
- return nullptr;
- }
- int unsetenv(const char* name)
- {
- auto new_var_len = strlen(name);
- size_t environ_size = 0;
- int skip = -1;
- for (; environ[environ_size]; ++environ_size) {
- char* old_var = environ[environ_size];
- char* old_eq = strchr(old_var, '=');
- ASSERT(old_eq);
- size_t old_var_len = old_eq - old_var;
- if (new_var_len != old_var_len)
- continue; // can't match
- if (strncmp(name, old_var, new_var_len) == 0)
- skip = environ_size;
- }
- if (skip == -1)
- return 0; // not found: no failure.
- // Shuffle the existing array down by one.
- memmove(&environ[skip], &environ[skip + 1], ((environ_size - 1) - skip) * sizeof(environ[0]));
- environ[environ_size - 1] = nullptr;
- free_environment_variable_if_needed(name);
- return 0;
- }
- int setenv(const char* name, const char* value, int overwrite)
- {
- if (!overwrite && !getenv(name))
- return 0;
- auto length = strlen(name) + strlen(value) + 2;
- auto* var = (char*)malloc(length);
- snprintf(var, length, "%s=%s", name, value);
- s_malloced_environment_variables.set(var);
- return putenv(var);
- }
- int putenv(char* new_var)
- {
- char* new_eq = strchr(new_var, '=');
- if (!new_eq)
- return unsetenv(new_var);
- auto new_var_len = new_eq - new_var;
- int environ_size = 0;
- for (; environ[environ_size]; ++environ_size) {
- char* old_var = environ[environ_size];
- char* old_eq = strchr(old_var, '=');
- ASSERT(old_eq);
- auto old_var_len = old_eq - old_var;
- if (new_var_len != old_var_len)
- continue; // can't match
- if (strncmp(new_var, old_var, new_var_len) == 0) {
- free_environment_variable_if_needed(old_var);
- environ[environ_size] = new_var;
- return 0;
- }
- }
- // At this point, we need to append the new var.
- // 2 here: one for the new var, one for the sentinel value.
- char** new_environ = (char**)malloc((environ_size + 2) * sizeof(char*));
- if (new_environ == nullptr) {
- errno = ENOMEM;
- return -1;
- }
- for (int i = 0; environ[i]; ++i) {
- new_environ[i] = environ[i];
- }
- new_environ[environ_size] = new_var;
- new_environ[environ_size + 1] = nullptr;
- // swap new and old
- // note that the initial environ is not heap allocated!
- extern bool __environ_is_malloced;
- if (__environ_is_malloced)
- free(environ);
- __environ_is_malloced = true;
- environ = new_environ;
- return 0;
- }
- double strtod(const char* str, char** endptr)
- {
- (void)str;
- (void)endptr;
- dbgprintf("LibC: strtod: '%s'\n", str);
- ASSERT_NOT_REACHED();
- }
- float strtof(const char* str, char** endptr)
- {
- (void)str;
- (void)endptr;
- dbgprintf("LibC: strtof: '%s'\n", str);
- ASSERT_NOT_REACHED();
- }
- double atof(const char* str)
- {
- dbgprintf("LibC: atof: '%s'\n", str);
- ASSERT_NOT_REACHED();
- }
- int atoi(const char* str)
- {
- size_t len = strlen(str);
- int value = 0;
- bool isNegative = false;
- for (size_t i = 0; i < len; ++i) {
- if (i == 0 && str[0] == '-') {
- isNegative = true;
- continue;
- }
- if (str[i] < '0' || str[i] > '9')
- return value;
- value = value * 10;
- value += str[i] - '0';
- }
- return isNegative ? -value : value;
- }
- long atol(const char* str)
- {
- static_assert(sizeof(int) == sizeof(long));
- return atoi(str);
- }
- long long atoll(const char* str)
- {
- dbgprintf("FIXME(Libc): atoll('%s') passing through to atol()\n", str);
- return atol(str);
- }
- static char ptsname_buf[32];
- char* ptsname(int fd)
- {
- if (ptsname_r(fd, ptsname_buf, sizeof(ptsname_buf)) < 0)
- return nullptr;
- return ptsname_buf;
- }
- int ptsname_r(int fd, char* buffer, size_t size)
- {
- int rc = syscall(SC_ptsname_r, fd, buffer, size);
- __RETURN_WITH_ERRNO(rc, rc, -1);
- }
- static unsigned long s_next_rand = 1;
- int rand()
- {
- s_next_rand = s_next_rand * 1103515245 + 12345;
- return ((unsigned)(s_next_rand / ((RAND_MAX + 1) * 2)) % (RAND_MAX + 1));
- }
- void srand(unsigned seed)
- {
- s_next_rand = seed;
- }
- int abs(int i)
- {
- return i < 0 ? -i : i;
- }
- long int random()
- {
- return rand();
- }
- void srandom(unsigned seed)
- {
- srand(seed);
- }
- int system(const char* command)
- {
- auto child = fork();
- if (!child) {
- int rc = execl("/bin/sh", "sh", "-c", command, nullptr);
- if (rc < 0)
- perror("execl");
- exit(0);
- }
- int wstatus;
- waitpid(child, &wstatus, 0);
- return WEXITSTATUS(wstatus);
- }
- char* mktemp(char* pattern)
- {
- int length = strlen(pattern);
- // FIXME: Check for an invalid template pattern and return EINVAL.
- if (length < 6) {
- pattern[0] = '\0';
- errno = EINVAL;
- return pattern;
- }
- int start = length - 6;
- static constexpr char random_characters[] = "abcdefghijklmnopqrstuvwxyz0123456789";
- for (int attempt = 0; attempt < 100; ++attempt) {
- for (int i = 0; i < 6; ++i)
- pattern[start + i] = random_characters[(rand() % sizeof(random_characters))];
- struct stat st;
- int rc = lstat(pattern, &st);
- if (rc < 0 && errno == ENOENT)
- return pattern;
- }
- pattern[0] = '\0';
- errno = EEXIST;
- return pattern;
- }
- void* bsearch(const void* key, const void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*))
- {
- dbgprintf("FIXME(LibC): bsearch(%p, %p, %u, %u, %p)\n", key, base, nmemb, size, compar);
- ASSERT_NOT_REACHED();
- }
- div_t div(int numerator, int denominator)
- {
- div_t result;
- result.quot = numerator / denominator;
- result.rem = numerator % denominator;
- return result;
- }
- ldiv_t ldiv(long numerator, long denominator)
- {
- ldiv_t result;
- result.quot = numerator / denominator;
- result.rem = numerator % denominator;
- return result;
- }
- size_t mbstowcs(wchar_t*, const char*, size_t)
- {
- ASSERT_NOT_REACHED();
- }
- long strtol(const char* nptr, char** endptr, int base)
- {
- errno = 0;
- if (base < 0 || base == 1 || base > 36) {
- errno = EINVAL;
- if (endptr)
- *endptr = const_cast<char*>(nptr);
- return 0;
- }
- const char* p = nptr;
- while (isspace(*p))
- ++p;
- bool is_negative = false;
- if (*p == '-') {
- is_negative = true;
- ++p;
- } else {
- if (*p == '+')
- ++p;
- }
- if (base == 0 || base == 16) {
- if (base == 0)
- base = 10;
- if (*p == '0') {
- if (*(p + 1) == 'X' || *(p + 1) == 'x') {
- p += 2;
- base = 16;
- } else if (base != 16) {
- base = 8;
- }
- }
- }
- long cutoff_point = is_negative ? (LONG_MIN / base) : (LONG_MAX / base);
- int max_valid_digit_at_cutoff_point = is_negative ? (LONG_MIN % base) : (LONG_MAX % base);
- long num = 0;
- bool has_overflowed = false;
- unsigned digits_consumed = 0;
- for (;;) {
- char ch = *(p++);
- int digit;
- if (isdigit(ch))
- digit = ch - '0';
- else if (islower(ch))
- digit = ch - ('a' - 10);
- else if (isupper(ch))
- digit = ch - ('A' - 10);
- else
- break;
- if (digit >= base)
- break;
- if (has_overflowed)
- continue;
- bool is_past_cutoff = is_negative ? num < cutoff_point : num > cutoff_point;
- if (is_past_cutoff || (num == cutoff_point && digit > max_valid_digit_at_cutoff_point)) {
- has_overflowed = true;
- num = is_negative ? LONG_MIN : LONG_MAX;
- errno = ERANGE;
- } else {
- num *= base;
- num += is_negative ? -digit : digit;
- ++digits_consumed;
- }
- }
- if (endptr) {
- if (has_overflowed || digits_consumed > 0)
- *endptr = const_cast<char*>(p - 1);
- else
- *endptr = const_cast<char*>(nptr);
- }
- return num;
- }
- unsigned long strtoul(const char* str, char** endptr, int base)
- {
- auto value = strtol(str, endptr, base);
- ASSERT(value >= 0);
- return value;
- }
- }
|