Luna/libs/libc/src/file.cpp
2022-10-15 10:28:52 +02:00

137 lines
3.3 KiB
C++

#include <errno.h>
#include <fcntl.h>
#include <luna.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
FILE* stderr;
FILE* stdout;
extern "C"
{
int fclose(FILE* stream)
{
int status = close(stream->f_fd);
if (status < 0)
{
int savederr = errno;
free(stream); // We do not want to leak memory. man fclose(3) says that whether fclose() fails or not, any
// further operation on the stream results in undefined behavior. So we are free to free the
// stream.
errno = savederr; // free might reset errno. We don't want that.
}
else { free(stream); }
return status;
}
int fflush(FILE*)
{
return 0; // FIXME: Implement buffered IO.
}
FILE* fopen(const char* pathname, const char*)
{
int fd = open(pathname, O_RDWR); // FIXME: Use the mode string.
if (fd < 0) { return 0; }
FILE* stream = (FILE*)malloc(sizeof(FILE));
stream->f_fd = fd;
clearerr(stream);
return stream;
}
FILE* fdopen(int fd, const char*)
{
if (fd < 0) // FIXME: Also check if the mode string is compatible with how fd was opened.
{
errno = EBADF;
return 0;
}
FILE* stream = (FILE*)malloc(sizeof(FILE));
stream->f_fd = fd;
clearerr(stream);
return stream;
}
int fileno(FILE* stream)
{
return stream->f_fd;
}
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = read(stream->f_fd, buf, size * nmemb);
if (status < 0)
{
stream->f_err = 1;
return 0;
}
if (status == 0) stream->f_eof = 1;
return (size_t)status;
}
int ferror(FILE* stream)
{
return stream->f_err;
}
int feof(FILE* stream)
{
return stream->f_eof;
}
void clearerr(FILE* stream)
{
stream->f_err = stream->f_eof = 0;
}
int fseek(FILE* stream, long offset, int whence)
{
long result = lseek(stream->f_fd, offset, whence);
if (result < 0) { return -1; }
return 0;
}
int fsetpos(FILE* stream, const fpos_t* pos)
{
return fseek(stream, pos->f_offset, SEEK_SET);
}
long ftell(FILE* stream)
{
return lseek(stream->f_fd, 0,
SEEK_CUR); // FIXME: Store the last seeked position in the file struct to avoid redundant syscalls
// maybe? We'd have to update this value in fread() and fwrite() as well...
}
int fgetpos(FILE* stream, fpos_t* pos)
{
long result = ftell(stream);
if (result < 0) { return -1; }
pos->f_offset = result;
return 0;
}
void rewind(FILE* stream)
{
lseek(stream->f_fd, 0, SEEK_SET);
clearerr(stream);
}
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)
{
ssize_t status = write(stream->f_fd, buf, size * nmemb);
if (status < 0)
{
stream->f_err = 1;
return 0;
}
if (status == 0) stream->f_eof = 1;
return (size_t)status;
}
void setbuf(FILE*, char*)
{
NOT_IMPLEMENTED("setbuf");
}
}