LibC: Write mostly functioning stdio
This commit is contained in:
parent
9b2a577fc3
commit
cd74b2167d
|
@ -43,6 +43,7 @@ namespace Kernel
|
||||||
BAN::ErrorOr<size_t> read(int, void*, size_t);
|
BAN::ErrorOr<size_t> read(int, void*, size_t);
|
||||||
BAN::ErrorOr<size_t> write(int, const void*, size_t);
|
BAN::ErrorOr<size_t> write(int, const void*, size_t);
|
||||||
BAN::ErrorOr<void> creat(BAN::StringView, mode_t);
|
BAN::ErrorOr<void> creat(BAN::StringView, mode_t);
|
||||||
|
BAN::ErrorOr<void> seek(int, size_t);
|
||||||
|
|
||||||
BAN::ErrorOr<void> fstat(int, stat*);
|
BAN::ErrorOr<void> fstat(int, stat*);
|
||||||
BAN::ErrorOr<void> stat(BAN::StringView, stat*);
|
BAN::ErrorOr<void> stat(BAN::StringView, stat*);
|
||||||
|
@ -54,6 +55,8 @@ namespace Kernel
|
||||||
BAN::ErrorOr<BAN::String> working_directory() const;
|
BAN::ErrorOr<BAN::String> working_directory() const;
|
||||||
BAN::ErrorOr<void> set_working_directory(BAN::StringView);
|
BAN::ErrorOr<void> set_working_directory(BAN::StringView);
|
||||||
|
|
||||||
|
void termid(char*) const;
|
||||||
|
|
||||||
static Process& current() { return Thread::current().process(); }
|
static Process& current() { return Thread::current().process(); }
|
||||||
|
|
||||||
MMU& mmu() { return m_mmu ? *m_mmu : MMU::get(); }
|
MMU& mmu() { return m_mmu ? *m_mmu : MMU::get(); }
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
#define SYS_EXIT 1
|
#define SYS_EXIT 1
|
||||||
#define SYS_READ 2
|
#define SYS_READ 2
|
||||||
#define SYS_WRITE 3
|
#define SYS_WRITE 3
|
||||||
|
#define SYS_TERMID 4
|
||||||
|
#define SYS_CLOSE 5
|
||||||
|
#define SYS_SEEK 6
|
||||||
|
#define SYS_OPEN 7
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
|
@ -304,6 +304,15 @@ namespace Kernel
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Process::seek(int fd, size_t offset)
|
||||||
|
{
|
||||||
|
LockGuard _(m_lock);
|
||||||
|
TRY(validate_fd(fd));
|
||||||
|
auto& open_fd = open_file_description(fd);
|
||||||
|
open_fd.offset = offset;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd)
|
BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd)
|
||||||
{
|
{
|
||||||
OpenFileDescription open_fd_copy;
|
OpenFileDescription open_fd_copy;
|
||||||
|
@ -349,6 +358,14 @@ namespace Kernel
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Process::termid(char* buffer) const
|
||||||
|
{
|
||||||
|
if (m_tty == nullptr)
|
||||||
|
buffer[0] = '\0';
|
||||||
|
strcpy(buffer, "/dev/");
|
||||||
|
strcpy(buffer + 5, m_tty->name().data());
|
||||||
|
}
|
||||||
|
|
||||||
BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
|
BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
auto res = Process::current().read(fd, buffer, size);
|
auto res = Process::current().read(fd, buffer, size);
|
||||||
if (res.is_error())
|
if (res.is_error())
|
||||||
return res.error().get_error_code();
|
return -res.error().get_error_code();
|
||||||
return res.value();
|
return res.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,36 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
auto res = Process::current().write(fd, buffer, size);
|
auto res = Process::current().write(fd, buffer, size);
|
||||||
if (res.is_error())
|
if (res.is_error())
|
||||||
return res.error().get_error_code();
|
return -res.error().get_error_code();
|
||||||
|
return res.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_close(int fd)
|
||||||
|
{
|
||||||
|
auto res = Process::current().close(fd);
|
||||||
|
if (res.is_error())
|
||||||
|
return -res.error().get_error_code();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_seek(int fd, long offset)
|
||||||
|
{
|
||||||
|
auto res = Process::current().seek(fd, offset);
|
||||||
|
if (res.is_error())
|
||||||
|
return -res.error().get_error_code();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_termid(char* buffer)
|
||||||
|
{
|
||||||
|
Process::current().termid(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sys_open(const char* path, int oflags)
|
||||||
|
{
|
||||||
|
auto res = Process::current().open(path, oflags);
|
||||||
|
if (res.is_error())
|
||||||
|
return -res.error().get_error_code();
|
||||||
return res.value();
|
return res.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,10 +73,20 @@ namespace Kernel
|
||||||
case SYS_WRITE:
|
case SYS_WRITE:
|
||||||
ret = sys_write((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3);
|
ret = sys_write((int)(uintptr_t)arg1, arg2, (size_t)(uintptr_t)arg3);
|
||||||
break;
|
break;
|
||||||
default:
|
case SYS_TERMID:
|
||||||
ret = -1;
|
sys_termid((char*)arg1);
|
||||||
dprintln("Unknown syscall");
|
|
||||||
break;
|
break;
|
||||||
|
case SYS_CLOSE:
|
||||||
|
ret = sys_close((int)(uintptr_t)arg1);
|
||||||
|
break;
|
||||||
|
case SYS_SEEK:
|
||||||
|
ret = sys_seek((int)(uintptr_t)arg1, (long)arg2);
|
||||||
|
break;
|
||||||
|
case SYS_OPEN:
|
||||||
|
ret = sys_open((const char*)arg1, (int)(uintptr_t)arg2);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Kernel::panic("Unknown syscall {}", syscall);
|
||||||
}
|
}
|
||||||
|
|
||||||
asm volatile("cli");
|
asm volatile("cli");
|
||||||
|
|
|
@ -4,6 +4,7 @@ project(libc CXX)
|
||||||
|
|
||||||
set(LIBC_SOURCES
|
set(LIBC_SOURCES
|
||||||
ctype.cpp
|
ctype.cpp
|
||||||
|
fcntl.cpp
|
||||||
stdio.cpp
|
stdio.cpp
|
||||||
stdlib.cpp
|
stdlib.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int open(const char* path, int oflag, ...)
|
||||||
|
{
|
||||||
|
int ret = syscall(SYS_OPEN, path, oflag);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
errno = -ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -16,6 +16,9 @@
|
||||||
#define ENOBUFS 12
|
#define ENOBUFS 12
|
||||||
#define ENOTTY 13
|
#define ENOTTY 13
|
||||||
#define ENOTBLK 14
|
#define ENOTBLK 14
|
||||||
|
#define EMFILE 15
|
||||||
|
|
||||||
|
#define errno errno
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
#define O_RDONLY (1 << 0)
|
#define O_RDONLY (1 << 0)
|
||||||
#define O_WRONLY (1 << 1)
|
#define O_WRONLY (1 << 1)
|
||||||
#define O_RDWR (O_RDONLY | O_WRONLY)
|
#define O_RDWR (O_RDONLY | O_WRONLY)
|
||||||
#define O_ACCMODE (O_RDONLY | O_WRONLY)
|
#define O_ACCMODE (O_RDONLY | O_WRONLY)
|
||||||
#define O_EXCL (1 << 2)
|
#define O_EXCL (1 << 2)
|
||||||
#define O_CREAT (1 << 3)
|
#define O_CREAT (1 << 3)
|
||||||
|
#define O_TRUNC (1 << 4)
|
||||||
|
#define O_APPEND (1 << 5)
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
int open(const char*, int, ...);
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
|
@ -18,28 +18,83 @@
|
||||||
#define EXIT_FAILURE 1
|
#define EXIT_FAILURE 1
|
||||||
#define EXIT_SUCCESS 0
|
#define EXIT_SUCCESS 0
|
||||||
|
|
||||||
|
#define L_ctermid 50
|
||||||
|
|
||||||
|
#define BUFSIZ 128
|
||||||
|
|
||||||
|
#define FOPEN_MAX 16
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
struct FILE;
|
struct FILE;
|
||||||
typedef struct FILE FILE;
|
typedef struct FILE FILE;
|
||||||
|
|
||||||
|
typedef uint64_t fpos_t;
|
||||||
|
|
||||||
extern FILE* stdin;
|
extern FILE* stdin;
|
||||||
extern FILE* stdout;
|
extern FILE* stdout;
|
||||||
extern FILE* stderr;
|
extern FILE* stderr;
|
||||||
|
|
||||||
FILE* fopen(const char* __restrict__, const char* __restrict__);
|
void clearerr(FILE*);
|
||||||
int fclose(FILE*);
|
char* ctermid(char*);
|
||||||
int fflush(FILE*);
|
int fclose(FILE*);
|
||||||
int fprintf(FILE* __restrict__, const char* __restrict__, ...);
|
FILE* fdopen(int, const char*);
|
||||||
int fseek(FILE*, long, int);
|
int feof(FILE*);
|
||||||
int printf(const char* __restrict__, ...);
|
int ferror(FILE*);
|
||||||
int putchar(int);
|
int fflush(FILE*);
|
||||||
int puts(const char*);
|
int fgetc(FILE*);
|
||||||
int vfprintf(FILE* __restrict__, const char* __restrict__, va_list);
|
int fgetpos(FILE*, fpos_t*);
|
||||||
long ftell(FILE*);
|
char* fgets(char*, int, FILE*);
|
||||||
size_t fread(void* __restrict__, size_t, size_t, FILE*);
|
int fileno(FILE*);
|
||||||
size_t fwrite(void const* __restrict__, size_t, size_t, FILE*);
|
void flockfile(FILE*);
|
||||||
void setbuf(FILE* __restrict__, char* __restrict__);
|
FILE* fopen(const char*, const char*);
|
||||||
int sprintf(char* __restrict__, const char* __restrict__, ...);
|
int fprintf(FILE*, const char*, ...);
|
||||||
|
int fputc(int, FILE*);
|
||||||
|
int fputs(const char*, FILE*);
|
||||||
|
size_t fread(void*, size_t, size_t, FILE*);
|
||||||
|
FILE* freopen(const char*, const char*, FILE*);
|
||||||
|
int fscanf(FILE*, const char*, ...);
|
||||||
|
int fseek(FILE*, long, int);
|
||||||
|
int fseeko(FILE*, off_t, int);
|
||||||
|
int fsetpos(FILE*, const fpos_t*);
|
||||||
|
long ftell(FILE*);
|
||||||
|
off_t ftello(FILE*);
|
||||||
|
int ftrylockfile(FILE*);
|
||||||
|
void funlockfile(FILE*);
|
||||||
|
size_t fwrite(const void*, size_t, size_t, FILE*);
|
||||||
|
int getc(FILE*);
|
||||||
|
int getchar(void);
|
||||||
|
int getc_unlocked(FILE*);
|
||||||
|
int getchar_unlocked(void);
|
||||||
|
char* gets(char*);
|
||||||
|
int pclose(FILE*);
|
||||||
|
void perror(const char*);
|
||||||
|
FILE* popen(const char*, const char*);
|
||||||
|
int printf(const char*, ...);
|
||||||
|
int putc(int, FILE*);
|
||||||
|
int putchar(int);
|
||||||
|
int putc_unlocked(int, FILE*);
|
||||||
|
int putchar_unlocked(int);
|
||||||
|
int puts(const char*);
|
||||||
|
int remove(const char*);
|
||||||
|
int rename(const char*, const char*);
|
||||||
|
void rewind(FILE*);
|
||||||
|
int scanf(const char*, ...);
|
||||||
|
void setbuf(FILE*, char*);
|
||||||
|
int setvbuf(FILE*, char*, int, size_t);
|
||||||
|
int snprintf(char*, size_t, const char*, ...);
|
||||||
|
int sprintf(char*, const char*, ...);
|
||||||
|
int sscanf(const char*, const char*, ...);
|
||||||
|
char* tempnam(const char*, const char*);
|
||||||
|
FILE* tmpfile(void);
|
||||||
|
char* tmpnam(char*);
|
||||||
|
int ungetc(int, FILE*);
|
||||||
|
int vfprintf(FILE*, const char*, va_list);
|
||||||
|
int vfscanf(FILE*, const char*, va_list);
|
||||||
|
int vprintf(const char*, va_list);
|
||||||
|
int vscanf(const char*, va_list);
|
||||||
|
int vsnprintf(char*, size_t, const char*, va_list);
|
||||||
|
int vsprintf(char*, const char*, va_list);
|
||||||
|
int vsscanf(const char*, const char*, va_list);
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
486
libc/stdio.cpp
486
libc/stdio.cpp
|
@ -1,3 +1,5 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -6,92 +8,496 @@
|
||||||
|
|
||||||
struct FILE
|
struct FILE
|
||||||
{
|
{
|
||||||
int fd;
|
int fd { -1 };
|
||||||
|
off_t offset { 0 };
|
||||||
|
bool eof { false };
|
||||||
|
bool error { false };
|
||||||
|
|
||||||
|
unsigned char buffer[BUFSIZ];
|
||||||
|
uint32_t buffer_index { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
static FILE __stdin { .fd = STDIN_FILENO };
|
static FILE s_files[FOPEN_MAX] {
|
||||||
static FILE __stdout { .fd = STDOUT_FILENO };
|
{ .fd = STDIN_FILENO },
|
||||||
static FILE __stderr { .fd = STDERR_FILENO };
|
{ .fd = STDOUT_FILENO },
|
||||||
|
{ .fd = STDERR_FILENO },
|
||||||
|
};
|
||||||
|
|
||||||
FILE* stdin = &__stdin;
|
FILE* stdin = &s_files[0];
|
||||||
FILE* stdout = &__stdout;
|
FILE* stdout = &s_files[1];
|
||||||
FILE* stderr = &__stderr;
|
FILE* stderr = &s_files[2];
|
||||||
|
|
||||||
int fclose(FILE*)
|
void clearerr(FILE* file)
|
||||||
{
|
{
|
||||||
return -1;
|
file->eof = false;
|
||||||
|
file->error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fflush(FILE*)
|
char* ctermid(char* buffer)
|
||||||
{
|
{
|
||||||
|
static char s_buffer[L_ctermid];
|
||||||
|
char* target = buffer ? buffer : s_buffer;
|
||||||
|
syscall(SYS_TERMID, target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fclose(FILE* file)
|
||||||
|
{
|
||||||
|
if (int ret = syscall(SYS_CLOSE, file->fd) < 0)
|
||||||
|
{
|
||||||
|
errno = -ret;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
file->fd = -1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* fopen(const char* __restrict__, const char* __restrict__)
|
// TODO
|
||||||
|
FILE* fdopen(int, const char*);
|
||||||
|
|
||||||
|
int feof(FILE* file)
|
||||||
{
|
{
|
||||||
|
return file->eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ferror(FILE* file)
|
||||||
|
{
|
||||||
|
return file->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fflush(FILE* file)
|
||||||
|
{
|
||||||
|
if (file == nullptr)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < FOPEN_MAX; i++)
|
||||||
|
if (s_files[i].fd != -1)
|
||||||
|
if (int ret = fflush(&s_files[i]); ret != 0)
|
||||||
|
return ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->buffer_index == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (long ret = syscall(SYS_WRITE, file->fd, file->buffer, file->buffer_index); ret < 0)
|
||||||
|
{
|
||||||
|
errno = -ret;
|
||||||
|
file->error = true;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->buffer_index = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetc(FILE* file)
|
||||||
|
{
|
||||||
|
if (file->eof)
|
||||||
|
return EOF;
|
||||||
|
|
||||||
|
unsigned char c;
|
||||||
|
long ret = syscall(SYS_READ, file->fd, &c, 1);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
errno = -ret;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
{
|
||||||
|
file->eof = true;
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->offset++;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetpos(FILE* file, fpos_t* pos)
|
||||||
|
{
|
||||||
|
*pos = file->offset;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* fgets(char* str, int size, FILE* file)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
return str;
|
||||||
|
int c = fgetc(file);
|
||||||
|
if (c == EOF)
|
||||||
|
return nullptr;
|
||||||
|
str[0] = c;
|
||||||
|
for (int i = 1; i < size - 1; i++)
|
||||||
|
{
|
||||||
|
str[i] = fgetc(file);
|
||||||
|
if (str[i] == EOF)
|
||||||
|
{
|
||||||
|
str[i] = '\0';
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (str[i] == '\n')
|
||||||
|
{
|
||||||
|
str[i + 1] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str[size - 1] = '\0';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int fileno(FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void flockfile(FILE*);
|
||||||
|
|
||||||
|
FILE* fopen(const char* pathname, const char* mode)
|
||||||
|
{
|
||||||
|
uint8_t flags = 0;
|
||||||
|
if (mode[0] == 'r')
|
||||||
|
flags |= O_RDONLY;
|
||||||
|
else if (mode[0] == 'b')
|
||||||
|
flags |= O_WRONLY | O_CREAT | O_TRUNC;
|
||||||
|
else if (mode[0] == 'a')
|
||||||
|
flags |= O_WRONLY | O_CREAT | O_APPEND;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode[1] && mode[2] && mode[1] == mode[2])
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i <= 2; i++)
|
||||||
|
{
|
||||||
|
if (mode[i] == 0)
|
||||||
|
break;
|
||||||
|
else if (mode[i] == '+')
|
||||||
|
flags |= O_RDWR;
|
||||||
|
else if (mode[i] == 'b')
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = open(pathname, flags);
|
||||||
|
if (fd == -1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < FOPEN_MAX; i++)
|
||||||
|
{
|
||||||
|
if (s_files[i].fd == -1)
|
||||||
|
{
|
||||||
|
s_files[i] = { .fd = fd };
|
||||||
|
return &s_files[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = EMFILE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fseek(FILE*, long, int)
|
int fprintf(FILE* file, const char* format, ...)
|
||||||
{
|
{
|
||||||
return -1;
|
va_list arguments;
|
||||||
|
va_start(arguments, format);
|
||||||
|
int ret = vfprintf(file, format, arguments);
|
||||||
|
va_end(arguments);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
long ftell(FILE*)
|
int fputc(int c, FILE* file)
|
||||||
{
|
{
|
||||||
return -1;
|
file->buffer[file->buffer_index++] = c;
|
||||||
|
if (c == '\n' || file->buffer_index == sizeof(file->buffer))
|
||||||
|
if (fflush(file) == EOF)
|
||||||
|
return EOF;
|
||||||
|
return (unsigned char)c;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t fread(void* __restrict__, size_t, size_t, FILE*)
|
int fputs(const char* str, FILE* file)
|
||||||
{
|
{
|
||||||
|
while (*str)
|
||||||
|
{
|
||||||
|
if (putc(*str, file) == EOF)
|
||||||
|
return EOF;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t fwrite(void const* __restrict__, size_t, size_t, FILE*)
|
size_t fread(void* buffer, size_t size, size_t nitems, FILE* file)
|
||||||
{
|
{
|
||||||
|
unsigned char* ubuffer = (unsigned char*)buffer;
|
||||||
|
for (size_t byte = 0; byte < nitems * size; byte++)
|
||||||
|
if ((ubuffer[byte] = fgetc(file)) == EOF)
|
||||||
|
return byte / size;
|
||||||
|
return nitems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
FILE* freopen(const char*, const char*, FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int fscanf(FILE*, const char*, ...);
|
||||||
|
|
||||||
|
int fseek(FILE* file, long offset, int whence)
|
||||||
|
{
|
||||||
|
return fseeko(file, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fseeko(FILE* file, off_t offset, int whence)
|
||||||
|
{
|
||||||
|
if (whence == SEEK_CUR)
|
||||||
|
file->offset += offset;
|
||||||
|
else if (whence == SEEK_SET)
|
||||||
|
file->offset = offset;
|
||||||
|
else if (whence == SEEK_END)
|
||||||
|
{
|
||||||
|
errno = ENOTSUP;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->offset < 0)
|
||||||
|
{
|
||||||
|
file->offset -= offset;
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long ret = syscall(SYS_SEEK, file->fd, file->offset); ret < 0)
|
||||||
|
{
|
||||||
|
errno = -ret;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->eof = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fprintf(FILE* __restrict__ file, const char* __restrict__ format, ...)
|
int fsetpos(FILE* file, const fpos_t* pos)
|
||||||
{
|
{
|
||||||
va_list args;
|
return fseek(file, *pos, SEEK_SET);
|
||||||
va_start(args, format);
|
|
||||||
int res = vfprintf(stdout, format, args);
|
|
||||||
va_end(args);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long ftell(FILE* file)
|
||||||
void setbuf(FILE* __restrict__, char* __restrict__)
|
|
||||||
{
|
{
|
||||||
|
return ftello(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfprintf(FILE* __restrict__, const char* __restrict__, va_list)
|
off_t ftello(FILE* file)
|
||||||
{
|
{
|
||||||
return -1;
|
return file->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
int printf(const char* __restrict__ format, ...)
|
// TODO
|
||||||
|
int ftrylockfile(FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void funlockfile(FILE*);
|
||||||
|
|
||||||
|
size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file)
|
||||||
{
|
{
|
||||||
va_list args;
|
unsigned char* ubuffer = (unsigned char*)buffer;
|
||||||
va_start(args, format);
|
for (size_t byte = 0; byte < nitems * size; byte++)
|
||||||
int res = vfprintf(stdout, format, args);
|
if (fputc(ubuffer[byte], file) == EOF)
|
||||||
va_end(args);
|
return byte / size;
|
||||||
return res;
|
return nitems;
|
||||||
}
|
}
|
||||||
|
|
||||||
int putchar(int ch)
|
int getc(FILE* file)
|
||||||
{
|
{
|
||||||
return printf("%c", ch);
|
return fgetc(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
int puts(const char* str)
|
int getchar(void)
|
||||||
{
|
{
|
||||||
return syscall(SYS_WRITE, STDOUT_FILENO, str, strlen(str));
|
return getc(stdin);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sprintf(char* __restrict__ stream, const char* __restrict__ format, ...)
|
// TODO
|
||||||
|
int getc_unlocked(FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int getchar_unlocked(void);
|
||||||
|
|
||||||
|
char* gets(char* buffer)
|
||||||
{
|
{
|
||||||
return -1;
|
if (stdin->eof)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
unsigned char* ubuffer = (unsigned char*)buffer;
|
||||||
|
|
||||||
|
int first = fgetc(stdin);
|
||||||
|
if (first == EOF)
|
||||||
|
return nullptr;
|
||||||
|
*ubuffer++ = first;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int c = fgetc(stdin);
|
||||||
|
if (c == '\n' || c == EOF)
|
||||||
|
{
|
||||||
|
*ubuffer++ = '\0';
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
*ubuffer++ = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int pclose(FILE*);
|
||||||
|
|
||||||
|
void perror(const char* string)
|
||||||
|
{
|
||||||
|
if (string && *string)
|
||||||
|
{
|
||||||
|
fputs(string, stderr);
|
||||||
|
fputs(": ", stderr);
|
||||||
|
}
|
||||||
|
fputs(strerror(errno), stderr);
|
||||||
|
fflush(stderr);
|
||||||
|
stderr->error = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
FILE* popen(const char*, const char*);
|
||||||
|
|
||||||
|
int printf(const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list arguments;
|
||||||
|
va_start(arguments, format);
|
||||||
|
int ret = vfprintf(stdout, format, arguments);
|
||||||
|
va_end(arguments);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putc(int c, FILE* file)
|
||||||
|
{
|
||||||
|
return fputc(c, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
int putchar(int c)
|
||||||
|
{
|
||||||
|
return putc(c, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int putc_unlocked(int, FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int putchar_unlocked(int);
|
||||||
|
|
||||||
|
int puts(const char* string)
|
||||||
|
{
|
||||||
|
if (fputs(string, stdout) == EOF)
|
||||||
|
return EOF;
|
||||||
|
if (fputc('\n', stdout) == EOF)
|
||||||
|
return EOF;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int remove(const char*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int rename(const char*, const char*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void rewind(FILE*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int scanf(const char*, ...);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
void setbuf(FILE*, char*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int setvbuf(FILE*, char*, int, size_t);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int snprintf(char*, size_t, const char*, ...);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int sprintf(char*, const char*, ...);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int sscanf(const char*, const char*, ...);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
char* tempnam(const char*, const char*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
FILE* tmpfile(void);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
char* tmpnam(char*);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int ungetc(int, FILE*);
|
||||||
|
|
||||||
|
int vfprintf(FILE* file, const char* format, va_list arguments)
|
||||||
|
{
|
||||||
|
int written = 0;
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
switch (*format)
|
||||||
|
{
|
||||||
|
case '%':
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
{
|
||||||
|
const char* string = va_arg(arguments, const char*);
|
||||||
|
if (fputs(string, file) == EOF)
|
||||||
|
return -1;
|
||||||
|
written += strlen(string);
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fputc(*format, file) == EOF)
|
||||||
|
return -1;
|
||||||
|
written++;
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int vfscanf(FILE*, const char*, va_list);
|
||||||
|
|
||||||
|
int vprintf(const char* format, va_list arguments)
|
||||||
|
{
|
||||||
|
return vfprintf(stdout, format, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int vscanf(const char*, va_list);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int vsnprintf(char*, size_t, const char*, va_list);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int vsprintf(char*, const char*, va_list);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
int vsscanf(const char*, const char*, va_list);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <BAN/Assert.h>
|
#include <BAN/Assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -13,6 +14,7 @@ void abort(void)
|
||||||
|
|
||||||
void exit(int status)
|
void exit(int status)
|
||||||
{
|
{
|
||||||
|
fflush(nullptr);
|
||||||
_fini();
|
_fini();
|
||||||
_exit(status);
|
_exit(status);
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
|
|
|
@ -125,6 +125,9 @@ char* strerror(int error)
|
||||||
case ENOTBLK:
|
case ENOTBLK:
|
||||||
strcpy(buffer, "Block device required");
|
strcpy(buffer, "Block device required");
|
||||||
break;
|
break;
|
||||||
|
case EMFILE:
|
||||||
|
strcpy(buffer, "File descriptor value too large");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
// FIXME: sprintf
|
// FIXME: sprintf
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
puts("Hello World!");
|
if (printf("Hello %s!", "World") == -1)
|
||||||
|
perror(NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue