#ifndef LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H
#define LLVM_LIBC_SRC_SUPPORT_OSUTIL_FILE_H
#include "src/__support/threads/mutex.h"
#include <stddef.h>
#include <stdint.h>
namespace __llvm_libc {
class File {
public:
static constexpr size_t DEFAULT_BUFFER_SIZE = 1024;
using LockFunc = void(File *);
using UnlockFunc = void(File *);
using WriteFunc = size_t(File *, const void *, size_t);
using ReadFunc = size_t(File *, void *, size_t);
using SeekFunc = int(File *, long, int);
using CloseFunc = int(File *);
using FlushFunc = int(File *);
using ModeFlags = uint32_t;
enum class OpenMode : ModeFlags {
READ = 0x1,
WRITE = 0x2,
APPEND = 0x4,
PLUS = 0x8,
};
enum class ContentType : ModeFlags {
BINARY = 0x10,
};
enum class CreateType : ModeFlags {
EXCLUSIVE = 0x100,
};
private:
enum class FileOp : uint8_t { NONE, READ, WRITE, SEEK };
WriteFunc *platform_write;
ReadFunc *platform_read;
SeekFunc *platform_seek;
CloseFunc *platform_close;
FlushFunc *platform_flush;
Mutex mutex;
void *buf;
size_t bufsize;
int bufmode;
bool own_buf;
ModeFlags mode;
size_t pos;
FileOp prev_op;
size_t read_limit;
bool eof;
bool err;
class FileLock {
File *file;
public:
explicit FileLock(File *f) : file(f) { file->lock(); }
~FileLock() { file->unlock(); }
FileLock(const FileLock &) = delete;
FileLock(FileLock &&) = delete;
};
protected:
bool write_allowed() const {
return mode & (static_cast<ModeFlags>(OpenMode::WRITE) |
static_cast<ModeFlags>(OpenMode::APPEND) |
static_cast<ModeFlags>(OpenMode::PLUS));
}
bool read_allowed() const {
return mode & (static_cast<ModeFlags>(OpenMode::READ) |
static_cast<ModeFlags>(OpenMode::PLUS));
}
public:
constexpr File(WriteFunc *wf, ReadFunc *rf, SeekFunc *sf, CloseFunc *cf,
FlushFunc *ff, void *buffer, size_t buffer_size,
int buffer_mode, bool owned, ModeFlags modeflags)
: platform_write(wf), platform_read(rf), platform_seek(sf),
platform_close(cf), platform_flush(ff), mutex(false, false, false),
buf(buffer), bufsize(buffer_size), bufmode(buffer_mode), own_buf(owned),
mode(modeflags), pos(0), prev_op(FileOp::NONE), read_limit(0),
eof(false), err(false) {}
static void init(File *f, WriteFunc *wf, ReadFunc *rf, SeekFunc *sf,
CloseFunc *cf, FlushFunc *ff, void *buffer,
size_t buffer_size, int buffer_mode, bool owned,
ModeFlags modeflags) {
Mutex::init(&f->mutex, false, false, false);
f->platform_write = wf;
f->platform_read = rf;
f->platform_seek = sf;
f->platform_close = cf;
f->platform_flush = ff;
f->buf = reinterpret_cast<uint8_t *>(buffer);
f->bufsize = buffer_size;
f->bufmode = buffer_mode;
f->own_buf = owned;
f->mode = modeflags;
f->prev_op = FileOp::NONE;
f->read_limit = f->pos = 0;
f->eof = f->err = false;
}
size_t write_unlocked(const void *data, size_t len);
size_t write(const void *data, size_t len) {
FileLock l(this);
return write_unlocked(data, len);
}
size_t read_unlocked(void *data, size_t len);
size_t read(void *data, size_t len) {
FileLock l(this);
return read_unlocked(data, len);
}
int seek(long offset, int whence);
int flush() {
FileLock lock(this);
return flush_unlocked();
}
int flush_unlocked();
void set_buffer(void *buffer, size_t size, bool owned);
int close();
void lock() { mutex.lock(); }
void unlock() { mutex.unlock(); }
bool error_unlocked() const { return err; }
bool error() {
FileLock l(this);
return error_unlocked();
}
void clearerr_unlocked() { err = false; }
void clearerr() {
FileLock l(this);
clearerr_unlocked();
}
bool iseof_unlocked() { return eof; }
bool iseof() {
FileLock l(this);
return iseof_unlocked();
}
static ModeFlags mode_flags(const char *mode);
private:
size_t write_unlocked_lbf(const void *data, size_t len);
size_t write_unlocked_fbf(const void *data, size_t len);
size_t write_unlocked_nbf(const void *data, size_t len);
};
File *openfile(const char *path, const char *mode);
extern File *stdout;
extern File *stderr;
}
#endif