From 78ae0f154df54862c881d02079fc44261ade6130 Mon Sep 17 00:00:00 2001 From: boreddevnl Date: Sun, 19 Apr 2026 21:58:25 +0200 Subject: [PATCH] refactor(libc): move Lua an DOOM stubs into shared libc modules --- src/userland/Makefile | 2 +- .../cli/third_party/lua/boredos_stubs.h | 1026 ----------------- .../cli/third_party/lua/sysinclude/time.h | 5 + src/userland/games/doom/boredos_libc.c | 219 ---- src/userland/games/doom/boredos_libc.h | 22 +- src/userland/games/doom/hu_stuff.c | 38 +- src/userland/games/doom/i_system.c | 6 +- src/userland/games/doom/sys/stat.h | 16 +- src/userland/games/doom/sys/types.h | 9 +- src/userland/libc/ctype.c | 21 + src/userland/libc/ctype.h | 18 + src/userland/libc/errno.c | 3 + src/userland/libc/errno.h | 18 + src/userland/libc/fcntl.h | 15 + src/userland/libc/limits.h | 22 + src/userland/libc/locale.c | 19 + src/userland/libc/locale.h | 30 + src/userland/libc/math.h | 5 + src/userland/libc/math_ext.c | 91 ++ src/userland/libc/posix_fs.c | 53 + src/userland/libc/posix_io.c | 153 +++ src/userland/libc/runtime.c | 178 +++ src/userland/libc/setjmp.c | 38 + src/userland/libc/setjmp.h | 20 + src/userland/libc/signal.c | 15 + src/userland/libc/signal.h | 13 + src/userland/libc/stdio.c | 880 ++++++++++++++ src/userland/libc/stdio.h | 56 + src/userland/libc/stdlib.h | 9 + src/userland/libc/string.h | 11 + src/userland/libc/string_ext.c | 158 +++ src/userland/libc/sys/stat.h | 13 + src/userland/libc/sys/types.h | 8 + src/userland/libc/time.c | 166 +++ src/userland/libc/time.h | 30 + src/userland/libc/unistd.h | 22 + 36 files changed, 2145 insertions(+), 1263 deletions(-) delete mode 100644 src/userland/games/doom/boredos_libc.c create mode 100644 src/userland/libc/ctype.c create mode 100644 src/userland/libc/ctype.h create mode 100644 src/userland/libc/errno.c create mode 100644 src/userland/libc/errno.h create mode 100644 src/userland/libc/fcntl.h create mode 100644 src/userland/libc/limits.h create mode 100644 src/userland/libc/locale.c create mode 100644 src/userland/libc/locale.h create mode 100644 src/userland/libc/math_ext.c create mode 100644 src/userland/libc/posix_fs.c create mode 100644 src/userland/libc/posix_io.c create mode 100644 src/userland/libc/runtime.c create mode 100644 src/userland/libc/setjmp.c create mode 100644 src/userland/libc/setjmp.h create mode 100644 src/userland/libc/signal.c create mode 100644 src/userland/libc/signal.h create mode 100644 src/userland/libc/stdio.c create mode 100644 src/userland/libc/stdio.h create mode 100644 src/userland/libc/string_ext.c create mode 100644 src/userland/libc/sys/stat.h create mode 100644 src/userland/libc/sys/types.h create mode 100644 src/userland/libc/time.c create mode 100644 src/userland/libc/time.h create mode 100644 src/userland/libc/unistd.h diff --git a/src/userland/Makefile b/src/userland/Makefile index a3d4207..6e2f2fa 100644 --- a/src/userland/Makefile +++ b/src/userland/Makefile @@ -59,7 +59,7 @@ $(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/stb_i $(LD) $(LDFLAGS) $^ -o $@ $(BIN_DIR)/%.o: games/doom/%.c | $(BIN_DIR) - $(CC) $(CFLAGS) -Wno-error -Igames/doom -c $< -o $@ + $(CC) $(CFLAGS) -Wno-error -DBOREDOS -Igames/doom -c $< -o $@ $(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/stb_image.o $(LD) $(LDFLAGS) $^ -o $@ diff --git a/src/userland/cli/third_party/lua/boredos_stubs.h b/src/userland/cli/third_party/lua/boredos_stubs.h index d78767a..3b44cea 100644 --- a/src/userland/cli/third_party/lua/boredos_stubs.h +++ b/src/userland/cli/third_party/lua/boredos_stubs.h @@ -1,1033 +1,7 @@ #ifndef BOREDOS_LUA_STUBS_H #define BOREDOS_LUA_STUBS_H -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include - -#include "stdlib.h" -#include "string.h" #include "syscall.h" -#include "math.h" - -int errno = 0; - -static FILE boredos_stdin_obj = {0, 0, 0, 0, 0}; -static FILE boredos_stdout_obj = {1, 0, 0, 0, 0}; -static FILE boredos_stderr_obj = {2, 0, 0, 0, 0}; -FILE *stdin = &boredos_stdin_obj; -FILE *stdout = &boredos_stdout_obj; -FILE *stderr = &boredos_stderr_obj; - -static int _b_is_leap(int year) { - return ((year % 4) == 0 && (year % 100) != 0) || ((year % 400) == 0); -} - -static int _b_days_in_month(int year, int month) { - static const int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - if (month == 1 && _b_is_leap(year)) { - return 29; - } - return mdays[month]; -} - -static long long _b_days_before_year(int year) { - long long y = (long long)year - 1; - return y * 365 + y / 4 - y / 100 + y / 400; -} - -static long long _b_days_since_epoch(int year, int month, int day) { - long long days = _b_days_before_year(year) - _b_days_before_year(1970); - int m; - for (m = 0; m < month - 1; m++) { - days += _b_days_in_month(year, m); - } - days += (day - 1); - return days; -} - -static void _b_civil_from_days(long long z, int *year, int *month, int *day) { - z += 719468; - long long era = (z >= 0 ? z : z - 146096) / 146097; - unsigned doe = (unsigned)(z - era * 146097); - unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; - int y = (int)yoe + (int)era * 400; - unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); - unsigned mp = (5 * doy + 2) / 153; - unsigned d = doy - (153 * mp + 2) / 5 + 1; - unsigned m = mp + (mp < 10 ? 3 : (unsigned)-9); - y += (m <= 2); - *year = y; - *month = (int)m; - *day = (int)d; -} - -int setjmp(jmp_buf env) { - __asm__ volatile( - "movq %%rbx, 0(%0)\n\t" - "movq %%rbp, 8(%0)\n\t" - "movq %%r12, 16(%0)\n\t" - "movq %%r13, 24(%0)\n\t" - "movq %%r14, 32(%0)\n\t" - "movq %%r15, 40(%0)\n\t" - "leaq 8(%%rsp), %%rax\n\t" - "movq %%rax, 48(%0)\n\t" - "movq (%%rsp), %%rax\n\t" - "movq %%rax, 56(%0)\n\t" - : - : "r"(env) - : "rax", "memory"); - return 0; -} - -void longjmp(jmp_buf env, int val) { - int r = (val == 0) ? 1 : val; - __asm__ volatile( - "movq 0(%0), %%rbx\n\t" - "movq 8(%0), %%rbp\n\t" - "movq 16(%0), %%r12\n\t" - "movq 24(%0), %%r13\n\t" - "movq 32(%0), %%r14\n\t" - "movq 40(%0), %%r15\n\t" - "movq 48(%0), %%rsp\n\t" - "movl %1, %%eax\n\t" - "movq 56(%0), %%rdx\n\t" - "jmp *%%rdx\n\t" - : - : "r"(env), "r"(r) - : "rax", "rdx", "memory"); - __builtin_unreachable(); -} - -FILE *fopen(const char *path, const char *mode) { - int fd = sys_open(path, mode); - FILE *f; - if (fd < 0) { - errno = EINVAL; - return NULL; - } - f = (FILE *)malloc(sizeof(FILE)); - if (!f) { - sys_close(fd); - errno = ERANGE; - return NULL; - } - f->fd = fd; - f->eof = 0; - f->err = 0; - f->has_ungetc = 0; - f->ungetc_char = 0; - return f; -} - -FILE *freopen(const char *path, const char *mode, FILE *stream) { - int fd; - if (!stream) { - return fopen(path, mode); - } - if (stream->fd >= 0) { - sys_close(stream->fd); - } - fd = sys_open(path, mode); - if (fd < 0) { - stream->err = 1; - errno = EINVAL; - return NULL; - } - stream->fd = fd; - stream->eof = 0; - stream->err = 0; - stream->has_ungetc = 0; - return stream; -} - -int fclose(FILE *stream) { - if (!stream) { - return EOF; - } - if (stream != stdin && stream != stdout && stream != stderr) { - if (stream->fd >= 0) { - sys_close(stream->fd); - } - free(stream); - } - return 0; -} - -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { - size_t total; - int n; - if (!stream || !ptr || size == 0 || nmemb == 0) { - return 0; - } - total = size * nmemb; - n = sys_read(stream->fd, ptr, (uint32_t)total); - if (n <= 0) { - if (n == 0) { - stream->eof = 1; - } else { - stream->err = 1; - } - return 0; - } - if ((size_t)n < total) { - stream->eof = 1; - } - return (size_t)n / size; -} - -size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - size_t total; - int n; - if (!stream || !ptr || size == 0 || nmemb == 0) { - return 0; - } - total = size * nmemb; - if (stream->fd <= 2) { - n = sys_write(stream->fd, (const char *)ptr, (int)total); - } else { - n = sys_write_fs(stream->fd, ptr, (uint32_t)total); - } - if (n < 0) { - stream->err = 1; - return 0; - } - return (size_t)n / size; -} - -int fseek(FILE *stream, long offset, int whence) { - if (!stream) { - return -1; - } - if (sys_seek(stream->fd, (int)offset, whence) < 0) { - stream->err = 1; - return -1; - } - stream->eof = 0; - stream->has_ungetc = 0; - return 0; -} - -long ftell(FILE *stream) { - if (!stream) { - return -1; - } - return (long)sys_tell(stream->fd); -} - -int getc(FILE *stream) { - unsigned char ch; - int n; - if (!stream) { - return EOF; - } - if (stream->has_ungetc) { - stream->has_ungetc = 0; - return stream->ungetc_char; - } - n = sys_read(stream->fd, &ch, 1); - if (n <= 0) { - if (n == 0) { - stream->eof = 1; - } else { - stream->err = 1; - } - return EOF; - } - return (int)ch; -} - -int ungetc(int c, FILE *stream) { - if (!stream || c == EOF) { - return EOF; - } - stream->has_ungetc = 1; - stream->ungetc_char = (unsigned char)c; - stream->eof = 0; - return c; -} - -char *fgets(char *s, int n, FILE *stream) { - int i; - if (!s || n <= 0 || !stream) { - return NULL; - } - for (i = 0; i < n - 1; i++) { - int c = getc(stream); - if (c == EOF) { - break; - } - s[i] = (char)c; - if (c == '\n') { - i++; - break; - } - } - if (i == 0) { - return NULL; - } - s[i] = '\0'; - return s; -} - -int fputs(const char *s, FILE *stream) { - size_t len; - size_t written; - if (!s || !stream) { - return EOF; - } - len = strlen(s); - written = fwrite(s, 1, len, stream); - return (written == len) ? (int)len : EOF; -} - -int feof(FILE *stream) { - return stream ? stream->eof : 1; -} - -int ferror(FILE *stream) { - return stream ? stream->err : 1; -} - -void clearerr(FILE *stream) { - if (stream) { - stream->eof = 0; - stream->err = 0; - } -} - -int fflush(FILE *stream) { - (void)stream; - return 0; -} - -int remove(const char *path) { - return sys_delete(path); -} - -int rename(const char *oldpath, const char *newpath) { - (void)oldpath; - (void)newpath; - errno = EINVAL; - return -1; -} - -FILE *tmpfile(void) { - errno = EINVAL; - return NULL; -} - -char *tmpnam(char *s) { - (void)s; - errno = EINVAL; - return NULL; -} - -int isdigit(int c) { return (c >= '0' && c <= '9'); } -int isalpha(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); } -int isalnum(int c) { return isalpha(c) || isdigit(c); } -int isspace(int c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; -} -int isupper(int c) { return (c >= 'A' && c <= 'Z'); } -int islower(int c) { return (c >= 'a' && c <= 'z'); } -int isxdigit(int c) { - return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); -} -int iscntrl(int c) { return ((c >= 0 && c < 32) || c == 127); } -int ispunct(int c) { - return isprint(c) && !isalnum(c) && !isspace(c); -} -int isprint(int c) { return (c >= 32 && c < 127); } -int isgraph(int c) { return (c > 32 && c < 127); } -int tolower(int c) { return isupper(c) ? (c - 'A' + 'a') : c; } -int toupper(int c) { return islower(c) ? (c - 'a' + 'A') : c; } - -int abs(int x) { - return (x < 0) ? -x : x; -} - -int strncmp(const char *s1, const char *s2, size_t n) { - size_t i; - for (i = 0; i < n; i++) { - unsigned char c1 = (unsigned char)s1[i]; - unsigned char c2 = (unsigned char)s2[i]; - if (c1 != c2) { - return (int)c1 - (int)c2; - } - if (c1 == '\0') { - return 0; - } - } - return 0; -} - -char *strncpy(char *dest, const char *src, size_t n) { - size_t i; - for (i = 0; i < n && src[i] != '\0'; i++) { - dest[i] = src[i]; - } - for (; i < n; i++) { - dest[i] = '\0'; - } - return dest; -} - -char *strncat(char *dest, const char *src, size_t n) { - size_t dlen = strlen(dest); - size_t i; - for (i = 0; i < n && src[i] != '\0'; i++) { - dest[dlen + i] = src[i]; - } - dest[dlen + i] = '\0'; - return dest; -} - -char *strrchr(const char *s, int c) { - const char *last = NULL; - for (;; s++) { - if (*s == (char)c) { - last = s; - } - if (*s == '\0') { - break; - } - } - return (char *)last; -} - -char *strpbrk(const char *s, const char *accept) { - for (; *s; s++) { - const char *a; - for (a = accept; *a; a++) { - if (*s == *a) { - return (char *)s; - } - } - } - return NULL; -} - -size_t strspn(const char *s, const char *accept) { - size_t n = 0; - while (*s) { - if (!strchr(accept, *s)) { - break; - } - n++; - s++; - } - return n; -} - -size_t strcspn(const char *s, const char *reject) { - size_t n = 0; - while (*s) { - if (strchr(reject, *s)) { - break; - } - n++; - s++; - } - return n; -} - -void *memchr(const void *s, int c, size_t n) { - const unsigned char *p = (const unsigned char *)s; - size_t i; - for (i = 0; i < n; i++) { - if (p[i] == (unsigned char)c) { - return (void *)(p + i); - } - } - return NULL; -} - -int strcoll(const char *s1, const char *s2) { - return strcmp(s1, s2); -} - -char *strerror(int errnum) { - switch (errnum) { - case 0: return "no error"; - case EDOM: return "domain error"; - case ERANGE: return "range error"; - case EINVAL: return "invalid argument"; - default: return "unknown error"; - } -} - -static int _b_hex_digit(unsigned value, int upper) { - if (value < 10U) { - return (int)('0' + value); - } - return (int)((upper ? 'A' : 'a') + (value - 10U)); -} - -static void _b_append_char(char *out, size_t cap, size_t *idx, int c) { - if (*idx + 1 < cap) { - out[*idx] = (char)c; - } - (*idx)++; -} - -static void _b_append_strn(char *out, size_t cap, size_t *idx, const char *s, size_t n) { - size_t i; - for (i = 0; i < n; i++) { - _b_append_char(out, cap, idx, s[i]); - } -} - -static void _b_utoa(unsigned long long v, unsigned base, int upper, char *buf, size_t *len) { - char tmp[64]; - size_t i = 0; - if (v == 0) { - tmp[i++] = '0'; - } else { - while (v && i < sizeof(tmp)) { - tmp[i++] = (char)_b_hex_digit((unsigned)(v % base), upper); - v /= base; - } - } - *len = i; - while (i > 0) { - *buf++ = tmp[--i]; - } -} - -static void _b_itoa(long long v, char *buf, size_t *len) { - unsigned long long uv; - size_t n = 0; - if (v < 0) { - *buf++ = '-'; - n++; - uv = (unsigned long long)(-(v + 1)) + 1ULL; - } else { - uv = (unsigned long long)v; - } - _b_utoa(uv, 10U, 0, buf, len); - *len += n; -} - -static void _b_ftoa(double d, int precision, char *buf, size_t *len) { - long long ip; - double frac; - size_t n = 0; - if (precision < 0) { - precision = 6; - } - if (d < 0.0) { - buf[n++] = '-'; - d = -d; - } - ip = (long long)d; - frac = d - (double)ip; - { - char ibuf[64]; - size_t ilen = 0; - _b_utoa((unsigned long long)ip, 10U, 0, ibuf, &ilen); - memcpy(buf + n, ibuf, ilen); - n += ilen; - } - if (precision > 0) { - int i; - buf[n++] = '.'; - for (i = 0; i < precision; i++) { - int digit; - frac *= 10.0; - digit = (int)frac; - if (digit < 0) digit = 0; - if (digit > 9) digit = 9; - buf[n++] = (char)('0' + digit); - frac -= (double)digit; - } - } - *len = n; -} - -int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) { - size_t out_i = 0; - while (*fmt) { - if (*fmt != '%') { - _b_append_char(str, size, &out_i, *fmt++); - continue; - } - - fmt++; - if (*fmt == '%') { - _b_append_char(str, size, &out_i, '%'); - fmt++; - continue; - } - - while (*fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#' || *fmt == '0') { - fmt++; - } - - if (*fmt == '*') { - (void)va_arg(ap, int); - fmt++; - } else { - while (isdigit((unsigned char)*fmt)) { - fmt++; - } - } - - { - int precision = -1; - if (*fmt == '.') { - fmt++; - precision = 0; - if (*fmt == '*') { - precision = va_arg(ap, int); - fmt++; - } else { - while (isdigit((unsigned char)*fmt)) { - precision = precision * 10 + (*fmt - '0'); - fmt++; - } - } - } - - int lcount = 0; - while (*fmt == 'l') { - lcount++; - fmt++; - } - - switch (*fmt) { - case 'd': - case 'i': { - long long v; - char nbuf[64]; - size_t nlen = 0; - if (lcount >= 2) v = va_arg(ap, long long); - else if (lcount == 1) v = va_arg(ap, long); - else v = va_arg(ap, int); - _b_itoa(v, nbuf, &nlen); - _b_append_strn(str, size, &out_i, nbuf, nlen); - break; - } - case 'u': - case 'x': - case 'X': - case 'o': { - unsigned long long v; - unsigned base = (*fmt == 'o') ? 8U : ((*fmt == 'u') ? 10U : 16U); - char nbuf[64]; - size_t nlen = 0; - int upper = (*fmt == 'X'); - if (lcount >= 2) v = va_arg(ap, unsigned long long); - else if (lcount == 1) v = va_arg(ap, unsigned long); - else v = va_arg(ap, unsigned int); - _b_utoa(v, base, upper, nbuf, &nlen); - _b_append_strn(str, size, &out_i, nbuf, nlen); - break; - } - case 'c': { - int c = va_arg(ap, int); - _b_append_char(str, size, &out_i, c); - break; - } - case 's': { - const char *s = va_arg(ap, const char *); - size_t slen; - if (!s) s = "(null)"; - slen = strlen(s); - if (precision >= 0 && (size_t)precision < slen) { - slen = (size_t)precision; - } - _b_append_strn(str, size, &out_i, s, slen); - break; - } - case 'p': { - uintptr_t v = (uintptr_t)va_arg(ap, void *); - char nbuf[32]; - size_t nlen = 0; - _b_append_strn(str, size, &out_i, "0x", 2); - _b_utoa((unsigned long long)v, 16U, 0, nbuf, &nlen); - _b_append_strn(str, size, &out_i, nbuf, nlen); - break; - } - case 'f': - case 'g': - case 'e': { - double v = va_arg(ap, double); - char nbuf[96]; - size_t nlen = 0; - _b_ftoa(v, precision, nbuf, &nlen); - _b_append_strn(str, size, &out_i, nbuf, nlen); - break; - } - default: - _b_append_char(str, size, &out_i, '%'); - _b_append_char(str, size, &out_i, *fmt); - break; - } - } - if (*fmt) { - fmt++; - } - } - - if (size > 0) { - size_t term = (out_i < size - 1) ? out_i : (size - 1); - str[term] = '\0'; - } - return (int)out_i; -} - -int snprintf(char *str, size_t size, const char *fmt, ...) { - int n; - va_list ap; - va_start(ap, fmt); - n = vsnprintf(str, size, fmt, ap); - va_end(ap); - return n; -} - -int sprintf(char *str, const char *fmt, ...) { - int n; - va_list ap; - va_start(ap, fmt); - n = vsnprintf(str, (size_t)-1, fmt, ap); - va_end(ap); - return n; -} - -int fprintf(FILE *stream, const char *fmt, ...) { - char buf[1024]; - int len; - va_list ap; - va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - if (len <= 0) { - return len; - } - if ((size_t)len > sizeof(buf)) { - len = (int)sizeof(buf); - } - if (fwrite(buf, 1, (size_t)len, stream) == 0) { - return -1; - } - return len; -} - -int sscanf(const char *str, const char *fmt, ...) { - (void)str; - (void)fmt; - return 0; -} - -double ldexp(double x, int expn) { - double v = x; - int i; - if (expn >= 0) { - for (i = 0; i < expn; i++) { - v *= 2.0; - } - } else { - for (i = 0; i < -expn; i++) { - v *= 0.5; - } - } - return v; -} - -double frexp(double x, int *expn) { - int e = 0; - double v = x; - if (x == 0.0) { - *expn = 0; - return 0.0; - } - while (fabs(v) >= 1.0) { - v *= 0.5; - e++; - } - while (fabs(v) > 0.0 && fabs(v) < 0.5) { - v *= 2.0; - e--; - } - *expn = e; - return v; -} - -static double _b_atan_series(double x) { - double x2 = x * x; - double term = x; - double sum = x; - for (int n = 3; n <= 23; n += 2) { - term *= -x2; - sum += term / (double)n; - } - return sum; -} - -static double _b_atan_precise(double x) { - if (x < 0.0) { - return -_b_atan_precise(-x); - } - if (x > 1.0) { - return (M_PI / 2.0) - _b_atan_precise(1.0 / x); - } - if (x > 0.5) { - double y = (x - 1.0) / (x + 1.0); - return (M_PI / 4.0) + _b_atan_series(y); - } - return _b_atan_series(x); -} - -double atan2(double y, double x) { - if (x > 0.0) { - return _b_atan_precise(y / x); - } - if (x < 0.0) { - if (y >= 0.0) return _b_atan_precise(y / x) + M_PI; - return _b_atan_precise(y / x) - M_PI; - } - if (y > 0.0) return M_PI / 2.0; - if (y < 0.0) return -M_PI / 2.0; - return 0.0; -} - -double asin(double x) { - if (x > 1.0 || x < -1.0) { - errno = EDOM; - return 0.0; - } - return atan2(x, sqrt(1.0 - x * x)); -} - -double acos(double x) { - if (x > 1.0 || x < -1.0) { - errno = EDOM; - return 0.0; - } - return M_PI / 2.0 - asin(x); -} - -static time_t _b_seconds_from_ymdhms(int year, int month, int day, int hour, int minute, int second) { - long long days = _b_days_since_epoch(year, month, day); - return (time_t)(days * 86400LL + hour * 3600LL + minute * 60LL + second); -} - -static void _b_fill_tm_from_epoch(time_t t, struct tm *out) { - long long sec = (long long)t; - long long days; - int sod; - int year, month, day; - - if (sec < 0) { - long long d = ((-sec) + 86399LL) / 86400LL; - sec += d * 86400LL; - } - - days = sec / 86400LL; - sod = (int)(sec % 86400LL); - if (sod < 0) { - sod += 86400; - days--; - } - - _b_civil_from_days(days, &year, &month, &day); - - out->tm_year = year - 1900; - out->tm_mon = month - 1; - out->tm_mday = day; - out->tm_hour = sod / 3600; - out->tm_min = (sod % 3600) / 60; - out->tm_sec = sod % 60; - out->tm_wday = (int)((days + 4) % 7); - if (out->tm_wday < 0) out->tm_wday += 7; - - { - long long jan1 = _b_days_since_epoch(year, 1, 1); - out->tm_yday = (int)(days - jan1); - } - out->tm_isdst = 0; -} - -time_t time(time_t *out) { - int dt[6] = {1970, 1, 1, 0, 0, 0}; - time_t t; - if (sys_system(SYSTEM_CMD_RTC_GET, 0, (uint64_t)dt, 0, 0) != 0) { - t = 0; - } else { - t = _b_seconds_from_ymdhms(dt[0], dt[1], dt[2], dt[3], dt[4], dt[5]); - } - if (out) { - *out = t; - } - return t; -} - -clock_t clock(void) { - static uint64_t start_tsc = 0; - unsigned int lo; - unsigned int hi; - uint64_t now_tsc; - - __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); - now_tsc = ((uint64_t)hi << 32) | (uint64_t)lo; - - if (start_tsc == 0) { - start_tsc = now_tsc; - __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); - now_tsc = ((uint64_t)hi << 32) | (uint64_t)lo; - } - - return (clock_t)(now_tsc - start_tsc); -} - -struct tm *gmtime(const time_t *timer) { - static struct tm tmv; - if (!timer) { - return NULL; - } - _b_fill_tm_from_epoch(*timer, &tmv); - return &tmv; -} - -struct tm *localtime(const time_t *timer) { - return gmtime(timer); -} - -size_t strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { - (void)fmt; - if (!s || max == 0 || !tm) { - return 0; - } - { - int n = snprintf(s, max, "%04d-%02d-%02d %02d:%02d:%02d", - tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - if (n < 0 || (size_t)n >= max) { - if (max > 0) s[0] = '\0'; - return 0; - } - return (size_t)n; - } -} - -time_t mktime(struct tm *tm) { - if (!tm) { - return (time_t)-1; - } - return _b_seconds_from_ymdhms( - tm->tm_year + 1900, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_hour, - tm->tm_min, - tm->tm_sec); -} - -static struct lconv _b_lconv = { - ".", "", "", "", "", ".", "", "", "", "", - 0, 0, 0, 0, 0, 0, 0, 0 -}; - -char *setlocale(int category, const char *locale) { - (void)category; - if (locale == NULL || strcmp(locale, "C") == 0 || strcmp(locale, "") == 0) { - return "C"; - } - return NULL; -} - -struct lconv *localeconv(void) { - return &_b_lconv; -} - -sighandler_t signal(int sig, sighandler_t handler) { - (void)sig; - return handler; -} - -int system(const char *command) { - (void)command; - errno = EINVAL; - return -1; -} - -char *getenv(const char *name) { - (void)name; - return NULL; -} - -void abort(void) { - sys_exit(1); - while (1) {} -} - -double strtod(const char *nptr, char **endptr) { - const char *p = nptr; - int sign = 1; - double value = 0.0; - double frac = 0.0; - double scale = 1.0; - int exp_sign = 1; - int exp_val = 0; - - while (isspace((unsigned char)*p)) p++; - - if (*p == '-') { - sign = -1; - p++; - } else if (*p == '+') { - p++; - } - - while (isdigit((unsigned char)*p)) { - value = value * 10.0 + (double)(*p - '0'); - p++; - } - - if (*p == '.') { - p++; - while (isdigit((unsigned char)*p)) { - frac = frac * 10.0 + (double)(*p - '0'); - scale *= 10.0; - p++; - } - value += frac / scale; - } - - if (*p == 'e' || *p == 'E') { - const char *ep = p + 1; - if (*ep == '-') { - exp_sign = -1; - ep++; - } else if (*ep == '+') { - ep++; - } - if (isdigit((unsigned char)*ep)) { - p = ep; - while (isdigit((unsigned char)*p)) { - exp_val = exp_val * 10 + (*p - '0'); - p++; - } - } - } - - if (endptr) { - *endptr = (char *)p; - } - - if (exp_val != 0) { - value = ldexp(value, exp_sign * exp_val); - } - return sign * value; -} #endif diff --git a/src/userland/cli/third_party/lua/sysinclude/time.h b/src/userland/cli/third_party/lua/sysinclude/time.h index 8fb30c3..69d4123 100644 --- a/src/userland/cli/third_party/lua/sysinclude/time.h +++ b/src/userland/cli/third_party/lua/sysinclude/time.h @@ -3,6 +3,9 @@ #include +#ifndef BOREDOS_LIBC_TIME_H +#define BOREDOS_LIBC_TIME_H + typedef long long time_t; typedef unsigned long long clock_t; @@ -28,3 +31,5 @@ size_t strftime(char *s, size_t max, const char *fmt, const struct tm *tm); time_t mktime(struct tm *tm); #endif + +#endif diff --git a/src/userland/games/doom/boredos_libc.c b/src/userland/games/doom/boredos_libc.c deleted file mode 100644 index 165bd0f..0000000 --- a/src/userland/games/doom/boredos_libc.c +++ /dev/null @@ -1,219 +0,0 @@ -#include "boredos_libc.h" -#include - -int errno = 0; - -static FILE _stderr = {2, 0, 0}; -static FILE _stdout = {1, 0, 0}; -static FILE _stdin = {0, 0, 0}; - -FILE* stderr = &_stderr; -FILE* stdout = &_stdout; -FILE* stdin = &_stdin; - -FILE *fopen(const char *path, const char *mode) { - int fd = sys_open(path, mode); - if (fd < 0) return NULL; - FILE *f = malloc(sizeof(FILE)); - f->fd = fd; - f->eof = 0; - f->error = 0; - return f; -} - -int fclose(FILE *stream) { - if (!stream) return EOF; - if (stream != stderr && stream != stdout && stream != stdin) { - sys_close(stream->fd); - free(stream); - } - return 0; -} - -size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { - if (!stream) return 0; - int bytes = sys_read(stream->fd, ptr, size * nmemb); - if (bytes < 0) { - stream->error = 1; - return 0; - } - if (bytes == 0) stream->eof = 1; - return bytes / size; -} - -size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - if (!stream) return 0; - if (stream == stdout || stream == stderr) { - sys_write(stream->fd, ptr, size * nmemb); - return nmemb; - } - int bytes = sys_write_fs(stream->fd, ptr, size * nmemb); - if (bytes < 0) { - stream->error = 1; - return 0; - } - return bytes / size; -} - -int fseek(FILE *stream, long offset, int whence) { - if (!stream) return -1; - stream->eof = 0; - return sys_seek(stream->fd, offset, whence); -} - -long ftell(FILE *stream) { - if (!stream) return -1; - return sys_tell(stream->fd); -} - -int remove(const char *pathname) { - return sys_delete(pathname); -} - -int rename(const char *oldpath, const char *newpath) { - return -1; -} - -int fputc(int c, FILE *stream) { - unsigned char ch = c; - if (fwrite(&ch, 1, 1, stream) != 1) return EOF; - return ch; -} - -int fputs(const char *s, FILE *stream) { - size_t len = strlen(s); - if (fwrite(s, 1, len, stream) != len) return EOF; - return 0; -} - -long filelength(FILE *f) { - if (!f) return -1; - return sys_size(f->fd); -} - -int mkdir(const char *pathname, int mode) { - return sys_mkdir(pathname); -} - -int access(const char *pathname, int mode) { - if (sys_exists(pathname)) return 0; - return -1; -} - -int stat(const char *pathname, struct stat *statbuf) { - if (sys_exists(pathname)) { - if (statbuf) { - statbuf->st_size = 0; - statbuf->st_mode = 0; - } - return 0; - } - return -1; -} - -int strncasecmp(const char *s1, const char *s2, size_t n) { - while (n--) { - char c1 = tolower(*s1++); - char c2 = tolower(*s2++); - if (c1 != c2) return c1 - c2; - if (!c1) break; - } - return 0; -} -int strcasecmp(const char *s1, const char *s2) { - while (1) { - char c1 = tolower(*s1++); - char c2 = tolower(*s2++); - if (c1 != c2) return c1 - c2; - if (!c1) break; - } - return 0; -} -char *strncpy(char *dest, const char *src, size_t n) { - char *ret = dest; - while (n && *src) { *dest++ = *src++; n--; } - while (n) { *dest++ = 0; n--; } - return ret; -} -int strncmp(const char *s1, const char *s2, size_t n) { - while (n--) { - if (*s1 != *s2) return *s1 - *s2; - if (!*s1) break; - s1++; s2++; - } - return 0; -} -char *strrchr(const char *s, int c) { - const char *last = NULL; - while (*s) { if (*s == c) last = s; s++; } - if (c == 0) last = s; - return (char*)last; -} -char *strdup(const char *s) { - size_t len = strlen(s) + 1; - char *dup = malloc(len); - if (dup) memcpy(dup, s, len); - return dup; -} - -int toupper(int c) { return (c >= 'a' && c <= 'z') ? c - 32 : c; } -int tolower(int c) { return (c >= 'A' && c <= 'Z') ? c + 32 : c; } -int isspace(int c) { return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\v' || c == '\f'; } -int isdigit(int c) { return c >= '0' && c <= '9'; } -int isprint(int c) { return c >= 32 && c <= 126; } -int isalpha(int c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -int isalnum(int c) { return isalpha(c) || isdigit(c); } -int isgraph(int c) { return c > 32 && c <= 126; } -int ispunct(int c) { return isprint(c) && !isspace(c) && !isalnum(c); } -int isupper(int c) { return c >= 'A' && c <= 'Z'; } - -void _exit(int status) { - exit(status); -} - - - -int fflush(FILE *stream) { return 0; } -int abs(int x) { return x < 0 ? -x : x; } -int putchar(int c) { return fputc(c, stdout); } -int system(const char *command) { return -1; } -#define STB_SPRINTF_IMPLEMENTATION -#define STB_SPRINTF_NOFLOAT -#include "stb_sprintf.h" - -int vfprintf(FILE *stream, const char *format, va_list ap) { - char buf[1024]; - int len = stbsp_vsnprintf(buf, sizeof(buf), format, ap); - if (len > 0) fwrite(buf, 1, len, stream); - return len; -} - -int fprintf(FILE *stream, const char *format, ...) { - va_list ap; - va_start(ap, format); - int len = vfprintf(stream, format, ap); - va_end(ap); - return len; -} - -int sprintf(char *str, const char *format, ...) { - va_list ap; - va_start(ap, format); - int len = stbsp_vsprintf(str, format, ap); - va_end(ap); - return len; -} - -int snprintf(char *str, size_t size, const char *format, ...) { - va_list ap; - va_start(ap, format); - int len = stbsp_vsnprintf(str, size, format, ap); - va_end(ap); - return len; -} - -int vsnprintf(char *str, size_t size, const char *format, va_list ap) { - return stbsp_vsnprintf(str, size, format, ap); -} - -int sscanf(const char *str, const char *format, ...) { return 0; } diff --git a/src/userland/games/doom/boredos_libc.h b/src/userland/games/doom/boredos_libc.h index ff63838..46e428d 100644 --- a/src/userland/games/doom/boredos_libc.h +++ b/src/userland/games/doom/boredos_libc.h @@ -5,6 +5,9 @@ #include #include #include +#include +#include +#include #define SEEK_SET 0 #define SEEK_CUR 1 @@ -12,12 +15,6 @@ #define EOF (-1) -typedef struct { - int fd; - int eof; - int error; -} FILE; - extern FILE* stderr; extern FILE* stdout; extern FILE* stdin; @@ -34,6 +31,14 @@ extern FILE* stdin; #define W_OK 2 #define X_OK 1 +int open(const char *pathname, int flags, ...); +int close(int fd); +ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); +off_t lseek(int fd, off_t offset, int whence); +int unlink(const char *pathname); +int isatty(int fd); + FILE *fopen(const char *path, const char *mode); int fclose(FILE *stream); size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); @@ -73,11 +78,6 @@ int isupper(int c); int mkdir(const char *pathname, int mode); int access(const char *pathname, int mode); - -struct stat { - int st_size; - int st_mode; -}; int stat(const char *pathname, struct stat *statbuf); char *strstr(const char *haystack, const char *needle); diff --git a/src/userland/games/doom/hu_stuff.c b/src/userland/games/doom/hu_stuff.c index b63cac7..253e4c7 100644 --- a/src/userland/games/doom/hu_stuff.c +++ b/src/userland/games/doom/hu_stuff.c @@ -25,6 +25,7 @@ #include "deh_main.h" #include "i_swap.h" +#include "i_system.h" #include "i_video.h" #include "hu_stuff.h" @@ -288,14 +289,47 @@ void HU_Init(void) int i; int j; + int fallback_lump = -1; char buffer[9]; // load the heads-up font j = HU_FONTSTART; for (i=0;i= 0) + { + break; + } + } + + if (fallback_lump < 0) + { + fallback_lump = W_CheckNumForName("STTNUM0"); + } + } + + if (lump < 0) + { + lump = fallback_lump; + } + + if (lump < 0) + { + I_Error("HU_Init: no usable HUD font lumps (missing STCFNxxx/STTNUM0)"); + } + + hu_font[i] = (patch_t *) W_CacheLumpNum(lump, PU_STATIC); } } diff --git a/src/userland/games/doom/i_system.c b/src/userland/games/doom/i_system.c index 53ab2c9..adfa390 100644 --- a/src/userland/games/doom/i_system.c +++ b/src/userland/games/doom/i_system.c @@ -264,7 +264,7 @@ void I_Quit (void) #endif } -#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) +#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) && !defined(BOREDOS) #define ZENITY_BINARY "/usr/bin/zenity" // returns non-zero if zenity is available @@ -347,7 +347,7 @@ static int ZenityErrorBox(char *message) return result; } -#endif /* !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) */ +#endif /* !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) && !defined(BOREDOS) */ // @@ -456,7 +456,9 @@ void I_Error (char *error, ...) #else { +#if !defined(BOREDOS) ZenityErrorBox(msgbuf); +#endif } #endif diff --git a/src/userland/games/doom/sys/stat.h b/src/userland/games/doom/sys/stat.h index 9300dee..73aacfe 100644 --- a/src/userland/games/doom/sys/stat.h +++ b/src/userland/games/doom/sys/stat.h @@ -1 +1,15 @@ -#include "../boredos_libc.h" +#ifndef DOOM_COMPAT_SYS_STAT_H +#define DOOM_COMPAT_SYS_STAT_H + +#include "types.h" + +struct stat { + int st_size; + int st_mode; +}; + +int stat(const char *pathname, struct stat *statbuf); +int fstat(int fd, struct stat *statbuf); +int mkdir(const char *pathname, int mode); + +#endif diff --git a/src/userland/games/doom/sys/types.h b/src/userland/games/doom/sys/types.h index 9300dee..0cdc230 100644 --- a/src/userland/games/doom/sys/types.h +++ b/src/userland/games/doom/sys/types.h @@ -1 +1,8 @@ -#include "../boredos_libc.h" +#ifndef DOOM_COMPAT_SYS_TYPES_H +#define DOOM_COMPAT_SYS_TYPES_H + +typedef long ssize_t; +typedef long off_t; +typedef unsigned int mode_t; + +#endif diff --git a/src/userland/libc/ctype.c b/src/userland/libc/ctype.c new file mode 100644 index 0000000..7783d36 --- /dev/null +++ b/src/userland/libc/ctype.c @@ -0,0 +1,21 @@ +#include "ctype.h" + +__attribute__((weak)) int isdigit(int c) { return (c >= '0' && c <= '9'); } +__attribute__((weak)) int isalpha(int c) { return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); } +__attribute__((weak)) int isalnum(int c) { return isalpha(c) || isdigit(c); } +__attribute__((weak)) int isspace(int c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; +} +__attribute__((weak)) int isupper(int c) { return (c >= 'A' && c <= 'Z'); } +__attribute__((weak)) int islower(int c) { return (c >= 'a' && c <= 'z'); } +__attribute__((weak)) int isxdigit(int c) { + return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} +__attribute__((weak)) int iscntrl(int c) { return ((c >= 0 && c < 32) || c == 127); } +__attribute__((weak)) int isprint(int c) { return (c >= 32 && c < 127); } +__attribute__((weak)) int isgraph(int c) { return (c > 32 && c < 127); } +__attribute__((weak)) int ispunct(int c) { + return isprint(c) && !isalnum(c) && !isspace(c); +} +__attribute__((weak)) int tolower(int c) { return isupper(c) ? (c - 'A' + 'a') : c; } +__attribute__((weak)) int toupper(int c) { return islower(c) ? (c - 'a' + 'A') : c; } diff --git a/src/userland/libc/ctype.h b/src/userland/libc/ctype.h new file mode 100644 index 0000000..4960be3 --- /dev/null +++ b/src/userland/libc/ctype.h @@ -0,0 +1,18 @@ +#ifndef BOREDOS_LIBC_CTYPE_H +#define BOREDOS_LIBC_CTYPE_H + +int isdigit(int c); +int isalpha(int c); +int isalnum(int c); +int isspace(int c); +int isupper(int c); +int islower(int c); +int isxdigit(int c); +int iscntrl(int c); +int ispunct(int c); +int isprint(int c); +int isgraph(int c); +int tolower(int c); +int toupper(int c); + +#endif diff --git a/src/userland/libc/errno.c b/src/userland/libc/errno.c new file mode 100644 index 0000000..8a8ab21 --- /dev/null +++ b/src/userland/libc/errno.c @@ -0,0 +1,3 @@ +#include "errno.h" + +__attribute__((weak)) int errno = 0; diff --git a/src/userland/libc/errno.h b/src/userland/libc/errno.h new file mode 100644 index 0000000..3901593 --- /dev/null +++ b/src/userland/libc/errno.h @@ -0,0 +1,18 @@ +#ifndef BOREDOS_LIBC_ERRNO_H +#define BOREDOS_LIBC_ERRNO_H + +extern int errno; + +#define EDOM 33 +#define ERANGE 34 +#define EINVAL 22 +#define EISDIR 21 +#define ENOENT 2 +#define ENOMEM 12 +#define EACCES 13 +#define EBADF 9 +#define EIO 5 +#define EEXIST 17 +#define ENOSYS 38 + +#endif diff --git a/src/userland/libc/fcntl.h b/src/userland/libc/fcntl.h new file mode 100644 index 0000000..7cc4fd8 --- /dev/null +++ b/src/userland/libc/fcntl.h @@ -0,0 +1,15 @@ +#ifndef BOREDOS_LIBC_FCNTL_H +#define BOREDOS_LIBC_FCNTL_H + +#include "sys/types.h" + +#define O_RDONLY 0x0000 +#define O_WRONLY 0x0001 +#define O_RDWR 0x0002 +#define O_CREAT 0x0040 +#define O_TRUNC 0x0200 +#define O_APPEND 0x0400 + +int open(const char *pathname, int flags, ...); + +#endif diff --git a/src/userland/libc/limits.h b/src/userland/libc/limits.h new file mode 100644 index 0000000..760f213 --- /dev/null +++ b/src/userland/libc/limits.h @@ -0,0 +1,22 @@ +#ifndef BOREDOS_LIBC_LIMITS_H +#define BOREDOS_LIBC_LIMITS_H + +#define CHAR_BIT 8 +#define SCHAR_MIN (-128) +#define SCHAR_MAX 127 +#define UCHAR_MAX 255 +#define SHRT_MIN (-32768) +#define SHRT_MAX 32767 +#define USHRT_MAX 65535 +#define INT_MIN (-2147483647 - 1) +#define INT_MAX 2147483647 +#define UINT_MAX 4294967295U +#define LONG_MIN (-9223372036854775807L - 1) +#define LONG_MAX 9223372036854775807L +#define ULONG_MAX 18446744073709551615UL +#define LLONG_MIN (-9223372036854775807LL - 1) +#define LLONG_MAX 9223372036854775807LL +#define ULLONG_MAX 18446744073709551615ULL +#define DBL_MAX 1.7976931348623157e+308 + +#endif diff --git a/src/userland/libc/locale.c b/src/userland/libc/locale.c new file mode 100644 index 0000000..4276e7d --- /dev/null +++ b/src/userland/libc/locale.c @@ -0,0 +1,19 @@ +#include "locale.h" +#include "string.h" + +static struct lconv _b_lconv = { + ".", "", "", "", "", ".", "", "", "", "", + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +__attribute__((weak)) char *setlocale(int category, const char *locale) { + (void)category; + if (locale == NULL || strcmp(locale, "C") == 0 || strcmp(locale, "") == 0) { + return "C"; + } + return NULL; +} + +__attribute__((weak)) struct lconv *localeconv(void) { + return &_b_lconv; +} diff --git a/src/userland/libc/locale.h b/src/userland/libc/locale.h new file mode 100644 index 0000000..46158da --- /dev/null +++ b/src/userland/libc/locale.h @@ -0,0 +1,30 @@ +#ifndef BOREDOS_LIBC_LOCALE_H +#define BOREDOS_LIBC_LOCALE_H + +struct lconv { + char *decimal_point; + char *thousands_sep; + char *grouping; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +}; + +#define LC_ALL 0 + +char *setlocale(int category, const char *locale); +struct lconv *localeconv(void); + +#endif diff --git a/src/userland/libc/math.h b/src/userland/libc/math.h index acd193c..25d91ab 100644 --- a/src/userland/libc/math.h +++ b/src/userland/libc/math.h @@ -28,7 +28,12 @@ double log(double x); double log2(double x); double log10(double x); double exp(double x); +double ldexp(double x, int expn); +double frexp(double x, int *expn); double pow(double base, double exponent); +double atan2(double y, double x); +double asin(double x); +double acos(double x); double sinh(double x); double cosh(double x); double tanh(double x); diff --git a/src/userland/libc/math_ext.c b/src/userland/libc/math_ext.c new file mode 100644 index 0000000..180b6af --- /dev/null +++ b/src/userland/libc/math_ext.c @@ -0,0 +1,91 @@ +#include "math.h" +#include "errno.h" + +__attribute__((weak)) double ldexp(double x, int expn) { + double v = x; + int i; + if (expn >= 0) { + for (i = 0; i < expn; i++) { + v *= 2.0; + } + } else { + for (i = 0; i < -expn; i++) { + v *= 0.5; + } + } + return v; +} + +__attribute__((weak)) double frexp(double x, int *expn) { + int e = 0; + double v = x; + if (x == 0.0) { + *expn = 0; + return 0.0; + } + while (fabs(v) >= 1.0) { + v *= 0.5; + e++; + } + while (fabs(v) > 0.0 && fabs(v) < 0.5) { + v *= 2.0; + e--; + } + *expn = e; + return v; +} + +static double _b_atan_series(double x) { + double x2 = x * x; + double term = x; + double sum = x; + int n; + for (n = 3; n <= 23; n += 2) { + term *= -x2; + sum += term / (double)n; + } + return sum; +} + +static double _b_atan_precise(double x) { + if (x < 0.0) { + return -_b_atan_precise(-x); + } + if (x > 1.0) { + return (M_PI / 2.0) - _b_atan_precise(1.0 / x); + } + if (x > 0.5) { + double y = (x - 1.0) / (x + 1.0); + return (M_PI / 4.0) + _b_atan_series(y); + } + return _b_atan_series(x); +} + +__attribute__((weak)) double atan2(double y, double x) { + if (x > 0.0) { + return _b_atan_precise(y / x); + } + if (x < 0.0) { + if (y >= 0.0) return _b_atan_precise(y / x) + M_PI; + return _b_atan_precise(y / x) - M_PI; + } + if (y > 0.0) return M_PI / 2.0; + if (y < 0.0) return -M_PI / 2.0; + return 0.0; +} + +__attribute__((weak)) double asin(double x) { + if (x > 1.0 || x < -1.0) { + errno = EDOM; + return 0.0; + } + return atan2(x, sqrt(1.0 - x * x)); +} + +__attribute__((weak)) double acos(double x) { + if (x > 1.0 || x < -1.0) { + errno = EDOM; + return 0.0; + } + return M_PI / 2.0 - asin(x); +} diff --git a/src/userland/libc/posix_fs.c b/src/userland/libc/posix_fs.c new file mode 100644 index 0000000..d85c19a --- /dev/null +++ b/src/userland/libc/posix_fs.c @@ -0,0 +1,53 @@ +#include "errno.h" +#include "syscall.h" +#include "sys/stat.h" + +__attribute__((weak)) int mkdir(const char *pathname, int mode) { + (void)mode; + if (!pathname || pathname[0] == '\0') { + errno = EINVAL; + return -1; + } + if (sys_mkdir(pathname) == 0) { + return 0; + } + errno = EIO; + return -1; +} + +__attribute__((weak)) int access(const char *pathname, int mode) { + (void)mode; + if (!pathname || pathname[0] == '\0') { + errno = EINVAL; + return -1; + } + if (sys_exists(pathname)) { + return 0; + } + errno = ENOENT; + return -1; +} + +__attribute__((weak)) int stat(const char *pathname, struct stat *statbuf) { + if (!pathname || pathname[0] == '\0') { + errno = EINVAL; + return -1; + } + if (!sys_exists(pathname)) { + errno = ENOENT; + return -1; + } + + if (statbuf) { + int fd = sys_open(pathname, "rb"); + if (fd >= 0) { + statbuf->st_size = (int)sys_size(fd); + sys_close(fd); + } else { + statbuf->st_size = 0; + } + statbuf->st_mode = 0; + } + + return 0; +} diff --git a/src/userland/libc/posix_io.c b/src/userland/libc/posix_io.c new file mode 100644 index 0000000..7e0a8fe --- /dev/null +++ b/src/userland/libc/posix_io.c @@ -0,0 +1,153 @@ +#include +#include + +#include "errno.h" +#include "fcntl.h" +#include "sys/stat.h" +#include "syscall.h" +#include "unistd.h" + +static const char *_b_mode_from_flags(int flags) { + int accmode = (flags & O_RDWR) ? O_RDWR : ((flags & O_WRONLY) ? O_WRONLY : O_RDONLY); + + if (accmode == O_RDONLY) { + return "rb"; + } + + if (accmode == O_RDWR) { + if (flags & O_TRUNC) { + return "w+"; + } + if (flags & O_CREAT) { + return "a+"; + } + return "r+"; + } + + if (flags & O_APPEND) { + return "ab"; + } + if (flags & O_TRUNC) { + return "wb"; + } + if (flags & O_CREAT) { + return "wb"; + } + return "wb"; +} + +__attribute__((weak)) int open(const char *pathname, int flags, ...) { + int fd; + + if (!pathname || pathname[0] == '\0') { + errno = EINVAL; + return -1; + } + + if (flags & O_CREAT) { + va_list ap; + (void)ap; + va_start(ap, flags); + (void)va_arg(ap, int); + va_end(ap); + } + + fd = sys_open(pathname, _b_mode_from_flags(flags)); + if (fd < 0) { + errno = ENOENT; + return -1; + } + + if (flags & O_APPEND) { + (void)sys_seek(fd, 0, SEEK_END); + } + + return fd; +} + +__attribute__((weak)) int close(int fd) { + if (fd < 0) { + errno = EBADF; + return -1; + } + sys_close(fd); + return 0; +} + +__attribute__((weak)) ssize_t read(int fd, void *buf, size_t count) { + int n; + if (fd < 0 || (!buf && count != 0)) { + errno = EINVAL; + return -1; + } + n = sys_read(fd, buf, (uint32_t)count); + if (n < 0) { + errno = EIO; + return -1; + } + return (ssize_t)n; +} + +__attribute__((weak)) ssize_t write(int fd, const void *buf, size_t count) { + int n; + if (fd < 0 || (!buf && count != 0)) { + errno = EINVAL; + return -1; + } + + if (fd <= 2) { + n = sys_write(fd, (const char *)buf, (int)count); + } else { + n = sys_write_fs(fd, buf, (uint32_t)count); + } + + if (n < 0) { + errno = EIO; + return -1; + } + return (ssize_t)n; +} + +__attribute__((weak)) off_t lseek(int fd, off_t offset, int whence) { + if (fd < 0) { + errno = EBADF; + return -1; + } + if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) { + errno = EINVAL; + return -1; + } + + if (sys_seek(fd, (int)offset, whence) < 0) { + errno = EIO; + return -1; + } + return (off_t)sys_tell(fd); +} + +__attribute__((weak)) int unlink(const char *pathname) { + if (!pathname || pathname[0] == '\0') { + errno = EINVAL; + return -1; + } + if (sys_delete(pathname) != 0) { + errno = ENOENT; + return -1; + } + return 0; +} + +__attribute__((weak)) int isatty(int fd) { + return (fd >= 0 && fd <= 2) ? 1 : 0; +} + +__attribute__((weak)) int fstat(int fd, struct stat *statbuf) { + if (fd < 0 || !statbuf) { + errno = EINVAL; + return -1; + } + + statbuf->st_size = (int)sys_size(fd); + statbuf->st_mode = 0; + return 0; +} diff --git a/src/userland/libc/runtime.c b/src/userland/libc/runtime.c new file mode 100644 index 0000000..9d21b32 --- /dev/null +++ b/src/userland/libc/runtime.c @@ -0,0 +1,178 @@ +#include "stdlib.h" +#include "string.h" +#include "errno.h" +#include "syscall.h" +#include "stdio.h" +#include "math.h" + +static int _b_is_space_char(int c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; +} + +static int _b_try_spawn_command(const char *command) { + char cmd[128]; + char args[256]; + int i = 0; + int j = 0; + int pid; + + while (command[i] && _b_is_space_char((unsigned char)command[i])) i++; + while (command[i] && !_b_is_space_char((unsigned char)command[i]) && j < (int)sizeof(cmd) - 1) { + cmd[j++] = command[i++]; + } + cmd[j] = '\0'; + + if (cmd[0] == '\0') { + return 0; + } + + while (command[i] && _b_is_space_char((unsigned char)command[i])) i++; + { + int k = 0; + while (command[i] && k < (int)sizeof(args) - 1) { + args[k++] = command[i++]; + } + args[k] = '\0'; + } + + pid = sys_spawn(cmd, args[0] ? args : NULL, SPAWN_FLAG_TERMINAL | SPAWN_FLAG_INHERIT_TTY, 0); + if (pid >= 0) { + return 0; + } + + if (cmd[0] != '/') { + char path[160]; + snprintf(path, sizeof(path), "/bin/%s", cmd); + pid = sys_spawn(path, args[0] ? args : NULL, SPAWN_FLAG_TERMINAL | SPAWN_FLAG_INHERIT_TTY, 0); + if (pid >= 0) { + return 0; + } + + snprintf(path, sizeof(path), "/bin/%s.elf", cmd); + pid = sys_spawn(path, args[0] ? args : NULL, SPAWN_FLAG_TERMINAL | SPAWN_FLAG_INHERIT_TTY, 0); + if (pid >= 0) { + return 0; + } + } + + errno = ENOENT; + return -1; +} + +static int _b_streq(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + return 0; + } + a++; + b++; + } + return *a == '\0' && *b == '\0'; +} + +__attribute__((weak)) int abs(int x) { + return (x < 0) ? -x : x; +} + +__attribute__((weak)) int system(const char *command) { + if (command == NULL) { + return 1; + } + return _b_try_spawn_command(command); +} + +__attribute__((weak)) char *getenv(const char *name) { + const char *cfg; + static char cwd_buf[256]; + if (!name || name[0] == '\0') { + return NULL; + } + + if (_b_streq(name, "PWD")) { + if (sys_getcwd(cwd_buf, (int)sizeof(cwd_buf)) >= 0) { + return cwd_buf; + } + return NULL; + } + + if (_b_streq(name, "PATH")) return "/bin:/"; + if (_b_streq(name, "HOME")) return "/"; + if (_b_streq(name, "SHELL")) return "/bin/bsh"; + if (_b_streq(name, "TERM")) return "boredos"; + + cfg = (const char *)(uintptr_t)sys_get_shell_config(name); + if ((uintptr_t)cfg > 0x10000ULL) { + return (char *)cfg; + } + return NULL; +} + +__attribute__((weak)) void abort(void) { + sys_exit(1); + while (1) {} +} + +__attribute__((weak)) void _exit(int status) { + sys_exit(status); + while (1) {} +} + +__attribute__((weak)) double strtod(const char *nptr, char **endptr) { + const char *p = nptr; + int sign = 1; + double value = 0.0; + double frac = 0.0; + double scale = 1.0; + int exp_sign = 1; + int exp_val = 0; + + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r' || *p == '\f' || *p == '\v') p++; + + if (*p == '-') { + sign = -1; + p++; + } else if (*p == '+') { + p++; + } + + while (*p >= '0' && *p <= '9') { + value = value * 10.0 + (double)(*p - '0'); + p++; + } + + if (*p == '.') { + p++; + while (*p >= '0' && *p <= '9') { + frac = frac * 10.0 + (double)(*p - '0'); + scale *= 10.0; + p++; + } + value += frac / scale; + } + + if (*p == 'e' || *p == 'E') { + const char *ep = p + 1; + if (*ep == '-') { + exp_sign = -1; + ep++; + } else if (*ep == '+') { + ep++; + } + if (*ep >= '0' && *ep <= '9') { + p = ep; + while (*p >= '0' && *p <= '9') { + exp_val = exp_val * 10 + (*p - '0'); + p++; + } + } + } + + if (endptr) { + *endptr = (char *)p; + } + + if (exp_val != 0) { + value = ldexp(value, exp_sign * exp_val); + } + return sign * value; +} diff --git a/src/userland/libc/setjmp.c b/src/userland/libc/setjmp.c new file mode 100644 index 0000000..9a57aa8 --- /dev/null +++ b/src/userland/libc/setjmp.c @@ -0,0 +1,38 @@ +#include "setjmp.h" + +__attribute__((weak)) int setjmp(jmp_buf env) { + __asm__ volatile( + "movq %%rbx, 0(%0)\n\t" + "movq %%rbp, 8(%0)\n\t" + "movq %%r12, 16(%0)\n\t" + "movq %%r13, 24(%0)\n\t" + "movq %%r14, 32(%0)\n\t" + "movq %%r15, 40(%0)\n\t" + "leaq 8(%%rsp), %%rax\n\t" + "movq %%rax, 48(%0)\n\t" + "movq (%%rsp), %%rax\n\t" + "movq %%rax, 56(%0)\n\t" + : + : "r"(env) + : "rax", "memory"); + return 0; +} + +__attribute__((weak)) void longjmp(jmp_buf env, int val) { + int r = (val == 0) ? 1 : val; + __asm__ volatile( + "movq 0(%0), %%rbx\n\t" + "movq 8(%0), %%rbp\n\t" + "movq 16(%0), %%r12\n\t" + "movq 24(%0), %%r13\n\t" + "movq 32(%0), %%r14\n\t" + "movq 40(%0), %%r15\n\t" + "movq 48(%0), %%rsp\n\t" + "movl %1, %%eax\n\t" + "movq 56(%0), %%rdx\n\t" + "jmp *%%rdx\n\t" + : + : "r"(env), "r"(r) + : "rax", "rdx", "memory"); + __builtin_unreachable(); +} diff --git a/src/userland/libc/setjmp.h b/src/userland/libc/setjmp.h new file mode 100644 index 0000000..4bbc400 --- /dev/null +++ b/src/userland/libc/setjmp.h @@ -0,0 +1,20 @@ +#ifndef BOREDOS_LIBC_SETJMP_H +#define BOREDOS_LIBC_SETJMP_H + +#include + +typedef struct boredos_jmp_buf_s { + uint64_t rbx; + uint64_t rbp; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rsp; + uint64_t rip; +} jmp_buf[1]; + +int setjmp(jmp_buf env) __attribute__((returns_twice, noinline)); +void longjmp(jmp_buf env, int val) __attribute__((noreturn, noinline)); + +#endif diff --git a/src/userland/libc/signal.c b/src/userland/libc/signal.c new file mode 100644 index 0000000..105f2bc --- /dev/null +++ b/src/userland/libc/signal.c @@ -0,0 +1,15 @@ +#include "signal.h" +#include "errno.h" + +static sighandler_t _signal_table[32] = {0}; + +__attribute__((weak)) sighandler_t signal(int sig, sighandler_t handler) { + sighandler_t old; + if (sig < 0 || sig >= (int)(sizeof(_signal_table) / sizeof(_signal_table[0]))) { + errno = EINVAL; + return SIG_ERR; + } + old = _signal_table[sig]; + _signal_table[sig] = handler; + return old; +} diff --git a/src/userland/libc/signal.h b/src/userland/libc/signal.h new file mode 100644 index 0000000..9514e1c --- /dev/null +++ b/src/userland/libc/signal.h @@ -0,0 +1,13 @@ +#ifndef BOREDOS_LIBC_SIGNAL_H +#define BOREDOS_LIBC_SIGNAL_H + +typedef void (*sighandler_t)(int); + +#define SIG_DFL ((sighandler_t)0) +#define SIG_IGN ((sighandler_t)1) +#define SIG_ERR ((sighandler_t)-1) +#define SIGINT 2 + +sighandler_t signal(int sig, sighandler_t handler); + +#endif diff --git a/src/userland/libc/stdio.c b/src/userland/libc/stdio.c new file mode 100644 index 0000000..edaee8d --- /dev/null +++ b/src/userland/libc/stdio.c @@ -0,0 +1,880 @@ +#include +#include +#include + +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "ctype.h" +#include "errno.h" +#include "syscall.h" +#include "time.h" + +static FILE boredos_stdin_obj = {0, 0, 0, 0, 0}; +static FILE boredos_stdout_obj = {1, 0, 0, 0, 0}; +static FILE boredos_stderr_obj = {2, 0, 0, 0, 0}; +__attribute__((weak)) FILE *stdin = &boredos_stdin_obj; +__attribute__((weak)) FILE *stdout = &boredos_stdout_obj; +__attribute__((weak)) FILE *stderr = &boredos_stderr_obj; + +static int _b_streq(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + return 0; + } + a++; + b++; + } + return *a == '\0' && *b == '\0'; +} + +static int _b_is_space_char(int c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; +} + +static char _b_tmpname_buf[FILENAME_MAX]; +static unsigned _b_tmp_counter = 0; + +static char *_b_tmpname_generate(char *out, size_t out_cap) { + unsigned tries; + if (out_cap == 0) { + errno = EINVAL; + return NULL; + } + + (void)sys_mkdir("/tmp"); + for (tries = 0; tries < 256; tries++) { + unsigned long long t = (unsigned long long)clock(); + snprintf(out, out_cap, "/tmp/tmp_%llu_%u.tmp", t, _b_tmp_counter++); + if (!sys_exists(out)) { + return out; + } + } + + errno = EEXIST; + return NULL; +} + +__attribute__((weak)) FILE *fopen(const char *path, const char *mode) { + int fd = sys_open(path, mode); + FILE *f; + if (fd < 0) { + errno = EINVAL; + return NULL; + } + f = (FILE *)malloc(sizeof(FILE)); + if (!f) { + sys_close(fd); + errno = ENOMEM; + return NULL; + } + f->fd = fd; + f->eof = 0; + f->err = 0; + f->has_ungetc = 0; + f->ungetc_char = 0; + return f; +} + +__attribute__((weak)) FILE *freopen(const char *path, const char *mode, FILE *stream) { + int fd; + if (!stream) { + return fopen(path, mode); + } + if (stream->fd >= 0) { + sys_close(stream->fd); + } + fd = sys_open(path, mode); + if (fd < 0) { + stream->err = 1; + errno = EINVAL; + return NULL; + } + stream->fd = fd; + stream->eof = 0; + stream->err = 0; + stream->has_ungetc = 0; + return stream; +} + +__attribute__((weak)) int fclose(FILE *stream) { + if (!stream) { + return EOF; + } + if (stream != stdin && stream != stdout && stream != stderr) { + if (stream->fd >= 0) { + sys_close(stream->fd); + } + free(stream); + } + return 0; +} + +__attribute__((weak)) size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t total; + int n; + if (!stream || !ptr || size == 0 || nmemb == 0) { + return 0; + } + total = size * nmemb; + n = sys_read(stream->fd, ptr, (uint32_t)total); + if (n <= 0) { + if (n == 0) { + stream->eof = 1; + } else { + stream->err = 1; + } + return 0; + } + if ((size_t)n < total) { + stream->eof = 1; + } + return (size_t)n / size; +} + +__attribute__((weak)) size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { + size_t total; + int n; + if (!stream || !ptr || size == 0 || nmemb == 0) { + return 0; + } + total = size * nmemb; + if (stream->fd <= 2) { + n = sys_write(stream->fd, (const char *)ptr, (int)total); + } else { + n = sys_write_fs(stream->fd, ptr, (uint32_t)total); + } + if (n < 0) { + stream->err = 1; + return 0; + } + return (size_t)n / size; +} + +__attribute__((weak)) int fseek(FILE *stream, long offset, int whence) { + if (!stream) { + return -1; + } + if (sys_seek(stream->fd, (int)offset, whence) < 0) { + stream->err = 1; + return -1; + } + stream->eof = 0; + stream->has_ungetc = 0; + return 0; +} + +__attribute__((weak)) long ftell(FILE *stream) { + if (!stream) { + return -1; + } + return (long)sys_tell(stream->fd); +} + +__attribute__((weak)) int getc(FILE *stream) { + unsigned char ch; + int n; + if (!stream) { + return EOF; + } + if (stream->has_ungetc) { + stream->has_ungetc = 0; + return stream->ungetc_char; + } + n = sys_read(stream->fd, &ch, 1); + if (n <= 0) { + if (n == 0) { + stream->eof = 1; + } else { + stream->err = 1; + } + return EOF; + } + return (int)ch; +} + +__attribute__((weak)) int ungetc(int c, FILE *stream) { + if (!stream || c == EOF) { + return EOF; + } + stream->has_ungetc = 1; + stream->ungetc_char = (unsigned char)c; + stream->eof = 0; + return c; +} + +__attribute__((weak)) char *fgets(char *s, int n, FILE *stream) { + int i; + if (!s || n <= 0 || !stream) { + return NULL; + } + for (i = 0; i < n - 1; i++) { + int c = getc(stream); + if (c == EOF) { + break; + } + s[i] = (char)c; + if (c == '\n') { + i++; + break; + } + } + if (i == 0) { + return NULL; + } + s[i] = '\0'; + return s; +} + +__attribute__((weak)) int fputs(const char *s, FILE *stream) { + size_t len; + size_t written; + if (!s || !stream) { + return EOF; + } + len = strlen(s); + written = fwrite(s, 1, len, stream); + return (written == len) ? (int)len : EOF; +} + +__attribute__((weak)) int feof(FILE *stream) { + return stream ? stream->eof : 1; +} + +__attribute__((weak)) int ferror(FILE *stream) { + return stream ? stream->err : 1; +} + +__attribute__((weak)) void clearerr(FILE *stream) { + if (stream) { + stream->eof = 0; + stream->err = 0; + } +} + +__attribute__((weak)) int fflush(FILE *stream) { + (void)stream; + return 0; +} + +__attribute__((weak)) int remove(const char *path) { + return sys_delete(path); +} + +__attribute__((weak)) int rename(const char *oldpath, const char *newpath) { + FILE *src; + FILE *dst; + char buf[1024]; + size_t nread; + + if (!oldpath || !newpath || oldpath[0] == '\0' || newpath[0] == '\0') { + errno = EINVAL; + return -1; + } + if (_b_streq(oldpath, newpath)) { + return 0; + } + + src = fopen(oldpath, "rb"); + if (!src) { + errno = ENOENT; + return -1; + } + dst = fopen(newpath, "wb"); + if (!dst) { + fclose(src); + return -1; + } + + for (;;) { + nread = fread(buf, 1, sizeof(buf), src); + if (nread == 0) { + break; + } + if (fwrite(buf, 1, nread, dst) != nread) { + fclose(src); + fclose(dst); + sys_delete(newpath); + errno = EIO; + return -1; + } + } + + if (ferror(src) || ferror(dst)) { + fclose(src); + fclose(dst); + sys_delete(newpath); + errno = EIO; + return -1; + } + + fclose(src); + fclose(dst); + if (sys_delete(oldpath) != 0) { + errno = EIO; + return -1; + } + return 0; +} + +__attribute__((weak)) FILE *tmpfile(void) { + char path[FILENAME_MAX]; + if (!_b_tmpname_generate(path, sizeof(path))) { + return NULL; + } + return fopen(path, "w+"); +} + +__attribute__((weak)) char *tmpnam(char *s) { + char *dst = s ? s : _b_tmpname_buf; + return _b_tmpname_generate(dst, FILENAME_MAX); +} + +static int _b_hex_digit(unsigned value, int upper) { + if (value < 10U) { + return (int)('0' + value); + } + return (int)((upper ? 'A' : 'a') + (value - 10U)); +} + +static void _b_append_char(char *out, size_t cap, size_t *idx, int c) { + if (*idx + 1 < cap) { + out[*idx] = (char)c; + } + (*idx)++; +} + +static void _b_append_strn(char *out, size_t cap, size_t *idx, const char *s, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + _b_append_char(out, cap, idx, s[i]); + } +} + +static void _b_utoa(unsigned long long v, unsigned base, int upper, char *buf, size_t *len) { + char tmp[64]; + size_t i = 0; + if (v == 0) { + tmp[i++] = '0'; + } else { + while (v && i < sizeof(tmp)) { + tmp[i++] = (char)_b_hex_digit((unsigned)(v % base), upper); + v /= base; + } + } + *len = i; + while (i > 0) { + *buf++ = tmp[--i]; + } +} + +static void _b_itoa(long long v, char *buf, size_t *len) { + unsigned long long uv; + size_t n = 0; + if (v < 0) { + *buf++ = '-'; + n++; + uv = (unsigned long long)(-(v + 1)) + 1ULL; + } else { + uv = (unsigned long long)v; + } + _b_utoa(uv, 10U, 0, buf, len); + *len += n; +} + +static void _b_ftoa(double d, int precision, char *buf, size_t *len) { + long long ip; + double frac; + size_t n = 0; + if (precision < 0) { + precision = 6; + } + if (d < 0.0) { + buf[n++] = '-'; + d = -d; + } + ip = (long long)d; + frac = d - (double)ip; + { + char ibuf[64]; + size_t ilen = 0; + _b_utoa((unsigned long long)ip, 10U, 0, ibuf, &ilen); + memcpy(buf + n, ibuf, ilen); + n += ilen; + } + if (precision > 0) { + int i; + buf[n++] = '.'; + for (i = 0; i < precision; i++) { + int digit; + frac *= 10.0; + digit = (int)frac; + if (digit < 0) digit = 0; + if (digit > 9) digit = 9; + buf[n++] = (char)('0' + digit); + frac -= (double)digit; + } + } + *len = n; +} + +__attribute__((weak)) int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) { + size_t out_i = 0; + while (*fmt) { + if (*fmt != '%') { + _b_append_char(str, size, &out_i, *fmt++); + continue; + } + + fmt++; + if (*fmt == '%') { + _b_append_char(str, size, &out_i, '%'); + fmt++; + continue; + } + + while (*fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '#' || *fmt == '0') { + fmt++; + } + + if (*fmt == '*') { + (void)va_arg(ap, int); + fmt++; + } else { + while (isdigit((unsigned char)*fmt)) { + fmt++; + } + } + + { + int precision = -1; + if (*fmt == '.') { + fmt++; + precision = 0; + if (*fmt == '*') { + precision = va_arg(ap, int); + fmt++; + } else { + while (isdigit((unsigned char)*fmt)) { + precision = precision * 10 + (*fmt - '0'); + fmt++; + } + } + } + + int lcount = 0; + while (*fmt == 'l') { + lcount++; + fmt++; + } + + switch (*fmt) { + case 'd': + case 'i': { + long long v; + char nbuf[64]; + size_t nlen = 0; + if (lcount >= 2) v = va_arg(ap, long long); + else if (lcount == 1) v = va_arg(ap, long); + else v = va_arg(ap, int); + _b_itoa(v, nbuf, &nlen); + _b_append_strn(str, size, &out_i, nbuf, nlen); + break; + } + case 'u': + case 'x': + case 'X': + case 'o': { + unsigned long long v; + unsigned base = (*fmt == 'o') ? 8U : ((*fmt == 'u') ? 10U : 16U); + char nbuf[64]; + size_t nlen = 0; + int upper = (*fmt == 'X'); + if (lcount >= 2) v = va_arg(ap, unsigned long long); + else if (lcount == 1) v = va_arg(ap, unsigned long); + else v = va_arg(ap, unsigned int); + _b_utoa(v, base, upper, nbuf, &nlen); + _b_append_strn(str, size, &out_i, nbuf, nlen); + break; + } + case 'c': { + int c = va_arg(ap, int); + _b_append_char(str, size, &out_i, c); + break; + } + case 's': { + const char *s = va_arg(ap, const char *); + size_t slen; + if (!s) s = "(null)"; + slen = strlen(s); + if (precision >= 0 && (size_t)precision < slen) { + slen = (size_t)precision; + } + _b_append_strn(str, size, &out_i, s, slen); + break; + } + case 'p': { + uintptr_t v = (uintptr_t)va_arg(ap, void *); + char nbuf[32]; + size_t nlen = 0; + _b_append_strn(str, size, &out_i, "0x", 2); + _b_utoa((unsigned long long)v, 16U, 0, nbuf, &nlen); + _b_append_strn(str, size, &out_i, nbuf, nlen); + break; + } + case 'f': + case 'g': + case 'e': { + double v = va_arg(ap, double); + char nbuf[96]; + size_t nlen = 0; + _b_ftoa(v, precision, nbuf, &nlen); + _b_append_strn(str, size, &out_i, nbuf, nlen); + break; + } + default: + _b_append_char(str, size, &out_i, '%'); + _b_append_char(str, size, &out_i, *fmt); + break; + } + } + if (*fmt) { + fmt++; + } + } + + if (size > 0) { + size_t term = (out_i < size - 1) ? out_i : (size - 1); + str[term] = '\0'; + } + return (int)out_i; +} + +__attribute__((weak)) int snprintf(char *str, size_t size, const char *fmt, ...) { + int n; + va_list ap; + va_start(ap, fmt); + n = vsnprintf(str, size, fmt, ap); + va_end(ap); + return n; +} + +__attribute__((weak)) int sprintf(char *str, const char *fmt, ...) { + int n; + va_list ap; + va_start(ap, fmt); + n = vsnprintf(str, (size_t)-1, fmt, ap); + va_end(ap); + return n; +} + +__attribute__((weak)) int fprintf(FILE *stream, const char *fmt, ...) { + char buf[1024]; + int len; + va_list ap; + va_start(ap, fmt); + len = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (len <= 0) { + return len; + } + if ((size_t)len > sizeof(buf)) { + len = (int)sizeof(buf); + } + if (fwrite(buf, 1, (size_t)len, stream) == 0) { + return -1; + } + return len; +} + +__attribute__((weak)) int vfprintf(FILE *stream, const char *fmt, va_list ap) { + char buf[1024]; + int len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (len <= 0) { + return len; + } + if ((size_t)len > sizeof(buf)) { + len = (int)sizeof(buf); + } + if (fwrite(buf, 1, (size_t)len, stream) == 0) { + return -1; + } + return len; +} + +__attribute__((weak)) int fputc(int c, FILE *stream) { + unsigned char ch = (unsigned char)c; + if (!stream) { + return EOF; + } + if (fwrite(&ch, 1, 1, stream) != 1) { + return EOF; + } + return c; +} + +__attribute__((weak)) int putchar(int c) { + return fputc(c, stdout); +} + +__attribute__((weak)) long filelength(FILE *f) { + if (!f) { + return -1; + } + return (long)sys_size(f->fd); +} + +static const char *_b_skip_spaces(const char *p) { + while (*p && _b_is_space_char((unsigned char)*p)) { + p++; + } + return p; +} + +static int _b_digit_val(int c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); + if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); + return -1; +} + +static int _b_parse_u64(const char **sp, int base, int width, unsigned long long *out) { + const char *p = *sp; + unsigned long long v = 0; + int any = 0; + + if (width != 0 && base == 16 && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + p += 2; + if (width > 0) { + width -= 2; + } + } + + while (*p && (width < 0 || width > 0)) { + int d = _b_digit_val((unsigned char)*p); + if (d < 0 || d >= base) { + break; + } + v = v * (unsigned long long)base + (unsigned long long)d; + any = 1; + p++; + if (width > 0) { + width--; + } + } + + if (!any) { + return 0; + } + *sp = p; + *out = v; + return 1; +} + +static int _b_parse_auto_int(const char **sp, int width, long long *out) { + const char *p = *sp; + int neg = 0; + int base = 10; + unsigned long long uv; + + if (*p == '+' || *p == '-') { + neg = (*p == '-'); + p++; + if (width > 0) { + width--; + } + } + + if ((width < 0 || width >= 2) && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { + base = 16; + } else if ((width < 0 || width >= 1) && p[0] == '0') { + base = 8; + } + + if (!_b_parse_u64(&p, base, width, &uv)) { + return 0; + } + *sp = p; + *out = neg ? -(long long)uv : (long long)uv; + return 1; +} + +static int _b_parse_s64(const char **sp, int base, int width, long long *out) { + const char *p = *sp; + int neg = 0; + unsigned long long uv; + + if (*p == '+' || *p == '-') { + neg = (*p == '-'); + p++; + if (width > 0) { + width--; + } + } + if (!_b_parse_u64(&p, base, width, &uv)) { + return 0; + } + *sp = p; + *out = neg ? -(long long)uv : (long long)uv; + return 1; +} + +static int _b_vsscanf_core(const char *str, const char *fmt, va_list ap) { + const char *s = str; + const char *f = fmt; + int assigned = 0; + + while (*f) { + if (_b_is_space_char((unsigned char)*f)) { + while (_b_is_space_char((unsigned char)*f)) f++; + s = _b_skip_spaces(s); + continue; + } + + if (*f != '%') { + if (*s != *f) { + break; + } + s++; + f++; + continue; + } + + f++; + if (*f == '%') { + if (*s != '%') { + break; + } + s++; + f++; + continue; + } + + { + int suppress = 0; + int width = -1; + int lcount = 0; + + if (*f == '*') { + suppress = 1; + f++; + } + + if (isdigit((unsigned char)*f)) { + width = 0; + while (isdigit((unsigned char)*f)) { + width = width * 10 + (*f - '0'); + f++; + } + } + + while (*f == 'l') { + lcount++; + f++; + } + + if (*f != 'c' && *f != 'n') { + s = _b_skip_spaces(s); + } + + switch (*f) { + case 'd': { + long long v; + if (!_b_parse_s64(&s, 10, width, &v)) return assigned; + if (!suppress) { + if (lcount >= 1) *va_arg(ap, long *) = (long)v; + else *va_arg(ap, int *) = (int)v; + assigned++; + } + break; + } + case 'i': { + long long v; + if (!_b_parse_auto_int(&s, width, &v)) return assigned; + if (!suppress) { + if (lcount >= 1) *va_arg(ap, long *) = (long)v; + else *va_arg(ap, int *) = (int)v; + assigned++; + } + break; + } + case 'u': + case 'x': + case 'X': + case 'o': { + int base = (*f == 'o') ? 8 : ((*f == 'u') ? 10 : 16); + unsigned long long v; + if (!_b_parse_u64(&s, base, width, &v)) return assigned; + if (!suppress) { + if (lcount >= 1) *va_arg(ap, unsigned long *) = (unsigned long)v; + else *va_arg(ap, unsigned *) = (unsigned)v; + assigned++; + } + break; + } + case 'c': { + int count = (width > 0) ? width : 1; + if (!*s) return assigned; + if (!suppress) { + char *dst = va_arg(ap, char *); + while (count-- > 0 && *s) { + *dst++ = *s++; + } + assigned++; + } else { + while (count-- > 0 && *s) s++; + } + break; + } + case 's': { + int wrote = 0; + if (!*s) return assigned; + if (!suppress) { + char *dst = va_arg(ap, char *); + while (*s && !_b_is_space_char((unsigned char)*s) && (width < 0 || width-- > 0)) { + *dst++ = *s++; + wrote = 1; + } + if (!wrote) return assigned; + *dst = '\0'; + assigned++; + } else { + while (*s && !_b_is_space_char((unsigned char)*s) && (width < 0 || width-- > 0)) { + s++; + wrote = 1; + } + if (!wrote) return assigned; + } + break; + } + case 'n': { + if (!suppress) { + *va_arg(ap, int *) = (int)(s - str); + } + break; + } + default: + return assigned; + } + } + + if (*f) { + f++; + } + } + + return assigned; +} + +__attribute__((weak)) int sscanf(const char *str, const char *fmt, ...) { + int n; + va_list ap; + if (!str || !fmt) { + errno = EINVAL; + return 0; + } + va_start(ap, fmt); + n = _b_vsscanf_core(str, fmt, ap); + va_end(ap); + return n; +} diff --git a/src/userland/libc/stdio.h b/src/userland/libc/stdio.h new file mode 100644 index 0000000..4d8447f --- /dev/null +++ b/src/userland/libc/stdio.h @@ -0,0 +1,56 @@ +#ifndef BOREDOS_LIBC_STDIO_H +#define BOREDOS_LIBC_STDIO_H + +#include +#include + +typedef struct BOREDOS_FILE { + int fd; + int eof; + int err; + int has_ungetc; + int ungetc_char; +} FILE; + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +#define EOF (-1) +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define BUFSIZ 1024 +#define FILENAME_MAX 260 +#define TMP_MAX 32 + +FILE *fopen(const char *path, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int fclose(FILE *stream); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +int fseek(FILE *stream, long offset, int whence); +long ftell(FILE *stream); +int getc(FILE *stream); +int ungetc(int c, FILE *stream); +char *fgets(char *s, int n, FILE *stream); +int fputs(const char *s, FILE *stream); +int feof(FILE *stream); +int ferror(FILE *stream); +void clearerr(FILE *stream); +int fflush(FILE *stream); +int fputc(int c, FILE *stream); +int putchar(int c); +int fprintf(FILE *stream, const char *fmt, ...); +int vfprintf(FILE *stream, const char *fmt, va_list ap); +long filelength(FILE *f); +int vsnprintf(char *str, size_t size, const char *fmt, va_list ap); +int snprintf(char *str, size_t size, const char *fmt, ...); +int sprintf(char *str, const char *fmt, ...); +int sscanf(const char *str, const char *fmt, ...); +int remove(const char *path); +int rename(const char *oldpath, const char *newpath); +FILE *tmpfile(void); +char *tmpnam(char *s); + +#endif diff --git a/src/userland/libc/stdlib.h b/src/userland/libc/stdlib.h index 2b4818d..8e87f46 100644 --- a/src/userland/libc/stdlib.h +++ b/src/userland/libc/stdlib.h @@ -16,15 +16,24 @@ void *memcpy(void *dest, const void *src, size_t n); // Math/Utility functions int atoi(const char *nptr); void itoa(int n, char *buf); +int abs(int x); +double strtod(const char *nptr, char **endptr); // IO functions void puts(const char *s); void printf(const char *fmt, ...); +// Runtime stubs +int system(const char *command); +char *getenv(const char *name); +void abort(void); + // System/Process functions int chdir(const char *path); char* getcwd(char *buf, int size); +int access(const char *pathname, int mode); void sleep(int ms); void exit(int status); +void _exit(int status); #endif diff --git a/src/userland/libc/string.h b/src/userland/libc/string.h index a0e32ec..a5eab52 100644 --- a/src/userland/libc/string.h +++ b/src/userland/libc/string.h @@ -7,11 +7,22 @@ void *memmove(void *dest, const void *src, size_t n); int memcmp(const void *s1, const void *s2, size_t n); void *memcpy(void *dest, const void *src, size_t n); void *memset(void *s, int c, size_t n); +void *memchr(const void *s, int c, size_t n); char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strpbrk(const char *s, const char *accept); char *strstr(const char *haystack, const char *needle); +size_t strspn(const char *s, const char *accept); +size_t strcspn(const char *s, const char *reject); size_t strlen(const char *s); int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +int strncasecmp(const char *s1, const char *s2, size_t n); +int strcasecmp(const char *s1, const char *s2); +int strcoll(const char *s1, const char *s2); char* strcpy(char *dest, const char *src); char* strcat(char *dest, const char *src); +char *strdup(const char *s); +char *strerror(int errnum); #endif diff --git a/src/userland/libc/string_ext.c b/src/userland/libc/string_ext.c new file mode 100644 index 0000000..06abb5e --- /dev/null +++ b/src/userland/libc/string_ext.c @@ -0,0 +1,158 @@ +#include "string.h" +#include "errno.h" +#include "ctype.h" +#include "stdlib.h" + +__attribute__((weak)) int strncmp(const char *s1, const char *s2, size_t n) { + size_t i; + for (i = 0; i < n; i++) { + unsigned char c1 = (unsigned char)s1[i]; + unsigned char c2 = (unsigned char)s2[i]; + if (c1 != c2) { + return (int)c1 - (int)c2; + } + if (c1 == '\0') { + return 0; + } + } + return 0; +} + +__attribute__((weak)) char *strncpy(char *dest, const char *src, size_t n) { + size_t i; + for (i = 0; i < n && src[i] != '\0'; i++) { + dest[i] = src[i]; + } + for (; i < n; i++) { + dest[i] = '\0'; + } + return dest; +} + +__attribute__((weak)) char *strncat(char *dest, const char *src, size_t n) { + size_t dlen = strlen(dest); + size_t i; + for (i = 0; i < n && src[i] != '\0'; i++) { + dest[dlen + i] = src[i]; + } + dest[dlen + i] = '\0'; + return dest; +} + +__attribute__((weak)) char *strrchr(const char *s, int c) { + const char *last = NULL; + for (;; s++) { + if (*s == (char)c) { + last = s; + } + if (*s == '\0') { + break; + } + } + return (char *)last; +} + +__attribute__((weak)) char *strpbrk(const char *s, const char *accept) { + for (; *s; s++) { + const char *a; + for (a = accept; *a; a++) { + if (*s == *a) { + return (char *)s; + } + } + } + return NULL; +} + +__attribute__((weak)) size_t strspn(const char *s, const char *accept) { + size_t n = 0; + while (*s) { + if (!strchr(accept, *s)) { + break; + } + n++; + s++; + } + return n; +} + +__attribute__((weak)) size_t strcspn(const char *s, const char *reject) { + size_t n = 0; + while (*s) { + if (strchr(reject, *s)) { + break; + } + n++; + s++; + } + return n; +} + +__attribute__((weak)) void *memchr(const void *s, int c, size_t n) { + const unsigned char *p = (const unsigned char *)s; + size_t i; + for (i = 0; i < n; i++) { + if (p[i] == (unsigned char)c) { + return (void *)(p + i); + } + } + return NULL; +} + +__attribute__((weak)) int strcoll(const char *s1, const char *s2) { + return strcmp(s1, s2); +} + +__attribute__((weak)) char *strerror(int errnum) { + switch (errnum) { + case 0: return "no error"; + case EDOM: return "domain error"; + case ERANGE: return "range error"; + case EINVAL: return "invalid argument"; + case ENOENT: return "no such file or directory"; + case ENOMEM: return "not enough memory"; + case EEXIST: return "file exists"; + case EIO: return "i/o error"; + case ENOSYS: return "function not implemented"; + default: return "unknown error"; + } +} + +__attribute__((weak)) int strncasecmp(const char *s1, const char *s2, size_t n) { + while (n--) { + char c1 = (char)tolower((unsigned char)*s1++); + char c2 = (char)tolower((unsigned char)*s2++); + if (c1 != c2) { + return c1 - c2; + } + if (!c1) { + break; + } + } + return 0; +} + +__attribute__((weak)) int strcasecmp(const char *s1, const char *s2) { + while (1) { + char c1 = (char)tolower((unsigned char)*s1++); + char c2 = (char)tolower((unsigned char)*s2++); + if (c1 != c2) { + return c1 - c2; + } + if (!c1) { + break; + } + } + return 0; +} + +__attribute__((weak)) char *strdup(const char *s) { + size_t len = strlen(s) + 1; + char *dup = (char *)malloc(len); + if (!dup) { + errno = ENOMEM; + return NULL; + } + memcpy(dup, s, len); + return dup; +} diff --git a/src/userland/libc/sys/stat.h b/src/userland/libc/sys/stat.h new file mode 100644 index 0000000..318d322 --- /dev/null +++ b/src/userland/libc/sys/stat.h @@ -0,0 +1,13 @@ +#ifndef BOREDOS_LIBC_SYS_STAT_H +#define BOREDOS_LIBC_SYS_STAT_H + +struct stat { + int st_size; + int st_mode; +}; + +int stat(const char *pathname, struct stat *statbuf); +int fstat(int fd, struct stat *statbuf); +int mkdir(const char *pathname, int mode); + +#endif diff --git a/src/userland/libc/sys/types.h b/src/userland/libc/sys/types.h new file mode 100644 index 0000000..4d680b5 --- /dev/null +++ b/src/userland/libc/sys/types.h @@ -0,0 +1,8 @@ +#ifndef BOREDOS_LIBC_SYS_TYPES_H +#define BOREDOS_LIBC_SYS_TYPES_H + +typedef long ssize_t; +typedef long off_t; +typedef unsigned int mode_t; + +#endif diff --git a/src/userland/libc/time.c b/src/userland/libc/time.c new file mode 100644 index 0000000..6bb1248 --- /dev/null +++ b/src/userland/libc/time.c @@ -0,0 +1,166 @@ +#include + +#include "time.h" +#include "stdio.h" +#include "syscall.h" + +static int _b_is_leap(int year) { + return ((year % 4) == 0 && (year % 100) != 0) || ((year % 400) == 0); +} + +static int _b_days_in_month(int year, int month) { + static const int mdays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + if (month == 1 && _b_is_leap(year)) { + return 29; + } + return mdays[month]; +} + +static long long _b_days_before_year(int year) { + long long y = (long long)year - 1; + return y * 365 + y / 4 - y / 100 + y / 400; +} + +static long long _b_days_since_epoch(int year, int month, int day) { + long long days = _b_days_before_year(year) - _b_days_before_year(1970); + int m; + for (m = 0; m < month - 1; m++) { + days += _b_days_in_month(year, m); + } + days += (day - 1); + return days; +} + +static void _b_civil_from_days(long long z, int *year, int *month, int *day) { + z += 719468; + long long era = (z >= 0 ? z : z - 146096) / 146097; + unsigned doe = (unsigned)(z - era * 146097); + unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; + int y = (int)yoe + (int)era * 400; + unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100); + unsigned mp = (5 * doy + 2) / 153; + unsigned d = doy - (153 * mp + 2) / 5 + 1; + unsigned m = mp + (mp < 10 ? 3 : (unsigned)-9); + y += (m <= 2); + *year = y; + *month = (int)m; + *day = (int)d; +} + +static time_t _b_seconds_from_ymdhms(int year, int month, int day, int hour, int minute, int second) { + long long days = _b_days_since_epoch(year, month, day); + return (time_t)(days * 86400LL + hour * 3600LL + minute * 60LL + second); +} + +static void _b_fill_tm_from_epoch(time_t t, struct tm *out) { + long long sec = (long long)t; + long long days; + int sod; + int year; + int month; + int day; + + if (sec < 0) { + long long d = ((-sec) + 86399LL) / 86400LL; + sec += d * 86400LL; + } + + days = sec / 86400LL; + sod = (int)(sec % 86400LL); + if (sod < 0) { + sod += 86400; + days--; + } + + _b_civil_from_days(days, &year, &month, &day); + + out->tm_year = year - 1900; + out->tm_mon = month - 1; + out->tm_mday = day; + out->tm_hour = sod / 3600; + out->tm_min = (sod % 3600) / 60; + out->tm_sec = sod % 60; + out->tm_wday = (int)((days + 4) % 7); + if (out->tm_wday < 0) out->tm_wday += 7; + + { + long long jan1 = _b_days_since_epoch(year, 1, 1); + out->tm_yday = (int)(days - jan1); + } + out->tm_isdst = 0; +} + +__attribute__((weak)) time_t time(time_t *out) { + int dt[6] = {1970, 1, 1, 0, 0, 0}; + time_t t; + if (sys_system(SYSTEM_CMD_RTC_GET, 0, (uint64_t)dt, 0, 0) != 0) { + t = 0; + } else { + t = _b_seconds_from_ymdhms(dt[0], dt[1], dt[2], dt[3], dt[4], dt[5]); + } + if (out) { + *out = t; + } + return t; +} + +__attribute__((weak)) clock_t clock(void) { + static uint64_t start_tsc = 0; + unsigned int lo; + unsigned int hi; + uint64_t now_tsc; + + __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); + now_tsc = ((uint64_t)hi << 32) | (uint64_t)lo; + + if (start_tsc == 0) { + start_tsc = now_tsc; + __asm__ volatile("rdtsc" : "=a"(lo), "=d"(hi)); + now_tsc = ((uint64_t)hi << 32) | (uint64_t)lo; + } + + return (clock_t)(now_tsc - start_tsc); +} + +__attribute__((weak)) struct tm *gmtime(const time_t *timer) { + static struct tm tmv; + if (!timer) { + return NULL; + } + _b_fill_tm_from_epoch(*timer, &tmv); + return &tmv; +} + +__attribute__((weak)) struct tm *localtime(const time_t *timer) { + return gmtime(timer); +} + +__attribute__((weak)) size_t strftime(char *s, size_t max, const char *fmt, const struct tm *tm) { + (void)fmt; + if (!s || max == 0 || !tm) { + return 0; + } + { + int n = snprintf(s, max, "%04d-%02d-%02d %02d:%02d:%02d", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + if (n < 0 || (size_t)n >= max) { + if (max > 0) s[0] = '\0'; + return 0; + } + return (size_t)n; + } +} + +__attribute__((weak)) time_t mktime(struct tm *tm) { + if (!tm) { + return (time_t)-1; + } + return _b_seconds_from_ymdhms( + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec); +} diff --git a/src/userland/libc/time.h b/src/userland/libc/time.h new file mode 100644 index 0000000..b3e7c3c --- /dev/null +++ b/src/userland/libc/time.h @@ -0,0 +1,30 @@ +#ifndef BOREDOS_LIBC_TIME_H +#define BOREDOS_LIBC_TIME_H + +#include + +typedef long long time_t; +typedef unsigned long long clock_t; + +#define CLOCKS_PER_SEC 3000000000ULL + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +time_t time(time_t *out); +clock_t clock(void); +struct tm *localtime(const time_t *timer); +struct tm *gmtime(const time_t *timer); +size_t strftime(char *s, size_t max, const char *fmt, const struct tm *tm); +time_t mktime(struct tm *tm); + +#endif diff --git a/src/userland/libc/unistd.h b/src/userland/libc/unistd.h new file mode 100644 index 0000000..e1c70b8 --- /dev/null +++ b/src/userland/libc/unistd.h @@ -0,0 +1,22 @@ +#ifndef BOREDOS_LIBC_UNISTD_H +#define BOREDOS_LIBC_UNISTD_H + +#include "sys/types.h" + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define F_OK 0 +#define X_OK 1 +#define W_OK 2 +#define R_OK 4 + +int close(int fd); +ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); +off_t lseek(int fd, off_t offset, int whence); +int unlink(const char *pathname); +int isatty(int fd); + +#endif