#include #include #include #include #include #include #include #include struct FILE { int fd { -1 }; bool eof { false }; bool error { false }; unsigned char buffer[BUFSIZ]; uint32_t buffer_index { 0 }; }; static FILE s_files[FOPEN_MAX] { { .fd = STDIN_FILENO }, { .fd = STDOUT_FILENO }, { .fd = STDERR_FILENO }, }; FILE* stdin = &s_files[0]; FILE* stdout = &s_files[1]; FILE* stderr = &s_files[2]; void clearerr(FILE* file) { file->eof = false; file->error = false; } 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 (close(file->fd) == -1) return EOF; file->fd = -1; return 0; } FILE* fdopen(int fd, const char* mode) { // FIXME (void)mode; 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; } 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 (syscall(SYS_WRITE, file->fd, file->buffer, file->buffer_index) < 0) { 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) { file->error = true; return EOF; } if (ret == 0) { file->eof = true; return EOF; } return c; } int fgetpos(FILE* file, fpos_t* pos) { off_t offset = ftello(file); if (offset == -1) return -1; *pos = 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; } int fileno(FILE* fp) { if (fp == nullptr) return EBADF; return fp->fd; } // 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] == 'w') 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; } int fprintf(FILE* file, const char* format, ...) { va_list arguments; va_start(arguments, format); int ret = vfprintf(file, format, arguments); va_end(arguments); return ret; } int fputc(int c, FILE* file) { 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; } int fputs(const char* str, FILE* file) { while (*str) { if (fputc(*str, file) == EOF) return EOF; str++; } return 0; } size_t fread(void* buffer, size_t size, size_t nitems, FILE* file) { if (file->eof || nitems * size == 0) return 0; size_t target = size * nitems; size_t nread = 0; while (nread < target) { size_t ret = syscall(SYS_READ, file->fd, (uint8_t*)buffer + nread, target - nread); if (ret < 0) file->error = true; else if (ret == 0) file->eof = true; if (ret <= 0) return nread; nread += ret; } return nread / size; } // 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) { long ret = syscall(SYS_SEEK, file->fd, offset, whence); if (ret < 0) return -1; file->eof = false; return 0; } int fsetpos(FILE* file, const fpos_t* pos) { return fseek(file, *pos, SEEK_SET); } long ftell(FILE* file) { return ftello(file); } off_t ftello(FILE* file) { long ret = syscall(SYS_TELL, file->fd); if (ret < 0) return -1; return ret; } // TODO int ftrylockfile(FILE*); // TODO void funlockfile(FILE*); size_t fwrite(const 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 (fputc(ubuffer[byte], file) == EOF) return byte / size; return nitems; } int getc(FILE* file) { return fgetc(file); } int getchar(void) { return getc(stdin); } // TODO int getc_unlocked(FILE*); // TODO int getchar_unlocked(void); char* gets(char* buffer) { 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); fputc('\n', 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); int snprintf(char* buffer, size_t max_size, const char* format, ...) { va_list arguments; va_start(arguments, format); int ret = vsnprintf(buffer, max_size, format, arguments); va_end(arguments); return ret; } int sprintf(char* buffer, const char* format, ...) { va_list arguments; va_start(arguments, format); int ret = vsprintf(buffer, format, arguments); va_end(arguments); return ret; } // 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) { return printf_impl(format, arguments, [](int c, void* file) { return fputc(c, (FILE*)file); }, file); } // 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); int vsnprintf(char* buffer, size_t max_size, const char* format, va_list arguments) { if (buffer == nullptr) return printf_impl(format, arguments, [](int, void*) { return 0; }, nullptr); struct print_info { char* buffer; size_t remaining; }; print_info info { buffer, max_size }; int ret = printf_impl(format, arguments, [](int c, void* _info) { print_info* info = (print_info*)_info; if (info->remaining == 1) { *info->buffer = '\0'; info->remaining = 0; } else if (info->remaining) { *info->buffer = c; info->buffer++; info->remaining--; } return 0; }, &info ); *info.buffer = '\0'; return ret; } int vsprintf(char* buffer, const char* format, va_list arguments) { if (buffer == nullptr) return printf_impl(format, arguments, [](int, void*) { return 0; }, nullptr); int ret = printf_impl(format, arguments, [](int c, void* _buffer) { *(*(char**)_buffer)++ = c; return 0; }, &buffer ); *buffer = '\0'; return ret; } // TODO int vsscanf(const char*, const char*, va_list);