push
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
extern int __cervus_errno;
|
||||
extern int __cervus_argc;
|
||||
extern char **__cervus_argv;
|
||||
|
||||
int abs(int x) { return x < 0 ? -x : x; }
|
||||
long labs(long x) { return x < 0 ? -x : x; }
|
||||
long long llabs(long long x){ return x < 0 ? -x : x; }
|
||||
|
||||
static long long __parse_signed(const char *s, char **end, int base, int is_unsigned)
|
||||
{
|
||||
while (isspace((unsigned char)*s)) s++;
|
||||
int neg = 0;
|
||||
if (*s == '-') { neg = 1; s++; }
|
||||
else if (*s == '+') s++;
|
||||
if ((base == 0 || base == 16) && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
|
||||
s += 2; base = 16;
|
||||
} else if (base == 0 && *s == '0') {
|
||||
s++; base = 8;
|
||||
} else if (base == 0) {
|
||||
base = 10;
|
||||
}
|
||||
unsigned long long v = 0;
|
||||
while (*s) {
|
||||
int d;
|
||||
if (isdigit((unsigned char)*s)) d = *s - '0';
|
||||
else if (*s >= 'a' && *s <= 'z') d = *s - 'a' + 10;
|
||||
else if (*s >= 'A' && *s <= 'Z') d = *s - 'A' + 10;
|
||||
else break;
|
||||
if (d >= base) break;
|
||||
v = v * (unsigned long long)base + (unsigned long long)d;
|
||||
s++;
|
||||
}
|
||||
if (end) *end = (char *)s;
|
||||
if (is_unsigned) return (long long)v;
|
||||
return neg ? -(long long)v : (long long)v;
|
||||
}
|
||||
|
||||
long strtol(const char *s, char **e, int b) { return (long)__parse_signed(s, e, b, 0); }
|
||||
long long strtoll(const char *s, char **e, int b) { return __parse_signed(s, e, b, 0); }
|
||||
unsigned long strtoul(const char *s, char **e, int b) { return (unsigned long)__parse_signed(s, e, b, 1); }
|
||||
unsigned long long strtoull(const char *s, char **e, int b) { return (unsigned long long)__parse_signed(s, e, b, 1); }
|
||||
|
||||
int atoi(const char *s) { return (int)strtol(s, NULL, 10); }
|
||||
long atol(const char *s) { return strtol(s, NULL, 10); }
|
||||
long long atoll(const char *s) { return strtoll(s, NULL, 10); }
|
||||
|
||||
static unsigned long __rand_state = 1;
|
||||
int rand(void) { __rand_state = __rand_state * 1103515245UL + 12345UL; return (int)((__rand_state >> 16) & 0x7FFF); }
|
||||
void srand(unsigned int seed) { __rand_state = seed; }
|
||||
|
||||
static void __qswap(void *a, void *b, size_t sz)
|
||||
{
|
||||
unsigned char tmp;
|
||||
unsigned char *pa = (unsigned char *)a;
|
||||
unsigned char *pb = (unsigned char *)b;
|
||||
while (sz--) { tmp = *pa; *pa++ = *pb; *pb++ = tmp; }
|
||||
}
|
||||
|
||||
void qsort(void *base, size_t nmemb, size_t sz, int (*cmp)(const void *, const void *))
|
||||
{
|
||||
if (nmemb < 2) return;
|
||||
unsigned char *arr = (unsigned char *)base;
|
||||
unsigned char *pivot = arr + (nmemb - 1) * sz;
|
||||
size_t i = 0;
|
||||
for (size_t j = 0; j < nmemb - 1; j++) {
|
||||
if (cmp(arr + j * sz, pivot) <= 0) {
|
||||
if (i != j) __qswap(arr + i * sz, arr + j * sz, sz);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
__qswap(arr + i * sz, pivot, sz);
|
||||
qsort(arr, i, sz, cmp);
|
||||
qsort(arr + (i + 1) * sz, nmemb - i - 1, sz, cmp);
|
||||
}
|
||||
|
||||
char *getenv(const char *name)
|
||||
{
|
||||
if (!name) return NULL;
|
||||
size_t nl = strlen(name);
|
||||
for (int i = 1; i < __cervus_argc; i++) {
|
||||
const char *a = __cervus_argv[i];
|
||||
if (a && a[0] == '-' && a[1] == '-' &&
|
||||
a[2] == 'e' && a[3] == 'n' && a[4] == 'v' && a[5] == ':') {
|
||||
const char *kv = a + 6;
|
||||
if (strncmp(kv, name, nl) == 0 && kv[nl] == '=')
|
||||
return (char *)(kv + nl + 1);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int system(const char *cmd)
|
||||
{
|
||||
(void)cmd;
|
||||
__cervus_errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define ATEXIT_MAX 32
|
||||
static void (*__atexit_fns[ATEXIT_MAX])(void);
|
||||
static int __atexit_cnt = 0;
|
||||
|
||||
int atexit(void (*fn)(void))
|
||||
{
|
||||
if (__atexit_cnt >= ATEXIT_MAX) return -1;
|
||||
__atexit_fns[__atexit_cnt++] = fn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fflush(FILE *stream);
|
||||
|
||||
void exit(int status)
|
||||
{
|
||||
while (__atexit_cnt > 0) {
|
||||
__atexit_cnt--;
|
||||
if (__atexit_fns[__atexit_cnt]) __atexit_fns[__atexit_cnt]();
|
||||
}
|
||||
extern FILE *stdout;
|
||||
extern FILE *stderr;
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
syscall1(SYS_EXIT, status);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
void abort(void)
|
||||
{
|
||||
syscall1(SYS_EXIT, 134);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
uint64_t __cervus_strtod_bits(const char *s, char **endptr)
|
||||
{
|
||||
if (!s) {
|
||||
if (endptr) *endptr = (char *)s;
|
||||
return 0;
|
||||
}
|
||||
const char *p = s;
|
||||
while (*p == ' ' || *p == '\t' || *p == '\n' ||
|
||||
*p == '\r' || *p == '\f' || *p == '\v') p++;
|
||||
|
||||
int sign = 0;
|
||||
if (*p == '+') p++;
|
||||
else if (*p == '-') { sign = 1; p++; }
|
||||
|
||||
if ((p[0] == 'i' || p[0] == 'I') &&
|
||||
(p[1] == 'n' || p[1] == 'N') &&
|
||||
(p[2] == 'f' || p[2] == 'F')) {
|
||||
p += 3;
|
||||
if ((p[0] == 'i' || p[0] == 'I') &&
|
||||
(p[1] == 'n' || p[1] == 'N') &&
|
||||
(p[2] == 'i' || p[2] == 'I') &&
|
||||
(p[3] == 't' || p[3] == 'T') &&
|
||||
(p[4] == 'y' || p[4] == 'Y')) p += 5;
|
||||
if (endptr) *endptr = (char *)p;
|
||||
return ((uint64_t)sign << 63) | 0x7FF0000000000000ULL;
|
||||
}
|
||||
if ((p[0] == 'n' || p[0] == 'N') &&
|
||||
(p[1] == 'a' || p[1] == 'A') &&
|
||||
(p[2] == 'n' || p[2] == 'N')) {
|
||||
p += 3;
|
||||
if (endptr) *endptr = (char *)p;
|
||||
return 0x7FF8000000000000ULL;
|
||||
}
|
||||
|
||||
uint64_t mant = 0;
|
||||
int dec_exp = 0;
|
||||
int seen_digit = 0;
|
||||
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
seen_digit = 1;
|
||||
if (mant <= (UINT64_MAX - 9) / 10) {
|
||||
mant = mant * 10 + (uint64_t)(*p - '0');
|
||||
} else {
|
||||
dec_exp++;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
seen_digit = 1;
|
||||
if (mant <= (UINT64_MAX - 9) / 10) {
|
||||
mant = mant * 10 + (uint64_t)(*p - '0');
|
||||
dec_exp--;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
if (!seen_digit) {
|
||||
if (endptr) *endptr = (char *)s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*p == 'e' || *p == 'E') {
|
||||
const char *ep = p + 1;
|
||||
int esign = 0;
|
||||
if (*ep == '+') ep++;
|
||||
else if (*ep == '-') { esign = 1; ep++; }
|
||||
if (*ep >= '0' && *ep <= '9') {
|
||||
int eval = 0;
|
||||
while (*ep >= '0' && *ep <= '9') {
|
||||
if (eval < 10000) eval = eval * 10 + (*ep - '0');
|
||||
ep++;
|
||||
}
|
||||
dec_exp += esign ? -eval : eval;
|
||||
p = ep;
|
||||
}
|
||||
}
|
||||
if (endptr) *endptr = (char *)p;
|
||||
|
||||
if (mant == 0) {
|
||||
return (uint64_t)sign << 63;
|
||||
}
|
||||
|
||||
int bin_exp = 0;
|
||||
while ((mant >> 63) == 0) {
|
||||
mant <<= 1;
|
||||
bin_exp--;
|
||||
}
|
||||
|
||||
while (dec_exp > 0) {
|
||||
uint64_t a_hi = mant >> 32;
|
||||
uint64_t a_lo = mant & 0xFFFFFFFFULL;
|
||||
uint64_t p_lo = a_lo * 10;
|
||||
uint64_t p_hi = a_hi * 10;
|
||||
uint64_t mid_carry = p_lo >> 32;
|
||||
uint64_t lo = ((p_hi + mid_carry) << 32) | (p_lo & 0xFFFFFFFFULL);
|
||||
uint64_t hi = (p_hi + mid_carry) >> 32;
|
||||
|
||||
while (hi != 0) {
|
||||
lo = (lo >> 1) | (hi << 63);
|
||||
hi >>= 1;
|
||||
bin_exp++;
|
||||
}
|
||||
mant = lo;
|
||||
while ((mant >> 63) == 0) {
|
||||
mant <<= 1;
|
||||
bin_exp--;
|
||||
}
|
||||
dec_exp--;
|
||||
}
|
||||
while (dec_exp < 0) {
|
||||
mant = mant / 10;
|
||||
if (mant == 0) break;
|
||||
while ((mant >> 63) == 0) {
|
||||
mant <<= 1;
|
||||
bin_exp--;
|
||||
}
|
||||
dec_exp++;
|
||||
}
|
||||
|
||||
int ieee_exp = bin_exp + 63 + 1023;
|
||||
uint64_t no_implicit = mant & 0x7FFFFFFFFFFFFFFFULL;
|
||||
uint64_t round_bit = (no_implicit >> 10) & 1;
|
||||
uint64_t sticky = (no_implicit & 0x3FFULL) ? 1 : 0;
|
||||
uint64_t frac = no_implicit >> 11;
|
||||
if (round_bit && (sticky || (frac & 1))) {
|
||||
frac++;
|
||||
if (frac == (1ULL << 52)) {
|
||||
frac = 0;
|
||||
ieee_exp++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ieee_exp >= 0x7FF) {
|
||||
return ((uint64_t)sign << 63) | 0x7FF0000000000000ULL;
|
||||
}
|
||||
if (ieee_exp <= 0) {
|
||||
return (uint64_t)sign << 63;
|
||||
}
|
||||
return ((uint64_t)sign << 63) |
|
||||
((uint64_t)ieee_exp << 52) |
|
||||
(frac & 0xFFFFFFFFFFFFFULL);
|
||||
}
|
||||
|
||||
double strtod(const char *s, char **endptr)
|
||||
{
|
||||
uint64_t bits = __cervus_strtod_bits(s, endptr);
|
||||
double result;
|
||||
__builtin_memcpy(&result, &bits, sizeof(double));
|
||||
return result;
|
||||
}
|
||||
|
||||
float strtof(const char *s, char **endptr)
|
||||
{
|
||||
return (float)strtod(s, endptr);
|
||||
}
|
||||
|
||||
long double strtold(const char *s, char **endptr)
|
||||
{
|
||||
return (long double)strtod(s, endptr);
|
||||
}
|
||||
|
||||
double atof(const char *s)
|
||||
{
|
||||
return strtod(s, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user