2023-01-06 19:15:43 +00:00
|
|
|
#define _LUNA_SYSTEM_ERROR_EXTENSIONS
|
2023-01-06 16:35:07 +00:00
|
|
|
#include <bits/errno-return.h>
|
2023-03-12 09:23:08 +00:00
|
|
|
#include <fcntl.h>
|
2023-01-06 19:15:43 +00:00
|
|
|
#include <luna/Format.h>
|
2023-01-06 12:31:14 +00:00
|
|
|
#include <stdio.h>
|
2023-03-12 09:23:08 +00:00
|
|
|
#include <stdlib.h>
|
2023-01-07 00:49:26 +00:00
|
|
|
#include <string.h>
|
2023-01-06 12:31:14 +00:00
|
|
|
#include <sys/syscall.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2023-01-06 16:35:07 +00:00
|
|
|
FILE* stderr = nullptr;
|
|
|
|
|
2023-03-12 16:36:04 +00:00
|
|
|
static int fopen_parse_mode(const char* mode)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
switch (*mode)
|
|
|
|
{
|
|
|
|
case 'r': result |= O_RDONLY; break;
|
|
|
|
case 'w': result |= (O_WRONLY | O_CREAT | O_TRUNC); break;
|
|
|
|
case 'a': result |= (O_WRONLY | O_CREAT | O_APPEND); break;
|
|
|
|
|
|
|
|
default: errno = EINVAL; return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strchr(mode, '+')) result |= O_RDWR;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2023-01-06 12:31:14 +00:00
|
|
|
extern "C"
|
|
|
|
{
|
2023-01-07 00:49:26 +00:00
|
|
|
int console_write(const char* str, size_t size)
|
2023-01-06 12:31:14 +00:00
|
|
|
{
|
2023-01-07 00:49:26 +00:00
|
|
|
long rc = syscall(SYS_console_write, str, size);
|
2023-01-06 16:35:07 +00:00
|
|
|
__errno_return(rc, int);
|
2023-01-06 12:31:14 +00:00
|
|
|
}
|
2023-01-06 19:15:43 +00:00
|
|
|
|
2023-03-12 16:36:04 +00:00
|
|
|
FILE* fopen(const char* path, const char* mode)
|
2023-03-12 09:23:08 +00:00
|
|
|
{
|
2023-03-12 16:36:04 +00:00
|
|
|
int flags;
|
|
|
|
|
|
|
|
if ((flags = fopen_parse_mode(mode)) < 0) return nullptr;
|
|
|
|
|
|
|
|
int fd = open(path, flags, 0666);
|
2023-03-12 09:23:08 +00:00
|
|
|
if (fd < 0) return nullptr;
|
|
|
|
|
|
|
|
FILE* f = (FILE*)malloc(sizeof(FILE));
|
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
close(fd);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
f->_fd = fd;
|
|
|
|
clearerr(f);
|
|
|
|
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fclose(FILE* stream)
|
|
|
|
{
|
|
|
|
if (close(stream->_fd) < 0) return EOF;
|
|
|
|
|
|
|
|
free(stream);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t fread(void* buf, size_t size, size_t nmemb, FILE* stream)
|
|
|
|
{
|
|
|
|
if (size * nmemb == 0) return 0;
|
|
|
|
|
|
|
|
ssize_t nread = read(stream->_fd, buf, size * nmemb);
|
|
|
|
|
|
|
|
if (nread < 0)
|
|
|
|
{
|
|
|
|
stream->_err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else if (nread == 0)
|
|
|
|
{
|
|
|
|
stream->_eof = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return (size_t)nread / size;
|
|
|
|
}
|
|
|
|
|
2023-03-12 10:37:41 +00:00
|
|
|
size_t fwrite(const void* buf, size_t size, size_t nmemb, FILE* stream)
|
|
|
|
{
|
|
|
|
if (size * nmemb == 0) return 0;
|
|
|
|
|
|
|
|
ssize_t nwrite = write(stream->_fd, buf, size * nmemb);
|
|
|
|
|
|
|
|
return (size_t)nwrite / size;
|
|
|
|
}
|
|
|
|
|
2023-03-12 12:15:24 +00:00
|
|
|
int fseek(FILE* stream, long offset, int whence)
|
|
|
|
{
|
|
|
|
long result = lseek(stream->_fd, offset, whence);
|
|
|
|
if (result < 0) return -1;
|
|
|
|
|
|
|
|
// man fseek(3): A successful call to the fseek() function clears the end-of-file indicator for the stream.
|
|
|
|
stream->_eof = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
long ftell(FILE* stream)
|
|
|
|
{
|
|
|
|
return lseek(stream->_fd, 0, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
|
|
|
void rewind(FILE* stream)
|
|
|
|
{
|
|
|
|
lseek(stream->_fd, 0, SEEK_SET);
|
|
|
|
|
|
|
|
clearerr(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fgetpos(FILE* stream, fpos_t* pos)
|
|
|
|
{
|
|
|
|
long offset = ftell(stream);
|
|
|
|
if (offset < 0) return -1;
|
|
|
|
|
|
|
|
*pos = offset;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int fsetpos(FILE* stream, const fpos_t* pos)
|
|
|
|
{
|
|
|
|
return fseek(stream, *pos, SEEK_SET);
|
|
|
|
}
|
|
|
|
|
2023-03-12 09:23:08 +00:00
|
|
|
int ferror(FILE* stream)
|
|
|
|
{
|
|
|
|
return stream->_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
int feof(FILE* stream)
|
|
|
|
{
|
|
|
|
return stream->_eof;
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearerr(FILE* stream)
|
|
|
|
{
|
|
|
|
stream->_eof = stream->_err = 0;
|
|
|
|
}
|
|
|
|
|
2023-01-06 19:15:43 +00:00
|
|
|
int vsnprintf(char* buf, size_t max, const char* format, va_list ap)
|
|
|
|
{
|
|
|
|
return (int)vstring_format(buf, max, format, ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
int snprintf(char* buf, size_t max, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
|
|
|
|
int rc = vsnprintf(buf, max, format, ap);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int vsprintf(char* buf, const char* format, va_list ap)
|
|
|
|
{
|
|
|
|
return vsnprintf(buf, (size_t)-1, format, ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
int sprintf(char* buf, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
|
|
|
|
int rc = vsnprintf(buf, (size_t)-1, format, ap);
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2023-01-07 00:49:26 +00:00
|
|
|
|
|
|
|
int printf(const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format);
|
|
|
|
|
2023-03-02 12:38:21 +00:00
|
|
|
int rc = (int)cstyle_format(
|
|
|
|
format,
|
|
|
|
[](char c, void*) -> Result<void> {
|
|
|
|
console_write(&c, 1);
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
nullptr, ap)
|
|
|
|
.value();
|
2023-01-07 00:49:26 +00:00
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int puts(const char* s)
|
|
|
|
{
|
|
|
|
if (console_write(s, strlen(s)) < 0) return -1;
|
|
|
|
if (console_write("\n", 1) < 0) return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2023-01-13 20:08:10 +00:00
|
|
|
|
|
|
|
void perror(const char* s)
|
|
|
|
{
|
|
|
|
// FIXME: Output to stderr when available.
|
|
|
|
int err = errno;
|
|
|
|
if (s && *s) printf("%s: ", s);
|
|
|
|
printf("%s\n", strerror(err));
|
|
|
|
}
|
2023-01-06 12:31:14 +00:00
|
|
|
}
|
2023-01-13 19:00:20 +00:00
|
|
|
|
|
|
|
void debug_log_impl(const char* format, va_list ap)
|
|
|
|
{
|
2023-03-02 12:38:21 +00:00
|
|
|
cstyle_format(
|
|
|
|
format,
|
|
|
|
[](char c, void*) -> Result<void> {
|
|
|
|
console_write(&c, 1);
|
|
|
|
return {};
|
|
|
|
},
|
|
|
|
nullptr, ap)
|
|
|
|
.value();
|
2023-02-25 16:36:03 +00:00
|
|
|
console_write("\n", 1);
|
2023-01-13 19:00:20 +00:00
|
|
|
}
|