mirror of
https://github.com/RGBCube/serenity
synced 2025-06-01 08:28:11 +00:00
LibC: Implement {f,}getwc()
This commit is contained in:
parent
3b281baf75
commit
cf17677206
5 changed files with 207 additions and 130 deletions
141
Userland/Libraries/LibC/bits/stdio_file_implementation.h
Normal file
141
Userland/Libraries/LibC/bits/stdio_file_implementation.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2021, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <LibC/bits/FILE.h>
|
||||
#include <LibC/bits/pthread_integration.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
struct FILE {
|
||||
public:
|
||||
FILE(int fd, int mode)
|
||||
: m_fd(fd)
|
||||
, m_mode(mode)
|
||||
{
|
||||
__pthread_mutex_init(&m_mutex, nullptr);
|
||||
}
|
||||
~FILE();
|
||||
|
||||
static FILE* create(int fd, int mode);
|
||||
|
||||
void setbuf(u8* data, int mode, size_t size) { m_buffer.setbuf(data, mode, size); }
|
||||
|
||||
bool flush();
|
||||
void purge();
|
||||
bool close();
|
||||
|
||||
int fileno() const { return m_fd; }
|
||||
bool eof() const { return m_eof; }
|
||||
int mode() const { return m_mode; }
|
||||
u8 flags() const { return m_flags; }
|
||||
|
||||
int error() const { return m_error; }
|
||||
void clear_err() { m_error = 0; }
|
||||
|
||||
size_t read(u8*, size_t);
|
||||
size_t write(const u8*, size_t);
|
||||
|
||||
bool gets(u8*, size_t);
|
||||
bool ungetc(u8 byte) { return m_buffer.enqueue_front(byte); }
|
||||
|
||||
int seek(off_t offset, int whence);
|
||||
off_t tell();
|
||||
|
||||
pid_t popen_child() { return m_popen_child; }
|
||||
void set_popen_child(pid_t child_pid) { m_popen_child = child_pid; }
|
||||
|
||||
void reopen(int fd, int mode);
|
||||
|
||||
enum Flags : u8 {
|
||||
None = 0,
|
||||
LastRead = 1,
|
||||
LastWrite = 2,
|
||||
};
|
||||
|
||||
private:
|
||||
struct Buffer {
|
||||
// A ringbuffer that also transparently implements ungetc().
|
||||
public:
|
||||
~Buffer();
|
||||
|
||||
int mode() const { return m_mode; }
|
||||
void setbuf(u8* data, int mode, size_t size);
|
||||
// Make sure to call realize() before enqueuing any data.
|
||||
// Dequeuing can be attempted without it.
|
||||
void realize(int fd);
|
||||
void drop();
|
||||
|
||||
bool may_use() const { return m_ungotten || m_mode != _IONBF; }
|
||||
bool is_not_empty() const { return m_ungotten || !m_empty; }
|
||||
size_t buffered_size() const;
|
||||
|
||||
const u8* begin_dequeue(size_t& available_size) const;
|
||||
void did_dequeue(size_t actual_size);
|
||||
|
||||
u8* begin_enqueue(size_t& available_size) const;
|
||||
void did_enqueue(size_t actual_size);
|
||||
|
||||
bool enqueue_front(u8 byte);
|
||||
|
||||
private:
|
||||
// Note: the fields here are arranged this way
|
||||
// to make sizeof(Buffer) smaller.
|
||||
u8* m_data { nullptr };
|
||||
size_t m_capacity { BUFSIZ };
|
||||
size_t m_begin { 0 };
|
||||
size_t m_end { 0 };
|
||||
|
||||
int m_mode { -1 };
|
||||
u8 m_unget_buffer { 0 };
|
||||
bool m_ungotten : 1 { false };
|
||||
bool m_data_is_malloced : 1 { false };
|
||||
// When m_begin == m_end, we want to distinguish whether
|
||||
// the buffer is full or empty.
|
||||
bool m_empty : 1 { true };
|
||||
};
|
||||
|
||||
// Read or write using the underlying fd, bypassing the buffer.
|
||||
ssize_t do_read(u8*, size_t);
|
||||
ssize_t do_write(const u8*, size_t);
|
||||
|
||||
// Read some data into the buffer.
|
||||
bool read_into_buffer();
|
||||
// Flush *some* data from the buffer.
|
||||
bool write_from_buffer();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
int m_fd { -1 };
|
||||
int m_mode { 0 };
|
||||
u8 m_flags { Flags::None };
|
||||
int m_error { 0 };
|
||||
bool m_eof { false };
|
||||
pid_t m_popen_child { -1 };
|
||||
Buffer m_buffer;
|
||||
__pthread_mutex_t m_mutex;
|
||||
|
||||
friend class ScopedFileLock;
|
||||
};
|
||||
|
||||
class ScopedFileLock {
|
||||
public:
|
||||
ScopedFileLock(FILE* file)
|
||||
: m_file(file)
|
||||
{
|
||||
m_file->lock();
|
||||
}
|
||||
|
||||
~ScopedFileLock()
|
||||
{
|
||||
m_file->unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
FILE* m_file;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue