banan-os/libc/stdlib.cpp

207 lines
3.3 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;
}
void* malloc(size_t bytes)
{
long res = syscall(SYS_ALLOC, bytes);
if (res < 0)
return nullptr;
return (void*)res;
}
void* calloc(size_t nmemb, size_t size)
{
if (nmemb * size < nmemb)
return nullptr;
void* ptr = malloc(nmemb * size);
if (ptr == nullptr)
return nullptr;
memset(ptr, 0, nmemb * size);
return ptr;
}
void* realloc(void* ptr, size_t size)
{
if (ptr == nullptr)
return malloc(size);
long ret = syscall(SYS_REALLOC, ptr, size);
if (ret == -1)
return nullptr;
return (void*)ret;
}
void free(void* ptr)
{
if (ptr == nullptr)
return;
syscall(SYS_FREE, ptr);
}