#define _LUNA_SYSTEM_ERROR_EXTENSIONS #include #include #include #include #include #include #include #include FILE* stderr = nullptr; FILE* stdout = nullptr; 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; } extern "C" { FILE* fopen(const char* path, const char* mode) { int flags; if ((flags = fopen_parse_mode(mode)) < 0) return nullptr; FILE* f = (FILE*)malloc(sizeof(FILE)); if (!f) { return nullptr; } int fd = open(path, flags, 0666); if (fd < 0) { free(f); return nullptr; } f->_fd = fd; clearerr(f); return f; } FILE* fdopen(int fd, const char* mode) { int flags; if ((flags = fopen_parse_mode(mode)) < 0) return nullptr; // FIXME: We do verify that fd is valid, but not that the mode is compatible. long rc = lseek(fd, 0, SEEK_CUR); if (rc < 0) return nullptr; FILE* f = (FILE*)malloc(sizeof(FILE)); if (!f) { return nullptr; } f->_fd = fd; clearerr(f); return f; } int fclose(FILE* stream) { if (close(stream->_fd) < 0) return EOF; free(stream); return 0; } int fileno(FILE* stream) { return stream->_fd; } 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; } 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; } 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); } int ferror(FILE* stream) { return stream->_err; } int feof(FILE* stream) { return stream->_eof; } int fputc(int c, FILE* stream) { u8 value = (u8)c; ssize_t rc = write(stream->_fd, &value, 1); if (rc <= 0) return EOF; return c; } int putc(int c, FILE* stream) { return fputc(c, stream); } int putchar(int c) { return fputc(c, stdout); } int fputs(const char* str, FILE* stream) { ssize_t rc = write(stream->_fd, str, strlen(str)); return (rc < 0) ? -1 : 0; } void clearerr(FILE* stream) { stream->_eof = stream->_err = 0; } 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; } int vfprintf(FILE* stream, const char* format, va_list ap) { usize rc = cstyle_format( format, [](char c, void* f) -> Result { int rc = fputc(c, (FILE*)f); if (rc == EOF) return err(errno); return {}; }, stream, ap) .value_or(-1); if (rc == (usize)-1) return -1; return (int)rc; } int fprintf(FILE* stream, const char* format, ...) { va_list ap; va_start(ap, format); int rc = vfprintf(stream, format, ap); va_end(ap); return rc; } int vprintf(const char* format, va_list ap) { return vfprintf(stdout, format, ap); } int printf(const char* format, ...) { va_list ap; va_start(ap, format); int rc = vfprintf(stdout, format, ap); va_end(ap); return rc; } int puts(const char* s) { if (fputs(s, stdout) < 0) return -1; if (putchar('\n') == EOF) return -1; return 0; } void perror(const char* s) { int err = errno; if (s && *s) fprintf(stderr, "%s: ", s); fprintf(stderr, "%s\n", strerror(err)); } } void debug_log_impl(const char* format, va_list ap) { vfprintf(stderr, format, ap); fputc('\n', stderr); }