#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include template static inline ResultT __generic_div(ArgT a, ArgT b) { ResultT result; result.quot = a / b; result.rem = a % b; if (a >= 0 && result.rem < 0) { result.quot++; result.rem -= b; } return result; } extern "C" { int abs(int v) { return __builtin_abs(v); } long labs(long v) { return __builtin_labs(v); } long long llabs(long long v) { return __builtin_llabs(v); } div_t div(int num, int den) { return __generic_div(num, den); } ldiv_t ldiv(long num, long den) { return __generic_div(num, den); } lldiv_t lldiv(long long num, long long den) { return __generic_div(num, den); } int atoi(const char* s) { return (int)strtol(s, NULL, 10); } long atol(const char* s) { return strtol(s, NULL, 10); } // Assuming LP64, long long == long. long long atoll(const char* s) { return (long long)strtol(s, NULL, 10); } // These checks are only necessary on LLP64 platforms, where long won't match size_t/ssize_t. Probably redundant // then (since Luna follows the regular LP64 model), but oh well... long strtol(const char* str, char** endptr, int base) { isize rc = parse_signed_integer(str, const_cast(endptr), base); if (rc > (isize)LONG_MAX) return LONG_MAX; if (rc < (isize)LONG_MIN) return LONG_MIN; return rc; } unsigned long strtoul(const char* str, char** endptr, int base) { usize rc = parse_unsigned_integer(str, const_cast(endptr), base); if (rc > (usize)ULONG_MAX) return ULONG_MAX; return rc; } __noreturn void abort() { // First, try to unblock SIGABRT and then raise it. sigset_t set; sigemptyset(&set); sigaddset(&set, SIGABRT); sigprocmask(SIG_UNBLOCK, &set, nullptr); raise(SIGABRT); // Still here? The program must have catched it. Reset the disposition to default. struct sigaction act; act.sa_handler = SIG_DFL; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGABRT, &act, nullptr); raise(SIGABRT); __builtin_trap(); } __noreturn void _Exit(int status) { syscall(SYS_exit, status); __builtin_unreachable(); } size_t mbstowcs(wchar_t* buf, const char* src, size_t max) { if (max == 0) return 0; size_t result = (size_t)-1; Utf8StringDecoder decoder(src); if (!buf) { decoder.code_points().try_set_value_or_error(result, errno); return result; } decoder.decode(buf, max).try_set_value_or_error(result, errno); return result; } size_t wcstombs(char* buf, const wchar_t* src, size_t max) { if (max == 0) return 0; size_t result = (size_t)-1; Utf8StringEncoder encoder(src); if (!buf) { encoder.byte_length().try_set_value_or_error(result, errno); return result; } encoder.encode(buf, max).try_set_value_or_error(result, errno); return result; } void* malloc(size_t size) { return TRY_OR_SET_ERRNO(malloc_impl(size), void*, nullptr); } void* calloc(size_t nmemb, size_t size) { return TRY_OR_SET_ERRNO(calloc_impl(nmemb, size), void*, nullptr); } void* realloc(void* ptr, size_t size) { return TRY_OR_SET_ERRNO(realloc_impl(ptr, size), void*, nullptr); } void free(void* ptr) { free_impl(ptr); } int system(const char* cmd) { if (!cmd) { struct stat st; if (stat("/bin/sh", &st) < 0) return 0; return S_ISREG(st.st_mode); } pid_t child = fork(); if (child == 0) { execl("/bin/sh", "sh", "-c", cmd, NULL); _Exit(127); } if (child < 0) return -1; sigset_t set, oldset; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigprocmask(SIG_BLOCK, &set, &oldset); auto old_int = signal(SIGINT, SIG_IGN); auto old_quit = signal(SIGQUIT, SIG_IGN); int status; waitpid(child, &status, 0); sigprocmask(SIG_SETMASK, &oldset, nullptr); signal(SIGINT, old_int); signal(SIGQUIT, old_quit); return status; } void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) { c_quicksort(base, nmemb, size, compar); } static unsigned next = 42; int rand() { next = next * 1103515245 + 12345; return (int)((unsigned)(next / 65536) % 32768); } void srand(unsigned int seed) { next = seed; } static void generate_random_character(char* ptr) { constexpr const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"; *ptr = chars[rand() % (sizeof(chars) - 1)]; } static int check_template(char* _template, size_t* len) { *len = strlen(_template); if (*len < 6) { errno = EINVAL; return -1; } if (strncmp(_template + (*len - 6), "XXXXXX", 6)) { errno = EINVAL; return -1; } return 0; } static void generate_random_name(char* _template, const size_t* len) { size_t index = *len - 6; while (index < *len) generate_random_character(&_template[index++]); } char* mkdtemp(char* _template) { size_t len; if (check_template(_template, &len) < 0) return nullptr; while (true) { generate_random_name(_template, &len); if (mkdir(_template, 0700) == 0) return _template; if (errno != EEXIST) return nullptr; } } int mkstemp(char* _template) { size_t len; if (check_template(_template, &len) < 0) return -1; while (true) { generate_random_name(_template, &len); int fd; if ((fd = open(_template, O_RDWR | O_CREAT | O_EXCL, 0600)) >= 0) return fd; if (errno != EEXIST) return -1; } } double atof(const char* str) { return strtod(str, nullptr); } int posix_openpt(int flags) { return open("/dev/ptmx", flags); } int grantpt(int) { return 0; } int unlockpt(int) { return 0; } char* ptsname(int fd) { static char buffer[4096]; int index; if (ioctl(fd, TIOCGPTN, &index) < 0) return nullptr; snprintf(buffer, sizeof(buffer), "/dev/pts/%d", index); return buffer; } }