Luna/libs/libc/src/stdlib.cpp

241 lines
5.0 KiB
C++

#include <ctype.h>
#include <luna.h>
#include <luna/syscall.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/wait.h>
#include <unistd.h>
template <typename T> static T string_to_integer_type(const char* str)
{
bool neg = false;
T val = 0;
switch (*str)
{
case '-':
neg = true;
str++;
break;
case '+': str++; break;
default: break;
}
while (isdigit(*str)) { val = (10 * val) + (*str++ - '0'); }
return (neg ? -val : val);
}
template <typename T> static T string_to_float_type(const char* str)
{
bool neg = false;
T val = 0;
T small = 0;
switch (*str)
{
case '-':
neg = true;
str++;
break;
case '+': str++; break;
default: break;
}
while (isdigit(*str)) { val = (10 * val) + (T)(*str++ - '0'); }
if (*str == '.')
{
str++;
T div = 10;
while (isdigit(*str))
{
small = small + (T)(*str++ - '0') / div;
div *= 10;
}
val += small;
}
return (neg ? -val : val);
}
template <typename Arg, typename Struct> static inline Struct common_div(Arg a, Arg b)
{
Struct result;
result.quot = a / b;
result.rem = a % b;
if (a >= 0 && result.rem < 0)
{
result.quot++;
result.rem -= b;
}
return result;
}
extern "C"
{
__lc_noreturn void abort()
{
_Exit(-1);
}
float atof(const char* str)
{
return string_to_float_type<float>(str);
}
int atoi(const char* str)
{
return string_to_integer_type<int>(str);
}
long atol(const char* str)
{
return string_to_integer_type<long>(str);
}
long long atoll(const char* str)
{
return string_to_integer_type<long long>(str);
}
unsigned long strtoul(const char* str, char** endptr, int base)
{
if (base != 0 && base != 10) NOT_IMPLEMENTED("strtoul with base not in (0,10)");
if (endptr) NOT_IMPLEMENTED("strtoul with non-null endptr");
return string_to_integer_type<unsigned long>(str);
}
long strtol(const char* str, char** endptr, int base)
{
if (base != 0 && base != 10) NOT_IMPLEMENTED("strtol with base not in (0,10)");
if (endptr) NOT_IMPLEMENTED("strtol with non-null endptr");
return string_to_integer_type<long>(str);
}
char* getenv(const char*)
{
return NULL; // FIXME: Not implemented :)
}
__lc_noreturn void _Exit(int status)
{
__lc_fast_syscall1(SYS_exit, status);
__lc_unreachable();
}
int abs(int val)
{
return __builtin_abs(val);
}
long labs(long val)
{
return __builtin_labs(val);
}
long long llabs(long long val)
{
return __builtin_llabs(val);
}
div_t div(int a, int b)
{
return common_div<int, div_t>(a, b);
}
ldiv_t ldiv(long a, long b)
{
return common_div<long, ldiv_t>(a, b);
}
lldiv_t lldiv(long long a, long long b)
{
return common_div<long long, lldiv_t>(a, b);
}
int system(const char* command)
{
pid_t child = fork();
if (child < 0) return -1;
if (child == 0)
{
char* argv[] = {const_cast<char*>("/bin/sh"), const_cast<char*>("-c"), const_cast<char*>(command),
nullptr}; // FIXME: This is very verbose.
execv(argv[0], argv);
exit(127);
}
int status;
waitpid(child, &status, 0);
return status;
}
void qsort(void*, size_t, size_t, int (*)(const void*, const void*))
{
NOT_IMPLEMENTED("qsort");
}
void* bsearch(const void*, const void*, size_t, size_t, int (*)(const void*, const void*))
{
NOT_IMPLEMENTED("bsearch");
}
size_t mbstowcs(wchar_t*, const char*, size_t)
{
NOT_IMPLEMENTED("mbstowcs");
}
static void gentemp(char* startptr)
{
for (int i = 0; i < 6; i++)
{
startptr[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"[rand() % 63];
}
}
char* mktemp(char* str)
{
size_t len = strlen(str);
if (len < 6)
{
errno = EINVAL;
return NULL;
}
char* startptr = str + (len - 6);
if (strncmp(startptr, "XXXXXX", 6))
{
errno = EINVAL;
return NULL;
}
do {
gentemp(startptr);
} while (access(str, F_OK) == 0);
return str;
}
char* mkdtemp(char* str)
{
size_t len = strlen(str);
if (len < 6)
{
errno = EINVAL;
return NULL;
}
char* startptr = str + (len - 6);
if (strncmp(startptr, "XXXXXX", 6))
{
errno = EINVAL;
return NULL;
}
do {
gentemp(startptr);
} while (mkdir(str, 0700) < 0 && errno == EEXIST);
if (errno) return NULL;
return str;
}
}