banan-os/libc/stdlib.cpp

198 lines
3.4 KiB
C++

#include <BAN/Assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <unistd.h>
extern "C" char** environ;
extern "C" void _fini();
void abort(void)
{
fflush(nullptr);
fprintf(stderr, "abort()\n");
exit(1);
}
void exit(int status)
{
fflush(nullptr);
_fini();
_exit(status);
ASSERT_NOT_REACHED();
}
int abs(int val)
{
return val < 0 ? -val : val;
}
int atexit(void(*)(void))
{
return -1;
}
int atoi(const char* str)
{
while (isspace(*str))
str++;
bool negative = (*str == '-');
if (*str == '-' || *str == '+')
str++;
int res = 0;
while (isdigit(*str))
{
res = (res * 10) + (*str - '0');
str++;
}
return negative ? -res : res;
}
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 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;
}
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)
{
errno = ENOMEM;
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;
if (syscall(SYS_SETENVP, environ) == -1)
return -1;
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();
}