mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
refactor(libc): move Lua an DOOM stubs into shared libc modules
This commit is contained in:
parent
f788ba416d
commit
78ae0f154d
36 changed files with 2145 additions and 1263 deletions
|
|
@ -59,7 +59,7 @@ $(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/stb_i
|
||||||
$(LD) $(LDFLAGS) $^ -o $@
|
$(LD) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
$(BIN_DIR)/%.o: games/doom/%.c | $(BIN_DIR)
|
$(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
|
$(BIN_DIR)/doom.elf: $(LIBC_OBJS) $(DOOM_OBJS) $(BIN_DIR)/stb_image.o
|
||||||
$(LD) $(LDFLAGS) $^ -o $@
|
$(LD) $(LDFLAGS) $^ -o $@
|
||||||
|
|
|
||||||
1026
src/userland/cli/third_party/lua/boredos_stubs.h
vendored
1026
src/userland/cli/third_party/lua/boredos_stubs.h
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef BOREDOS_LIBC_TIME_H
|
||||||
|
#define BOREDOS_LIBC_TIME_H
|
||||||
|
|
||||||
typedef long long time_t;
|
typedef long long time_t;
|
||||||
typedef unsigned long long clock_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);
|
time_t mktime(struct tm *tm);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,219 +0,0 @@
|
||||||
#include "boredos_libc.h"
|
|
||||||
#include <syscall.h>
|
|
||||||
|
|
||||||
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; }
|
|
||||||
|
|
@ -5,6 +5,9 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#define SEEK_SET 0
|
#define SEEK_SET 0
|
||||||
#define SEEK_CUR 1
|
#define SEEK_CUR 1
|
||||||
|
|
@ -12,12 +15,6 @@
|
||||||
|
|
||||||
#define EOF (-1)
|
#define EOF (-1)
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int fd;
|
|
||||||
int eof;
|
|
||||||
int error;
|
|
||||||
} FILE;
|
|
||||||
|
|
||||||
extern FILE* stderr;
|
extern FILE* stderr;
|
||||||
extern FILE* stdout;
|
extern FILE* stdout;
|
||||||
extern FILE* stdin;
|
extern FILE* stdin;
|
||||||
|
|
@ -34,6 +31,14 @@ extern FILE* stdin;
|
||||||
#define W_OK 2
|
#define W_OK 2
|
||||||
#define X_OK 1
|
#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);
|
FILE *fopen(const char *path, const char *mode);
|
||||||
int fclose(FILE *stream);
|
int fclose(FILE *stream);
|
||||||
size_t fread(void *ptr, size_t size, size_t nmemb, 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 mkdir(const char *pathname, int mode);
|
||||||
int access(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);
|
int stat(const char *pathname, struct stat *statbuf);
|
||||||
|
|
||||||
char *strstr(const char *haystack, const char *needle);
|
char *strstr(const char *haystack, const char *needle);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include "deh_main.h"
|
#include "deh_main.h"
|
||||||
#include "i_swap.h"
|
#include "i_swap.h"
|
||||||
|
#include "i_system.h"
|
||||||
#include "i_video.h"
|
#include "i_video.h"
|
||||||
|
|
||||||
#include "hu_stuff.h"
|
#include "hu_stuff.h"
|
||||||
|
|
@ -288,14 +289,47 @@ void HU_Init(void)
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
|
int fallback_lump = -1;
|
||||||
char buffer[9];
|
char buffer[9];
|
||||||
|
|
||||||
// load the heads-up font
|
// load the heads-up font
|
||||||
j = HU_FONTSTART;
|
j = HU_FONTSTART;
|
||||||
for (i=0;i<HU_FONTSIZE;i++)
|
for (i=0;i<HU_FONTSIZE;i++)
|
||||||
{
|
{
|
||||||
|
int lump;
|
||||||
DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
|
DEH_snprintf(buffer, 9, "STCFN%.3d", j++);
|
||||||
hu_font[i] = (patch_t *) W_CacheLumpName(buffer, PU_STATIC);
|
lump = W_CheckNumForName(buffer);
|
||||||
|
|
||||||
|
if (lump < 0 && fallback_lump < 0)
|
||||||
|
{
|
||||||
|
int probe;
|
||||||
|
for (probe = HU_FONTSTART; probe <= HU_FONTEND; ++probe)
|
||||||
|
{
|
||||||
|
DEH_snprintf(buffer, 9, "STCFN%.3d", probe);
|
||||||
|
fallback_lump = W_CheckNumForName(buffer);
|
||||||
|
if (fallback_lump >= 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -264,7 +264,7 @@ void I_Quit (void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__)
|
#if !defined(_WIN32) && !defined(__MACOSX__) && !defined(__DJGPP__) && !defined(BOREDOS)
|
||||||
#define ZENITY_BINARY "/usr/bin/zenity"
|
#define ZENITY_BINARY "/usr/bin/zenity"
|
||||||
|
|
||||||
// returns non-zero if zenity is available
|
// returns non-zero if zenity is available
|
||||||
|
|
@ -347,7 +347,7 @@ static int ZenityErrorBox(char *message)
|
||||||
return result;
|
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
|
#else
|
||||||
{
|
{
|
||||||
|
#if !defined(BOREDOS)
|
||||||
ZenityErrorBox(msgbuf);
|
ZenityErrorBox(msgbuf);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
21
src/userland/libc/ctype.c
Normal file
21
src/userland/libc/ctype.c
Normal file
|
|
@ -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; }
|
||||||
18
src/userland/libc/ctype.h
Normal file
18
src/userland/libc/ctype.h
Normal file
|
|
@ -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
|
||||||
3
src/userland/libc/errno.c
Normal file
3
src/userland/libc/errno.c
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "errno.h"
|
||||||
|
|
||||||
|
__attribute__((weak)) int errno = 0;
|
||||||
18
src/userland/libc/errno.h
Normal file
18
src/userland/libc/errno.h
Normal file
|
|
@ -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
|
||||||
15
src/userland/libc/fcntl.h
Normal file
15
src/userland/libc/fcntl.h
Normal file
|
|
@ -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
|
||||||
22
src/userland/libc/limits.h
Normal file
22
src/userland/libc/limits.h
Normal file
|
|
@ -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
|
||||||
19
src/userland/libc/locale.c
Normal file
19
src/userland/libc/locale.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
30
src/userland/libc/locale.h
Normal file
30
src/userland/libc/locale.h
Normal file
|
|
@ -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
|
||||||
|
|
@ -28,7 +28,12 @@ double log(double x);
|
||||||
double log2(double x);
|
double log2(double x);
|
||||||
double log10(double x);
|
double log10(double x);
|
||||||
double exp(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 pow(double base, double exponent);
|
||||||
|
double atan2(double y, double x);
|
||||||
|
double asin(double x);
|
||||||
|
double acos(double x);
|
||||||
double sinh(double x);
|
double sinh(double x);
|
||||||
double cosh(double x);
|
double cosh(double x);
|
||||||
double tanh(double x);
|
double tanh(double x);
|
||||||
|
|
|
||||||
91
src/userland/libc/math_ext.c
Normal file
91
src/userland/libc/math_ext.c
Normal file
|
|
@ -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);
|
||||||
|
}
|
||||||
53
src/userland/libc/posix_fs.c
Normal file
53
src/userland/libc/posix_fs.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
153
src/userland/libc/posix_io.c
Normal file
153
src/userland/libc/posix_io.c
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
178
src/userland/libc/runtime.c
Normal file
178
src/userland/libc/runtime.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
38
src/userland/libc/setjmp.c
Normal file
38
src/userland/libc/setjmp.c
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
20
src/userland/libc/setjmp.h
Normal file
20
src/userland/libc/setjmp.h
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef BOREDOS_LIBC_SETJMP_H
|
||||||
|
#define BOREDOS_LIBC_SETJMP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
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
|
||||||
15
src/userland/libc/signal.c
Normal file
15
src/userland/libc/signal.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
13
src/userland/libc/signal.h
Normal file
13
src/userland/libc/signal.h
Normal file
|
|
@ -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
|
||||||
880
src/userland/libc/stdio.c
Normal file
880
src/userland/libc/stdio.c
Normal file
|
|
@ -0,0 +1,880 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
56
src/userland/libc/stdio.h
Normal file
56
src/userland/libc/stdio.h
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef BOREDOS_LIBC_STDIO_H
|
||||||
|
#define BOREDOS_LIBC_STDIO_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -16,15 +16,24 @@ void *memcpy(void *dest, const void *src, size_t n);
|
||||||
// Math/Utility functions
|
// Math/Utility functions
|
||||||
int atoi(const char *nptr);
|
int atoi(const char *nptr);
|
||||||
void itoa(int n, char *buf);
|
void itoa(int n, char *buf);
|
||||||
|
int abs(int x);
|
||||||
|
double strtod(const char *nptr, char **endptr);
|
||||||
|
|
||||||
// IO functions
|
// IO functions
|
||||||
void puts(const char *s);
|
void puts(const char *s);
|
||||||
void printf(const char *fmt, ...);
|
void printf(const char *fmt, ...);
|
||||||
|
|
||||||
|
// Runtime stubs
|
||||||
|
int system(const char *command);
|
||||||
|
char *getenv(const char *name);
|
||||||
|
void abort(void);
|
||||||
|
|
||||||
// System/Process functions
|
// System/Process functions
|
||||||
int chdir(const char *path);
|
int chdir(const char *path);
|
||||||
char* getcwd(char *buf, int size);
|
char* getcwd(char *buf, int size);
|
||||||
|
int access(const char *pathname, int mode);
|
||||||
void sleep(int ms);
|
void sleep(int ms);
|
||||||
void exit(int status);
|
void exit(int status);
|
||||||
|
void _exit(int status);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -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);
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
void *memcpy(void *dest, const void *src, size_t n);
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
void *memset(void *s, int c, 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 *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);
|
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);
|
size_t strlen(const char *s);
|
||||||
int strcmp(const char *s1, const char *s2);
|
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* strcpy(char *dest, const char *src);
|
||||||
char* strcat(char *dest, const char *src);
|
char* strcat(char *dest, const char *src);
|
||||||
|
char *strdup(const char *s);
|
||||||
|
char *strerror(int errnum);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
158
src/userland/libc/string_ext.c
Normal file
158
src/userland/libc/string_ext.c
Normal file
|
|
@ -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;
|
||||||
|
}
|
||||||
13
src/userland/libc/sys/stat.h
Normal file
13
src/userland/libc/sys/stat.h
Normal file
|
|
@ -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
|
||||||
8
src/userland/libc/sys/types.h
Normal file
8
src/userland/libc/sys/types.h
Normal file
|
|
@ -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
|
||||||
166
src/userland/libc/time.c
Normal file
166
src/userland/libc/time.c
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
30
src/userland/libc/time.h
Normal file
30
src/userland/libc/time.h
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef BOREDOS_LIBC_TIME_H
|
||||||
|
#define BOREDOS_LIBC_TIME_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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
|
||||||
22
src/userland/libc/unistd.h
Normal file
22
src/userland/libc/unistd.h
Normal file
|
|
@ -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
|
||||||
Loading…
Reference in a new issue