#include #include #include #include #include #include #include #include #include #include extern "C" char** environ; extern "C" void _fini(); static void (*at_exit_funcs[64])(); static uint32_t at_exit_funcs_count = 0; void abort(void) { fflush(nullptr); fprintf(stderr, "abort()\n"); exit(1); } void exit(int status) { for (uint32_t i = at_exit_funcs_count; i > 0; i--) at_exit_funcs[i - 1](); fflush(nullptr); __cxa_finalize(nullptr); _fini(); _exit(status); ASSERT_NOT_REACHED(); } int abs(int val) { return val < 0 ? -val : val; } int atexit(void (*func)(void)) { if (at_exit_funcs_count > sizeof(at_exit_funcs) / sizeof(*at_exit_funcs)) { errno = ENOBUFS; return -1; } at_exit_funcs[at_exit_funcs_count++] = func; return 0; } template static T strtoT(const char* str, char** endp, int base) { // validate base if (base != 0 && (base < 2 || base > 36)) { errno = EINVAL; return 0; } // parse character to its value in base // if digit is not of base, return -1 auto get_base_digit = [](char c, int base) -> int { int digit = -1; if (isdigit(c)) digit = c - '0'; else if (isalpha(c)) digit = 10 + tolower(c) - 'a'; if (digit < base) return digit; return -1; }; // skip whitespace while (isspace(*str)) str++; // get sign and skip in bool negative = (*str == '-'); if (*str == '-' || *str == '+') str++; // determine base from prefix if (base == 0) { if (strncasecmp(str, "0x", 2) == 0) base = 16; else if (*str == '0') base = 8; else if (isdigit(*str)) base = 10; } // check for invalid conversion if (get_base_digit(*str, base) == -1) { if (endp) *endp = const_cast(str); errno = EINVAL; return 0; } // remove "0x" prefix from hexadecimal if (base == 16) { if (strncasecmp(str, "0x", 2) == 0) str += 2; } // limits of type T constexpr T max_val = BAN::numeric_limits::max(); constexpr T min_val = -max_val - 1; bool overflow = false; T result = 0; while (!overflow) { int digit = get_base_digit(*str, base); if (digit == -1) break; // check for overflow if (negative) { if (result < min_val / base) overflow = true; else if (result * base < min_val + digit) overflow = true; } else { if (result > max_val / base) overflow = true; else if (result * base > max_val - digit) overflow = true; } // calculate result's next step and move to next character if (!overflow) { result = result * base + (negative ? -digit : digit); str++; } } // save endp if asked if (endp) { while (get_base_digit(*str, base) != -1) str++; *endp = const_cast(str); } // return error on overflow if (overflow) { errno = ERANGE; return negative ? min_val : max_val; } return negative ? -result : result; } int atoi(const char* str) { return strtol(str, nullptr, 10); } long atol(const char* str) { return strtol(str, nullptr, 10); } long long atoll(const char* str) { return strtoll(str, nullptr, 10); } long strtol(const char* __restrict str, char** __restrict endp, int base) { return strtoT(str, endp, base); } long long strtoll(const char* __restrict str, char** __restrict endp, int base) { return strtoT(str, endp, base); } char* getenv(const char* name) { if (environ == nullptr) return nullptr; size_t len = strlen(name); for (int i = 0; environ[i]; i++) if (strncmp(name, environ[i], len) == 0) if (environ[i][len] == '=') return environ[i] + len + 1; return nullptr; } int system(const char* command) { // FIXME if (command == nullptr) return 1; int pid = fork(); if (pid == 0) { execl("/bin/Shell", "Shell", "-c", command, (char*)0); exit(1); } if (pid == -1) return -1; int stat_val; waitpid(pid, &stat_val, 0); return stat_val; } int setenv(const char* name, const char* val, int overwrite) { if (name == nullptr || !name[0] || strchr(name, '=')) { errno = EINVAL; return -1; } if (!overwrite && getenv(name)) return 0; size_t namelen = strlen(name); size_t vallen = strlen(val); char* string = (char*)malloc(namelen + vallen + 2); memcpy(string, name, namelen); string[namelen] = '='; memcpy(string + namelen + 1, val, vallen); string[namelen + vallen + 1] = '\0'; return putenv(string); } int unsetenv(const char* name) { if (name == nullptr || !name[0] || strchr(name, '=')) { errno = EINVAL; return -1; } size_t len = strlen(name); bool found = false; for (int i = 0; environ[i]; i++) { if (!found && strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') { free(environ[i]); found = true; } if (found) environ[i] = environ[i + 1]; } return 0; } int putenv(char* string) { if (string == nullptr || !string[0]) { errno = EINVAL; return -1; } if (!environ) { environ = (char**)malloc(sizeof(char*) * 2); if (!environ) return -1; environ[0] = string; environ[1] = nullptr; return 0; } int cnt = 0; for (int i = 0; string[i]; i++) if (string[i] == '=') cnt++; if (cnt != 1) { errno = EINVAL; return -1; } int namelen = strchr(string, '=') - string; for (int i = 0; environ[i]; i++) { if (strncmp(environ[i], string, namelen + 1) == 0) { free(environ[i]); environ[i] = string; return 0; } } int env_count = 0; while (environ[env_count]) env_count++; char** new_envp = (char**)malloc(sizeof(char*) * (env_count + 2)); if (new_envp == nullptr) return -1; for (int i = 0; i < env_count; i++) new_envp[i] = environ[i]; new_envp[env_count] = string; new_envp[env_count + 1] = nullptr; free(environ); environ = new_envp; return 0; } // Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator static uint64_t s_rand_state = 0x4d595df4d0f33173; static constexpr uint64_t s_rand_multiplier = 6364136223846793005; static constexpr uint64_t s_rand_increment = 1442695040888963407; static constexpr uint32_t rotr32(uint32_t x, unsigned r) { return x >> r | x << (-r & 31); } int rand(void) { uint64_t x = s_rand_state; unsigned count = (unsigned)(x >> 59); s_rand_state = x * s_rand_multiplier + s_rand_increment; x ^= x >> 18; return rotr32(x >> 27, count) % RAND_MAX; } void srand(unsigned int seed) { s_rand_state = seed + s_rand_increment; (void)rand(); }